]> git.mxchange.org Git - friendica.git/blob - bin/composer.phar
Merge pull request #10179 from nupplaphil/fix/transifex_script
[friendica.git] / bin / composer.phar
1 #!/usr/bin/env php
2 <?php
3 /*
4  * This file is part of Composer.
5  *
6  * (c) Nils Adermann <naderman@naderman.de>
7  *     Jordi Boggiano <j.boggiano@seld.be>
8  *
9  * For the full copyright and license information, please view
10  * the license that is located at the bottom of this file.
11  */
12
13 // Avoid APC causing random fatal errors per https://github.com/composer/composer/issues/264
14 if (extension_loaded('apc') && filter_var(ini_get('apc.enable_cli'), FILTER_VALIDATE_BOOLEAN) && filter_var(ini_get('apc.cache_by_default'), FILTER_VALIDATE_BOOLEAN)) {
15     if (version_compare(phpversion('apc'), '3.0.12', '>=')) {
16         ini_set('apc.cache_by_default', 0);
17     } else {
18         fwrite(STDERR, 'Warning: APC <= 3.0.12 may cause fatal errors when running composer commands.'.PHP_EOL);
19         fwrite(STDERR, 'Update APC, or set apc.enable_cli or apc.cache_by_default to 0 in your php.ini.'.PHP_EOL);
20     }
21 }
22
23 Phar::mapPhar('composer.phar');
24 require 'phar://composer.phar/bin/composer';
25
26 __HALT_COMPILER(); ?>\r
27 \8d\96\0\0û\ 1\0\0\11\0\0\0\ 1\0\r\0\0\0composer.phar\0\0\0\0+\0\0\0src/Composer/Autoload/AutoloadGenerator.php3k\0\0\82{\11`3k\0\0y[£\13¤\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Autoload/ClassMapGenerator.phpÖ\1a\0\0\82{\11\1a\0\0ß\f\86\ 1\0\0\0\0\0\0\16\0\0\0src/Composer/Cache.phpä\13\0\0\82{\11\13\0\0xw\0ܤ\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Command/AboutCommand.phpØ\ 2\0\0\82{\11\ 2\0\0ö÷;\87¤\ 1\0\0\0\0\0\0'\0\0\0src/Composer/Command/ArchiveCommand.phpä\14\0\0\82{\11\14\0\0Õ\15­\7f¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Command/BaseCommand.phpÚ\v\0\0\82{\11\v\0\0Ý\10\88ˤ\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Command/BaseDependencyCommand.php\\19\0\0\82{\11`\\19\0\0{\8d9d¤\ 1\0\0\0\0\0\01\0\0\0src/Composer/Command/CheckPlatformReqsCommand.php}\ f\0\0\82{\11`}\ f\0\0\1c0Û¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Command/ClearCacheCommand.php½\ 5\0\0\82{\11\ 5\0\0°\ 2\b\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Command/ConfigCommand.php»Q\0\0\82{\11`»Q\0\0^¼ÿȤ\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Command/CreateProjectCommand.phpe;\0\0\82{\11`e;\0\0'\98À\ 5¤\ 1\0\0\0\0\0\0'\0\0\0src/Composer/Command/DependsCommand.phpø\ 2\0\0\82{\11\ 2\0\0ªe\11á¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Command/DiagnoseCommand.php]P\0\0\82{\11`]P\0\0MTõj¤\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Command/DumpAutoloadCommand.phpã\v\0\0\82{\11\v\0\0© ]\86¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Command/ExecCommand.php\1c \0\0\82{\11`\1c \0\0?ìç\11¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Command/FundCommand.php+
28 \0\0\82{\11`+
29 \0\0ð\19`ó¤\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Command/GlobalCommand.phpÅ       \0\0\82{\11`Å \0\0©O:ü¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Command/HomeCommand.php\ 1\ f\0\0\82{\11`\ 1\ f\0\0\ 4\92\89 ¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Command/InitCommand.php:U\0\0\82{\11`:U\0\0\88\8a»â¤\ 1\0\0\0\0\0\0'\0\0\0src/Composer/Command/InstallCommand.phpT\14\0\0\82{\11`T\14\0\0Þùõ\9b¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Command/LicensesCommand.phpò\ e\0\0\82{\11\ e\0\0´\18È\1c¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Command/OutdatedCommand.php\ f\f\0\0\82{\11`\ f\f\0\0ا\14\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Command/ProhibitsCommand.php\12\ 3\0\0\82{\11`\12\ 3\0\0_¤éS¤\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Command/RemoveCommand.phpß\18\0\0\82{\11\18\0\0ì:/|¤\ 1\0\0\0\0\0\0'\0\0\0src/Composer/Command/RequireCommand.php¨)\0\0\82{\11`¨)\0\0µDàÿ¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Command/RunScriptCommand.php±\ f\0\0\82{\11\ f\0\0\99Ò-Ť\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Command/ScriptAliasCommand.php¯\ 5\0\0\82{\11\ 5\0\0?=\10Ѥ\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Command/SearchCommand.phpT      \0\0\82{\11`T \0\0\7f±¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Command/SelfUpdateCommand.phpðC\0\0\82{\11`ðC\0\0vÕ      <¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Command/ShowCommand.phpp\82\0\0\82{\11`p\82\0\0¼¨ìÛ¤\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Command/StatusCommand.php%\16\0\0\82{\11`%\16\0\0\8e\14ÞÚ¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Command/SuggestsCommand.php
30 \ e\0\0\82{\11`
31 \ e\0\0y\92°ø¤\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Command/UpdateCommand.phpë#\0\0\82{\11`ë#\0\03<&\0¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Command/ValidateCommand.phpe\14\0\0\82{\11`e\14\0\0ï\ 3
32 ²¤\ 1\0\0\0\0\0\0\19\0\0\0src/Composer/Composer.php}\v\0\0\82{\11`}\v\0\0 ¯ï\9c¤\ 1\0\0\0\0\0\0\17\0\0\0src/Composer/Config.phpø$\0\0\82{\11`ø$\0\0\19öÙú¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Config/ConfigSourceInterface.php\ e\ 2\0\0\82{\11`\ e\ 2\0\0³\f[/¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Config/JsonConfigSource.php²\14\0\0\82{\11\14\0\0Gd=\9e¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Console/Application.phpY8\0\0\82{\11`Y8\0\0Äë檤\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Console/HtmlOutputFormatter.php0\ 6\0\0\82{\11`0\ 6\0\0\9aÒ¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/DependencyResolver/Decisions.php6\10\0\0\82{\11`6\10\0\0à\95\f\9e¤\ 1\0\0\0\0\0\01\0\0\0src/Composer/DependencyResolver/DefaultPolicy.php\ 5\17\0\0\82{\11`\ 5\17\0\0Þ       \b¼¤\ 1\0\0\0\0\0\0/\0\0\0src/Composer/DependencyResolver/GenericRule.php´\ 3\0\0\82{\11\ 3\0\0n±ðã¤\ 1\0\0\0\0\0\0>\0\0\0src/Composer/DependencyResolver/Operation/InstallOperation.phpC\ 2\0\0\82{\11`C\ 2\0\0´\õ*¤\ 1\0\0\0\0\0\0I\0\0\0src/Composer/DependencyResolver/Operation/MarkAliasInstalledOperation.php÷\ 2\0\0\82{\11\ 2\0\0ïÎà÷¤\ 1\0\0\0\0\0\0K\0\0\0src/Composer/DependencyResolver/Operation/MarkAliasUninstalledOperation.phpý\ 2\0\0\82{\11\ 2\0\0\193#\86¤\ 1\0\0\0\0\0\0@\0\0\0src/Composer/DependencyResolver/Operation/OperationInterface.phpÓ\0\0\0\82{\11\0\0\0Ùâ&ä¤\ 1\0\0\0\0\0\0=\0\0\0src/Composer/DependencyResolver/Operation/SolverOperation.php¹\ 1\0\0\82{\11\ 1\0\0&¢e
33 ¤\ 1\0\0\0\0\0\0@\0\0\0src/Composer/DependencyResolver/Operation/UninstallOperation.phpI\ 2\0\0\82{\11`I\ 2\0\0FûÂɤ\ 1\0\0\0\0\0\0=\0\0\0src/Composer/DependencyResolver/Operation/UpdateOperation.php'\ 4\0\0\82{\11`'\ 4\0\0Qúɯ¤\ 1\0\0\0\0\0\03\0\0\0src/Composer/DependencyResolver/PolicyInterface.php­\ 1\0\0\82{\11\ 1\0\0\18\9f\8b\ 1\0\0\0\0\0\0(\0\0\0src/Composer/DependencyResolver/Pool.phpü"\0\0\82{\11`ü"\0\0l\9e\83Ƥ\ 1\0\0\0\0\0\0+\0\0\0src/Composer/DependencyResolver/Problem.php÷\17\0\0\82{\11\17\0\0K\8eX\8b¤\ 1\0\0\0\0\0\0+\0\0\0src/Composer/DependencyResolver/Request.php\83\ 4\0\0\82{\11`\83\ 4\0\0åVP\84¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/DependencyResolver/Rule.php:\19\0\0\82{\11`:\19\0\0=$\19¨¤\ 1\0\0\0\0\0\01\0\0\0src/Composer/DependencyResolver/Rule2Literals.php\17\ 5\0\0\82{\11`\17\ 5\0\0\r\11NS¤\ 1\0\0\0\0\0\0+\0\0\0src/Composer/DependencyResolver/RuleSet.php¨
34 \0\0\82{\11
35 \0\0XÏé¤\ 1\0\0\0\0\0\04\0\0\0src/Composer/DependencyResolver/RuleSetGenerator.php\83\1f\0\0\82{\11`\83\1f\0\0ù\15c\1a¤\ 1\0\0\0\0\0\03\0\0\0src/Composer/DependencyResolver/RuleSetIterator.php\11\ 6\0\0\82{\11`\11\ 6\0\0\9bCü$¤\ 1\0\0\0\0\0\02\0\0\0src/Composer/DependencyResolver/RuleWatchChain.phpi\ 1\0\0\82{\11`i\ 1\0\0\9a\ 1\0\0\0\0\0\02\0\0\0src/Composer/DependencyResolver/RuleWatchGraph.phpÞ\ 6\0\0\82{\11\ 6\0\0ã\983¼¤\ 1\0\0\0\0\0\01\0\0\0src/Composer/DependencyResolver/RuleWatchNode.php\ 4\ 4\0\0\82{\11`\ 4\ 4\0\07§¹!¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/DependencyResolver/Solver.phpF:\0\0\82{\11`F:\0\0\10\93\89¨¤\ 1\0\0\0\0\0\06\0\0\0src/Composer/DependencyResolver/SolverBugException.php\99\ 1\0\0\82{\11`\99\ 1\0\0X\12g6¤\ 1\0\0\0\0\0\0;\0\0\0src/Composer/DependencyResolver/SolverProblemsException.phpô\a\0\0\82{\11\a\0\0×|Ŧ¤\ 1\0\0\0\0\0\0/\0\0\0src/Composer/DependencyResolver/Transaction.phpÔ\13\0\0\82{\11\13\0\0\99\8d^G¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Downloader/ArchiveDownloader.phpÁ      \0\0\82{\11`Á \0\0ÖÞw7¤\ 1\0\0\0\0\0\01\0\0\0src/Composer/Downloader/ChangeReportInterface.phpÌ\0\0\0\82{\11\0\0\0¯à¨¿¤\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Downloader/DownloadManager.php_\15\0\0\82{\11`_\15\0\0\fóøþ¤\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Downloader/DownloaderInterface.phpÊ\ 1\0\0\82{\11\ 1\0\0gs!l¤\ 1\0\0\0\0\0\03\0\0\0src/Composer/Downloader/DvcsDownloaderInterface.phpÑ\0\0\0\82{\11\0\0\0\9c¿¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Downloader/FileDownloader.php>\1c\0\0\82{\11`>\1c\0\0tÀU\98¤\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Downloader/FilesystemException.php
36 \ 1\0\0\82{\11`
37 \ 1\0\0.-\1e\8b¤\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Downloader/FossilDownloader.php\80\v\0\0\82{\11`\80\v\0\0\7f\98\ 6\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Downloader/GitDownloader.phpå6\0\0\82{\11`å6\0\0<'Oפ\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Downloader/GzipDownloader.phpð\ 6\0\0\82{\11\ 6\0\0H\1dá\11¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Downloader/HgDownloader.php\94\b\0\0\82{\11`\94\b\0\0ßis̤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Downloader/PathDownloader.phpJ\15\0\0\82{\11`J\15\0\0)4\ 4פ\ 1\0\0\0\0\0\00\0\0\0src/Composer/Downloader/PearPackageExtractor.phpq\e\0\0\82{\11`q\e\0\0y5+\ 5¤\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Downloader/PerforceDownloader.php\9e\a\0\0\82{\11`\9e\a\0\0Öüñ9¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Downloader/PharDownloader.phpä\0\0\0\82{\11\0\0\0B"2(¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Downloader/RarDownloader.php\9c\a\0\0\82{\11`\9c\a\0\0¸\9a\8f\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Downloader/SvnDownloader.phpK\14\0\0\82{\11`K\14\0\0\8f\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Downloader/TarDownloader.phpâ\0\0\0\82{\11\0\0\0\ 4+«r¤\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Downloader/TransportException.php=\ 2\0\0\82{\11`=\ 2\0\0ZÎÈÞ¤\ 1\0\0\0\0\0\09\0\0\0src/Composer/Downloader/VcsCapableDownloaderInterface.phpÔ\0\0\0\82{\11\0\0\0`§ôö¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Downloader/VcsDownloader.php\98\16\0\0\82{\11`\98\16\0\0ö\9f\86\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Downloader/XzDownloader.php§\ 4\0\0\82{\11\ 4\0\0W$;á¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Downloader/ZipDownloader.phpx\15\0\0\82{\11`x\15\0\0\82MÚH¤\ 1\0\0\0\0\0\0&\0\0\0src/Composer/EventDispatcher/Event.php \ 2\0\0\82{\11\ 2\0\0±\99jï¤\ 1\0\0\0\0\0\00\0\0\0src/Composer/EventDispatcher/EventDispatcher.phpL7\0\0\82{\11`L7\0\0+[¸\8c¤\ 1\0\0\0\0\0\09\0\0\0src/Composer/EventDispatcher/EventSubscriberInterface.php©\0\0\0\82{\11\0\0\0\ 1\ 1\0\0\0\0\0\09\0\0\0src/Composer/EventDispatcher/ScriptExecutionException.phpv\0\0\0\82{\11`v\0\0\0wZ8S¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Exception/NoSslException.phpf\0\0\0\82{\11`f\0\0\0ËíM\9d¤\ 1\0\0\0\0\0\0\18\0\0\0src/Composer/Factory.php#>\0\0\82{\11`#>\0\0\ 2^¡4¤\ 1\0\0\0\0\0\0\1a\0\0\0src/Composer/IO/BaseIO.php\93\12\0\0\82{\11`\93\12\0\0ÔÁf[¤\ 1\0\0\0\0\0\0\1c\0\0\0src/Composer/IO/BufferIO.php½\ 6\0\0\82{\11\ 6\0\0*Äx\87¤\ 1\0\0\0\0\0\0\1d\0\0\0src/Composer/IO/ConsoleIO.php\11\19\0\0\82{\11`\11\19\0\0\88\8fÍ\11¤\ 1\0\0\0\0\0\0\1f\0\0\0src/Composer/IO/IOInterface.phpì\ 5\0\0\82{\11\ 5\0\0\0Õ\9d\ e¤\ 1\0\0\0\0\0\0\1a\0\0\0src/Composer/IO/NullIO.phpÀ\ 4\0\0\82{\11\ 4\0\0F`sʤ\ 1\0\0\0\0\0\0\1a\0\0\0src/Composer/Installer.phpD£\0\0\82{\11`D£\0\0\10{¶Ï¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Installer/BinaryInstaller.php\ 1\12\0\0\82{\11`\ 1\12\0\0a·Á\10¤\ 1\0\0\0\0\0\02\0\0\0src/Composer/Installer/BinaryPresenceInterface.phpË\0\0\0\82{\11\0\0\0À5\9a¨¤\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Installer/InstallationManager.php*\17\0\0\82{\11`*\17\0\0Í\96\85ª¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Installer/InstallerEvent.php\ e\ 6\0\0\82{\11`\ e\ 6\0\0lÔzi¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Installer/InstallerEvents.phpÞ\0\0\0\82{\11\0\0\0ì\9f@G¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Installer/InstallerInterface.phpã\ 2\0\0\82{\11\ 2\0\0^\83\93ʤ\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Installer/LibraryInstaller.php"\14\0\0\82{\11`"\14\0\0?¦@¬¤\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Installer/MetapackageInstaller.phpÊ\a\0\0\82{\11\a\0\0Ùti·¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Installer/NoopInstaller.php+\ 5\0\0\82{\11`+\ 5\0\0À·M}¤\ 1\0\0\0\0\0\0'\0\0\0src/Composer/Installer/PackageEvent.phpe\ 3\0\0\82{\11`e\ 3\0\0;° \1a¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Installer/PackageEvents.php¸\ 1\0\0\82{\11\ 1\0\0dbØs¤\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Installer/PearBinaryInstaller.phpø\f\0\0\82{\11\f\0\0\95\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Installer/PearInstaller.php¢\a\0\0\82{\11\a\0\0È\82¶Ñ¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Installer/PluginInstaller.php¡\ 6\0\0\82{\11\ 6\0\0¤õÏܤ\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Installer/ProjectInstaller.php\1d\ 6\0\0\82{\11`\1d\ 6\0\0*0@P¤\ 1\0\0\0\0\0\04\0\0\0src/Composer/Installer/SuggestedPackagesReporter.php:\a\0\0\82{\11`:\a\0\0\82´UV¤\ 1\0\0\0\0\0\0\1e\0\0\0src/Composer/Json/JsonFile.phpJ\15\0\0\82{\11`J\15\0\0\8a\ 1\0\0\0\0\0\0#\0\0\0src/Composer/Json/JsonFormatter.phpW\ 6\0\0\82{\11`W\ 6\0\0uüb\8c¤\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Json/JsonManipulator.phpv4\0\0\82{\11`v4\0\0\18­¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Json/JsonValidationException.php\\ 1\0\0\82{\11`\\ 1\0\0.Xóܤ\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Package/AliasPackage.phpí\17\0\0\82{\11\17\0\0\98J¸X¤\ 1\0\0\0\0\0\07\0\0\0src/Composer/Package/Archiver/ArchivableFilesFilter.php    \ 2\0\0\82{\11\ 2\0\0yY+¦¤\ 1\0\0\0\0\0\07\0\0\0src/Composer/Package/Archiver/ArchivableFilesFinder.phpæ\ 5\0\0\82{\11\ 5\0\0U`\eƤ\ 1\0\0\0\0\0\00\0\0\0src/Composer/Package/Archiver/ArchiveManager.phpÕ\f\0\0\82{\11\f\0\0q^Z\90¤\ 1\0\0\0\0\0\03\0\0\0src/Composer/Package/Archiver/ArchiverInterface.php\a\ 1\0\0\82{\11`\a\ 1\0\0ñ´>\v¤\ 1\0\0\0\0\0\03\0\0\0src/Composer/Package/Archiver/BaseExcludeFilter.php\96\ 6\0\0\82{\11`\96\ 6\0\0v,ÝФ\ 1\0\0\0\0\0\07\0\0\0src/Composer/Package/Archiver/ComposerExcludeFilter.php\1f\ 1\0\0\82{\11`\1f\ 1\0\0\8bSZ0¤\ 1\0\0\0\0\0\02\0\0\0src/Composer/Package/Archiver/GitExcludeFilter.phpr\ 3\0\0\82{\11`r\ 3\0\03\91Mh¤\ 1\0\0\0\0\0\01\0\0\0src/Composer/Package/Archiver/HgExcludeFilter.php
38 \ 5\0\0\82{\11`
39 \ 5\0\0&ðm(¤\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Package/Archiver/PharArchiver.php8\ 6\0\0\82{\11`8\ 6\0\0Fx'M¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Package/Archiver/ZipArchiver.phpX\ 5\0\0\82{\11`X\ 5\0\0¤k\9d\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Package/BasePackage.php\b\ e\0\0\82{\11`\b\ e\0\0r\97F«¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Package/Comparer/Comparer.php½\b\0\0\82{\11\b\0\0¡fK}¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Package/CompletePackage.php¦\a\0\0\82{\11\a\0\0p[\ 3Ö¤\ 1\0\0\0\0\0\01\0\0\0src/Composer/Package/CompletePackageInterface.php\e\ 2\0\0\82{\11`\e\ 2\0\0Î\12«>¤\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Package/Dumper/ArrayDumper.phpb\f\0\0\82{\11`b\f\0\0s\95°\9b¤\ 1\0\0\0\0\0\0\1d\0\0\0src/Composer/Package/Link.php\88\ 5\0\0\82{\11`\88\ 5\0\0å¶Y«¤\ 1\0\0\0\0\0\07\0\0\0src/Composer/Package/LinkConstraint/EmptyConstraint.php\82\ 1\0\0\82{\11`\82\ 1\0\0\ eé~\8b¤\ 1\0\0\0\0\0\0?\0\0\0src/Composer/Package/LinkConstraint/LinkConstraintInterface.phpd\ 1\0\0\82{\11`d\ 1\0\0¤ôLn¤\ 1\0\0\0\0\0\07\0\0\0src/Composer/Package/LinkConstraint/MultiConstraint.php\82\ 1\0\0\82{\11`\82\ 1\0\0ób`ý¤\ 1\0\0\0\0\0\0:\0\0\0src/Composer/Package/LinkConstraint/SpecificConstraint.phpi\ 1\0\0\82{\11`i\ 1\0\0Þ\94\9a\ 1\0\0\0\0\0\09\0\0\0src/Composer/Package/LinkConstraint/VersionConstraint.phpX\ 1\0\0\82{\11`X\ 1\0\0\ 2}`y¤\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Package/Loader/ArrayLoader.phpô\1e\0\0\82{\11\1e\0\0\11h°ª¤\ 1\0\0\0\0\0\07\0\0\0src/Composer/Package/Loader/InvalidPackageException.phpE\ 2\0\0\82{\11`E\ 2\0\0xb\13¾¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Package/Loader/JsonLoader.phpù\ 1\0\0\82{\11\ 1\0\0!~\88\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Package/Loader/LoaderInterface.php²\0\0\0\82{\11\0\0\0¦}úΤ\ 1\0\0\0\0\0\01\0\0\0src/Composer/Package/Loader/RootPackageLoader.phpÆ\1a\0\0\82{\11\1a\0\0\99£ã\9b¤\ 1\0\0\0\0\0\05\0\0\0src/Composer/Package/Loader/ValidatingArrayLoader.phpâA\0\0\82{\11`âA\0\0\1c\91É\98¤\ 1\0\0\0\0\0\0\1f\0\0\0src/Composer/Package/Locker.php\11#\0\0\82{\11`\11#\0\0»ÀÎí¤\ 1\0\0\0\0\0\0 \0\0\0src/Composer/Package/Package.phpÉ\1a\0\0\82{\11\1a\0\0\8f\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Package/PackageInterface.php\\b\0\0\82{\11`\\b\0\0xåp¨¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Package/RootAliasPackage.php\1f        \0\0\82{\11`\1f \0\0      _\80ø¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Package/RootPackage.php\11\ 5\0\0\82{\11`\11\ 5\0\0\ 2\8eÎ_¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Package/RootPackageInterface.php¹\ 3\0\0\82{\11\ 3\0\0"maV¤\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Package/Version/VersionGuesser.phpÏ#\0\0\82{\11`Ï#\0\0@»å'¤\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Package/Version/VersionParser.php¥\ 5\0\0\82{\11\ 5\0\0ô´\16à¤\ 1\0\0\0\0\0\00\0\0\0src/Composer/Package/Version/VersionSelector.php\9a\ e\0\0\82{\11`\9a\ e\0\0ô¥×¥¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Plugin/Capability/Capability.phpW\0\0\0\82{\11`W\0\0\0æ_¨1¤\ 1\0\0\0\0\0\02\0\0\0src/Composer/Plugin/Capability/CommandProvider.php\97\0\0\0\82{\11`\97\0\0\0ûOâ>¤\ 1\0\0\0\0\0\0\1f\0\0\0src/Composer/Plugin/Capable.php\7f\0\0\0\82{\11`\7f\0\0\0Æq\15\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Plugin/CommandEvent.phpâ\ 2\0\0\82{\11\ 2\0\0³ÆÇW¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Plugin/PluginEvents.phpö\0\0\0\82{\11\0\0\0á1=z¤\ 1\0\0\0\0\0\0'\0\0\0src/Composer/Plugin/PluginInterface.phpô\0\0\0\82{\11\0\0\0)'*ؤ\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Plugin/PluginManager.php¨$\0\0\82{\11`¨$\0\03 :\90¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Plugin/PreCommandRunEvent.phpõ\ 1\0\0\82{\11\ 1\0\0:ðd\1e¤\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Plugin/PreFileDownloadEvent.php`\ 2\0\0\82{\11``\ 2\0\0\09-Τ\ 1\0\0\0\0\0\04\0\0\0src/Composer/Question/StrictConfirmationQuestion.php\1e\ 5\0\0\82{\11`\1e\ 5\0\0'.³è¤\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Repository/ArrayRepository.php©\ e\0\0\82{\11\ e\0\0Â\92/Ƥ\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Repository/ArtifactRepository.phpí\b\0\0\82{\11\b\0\0q9OS¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Repository/BaseRepository.phpU\10\0\0\82{\11`U\10\0\0{<\9f\16¤\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Repository/ComposerRepository.php5U\0\0\82{\11`5U\0\0¾øU&¤\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Repository/CompositeRepository.php;\b\0\0\82{\11`;\b\0\0¤¯S\1f¤\ 1\0\0\0\0\0\0;\0\0\0src/Composer/Repository/ConfigurableRepositoryInterface.php\85\0\0\0\82{\11`\85\0\0\0±\9f_\1c¤\ 1\0\0\0\0\0\00\0\0\0src/Composer/Repository/FilesystemRepository.phpo\ 5\0\0\82{\11`o\ 5\0\0åè¼\9e¤\ 1\0\0\0\0\0\04\0\0\0src/Composer/Repository/InstalledArrayRepository.php£\0\0\0\82{\11\0\0\0/ö~>¤\ 1\0\0\0\0\0\09\0\0\0src/Composer/Repository/InstalledFilesystemRepository.php£\0\0\0\82{\11\0\0\0V
40 \95\ 1\0\0\0\0\0\08\0\0\0src/Composer/Repository/InstalledRepositoryInterface.php\87\0\0\0\82{\11`\87\0\0\0\18£9p¤\ 1\0\0\0\0\0\06\0\0\0src/Composer/Repository/InvalidRepositoryException.phpn\0\0\0\82{\11`n\0\0\0à\93ë\98¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Repository/PackageRepository.phpi\ 3\0\0\82{\11`i\ 3\0\0\82\ 1\b\96¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Repository/PathRepository.php¬\ f\0\0\82{\11\ f\0\0ÐU\91\ 1\0\0\0\0\0\02\0\0\0src/Composer/Repository/Pear/BaseChannelReader.phpH\ 5\0\0\82{\11`H\ 5\0\0\vÁÚ\8b¤\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Repository/Pear/ChannelInfo.phpÄ\ 1\0\0\82{\11\ 1\0\0:T*ɤ\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Repository/Pear/ChannelReader.phpë\ 6\0\0\82{\11\ 6\0\0åÄLi¤\ 1\0\0\0\0\0\04\0\0\0src/Composer/Repository/Pear/ChannelRest10Reader.php®        \0\0\82{\11`® \0\0\99ÖÛú¤\ 1\0\0\0\0\0\04\0\0\0src/Composer/Repository/Pear/ChannelRest11Reader.php& \0\0\82{\11`& \0\0òUb\b¤\ 1\0\0\0\0\0\05\0\0\0src/Composer/Repository/Pear/DependencyConstraint.phpq\ 2\0\0\82{\11`q\ 2\0\09\ e\17\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Repository/Pear/DependencyInfo.phpq\ 1\0\0\82{\11`q\ 1\0\0fºTò¤\ 1\0\0\0\0\0\08\0\0\0src/Composer/Repository/Pear/PackageDependencyParser.php\83\16\0\0\82{\11`\83\16\0\0ð\90\93\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Repository/Pear/PackageInfo.php°\ 3\0\0\82{\11\ 3\0\0\9f\r¸\f¤\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Repository/Pear/ReleaseInfo.php\92\ 1\0\0\82{\11`\92\ 1\0\0o\93\8aä\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Repository/PearRepository.php¥\16\0\0\82{\11\16\0\0ç\ f|5¤\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Repository/PlatformRepository.php)!\0\0\82{\11`)!\0\0À(\87ߤ\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Repository/RepositoryFactory.phpa\13\0\0\82{\11`a\13\0\0lÂéÔ¤\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Repository/RepositoryInterface.phpÛ\ 1\0\0\82{\11\ 1\0\0\92\11âÁ¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Repository/RepositoryManager.phpM\v\0\0\82{\11`M\v\0\0<(;\8c¤\ 1\0\0\0\0\0\07\0\0\0src/Composer/Repository/RepositorySecurityException.phpo\0\0\0\82{\11`o\0\0\0pÕ«ª¤\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Repository/Vcs/BitbucketDriver.php~ \0\0\82{\11`~ \0\0Ebºå¤\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Repository/Vcs/FossilDriver.php«\13\0\0\82{\11\13\0\0&âƧ¤\ 1\0\0\0\0\0\02\0\0\0src/Composer/Repository/Vcs/GitBitbucketDriver.phpë\ 5\0\0\82{\11\ 5\0\0\9c´½X¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Repository/Vcs/GitDriver.php7\13\0\0\82{\11`7\13\0\0lj'N¤\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Repository/Vcs/GitHubDriver.php\834\0\0\82{\11`\834\0\0:0G\b¤\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Repository/Vcs/GitLabDriver.php}*\0\0\82{\11`}*\0\0d\8fer¤\ 1\0\0\0\0\0\01\0\0\0src/Composer/Repository/Vcs/HgBitbucketDriver.phpå\ 5\0\0\82{\11\ 5\0\0@)\89\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Repository/Vcs/HgDriver.php<\12\0\0\82{\11`<\12\0\0çæ>V¤\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Repository/Vcs/PerforceDriver.phpù        \0\0\82{\11`ù \0\0&½tÙ¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Repository/Vcs/SvnDriver.php\9b\1c\0\0\82{\11`\9b\1c\0\0\ 2в]¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Repository/Vcs/VcsDriver.phpæ
41 \0\0\82{\11
42 \0\0eׯ-¤\ 1\0\0\0\0\0\02\0\0\0src/Composer/Repository/Vcs/VcsDriverInterface.php÷\ 2\0\0\82{\11\ 2\0\0ÇX[\89¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Repository/VcsRepository.php\8e-\0\0\82{\11`\8e-\0\0÷ï\rì¤\ 1\0\0\0\0\0\01\0\0\0src/Composer/Repository/VersionCacheInterface.php\94\0\0\0\82{\11`\94\0\0\0A?Rï¤\ 1\0\0\0\0\0\03\0\0\0src/Composer/Repository/WritableArrayRepository.php\r\ 3\0\0\82{\11`\r\ 3\0\0¤3¶¢¤\ 1\0\0\0\0\0\07\0\0\0src/Composer/Repository/WritableRepositoryInterface.php\89\ 1\0\0\82{\11`\89\ 1\0\0\91/sï¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Script/CommandEvent.phpW\0\0\0\82{\11`W\0\0\0£VZt¤\ 1\0\0\0\0\0\0\1d\0\0\0src/Composer/Script/Event.phpº\ 4\0\0\82{\11\ 4\0\0ò\9d»¤¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Script/PackageEvent.php\9c\0\0\0\82{\11`\9c\0\0\0§ÿÉ\r¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Script/ScriptEvents.phpP\ 4\0\0\82{\11`P\ 4\0\0\87\8f\ 4¶¤\ 1\0\0\0\0\0\0 \0\0\0src/Composer/SelfUpdate/Keys.php\9c\ 1\0\0\82{\11`\9c\ 1\0\0ze\83\8e¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/SelfUpdate/Versions.phpH\a\0\0\82{\11`H\a\0\0c\vlB¤\ 1\0\0\0\0\0\0 \0\0\0src/Composer/Util/AuthHelper.phpË\ 3\0\0\82{\11\ 3\0\0>zx\96¤\ 1\0\0\0\0\0\0\1f\0\0\0src/Composer/Util/Bitbucket.php%\15\0\0\82{\11`%\15\0\0N,vÕ¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Util/ComposerMirror.php±\ 4\0\0\82{\11\ 4\0\0­½øؤ\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Util/ConfigValidator.phpà\15\0\0\82{\11\15\0\0¯º`\97¤\ 1\0\0\0\0\0\0"\0\0\0src/Composer/Util/ErrorHandler.phpº\ 4\0\0\82{\11\ 4\0\0\14ª\17\13¤\ 1\0\0\0\0\0\0 \0\0\0src/Composer/Util/Filesystem.php`/\0\0\82{\11``/\0\0ÓJ\89\ 1\0\0\0\0\0\0\19\0\0\0src/Composer/Util/Git.phpï0\0\0\82{\11`ï0\0\0\92V\96\82¤\ 1\0\0\0\0\0\0\1c\0\0\0src/Composer/Util/GitHub.phpz\r\0\0\82{\11`z\r\0\0\13\f!Ò¤\ 1\0\0\0\0\0\0\1c\0\0\0src/Composer/Util/GitLab.phpó\ e\0\0\82{\11\ e\0\0^\1e      '¤\ 1\0\0\0\0\0\0\18\0\0\0src/Composer/Util/Hg.php¼\a\0\0\82{\11\a\0\0\83]\18\ 1\0\0\0\0\0\0\1f\0\0\0src/Composer/Util/IniHelper.phph\ 2\0\0\82{\11`h\ 2\0\0;F\b\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Util/NoProxyPattern.phpr\14\0\0\82{\11`r\14\0\0\e\9c´R¤\ 1\0\0\0\0\0\0#\0\0\0src/Composer/Util/PackageSorter.phpÜ\ 5\0\0\82{\11\ 5\0\0w\88Ôâ¤\ 1\0\0\0\0\0\0\1e\0\0\0src/Composer/Util/Perforce.php¶2\0\0\82{\11`¶2\0\0ßÑvT¤\ 1\0\0\0\0\0\0\1e\0\0\0src/Composer/Util/Platform.phpû\ 4\0\0\82{\11\ 4\0\0ñ®\8f\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Util/ProcessExecutor.php\e\r\0\0\82{\11`\e\r\0\0F\9f¹\ 6¤\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Util/RemoteFilesystem.phpRr\0\0\82{\11`Rr\0\0à¹\96\10¤\ 1\0\0\0\0\0\0\1e\0\0\0src/Composer/Util/Silencer.phpè\ 2\0\0\82{\11\ 2\0\0¿5ѳ¤\ 1\0\0\0\0\0\0!\0\0\0src/Composer/Util/SpdxLicense.php\ 3\ 1\0\0\82{\11`\ 3\ 1\0\0¾7
43 ñ¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Util/StreamContextFactory.phpú\ f\0\0\82{\11\ f\0\00K\9a\ 1\0\0\0\0\0\0\19\0\0\0src/Composer/Util/Svn.php$\14\0\0\82{\11`$\14\0\0w!Áö¤\ 1\0\0\0\0\0\0\1f\0\0\0src/Composer/Util/TlsHelper.phpH
44 \0\0\82{\11`H
45 \0\0Ì\ 6Ú\ f¤\ 1\0\0\0\0\0\0\19\0\0\0src/Composer/Util/Url.php\9e\a\0\0\82{\11`\9e\a\0\0qµkQ¤\ 1\0\0\0\0\0\0\19\0\0\0src/Composer/Util/Zip.php¯\ 5\0\0\82{\11\ 5\0\0ti¸Î¤\ 1\0\0\0\0\0\0\1e\0\0\0src/Composer/XdebugHandler.phpð\ 1\0\0\82{\11\ 1\0\0zÓf~¤\ 1\0\0\0\0\0\0\11\0\0\0src/bootstrap.php¹\ 1\0\0\82{\11\ 1\0\0\15I}\9c¤\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Autoload/ClassLoader.php¡4\0\0\82{\11`¡4\0\0Þs\85\ 1\0\0\0\0\0\0#\0\0\0res/composer-repository-schema.jsonð\ f\0\0\82{\11\ f\0\0\81GÐà¤\ 1\0\0\0\0\0\0\18\0\0\0res/composer-schema.jsonM\9d\0\0\82{\11`M\9d\0\0U|Û\b¤\ 1\0\0\0\0\0\06\0\0\0vendor/composer/spdx-licenses/res/spdx-exceptions.json¸\v\0\0\82{\11\v\0\0Â4DC¤\ 1\0\0\0\0\0\04\0\0\0vendor/composer/spdx-licenses/res/spdx-licenses.jsonu°\0\0\82{\11`u°\0\0\9bý\85\ 1\0\0\0\0\0\04\0\0\0vendor/symfony/console/Resources/bin/hiddeninput.exe\0$\0\0\82{\11`\0$\0\0\95\8d¥v¤\ 1\0\0\0\0\0\0D\0\0\0vendor/symfony/polyfill-mbstring/Resources/mb_convert_variables.php8?\ 3\0\0\82{\11`?\ 3\0\0ò\16ï ¤\ 1\0\0\0\0\0\0&\0\0\0vendor/symfony/console/Application.php+X\0\0\82{\11`+X\0\0«­yX¤\ 1\0\0\0\0\0\0*\0\0\0vendor/symfony/console/Command/Command.phpä"\0\0\82{\11`ä"\0\0\90¤Ê¤\ 1\0\0\0\0\0\0.\0\0\0vendor/symfony/console/Command/HelpCommand.phpØ\a\0\0\82{\11\a\0\0¦Ú-:¤\ 1\0\0\0\0\0\0.\0\0\0vendor/symfony/console/Command/ListCommand.phpZ\b\0\0\82{\11`Z\b\0\0»w\ 4\ 1\0\0\0\0\0\0(\0\0\0vendor/symfony/console/ConsoleEvents.phpé\0\0\0\82{\11\0\0\0RÛÔe¤\ 1\0\0\0\0\0\0<\0\0\0vendor/symfony/console/Descriptor/ApplicationDescription.phpÏ\b\0\0\82{\11\b\0\0<\8eUî¤\ 1\0\0\0\0\0\00\0\0\0vendor/symfony/console/Descriptor/Descriptor.php\8f\a\0\0\82{\11`\8f\a\0\0¿N\ f\95¤\ 1\0\0\0\0\0\09\0\0\0vendor/symfony/console/Descriptor/DescriptorInterface.phpü\0\0\0\82{\11\0\0\0±Q\aµ¤\ 1\0\0\0\0\0\04\0\0\0vendor/symfony/console/Descriptor/JsonDescriptor.phpÜ\r\0\0\82{\11\r\0\0\9dɤ\ 1\0\0\0\0\0\08\0\0\0vendor/symfony/console/Descriptor/MarkdownDescriptor.php¶\ e\0\0\82{\11\ e\0\0·Ô;ݤ\ 1\0\0\0\0\0\04\0\0\0vendor/symfony/console/Descriptor/TextDescriptor.php·\1e\0\0\82{\11\1e\0\0c\93q\80¤\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/console/Descriptor/XmlDescriptor.php\ 1\1c\0\0\82{\11`\ 1\1c\0\0\7fb{<¤\ 1\0\0\0\0\0\04\0\0\0vendor/symfony/console/Event/ConsoleCommandEvent.php°\ 1\0\0\82{\11\ 1\0\0\a!\0Ȥ\ 1\0\0\0\0\0\0-\0\0\0vendor/symfony/console/Event/ConsoleEvent.phpÅ\ 2\0\0\82{\11\ 2\0\0ÒxÛ\¤\ 1\0\0\0\0\0\06\0\0\0vendor/symfony/console/Event/ConsoleExceptionEvent.php\12\ 3\0\0\82{\11`\12\ 3\0\0á\162é¤\ 1\0\0\0\0\0\06\0\0\0vendor/symfony/console/Event/ConsoleTerminateEvent.phpz\ 2\0\0\82{\11`z\ 2\0\0³,îL¤\ 1\0\0\0\0\0\0=\0\0\0vendor/symfony/console/Exception/CommandNotFoundException.phpÔ\ 1\0\0\82{\11\ 1\0\0È÷ L¤\ 1\0\0\0\0\0\07\0\0\0vendor/symfony/console/Exception/ExceptionInterface.phpf\0\0\0\82{\11`f\0\0\0¡ABª¤\ 1\0\0\0\0\0\0=\0\0\0vendor/symfony/console/Exception/InvalidArgumentException.php¦\0\0\0\82{\11\0\0\0Ö̽Z¤\ 1\0\0\0\0\0\0;\0\0\0vendor/symfony/console/Exception/InvalidOptionException.php¦\0\0\0\82{\11\0\0\0\13Ë×H¤\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/console/Exception/LogicException.php\92\0\0\0\82{\11`\92\0\0\0ÍO\e¤\ 1\0\0\0\0\0\05\0\0\0vendor/symfony/console/Exception/RuntimeException.php\96\0\0\0\82{\11`\96\0\0\0Ùí,6¤\ 1\0\0\0\0\0\04\0\0\0vendor/symfony/console/Formatter/OutputFormatter.php3\ e\0\0\82{\11`3\ e\0\0\11à\10פ\ 1\0\0\0\0\0\0=\0\0\0vendor/symfony/console/Formatter/OutputFormatterInterface.php\8c\ 1\0\0\82{\11`\8c\ 1\0\0òññÀ¤\ 1\0\0\0\0\0\09\0\0\0vendor/symfony/console/Formatter/OutputFormatterStyle.phpF\10\0\0\82{\11`F\10\0\0\1d𦴤\ 1\0\0\0\0\0\0B\0\0\0vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php\84\ 1\0\0\82{\11`\84\ 1\0\0÷½\10\ 1\0\0\0\0\0\0>\0\0\0vendor/symfony/console/Formatter/OutputFormatterStyleStack.php@\ 5\0\0\82{\11`@\ 5\0\0G¨ýU¤\ 1\0\0\0\0\0\06\0\0\0vendor/symfony/console/Helper/DebugFormatterHelper.phpy\b\0\0\82{\11`y\b\0\0Ì8ÆФ\ 1\0\0\0\0\0\02\0\0\0vendor/symfony/console/Helper/DescriptorHelper.phpw\ 5\0\0\82{\11`w\ 5\0\0\ 1\ 1\0\0\0\0\0\0.\0\0\0vendor/symfony/console/Helper/DialogHelper.phpð\1e\0\0\82{\11\1e\0\0ÔÈ\16\ 1\0\0\0\0\0\01\0\0\0vendor/symfony/console/Helper/FormatterHelper.phpd\ 4\0\0\82{\11`d\ 4\0\0§×,¸¤\ 1\0\0\0\0\0\0(\0\0\0vendor/symfony/console/Helper/Helper.php©\a\0\0\82{\11\a\0\0Õ'\83±¤\ 1\0\0\0\0\0\01\0\0\0vendor/symfony/console/Helper/HelperInterface.phpå\0\0\0\82{\11\0\0\0\1f\8a \18¤\ 1\0\0\0\0\0\0+\0\0\0vendor/symfony/console/Helper/HelperSet.phpÊ\a\0\0\82{\11\a\0\0áÏW"¤\ 1\0\0\0\0\0\02\0\0\0vendor/symfony/console/Helper/InputAwareHelper.phpc\ 1\0\0\82{\11`c\ 1\0\0\ 6Ìø\83¤\ 1\0\0\0\0\0\0/\0\0\0vendor/symfony/console/Helper/ProcessHelper.phpÓ       \0\0\82{\11`Ó \0\0©w\82\ 1\0\0\0\0\0\0-\0\0\0vendor/symfony/console/Helper/ProgressBar.phpc%\0\0\82{\11`c%\0\0C\e&w¤\ 1\0\0\0\0\0\00\0\0\0vendor/symfony/console/Helper/ProgressHelper.phpY\e\0\0\82{\11`Y\e\0\0R!\8f\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/console/Helper/ProgressIndicator.phpM\14\0\0\82{\11`M\14\0\0ü\8d\b\87¤\ 1\0\0\0\0\0\00\0\0\0vendor/symfony/console/Helper/QuestionHelper.php[\1d\0\0\82{\11`[\1d\0\0¯6}ñ¤\ 1\0\0\0\0\0\07\0\0\0vendor/symfony/console/Helper/SymfonyQuestionHelper.php\95
46 \0\0\82{\11`\95
47 \0\0\0]~R¤\ 1\0\0\0\0\0\0'\0\0\0vendor/symfony/console/Helper/Table.php¼*\0\0\82{\11`¼*\0\0fêý!¤\ 1\0\0\0\0\0\0+\0\0\0vendor/symfony/console/Helper/TableCell.php\80\ 3\0\0\82{\11`\80\ 3\0\0\8b\83[\ e¤\ 1\0\0\0\0\0\0-\0\0\0vendor/symfony/console/Helper/TableHelper.php\ e\f\0\0\82{\11`\ e\f\0\0\9b\99¤\ 1\0\0\0\0\0\00\0\0\0vendor/symfony/console/Helper/TableSeparator.phpÊ\0\0\0\82{\11\0\0\0az\1f\1c¤\ 1\0\0\0\0\0\0,\0\0\0vendor/symfony/console/Helper/TableStyle.php 
48 \0\0\82{\11
49 \0\0_ÍI"¤\ 1\0\0\0\0\0\0*\0\0\0vendor/symfony/console/Input/ArgvInput.php\ 1\16\0\0\82{\11`\ 1\16\0\0ªèB-¤\ 1\0\0\0\0\0\0+\0\0\0vendor/symfony/console/Input/ArrayInput.php)\v\0\0\82{\11`)\v\0\0¥Ñ\ 6\ 1\0\0\0\0\0\0&\0\0\0vendor/symfony/console/Input/Input.php£\v\0\0\82{\11\v\0\0\13f¡?¤\ 1\0\0\0\0\0\0.\0\0\0vendor/symfony/console/Input/InputArgument.php\12\ 6\0\0\82{\11`\12\ 6\0\0D\r£\ 6¤\ 1\0\0\0\0\0\04\0\0\0vendor/symfony/console/Input/InputAwareInterface.php\98\0\0\0\82{\11`\98\0\0\0­\ fO°¤\ 1\0\0\0\0\0\00\0\0\0vendor/symfony/console/Input/InputDefinition.php\86\19\0\0\82{\11`\86\19\0\0¤U)¤¤\ 1\0\0\0\0\0\0/\0\0\0vendor/symfony/console/Input/InputInterface.php£\ 3\0\0\82{\11\ 3\0\0ÆB\8c\ 1\0\0\0\0\0\0,\0\0\0vendor/symfony/console/Input/InputOption.php\14\f\0\0\82{\11`\14\f\0\0\¢Ü=¤\ 1\0\0\0\0\0\0,\0\0\0vendor/symfony/console/Input/StringInput.php\99\ 6\0\0\82{\11`\99\ 6\0\0{\8a\9cþ¤\ 1\0\0\0\0\0\0\1e\0\0\0vendor/symfony/console/LICENSE)\ 4\0\0\82{\11`)\ 4\0\0NUN½¤\ 1\0\0\0\0\0\0/\0\0\0vendor/symfony/console/Logger/ConsoleLogger.php-    \0\0\82{\11`- \0\0ghT\9b¤\ 1\0\0\0\0\0\00\0\0\0vendor/symfony/console/Output/BufferedOutput.php_\ 1\0\0\82{\11`_\ 1\0\0\8b >P¤\ 1\0\0\0\0\0\0/\0\0\0vendor/symfony/console/Output/ConsoleOutput.php±\a\0\0\82{\11\a\0\0nì!f¤\ 1\0\0\0\0\0\08\0\0\0vendor/symfony/console/Output/ConsoleOutputInterface.phpà\0\0\0\82{\11\0\0\0\87\86Æʤ\ 1\0\0\0\0\0\0,\0\0\0vendor/symfony/console/Output/NullOutput.phpÉ\ 3\0\0\82{\11\ 3\0\0\990ïf¤\ 1\0\0\0\0\0\0(\0\0\0vendor/symfony/console/Output/Output.php\98  \0\0\82{\11`\98 \0\00p\ 4\b¤\ 1\0\0\0\0\0\01\0\0\0vendor/symfony/console/Output/OutputInterface.php\17\ 3\0\0\82{\11`\17\ 3\0\0\0ì\ 6\ 1\0\0\0\0\0\0.\0\0\0vendor/symfony/console/Output/StreamOutput.php\9b\ 6\0\0\82{\11`\9b\ 6\0\0.¡îî¤\ 1\0\0\0\0\0\02\0\0\0vendor/symfony/console/Question/ChoiceQuestion.phpv
50 \0\0\82{\11`v
51 \0\0\8b²WP¤\ 1\0\0\0\0\0\08\0\0\0vendor/symfony/console/Question/ConfirmationQuestion.phpè\ 2\0\0\82{\11\ 2\0\0/\1dÔ\8f¤\ 1\0\0\0\0\0\0,\0\0\0vendor/symfony/console/Question/Question.phpΠ    \0\0\82{\11`Π\0\0lF\ f\10¤\ 1\0\0\0\0\0\0 \0\0\0vendor/symfony/console/Shell.phpã\ f\0\0\82{\11\ f\0\0\89Á\8eå¤\ 1\0\0\0\0\0\0,\0\0\0vendor/symfony/console/Style/OutputStyle.php\\ 5\0\0\82{\11`\\ 5\0\0wפ\ 4¤\ 1\0\0\0\0\0\0/\0\0\0vendor/symfony/console/Style/StyleInterface.phpÏ\ 3\0\0\82{\11\ 3\0\0&nÅѤ\ 1\0\0\0\0\0\0-\0\0\0vendor/symfony/console/Style/SymfonyStyle.phpÛ\1f\0\0\82{\11\1f\0\0§ðcä¤\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/console/Tester/ApplicationTester.phpÏ\ 5\0\0\82{\11\ 5\0\0s\9e9i¤\ 1\0\0\0\0\0\0/\0\0\0vendor/symfony/console/Tester/CommandTester.php¨\ 6\0\0\82{\11\ 6\0\0\7f<\9c\95¤\ 1\0\0\0\0\0\0(\0\0\0vendor/symfony/debug/BufferingLogger.phpt\ 1\0\0\82{\11`t\ 1\0\0=\0hܤ\ 1\0\0\0\0\0\0\1e\0\0\0vendor/symfony/debug/Debug.php+\ 3\0\0\82{\11`+\ 3\0\0.À=©¤\ 1\0\0\0\0\0\0)\0\0\0vendor/symfony/debug/DebugClassLoader.php°\1d\0\0\82{\11\1d\0\0^æ*ñ¤\ 1\0\0\0\0\0\0%\0\0\0vendor/symfony/debug/ErrorHandler.phpýG\0\0\82{\11`ýG\0\0¿zL\1d¤\ 1\0\0\0\0\0\09\0\0\0vendor/symfony/debug/Exception/ClassNotFoundException.php\96\ 1\0\0\82{\11`\96\ 1\0\0i\89æô¤\ 1\0\0\0\0\0\08\0\0\0vendor/symfony/debug/Exception/ContextErrorException.php\98\ 1\0\0\82{\11`\98\ 1\0\0-
52 d2¤\ 1\0\0\0\0\0\01\0\0\0vendor/symfony/debug/Exception/DummyException.php\ 2\ 1\0\0\82{\11`\ 2\ 1\0\0®+Ãê¤\ 1\0\0\0\0\0\06\0\0\0vendor/symfony/debug/Exception/FatalErrorException.php\f\a\0\0\82{\11`\f\a\0\04ç$¤¤\ 1\0\0\0\0\0\06\0\0\0vendor/symfony/debug/Exception/FatalThrowableError.phpW\ 2\0\0\82{\11`W\ 2\0\0?àèK¤\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/debug/Exception/FlattenException.php»\16\0\0\82{\11\16\0\0+a&\11¤\ 1\0\0\0\0\0\07\0\0\0vendor/symfony/debug/Exception/OutOfMemoryException.php~\0\0\0\82{\11`~\0\0\0ë¨oâ¤\ 1\0\0\0\0\0\0=\0\0\0vendor/symfony/debug/Exception/UndefinedFunctionException.php\9a\ 1\0\0\82{\11`\9a\ 1\0\0\81ñJÀ¤\ 1\0\0\0\0\0\0;\0\0\0vendor/symfony/debug/Exception/UndefinedMethodException.php\98\ 1\0\0\82{\11`\98\ 1\0\0nöêؤ\ 1\0\0\0\0\0\0)\0\0\0vendor/symfony/debug/ExceptionHandler.php$3\0\0\82{\11`$3\0\0Eë×£¤\ 1\0\0\0\0\0\0I\0\0\0vendor/symfony/debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php5\12\0\0\82{\11`5\12\0\0\8aÁ*V¤\ 1\0\0\0\0\0\0E\0\0\0vendor/symfony/debug/FatalErrorHandler/FatalErrorHandlerInterface.php\ 3\ 1\0\0\82{\11`\ 3\ 1\0\0ĹBV¤\ 1\0\0\0\0\0\0M\0\0\0vendor/symfony/debug/FatalErrorHandler/UndefinedFunctionFatalErrorHandler.phpx\b\0\0\82{\11`x\b\0\0~ò"\7f¤\ 1\0\0\0\0\0\0K\0\0\0vendor/symfony/debug/FatalErrorHandler/UndefinedMethodFatalErrorHandler.phpN\ 5\0\0\82{\11`N\ 5\0\0'\80³\88¤\ 1\0\0\0\0\0\0\1c\0\0\0vendor/symfony/debug/LICENSE)\ 4\0\0\82{\11`)\ 4\0\0NUN½¤\ 1\0\0\0\0\0\0:\0\0\0vendor/symfony/filesystem/Exception/ExceptionInterface.phpi\0\0\0\82{\11`i\0\0\0$ ÿ\9b¤\ 1\0\0\0\0\0\0=\0\0\0vendor/symfony/filesystem/Exception/FileNotFoundException.php¼\ 1\0\0\82{\11\ 1\0\0pí\¶¤\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/filesystem/Exception/IOException.php\87\ 1\0\0\82{\11`\87\ 1\0\0\80ü#Ѥ\ 1\0\0\0\0\0\0<\0\0\0vendor/symfony/filesystem/Exception/IOExceptionInterface.php¦\0\0\0\82{\11\0\0\0jÙwM¤\ 1\0\0\0\0\0\0(\0\0\0vendor/symfony/filesystem/Filesystem.phpM4\0\0\82{\11`M4\0\0ãz_\a¤\ 1\0\0\0\0\0\0!\0\0\0vendor/symfony/filesystem/LICENSE)\ 4\0\0\82{\11`)\ 4\0\0NUN½¤\ 1\0\0\0\0\0\0)\0\0\0vendor/symfony/filesystem/LockHandler.phpò\ 5\0\0\82{\11\ 5\0\0~3\9f\ 1\0\0\0\0\0\01\0\0\0vendor/symfony/finder/Adapter/AbstractAdapter.php\\v\0\0\82{\11`\\v\0\0h\19\88\ 1\0\0\0\0\0\05\0\0\0vendor/symfony/finder/Adapter/AbstractFindAdapter.php\83\19\0\0\82{\11`\83\19\0\0kM Þ¤\ 1\0\0\0\0\0\02\0\0\0vendor/symfony/finder/Adapter/AdapterInterface.php\9b\ 3\0\0\82{\11`\9b\ 3\0\0M\aþ\e¤\ 1\0\0\0\0\0\00\0\0\0vendor/symfony/finder/Adapter/BsdFindAdapter.php2\a\0\0\82{\11`2\a\0\0\83\80D)¤\ 1\0\0\0\0\0\00\0\0\0vendor/symfony/finder/Adapter/GnuFindAdapter.php\14\a\0\0\82{\11`\14\a\0\0¦äàO¤\ 1\0\0\0\0\0\0,\0\0\0vendor/symfony/finder/Adapter/PhpAdapter.phpô\a\0\0\82{\11\a\0\0Þdè;¤\ 1\0\0\0\0\0\0/\0\0\0vendor/symfony/finder/Comparator/Comparator.php\8d\ 3\0\0\82{\11`\8d\ 3\0\0¾ü\9cµ¤\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/finder/Comparator/DateComparator.php#\ 3\0\0\82{\11`#\ 3\0\0\16°\1fΤ\ 1\0\0\0\0\0\05\0\0\0vendor/symfony/finder/Comparator/NumberComparator.php{\ 3\0\0\82{\11`{\ 3\0\0\80ÚùY¤\ 1\0\0\0\0\0\09\0\0\0vendor/symfony/finder/Exception/AccessDeniedException.php\84\0\0\0\82{\11`\84\0\0\0½¾s\9c¤\ 1\0\0\0\0\0\0;\0\0\0vendor/symfony/finder/Exception/AdapterFailureException.php¬\ 2\0\0\82{\11\ 2\0\0w\1e\18\ 1\0\0\0\0\0\06\0\0\0vendor/symfony/finder/Exception/ExceptionInterface.php\84\0\0\0\82{\11`\84\0\0\0\1cGz-¤\ 1\0\0\0\0\0\0A\0\0\0vendor/symfony/finder/Exception/OperationNotPermitedException.php)\ 1\0\0\82{\11`)\ 1\0\0x\1f§e¤\ 1\0\0\0\0\0\0@\0\0\0vendor/symfony/finder/Exception/ShellCommandFailureException.phpº\ 2\0\0\82{\11\ 2\0\0\98þ\15\98¤\ 1\0\0\0\0\0\0/\0\0\0vendor/symfony/finder/Expression/Expression.php\a\ 6\0\0\82{\11`\a\ 6\0\0i¥:Ť\ 1\0\0\0\0\0\0)\0\0\0vendor/symfony/finder/Expression/Glob.phpf\ 4\0\0\82{\11`f\ 4\0\0DÞcj¤\ 1\0\0\0\0\0\0*\0\0\0vendor/symfony/finder/Expression/Regex.php\ 3\ f\0\0\82{\11`\ 3\ f\0\0§;M)¤\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/finder/Expression/ValueInterface.phpÍ\ 1\0\0\82{\11\ 1\0\0\p4\86¤\ 1\0\0\0\0\0\0 \0\0\0vendor/symfony/finder/Finder.phpc.\0\0\82{\11`c.\0\0:\885g¤\ 1\0\0\0\0\0\0\1e\0\0\0vendor/symfony/finder/Glob.phpL\ 5\0\0\82{\11`L\ 5\0\0jÍ9פ\ 1\0\0\0\0\0\07\0\0\0vendor/symfony/finder/Iterator/CustomFilterIterator.php]\ 2\0\0\82{\11`]\ 2\0\0ÎoÅƤ\ 1\0\0\0\0\0\0:\0\0\0vendor/symfony/finder/Iterator/DateRangeFilterIterator.phpx\ 2\0\0\82{\11`x\ 2\0\0\ fô\ 3\ 1\0\0\0\0\0\0;\0\0\0vendor/symfony/finder/Iterator/DepthRangeFilterIterator.phpî\ 1\0\0\82{\11\ 1\0\0üÍ\9d\ 1\0\0\0\0\0\0A\0\0\0vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.phpí\ 5\0\0\82{\11\ 5\0\0n\ 5õH¤\ 1\0\0\0\0\0\04\0\0\0vendor/symfony/finder/Iterator/FilePathsIterator.php#\ 6\0\0\82{\11`#\ 6\0\0G?T½¤\ 1\0\0\0\0\0\09\0\0\0vendor/symfony/finder/Iterator/FileTypeFilterIterator.phpZ\ 2\0\0\82{\11`Z\ 2\0\0(\1a&ø¤\ 1\0\0\0\0\0\0<\0\0\0vendor/symfony/finder/Iterator/FilecontentFilterIterator.php5\ 2\0\0\82{\11`5\ 2\0\0\9aí\1f\14¤\ 1\0\0\0\0\0\09\0\0\0vendor/symfony/finder/Iterator/FilenameFilterIterator.phpr\ 1\0\0\82{\11`r\ 1\0\0t\b\1a\ 1\0\0\0\0\0\01\0\0\0vendor/symfony/finder/Iterator/FilterIterator.phpÂ\ 2\0\0\82{\11\ 2\0\0\1c\8f㯤\ 1\0\0\0\0\0\0=\0\0\0vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php*\ 5\0\0\82{\11`*\ 5\0\0\ 2\8c\9e\9d¤\ 1\0\0\0\0\0\05\0\0\0vendor/symfony/finder/Iterator/PathFilterIterator.phpÐ\ 1\0\0\82{\11\ 1\0\0\12\82\b\ 1\0\0\0\0\0\0=\0\0\0vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php\ f   \0\0\82{\11`\ f \0\0O}Cä¤\ 1\0\0\0\0\0\0:\0\0\0vendor/symfony/finder/Iterator/SizeRangeFilterIterator.phpe\ 2\0\0\82{\11`e\ 2\0\0\9f\92áé¤\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/finder/Iterator/SortableIterator.php+\ 6\0\0\82{\11`+\ 6\0\0õÝË ¤\ 1\0\0\0\0\0\0\1d\0\0\0vendor/symfony/finder/LICENSE)\ 4\0\0\82{\11`)\ 4\0\0NUN½¤\ 1\0\0\0\0\0\0'\0\0\0vendor/symfony/finder/Shell/Command.php>\v\0\0\82{\11`>\v\0\0_~u\f¤\ 1\0\0\0\0\0\0%\0\0\0vendor/symfony/finder/Shell/Shell.phpq\ 4\0\0\82{\11`q\ 4\0\0·Ó\8a\ 1\0\0\0\0\0\0%\0\0\0vendor/symfony/finder/SplFileInfo.php\ 6\ 3\0\0\82{\11`\ 6\ 3\0\0þ\0íù¤\ 1\0\0\0\0\0\0'\0\0\0vendor/symfony/polyfill-ctype/Ctype.phpH   \0\0\82{\11`H \0\0³\9dÕݤ\ 1\0\0\0\0\0\0%\0\0\0vendor/symfony/polyfill-ctype/LICENSE)\ 4\0\0\82{\11`)\ 4\0\0´`e0¤\ 1\0\0\0\0\0\0+\0\0\0vendor/symfony/polyfill-ctype/bootstrap.phpú\ 4\0\0\82{\11\ 4\0\0\15|p:¤\ 1\0\0\0\0\0\0(\0\0\0vendor/symfony/polyfill-mbstring/LICENSE)\ 4\0\0\82{\11`)\ 4\0\0\1f\93\ª¤\ 1\0\0\0\0\0\0-\0\0\0vendor/symfony/polyfill-mbstring/Mbstring.php~G\0\0\82{\11`~G\0\0úì¡T¤\ 1\0\0\0\0\0\0@\0\0\0vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php÷T\0\0\82{\11`÷T\0\0ß2ª?¤\ 1\0\0\0\0\0\0F\0\0\0vendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.phpã\17\0\0\82{\11\17\0\0öy_\95¤\ 1\0\0\0\0\0\0@\0\0\0vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.phpîU\0\0\82{\11`îU\0\0`þ8Q¤\ 1\0\0\0\0\0\0.\0\0\0vendor/symfony/polyfill-mbstring/bootstrap.php\ 3\e\0\0\82{\11`\ 3\e\0\0\11þJ¾¤\ 1\0\0\0\0\0\07\0\0\0vendor/symfony/process/Exception/ExceptionInterface.phpf\0\0\0\82{\11`f\0\0\0]ö>T¤\ 1\0\0\0\0\0\0=\0\0\0vendor/symfony/process/Exception/InvalidArgumentException.php¨\0\0\0\82{\11\0\0\0ÐÀ+_¤\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/process/Exception/LogicException.php\94\0\0\0\82{\11`\94\0\0\0 ³ãñ¤\ 1\0\0\0\0\0\0;\0\0\0vendor/symfony/process/Exception/ProcessFailedException.phpx\ 3\0\0\82{\11`x\ 3\0\0¨Ìzy¤\ 1\0\0\0\0\0\0=\0\0\0vendor/symfony/process/Exception/ProcessTimedOutException.php\1f\ 4\0\0\82{\11`\1f\ 4\0\0\7fï\ e«¤\ 1\0\0\0\0\0\05\0\0\0vendor/symfony/process/Exception/RuntimeException.php\98\0\0\0\82{\11`\98\0\0\0¢\eØ:¤\ 1\0\0\0\0\0\0+\0\0\0vendor/symfony/process/ExecutableFinder.php\9c\ 4\0\0\82{\11`\9c\ 4\0\0\1eçÁ̤\ 1\0\0\0\0\0\0\1e\0\0\0vendor/symfony/process/LICENSE)\ 4\0\0\82{\11`)\ 4\0\0NUN½¤\ 1\0\0\0\0\0\0.\0\0\0vendor/symfony/process/PhpExecutableFinder.phpÍ\ 4\0\0\82{\11\ 4\0\0í\ 50ã¤\ 1\0\0\0\0\0\0%\0\0\0vendor/symfony/process/PhpProcess.phpù\ 3\0\0\82{\11\ 3\0\0c¶ßĤ\ 1\0\0\0\0\0\0.\0\0\0vendor/symfony/process/Pipes/AbstractPipes.php¸\a\0\0\82{\11\a\0\0xÓ,§¤\ 1\0\0\0\0\0\0/\0\0\0vendor/symfony/process/Pipes/PipesInterface.phpD\ 1\0\0\82{\11`D\ 1\0\0vØ\ 1\0\0\0\0\0\0*\0\0\0vendor/symfony/process/Pipes/UnixPipes.php7\b\0\0\82{\11`7\b\0\0bÜp\84¤\ 1\0\0\0\0\0\0-\0\0\0vendor/symfony/process/Pipes/WindowsPipes.phpi\f\0\0\82{\11`i\f\0\0Ó
53  Ä¤\ 1\0\0\0\0\0\0"\0\0\0vendor/symfony/process/Process.php R\0\0\82{\11` R\0\0×Ó¥¹¤\ 1\0\0\0\0\0\0)\0\0\0vendor/symfony/process/ProcessBuilder.phpá
54 \0\0\82{\11
55 \0\0ñ6I\95¤\ 1\0\0\0\0\0\0'\0\0\0vendor/symfony/process/ProcessUtils.phpJ\ 6\0\0\82{\11`J\ 6\0\0\ 6{ñC¤\ 1\0\0\0\0\0\0\1c\0\0\0vendor/seld/jsonlint/LICENSE"\ 4\0\0\82{\11`"\ 4\0\0a\83sy¤\ 1\0\0\0\0\0\0@\0\0\0vendor/seld/jsonlint/src/Seld/JsonLint/DuplicateKeyException.phpk\ 1\0\0\82{\11`k\ 1\0\0Zù¶Ã¤\ 1\0\0\0\0\0\05\0\0\0vendor/seld/jsonlint/src/Seld/JsonLint/JsonParser.php62\0\0\82{\11`62\0\0\1128ˤ\ 1\0\0\0\0\0\00\0\0\0vendor/seld/jsonlint/src/Seld/JsonLint/Lexer.php#\11\0\0\82{\11`#\11\0\0Úá@,¤\ 1\0\0\0\0\0\0;\0\0\0vendor/seld/jsonlint/src/Seld/JsonLint/ParsingException.php%\ 1\0\0\82{\11`%\ 1\0\0`a\84\ 1\0\0\0\0\0\04\0\0\0vendor/seld/jsonlint/src/Seld/JsonLint/Undefined.php>\0\0\0\82{\11`>\0\0\0ÿq\9f\9f¤\ 1\0\0\0\0\0\0(\0\0\0vendor/justinrainbow/json-schema/LICENSE \ 4\0\0\82{\11\ 4\0\0ºç\ 6©¤\ 1\0\0\0\0\0\0.\0\0\0vendor/justinrainbow/json-schema/demo/demo.phpñ\ 1\0\0\82{\11\ 1\0\0f\e\12\ 1\0\0\0\0\0\0N\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/BaseConstraint.php¡      \0\0\82{\11`¡ \0\0\86wÌl¤\ 1\0\0\0\0\0\0T\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/CollectionConstraint.php\83
56 \0\0\82{\11`\83
57 \0\0\9e¸=\9a¤\ 1\0\0\0\0\0\0J\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Constraint.php§\r\0\0\82{\11\r\0\0\9b\18¤\ 1\0\0\0\0\0\0S\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ConstraintInterface.php¼\ 1\0\0\82{\11\ 1\0\0ÿ Q\9c¤\ 1\0\0\0\0\0\0N\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/EnumConstraint.php\\ 3\0\0\82{\11`\\ 3\0\0_\7f}ý¤\ 1\0\0\0\0\0\0G\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Factory.phpà\f\0\0\82{\11\f\0\0ë\92_\94¤\ 1\0\0\0\0\0\0P\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/FormatConstraint.phps\14\0\0\82{\11`s\14\0\0d\ 5\vÞ¤\ 1\0\0\0\0\0\0P\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/NumberConstraint.php\83       \0\0\82{\11`\83 \0\0e\90\f¨¤\ 1\0\0\0\0\0\0P\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ObjectConstraint.php·\11\0\0\82{\11\11\0\0%l¬ö¤\ 1\0\0\0\0\0\0P\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/SchemaConstraint.php& \0\0\82{\11`& \0\078÷¬¤\ 1\0\0\0\0\0\0P\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/StringConstraint.phpz\ 4\0\0\82{\11`z\ 4\0\0ùfÅ~¤\ 1\0\0\0\0\0\0X\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeCheck/LooseTypeCheck.phpa\ 4\0\0\82{\11`a\ 4\0\0\v     qä\ 1\0\0\0\0\0\0Y\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeCheck/StrictTypeCheck.php\97\ 2\0\0\82{\11`\97\ 2\0\04~¾ ¤\ 1\0\0\0\0\0\0\\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeCheck/TypeCheckInterface.php\89\ 1\0\0\82{\11`\89\ 1\0\0\93µ+j¤\ 1\0\0\0\0\0\0N\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeConstraint.php\1f\ f\0\0\82{\11`\1f\ f\0\0ª%}\ f¤\ 1\0\0\0\0\0\0S\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/UndefinedConstraint.php,"\0\0\82{\11`,"\0\0\17\ 1\89\ 1\0\0\0\0\0\0F\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Entity/JsonPointer.phpè\ 6\0\0\82{\11\ 6\0\0\ 6{N\96¤\ 1\0\0\0\0\0\0P\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Exception/ExceptionInterface.phpI\0\0\0\82{\11`I\0\0\0%|\19°¤\ 1\0\0\0\0\0\0V\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidArgumentException.php\95\0\0\0\82{\11`\95\0\0\0\8bàG\ 5¤\ 1\0\0\0\0\0\0T\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidConfigException.phpl\0\0\0\82{\11`l\0\0\0A!Lפ\ 1\0\0\0\0\0\0T\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidSchemaException.phpl\0\0\0\82{\11`l\0\0\0è2÷þ¤\ 1\0\0\0\0\0\0]\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidSchemaMediaTypeException.phpu\0\0\0\82{\11`u\0\0\0=hç\a¤\ 1\0\0\0\0\0\0W\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidSourceUriException.phpw\0\0\0\82{\11`w\0\0\0N-ò[¤\ 1\0\0\0\0\0\0S\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Exception/JsonDecodingException.phpÞ\ 2\0\0\82{\11\ 2\0\0\r
58 ¤\ 1\0\0\0\0\0\0W\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Exception/ResourceNotFoundException.phpo\0\0\0\82{\11`o\0\0\0píÛù¤\ 1\0\0\0\0\0\0N\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Exception/RuntimeException.php\85\0\0\0\82{\11`\85\0\0\0\b%\85\97¤\ 1\0\0\0\0\0\0^\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Exception/UnresolvableJsonPointerException.php\80\0\0\0\82{\11`\80\0\0\0u-#1¤\ 1\0\0\0\0\0\0R\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Exception/UriResolverException.phpj\0\0\0\82{\11`j\0\0\0å\1a>\8f¤\ 1\0\0\0\0\0\0Q\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Exception/ValidationException.phpf\0\0\0\82{\11`f\0\0\0¬¤\84þ¤\ 1\0\0\0\0\0\0K\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Iterator/ObjectIterator.phpþ\ 5\0\0\82{\11\ 5\0\0M\8f\84õ¤\ 1\0\0\0\0\0\0;\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Rfc3339.php \ 2\0\0\82{\11\ 2\0\0f4÷³¤\ 1\0\0\0\0\0\0A\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/SchemaStorage.php\93\r\0\0\82{\11`\93\r\0\0&zß^¤\ 1\0\0\0\0\0\0J\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/SchemaStorageInterface.php\ 1\ 1\0\0\82{\11`\ 1\ 1\0\0o\8a+}¤\ 1\0\0\0\0\0\0T\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/AbstractRetriever.phpá\0\0\0\82{\11\0\0\0[þA\81¤\ 1\0\0\0\0\0\0G\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/Curl.php£\ 4\0\0\82{\11\ 4\0\0Ç\92ô¦¤\ 1\0\0\0\0\0\0R\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/FileGetContents.php \ 5\0\0\82{\11\ 5\0\0£Á\1f\16¤\ 1\0\0\0\0\0\0R\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/PredefinedArray.php,\ 2\0\0\82{\11`,\ 2\0\01\955þ¤\ 1\0\0\0\0\0\0X\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/UriRetrieverInterface.php®\0\0\0\82{\11\0\0\0ÿ\8bÁå¤\ 1\0\0\0\0\0\0C\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Uri/UriResolver.php\ 4\v\0\0\82{\11`\ 4\v\0\0æ\ 6\1a\ 1\0\0\0\0\0\0D\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Uri/UriRetriever.php@\14\0\0\82{\11`@\14\0\05\eÎ3¤\ 1\0\0\0\0\0\0H\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/UriResolverInterface.php\83\0\0\0\82{\11`\83\0\0\0\12J\80\1f¤\ 1\0\0\0\0\0\0I\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/UriRetrieverInterface.php\85\0\0\0\82{\11`\85\0\0\0íæ\e\ 1\0\0\0\0\0\0=\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Validator.phps\ 5\0\0\82{\11`s\ 5\0\0ßÁ\91\ 1\0\0\0\0\0\0%\0\0\0vendor/composer/spdx-licenses/LICENSE\1c\ 4\0\0\82{\11`\1c\ 4\0\0\ 6Bhí¤\ 1\0\0\0\0\0\02\0\0\0vendor/composer/spdx-licenses/src/SpdxLicenses.phpH\14\0\0\82{\11`H\14\0\0Í\89T\ 4¤\ 1\0\0\0\0\0\0\1e\0\0\0vendor/composer/semver/LICENSE\1c\ 4\0\0\82{\11`\1c\ 4\0\0\ 6Bhí¤\ 1\0\0\0\0\0\0)\0\0\0vendor/composer/semver/src/Comparator.php\ 2\ 4\0\0\82{\11`\ 2\ 4\0\0wl\83ï¤\ 1\0\0\0\0\0\0<\0\0\0vendor/composer/semver/src/Constraint/AbstractConstraint.phpê\ 2\0\0\82{\11\ 2\0\0M äˤ\ 1\0\0\0\0\0\04\0\0\0vendor/composer/semver/src/Constraint/Constraint.php\8a\f\0\0\82{\11`\8a\f\0\0Ò      \90
59 ¤\ 1\0\0\0\0\0\0=\0\0\0vendor/composer/semver/src/Constraint/ConstraintInterface.phpß\0\0\0\82{\11\0\0\00C,\87¤\ 1\0\0\0\0\0\09\0\0\0vendor/composer/semver/src/Constraint/EmptyConstraint.phpä\ 1\0\0\82{\11\ 1\0\0ïõ\82³¤\ 1\0\0\0\0\0\09\0\0\0vendor/composer/semver/src/Constraint/MultiConstraint.php,\ 5\0\0\82{\11`,\ 5\0\0\ 2\ 1\0\0\0\0\0\0%\0\0\0vendor/composer/semver/src/Semver.php\7f\ 6\0\0\82{\11`\7f\ 6\0\0 YûÀ¤\ 1\0\0\0\0\0\0,\0\0\0vendor/composer/semver/src/VersionParser.phpw-\0\0\82{\11`w-\0\0Î=ð­¤\ 1\0\0\0\0\0\0!\0\0\0vendor/composer/ca-bundle/LICENSE\1c\ 4\0\0\82{\11`\1c\ 4\0\0*!^`¤\ 1\0\0\0\0\0\0*\0\0\0vendor/composer/ca-bundle/src/CaBundle.phpg\1f\0\0\82{\11`g\1f\0\0Axð\90¤\ 1\0\0\0\0\0\0&\0\0\0vendor/composer/xdebug-handler/LICENSE)\ 4\0\0\82{\11`)\ 4\0\0#Ô;^¤\ 1\0\0\0\0\0\00\0\0\0vendor/composer/xdebug-handler/src/PhpConfig.php´\ 2\0\0\82{\11\ 2\0\0*D\92\0¤\ 1\0\0\0\0\0\0.\0\0\0vendor/composer/xdebug-handler/src/Process.phpk        \0\0\82{\11`k \0\0\8eUÿߤ\ 1\0\0\0\0\0\0-\0\0\0vendor/composer/xdebug-handler/src/Status.php\ f
60 \0\0\82{\11`\ f
61 \0\0$\9fv-¤\ 1\0\0\0\0\0\04\0\0\0vendor/composer/xdebug-handler/src/XdebugHandler.php£$\0\0\82{\11`£$\0\0 \80\f\ 1\0\0\0\0\0\0\16\0\0\0vendor/psr/log/LICENSE=\ 4\0\0\82{\11`=\ 4\0\0\8e\ 1\0\0\0\0\0\0)\0\0\0vendor/psr/log/Psr/Log/AbstractLogger.php;\ 4\0\0\82{\11`;\ 4\0\0ñ>3[¤\ 1\0\0\0\0\0\03\0\0\0vendor/psr/log/Psr/Log/InvalidArgumentException.php`\0\0\0\82{\11``\0\0\0 \88X1¤\ 1\0\0\0\0\0\0#\0\0\0vendor/psr/log/Psr/Log/LogLevel.phpû\0\0\0\82{\11\0\0\0jðñ8¤\ 1\0\0\0\0\0\0/\0\0\0vendor/psr/log/Psr/Log/LoggerAwareInterface.php|\0\0\0\82{\11`|\0\0\0$\13£\88¤\ 1\0\0\0\0\0\0+\0\0\0vendor/psr/log/Psr/Log/LoggerAwareTrait.php§\0\0\0\82{\11\0\0\0T½úB¤\ 1\0\0\0\0\0\0*\0\0\0vendor/psr/log/Psr/Log/LoggerInterface.phpÈ\ 2\0\0\82{\11\ 2\0\0\9a\1fx\1d¤\ 1\0\0\0\0\0\0&\0\0\0vendor/psr/log/Psr/Log/LoggerTrait.phpk\ 4\0\0\82{\11`k\ 4\0\0£}\89\92¤\ 1\0\0\0\0\0\0%\0\0\0vendor/psr/log/Psr/Log/NullLogger.php\9f\0\0\0\82{\11`\9f\0\0\0\81Xóª¤\ 1\0\0\0\0\0\0)\0\0\0vendor/psr/log/Psr/Log/Test/DummyTest.phpp\0\0\0\82{\11`p\0\0\0\1a\15Î\ 5¤\ 1\0\0\0\0\0\03\0\0\0vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php \r\0\0\82{\11\r\0\0\1d$/Ò¤\ 1\0\0\0\0\0\0*\0\0\0vendor/psr/log/Psr/Log/Test/TestLogger.php<\b\0\0\82{\11`<\b\0\0þ(åI¤\ 1\0\0\0\0\0\0\13\0\0\0vendor/autoload.php\82\0\0\0\82{\11`\82\0\0\0»¿t`¤\ 1\0\0\0\0\0\0'\0\0\0vendor/composer/autoload_namespaces.phpd\0\0\0\82{\11`d\0\0\0Z¡¦H¤\ 1\0\0\0\0\0\0!\0\0\0vendor/composer/autoload_psr4.php÷\ 4\0\0\82{\11\ 4\0\0Å*\9a\16¤\ 1\0\0\0\0\0\0%\0\0\0vendor/composer/autoload_classmap.phpd\0\0\0\82{\11`d\0\0\0Z¡¦H¤\ 1\0\0\0\0\0\0"\0\0\0vendor/composer/autoload_files.php\1f\ 1\0\0\82{\11`\1f\ 1\0\0¥\0 ®¤\ 1\0\0\0\0\0\0!\0\0\0vendor/composer/autoload_real.phpL\a\0\0\82{\11`L\a\0\0Õ\bµ±¤\ 1\0\0\0\0\0\0#\0\0\0vendor/composer/autoload_static.php§
62 \0\0\82{\11
63 \0\09     MÖ¤\ 1\0\0\0\0\0\0\1f\0\0\0vendor/composer/ClassLoader.php¦\18\0\0\82{\11\18\0\0MI\0\8c¤\ 1\0\0\0\0\0\0(\0\0\0vendor/composer/ca-bundle/res/cacert.pemê`\ 3\0\82{\11`ê`\ 3\0­3\ 6\f¤\ 1\0\0\0\0\0\0\f\0\0\0bin/composerÊ\ 6\0\0\82{\11\ 6\0\0\a\8f4K¤\ 1\0\0\0\0\0\0\a\0\0\0LICENSE.\ 4\0\0\82{\11`.\ 4\0\0 Õ\b\ 3¤\ 1\0\0\0\0\0\0<?php
64
65
66
67
68
69
70
71
72
73
74
75 namespace Composer\Autoload;
76
77 use Composer\Config;
78 use Composer\EventDispatcher\EventDispatcher;
79 use Composer\Installer\InstallationManager;
80 use Composer\IO\IOInterface;
81 use Composer\Package\AliasPackage;
82 use Composer\Package\PackageInterface;
83 use Composer\Repository\InstalledRepositoryInterface;
84 use Composer\Util\Filesystem;
85 use Composer\Script\ScriptEvents;
86 use Composer\Util\PackageSorter;
87
88
89
90
91
92 class AutoloadGenerator
93 {
94
95
96
97 private $eventDispatcher;
98
99
100
101
102 private $io;
103
104
105
106
107 private $devMode = false;
108
109
110
111
112 private $classMapAuthoritative = false;
113
114
115
116
117 private $apcu = false;
118
119
120
121
122 private $runScripts = false;
123
124 public function __construct(EventDispatcher $eventDispatcher, IOInterface $io = null)
125 {
126 $this->eventDispatcher = $eventDispatcher;
127 $this->io = $io;
128 }
129
130 public function setDevMode($devMode = true)
131 {
132 $this->devMode = (bool) $devMode;
133 }
134
135
136
137
138
139
140
141 public function setClassMapAuthoritative($classMapAuthoritative)
142 {
143 $this->classMapAuthoritative = (bool) $classMapAuthoritative;
144 }
145
146
147
148
149
150
151 public function setApcu($apcu)
152 {
153 $this->apcu = (bool) $apcu;
154 }
155
156
157
158
159
160
161 public function setRunScripts($runScripts = true)
162 {
163 $this->runScripts = (bool) $runScripts;
164 }
165
166 public function dump(Config $config, InstalledRepositoryInterface $localRepo, PackageInterface $mainPackage, InstallationManager $installationManager, $targetDir, $scanPsrPackages = false, $suffix = '')
167 {
168 if ($this->classMapAuthoritative) {
169
170 $scanPsrPackages = true;
171 }
172 if ($this->runScripts) {
173 $this->eventDispatcher->dispatchScript(ScriptEvents::PRE_AUTOLOAD_DUMP, $this->devMode, array(), array(
174 'optimize' => (bool) $scanPsrPackages,
175 ));
176 }
177
178 $filesystem = new Filesystem();
179 $filesystem->ensureDirectoryExists($config->get('vendor-dir'));
180
181
182
183 $basePath = $filesystem->normalizePath(realpath(realpath(getcwd())));
184 $vendorPath = $filesystem->normalizePath(realpath(realpath($config->get('vendor-dir'))));
185 $useGlobalIncludePath = (bool) $config->get('use-include-path');
186 $prependAutoloader = $config->get('prepend-autoloader') === false ? 'false' : 'true';
187 $targetDir = $vendorPath.'/'.$targetDir;
188 $filesystem->ensureDirectoryExists($targetDir);
189
190 $vendorPathCode = $filesystem->findShortestPathCode(realpath($targetDir), $vendorPath, true);
191 $vendorPathCode52 = str_replace('__DIR__', 'dirname(__FILE__)', $vendorPathCode);
192 $vendorPathToTargetDirCode = $filesystem->findShortestPathCode($vendorPath, realpath($targetDir), true);
193
194 $appBaseDirCode = $filesystem->findShortestPathCode($vendorPath, $basePath, true);
195 $appBaseDirCode = str_replace('__DIR__', '$vendorDir', $appBaseDirCode);
196
197 $namespacesFile = <<<EOF
198 <?php
199
200 // autoload_namespaces.php @generated by Composer
201
202 \$vendorDir = $vendorPathCode52;
203 \$baseDir = $appBaseDirCode;
204
205 return array(
206
207 EOF;
208
209 $psr4File = <<<EOF
210 <?php
211
212 // autoload_psr4.php @generated by Composer
213
214 \$vendorDir = $vendorPathCode52;
215 \$baseDir = $appBaseDirCode;
216
217 return array(
218
219 EOF;
220
221
222 $packageMap = $this->buildPackageMap($installationManager, $mainPackage, $localRepo->getCanonicalPackages());
223 $autoloads = $this->parseAutoloads($packageMap, $mainPackage, $this->devMode === false);
224
225
226 foreach ($autoloads['psr-0'] as $namespace => $paths) {
227 $exportedPaths = array();
228 foreach ($paths as $path) {
229 $exportedPaths[] = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
230 }
231 $exportedPrefix = var_export($namespace, true);
232 $namespacesFile .= "    $exportedPrefix => ";
233 $namespacesFile .= "array(".implode(', ', $exportedPaths)."),\n";
234 }
235 $namespacesFile .= ");\n";
236
237
238 foreach ($autoloads['psr-4'] as $namespace => $paths) {
239 $exportedPaths = array();
240 foreach ($paths as $path) {
241 $exportedPaths[] = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
242 }
243 $exportedPrefix = var_export($namespace, true);
244 $psr4File .= "    $exportedPrefix => ";
245 $psr4File .= "array(".implode(', ', $exportedPaths)."),\n";
246 }
247 $psr4File .= ");\n";
248
249 $classmapFile = <<<EOF
250 <?php
251
252 // autoload_classmap.php @generated by Composer
253
254 \$vendorDir = $vendorPathCode52;
255 \$baseDir = $appBaseDirCode;
256
257 return array(
258
259 EOF;
260
261
262 $targetDirLoader = null;
263 $mainAutoload = $mainPackage->getAutoload();
264 if ($mainPackage->getTargetDir() && !empty($mainAutoload['psr-0'])) {
265 $levels = substr_count($filesystem->normalizePath($mainPackage->getTargetDir()), '/') + 1;
266 $prefixes = implode(', ', array_map(function ($prefix) {
267 return var_export($prefix, true);
268 }, array_keys($mainAutoload['psr-0'])));
269 $baseDirFromTargetDirCode = $filesystem->findShortestPathCode($targetDir, $basePath, true);
270
271 $targetDirLoader = <<<EOF
272
273     public static function autoload(\$class)
274     {
275         \$dir = $baseDirFromTargetDirCode . '/';
276         \$prefixes = array($prefixes);
277         foreach (\$prefixes as \$prefix) {
278             if (0 !== strpos(\$class, \$prefix)) {
279                 continue;
280             }
281             \$path = \$dir . implode('/', array_slice(explode('\\\\', \$class), $levels)).'.php';
282             if (!\$path = stream_resolve_include_path(\$path)) {
283                 return false;
284             }
285             require \$path;
286
287             return true;
288         }
289     }
290
291 EOF;
292 }
293
294 $excluded = null;
295 if (!empty($autoloads['exclude-from-classmap'])) {
296 $excluded = $autoloads['exclude-from-classmap'];
297 }
298
299 $classMap = array();
300 $ambiguousClasses = array();
301 $scannedFiles = array();
302 foreach ($autoloads['classmap'] as $dir) {
303 $classMap = $this->addClassMapCode($filesystem, $basePath, $vendorPath, $dir, $excluded, null, null, $classMap, $ambiguousClasses, $scannedFiles);
304 }
305
306 if ($scanPsrPackages) {
307 $namespacesToScan = array();
308
309
310 foreach (array('psr-4', 'psr-0') as $psrType) {
311 foreach ($autoloads[$psrType] as $namespace => $paths) {
312 $namespacesToScan[$namespace][] = array('paths' => $paths, 'type' => $psrType);
313 }
314 }
315
316 krsort($namespacesToScan);
317
318 foreach ($namespacesToScan as $namespace => $groups) {
319 foreach ($groups as $group) {
320 foreach ($group['paths'] as $dir) {
321 $dir = $filesystem->normalizePath($filesystem->isAbsolutePath($dir) ? $dir : $basePath.'/'.$dir);
322 if (!is_dir($dir)) {
323 continue;
324 }
325
326 $classMap = $this->addClassMapCode($filesystem, $basePath, $vendorPath, $dir, $excluded, $namespace, $group['type'], $classMap, $ambiguousClasses, $scannedFiles);
327 }
328 }
329 }
330 }
331
332 foreach ($ambiguousClasses as $className => $ambigiousPaths) {
333 $cleanPath = str_replace(array('$vendorDir . \'', '$baseDir . \'', "',\n"), array($vendorPath, $basePath, ''), $classMap[$className]);
334
335 $this->io->writeError(
336 '<warning>Warning: Ambiguous class resolution, "'.$className.'"'.
337 ' was found '. (count($ambigiousPaths) + 1) .'x: in "'.$cleanPath.'" and "'. implode('", "', $ambigiousPaths) .'", the first will be used.</warning>'
338 );
339 }
340
341 ksort($classMap);
342 foreach ($classMap as $class => $code) {
343 $classmapFile .= '    '.var_export($class, true).' => '.$code;
344 }
345 $classmapFile .= ");\n";
346
347 if (!$suffix) {
348 if (!$config->get('autoloader-suffix') && is_readable($vendorPath.'/autoload.php')) {
349 $content = file_get_contents($vendorPath.'/autoload.php');
350 if (preg_match('{ComposerAutoloaderInit([^:\s]+)::}', $content, $match)) {
351 $suffix = $match[1];
352 }
353 }
354
355 if (!$suffix) {
356 $suffix = $config->get('autoloader-suffix') ?: md5(uniqid('', true));
357 }
358 }
359
360 $this->filePutContentsIfModified($targetDir.'/autoload_namespaces.php', $namespacesFile);
361 $this->filePutContentsIfModified($targetDir.'/autoload_psr4.php', $psr4File);
362 $this->filePutContentsIfModified($targetDir.'/autoload_classmap.php', $classmapFile);
363 $includePathFilePath = $targetDir.'/include_paths.php';
364 if ($includePathFileContents = $this->getIncludePathsFile($packageMap, $filesystem, $basePath, $vendorPath, $vendorPathCode52, $appBaseDirCode)) {
365 $this->filePutContentsIfModified($includePathFilePath, $includePathFileContents);
366 } elseif (file_exists($includePathFilePath)) {
367 unlink($includePathFilePath);
368 }
369 $includeFilesFilePath = $targetDir.'/autoload_files.php';
370 if ($includeFilesFileContents = $this->getIncludeFilesFile($autoloads['files'], $filesystem, $basePath, $vendorPath, $vendorPathCode52, $appBaseDirCode)) {
371 $this->filePutContentsIfModified($includeFilesFilePath, $includeFilesFileContents);
372 } elseif (file_exists($includeFilesFilePath)) {
373 unlink($includeFilesFilePath);
374 }
375 $this->filePutContentsIfModified($targetDir.'/autoload_static.php', $this->getStaticFile($suffix, $targetDir, $vendorPath, $basePath, $staticPhpVersion));
376 $this->filePutContentsIfModified($vendorPath.'/autoload.php', $this->getAutoloadFile($vendorPathToTargetDirCode, $suffix));
377 $this->filePutContentsIfModified($targetDir.'/autoload_real.php', $this->getAutoloadRealFile(true, (bool) $includePathFileContents, $targetDirLoader, (bool) $includeFilesFileContents, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader, $staticPhpVersion));
378
379 $this->safeCopy(__DIR__.'/ClassLoader.php', $targetDir.'/ClassLoader.php');
380 $this->safeCopy(__DIR__.'/../../../LICENSE', $targetDir.'/LICENSE');
381
382 if ($this->runScripts) {
383 $this->eventDispatcher->dispatchScript(ScriptEvents::POST_AUTOLOAD_DUMP, $this->devMode, array(), array(
384 'optimize' => (bool) $scanPsrPackages,
385 ));
386 }
387
388 return count($classMap);
389 }
390
391 private function filePutContentsIfModified($path, $content)
392 {
393 $currentContent = @file_get_contents($path);
394 if (!$currentContent || ($currentContent != $content)) {
395 return file_put_contents($path, $content);
396 }
397
398 return 0;
399 }
400
401 private function addClassMapCode($filesystem, $basePath, $vendorPath, $dir, $excluded, $namespaceFilter, $autoloadType, array $classMap, array &$ambiguousClasses, array &$scannedFiles)
402 {
403 foreach ($this->generateClassMap($dir, $excluded, $namespaceFilter, $autoloadType, true, $scannedFiles) as $class => $path) {
404 $pathCode = $this->getPathCode($filesystem, $basePath, $vendorPath, $path).",\n";
405 if (!isset($classMap[$class])) {
406 $classMap[$class] = $pathCode;
407 } elseif ($this->io && $classMap[$class] !== $pathCode && !preg_match('{/(test|fixture|example|stub)s?/}i', strtr($classMap[$class].' '.$path, '\\', '/'))) {
408 $ambiguousClasses[$class][] = $path;
409 }
410 }
411
412 return $classMap;
413 }
414
415
416
417
418 private function generateClassMap($dir, $excluded, $namespaceFilter, $autoloadType, $showAmbiguousWarning, array &$scannedFiles)
419 {
420 if ($excluded) {
421
422
423
424 if (file_exists($dir)) {
425
426 $dirMatch = preg_quote(strtr(realpath($dir), '\\', '/'));
427 foreach ($excluded as $index => $pattern) {
428
429 $pattern = preg_replace('{^(([^.+*?\[^\]$(){}=!<>|:\\\\#-]+|\\\\[.+*?\[^\]$(){}=!<>|:#-])*).*}', '$1', $pattern);
430
431 if (0 !== strpos($pattern, $dirMatch) && 0 !== strpos($dirMatch, $pattern)) {
432 unset($excluded[$index]);
433 }
434 }
435 }
436
437 $excluded = $excluded ? '{(' . implode('|', $excluded) . ')}' : null;
438 }
439
440 return ClassMapGenerator::createMap($dir, $excluded, $showAmbiguousWarning ? $this->io : null, $namespaceFilter, $autoloadType, $scannedFiles);
441 }
442
443 public function buildPackageMap(InstallationManager $installationManager, PackageInterface $mainPackage, array $packages)
444 {
445
446 $packageMap = array(array($mainPackage, ''));
447
448 foreach ($packages as $package) {
449 if ($package instanceof AliasPackage) {
450 continue;
451 }
452 $this->validatePackage($package);
453
454 $packageMap[] = array(
455 $package,
456 $installationManager->getInstallPath($package),
457 );
458 }
459
460 return $packageMap;
461 }
462
463
464
465
466
467
468 protected function validatePackage(PackageInterface $package)
469 {
470 $autoload = $package->getAutoload();
471 if (!empty($autoload['psr-4']) && null !== $package->getTargetDir()) {
472 $name = $package->getName();
473 $package->getTargetDir();
474 throw new \InvalidArgumentException("PSR-4 autoloading is incompatible with the target-dir property, remove the target-dir in package '$name'.");
475 }
476 if (!empty($autoload['psr-4'])) {
477 foreach ($autoload['psr-4'] as $namespace => $dirs) {
478 if ($namespace !== '' && '\\' !== substr($namespace, -1)) {
479 throw new \InvalidArgumentException("psr-4 namespaces must end with a namespace separator, '$namespace' does not, use '$namespace\\'.");
480 }
481 }
482 }
483 }
484
485
486
487
488
489
490
491
492
493 public function parseAutoloads(array $packageMap, PackageInterface $mainPackage, $filterOutRequireDevPackages = false)
494 {
495 $mainPackageMap = array_shift($packageMap);
496 if ($filterOutRequireDevPackages) {
497 $packageMap = $this->filterPackageMap($packageMap, $mainPackage);
498 }
499 $sortedPackageMap = $this->sortPackageMap($packageMap);
500 $sortedPackageMap[] = $mainPackageMap;
501 array_unshift($packageMap, $mainPackageMap);
502
503 $psr0 = $this->parseAutoloadsType($packageMap, 'psr-0', $mainPackage);
504 $psr4 = $this->parseAutoloadsType($packageMap, 'psr-4', $mainPackage);
505 $classmap = $this->parseAutoloadsType(array_reverse($sortedPackageMap), 'classmap', $mainPackage);
506 $files = $this->parseAutoloadsType($sortedPackageMap, 'files', $mainPackage);
507 $exclude = $this->parseAutoloadsType($sortedPackageMap, 'exclude-from-classmap', $mainPackage);
508
509 krsort($psr0);
510 krsort($psr4);
511
512 return array(
513 'psr-0' => $psr0,
514 'psr-4' => $psr4,
515 'classmap' => $classmap,
516 'files' => $files,
517 'exclude-from-classmap' => $exclude,
518 );
519 }
520
521
522
523
524
525
526
527 public function createLoader(array $autoloads)
528 {
529 $loader = new ClassLoader();
530
531 if (isset($autoloads['psr-0'])) {
532 foreach ($autoloads['psr-0'] as $namespace => $path) {
533 $loader->add($namespace, $path);
534 }
535 }
536
537 if (isset($autoloads['psr-4'])) {
538 foreach ($autoloads['psr-4'] as $namespace => $path) {
539 $loader->addPsr4($namespace, $path);
540 }
541 }
542
543 if (isset($autoloads['classmap'])) {
544 $excluded = null;
545 if (!empty($autoloads['exclude-from-classmap'])) {
546 $excluded = $autoloads['exclude-from-classmap'];
547 }
548
549 $scannedFiles = array();
550 foreach ($autoloads['classmap'] as $dir) {
551 try {
552 $loader->addClassMap($this->generateClassMap($dir, $excluded, null, null, false, $scannedFiles));
553 } catch (\RuntimeException $e) {
554 $this->io->writeError('<warning>'.$e->getMessage().'</warning>');
555 }
556 }
557 }
558
559 return $loader;
560 }
561
562 protected function getIncludePathsFile(array $packageMap, Filesystem $filesystem, $basePath, $vendorPath, $vendorPathCode, $appBaseDirCode)
563 {
564 $includePaths = array();
565
566 foreach ($packageMap as $item) {
567 list($package, $installPath) = $item;
568
569 if (null !== $package->getTargetDir() && strlen($package->getTargetDir()) > 0) {
570 $installPath = substr($installPath, 0, -strlen('/'.$package->getTargetDir()));
571 }
572
573 foreach ($package->getIncludePaths() as $includePath) {
574 $includePath = trim($includePath, '/');
575 $includePaths[] = empty($installPath) ? $includePath : $installPath.'/'.$includePath;
576 }
577 }
578
579 if (!$includePaths) {
580 return;
581 }
582
583 $includePathsCode = '';
584 foreach ($includePaths as $path) {
585 $includePathsCode .= "    " . $this->getPathCode($filesystem, $basePath, $vendorPath, $path) . ",\n";
586 }
587
588 return <<<EOF
589 <?php
590
591 // include_paths.php @generated by Composer
592
593 \$vendorDir = $vendorPathCode;
594 \$baseDir = $appBaseDirCode;
595
596 return array(
597 $includePathsCode);
598
599 EOF;
600 }
601
602 protected function getIncludeFilesFile(array $files, Filesystem $filesystem, $basePath, $vendorPath, $vendorPathCode, $appBaseDirCode)
603 {
604 $filesCode = '';
605 foreach ($files as $fileIdentifier => $functionFile) {
606 $filesCode .= '    ' . var_export($fileIdentifier, true) . ' => '
607 . $this->getPathCode($filesystem, $basePath, $vendorPath, $functionFile) . ",\n";
608 }
609
610 if (!$filesCode) {
611 return false;
612 }
613
614 return <<<EOF
615 <?php
616
617 // autoload_files.php @generated by Composer
618
619 \$vendorDir = $vendorPathCode;
620 \$baseDir = $appBaseDirCode;
621
622 return array(
623 $filesCode);
624
625 EOF;
626 }
627
628 protected function getPathCode(Filesystem $filesystem, $basePath, $vendorPath, $path)
629 {
630 if (!$filesystem->isAbsolutePath($path)) {
631 $path = $basePath . '/' . $path;
632 }
633 $path = $filesystem->normalizePath($path);
634
635 $baseDir = '';
636 if (strpos($path.'/', $vendorPath.'/') === 0) {
637 $path = substr($path, strlen($vendorPath));
638 $baseDir = '$vendorDir';
639
640 if ($path !== false) {
641 $baseDir .= " . ";
642 }
643 } else {
644 $path = $filesystem->normalizePath($filesystem->findShortestPath($basePath, $path, true));
645 if (!$filesystem->isAbsolutePath($path)) {
646 $baseDir = '$baseDir . ';
647 $path = '/' . $path;
648 }
649 }
650
651 if (strpos($path, '.phar') !== false) {
652 $baseDir = "'phar://' . " . $baseDir;
653 }
654
655 return $baseDir . (($path !== false) ? var_export($path, true) : "");
656 }
657
658 protected function getAutoloadFile($vendorPathToTargetDirCode, $suffix)
659 {
660 $lastChar = $vendorPathToTargetDirCode[strlen($vendorPathToTargetDirCode) - 1];
661 if ("'" === $lastChar || '"' === $lastChar) {
662 $vendorPathToTargetDirCode = substr($vendorPathToTargetDirCode, 0, -1).'/autoload_real.php'.$lastChar;
663 } else {
664 $vendorPathToTargetDirCode .= " . '/autoload_real.php'";
665 }
666
667 return <<<AUTOLOAD
668 <?php
669
670 // autoload.php @generated by Composer
671
672 require_once $vendorPathToTargetDirCode;
673
674 return ComposerAutoloaderInit$suffix::getLoader();
675
676 AUTOLOAD;
677 }
678
679 protected function getAutoloadRealFile($useClassMap, $useIncludePath, $targetDirLoader, $useIncludeFiles, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader, $staticPhpVersion = 70000)
680 {
681 $file = <<<HEADER
682 <?php
683
684 // autoload_real.php @generated by Composer
685
686 class ComposerAutoloaderInit$suffix
687 {
688     private static \$loader;
689
690     public static function loadClassLoader(\$class)
691     {
692         if ('Composer\\Autoload\\ClassLoader' === \$class) {
693             require __DIR__ . '/ClassLoader.php';
694         }
695     }
696
697     /**
698      * @return \Composer\Autoload\ClassLoader
699      */
700     public static function getLoader()
701     {
702         if (null !== self::\$loader) {
703             return self::\$loader;
704         }
705
706         spl_autoload_register(array('ComposerAutoloaderInit$suffix', 'loadClassLoader'), true, $prependAutoloader);
707         self::\$loader = \$loader = new \\Composer\\Autoload\\ClassLoader();
708         spl_autoload_unregister(array('ComposerAutoloaderInit$suffix', 'loadClassLoader'));
709
710
711 HEADER;
712
713 if ($useIncludePath) {
714 $file .= <<<'INCLUDE_PATH'
715         $includePaths = require __DIR__ . '/include_paths.php';
716         $includePaths[] = get_include_path();
717         set_include_path(implode(PATH_SEPARATOR, $includePaths));
718
719
720 INCLUDE_PATH;
721 }
722
723 $file .= <<<STATIC_INIT
724         \$useStaticLoader = PHP_VERSION_ID >= $staticPhpVersion && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
725         if (\$useStaticLoader) {
726             require_once __DIR__ . '/autoload_static.php';
727
728             call_user_func(\Composer\Autoload\ComposerStaticInit$suffix::getInitializer(\$loader));
729         } else {
730
731 STATIC_INIT;
732
733 if (!$this->classMapAuthoritative) {
734 $file .= <<<'PSR04'
735             $map = require __DIR__ . '/autoload_namespaces.php';
736             foreach ($map as $namespace => $path) {
737                 $loader->set($namespace, $path);
738             }
739
740             $map = require __DIR__ . '/autoload_psr4.php';
741             foreach ($map as $namespace => $path) {
742                 $loader->setPsr4($namespace, $path);
743             }
744
745
746 PSR04;
747 }
748
749 if ($useClassMap) {
750 $file .= <<<'CLASSMAP'
751             $classMap = require __DIR__ . '/autoload_classmap.php';
752             if ($classMap) {
753                 $loader->addClassMap($classMap);
754             }
755
756 CLASSMAP;
757 }
758
759 $file .= "        }\n\n";
760
761 if ($this->classMapAuthoritative) {
762 $file .= <<<'CLASSMAPAUTHORITATIVE'
763         $loader->setClassMapAuthoritative(true);
764
765 CLASSMAPAUTHORITATIVE;
766 }
767
768 if ($this->apcu) {
769 $apcuPrefix = substr(base64_encode(md5(uniqid('', true), true)), 0, -3);
770 $file .= <<<APCU
771         \$loader->setApcuPrefix('$apcuPrefix');
772
773 APCU;
774 }
775
776 if ($useGlobalIncludePath) {
777 $file .= <<<'INCLUDEPATH'
778         $loader->setUseIncludePath(true);
779
780 INCLUDEPATH;
781 }
782
783 if ($targetDirLoader) {
784 $file .= <<<REGISTER_TARGET_DIR_AUTOLOAD
785         spl_autoload_register(array('ComposerAutoloaderInit$suffix', 'autoload'), true, true);
786
787
788 REGISTER_TARGET_DIR_AUTOLOAD;
789 }
790
791 $file .= <<<REGISTER_LOADER
792         \$loader->register($prependAutoloader);
793
794
795 REGISTER_LOADER;
796
797 if ($useIncludeFiles) {
798 $file .= <<<INCLUDE_FILES
799         if (\$useStaticLoader) {
800             \$includeFiles = Composer\Autoload\ComposerStaticInit$suffix::\$files;
801         } else {
802             \$includeFiles = require __DIR__ . '/autoload_files.php';
803         }
804         foreach (\$includeFiles as \$fileIdentifier => \$file) {
805             composerRequire$suffix(\$fileIdentifier, \$file);
806         }
807
808
809 INCLUDE_FILES;
810 }
811
812 $file .= <<<METHOD_FOOTER
813         return \$loader;
814     }
815
816 METHOD_FOOTER;
817
818 $file .= $targetDirLoader;
819
820 if ($useIncludeFiles) {
821 return $file . <<<FOOTER
822 }
823
824 function composerRequire$suffix(\$fileIdentifier, \$file)
825 {
826     if (empty(\$GLOBALS['__composer_autoload_files'][\$fileIdentifier])) {
827         require \$file;
828
829         \$GLOBALS['__composer_autoload_files'][\$fileIdentifier] = true;
830     }
831 }
832
833 FOOTER;
834 }
835
836 return $file . <<<FOOTER
837 }
838
839 FOOTER;
840 }
841
842 protected function getStaticFile($suffix, $targetDir, $vendorPath, $basePath, &$staticPhpVersion)
843 {
844 $staticPhpVersion = 50600;
845
846 $file = <<<HEADER
847 <?php
848
849 // autoload_static.php @generated by Composer
850
851 namespace Composer\Autoload;
852
853 class ComposerStaticInit$suffix
854 {
855
856 HEADER;
857
858 $loader = new ClassLoader();
859
860 $map = require $targetDir . '/autoload_namespaces.php';
861 foreach ($map as $namespace => $path) {
862 $loader->set($namespace, $path);
863 }
864
865 $map = require $targetDir . '/autoload_psr4.php';
866 foreach ($map as $namespace => $path) {
867 $loader->setPsr4($namespace, $path);
868 }
869
870 $classMap = require $targetDir . '/autoload_classmap.php';
871 if ($classMap) {
872 $loader->addClassMap($classMap);
873 }
874
875 $filesystem = new Filesystem();
876
877 $vendorPathCode = ' => ' . $filesystem->findShortestPathCode(realpath($targetDir), $vendorPath, true, true) . " . '/";
878 $vendorPharPathCode = ' => \'phar://\' . ' . $filesystem->findShortestPathCode(realpath($targetDir), $vendorPath, true, true) . " . '/";
879 $appBaseDirCode = ' => ' . $filesystem->findShortestPathCode(realpath($targetDir), $basePath, true, true) . " . '/";
880 $appBaseDirPharCode = ' => \'phar://\' . ' . $filesystem->findShortestPathCode(realpath($targetDir), $basePath, true, true) . " . '/";
881
882 $absoluteVendorPathCode = ' => ' . substr(var_export(rtrim($vendorDir, '\\/') . '/', true), 0, -1);
883 $absoluteVendorPharPathCode = ' => ' . substr(var_export(rtrim('phar://' . $vendorDir, '\\/') . '/', true), 0, -1);
884 $absoluteAppBaseDirCode = ' => ' . substr(var_export(rtrim($baseDir, '\\/') . '/', true), 0, -1);
885 $absoluteAppBaseDirPharCode = ' => ' . substr(var_export(rtrim('phar://' . $baseDir, '\\/') . '/', true), 0, -1);
886
887 $initializer = '';
888 $prefix = "\0Composer\Autoload\ClassLoader\0";
889 $prefixLen = strlen($prefix);
890 if (file_exists($targetDir . '/autoload_files.php')) {
891 $maps = array('files' => require $targetDir . '/autoload_files.php');
892 } else {
893 $maps = array();
894 }
895
896 foreach ((array) $loader as $prop => $value) {
897 if ($value && 0 === strpos($prop, $prefix)) {
898 $maps[substr($prop, $prefixLen)] = $value;
899 }
900 }
901
902 foreach ($maps as $prop => $value) {
903 if (count($value) > 32767) {
904
905
906 $staticPhpVersion = 70000;
907 }
908 $value = strtr(
909 var_export($value, true),
910 array(
911 $absoluteVendorPathCode => $vendorPathCode,
912 $absoluteVendorPharPathCode => $vendorPharPathCode,
913 $absoluteAppBaseDirCode => $appBaseDirCode,
914 $absoluteAppBaseDirPharCode => $appBaseDirPharCode,
915 )
916 );
917 $value = ltrim(preg_replace('/^ */m', '    $0$0', $value));
918
919 $file .= sprintf("    public static $%s = %s;\n\n", $prop, $value);
920 if ('files' !== $prop) {
921 $initializer .= "            \$loader->$prop = ComposerStaticInit$suffix::\$$prop;\n";
922 }
923 }
924
925 return $file . <<<INITIALIZER
926     public static function getInitializer(ClassLoader \$loader)
927     {
928         return \Closure::bind(function () use (\$loader) {
929 $initializer
930         }, null, ClassLoader::class);
931     }
932 }
933
934 INITIALIZER;
935 }
936
937 protected function parseAutoloadsType(array $packageMap, $type, PackageInterface $mainPackage)
938 {
939 $autoloads = array();
940
941 foreach ($packageMap as $item) {
942 list($package, $installPath) = $item;
943
944 $autoload = $package->getAutoload();
945 if ($this->devMode && $package === $mainPackage) {
946 $autoload = array_merge_recursive($autoload, $package->getDevAutoload());
947 }
948
949
950 if (!isset($autoload[$type]) || !is_array($autoload[$type])) {
951 continue;
952 }
953 if (null !== $package->getTargetDir() && $package !== $mainPackage) {
954 $installPath = substr($installPath, 0, -strlen('/'.$package->getTargetDir()));
955 }
956
957 foreach ($autoload[$type] as $namespace => $paths) {
958 foreach ((array) $paths as $path) {
959 if (($type === 'files' || $type === 'classmap' || $type === 'exclude-from-classmap') && $package->getTargetDir() && !is_readable($installPath.'/'.$path)) {
960
961 if ($package === $mainPackage) {
962 $targetDir = str_replace('\\<dirsep\\>', '[\\\\/]', preg_quote(str_replace(array('/', '\\'), '<dirsep>', $package->getTargetDir())));
963 $path = ltrim(preg_replace('{^'.$targetDir.'}', '', ltrim($path, '\\/')), '\\/');
964 } else {
965
966 $path = $package->getTargetDir() . '/' . $path;
967 }
968 }
969
970 if ($type === 'exclude-from-classmap') {
971
972 $path = preg_replace('{/+}', '/', preg_quote(trim(strtr($path, '\\', '/'), '/')));
973
974
975 $path = str_replace('\\*\\*', '.+?', $path);
976 $path = str_replace('\\*', '[^/]+?', $path);
977
978
979 $updir = null;
980 $path = preg_replace_callback(
981 '{^((?:(?:\\\\\\.){1,2}+/)+)}',
982 function ($matches) use (&$updir) {
983 if (isset($matches[1])) {
984
985 $updir = str_replace('\\.', '.', $matches[1]);
986 }
987
988 return '';
989 },
990 $path
991 );
992 if (empty($installPath)) {
993 $installPath = strtr(getcwd(), '\\', '/');
994 }
995
996 $resolvedPath = realpath($installPath . '/' . $updir);
997 $autoloads[] = preg_quote(strtr($resolvedPath, '\\', '/')) . '/' . $path . '($|/)';
998 continue;
999 }
1000
1001 $relativePath = empty($installPath) ? (empty($path) ? '.' : $path) : $installPath.'/'.$path;
1002
1003 if ($type === 'files') {
1004 $autoloads[$this->getFileIdentifier($package, $path)] = $relativePath;
1005 continue;
1006 } elseif ($type === 'classmap') {
1007 $autoloads[] = $relativePath;
1008 continue;
1009 }
1010
1011 $autoloads[$namespace][] = $relativePath;
1012 }
1013 }
1014 }
1015
1016 return $autoloads;
1017 }
1018
1019 protected function getFileIdentifier(PackageInterface $package, $path)
1020 {
1021 return md5($package->getName() . ':' . $path);
1022 }
1023
1024
1025
1026
1027
1028
1029
1030
1031 protected function filterPackageMap(array $packageMap, PackageInterface $mainPackage)
1032 {
1033 $packages = array();
1034 $include = array();
1035 $replacedBy = array();
1036
1037 foreach ($packageMap as $item) {
1038 $package = $item[0];
1039 $name = $package->getName();
1040 $packages[$name] = $package;
1041 foreach ($package->getReplaces() as $replace) {
1042 $replacedBy[$replace->getTarget()] = $name;
1043 }
1044 }
1045
1046 $add = function (PackageInterface $package) use (&$add, $packages, &$include, $replacedBy) {
1047 foreach ($package->getRequires() as $link) {
1048 $target = $link->getTarget();
1049 if (isset($replacedBy[$target])) {
1050 $target = $replacedBy[$target];
1051 }
1052 if (!isset($include[$target])) {
1053 $include[$target] = true;
1054 if (isset($packages[$target])) {
1055 $add($packages[$target]);
1056 }
1057 }
1058 }
1059 };
1060 $add($mainPackage);
1061
1062 return array_filter(
1063 $packageMap,
1064 function ($item) use ($include) {
1065 $package = $item[0];
1066 foreach ($package->getNames() as $name) {
1067 if (isset($include[$name])) {
1068 return true;
1069 }
1070 }
1071
1072 return false;
1073 }
1074 );
1075 }
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085 protected function sortPackageMap(array $packageMap)
1086 {
1087 $packages = array();
1088 $paths = array();
1089
1090 foreach ($packageMap as $item) {
1091 list($package, $path) = $item;
1092 $name = $package->getName();
1093 $packages[$name] = $package;
1094 $paths[$name] = $path;
1095 }
1096
1097 $sortedPackages = PackageSorter::sortPackages($packages);
1098
1099 $sortedPackageMap = array();
1100
1101 foreach ($sortedPackages as $package) {
1102 $name = $package->getName();
1103 $sortedPackageMap[] = array($packages[$name], $paths[$name]);
1104 }
1105
1106 return $sortedPackageMap;
1107 }
1108
1109
1110
1111
1112
1113
1114
1115 protected function safeCopy($source, $target)
1116 {
1117 if (!file_exists($target) || !file_exists($source) || !$this->filesAreEqual($source, $target)) {
1118 $source = fopen($source, 'r');
1119 $target = fopen($target, 'w+');
1120
1121 stream_copy_to_stream($source, $target);
1122 fclose($source);
1123 fclose($target);
1124 }
1125 }
1126
1127
1128
1129
1130
1131 private function filesAreEqual($a, $b)
1132 {
1133
1134 if (filesize($a) !== filesize($b)) {
1135 return false;
1136 }
1137
1138
1139 $ah = fopen($a, 'rb');
1140 $bh = fopen($b, 'rb');
1141
1142 $result = true;
1143 while (!feof($ah)) {
1144 if (fread($ah, 8192) != fread($bh, 8192)) {
1145 $result = false;
1146 break;
1147 }
1148 }
1149
1150 fclose($ah);
1151 fclose($bh);
1152
1153 return $result;
1154 }
1155 }
1156 <?php
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174 namespace Composer\Autoload;
1175
1176 use Symfony\Component\Finder\Finder;
1177 use Composer\IO\IOInterface;
1178 use Composer\Util\Filesystem;
1179
1180
1181
1182
1183
1184
1185
1186 class ClassMapGenerator
1187 {
1188
1189
1190
1191
1192
1193
1194 public static function dump($dirs, $file)
1195 {
1196 $maps = array();
1197
1198 foreach ($dirs as $dir) {
1199 $maps = array_merge($maps, static::createMap($dir));
1200 }
1201
1202 file_put_contents($file, sprintf('<?php return %s;', var_export($maps, true)));
1203 }
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217 public static function createMap($path, $excluded = null, IOInterface $io = null, $namespace = null, $autoloadType = null, &$scannedFiles = array())
1218 {
1219 if (is_string($path)) {
1220 $basePath = $path;
1221 if (is_file($path)) {
1222 $path = array(new \SplFileInfo($path));
1223 } elseif (is_dir($path)) {
1224 $path = Finder::create()->files()->followLinks()->name('/\.(php|inc|hh)$/')->in($path);
1225 } else {
1226 throw new \RuntimeException(
1227 'Could not scan for classes inside "'.$path.
1228 '" which does not appear to be a file nor a folder'
1229 );
1230 }
1231 } elseif (null !== $autoloadType) {
1232 throw new \RuntimeException('Path must be a string when specifying an autoload type');
1233 }
1234
1235 $map = array();
1236 $filesystem = new Filesystem();
1237 $cwd = realpath(getcwd());
1238
1239 foreach ($path as $file) {
1240 $filePath = $file->getPathname();
1241 if (!in_array(pathinfo($filePath, PATHINFO_EXTENSION), array('php', 'inc', 'hh'))) {
1242 continue;
1243 }
1244
1245 if (!$filesystem->isAbsolutePath($filePath)) {
1246 $filePath = $cwd . '/' . $filePath;
1247 $filePath = $filesystem->normalizePath($filePath);
1248 } else {
1249 $filePath = preg_replace('{[\\\\/]{2,}}', '/', $filePath);
1250 }
1251
1252 $realPath = realpath($filePath);
1253
1254
1255
1256 if (isset($scannedFiles[$realPath])) {
1257 continue;
1258 }
1259
1260
1261 if ($excluded && preg_match($excluded, strtr($realPath, '\\', '/'))) {
1262 continue;
1263 }
1264
1265 if ($excluded && preg_match($excluded, strtr($filePath, '\\', '/'))) {
1266 continue;
1267 }
1268
1269 $classes = self::findClasses($filePath);
1270 if (null !== $autoloadType) {
1271 list($classes, $validClasses) = self::filterByNamespace($classes, $filePath, $namespace, $autoloadType, $basePath, $io);
1272
1273
1274 if ($validClasses) {
1275 $scannedFiles[$realPath] = true;
1276 }
1277 } else {
1278
1279 $scannedFiles[$realPath] = true;
1280 }
1281
1282 foreach ($classes as $class) {
1283
1284
1285 if ( null !== $namespace && '' !== $namespace && 0 !== strpos($class, $namespace)) {
1286 continue;
1287 }
1288
1289 if (!isset($map[$class])) {
1290 $map[$class] = $filePath;
1291 } elseif ($io && $map[$class] !== $filePath && !preg_match('{/(test|fixture|example|stub)s?/}i', strtr($map[$class].' '.$filePath, '\\', '/'))) {
1292 $io->writeError(
1293 '<warning>Warning: Ambiguous class resolution, "'.$class.'"'.
1294 ' was found in both "'.$map[$class].'" and "'.$filePath.'", the first will be used.</warning>'
1295 );
1296 }
1297 }
1298 }
1299
1300 return $map;
1301 }
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314 private static function filterByNamespace($classes, $filePath, $baseNamespace, $namespaceType, $basePath, $io)
1315 {
1316 $validClasses = array();
1317 $rejectedClasses = array();
1318
1319 $realSubPath = substr($filePath, strlen($basePath) + 1);
1320 $realSubPath = substr($realSubPath, 0, strrpos($realSubPath, '.'));
1321
1322 foreach ($classes as $class) {
1323
1324 if ('' !== $baseNamespace && 0 !== strpos($class, $baseNamespace)) {
1325 continue;
1326 }
1327
1328 if ('psr-0' === $namespaceType) {
1329 $namespaceLength = strrpos($class, '\\');
1330 if (false !== $namespaceLength) {
1331 $namespace = substr($class, 0, $namespaceLength + 1);
1332 $className = substr($class, $namespaceLength + 1);
1333 $subPath = str_replace('\\', DIRECTORY_SEPARATOR, $namespace)
1334 . str_replace('_', DIRECTORY_SEPARATOR, $className);
1335 }
1336 else {
1337 $subPath = str_replace('_', DIRECTORY_SEPARATOR, $class);
1338 }
1339 } elseif ('psr-4' === $namespaceType) {
1340 $subNamespace = ('' !== $baseNamespace) ? substr($class, strlen($baseNamespace)) : $class;
1341 $subPath = str_replace('\\', DIRECTORY_SEPARATOR, $subNamespace);
1342 } else {
1343 throw new \RuntimeException("namespaceType must be psr-0 or psr-4, $namespaceType given");
1344 }
1345 if ($subPath === $realSubPath) {
1346 $validClasses[] = $class;
1347 } else {
1348 $rejectedClasses[] = $class;
1349 }
1350 }
1351
1352 if (empty($validClasses)) {
1353 foreach ($rejectedClasses as $class) {
1354 trigger_error(
1355 "Class $class located in ".preg_replace('{^'.preg_quote(getcwd()).'}', '.', $filePath, 1)." does not comply with $namespaceType autoloading standard. It will not autoload anymore in Composer v2.0.",
1356 E_USER_DEPRECATED
1357 );
1358 }
1359
1360
1361
1362 }
1363
1364
1365
1366 return array($classes, $validClasses);
1367 }
1368
1369
1370
1371
1372
1373
1374
1375
1376 private static function findClasses($path)
1377 {
1378 $extraTypes = PHP_VERSION_ID < 50400 ? '' : '|trait';
1379 if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>=')) {
1380 $extraTypes .= '|enum';
1381 }
1382
1383
1384
1385 $contents = @php_strip_whitespace($path);
1386 if (!$contents) {
1387 if (!file_exists($path)) {
1388 $message = 'File at "%s" does not exist, check your classmap definitions';
1389 } elseif (!is_readable($path)) {
1390 $message = 'File at "%s" is not readable, check its permissions';
1391 } elseif ('' === trim(file_get_contents($path))) {
1392
1393 return array();
1394 } else {
1395 $message = 'File at "%s" could not be parsed as PHP, it may be binary or corrupted';
1396 }
1397 $error = error_get_last();
1398 if (isset($error['message'])) {
1399 $message .= PHP_EOL . 'The following message may be helpful:' . PHP_EOL . $error['message'];
1400 }
1401 throw new \RuntimeException(sprintf($message, $path));
1402 }
1403
1404
1405 if (!preg_match('{\b(?:class|interface'.$extraTypes.')\s}i', $contents)) {
1406 return array();
1407 }
1408
1409
1410 $contents = preg_replace('{<<<[ \t]*([\'"]?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)(?:\s*)\\2(?=\s+|[;,.)])}s', 'null', $contents);
1411
1412 $contents = preg_replace('{"[^"\\\\]*+(\\\\.[^"\\\\]*+)*+"|\'[^\'\\\\]*+(\\\\.[^\'\\\\]*+)*+\'}s', 'null', $contents);
1413
1414 if (substr($contents, 0, 2) !== '<?') {
1415 $contents = preg_replace('{^.+?<\?}s', '<?', $contents, 1, $replacements);
1416 if ($replacements === 0) {
1417 return array();
1418 }
1419 }
1420
1421 $contents = preg_replace('{\?>(?:[^<]++|<(?!\?))*+<\?}s', '?><?', $contents);
1422
1423 $pos = strrpos($contents, '?>');
1424 if (false !== $pos && false === strpos(substr($contents, $pos), '<?')) {
1425 $contents = substr($contents, 0, $pos);
1426 }
1427
1428 if (preg_match('{(<\?)(?!(php|hh))}i', $contents)) {
1429 $contents = preg_replace('{//.* | /\*(?:[^*]++|\*(?!/))*\*/}x', '', $contents);
1430 }
1431
1432 preg_match_all('{
1433             (?:
1434                  \b(?<![\$:>])(?P<type>class|interface'.$extraTypes.') \s++ (?P<name>[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*+)
1435                | \b(?<![\$:>])(?P<ns>namespace) (?P<nsname>\s++[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\s*+\\\\\s*+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+)? \s*+ [\{;]
1436             )
1437         }ix', $contents, $matches);
1438
1439 $classes = array();
1440 $namespace = '';
1441
1442 for ($i = 0, $len = count($matches['type']); $i < $len; $i++) {
1443 if (!empty($matches['ns'][$i])) {
1444 $namespace = str_replace(array(' ', "\t", "\r", "\n"), '', $matches['nsname'][$i]) . '\\';
1445 } else {
1446 $name = $matches['name'][$i];
1447
1448 if ($name === 'extends' || $name === 'implements') {
1449 continue;
1450 }
1451 if ($name[0] === ':') {
1452
1453 $name = 'xhp'.substr(str_replace(array('-', ':'), array('_', '__'), $name), 1);
1454 } elseif ($matches['type'][$i] === 'enum') {
1455
1456
1457
1458
1459 $name = rtrim($name, ':');
1460 }
1461 $classes[] = ltrim($namespace . $name, '\\');
1462 }
1463 }
1464
1465 return $classes;
1466 }
1467 }
1468 <?php
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480 namespace Composer;
1481
1482 use Composer\IO\IOInterface;
1483 use Composer\Util\Filesystem;
1484 use Composer\Util\Silencer;
1485 use Symfony\Component\Finder\Finder;
1486
1487
1488
1489
1490
1491
1492 class Cache
1493 {
1494 private static $cacheCollected = false;
1495 private $io;
1496 private $root;
1497 private $enabled = true;
1498 private $allowList;
1499 private $filesystem;
1500
1501
1502
1503
1504
1505
1506
1507 public function __construct(IOInterface $io, $cacheDir, $allowList = 'a-z0-9.', Filesystem $filesystem = null)
1508 {
1509 $this->io = $io;
1510 $this->root = rtrim($cacheDir, '/\\') . '/';
1511 $this->allowList = $allowList;
1512 $this->filesystem = $filesystem ?: new Filesystem();
1513
1514 if (!self::isUsable($cacheDir)) {
1515 $this->enabled = false;
1516
1517 return;
1518 }
1519
1520 if (
1521 (!is_dir($this->root) && !Silencer::call('mkdir', $this->root, 0777, true))
1522 || !is_writable($this->root)
1523 ) {
1524 $this->io->writeError('<warning>Cannot create cache directory ' . $this->root . ', or directory is not writable. Proceeding without cache</warning>');
1525 $this->enabled = false;
1526 }
1527 }
1528
1529 public static function isUsable($path)
1530 {
1531 return !preg_match('{(^|[\\\\/])(\$null|nul|NUL|/dev/null)([\\\\/]|$)}', $path);
1532 }
1533
1534 public function isEnabled()
1535 {
1536 return $this->enabled;
1537 }
1538
1539 public function getRoot()
1540 {
1541 return $this->root;
1542 }
1543
1544 public function read($file)
1545 {
1546 if ($this->enabled) {
1547 $file = preg_replace('{[^'.$this->allowList.']}i', '-', $file);
1548 if (file_exists($this->root . $file)) {
1549 $this->io->writeError('Reading '.$this->root . $file.' from cache', true, IOInterface::DEBUG);
1550
1551 return file_get_contents($this->root . $file);
1552 }
1553 }
1554
1555 return false;
1556 }
1557
1558 public function write($file, $contents)
1559 {
1560 if ($this->enabled) {
1561 $file = preg_replace('{[^'.$this->allowList.']}i', '-', $file);
1562
1563 $this->io->writeError('Writing '.$this->root . $file.' into cache', true, IOInterface::DEBUG);
1564
1565 try {
1566 return file_put_contents($this->root . $file, $contents);
1567 } catch (\ErrorException $e) {
1568 $this->io->writeError('<warning>Failed to write into cache: '.$e->getMessage().'</warning>', true, IOInterface::DEBUG);
1569 if (preg_match('{^file_put_contents\(\): Only ([0-9]+) of ([0-9]+) bytes written}', $e->getMessage(), $m)) {
1570
1571 unlink($this->root . $file);
1572
1573 $message = sprintf(
1574 '<warning>Writing %1$s into cache failed after %2$u of %3$u bytes written, only %4$u bytes of free space available</warning>',
1575 $this->root . $file,
1576 $m[1],
1577 $m[2],
1578 @disk_free_space($this->root . dirname($file))
1579 );
1580
1581 $this->io->writeError($message);
1582
1583 return false;
1584 }
1585
1586 throw $e;
1587 }
1588 }
1589
1590 return false;
1591 }
1592
1593
1594
1595
1596 public function copyFrom($file, $source)
1597 {
1598 if ($this->enabled) {
1599 $file = preg_replace('{[^'.$this->allowList.']}i', '-', $file);
1600 $this->filesystem->ensureDirectoryExists(dirname($this->root . $file));
1601
1602 if (!file_exists($source)) {
1603 $this->io->writeError('<error>'.$source.' does not exist, can not write into cache</error>');
1604 } elseif ($this->io->isDebug()) {
1605 $this->io->writeError('Writing '.$this->root . $file.' into cache from '.$source);
1606 }
1607
1608 return copy($source, $this->root . $file);
1609 }
1610
1611 return false;
1612 }
1613
1614
1615
1616
1617 public function copyTo($file, $target)
1618 {
1619 if ($this->enabled) {
1620 $file = preg_replace('{[^'.$this->allowList.']}i', '-', $file);
1621 if (file_exists($this->root . $file)) {
1622 try {
1623 touch($this->root . $file, filemtime($this->root . $file), time());
1624 } catch (\ErrorException $e) {
1625
1626
1627 Silencer::call('touch', $this->root . $file);
1628 }
1629
1630 $this->io->writeError('Reading '.$this->root . $file.' from cache', true, IOInterface::DEBUG);
1631
1632 return copy($this->root . $file, $target);
1633 }
1634 }
1635
1636 return false;
1637 }
1638
1639 public function gcIsNecessary()
1640 {
1641 return (!self::$cacheCollected && !mt_rand(0, 50));
1642 }
1643
1644 public function remove($file)
1645 {
1646 if ($this->enabled) {
1647 $file = preg_replace('{[^'.$this->allowList.']}i', '-', $file);
1648 if (file_exists($this->root . $file)) {
1649 return $this->filesystem->unlink($this->root . $file);
1650 }
1651 }
1652
1653 return false;
1654 }
1655
1656 public function clear()
1657 {
1658 if ($this->enabled) {
1659 $this->filesystem->emptyDirectory($this->root);
1660 return true;
1661 }
1662
1663 return false;
1664 }
1665
1666 public function gc($ttl, $maxSize)
1667 {
1668 if ($this->enabled) {
1669 $expire = new \DateTime();
1670 $expire->modify('-'.$ttl.' seconds');
1671
1672 $finder = $this->getFinder()->date('until '.$expire->format('Y-m-d H:i:s'));
1673 foreach ($finder as $file) {
1674 $this->filesystem->unlink($file->getPathname());
1675 }
1676
1677 $totalSize = $this->filesystem->size($this->root);
1678 if ($totalSize > $maxSize) {
1679 $iterator = $this->getFinder()->sortByAccessedTime()->getIterator();
1680 while ($totalSize > $maxSize && $iterator->valid()) {
1681 $filepath = $iterator->current()->getPathname();
1682 $totalSize -= $this->filesystem->size($filepath);
1683 $this->filesystem->unlink($filepath);
1684 $iterator->next();
1685 }
1686 }
1687
1688 self::$cacheCollected = true;
1689
1690 return true;
1691 }
1692
1693 return false;
1694 }
1695
1696 public function sha1($file)
1697 {
1698 if ($this->enabled) {
1699 $file = preg_replace('{[^'.$this->allowList.']}i', '-', $file);
1700 if (file_exists($this->root . $file)) {
1701 return sha1_file($this->root . $file);
1702 }
1703 }
1704
1705 return false;
1706 }
1707
1708 public function sha256($file)
1709 {
1710 if ($this->enabled) {
1711 $file = preg_replace('{[^'.$this->allowList.']}i', '-', $file);
1712 if (file_exists($this->root . $file)) {
1713 return hash_file('sha256', $this->root . $file);
1714 }
1715 }
1716
1717 return false;
1718 }
1719
1720 protected function getFinder()
1721 {
1722 return Finder::create()->in($this->root)->files();
1723 }
1724 }
1725 <?php
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737 namespace Composer\Command;
1738
1739 use Symfony\Component\Console\Input\InputInterface;
1740 use Symfony\Component\Console\Output\OutputInterface;
1741
1742
1743
1744
1745 class AboutCommand extends BaseCommand
1746 {
1747 protected function configure()
1748 {
1749 $this
1750 ->setName('about')
1751 ->setDescription('Shows the short information about Composer.')
1752 ->setHelp(
1753 <<<EOT
1754 <info>php composer.phar about</info>
1755 EOT
1756 )
1757 ;
1758 }
1759
1760 protected function execute(InputInterface $input, OutputInterface $output)
1761 {
1762 $this->getIO()->write(
1763 <<<EOT
1764 <info>Composer - Dependency Manager for PHP</info>
1765 <comment>Composer is a dependency manager tracking local dependencies of your projects and libraries.
1766 See https://getcomposer.org/ for more information.</comment>
1767 EOT
1768 );
1769
1770 return 0;
1771 }
1772 }
1773 <?php
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785 namespace Composer\Command;
1786
1787 use Composer\Factory;
1788 use Composer\IO\IOInterface;
1789 use Composer\Config;
1790 use Composer\Composer;
1791 use Composer\Repository\CompositeRepository;
1792 use Composer\Repository\RepositoryFactory;
1793 use Composer\Script\ScriptEvents;
1794 use Composer\Plugin\CommandEvent;
1795 use Composer\Plugin\PluginEvents;
1796 use Composer\Util\Filesystem;
1797 use Symfony\Component\Console\Input\InputArgument;
1798 use Symfony\Component\Console\Input\InputInterface;
1799 use Symfony\Component\Console\Input\InputOption;
1800 use Symfony\Component\Console\Output\OutputInterface;
1801
1802
1803
1804
1805
1806
1807 class ArchiveCommand extends BaseCommand
1808 {
1809 protected function configure()
1810 {
1811 $this
1812 ->setName('archive')
1813 ->setDescription('Creates an archive of this composer package.')
1814 ->setDefinition(array(
1815 new InputArgument('package', InputArgument::OPTIONAL, 'The package to archive instead of the current project'),
1816 new InputArgument('version', InputArgument::OPTIONAL, 'A version constraint to find the package to archive'),
1817 new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the resulting archive: tar or zip'),
1818 new InputOption('dir', null, InputOption::VALUE_REQUIRED, 'Write the archive to this directory'),
1819 new InputOption('file', null, InputOption::VALUE_REQUIRED, 'Write the archive with the given file name.'
1820 .' Note that the format will be appended.'),
1821 new InputOption('ignore-filters', false, InputOption::VALUE_NONE, 'Ignore filters when saving package'),
1822 ))
1823 ->setHelp(
1824 <<<EOT
1825 The <info>archive</info> command creates an archive of the specified format
1826 containing the files and directories of the Composer project or the specified
1827 package in the specified version and writes it to the specified directory.
1828
1829 <info>php composer.phar archive [--format=zip] [--dir=/foo] [package [version]]</info>
1830
1831 Read more at https://getcomposer.org/doc/03-cli.md#archive
1832 EOT
1833 )
1834 ;
1835 }
1836
1837 protected function execute(InputInterface $input, OutputInterface $output)
1838 {
1839 $composer = $this->getComposer(false);
1840 $config = null;
1841
1842 if ($composer) {
1843 $config = $composer->getConfig();
1844 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'archive', $input, $output);
1845 $eventDispatcher = $composer->getEventDispatcher();
1846 $eventDispatcher->dispatch($commandEvent->getName(), $commandEvent);
1847 $eventDispatcher->dispatchScript(ScriptEvents::PRE_ARCHIVE_CMD);
1848 }
1849
1850 if (!$config) {
1851 $config = Factory::createConfig();
1852 }
1853
1854 if (null === $input->getOption('format')) {
1855 $input->setOption('format', $config->get('archive-format'));
1856 }
1857 if (null === $input->getOption('dir')) {
1858 $input->setOption('dir', $config->get('archive-dir'));
1859 }
1860
1861 $returnCode = $this->archive(
1862 $this->getIO(),
1863 $config,
1864 $input->getArgument('package'),
1865 $input->getArgument('version'),
1866 $input->getOption('format'),
1867 $input->getOption('dir'),
1868 $input->getOption('file'),
1869 $input->getOption('ignore-filters'),
1870 $composer
1871 );
1872
1873 if (0 === $returnCode && $composer) {
1874 $composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_ARCHIVE_CMD);
1875 }
1876
1877 return $returnCode;
1878 }
1879
1880 protected function archive(IOInterface $io, Config $config, $packageName = null, $version = null, $format = 'tar', $dest = '.', $fileName = null, $ignoreFilters = false, Composer $composer = null)
1881 {
1882 if ($composer) {
1883 $archiveManager = $composer->getArchiveManager();
1884 } else {
1885 $factory = new Factory;
1886 $downloadManager = $factory->createDownloadManager($io, $config);
1887 $archiveManager = $factory->createArchiveManager($config, $downloadManager);
1888 }
1889
1890 if ($packageName) {
1891 $package = $this->selectPackage($io, $packageName, $version);
1892
1893 if (!$package) {
1894 return 1;
1895 }
1896 } else {
1897 $package = $this->getComposer()->getPackage();
1898 }
1899
1900 $io->writeError('<info>Creating the archive into "'.$dest.'".</info>');
1901 $packagePath = $archiveManager->archive($package, $format, $dest, $fileName, $ignoreFilters);
1902 $fs = new Filesystem;
1903 $shortPath = $fs->findShortestPath(getcwd(), $packagePath, true);
1904
1905 $io->writeError('Created: ', false);
1906 $io->write(strlen($shortPath) < strlen($packagePath) ? $shortPath : $packagePath);
1907
1908 return 0;
1909 }
1910
1911 protected function selectPackage(IOInterface $io, $packageName, $version = null)
1912 {
1913 $io->writeError('<info>Searching for the specified package.</info>');
1914
1915 if ($composer = $this->getComposer(false)) {
1916 $localRepo = $composer->getRepositoryManager()->getLocalRepository();
1917 $repo = new CompositeRepository(array_merge(array($localRepo), $composer->getRepositoryManager()->getRepositories()));
1918 } else {
1919 $defaultRepos = RepositoryFactory::defaultRepos($this->getIO());
1920 $io->writeError('No composer.json found in the current directory, searching packages from ' . implode(', ', array_keys($defaultRepos)));
1921 $repo = new CompositeRepository($defaultRepos);
1922 }
1923
1924 $packages = $repo->findPackages($packageName, $version);
1925
1926 if (count($packages) > 1) {
1927 $package = reset($packages);
1928 $io->writeError('<info>Found multiple matches, selected '.$package->getPrettyString().'.</info>');
1929 $io->writeError('Alternatives were '.implode(', ', array_map(function ($p) {
1930 return $p->getPrettyString();
1931 }, $packages)).'.');
1932 $io->writeError('<comment>Please use a more specific constraint to pick a different package.</comment>');
1933 } elseif ($packages) {
1934 $package = reset($packages);
1935 $io->writeError('<info>Found an exact match '.$package->getPrettyString().'.</info>');
1936 } else {
1937 $io->writeError('<error>Could not find a package matching '.$packageName.'.</error>');
1938
1939 return false;
1940 }
1941
1942 return $package;
1943 }
1944 }
1945 <?php
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957 namespace Composer\Command;
1958
1959 use Composer\Composer;
1960 use Composer\Config;
1961 use Composer\Console\Application;
1962 use Composer\Factory;
1963 use Composer\IO\IOInterface;
1964 use Composer\IO\NullIO;
1965 use Composer\Plugin\PreCommandRunEvent;
1966 use Composer\Plugin\PluginEvents;
1967 use Symfony\Component\Console\Input\InputInterface;
1968 use Symfony\Component\Console\Output\OutputInterface;
1969 use Symfony\Component\Console\Command\Command;
1970
1971
1972
1973
1974
1975
1976
1977 abstract class BaseCommand extends Command
1978 {
1979
1980
1981
1982 private $composer;
1983
1984
1985
1986
1987 private $io;
1988
1989
1990
1991
1992
1993
1994
1995 public function getComposer($required = true, $disablePlugins = null)
1996 {
1997 if (null === $this->composer) {
1998 $application = $this->getApplication();
1999 if ($application instanceof Application) {
2000
2001 $this->composer = $application->getComposer($required, $disablePlugins);
2002 } elseif ($required) {
2003 throw new \RuntimeException(
2004 'Could not create a Composer\Composer instance, you must inject '.
2005 'one if this command is not used with a Composer\Console\Application instance'
2006 );
2007 }
2008 }
2009
2010 return $this->composer;
2011 }
2012
2013
2014
2015
2016 public function setComposer(Composer $composer)
2017 {
2018 $this->composer = $composer;
2019 }
2020
2021
2022
2023
2024 public function resetComposer()
2025 {
2026 $this->composer = null;
2027 $this->getApplication()->resetComposer();
2028 }
2029
2030
2031
2032
2033
2034
2035
2036
2037 public function isProxyCommand()
2038 {
2039 return false;
2040 }
2041
2042
2043
2044
2045 public function getIO()
2046 {
2047 if (null === $this->io) {
2048 $application = $this->getApplication();
2049 if ($application instanceof Application) {
2050
2051 $this->io = $application->getIO();
2052 } else {
2053 $this->io = new NullIO();
2054 }
2055 }
2056
2057 return $this->io;
2058 }
2059
2060
2061
2062
2063 public function setIO(IOInterface $io)
2064 {
2065 $this->io = $io;
2066 }
2067
2068
2069
2070
2071 protected function initialize(InputInterface $input, OutputInterface $output)
2072 {
2073
2074 $disablePlugins = $input->hasParameterOption('--no-plugins');
2075 $composer = $this->getComposer(false, $disablePlugins);
2076 if (null === $composer) {
2077 $composer = Factory::createGlobal($this->getIO(), $disablePlugins);
2078 }
2079 if ($composer) {
2080 $preCommandRunEvent = new PreCommandRunEvent(PluginEvents::PRE_COMMAND_RUN, $input, $this->getName());
2081 $composer->getEventDispatcher()->dispatch($preCommandRunEvent->getName(), $preCommandRunEvent);
2082 }
2083
2084 if (true === $input->hasParameterOption(array('--no-ansi')) && $input->hasOption('no-progress')) {
2085 $input->setOption('no-progress', true);
2086 }
2087
2088 parent::initialize($input, $output);
2089 }
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100 protected function getPreferredInstallOptions(Config $config, InputInterface $input, $keepVcsRequiresPreferSource = false)
2101 {
2102 $preferSource = false;
2103 $preferDist = false;
2104
2105 switch ($config->get('preferred-install')) {
2106 case 'source':
2107 $preferSource = true;
2108 break;
2109 case 'dist':
2110 $preferDist = true;
2111 break;
2112 case 'auto':
2113 default:
2114
2115 break;
2116 }
2117
2118 if ($input->getOption('prefer-source') || $input->getOption('prefer-dist') || ($keepVcsRequiresPreferSource && $input->hasOption('keep-vcs') && $input->getOption('keep-vcs'))) {
2119 $preferSource = $input->getOption('prefer-source') || ($keepVcsRequiresPreferSource && $input->hasOption('keep-vcs') && $input->getOption('keep-vcs'));
2120 $preferDist = $input->getOption('prefer-dist');
2121 }
2122
2123 return array($preferSource, $preferDist);
2124 }
2125 }
2126 <?php
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138 namespace Composer\Command;
2139
2140 use Composer\DependencyResolver\Pool;
2141 use Composer\Package\Link;
2142 use Composer\Package\PackageInterface;
2143 use Composer\Repository\ArrayRepository;
2144 use Composer\Repository\CompositeRepository;
2145 use Composer\Repository\PlatformRepository;
2146 use Composer\Repository\RepositoryFactory;
2147 use Composer\Plugin\CommandEvent;
2148 use Composer\Plugin\PluginEvents;
2149 use Symfony\Component\Console\Formatter\OutputFormatterStyle;
2150 use Composer\Package\Version\VersionParser;
2151 use Symfony\Component\Console\Helper\Table;
2152 use Symfony\Component\Console\Input\InputArgument;
2153 use Symfony\Component\Console\Input\InputInterface;
2154 use Symfony\Component\Console\Input\InputOption;
2155 use Symfony\Component\Console\Output\OutputInterface;
2156
2157
2158
2159
2160
2161
2162 class BaseDependencyCommand extends BaseCommand
2163 {
2164 const ARGUMENT_PACKAGE = 'package';
2165 const ARGUMENT_CONSTRAINT = 'constraint';
2166 const OPTION_RECURSIVE = 'recursive';
2167 const OPTION_TREE = 'tree';
2168
2169 protected $colors;
2170
2171
2172
2173
2174 protected function configure()
2175 {
2176 $this->setDefinition(array(
2177 new InputArgument(self::ARGUMENT_PACKAGE, InputArgument::REQUIRED, 'Package to inspect'),
2178 new InputArgument(self::ARGUMENT_CONSTRAINT, InputArgument::OPTIONAL, 'Optional version constraint', '*'),
2179 new InputOption(self::OPTION_RECURSIVE, 'r', InputOption::VALUE_NONE, 'Recursively resolves up to the root package'),
2180 new InputOption(self::OPTION_TREE, 't', InputOption::VALUE_NONE, 'Prints the results as a nested tree'),
2181 ));
2182 }
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192 protected function doExecute(InputInterface $input, OutputInterface $output, $inverted = false)
2193 {
2194
2195 $composer = $this->getComposer();
2196 $commandEvent = new CommandEvent(PluginEvents::COMMAND, $this->getName(), $input, $output);
2197 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
2198
2199
2200 $platformOverrides = $composer->getConfig()->get('platform') ?: array();
2201 $repository = new CompositeRepository(array(
2202 new ArrayRepository(array($composer->getPackage())),
2203 $composer->getRepositoryManager()->getLocalRepository(),
2204 new PlatformRepository(array(), $platformOverrides),
2205 ));
2206 $pool = new Pool();
2207 $pool->addRepository($repository);
2208
2209
2210 list($needle, $textConstraint) = array_pad(
2211 explode(':', $input->getArgument(self::ARGUMENT_PACKAGE)),
2212 2,
2213 $input->getArgument(self::ARGUMENT_CONSTRAINT)
2214 );
2215
2216
2217 $packages = $pool->whatProvides(strtolower($needle));
2218 if (empty($packages)) {
2219 throw new \InvalidArgumentException(sprintf('Could not find package "%s" in your project', $needle));
2220 }
2221
2222
2223
2224 if (!$repository->findPackage($needle, $textConstraint)) {
2225 $defaultRepos = new CompositeRepository(RepositoryFactory::defaultRepos($this->getIO()));
2226 if ($match = $defaultRepos->findPackage($needle, $textConstraint)) {
2227 $repository->addRepository(new ArrayRepository(array(clone $match)));
2228 }
2229 }
2230
2231
2232 $needles = array($needle);
2233 if ($inverted) {
2234 foreach ($packages as $package) {
2235 $needles = array_merge($needles, array_map(function (Link $link) {
2236 return $link->getTarget();
2237 }, $package->getReplaces()));
2238 }
2239 }
2240
2241
2242 if ('*' !== $textConstraint) {
2243 $versionParser = new VersionParser();
2244 $constraint = $versionParser->parseConstraints($textConstraint);
2245 } else {
2246 $constraint = null;
2247 }
2248
2249
2250 $renderTree = $input->getOption(self::OPTION_TREE);
2251 $recursive = $renderTree || $input->getOption(self::OPTION_RECURSIVE);
2252
2253
2254 $results = $repository->getDependents($needles, $constraint, $inverted, $recursive);
2255 if (empty($results)) {
2256 $extra = (null !== $constraint) ? sprintf(' in versions %smatching %s', $inverted ? 'not ' : '', $textConstraint) : '';
2257 $this->getIO()->writeError(sprintf(
2258 '<info>There is no installed package depending on "%s"%s</info>',
2259 $needle,
2260 $extra
2261 ));
2262 } elseif ($renderTree) {
2263 $this->initStyles($output);
2264 $root = $packages[0];
2265 $this->getIO()->write(sprintf('<info>%s</info> %s %s', $root->getPrettyName(), $root->getPrettyVersion(), $root->getDescription()));
2266 $this->printTree($results);
2267 } else {
2268 $this->printTable($output, $results);
2269 }
2270
2271 return 0;
2272 }
2273
2274
2275
2276
2277
2278
2279
2280 protected function printTable(OutputInterface $output, $results)
2281 {
2282 $table = array();
2283 $doubles = array();
2284 do {
2285 $queue = array();
2286 $rows = array();
2287 foreach ($results as $result) {
2288
2289
2290
2291
2292 list($package, $link, $children) = $result;
2293 $unique = (string) $link;
2294 if (isset($doubles[$unique])) {
2295 continue;
2296 }
2297 $doubles[$unique] = true;
2298 $version = (strpos($package->getPrettyVersion(), 'No version set') === 0) ? '-' : $package->getPrettyVersion();
2299 $rows[] = array($package->getPrettyName(), $version, $link->getDescription(), sprintf('%s (%s)', $link->getTarget(), $link->getPrettyConstraint()));
2300 if ($children) {
2301 $queue = array_merge($queue, $children);
2302 }
2303 }
2304 $results = $queue;
2305 $table = array_merge($rows, $table);
2306 } while (!empty($results));
2307
2308
2309 $renderer = new Table($output);
2310 $renderer->setStyle('compact');
2311 $rendererStyle = $renderer->getStyle();
2312 if (method_exists($rendererStyle, 'setVerticalBorderChars')) {
2313 $rendererStyle->setVerticalBorderChars('');
2314 } else {
2315 $rendererStyle->setVerticalBorderChar('');
2316 }
2317 $rendererStyle->setCellRowContentFormat('%s  ');
2318 $renderer->setRows($table)->render();
2319 }
2320
2321
2322
2323
2324
2325
2326 protected function initStyles(OutputInterface $output)
2327 {
2328 $this->colors = array(
2329 'green',
2330 'yellow',
2331 'cyan',
2332 'magenta',
2333 'blue',
2334 );
2335
2336 foreach ($this->colors as $color) {
2337 $style = new OutputFormatterStyle($color);
2338 $output->getFormatter()->setStyle($color, $style);
2339 }
2340 }
2341
2342
2343
2344
2345
2346
2347
2348
2349 protected function printTree($results, $prefix = '', $level = 1)
2350 {
2351 $count = count($results);
2352 $idx = 0;
2353 foreach ($results as $result) {
2354
2355
2356
2357
2358
2359 list($package, $link, $children) = $result;
2360
2361 $color = $this->colors[$level % count($this->colors)];
2362 $prevColor = $this->colors[($level - 1) % count($this->colors)];
2363 $isLast = (++$idx == $count);
2364 $versionText = (strpos($package->getPrettyVersion(), 'No version set') === 0) ? '' : $package->getPrettyVersion();
2365 $packageText = rtrim(sprintf('<%s>%s</%1$s> %s', $color, $package->getPrettyName(), $versionText));
2366 $linkText = sprintf('%s <%s>%s</%2$s> %s', $link->getDescription(), $prevColor, $link->getTarget(), $link->getPrettyConstraint());
2367 $circularWarn = $children === false ? '(circular dependency aborted here)' : '';
2368 $this->writeTreeLine(rtrim(sprintf("%s%s%s (%s) %s", $prefix, $isLast ? '└──' : '├──', $packageText, $linkText, $circularWarn)));
2369 if ($children) {
2370 $this->printTree($children, $prefix . ($isLast ? '   ' : '│  '), $level + 1);
2371 }
2372 }
2373 }
2374
2375 private function writeTreeLine($line)
2376 {
2377 $io = $this->getIO();
2378 if (!$io->isDecorated()) {
2379 $line = str_replace(array('└', '├', '──', '│'), array('`-', '|-', '-', '|'), $line);
2380 }
2381
2382 $io->write($line);
2383 }
2384 }
2385 <?php
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397 namespace Composer\Command;
2398
2399 use Composer\Package\Link;
2400 use Composer\Package\PackageInterface;
2401 use Composer\Semver\Constraint\Constraint;
2402 use Symfony\Component\Console\Helper\Table;
2403 use Symfony\Component\Console\Input\InputInterface;
2404 use Symfony\Component\Console\Input\InputOption;
2405 use Symfony\Component\Console\Output\OutputInterface;
2406 use Composer\Repository\PlatformRepository;
2407
2408 class CheckPlatformReqsCommand extends BaseCommand
2409 {
2410 protected function configure()
2411 {
2412 $this->setName('check-platform-reqs')
2413 ->setDescription('Check that platform requirements are satisfied.')
2414 ->setDefinition(array(
2415 new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables checking of require-dev packages requirements.'),
2416 ))
2417 ->setHelp(
2418 <<<EOT
2419 Checks that your PHP and extensions versions match the platform requirements of the installed packages.
2420
2421 Unlike update/install, this command will ignore config.platform settings and check the real platform packages so you can be certain you have the required platform dependencies.
2422
2423 <info>php composer.phar check-platform-reqs</info>
2424
2425 EOT
2426 );
2427 }
2428
2429 protected function execute(InputInterface $input, OutputInterface $output)
2430 {
2431 $composer = $this->getComposer();
2432
2433 $requires = $composer->getPackage()->getRequires();
2434 if ($input->getOption('no-dev')) {
2435 $dependencies = $composer->getLocker()->getLockedRepository(!$input->getOption('no-dev'))->getPackages();
2436 } else {
2437 $dependencies = $composer->getRepositoryManager()->getLocalRepository()->getPackages();
2438
2439 if (!$dependencies) {
2440 $dependencies = $composer->getLocker()->getLockedRepository(true)->getPackages();
2441 }
2442 $requires += $composer->getPackage()->getDevRequires();
2443 }
2444 foreach ($requires as $require => $link) {
2445 $requires[$require] = array($link);
2446 }
2447
2448 foreach ($dependencies as $package) {
2449 foreach ($package->getRequires() as $require => $link) {
2450 $requires[$require][] = $link;
2451 }
2452 }
2453
2454 ksort($requires);
2455
2456 $platformRepo = new PlatformRepository(array(), array());
2457 $currentPlatformPackages = $platformRepo->getPackages();
2458 $currentPlatformPackageMap = array();
2459
2460
2461
2462
2463 foreach ($currentPlatformPackages as $currentPlatformPackage) {
2464 $currentPlatformPackageMap[$currentPlatformPackage->getName()] = $currentPlatformPackage;
2465 }
2466
2467 $results = array();
2468
2469 $exitCode = 0;
2470
2471
2472
2473
2474 foreach ($requires as $require => $links) {
2475 if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $require)) {
2476 if (isset($currentPlatformPackageMap[$require])) {
2477 $pass = true;
2478 $version = $currentPlatformPackageMap[$require]->getVersion();
2479
2480 foreach ($links as $link) {
2481 if (!$link->getConstraint()->matches(new Constraint('=', $version))) {
2482 $results[] = array(
2483 $currentPlatformPackageMap[$require]->getPrettyName(),
2484 $currentPlatformPackageMap[$require]->getPrettyVersion(),
2485 $link,
2486 '<error>failed</error>',
2487 );
2488 $pass = false;
2489
2490 $exitCode = max($exitCode, 1);
2491 }
2492 }
2493
2494 if ($pass) {
2495 $results[] = array(
2496 $currentPlatformPackageMap[$require]->getPrettyName(),
2497 $currentPlatformPackageMap[$require]->getPrettyVersion(),
2498 null,
2499 '<info>success</info>',
2500 );
2501 }
2502 } else {
2503 $results[] = array(
2504 $require,
2505 'n/a',
2506 $links[0],
2507 '<error>missing</error>',
2508 );
2509
2510 $exitCode = max($exitCode, 2);
2511 }
2512 }
2513 }
2514
2515 $this->printTable($output, $results);
2516
2517 return $exitCode;
2518 }
2519
2520 protected function printTable(OutputInterface $output, $results)
2521 {
2522 $table = array();
2523 $rows = array();
2524 foreach ($results as $result) {
2525
2526
2527
2528 list($platformPackage, $version, $link, $status) = $result;
2529 $rows[] = array(
2530 $platformPackage,
2531 $version,
2532 $link ? sprintf('%s %s %s (%s)', $link->getSource(), $link->getDescription(), $link->getTarget(), $link->getPrettyConstraint()) : '',
2533 $status,
2534 );
2535 }
2536 $table = array_merge($rows, $table);
2537
2538
2539 $renderer = new Table($output);
2540 $renderer->setStyle('compact');
2541 $rendererStyle = $renderer->getStyle();
2542 if (method_exists($rendererStyle, 'setVerticalBorderChars')) {
2543 $rendererStyle->setVerticalBorderChars('');
2544 } else {
2545 $rendererStyle->setVerticalBorderChar('');
2546 }
2547 $rendererStyle->setCellRowContentFormat('%s  ');
2548 $renderer->setRows($table)->render();
2549 }
2550 }
2551 <?php
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563 namespace Composer\Command;
2564
2565 use Composer\Cache;
2566 use Composer\Factory;
2567 use Symfony\Component\Console\Input\InputInterface;
2568 use Symfony\Component\Console\Output\OutputInterface;
2569
2570
2571
2572
2573 class ClearCacheCommand extends BaseCommand
2574 {
2575 protected function configure()
2576 {
2577 $this
2578 ->setName('clear-cache')
2579 ->setAliases(array('clearcache', 'cc'))
2580 ->setDescription('Clears composer\'s internal package cache.')
2581 ->setHelp(
2582 <<<EOT
2583 The <info>clear-cache</info> deletes all cached packages from composer's
2584 cache directory.
2585
2586 Read more at https://getcomposer.org/doc/03-cli.md#clear-cache-clearcache-cc
2587 EOT
2588 )
2589 ;
2590 }
2591
2592 protected function execute(InputInterface $input, OutputInterface $output)
2593 {
2594 $config = Factory::createConfig();
2595 $io = $this->getIO();
2596
2597 $cachePaths = array(
2598 'cache-vcs-dir' => $config->get('cache-vcs-dir'),
2599 'cache-repo-dir' => $config->get('cache-repo-dir'),
2600 'cache-files-dir' => $config->get('cache-files-dir'),
2601 'cache-dir' => $config->get('cache-dir'),
2602 );
2603
2604 foreach ($cachePaths as $key => $cachePath) {
2605 $cachePath = realpath($cachePath);
2606 if (!$cachePath) {
2607 $io->writeError("<info>Cache directory does not exist ($key): $cachePath</info>");
2608
2609 continue;
2610 }
2611 $cache = new Cache($io, $cachePath);
2612 if (!$cache->isEnabled()) {
2613 $io->writeError("<info>Cache is not enabled ($key): $cachePath</info>");
2614
2615 continue;
2616 }
2617
2618 $io->writeError("<info>Clearing cache ($key): $cachePath</info>");
2619 $cache->clear();
2620 }
2621
2622 $io->writeError('<info>All caches cleared.</info>');
2623
2624 return 0;
2625 }
2626 }
2627 <?php
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639 namespace Composer\Command;
2640
2641 use Composer\Util\Platform;
2642 use Composer\Util\Silencer;
2643 use Symfony\Component\Console\Input\InputInterface;
2644 use Symfony\Component\Console\Input\InputArgument;
2645 use Symfony\Component\Console\Input\InputOption;
2646 use Symfony\Component\Console\Output\OutputInterface;
2647 use Composer\Config;
2648 use Composer\Config\JsonConfigSource;
2649 use Composer\Factory;
2650 use Composer\IO\IOInterface;
2651 use Composer\Json\JsonFile;
2652 use Composer\Semver\VersionParser;
2653 use Composer\Package\BasePackage;
2654
2655
2656
2657
2658
2659 class ConfigCommand extends BaseCommand
2660 {
2661
2662
2663
2664 protected $config;
2665
2666
2667
2668
2669 protected $configFile;
2670
2671
2672
2673
2674 protected $configSource;
2675
2676
2677
2678
2679 protected $authConfigFile;
2680
2681
2682
2683
2684 protected $authConfigSource;
2685
2686
2687
2688
2689 protected function configure()
2690 {
2691 $this
2692 ->setName('config')
2693 ->setDescription('Sets config options.')
2694 ->setDefinition(array(
2695 new InputOption('global', 'g', InputOption::VALUE_NONE, 'Apply command to the global config file'),
2696 new InputOption('editor', 'e', InputOption::VALUE_NONE, 'Open editor'),
2697 new InputOption('auth', 'a', InputOption::VALUE_NONE, 'Affect auth config file (only used for --editor)'),
2698 new InputOption('unset', null, InputOption::VALUE_NONE, 'Unset the given setting-key'),
2699 new InputOption('list', 'l', InputOption::VALUE_NONE, 'List configuration settings'),
2700 new InputOption('file', 'f', InputOption::VALUE_REQUIRED, 'If you want to choose a different composer.json or config.json'),
2701 new InputOption('absolute', null, InputOption::VALUE_NONE, 'Returns absolute paths when fetching *-dir config values instead of relative'),
2702 new InputArgument('setting-key', null, 'Setting key'),
2703 new InputArgument('setting-value', InputArgument::IS_ARRAY, 'Setting value'),
2704 ))
2705 ->setHelp(
2706 <<<EOT
2707 This command allows you to edit composer config settings and repositories
2708 in either the local composer.json file or the global config.json file.
2709
2710 Additionally it lets you edit most properties in the local composer.json.
2711
2712 To set a config setting:
2713
2714     <comment>%command.full_name% bin-dir bin/</comment>
2715
2716 To read a config setting:
2717
2718     <comment>%command.full_name% bin-dir</comment>
2719     Outputs: <info>bin</info>
2720
2721 To edit the global config.json file:
2722
2723     <comment>%command.full_name% --global</comment>
2724
2725 To add a repository:
2726
2727     <comment>%command.full_name% repositories.foo vcs https://bar.com</comment>
2728
2729 To remove a repository (repo is a short alias for repositories):
2730
2731     <comment>%command.full_name% --unset repo.foo</comment>
2732
2733 To disable packagist:
2734
2735     <comment>%command.full_name% repo.packagist false</comment>
2736
2737 You can alter repositories in the global config.json file by passing in the
2738 <info>--global</info> option.
2739
2740 To add or edit suggested packages you can use:
2741
2742     <comment>%command.full_name% suggest.package reason for the suggestion</comment>
2743
2744 To add or edit extra properties you can use:
2745
2746     <comment>%command.full_name% extra.property value</comment>
2747
2748 To edit the file in an external editor:
2749
2750     <comment>%command.full_name% --editor</comment>
2751
2752 To choose your editor you can set the "EDITOR" env variable.
2753
2754 To get a list of configuration values in the file:
2755
2756     <comment>%command.full_name% --list</comment>
2757
2758 You can always pass more than one option. As an example, if you want to edit the
2759 global config.json file.
2760
2761     <comment>%command.full_name% --editor --global</comment>
2762
2763 Read more at https://getcomposer.org/doc/03-cli.md#config
2764 EOT
2765 )
2766 ;
2767 }
2768
2769
2770
2771
2772 protected function initialize(InputInterface $input, OutputInterface $output)
2773 {
2774 parent::initialize($input, $output);
2775
2776 if ($input->getOption('global') && null !== $input->getOption('file')) {
2777 throw new \RuntimeException('--file and --global can not be combined');
2778 }
2779
2780 $io = $this->getIO();
2781 $this->config = Factory::createConfig($io);
2782
2783
2784
2785 $configFile = $input->getOption('global')
2786 ? ($this->config->get('home') . '/config.json')
2787 : ($input->getOption('file') ?: Factory::getComposerFile());
2788
2789
2790 if (
2791 ($configFile === 'composer.json' || $configFile === './composer.json')
2792 && !file_exists($configFile)
2793 && realpath(getcwd()) === realpath($this->config->get('home'))
2794 ) {
2795 file_put_contents($configFile, "{\n}\n");
2796 }
2797
2798 $this->configFile = new JsonFile($configFile, null, $io);
2799 $this->configSource = new JsonConfigSource($this->configFile);
2800
2801 $authConfigFile = $input->getOption('global')
2802 ? ($this->config->get('home') . '/auth.json')
2803 : dirname(realpath($configFile)) . '/auth.json';
2804
2805 $this->authConfigFile = new JsonFile($authConfigFile, null, $io);
2806 $this->authConfigSource = new JsonConfigSource($this->authConfigFile, true);
2807
2808
2809 if ($input->getOption('global') && !$this->configFile->exists()) {
2810 touch($this->configFile->getPath());
2811 $this->configFile->write(array('config' => new \ArrayObject));
2812 Silencer::call('chmod', $this->configFile->getPath(), 0600);
2813 }
2814 if ($input->getOption('global') && !$this->authConfigFile->exists()) {
2815 touch($this->authConfigFile->getPath());
2816 $this->authConfigFile->write(array('bitbucket-oauth' => new \ArrayObject, 'github-oauth' => new \ArrayObject, 'gitlab-oauth' => new \ArrayObject, 'gitlab-token' => new \ArrayObject, 'http-basic' => new \ArrayObject, 'bearer' => new \ArrayObject));
2817 Silencer::call('chmod', $this->authConfigFile->getPath(), 0600);
2818 }
2819
2820 if (!$this->configFile->exists()) {
2821 throw new \RuntimeException(sprintf('File "%s" cannot be found in the current directory', $configFile));
2822 }
2823 }
2824
2825
2826
2827
2828 protected function execute(InputInterface $input, OutputInterface $output)
2829 {
2830
2831 if ($input->getOption('editor')) {
2832 $editor = escapeshellcmd(getenv('EDITOR'));
2833 if (!$editor) {
2834 if (Platform::isWindows()) {
2835 $editor = 'notepad';
2836 } else {
2837 foreach (array('editor', 'vim', 'vi', 'nano', 'pico', 'ed') as $candidate) {
2838 if (exec('which '.$candidate)) {
2839 $editor = $candidate;
2840 break;
2841 }
2842 }
2843 }
2844 }
2845
2846 $file = $input->getOption('auth') ? $this->authConfigFile->getPath() : $this->configFile->getPath();
2847 system($editor . ' ' . $file . (Platform::isWindows() ? '' : ' > `tty`'));
2848
2849 return 0;
2850 }
2851
2852 if (!$input->getOption('global')) {
2853 $this->config->merge($this->configFile->read());
2854 $this->config->merge(array('config' => $this->authConfigFile->exists() ? $this->authConfigFile->read() : array()));
2855 }
2856
2857
2858 if ($input->getOption('list')) {
2859 $this->listConfiguration($this->config->all(), $this->config->raw(), $output);
2860
2861 return 0;
2862 }
2863
2864 $settingKey = $input->getArgument('setting-key');
2865 if (!$settingKey) {
2866 return 0;
2867 }
2868
2869
2870 if (array() !== $input->getArgument('setting-value') && $input->getOption('unset')) {
2871 throw new \RuntimeException('You can not combine a setting value with --unset');
2872 }
2873
2874
2875 if (array() === $input->getArgument('setting-value') && !$input->getOption('unset')) {
2876 $properties = array('name', 'type', 'description', 'homepage', 'version', 'minimum-stability', 'prefer-stable', 'keywords', 'license', 'extra');
2877 $rawData = $this->configFile->read();
2878 $data = $this->config->all();
2879 if (preg_match('/^repos?(?:itories)?(?:\.(.+))?/', $settingKey, $matches)) {
2880 if (!isset($matches[1]) || $matches[1] === '') {
2881 $value = isset($data['repositories']) ? $data['repositories'] : array();
2882 } else {
2883 if (!isset($data['repositories'][$matches[1]])) {
2884 throw new \InvalidArgumentException('There is no '.$matches[1].' repository defined');
2885 }
2886
2887 $value = $data['repositories'][$matches[1]];
2888 }
2889 } elseif (strpos($settingKey, '.')) {
2890 $bits = explode('.', $settingKey);
2891 if ($bits[0] === 'extra') {
2892 $data = $rawData;
2893 } else {
2894 $data = $data['config'];
2895 }
2896 $match = false;
2897 foreach ($bits as $bit) {
2898 $key = isset($key) ? $key.'.'.$bit : $bit;
2899 $match = false;
2900 if (isset($data[$key])) {
2901 $match = true;
2902 $data = $data[$key];
2903 unset($key);
2904 }
2905 }
2906
2907 if (!$match) {
2908 throw new \RuntimeException($settingKey.' is not defined.');
2909 }
2910
2911 $value = $data;
2912 } elseif (isset($data['config'][$settingKey])) {
2913 $value = $this->config->get($settingKey, $input->getOption('absolute') ? 0 : Config::RELATIVE_PATHS);
2914 } elseif (in_array($settingKey, $properties, true) && isset($rawData[$settingKey])) {
2915 $value = $rawData[$settingKey];
2916 } else {
2917 throw new \RuntimeException($settingKey.' is not defined');
2918 }
2919
2920 if (is_array($value)) {
2921 $value = json_encode($value);
2922 }
2923
2924 $this->getIO()->write($value, true, IOInterface::QUIET);
2925
2926 return 0;
2927 }
2928
2929 $values = $input->getArgument('setting-value'); 
2930
2931 $booleanValidator = function ($val) {
2932 return in_array($val, array('true', 'false', '1', '0'), true);
2933 };
2934 $booleanNormalizer = function ($val) {
2935 return $val !== 'false' && (bool) $val;
2936 };
2937
2938
2939 $uniqueConfigValues = array(
2940 'process-timeout' => array('is_numeric', 'intval'),
2941 'use-include-path' => array($booleanValidator, $booleanNormalizer),
2942 'use-github-api' => array($booleanValidator, $booleanNormalizer),
2943 'preferred-install' => array(
2944 function ($val) {
2945 return in_array($val, array('auto', 'source', 'dist'), true);
2946 },
2947 function ($val) {
2948 return $val;
2949 },
2950 ),
2951 'store-auths' => array(
2952 function ($val) {
2953 return in_array($val, array('true', 'false', 'prompt'), true);
2954 },
2955 function ($val) {
2956 if ('prompt' === $val) {
2957 return 'prompt';
2958 }
2959
2960 return $val !== 'false' && (bool) $val;
2961 },
2962 ),
2963 'notify-on-install' => array($booleanValidator, $booleanNormalizer),
2964 'vendor-dir' => array('is_string', function ($val) {
2965 return $val;
2966 }),
2967 'bin-dir' => array('is_string', function ($val) {
2968 return $val;
2969 }),
2970 'archive-dir' => array('is_string', function ($val) {
2971 return $val;
2972 }),
2973 'archive-format' => array('is_string', function ($val) {
2974 return $val;
2975 }),
2976 'data-dir' => array('is_string', function ($val) {
2977 return $val;
2978 }),
2979 'cache-dir' => array('is_string', function ($val) {
2980 return $val;
2981 }),
2982 'cache-files-dir' => array('is_string', function ($val) {
2983 return $val;
2984 }),
2985 'cache-repo-dir' => array('is_string', function ($val) {
2986 return $val;
2987 }),
2988 'cache-vcs-dir' => array('is_string', function ($val) {
2989 return $val;
2990 }),
2991 'cache-ttl' => array('is_numeric', 'intval'),
2992 'cache-files-ttl' => array('is_numeric', 'intval'),
2993 'cache-files-maxsize' => array(
2994 function ($val) {
2995 return preg_match('/^\s*([0-9.]+)\s*(?:([kmg])(?:i?b)?)?\s*$/i', $val) > 0;
2996 },
2997 function ($val) {
2998 return $val;
2999 },
3000 ),
3001 'bin-compat' => array(
3002 function ($val) {
3003 return in_array($val, array('auto', 'full'));
3004 },
3005 function ($val) {
3006 return $val;
3007 },
3008 ),
3009 'discard-changes' => array(
3010 function ($val) {
3011 return in_array($val, array('stash', 'true', 'false', '1', '0'), true);
3012 },
3013 function ($val) {
3014 if ('stash' === $val) {
3015 return 'stash';
3016 }
3017
3018 return $val !== 'false' && (bool) $val;
3019 },
3020 ),
3021 'autoloader-suffix' => array('is_string', function ($val) {
3022 return $val === 'null' ? null : $val;
3023 }),
3024 'sort-packages' => array($booleanValidator, $booleanNormalizer),
3025 'optimize-autoloader' => array($booleanValidator, $booleanNormalizer),
3026 'classmap-authoritative' => array($booleanValidator, $booleanNormalizer),
3027 'apcu-autoloader' => array($booleanValidator, $booleanNormalizer),
3028 'prepend-autoloader' => array($booleanValidator, $booleanNormalizer),
3029 'disable-tls' => array($booleanValidator, $booleanNormalizer),
3030 'secure-http' => array($booleanValidator, $booleanNormalizer),
3031 'cafile' => array(
3032 function ($val) {
3033 return file_exists($val) && is_readable($val);
3034 },
3035 function ($val) {
3036 return $val === 'null' ? null : $val;
3037 },
3038 ),
3039 'capath' => array(
3040 function ($val) {
3041 return is_dir($val) && is_readable($val);
3042 },
3043 function ($val) {
3044 return $val === 'null' ? null : $val;
3045 },
3046 ),
3047 'github-expose-hostname' => array($booleanValidator, $booleanNormalizer),
3048 'htaccess-protect' => array($booleanValidator, $booleanNormalizer),
3049 'lock' => array($booleanValidator, $booleanNormalizer),
3050 );
3051 $multiConfigValues = array(
3052 'github-protocols' => array(
3053 function ($vals) {
3054 if (!is_array($vals)) {
3055 return 'array expected';
3056 }
3057
3058 foreach ($vals as $val) {
3059 if (!in_array($val, array('git', 'https', 'ssh'))) {
3060 return 'valid protocols include: git, https, ssh';
3061 }
3062 }
3063
3064 return true;
3065 },
3066 function ($vals) {
3067 return $vals;
3068 },
3069 ),
3070 'github-domains' => array(
3071 function ($vals) {
3072 if (!is_array($vals)) {
3073 return 'array expected';
3074 }
3075
3076 return true;
3077 },
3078 function ($vals) {
3079 return $vals;
3080 },
3081 ),
3082 'gitlab-domains' => array(
3083 function ($vals) {
3084 if (!is_array($vals)) {
3085 return 'array expected';
3086 }
3087
3088 return true;
3089 },
3090 function ($vals) {
3091 return $vals;
3092 },
3093 ),
3094 );
3095
3096 if ($input->getOption('unset') && (isset($uniqueConfigValues[$settingKey]) || isset($multiConfigValues[$settingKey]))) {
3097 if ($settingKey === 'disable-tls' && $this->config->get('disable-tls')) {
3098 $this->getIO()->writeError('<info>You are now running Composer with SSL/TLS protection enabled.</info>');
3099 }
3100
3101 $this->configSource->removeConfigSetting($settingKey);
3102
3103 return 0;
3104 }
3105 if (isset($uniqueConfigValues[$settingKey])) {
3106 $this->handleSingleValue($settingKey, $uniqueConfigValues[$settingKey], $values, 'addConfigSetting');
3107
3108 return 0;
3109 }
3110 if (isset($multiConfigValues[$settingKey])) {
3111 $this->handleMultiValue($settingKey, $multiConfigValues[$settingKey], $values, 'addConfigSetting');
3112
3113 return 0;
3114 }
3115
3116 if (preg_match('/^preferred-install\.(.+)/', $settingKey, $matches)) {
3117 if ($input->getOption('unset')) {
3118 $this->configSource->removeConfigSetting($settingKey);
3119
3120 return 0;
3121 }
3122
3123 list($validator) = $uniqueConfigValues['preferred-install'];
3124 if (!$validator($values[0])) {
3125 throw new \RuntimeException('Invalid value for '.$settingKey.'. Should be one of: auto, source, or dist');
3126 }
3127
3128 $this->configSource->addConfigSetting($settingKey, $values[0]);
3129
3130 return 0;
3131 }
3132
3133
3134 $uniqueProps = array(
3135 'name' => array('is_string', function ($val) {
3136 return $val;
3137 }),
3138 'type' => array('is_string', function ($val) {
3139 return $val;
3140 }),
3141 'description' => array('is_string', function ($val) {
3142 return $val;
3143 }),
3144 'homepage' => array('is_string', function ($val) {
3145 return $val;
3146 }),
3147 'version' => array('is_string', function ($val) {
3148 return $val;
3149 }),
3150 'minimum-stability' => array(
3151 function ($val) {
3152 return isset(BasePackage::$stabilities[VersionParser::normalizeStability($val)]);
3153 },
3154 function ($val) {
3155 return VersionParser::normalizeStability($val);
3156 },
3157 ),
3158 'prefer-stable' => array($booleanValidator, $booleanNormalizer),
3159 );
3160 $multiProps = array(
3161 'keywords' => array(
3162 function ($vals) {
3163 if (!is_array($vals)) {
3164 return 'array expected';
3165 }
3166
3167 return true;
3168 },
3169 function ($vals) {
3170 return $vals;
3171 },
3172 ),
3173 'license' => array(
3174 function ($vals) {
3175 if (!is_array($vals)) {
3176 return 'array expected';
3177 }
3178
3179 return true;
3180 },
3181 function ($vals) {
3182 return $vals;
3183 },
3184 ),
3185 );
3186
3187 if ($input->getOption('global') && (isset($uniqueProps[$settingKey]) || isset($multiProps[$settingKey]) || substr($settingKey, 0, 6) === 'extra.')) {
3188 throw new \InvalidArgumentException('The '.$settingKey.' property can not be set in the global config.json file. Use `composer global config` to apply changes to the global composer.json');
3189 }
3190 if ($input->getOption('unset') && (isset($uniqueProps[$settingKey]) || isset($multiProps[$settingKey]))) {
3191 $this->configSource->removeProperty($settingKey);
3192
3193 return 0;
3194 }
3195 if (isset($uniqueProps[$settingKey])) {
3196 $this->handleSingleValue($settingKey, $uniqueProps[$settingKey], $values, 'addProperty');
3197
3198 return 0;
3199 }
3200 if (isset($multiProps[$settingKey])) {
3201 $this->handleMultiValue($settingKey, $multiProps[$settingKey], $values, 'addProperty');
3202
3203 return 0;
3204 }
3205
3206
3207 if (preg_match('/^repos?(?:itories)?\.(.+)/', $settingKey, $matches)) {
3208 if ($input->getOption('unset')) {
3209 $this->configSource->removeRepository($matches[1]);
3210
3211 return 0;
3212 }
3213
3214 if (2 === count($values)) {
3215 $this->configSource->addRepository($matches[1], array(
3216 'type' => $values[0],
3217 'url' => $values[1],
3218 ));
3219
3220 return 0;
3221 }
3222
3223 if (1 === count($values)) {
3224 $value = strtolower($values[0]);
3225 if (true === $booleanValidator($value)) {
3226 if (false === $booleanNormalizer($value)) {
3227 $this->configSource->addRepository($matches[1], false);
3228
3229 return 0;
3230 }
3231 } else {
3232 $value = JsonFile::parseJson($values[0]);
3233 $this->configSource->addRepository($matches[1], $value);
3234
3235 return 0;
3236 }
3237 }
3238
3239 throw new \RuntimeException('You must pass the type and a url. Example: php composer.phar config repositories.foo vcs https://bar.com');
3240 }
3241
3242
3243 if (preg_match('/^extra\.(.+)/', $settingKey, $matches)) {
3244 if ($input->getOption('unset')) {
3245 $this->configSource->removeProperty($settingKey);
3246
3247 return 0;
3248 }
3249
3250 $this->configSource->addProperty($settingKey, $values[0]);
3251
3252 return 0;
3253 }
3254
3255
3256 if (preg_match('/^suggest\.(.+)/', $settingKey, $matches)) {
3257 if ($input->getOption('unset')) {
3258 $this->configSource->removeProperty($settingKey);
3259
3260 return 0;
3261 }
3262
3263 $this->configSource->addProperty($settingKey, implode(' ', $values));
3264
3265 return 0;
3266 }
3267
3268
3269 if (in_array($settingKey, array('suggest', 'extra'), true) && $input->getOption('unset')) {
3270 $this->configSource->removeProperty($settingKey);
3271
3272 return 0;
3273 }
3274
3275
3276 if (preg_match('/^platform\.(.+)/', $settingKey, $matches)) {
3277 if ($input->getOption('unset')) {
3278 $this->configSource->removeConfigSetting($settingKey);
3279
3280 return 0;
3281 }
3282
3283 $this->configSource->addConfigSetting($settingKey, $values[0]);
3284
3285 return 0;
3286 }
3287
3288
3289 if ($settingKey === 'platform' && $input->getOption('unset')) {
3290 $this->configSource->removeConfigSetting($settingKey);
3291
3292 return 0;
3293 }
3294
3295
3296 if (preg_match('/^(bitbucket-oauth|github-oauth|gitlab-oauth|gitlab-token|http-basic|bearer)\.(.+)/', $settingKey, $matches)) {
3297 if ($input->getOption('unset')) {
3298 $this->authConfigSource->removeConfigSetting($matches[1].'.'.$matches[2]);
3299 $this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]);
3300
3301 return 0;
3302 }
3303
3304 if ($matches[1] === 'bitbucket-oauth') {
3305 if (2 !== count($values)) {
3306 throw new \RuntimeException('Expected two arguments (consumer-key, consumer-secret), got '.count($values));
3307 }
3308 $this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]);
3309 $this->authConfigSource->addConfigSetting($matches[1].'.'.$matches[2], array('consumer-key' => $values[0], 'consumer-secret' => $values[1]));
3310 } elseif (in_array($matches[1], array('github-oauth', 'gitlab-oauth', 'gitlab-token', 'bearer'), true)) {
3311 if (1 !== count($values)) {
3312 throw new \RuntimeException('Too many arguments, expected only one token');
3313 }
3314 $this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]);
3315 $this->authConfigSource->addConfigSetting($matches[1].'.'.$matches[2], $values[0]);
3316 } elseif ($matches[1] === 'http-basic') {
3317 if (2 !== count($values)) {
3318 throw new \RuntimeException('Expected two arguments (username, password), got '.count($values));
3319 }
3320 $this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]);
3321 $this->authConfigSource->addConfigSetting($matches[1].'.'.$matches[2], array('username' => $values[0], 'password' => $values[1]));
3322 }
3323
3324 return 0;
3325 }
3326
3327
3328 if (preg_match('/^scripts\.(.+)/', $settingKey, $matches)) {
3329 if ($input->getOption('unset')) {
3330 $this->configSource->removeProperty($settingKey);
3331
3332 return 0;
3333 }
3334
3335 $this->configSource->addProperty($settingKey, count($values) > 1 ? $values : $values[0]);
3336
3337 return 0;
3338 }
3339
3340 throw new \InvalidArgumentException('Setting '.$settingKey.' does not exist or is not supported by this command');
3341 }
3342
3343 protected function handleSingleValue($key, array $callbacks, array $values, $method)
3344 {
3345 list($validator, $normalizer) = $callbacks;
3346 if (1 !== count($values)) {
3347 throw new \RuntimeException('You can only pass one value. Example: php composer.phar config process-timeout 300');
3348 }
3349
3350 if (true !== $validation = $validator($values[0])) {
3351 throw new \RuntimeException(sprintf(
3352 '"%s" is an invalid value'.($validation ? ' ('.$validation.')' : ''),
3353 $values[0]
3354 ));
3355 }
3356
3357 $normalizedValue = $normalizer($values[0]);
3358
3359 if ($key === 'disable-tls') {
3360 if (!$normalizedValue && $this->config->get('disable-tls')) {
3361 $this->getIO()->writeError('<info>You are now running Composer with SSL/TLS protection enabled.</info>');
3362 } elseif ($normalizedValue && !$this->config->get('disable-tls')) {
3363 $this->getIO()->writeError('<warning>You are now running Composer with SSL/TLS protection disabled.</warning>');
3364 }
3365 }
3366
3367 return call_user_func(array($this->configSource, $method), $key, $normalizedValue);
3368 }
3369
3370 protected function handleMultiValue($key, array $callbacks, array $values, $method)
3371 {
3372 list($validator, $normalizer) = $callbacks;
3373 if (true !== $validation = $validator($values)) {
3374 throw new \RuntimeException(sprintf(
3375 '%s is an invalid value'.($validation ? ' ('.$validation.')' : ''),
3376 json_encode($values)
3377 ));
3378 }
3379
3380 return call_user_func(array($this->configSource, $method), $key, $normalizer($values));
3381 }
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391 protected function listConfiguration(array $contents, array $rawContents, OutputInterface $output, $k = null)
3392 {
3393 $origK = $k;
3394 $io = $this->getIO();
3395 foreach ($contents as $key => $value) {
3396 if ($k === null && !in_array($key, array('config', 'repositories'))) {
3397 continue;
3398 }
3399
3400 $rawVal = isset($rawContents[$key]) ? $rawContents[$key] : null;
3401
3402 if (is_array($value) && (!is_numeric(key($value)) || ($key === 'repositories' && null === $k))) {
3403 $k .= preg_replace('{^config\.}', '', $key . '.');
3404 $this->listConfiguration($value, $rawVal, $output, $k);
3405 $k = $origK;
3406
3407 continue;
3408 }
3409
3410 if (is_array($value)) {
3411 $value = array_map(function ($val) {
3412 return is_array($val) ? json_encode($val) : $val;
3413 }, $value);
3414
3415 $value = '['.implode(', ', $value).']';
3416 }
3417
3418 if (is_bool($value)) {
3419 $value = var_export($value, true);
3420 }
3421
3422 if (is_string($rawVal) && $rawVal != $value) {
3423 $io->write('[<comment>' . $k . $key . '</comment>] <info>' . $rawVal . ' (' . $value . ')</info>', true, IOInterface::QUIET);
3424 } else {
3425 $io->write('[<comment>' . $k . $key . '</comment>] <info>' . $value . '</info>', true, IOInterface::QUIET);
3426 }
3427 }
3428 }
3429 }
3430 <?php
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442 namespace Composer\Command;
3443
3444 use Composer\Config;
3445 use Composer\Factory;
3446 use Composer\Installer;
3447 use Composer\Installer\ProjectInstaller;
3448 use Composer\Installer\InstallationManager;
3449 use Composer\Installer\SuggestedPackagesReporter;
3450 use Composer\IO\IOInterface;
3451 use Composer\Package\BasePackage;
3452 use Composer\DependencyResolver\Pool;
3453 use Composer\DependencyResolver\Operation\InstallOperation;
3454 use Composer\Package\Version\VersionSelector;
3455 use Composer\Package\AliasPackage;
3456 use Composer\Repository\RepositoryFactory;
3457 use Composer\Repository\CompositeRepository;
3458 use Composer\Repository\PlatformRepository;
3459 use Composer\Repository\InstalledFilesystemRepository;
3460 use Composer\Script\ScriptEvents;
3461 use Composer\Util\Silencer;
3462 use Symfony\Component\Console\Input\InputArgument;
3463 use Symfony\Component\Console\Input\InputInterface;
3464 use Symfony\Component\Console\Input\InputOption;
3465 use Symfony\Component\Console\Output\OutputInterface;
3466 use Symfony\Component\Finder\Finder;
3467 use Composer\Json\JsonFile;
3468 use Composer\Config\JsonConfigSource;
3469 use Composer\Util\Filesystem;
3470 use Composer\Package\Version\VersionParser;
3471 use Composer\EventDispatcher\EventDispatcher;
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481 class CreateProjectCommand extends BaseCommand
3482 {
3483
3484
3485
3486 protected $suggestedPackagesReporter;
3487
3488 protected function configure()
3489 {
3490 $this
3491 ->setName('create-project')
3492 ->setDescription('Creates new project from a package into given directory.')
3493 ->setDefinition(array(
3494 new InputArgument('package', InputArgument::OPTIONAL, 'Package name to be installed'),
3495 new InputArgument('directory', InputArgument::OPTIONAL, 'Directory where the files should be created'),
3496 new InputArgument('version', InputArgument::OPTIONAL, 'Version, will default to latest'),
3497 new InputOption('stability', 's', InputOption::VALUE_REQUIRED, 'Minimum-stability allowed (unless a version is specified).'),
3498 new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
3499 new InputOption('prefer-dist', null, InputOption::VALUE_NONE, 'Forces installation from package dist even for dev versions.'),
3500 new InputOption('repository', null, InputOption::VALUE_REQUIRED, 'Pick a different repository (as url or json config) to look for the package.'),
3501 new InputOption('repository-url', null, InputOption::VALUE_REQUIRED, 'DEPRECATED: Use --repository instead.'),
3502 new InputOption('add-repository', null, InputOption::VALUE_NONE, 'Add the repository option to the composer.json.'),
3503 new InputOption('dev', null, InputOption::VALUE_NONE, 'Enables installation of require-dev packages (enabled by default, only present for BC).'),
3504 new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables installation of require-dev packages.'),
3505 new InputOption('no-custom-installers', null, InputOption::VALUE_NONE, 'DEPRECATED: Use no-plugins instead.'),
3506 new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Whether to prevent execution of all defined scripts in the root package.'),
3507 new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
3508 new InputOption('no-secure-http', null, InputOption::VALUE_NONE, 'Disable the secure-http config option temporarily while installing the root package. Use at your own risk. Using this flag is a bad idea.'),
3509 new InputOption('keep-vcs', null, InputOption::VALUE_NONE, 'Whether to prevent deleting the vcs folder.'),
3510 new InputOption('remove-vcs', null, InputOption::VALUE_NONE, 'Whether to force deletion of the vcs folder without prompting.'),
3511 new InputOption('no-install', null, InputOption::VALUE_NONE, 'Whether to skip installation of the package dependencies.'),
3512 new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'),
3513 ))
3514 ->setHelp(
3515 <<<EOT
3516 The <info>create-project</info> command creates a new project from a given
3517 package into a new directory. If executed without params and in a directory
3518 with a composer.json file it installs the packages for the current project.
3519
3520 You can use this command to bootstrap new projects or setup a clean
3521 version-controlled installation for developers of your project.
3522
3523 <info>php composer.phar create-project vendor/project target-directory [version]</info>
3524
3525 You can also specify the version with the package name using = or : as separator.
3526
3527 <info>php composer.phar create-project vendor/project:version target-directory</info>
3528
3529 To install unstable packages, either specify the version you want, or use the
3530 --stability=dev (where dev can be one of RC, beta, alpha or dev).
3531
3532 To setup a developer workable version you should create the project using the source
3533 controlled code by appending the <info>'--prefer-source'</info> flag.
3534
3535 To install a package from another repository than the default one you
3536 can pass the <info>'--repository=https://myrepository.org'</info> flag.
3537
3538 Read more at https://getcomposer.org/doc/03-cli.md#create-project
3539 EOT
3540 )
3541 ;
3542 }
3543
3544 protected function execute(InputInterface $input, OutputInterface $output)
3545 {
3546 $config = Factory::createConfig();
3547 $io = $this->getIO();
3548
3549 list($preferSource, $preferDist) = $this->getPreferredInstallOptions($config, $input, true);
3550
3551 if ($input->getOption('dev')) {
3552 $io->writeError('<warning>You are using the deprecated option "dev". Dev packages are installed by default now.</warning>');
3553 }
3554 if ($input->getOption('no-custom-installers')) {
3555 $io->writeError('<warning>You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.</warning>');
3556 $input->setOption('no-plugins', true);
3557 }
3558
3559 return $this->installProject(
3560 $io,
3561 $config,
3562 $input,
3563 $input->getArgument('package'),
3564 $input->getArgument('directory'),
3565 $input->getArgument('version'),
3566 $input->getOption('stability'),
3567 $preferSource,
3568 $preferDist,
3569 !$input->getOption('no-dev'),
3570 $input->getOption('repository') ?: $input->getOption('repository-url'),
3571 $input->getOption('no-plugins'),
3572 $input->getOption('no-scripts'),
3573 $input->getOption('no-progress'),
3574 $input->getOption('no-install'),
3575 $input->getOption('ignore-platform-reqs'),
3576 !$input->getOption('no-secure-http'),
3577 $input->getOption('add-repository')
3578 );
3579 }
3580
3581 public function installProject(IOInterface $io, Config $config, InputInterface $input, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repository = null, $disablePlugins = false, $noScripts = false, $noProgress = false, $noInstall = false, $ignorePlatformReqs = false, $secureHttp = true, $addRepository = false)
3582 {
3583 $oldCwd = getcwd();
3584
3585
3586 $io->loadConfiguration($config);
3587
3588 $this->suggestedPackagesReporter = new SuggestedPackagesReporter($io);
3589
3590 if ($packageName !== null) {
3591 $installedFromVcs = $this->installRootPackage($io, $config, $packageName, $directory, $packageVersion, $stability, $preferSource, $preferDist, $installDevPackages, $repository, $disablePlugins, $noScripts, $noProgress, $ignorePlatformReqs, $secureHttp);
3592 } else {
3593 $installedFromVcs = false;
3594 }
3595
3596 $composer = Factory::create($io, null, $disablePlugins);
3597
3598
3599 if ($repository !== null && $addRepository) {
3600 if ($composer->getLocker()->isLocked()) {
3601 $io->writeError('<error>Adding a repository when creating a project that provides a composer.lock file is not supported</error>');
3602
3603 return false;
3604 }
3605
3606 $repoConfig = RepositoryFactory::configFromString($io, $composer->getConfig(), $repository, true);
3607 $composerJsonRepositoriesConfig = $composer->getConfig()->getRepositories();
3608 $name = RepositoryFactory::generateRepositoryName(0, $repoConfig, $composerJsonRepositoriesConfig);
3609 $configSource = new JsonConfigSource(new JsonFile('composer.json'));
3610 $configSource->addRepository($name, $repoConfig);
3611
3612 $composer = Factory::create($io, null, $disablePlugins);
3613 }
3614
3615 $composer->getDownloadManager()->setOutputProgress(!$noProgress);
3616
3617 $fs = new Filesystem();
3618
3619 if ($noScripts === false) {
3620
3621 $composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_ROOT_PACKAGE_INSTALL, $installDevPackages);
3622 }
3623
3624
3625 $config = $composer->getConfig();
3626 list($preferSource, $preferDist) = $this->getPreferredInstallOptions($config, $input);
3627
3628
3629 if ($noInstall === false) {
3630 $installer = Installer::create($io, $composer);
3631 $installer->setPreferSource($preferSource)
3632 ->setPreferDist($preferDist)
3633 ->setDevMode($installDevPackages)
3634 ->setRunScripts(!$noScripts)
3635 ->setIgnorePlatformRequirements($ignorePlatformReqs)
3636 ->setSuggestedPackagesReporter($this->suggestedPackagesReporter)
3637 ->setOptimizeAutoloader($config->get('optimize-autoloader'))
3638 ->setClassMapAuthoritative($config->get('classmap-authoritative'))
3639 ->setApcuAutoloader($config->get('apcu-autoloader'));
3640
3641 if ($disablePlugins) {
3642 $installer->disablePlugins();
3643 }
3644
3645 $status = $installer->run();
3646 if (0 !== $status) {
3647 return $status;
3648 }
3649 }
3650
3651 $hasVcs = $installedFromVcs;
3652 if (
3653 !$input->getOption('keep-vcs')
3654 && $installedFromVcs
3655 && (
3656 $input->getOption('remove-vcs')
3657 || !$io->isInteractive()
3658 || $io->askConfirmation('<info>Do you want to remove the existing VCS (.git, .svn..) history?</info> [<comment>Y,n</comment>]? ', true)
3659 )
3660 ) {
3661 $finder = new Finder();
3662 $finder->depth(0)->directories()->in(getcwd())->ignoreVCS(false)->ignoreDotFiles(false);
3663 foreach (array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg', '.fslckout', '_FOSSIL_') as $vcsName) {
3664 $finder->name($vcsName);
3665 }
3666
3667 try {
3668 $dirs = iterator_to_array($finder);
3669 unset($finder);
3670 foreach ($dirs as $dir) {
3671 if (!$fs->removeDirectory($dir)) {
3672 throw new \RuntimeException('Could not remove '.$dir);
3673 }
3674 }
3675 } catch (\Exception $e) {
3676 $io->writeError('<error>An error occurred while removing the VCS metadata: '.$e->getMessage().'</error>');
3677 }
3678
3679 $hasVcs = false;
3680 }
3681
3682
3683 if (!$hasVcs) {
3684 $package = $composer->getPackage();
3685 $configSource = new JsonConfigSource(new JsonFile('composer.json'));
3686 foreach (BasePackage::$supportedLinkTypes as $type => $meta) {
3687 foreach ($package->{'get'.$meta['method']}() as $link) {
3688 if ($link->getPrettyConstraint() === 'self.version') {
3689 $configSource->addLink($type, $link->getTarget(), $package->getPrettyVersion());
3690 }
3691 }
3692 }
3693 }
3694
3695 if ($noScripts === false) {
3696
3697 $composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_CREATE_PROJECT_CMD, $installDevPackages);
3698 }
3699
3700 chdir($oldCwd);
3701 $vendorComposerDir = $config->get('vendor-dir').'/composer';
3702 if (is_dir($vendorComposerDir) && $fs->isDirEmpty($vendorComposerDir)) {
3703 Silencer::call('rmdir', $vendorComposerDir);
3704 $vendorDir = $config->get('vendor-dir');
3705 if (is_dir($vendorDir) && $fs->isDirEmpty($vendorDir)) {
3706 Silencer::call('rmdir', $vendorDir);
3707 }
3708 }
3709
3710 return 0;
3711 }
3712
3713 protected function installRootPackage(IOInterface $io, Config $config, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repository = null, $disablePlugins = false, $noScripts = false, $noProgress = false, $ignorePlatformReqs = false, $secureHttp = true)
3714 {
3715 if (!$secureHttp) {
3716 $config->merge(array('config' => array('secure-http' => false)));
3717 }
3718
3719 $composer = Factory::create($io, $config->all(), $disablePlugins);
3720 $config = $composer->getConfig();
3721 $rm = $composer->getRepositoryManager();
3722
3723 if (null === $repository) {
3724 $sourceRepo = new CompositeRepository(RepositoryFactory::defaultRepos($io, $config, $rm));
3725 } else {
3726 $sourceRepo = RepositoryFactory::fromString($io, $config, $repository, true, $rm);
3727 }
3728
3729 $parser = new VersionParser();
3730 $requirements = $parser->parseNameVersionPairs(array($packageName));
3731 $name = strtolower($requirements[0]['name']);
3732 if (!$packageVersion && isset($requirements[0]['version'])) {
3733 $packageVersion = $requirements[0]['version'];
3734 }
3735
3736
3737 if (null === $directory) {
3738 $parts = explode("/", $name, 2);
3739 $directory = getcwd() . DIRECTORY_SEPARATOR . array_pop($parts);
3740 }
3741
3742 $fs = new Filesystem();
3743 if (!$fs->isAbsolutePath($directory)) {
3744 $directory = getcwd() . DIRECTORY_SEPARATOR . $directory;
3745 }
3746
3747 $io->writeError('<info>Creating a "' . $packageName . '" project at "' . $fs->findShortestPath(getcwd(), $directory, true) . '"</info>');
3748
3749 if (file_exists($directory)) {
3750 if (!is_dir($directory)) {
3751 throw new \InvalidArgumentException('Cannot create project directory at "'.$directory.'", it exists as a file.');
3752 } elseif (!$fs->isDirEmpty($directory)) {
3753 throw new \InvalidArgumentException('Project directory "'.$directory.'" is not empty.');
3754 }
3755 }
3756
3757 if (null === $stability) {
3758 if (preg_match('{^[^,\s]*?@('.implode('|', array_keys(BasePackage::$stabilities)).')$}i', $packageVersion, $match)) {
3759 $stability = $match[1];
3760 } else {
3761 $stability = VersionParser::parseStability($packageVersion);
3762 }
3763 }
3764
3765 $stability = VersionParser::normalizeStability($stability);
3766
3767 if (!isset(BasePackage::$stabilities[$stability])) {
3768 throw new \InvalidArgumentException('Invalid stability provided ('.$stability.'), must be one of: '.implode(', ', array_keys(BasePackage::$stabilities)));
3769 }
3770
3771 $pool = new Pool($stability);
3772 $pool->addRepository($sourceRepo);
3773
3774 $phpVersion = null;
3775 $prettyPhpVersion = null;
3776 if (!$ignorePlatformReqs) {
3777 $platformOverrides = $config->get('platform') ?: array();
3778
3779 $platform = new PlatformRepository(array(), $platformOverrides);
3780 $phpPackage = $platform->findPackage('php', '*');
3781 $phpVersion = $phpPackage->getVersion();
3782 $prettyPhpVersion = $phpPackage->getPrettyVersion();
3783 }
3784
3785
3786 $versionSelector = new VersionSelector($pool);
3787 $package = $versionSelector->findBestCandidate($name, $packageVersion, $phpVersion, $stability);
3788
3789 if (!$package) {
3790 $errorMessage = "Could not find package $name with " . ($packageVersion ? "version $packageVersion" : "stability $stability");
3791 if ($phpVersion && $versionSelector->findBestCandidate($name, $packageVersion, null, $stability)) {
3792 throw new \InvalidArgumentException($errorMessage .' in a version installable using your PHP version '.$prettyPhpVersion.'.');
3793 }
3794
3795 throw new \InvalidArgumentException($errorMessage .'.');
3796 }
3797
3798
3799 if (function_exists('pcntl_async_signals') && function_exists('pcntl_signal')) {
3800 @mkdir($directory, 0777, true);
3801 if ($realDir = realpath($directory)) {
3802 pcntl_async_signals(true);
3803 pcntl_signal(SIGINT, function () use ($realDir) {
3804 $fs = new Filesystem();
3805 $fs->removeDirectory($realDir);
3806 exit(130);
3807 });
3808 }
3809 }
3810
3811 $io->writeError('<info>Installing ' . $package->getName() . ' (' . $package->getFullPrettyVersion(false) . ')</info>');
3812
3813 if ($disablePlugins) {
3814 $io->writeError('<info>Plugins have been disabled.</info>');
3815 }
3816
3817 if ($package instanceof AliasPackage) {
3818 $package = $package->getAliasOf();
3819 }
3820
3821 $dm = $composer->getDownloadManager();
3822 $dm->setPreferSource($preferSource)
3823 ->setPreferDist($preferDist)
3824 ->setOutputProgress(!$noProgress);
3825
3826 $projectInstaller = new ProjectInstaller($directory, $dm);
3827 $im = $composer->getInstallationManager();
3828 $im->addInstaller($projectInstaller);
3829 $im->install(new InstalledFilesystemRepository(new JsonFile('php://memory')), new InstallOperation($package));
3830 $im->notifyInstalls($io);
3831
3832
3833 $this->suggestedPackagesReporter->addSuggestionsFromPackage($package);
3834
3835 $installedFromVcs = 'source' === $package->getInstallationSource();
3836
3837 $io->writeError('<info>Created project in ' . $directory . '</info>');
3838 chdir($directory);
3839
3840 $_SERVER['COMPOSER_ROOT_VERSION'] = $package->getPrettyVersion();
3841 putenv('COMPOSER_ROOT_VERSION='.$_SERVER['COMPOSER_ROOT_VERSION']);
3842
3843 return $installedFromVcs;
3844 }
3845 }
3846 <?php
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858 namespace Composer\Command;
3859
3860 use Symfony\Component\Console\Input\InputInterface;
3861 use Symfony\Component\Console\Output\OutputInterface;
3862
3863
3864
3865
3866 class DependsCommand extends BaseDependencyCommand
3867 {
3868
3869
3870
3871 protected function configure()
3872 {
3873 parent::configure();
3874
3875 $this
3876 ->setName('depends')
3877 ->setAliases(array('why'))
3878 ->setDescription('Shows which packages cause the given package to be installed.')
3879 ->setHelp(
3880 <<<EOT
3881 Displays detailed information about where a package is referenced.
3882
3883 <info>php composer.phar depends composer/composer</info>
3884
3885 Read more at https://getcomposer.org/doc/03-cli.md#depends-why-
3886 EOT
3887 )
3888 ;
3889 }
3890
3891
3892
3893
3894
3895
3896
3897
3898 protected function execute(InputInterface $input, OutputInterface $output)
3899 {
3900 return parent::doExecute($input, $output, false);
3901 }
3902 }
3903 <?php
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915 namespace Composer\Command;
3916
3917 use Composer\Composer;
3918 use Composer\Factory;
3919 use Composer\Config;
3920 use Composer\Downloader\TransportException;
3921 use Composer\Repository\PlatformRepository;
3922 use Composer\Plugin\CommandEvent;
3923 use Composer\Plugin\PluginEvents;
3924 use Composer\Util\ConfigValidator;
3925 use Composer\Util\IniHelper;
3926 use Composer\Util\ProcessExecutor;
3927 use Composer\Util\RemoteFilesystem;
3928 use Composer\Util\StreamContextFactory;
3929 use Composer\SelfUpdate\Keys;
3930 use Composer\SelfUpdate\Versions;
3931 use Composer\IO\NullIO;
3932 use Symfony\Component\Console\Input\InputInterface;
3933 use Symfony\Component\Console\Output\OutputInterface;
3934
3935
3936
3937
3938 class DiagnoseCommand extends BaseCommand
3939 {
3940
3941 protected $rfs;
3942
3943
3944 protected $process;
3945
3946
3947 protected $exitCode = 0;
3948
3949 protected function configure()
3950 {
3951 $this
3952 ->setName('diagnose')
3953 ->setDescription('Diagnoses the system to identify common errors.')
3954 ->setHelp(
3955 <<<EOT
3956 The <info>diagnose</info> command checks common errors to help debugging problems.
3957
3958 The process exit code will be 1 in case of warnings and 2 for errors.
3959
3960 Read more at https://getcomposer.org/doc/03-cli.md#diagnose
3961 EOT
3962 )
3963 ;
3964 }
3965
3966
3967
3968
3969 protected function execute(InputInterface $input, OutputInterface $output)
3970 {
3971 $composer = $this->getComposer(false);
3972 $io = $this->getIO();
3973
3974 if ($composer) {
3975 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'diagnose', $input, $output);
3976 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
3977
3978 $io->write('Checking composer.json: ', false);
3979 $this->outputResult($this->checkComposerSchema());
3980 }
3981
3982 if ($composer) {
3983 $config = $composer->getConfig();
3984 } else {
3985 $config = Factory::createConfig();
3986 }
3987
3988 $config->merge(array('config' => array('secure-http' => false)));
3989 $config->prohibitUrlByConfig('http://repo.packagist.org', new NullIO);
3990
3991 $this->rfs = Factory::createRemoteFilesystem($io, $config);
3992 $this->process = new ProcessExecutor($io);
3993
3994 $io->write('Checking platform settings: ', false);
3995 $this->outputResult($this->checkPlatform());
3996
3997 $io->write('Checking git settings: ', false);
3998 $this->outputResult($this->checkGit());
3999
4000 $io->write('Checking http connectivity to packagist: ', false);
4001 $this->outputResult($this->checkHttp('http', $config));
4002
4003 $io->write('Checking https connectivity to packagist: ', false);
4004 $this->outputResult($this->checkHttp('https', $config));
4005
4006 $opts = stream_context_get_options(StreamContextFactory::getContext('http://example.org'));
4007 if (!empty($opts['http']['proxy'])) {
4008 $io->write('Checking HTTP proxy: ', false);
4009 $this->outputResult($this->checkHttpProxy());
4010 $io->write('Checking HTTP proxy support for request_fulluri: ', false);
4011 $this->outputResult($this->checkHttpProxyFullUriRequestParam());
4012 $io->write('Checking HTTPS proxy support for request_fulluri: ', false);
4013 $this->outputResult($this->checkHttpsProxyFullUriRequestParam());
4014 }
4015
4016 if ($oauth = $config->get('github-oauth')) {
4017 foreach ($oauth as $domain => $token) {
4018 $io->write('Checking '.$domain.' oauth access: ', false);
4019 $this->outputResult($this->checkGithubOauth($domain, $token));
4020 }
4021 } else {
4022 $io->write('Checking github.com rate limit: ', false);
4023 try {
4024 $rate = $this->getGithubRateLimit('github.com');
4025 if (!is_array($rate)) {
4026 $this->outputResult($rate);
4027 } elseif (10 > $rate['remaining']) {
4028 $io->write('<warning>WARNING</warning>');
4029 $io->write(sprintf(
4030 '<comment>Github has a rate limit on their API. '
4031 . 'You currently have <options=bold>%u</options=bold> '
4032 . 'out of <options=bold>%u</options=bold> requests left.' . PHP_EOL
4033 . 'See https://developer.github.com/v3/#rate-limiting and also' . PHP_EOL
4034 . '    https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens</comment>',
4035 $rate['remaining'],
4036 $rate['limit']
4037 ));
4038 } else {
4039 $this->outputResult(true);
4040 }
4041 } catch (\Exception $e) {
4042 if ($e instanceof TransportException && $e->getCode() === 401) {
4043 $this->outputResult('<comment>The oauth token for github.com seems invalid, run "composer config --global --unset github-oauth.github.com" to remove it</comment>');
4044 } else {
4045 $this->outputResult($e);
4046 }
4047 }
4048 }
4049
4050 $io->write('Checking disk free space: ', false);
4051 $this->outputResult($this->checkDiskSpace($config));
4052
4053 if ('phar:' === substr(__FILE__, 0, 5)) {
4054 $io->write('Checking pubkeys: ', false);
4055 $this->outputResult($this->checkPubKeys($config));
4056
4057 $io->write('Checking composer version: ', false);
4058 $this->outputResult($this->checkVersion($config));
4059 }
4060
4061 $io->write(sprintf('Composer version: <comment>%s</comment>', Composer::VERSION));
4062
4063 $platformOverrides = $config->get('platform') ?: array();
4064 $platformRepo = new PlatformRepository(array(), $platformOverrides);
4065 $phpPkg = $platformRepo->findPackage('php', '*');
4066 $phpVersion = $phpPkg->getPrettyVersion();
4067 if (false !== strpos($phpPkg->getDescription(), 'overridden')) {
4068 $phpVersion .= ' - ' . $phpPkg->getDescription();
4069 }
4070
4071 $io->write(sprintf('PHP version: <comment>%s</comment>', $phpVersion));
4072
4073 if (defined('PHP_BINARY')) {
4074 $io->write(sprintf('PHP binary path: <comment>%s</comment>', PHP_BINARY));
4075 }
4076
4077 $io->write('OpenSSL version: ' . (defined('OPENSSL_VERSION_TEXT') ? '<comment>'.OPENSSL_VERSION_TEXT.'</comment>' : '<error>missing</error>'));
4078
4079 return $this->exitCode;
4080 }
4081
4082 private function checkComposerSchema()
4083 {
4084 $validator = new ConfigValidator($this->getIO());
4085 list($errors, , $warnings) = $validator->validate(Factory::getComposerFile());
4086
4087 if ($errors || $warnings) {
4088 $messages = array(
4089 'error' => $errors,
4090 'warning' => $warnings,
4091 );
4092
4093 $output = '';
4094 foreach ($messages as $style => $msgs) {
4095 foreach ($msgs as $msg) {
4096 $output .= '<' . $style . '>' . $msg . '</' . $style . '>' . PHP_EOL;
4097 }
4098 }
4099
4100 return rtrim($output);
4101 }
4102
4103 return true;
4104 }
4105
4106 private function checkGit()
4107 {
4108 $this->process->execute('git config color.ui', $output);
4109 if (strtolower(trim($output)) === 'always') {
4110 return '<comment>Your git color.ui setting is set to always, this is known to create issues. Use "git config --global color.ui true" to set it correctly.</comment>';
4111 }
4112
4113 return true;
4114 }
4115
4116 private function checkHttp($proto, Config $config)
4117 {
4118 $result = $this->checkConnectivity();
4119 if ($result !== true) {
4120 return $result;
4121 }
4122
4123 $disableTls = false;
4124 $result = array();
4125 if ($proto === 'https' && $config->get('disable-tls') === true) {
4126 $disableTls = true;
4127 $result[] = '<warning>Composer is configured to disable SSL/TLS protection. This will leave remote HTTPS requests vulnerable to Man-In-The-Middle attacks.</warning>';
4128 }
4129 if ($proto === 'https' && !extension_loaded('openssl') && !$disableTls) {
4130 $result[] = '<error>Composer is configured to use SSL/TLS protection but the openssl extension is not available.</error>';
4131 }
4132
4133 try {
4134 $this->rfs->getContents('packagist.org', $proto . '://repo.packagist.org/packages.json', false);
4135 } catch (TransportException $e) {
4136 if (false !== strpos($e->getMessage(), 'cafile')) {
4137 $result[] = '<error>[' . get_class($e) . '] ' . $e->getMessage() . '</error>';
4138 $result[] = '<error>Unable to locate a valid CA certificate file. You must set a valid \'cafile\' option.</error>';
4139 $result[] = '<error>You can alternatively disable this error, at your own risk, by enabling the \'disable-tls\' option.</error>';
4140 } else {
4141 array_unshift($result, '[' . get_class($e) . '] ' . $e->getMessage());
4142 }
4143 }
4144
4145 if (count($result) > 0) {
4146 return $result;
4147 }
4148
4149 return true;
4150 }
4151
4152 private function checkHttpProxy()
4153 {
4154 $result = $this->checkConnectivity();
4155 if ($result !== true) {
4156 return $result;
4157 }
4158
4159 $protocol = extension_loaded('openssl') ? 'https' : 'http';
4160 try {
4161 $json = json_decode($this->rfs->getContents('packagist.org', $protocol . '://repo.packagist.org/packages.json', false), true);
4162 $hash = reset($json['provider-includes']);
4163 $hash = $hash['sha256'];
4164 $path = str_replace('%hash%', $hash, key($json['provider-includes']));
4165 $provider = $this->rfs->getContents('packagist.org', $protocol . '://repo.packagist.org/'.$path, false);
4166
4167 if (hash('sha256', $provider) !== $hash) {
4168 return 'It seems that your proxy is modifying http traffic on the fly';
4169 }
4170 } catch (\Exception $e) {
4171 return $e;
4172 }
4173
4174 return true;
4175 }
4176
4177
4178
4179
4180
4181
4182
4183
4184 private function checkHttpProxyFullUriRequestParam()
4185 {
4186 $result = $this->checkConnectivity();
4187 if ($result !== true) {
4188 return $result;
4189 }
4190
4191 $url = 'http://repo.packagist.org/packages.json';
4192 try {
4193 $this->rfs->getContents('packagist.org', $url, false);
4194 } catch (TransportException $e) {
4195 try {
4196 $this->rfs->getContents('packagist.org', $url, false, array('http' => array('request_fulluri' => false)));
4197 } catch (TransportException $e) {
4198 return 'Unable to assess the situation, maybe packagist.org is down ('.$e->getMessage().')';
4199 }
4200
4201 return 'It seems there is a problem with your proxy server, try setting the "HTTP_PROXY_REQUEST_FULLURI" and "HTTPS_PROXY_REQUEST_FULLURI" environment variables to "false"';
4202 }
4203
4204 return true;
4205 }
4206
4207
4208
4209
4210
4211
4212
4213
4214 private function checkHttpsProxyFullUriRequestParam()
4215 {
4216 $result = $this->checkConnectivity();
4217 if ($result !== true) {
4218 return $result;
4219 }
4220
4221 if (!extension_loaded('openssl')) {
4222 return 'You need the openssl extension installed for this check';
4223 }
4224
4225 $url = 'https://api.github.com/repos/Seldaek/jsonlint/zipball/1.0.0';
4226 try {
4227 $this->rfs->getContents('github.com', $url, false);
4228 } catch (TransportException $e) {
4229 try {
4230 $this->rfs->getContents('github.com', $url, false, array('http' => array('request_fulluri' => false)));
4231 } catch (TransportException $e) {
4232 return 'Unable to assess the situation, maybe github is down ('.$e->getMessage().')';
4233 }
4234
4235 return 'It seems there is a problem with your proxy server, try setting the "HTTPS_PROXY_REQUEST_FULLURI" environment variable to "false"';
4236 }
4237
4238 return true;
4239 }
4240
4241 private function checkGithubOauth($domain, $token)
4242 {
4243 $result = $this->checkConnectivity();
4244 if ($result !== true) {
4245 return $result;
4246 }
4247
4248 $this->getIO()->setAuthentication($domain, $token, 'x-oauth-basic');
4249 try {
4250 $url = $domain === 'github.com' ? 'https://api.'.$domain.'/' : 'https://'.$domain.'/api/v3/';
4251
4252 return $this->rfs->getContents($domain, $url, false, array(
4253 'retry-auth-failure' => false,
4254 )) ? true : 'Unexpected error';
4255 } catch (\Exception $e) {
4256 if ($e instanceof TransportException && $e->getCode() === 401) {
4257 return '<comment>The oauth token for '.$domain.' seems invalid, run "composer config --global --unset github-oauth.'.$domain.'" to remove it</comment>';
4258 }
4259
4260 return $e;
4261 }
4262 }
4263
4264
4265
4266
4267
4268
4269
4270 private function getGithubRateLimit($domain, $token = null)
4271 {
4272 $result = $this->checkConnectivity();
4273 if ($result !== true) {
4274 return $result;
4275 }
4276
4277 if ($token) {
4278 $this->getIO()->setAuthentication($domain, $token, 'x-oauth-basic');
4279 }
4280
4281 $url = $domain === 'github.com' ? 'https://api.'.$domain.'/rate_limit' : 'https://'.$domain.'/api/rate_limit';
4282 $json = $this->rfs->getContents($domain, $url, false, array('retry-auth-failure' => false));
4283 $data = json_decode($json, true);
4284
4285 return $data['resources']['core'];
4286 }
4287
4288 private function checkDiskSpace($config)
4289 {
4290 $minSpaceFree = 1024 * 1024;
4291 if ((($df = @disk_free_space($dir = $config->get('home'))) !== false && $df < $minSpaceFree)
4292 || (($df = @disk_free_space($dir = $config->get('vendor-dir'))) !== false && $df < $minSpaceFree)
4293 ) {
4294 return '<error>The disk hosting '.$dir.' is full</error>';
4295 }
4296
4297 return true;
4298 }
4299
4300 private function checkPubKeys($config)
4301 {
4302 $home = $config->get('home');
4303 $errors = array();
4304 $io = $this->getIO();
4305
4306 if (file_exists($home.'/keys.tags.pub') && file_exists($home.'/keys.dev.pub')) {
4307 $io->write('');
4308 }
4309
4310 if (file_exists($home.'/keys.tags.pub')) {
4311 $io->write('Tags Public Key Fingerprint: ' . Keys::fingerprint($home.'/keys.tags.pub'));
4312 } else {
4313 $errors[] = '<error>Missing pubkey for tags verification</error>';
4314 }
4315
4316 if (file_exists($home.'/keys.dev.pub')) {
4317 $io->write('Dev Public Key Fingerprint: ' . Keys::fingerprint($home.'/keys.dev.pub'));
4318 } else {
4319 $errors[] = '<error>Missing pubkey for dev verification</error>';
4320 }
4321
4322 if ($errors) {
4323 $errors[] = '<error>Run composer self-update --update-keys to set them up</error>';
4324 }
4325
4326 return $errors ?: true;
4327 }
4328
4329 private function checkVersion($config)
4330 {
4331 $result = $this->checkConnectivity();
4332 if ($result !== true) {
4333 return $result;
4334 }
4335
4336 $versionsUtil = new Versions($config, $this->rfs);
4337 try {
4338 $latest = $versionsUtil->getLatest();
4339 } catch (\Exception $e) {
4340 return $e;
4341 }
4342
4343 if (Composer::VERSION !== $latest['version'] && Composer::VERSION !== '@package_version@') {
4344 return '<comment>You are not running the latest '.$versionsUtil->getChannel().' version, run `composer self-update` to update ('.Composer::VERSION.' => '.$latest['version'].')</comment>';
4345 }
4346
4347 return true;
4348 }
4349
4350
4351
4352
4353 private function outputResult($result)
4354 {
4355 $io = $this->getIO();
4356 if (true === $result) {
4357 $io->write('<info>OK</info>');
4358
4359 return;
4360 }
4361
4362 $hadError = false;
4363 $hadWarning = false;
4364 if ($result instanceof \Exception) {
4365 $result = '<error>['.get_class($result).'] '.$result->getMessage().'</error>';
4366 }
4367
4368 if (!$result) {
4369
4370 $hadError = true;
4371 } else {
4372 if (!is_array($result)) {
4373 $result = array($result);
4374 }
4375 foreach ($result as $message) {
4376 if (false !== strpos($message, '<error>')) {
4377 $hadError = true;
4378 } elseif (false !== strpos($message, '<warning>')) {
4379 $hadWarning = true;
4380 }
4381 }
4382 }
4383
4384 if ($hadError) {
4385 $io->write('<error>FAIL</error>');
4386 $this->exitCode = max($this->exitCode, 2);
4387 } elseif ($hadWarning) {
4388 $io->write('<warning>WARNING</warning>');
4389 $this->exitCode = max($this->exitCode, 1);
4390 }
4391
4392 if ($result) {
4393 foreach ($result as $message) {
4394 $io->write($message);
4395 }
4396 }
4397 }
4398
4399 private function checkPlatform()
4400 {
4401 $output = '';
4402 $out = function ($msg, $style) use (&$output) {
4403 $output .= '<'.$style.'>'.$msg.'</'.$style.'>'.PHP_EOL;
4404 };
4405
4406
4407 $errors = array();
4408 $warnings = array();
4409 $displayIniMessage = false;
4410
4411 $iniMessage = PHP_EOL.PHP_EOL.IniHelper::getMessage();
4412 $iniMessage .= PHP_EOL.'If you can not modify the ini file, you can also run `php -d option=value` to modify ini values on the fly. You can use -d multiple times.';
4413
4414 if (!function_exists('json_decode')) {
4415 $errors['json'] = true;
4416 }
4417
4418 if (!extension_loaded('Phar')) {
4419 $errors['phar'] = true;
4420 }
4421
4422 if (!extension_loaded('filter')) {
4423 $errors['filter'] = true;
4424 }
4425
4426 if (!extension_loaded('hash')) {
4427 $errors['hash'] = true;
4428 }
4429
4430 if (!extension_loaded('iconv') && !extension_loaded('mbstring')) {
4431 $errors['iconv_mbstring'] = true;
4432 }
4433
4434 if (!filter_var(ini_get('allow_url_fopen'), FILTER_VALIDATE_BOOLEAN)) {
4435 $errors['allow_url_fopen'] = true;
4436 }
4437
4438 if (extension_loaded('ionCube Loader') && ioncube_loader_iversion() < 40009) {
4439 $errors['ioncube'] = ioncube_loader_version();
4440 }
4441
4442 if (PHP_VERSION_ID < 50302) {
4443 $errors['php'] = PHP_VERSION;
4444 }
4445
4446 if (!isset($errors['php']) && PHP_VERSION_ID < 50304) {
4447 $warnings['php'] = PHP_VERSION;
4448 }
4449
4450 if (!extension_loaded('openssl')) {
4451 $errors['openssl'] = true;
4452 }
4453
4454 if (extension_loaded('openssl') && OPENSSL_VERSION_NUMBER < 0x1000100f) {
4455 $warnings['openssl_version'] = true;
4456 }
4457
4458 if (!defined('HHVM_VERSION') && !extension_loaded('apcu') && filter_var(ini_get('apc.enable_cli'), FILTER_VALIDATE_BOOLEAN)) {
4459 $warnings['apc_cli'] = true;
4460 }
4461
4462 if (!extension_loaded('zlib')) {
4463 $warnings['zlib'] = true;
4464 }
4465
4466 ob_start();
4467 phpinfo(INFO_GENERAL);
4468 $phpinfo = ob_get_clean();
4469 if (preg_match('{Configure Command(?: *</td><td class="v">| *=> *)(.*?)(?:</td>|$)}m', $phpinfo, $match)) {
4470 $configure = $match[1];
4471
4472 if (false !== strpos($configure, '--enable-sigchild')) {
4473 $warnings['sigchild'] = true;
4474 }
4475
4476 if (false !== strpos($configure, '--with-curlwrappers')) {
4477 $warnings['curlwrappers'] = true;
4478 }
4479 }
4480
4481 if (filter_var(ini_get('xdebug.profiler_enabled'), FILTER_VALIDATE_BOOLEAN)) {
4482 $warnings['xdebug_profile'] = true;
4483 } elseif (extension_loaded('xdebug')) {
4484 $warnings['xdebug_loaded'] = true;
4485 }
4486
4487 if (defined('PHP_WINDOWS_VERSION_BUILD')
4488 && (version_compare(PHP_VERSION, '7.2.23', '<')
4489 || (version_compare(PHP_VERSION, '7.3.0', '>=')
4490 && version_compare(PHP_VERSION, '7.3.10', '<')))) {
4491 $warnings['onedrive'] = PHP_VERSION;
4492 }
4493
4494 if (!empty($errors)) {
4495 foreach ($errors as $error => $current) {
4496 switch ($error) {
4497 case 'json':
4498 $text = PHP_EOL."The json extension is missing.".PHP_EOL;
4499 $text .= "Install it or recompile php without --disable-json";
4500 break;
4501
4502 case 'phar':
4503 $text = PHP_EOL."The phar extension is missing.".PHP_EOL;
4504 $text .= "Install it or recompile php without --disable-phar";
4505 break;
4506
4507 case 'filter':
4508 $text = PHP_EOL."The filter extension is missing.".PHP_EOL;
4509 $text .= "Install it or recompile php without --disable-filter";
4510 break;
4511
4512 case 'hash':
4513 $text = PHP_EOL."The hash extension is missing.".PHP_EOL;
4514 $text .= "Install it or recompile php without --disable-hash";
4515 break;
4516
4517 case 'iconv_mbstring':
4518 $text = PHP_EOL."The iconv OR mbstring extension is required and both are missing.".PHP_EOL;
4519 $text .= "Install either of them or recompile php without --disable-iconv";
4520 break;
4521
4522 case 'unicode':
4523 $text = PHP_EOL."The detect_unicode setting must be disabled.".PHP_EOL;
4524 $text .= "Add the following to the end of your `php.ini`:".PHP_EOL;
4525 $text .= "    detect_unicode = Off";
4526 $displayIniMessage = true;
4527 break;
4528
4529 case 'suhosin':
4530 $text = PHP_EOL."The suhosin.executor.include.whitelist setting is incorrect.".PHP_EOL;
4531 $text .= "Add the following to the end of your `php.ini` or suhosin.ini (Example path [for Debian]: /etc/php5/cli/conf.d/suhosin.ini):".PHP_EOL;
4532 $text .= "    suhosin.executor.include.whitelist = phar ".$current;
4533 $displayIniMessage = true;
4534 break;
4535
4536 case 'php':
4537 $text = PHP_EOL."Your PHP ({$current}) is too old, you must upgrade to PHP 5.3.2 or higher.";
4538 break;
4539
4540 case 'allow_url_fopen':
4541 $text = PHP_EOL."The allow_url_fopen setting is incorrect.".PHP_EOL;
4542 $text .= "Add the following to the end of your `php.ini`:".PHP_EOL;
4543 $text .= "    allow_url_fopen = On";
4544 $displayIniMessage = true;
4545 break;
4546
4547 case 'ioncube':
4548 $text = PHP_EOL."Your ionCube Loader extension ($current) is incompatible with Phar files.".PHP_EOL;
4549 $text .= "Upgrade to ionCube 4.0.9 or higher or remove this line (path may be different) from your `php.ini` to disable it:".PHP_EOL;
4550 $text .= "    zend_extension = /usr/lib/php5/20090626+lfs/ioncube_loader_lin_5.3.so";
4551 $displayIniMessage = true;
4552 break;
4553
4554 case 'openssl':
4555 $text = PHP_EOL."The openssl extension is missing, which means that secure HTTPS transfers are impossible.".PHP_EOL;
4556 $text .= "If possible you should enable it or recompile php with --with-openssl";
4557 break;
4558 }
4559 $out($text, 'error');
4560 }
4561
4562 $output .= PHP_EOL;
4563 }
4564
4565 if (!empty($warnings)) {
4566 foreach ($warnings as $warning => $current) {
4567 switch ($warning) {
4568 case 'apc_cli':
4569 $text = "The apc.enable_cli setting is incorrect.".PHP_EOL;
4570 $text .= "Add the following to the end of your `php.ini`:".PHP_EOL;
4571 $text .= "  apc.enable_cli = Off";
4572 $displayIniMessage = true;
4573 break;
4574
4575 case 'zlib':
4576 $text = 'The zlib extension is not loaded, this can slow down Composer a lot.'.PHP_EOL;
4577 $text .= 'If possible, enable it or recompile php with --with-zlib'.PHP_EOL;
4578 $displayIniMessage = true;
4579 break;
4580
4581 case 'sigchild':
4582 $text = "PHP was compiled with --enable-sigchild which can cause issues on some platforms.".PHP_EOL;
4583 $text .= "Recompile it without this flag if possible, see also:".PHP_EOL;
4584 $text .= "  https://bugs.php.net/bug.php?id=22999";
4585 break;
4586
4587 case 'curlwrappers':
4588 $text = "PHP was compiled with --with-curlwrappers which will cause issues with HTTP authentication and GitHub.".PHP_EOL;
4589 $text .= " Recompile it without this flag if possible";
4590 break;
4591
4592 case 'php':
4593 $text = "Your PHP ({$current}) is quite old, upgrading to PHP 5.3.4 or higher is recommended.".PHP_EOL;
4594 $text .= " Composer works with 5.3.2+ for most people, but there might be edge case issues.";
4595 break;
4596
4597 case 'openssl_version':
4598
4599 $opensslVersion = strstr(trim(strstr(OPENSSL_VERSION_TEXT, ' ')), ' ', true);
4600 $opensslVersion = $opensslVersion ?: OPENSSL_VERSION_TEXT;
4601
4602 $text = "The OpenSSL library ({$opensslVersion}) used by PHP does not support TLSv1.2 or TLSv1.1.".PHP_EOL;
4603 $text .= "If possible you should upgrade OpenSSL to version 1.0.1 or above.";
4604 break;
4605
4606 case 'xdebug_loaded':
4607 $text = "The xdebug extension is loaded, this can slow down Composer a little.".PHP_EOL;
4608 $text .= " Disabling it when using Composer is recommended.";
4609 break;
4610
4611 case 'xdebug_profile':
4612 $text = "The xdebug.profiler_enabled setting is enabled, this can slow down Composer a lot.".PHP_EOL;
4613 $text .= "Add the following to the end of your `php.ini` to disable it:".PHP_EOL;
4614 $text .= "  xdebug.profiler_enabled = 0";
4615 $displayIniMessage = true;
4616 break;
4617
4618 case 'onedrive':
4619 $text = "The Windows OneDrive folder is not supported on PHP versions below 7.2.23 and 7.3.10.".PHP_EOL;
4620 $text .= "Upgrade your PHP ({$current}) to use this location with Composer.".PHP_EOL;
4621 break;
4622 }
4623 $out($text, 'comment');
4624 }
4625 }
4626
4627 if ($displayIniMessage) {
4628 $out($iniMessage, 'comment');
4629 }
4630
4631 return !$warnings && !$errors ? true : $output;
4632 }
4633
4634
4635
4636
4637
4638
4639
4640 private function checkConnectivity()
4641 {
4642 if (!ini_get('allow_url_fopen')) {
4643 $result = '<info>Skipped because allow_url_fopen is missing.</info>';
4644 return $result;
4645 }
4646
4647 return true;
4648 }
4649 }
4650 <?php
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662 namespace Composer\Command;
4663
4664 use Composer\Plugin\CommandEvent;
4665 use Composer\Plugin\PluginEvents;
4666 use Symfony\Component\Console\Input\InputInterface;
4667 use Symfony\Component\Console\Input\InputOption;
4668 use Symfony\Component\Console\Output\OutputInterface;
4669
4670
4671
4672
4673 class DumpAutoloadCommand extends BaseCommand
4674 {
4675 protected function configure()
4676 {
4677 $this
4678 ->setName('dump-autoload')
4679 ->setAliases(array('dumpautoload'))
4680 ->setDescription('Dumps the autoloader.')
4681 ->setDefinition(array(
4682 new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.'),
4683 new InputOption('optimize', 'o', InputOption::VALUE_NONE, 'Optimizes PSR0 and PSR4 packages to be loaded with classmaps too, good for production.'),
4684 new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize`.'),
4685 new InputOption('apcu', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'),
4686 new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables autoload-dev rules.'),
4687 ))
4688 ->setHelp(
4689 <<<EOT
4690 <info>php composer.phar dump-autoload</info>
4691
4692 Read more at https://getcomposer.org/doc/03-cli.md#dump-autoload-dumpautoload-
4693 EOT
4694 )
4695 ;
4696 }
4697
4698 protected function execute(InputInterface $input, OutputInterface $output)
4699 {
4700 $composer = $this->getComposer();
4701
4702 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'dump-autoload', $input, $output);
4703 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
4704
4705 $installationManager = $composer->getInstallationManager();
4706 $localRepo = $composer->getRepositoryManager()->getLocalRepository();
4707 $package = $composer->getPackage();
4708 $config = $composer->getConfig();
4709
4710 $optimize = $input->getOption('optimize') || $config->get('optimize-autoloader');
4711 $authoritative = $input->getOption('classmap-authoritative') || $config->get('classmap-authoritative');
4712 $apcu = $input->getOption('apcu') || $config->get('apcu-autoloader');
4713
4714 if ($authoritative) {
4715 $this->getIO()->write('<info>Generating optimized autoload files (authoritative)</info>');
4716 } elseif ($optimize) {
4717 $this->getIO()->write('<info>Generating optimized autoload files</info>');
4718 } else {
4719 $this->getIO()->write('<info>Generating autoload files</info>');
4720 }
4721
4722 $generator = $composer->getAutoloadGenerator();
4723 $generator->setDevMode(!$input->getOption('no-dev'));
4724 $generator->setClassMapAuthoritative($authoritative);
4725 $generator->setApcu($apcu);
4726 $generator->setRunScripts(!$input->getOption('no-scripts'));
4727 $numberOfClasses = $generator->dump($config, $localRepo, $package, $installationManager, 'composer', $optimize);
4728
4729 if ($authoritative) {
4730 $this->getIO()->write('<info>Generated optimized autoload files (authoritative) containing '. $numberOfClasses .' classes</info>');
4731 } elseif ($optimize) {
4732 $this->getIO()->write('<info>Generated optimized autoload files containing '. $numberOfClasses .' classes</info>');
4733 } else {
4734 $this->getIO()->write('<info>Generated autoload files</info>');
4735 }
4736
4737 return 0;
4738 }
4739 }
4740 <?php
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752 namespace Composer\Command;
4753
4754 use Symfony\Component\Console\Input\InputInterface;
4755 use Symfony\Component\Console\Input\InputOption;
4756 use Symfony\Component\Console\Output\OutputInterface;
4757 use Symfony\Component\Console\Input\InputArgument;
4758
4759
4760
4761
4762 class ExecCommand extends BaseCommand
4763 {
4764 protected function configure()
4765 {
4766 $this
4767 ->setName('exec')
4768 ->setDescription('Executes a vendored binary/script.')
4769 ->setDefinition(array(
4770 new InputOption('list', 'l', InputOption::VALUE_NONE),
4771 new InputArgument('binary', InputArgument::OPTIONAL, 'The binary to run, e.g. phpunit'),
4772 new InputArgument(
4773 'args',
4774 InputArgument::IS_ARRAY | InputArgument::OPTIONAL,
4775 'Arguments to pass to the binary. Use <info>--</info> to separate from composer arguments'
4776 ),
4777 ))
4778 ->setHelp(
4779 <<<EOT
4780 Executes a vendored binary/script.
4781
4782 Read more at https://getcomposer.org/doc/03-cli.md#exec
4783 EOT
4784 )
4785 ;
4786 }
4787
4788 protected function execute(InputInterface $input, OutputInterface $output)
4789 {
4790 $composer = $this->getComposer();
4791 $binDir = $composer->getConfig()->get('bin-dir');
4792 if ($input->getOption('list') || !$input->getArgument('binary')) {
4793 $bins = glob($binDir . '/*');
4794 $bins = array_merge($bins, array_map(function ($e) {
4795 return "$e (local)";
4796 }, $composer->getPackage()->getBinaries()));
4797
4798 if (!$bins) {
4799 throw new \RuntimeException("No binaries found in composer.json or in bin-dir ($binDir)");
4800 }
4801
4802 $this->getIO()->write(
4803 <<<EOT
4804 <comment>Available binaries:</comment>
4805 EOT
4806 );
4807
4808 foreach ($bins as $bin) {
4809
4810 if (isset($previousBin) && $bin === $previousBin.'.bat') {
4811 continue;
4812 }
4813
4814 $previousBin = $bin;
4815 $bin = basename($bin);
4816 $this->getIO()->write(
4817 <<<EOT
4818 <info>- $bin</info>
4819 EOT
4820 );
4821 }
4822
4823 return 0;
4824 }
4825
4826 $binary = $input->getArgument('binary');
4827
4828 $dispatcher = $composer->getEventDispatcher();
4829 $dispatcher->addListener('__exec_command', $binary);
4830 if ($output->getVerbosity() === OutputInterface::VERBOSITY_NORMAL) {
4831 $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
4832 }
4833
4834
4835
4836
4837 if (getcwd() !== $this->getApplication()->getInitialWorkingDirectory()) {
4838 try {
4839 chdir($this->getApplication()->getInitialWorkingDirectory());
4840 } catch (\Exception $e) {
4841 throw new \RuntimeException('Could not switch back to working directory "'.$this->getApplication()->getInitialWorkingDirectory().'"', 0, $e);
4842 }
4843 }
4844
4845 return $dispatcher->dispatchScript('__exec_command', true, $input->getArgument('args'));
4846 }
4847 }
4848 <?php
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860 namespace Composer\Command;
4861
4862 use Composer\Package\CompletePackageInterface;
4863 use Composer\Package\AliasPackage;
4864 use Composer\Repository\CompositeRepository;
4865 use Symfony\Component\Console\Input\InputInterface;
4866 use Symfony\Component\Console\Input\InputOption;
4867 use Symfony\Component\Console\Output\OutputInterface;
4868
4869
4870
4871
4872
4873 class FundCommand extends BaseCommand
4874 {
4875 protected function configure()
4876 {
4877 $this->setName('fund')
4878 ->setDescription('Discover how to help fund the maintenance of your dependencies.')
4879 ;
4880 }
4881
4882 protected function execute(InputInterface $input, OutputInterface $output)
4883 {
4884 $composer = $this->getComposer();
4885
4886 $repo = $composer->getRepositoryManager()->getLocalRepository();
4887 $remoteRepos = new CompositeRepository($composer->getRepositoryManager()->getRepositories());
4888 $fundings = array();
4889 foreach ($repo->getPackages() as $package) {
4890 if ($package instanceof AliasPackage) {
4891 continue;
4892 }
4893 $latest = $remoteRepos->findPackage($package->getName(), 'dev-master');
4894 if ($latest instanceof CompletePackageInterface && $latest->getFunding()) {
4895 $fundings = $this->insertFundingData($fundings, $latest);
4896 continue;
4897 }
4898 if ($package instanceof CompletePackageInterface && $package->getFunding()) {
4899 $fundings = $this->insertFundingData($fundings, $package);
4900 }
4901 }
4902
4903 ksort($fundings);
4904
4905 $io = $this->getIO();
4906
4907 if ($fundings) {
4908 $prev = null;
4909
4910 $io->write('The following packages were found in your dependencies which publish funding information:');
4911
4912 foreach ($fundings as $vendor => $links) {
4913 $io->write('');
4914 $io->write(sprintf("<comment>%s</comment>", $vendor));
4915 foreach ($links as $url => $packages) {
4916 $line = sprintf('  <info>%s</info>', implode(', ', $packages));
4917
4918 if ($prev !== $line) {
4919 $io->write($line);
4920 $prev = $line;
4921 }
4922
4923 $io->write(sprintf('    %s', $url));
4924 }
4925 }
4926
4927 $io->write("");
4928 $io->write("Please consider following these links and sponsoring the work of package authors!");
4929 $io->write("Thank you!");
4930 } else {
4931 $io->write("No funding links were found in your package dependencies. This doesn't mean they don't need your support!");
4932 }
4933
4934 return 0;
4935 }
4936
4937 private function insertFundingData(array $fundings, CompletePackageInterface $package)
4938 {
4939 foreach ($package->getFunding() as $fundingOption) {
4940 list($vendor, $packageName) = explode('/', $package->getPrettyName());
4941
4942 if (empty($fundingOption['url'])) {
4943 continue;
4944 }
4945 $url = $fundingOption['url'];
4946 if (!empty($fundingOption['type']) && $fundingOption['type'] === 'github' && preg_match('{^https://github.com/([^/]+)$}', $url, $match)) {
4947 $url = 'https://github.com/sponsors/'.$match[1];
4948 }
4949 $fundings[$vendor][$url][] = $packageName;
4950 }
4951
4952 return $fundings;
4953 }
4954 }
4955 <?php
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967 namespace Composer\Command;
4968
4969 use Composer\Factory;
4970 use Composer\Util\Filesystem;
4971 use Symfony\Component\Console\Input\InputInterface;
4972 use Symfony\Component\Console\Input\InputArgument;
4973 use Symfony\Component\Console\Input\StringInput;
4974 use Symfony\Component\Console\Output\OutputInterface;
4975
4976
4977
4978
4979 class GlobalCommand extends BaseCommand
4980 {
4981 protected function configure()
4982 {
4983 $this
4984 ->setName('global')
4985 ->setDescription('Allows running commands in the global composer dir ($COMPOSER_HOME).')
4986 ->setDefinition(array(
4987 new InputArgument('command-name', InputArgument::REQUIRED, ''),
4988 new InputArgument('args', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, ''),
4989 ))
4990 ->setHelp(
4991 <<<EOT
4992 Use this command as a wrapper to run other Composer commands
4993 within the global context of COMPOSER_HOME.
4994
4995 You can use this to install CLI utilities globally, all you need
4996 is to add the COMPOSER_HOME/vendor/bin dir to your PATH env var.
4997
4998 COMPOSER_HOME is c:\Users\<user>\AppData\Roaming\Composer on Windows
4999 and /home/<user>/.composer on unix systems.
5000
5001 If your system uses freedesktop.org standards, then it will first check
5002 XDG_CONFIG_HOME or default to /home/<user>/.config/composer
5003
5004 Note: This path may vary depending on customizations to bin-dir in
5005 composer.json or the environmental variable COMPOSER_BIN_DIR.
5006
5007 Read more at https://getcomposer.org/doc/03-cli.md#global
5008 EOT
5009 )
5010 ;
5011 }
5012
5013 public function run(InputInterface $input, OutputInterface $output)
5014 {
5015
5016 $tokens = preg_split('{\s+}', $input->__toString());
5017 $args = array();
5018 foreach ($tokens as $token) {
5019 if ($token && $token[0] !== '-') {
5020 $args[] = $token;
5021 if (count($args) >= 2) {
5022 break;
5023 }
5024 }
5025 }
5026
5027
5028 if (count($args) < 2) {
5029 return parent::run($input, $output);
5030 }
5031
5032
5033 if (getenv('COMPOSER')) {
5034 putenv('COMPOSER');
5035 unset($_SERVER['COMPOSER']);
5036 }
5037
5038
5039 $config = Factory::createConfig();
5040 $home = $config->get('home');
5041
5042 if (!is_dir($home)) {
5043 $fs = new Filesystem();
5044 $fs->ensureDirectoryExists($home);
5045 if (!is_dir($home)) {
5046 throw new \RuntimeException('Could not create home directory');
5047 }
5048 }
5049
5050 try {
5051 chdir($home);
5052 } catch (\Exception $e) {
5053 throw new \RuntimeException('Could not switch to home directory "'.$home.'"', 0, $e);
5054 }
5055 $this->getIO()->writeError('<info>Changed current directory to '.$home.'</info>');
5056
5057
5058 $input = new StringInput(preg_replace('{\bg(?:l(?:o(?:b(?:a(?:l)?)?)?)?)?\b}', '', $input->__toString(), 1));
5059 $this->getApplication()->resetComposer();
5060
5061 return $this->getApplication()->run($input, $output);
5062 }
5063
5064
5065
5066
5067 public function isProxyCommand()
5068 {
5069 return true;
5070 }
5071 }
5072 <?php
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084 namespace Composer\Command;
5085
5086 use Composer\Package\CompletePackageInterface;
5087 use Composer\Repository\RepositoryInterface;
5088 use Composer\Repository\ArrayRepository;
5089 use Composer\Repository\RepositoryFactory;
5090 use Composer\Util\Platform;
5091 use Composer\Util\ProcessExecutor;
5092 use Symfony\Component\Console\Input\InputArgument;
5093 use Symfony\Component\Console\Input\InputOption;
5094 use Symfony\Component\Console\Input\InputInterface;
5095 use Symfony\Component\Console\Output\OutputInterface;
5096
5097
5098
5099
5100 class HomeCommand extends BaseCommand
5101 {
5102
5103
5104
5105 protected function configure()
5106 {
5107 $this
5108 ->setName('browse')
5109 ->setAliases(array('home'))
5110 ->setDescription('Opens the package\'s repository URL or homepage in your browser.')
5111 ->setDefinition(array(
5112 new InputArgument('packages', InputArgument::IS_ARRAY, 'Package(s) to browse to.'),
5113 new InputOption('homepage', 'H', InputOption::VALUE_NONE, 'Open the homepage instead of the repository URL.'),
5114 new InputOption('show', 's', InputOption::VALUE_NONE, 'Only show the homepage or repository URL.'),
5115 ))
5116 ->setHelp(
5117 <<<EOT
5118 The home command opens or shows a package's repository URL or
5119 homepage in your default browser.
5120
5121 To open the homepage by default, use -H or --homepage.
5122 To show instead of open the repository or homepage URL, use -s or --show.
5123
5124 Read more at https://getcomposer.org/doc/03-cli.md#browse-home
5125 EOT
5126 );
5127 }
5128
5129
5130
5131
5132 protected function execute(InputInterface $input, OutputInterface $output)
5133 {
5134 $repos = $this->initializeRepos();
5135 $io = $this->getIO();
5136 $return = 0;
5137
5138 $packages = $input->getArgument('packages');
5139 if (!$packages) {
5140 $io->writeError('No package specified, opening homepage for the root package');
5141 $packages = array($this->getComposer()->getPackage()->getName());
5142 }
5143
5144 foreach ($packages as $packageName) {
5145 $handled = false;
5146 $packageExists = false;
5147 foreach ($repos as $repo) {
5148 foreach ($repo->findPackages($packageName) as $package) {
5149 $packageExists = true;
5150 if ($package instanceof CompletePackageInterface && $this->handlePackage($package, $input->getOption('homepage'), $input->getOption('show'))) {
5151 $handled = true;
5152 break 2;
5153 }
5154 }
5155 }
5156
5157 if (!$packageExists) {
5158 $return = 1;
5159 $io->writeError('<warning>Package '.$packageName.' not found</warning>');
5160 }
5161
5162 if (!$handled) {
5163 $return = 1;
5164 $io->writeError('<warning>'.($input->getOption('homepage') ? 'Invalid or missing homepage' : 'Invalid or missing repository URL').' for '.$packageName.'</warning>');
5165 }
5166 }
5167
5168 return $return;
5169 }
5170
5171 private function handlePackage(CompletePackageInterface $package, $showHomepage, $showOnly)
5172 {
5173 $support = $package->getSupport();
5174 $url = isset($support['source']) ? $support['source'] : $package->getSourceUrl();
5175 if (!$url || $showHomepage) {
5176 $url = $package->getHomepage();
5177 }
5178
5179 if (!$url || !filter_var($url, FILTER_VALIDATE_URL)) {
5180 return false;
5181 }
5182
5183 if ($showOnly) {
5184 $this->getIO()->write(sprintf('<info>%s</info>', $url));
5185 } else {
5186 $this->openBrowser($url);
5187 }
5188
5189 return true;
5190 }
5191
5192
5193
5194
5195
5196
5197 private function openBrowser($url)
5198 {
5199 $url = ProcessExecutor::escape($url);
5200
5201 $process = new ProcessExecutor($this->getIO());
5202 if (Platform::isWindows()) {
5203 return $process->execute('start "web" explorer "' . $url . '"', $output);
5204 }
5205
5206 $linux = $process->execute('which xdg-open', $output);
5207 $osx = $process->execute('which open', $output);
5208
5209 if (0 === $linux) {
5210 $process->execute('xdg-open ' . $url, $output);
5211 } elseif (0 === $osx) {
5212 $process->execute('open ' . $url, $output);
5213 } else {
5214 $this->getIO()->writeError('No suitable browser opening command found, open yourself: ' . $url);
5215 }
5216 }
5217
5218
5219
5220
5221
5222
5223
5224
5225 private function initializeRepos()
5226 {
5227 $composer = $this->getComposer(false);
5228
5229 if ($composer) {
5230 return array_merge(
5231 array(new ArrayRepository(array($composer->getPackage()))), 
5232 array($composer->getRepositoryManager()->getLocalRepository()), 
5233 $composer->getRepositoryManager()->getRepositories() 
5234 );
5235 }
5236
5237 return RepositoryFactory::defaultRepos($this->getIO());
5238 }
5239 }
5240 <?php
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252 namespace Composer\Command;
5253
5254 use Composer\DependencyResolver\Pool;
5255 use Composer\Factory;
5256 use Composer\Json\JsonFile;
5257 use Composer\Package\BasePackage;
5258 use Composer\Package\Package;
5259 use Composer\Package\Version\VersionParser;
5260 use Composer\Package\Version\VersionSelector;
5261 use Composer\Repository\CompositeRepository;
5262 use Composer\Repository\PlatformRepository;
5263 use Composer\Repository\RepositoryFactory;
5264 use Composer\Util\ProcessExecutor;
5265 use Symfony\Component\Console\Input\ArrayInput;
5266 use Symfony\Component\Console\Input\InputInterface;
5267 use Symfony\Component\Console\Input\InputOption;
5268 use Symfony\Component\Console\Output\OutputInterface;
5269 use Symfony\Component\Process\ExecutableFinder;
5270 use Symfony\Component\Process\Process;
5271
5272
5273
5274
5275
5276 class InitCommand extends BaseCommand
5277 {
5278
5279 protected $repos;
5280
5281
5282 private $gitConfig;
5283
5284
5285 private $pools;
5286
5287
5288
5289
5290 protected function configure()
5291 {
5292 $this
5293 ->setName('init')
5294 ->setDescription('Creates a basic composer.json file in current directory.')
5295 ->setDefinition(array(
5296 new InputOption('name', null, InputOption::VALUE_REQUIRED, 'Name of the package'),
5297 new InputOption('description', null, InputOption::VALUE_REQUIRED, 'Description of package'),
5298 new InputOption('author', null, InputOption::VALUE_REQUIRED, 'Author name of package'),
5299
5300 new InputOption('type', null, InputOption::VALUE_OPTIONAL, 'Type of package (e.g. library, project, metapackage, composer-plugin)'),
5301 new InputOption('homepage', null, InputOption::VALUE_REQUIRED, 'Homepage of package'),
5302 new InputOption('require', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Package to require with a version constraint, e.g. foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"'),
5303 new InputOption('require-dev', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Package to require for development with a version constraint, e.g. foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"'),
5304 new InputOption('stability', 's', InputOption::VALUE_REQUIRED, 'Minimum stability (empty or one of: '.implode(', ', array_keys(BasePackage::$stabilities)).')'),
5305 new InputOption('license', 'l', InputOption::VALUE_REQUIRED, 'License of package'),
5306 new InputOption('repository', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Add custom repositories, either by URL or using JSON arrays'),
5307 ))
5308 ->setHelp(
5309 <<<EOT
5310 The <info>init</info> command creates a basic composer.json file
5311 in the current directory.
5312
5313 <info>php composer.phar init</info>
5314
5315 Read more at https://getcomposer.org/doc/03-cli.md#init
5316 EOT
5317 )
5318 ;
5319 }
5320
5321
5322
5323
5324 protected function execute(InputInterface $input, OutputInterface $output)
5325 {
5326 $io = $this->getIO();
5327
5328 $allowList = array('name', 'description', 'author', 'type', 'homepage', 'require', 'require-dev', 'stability', 'license');
5329 $options = array_filter(array_intersect_key($input->getOptions(), array_flip($allowList)));
5330
5331 if (isset($options['author'])) {
5332 $options['authors'] = $this->formatAuthors($options['author']);
5333 unset($options['author']);
5334 }
5335
5336 $repositories = $input->getOption('repository');
5337 if ($repositories) {
5338 $config = Factory::createConfig($io);
5339 foreach ($repositories as $repo) {
5340 $options['repositories'][] = RepositoryFactory::configFromString($io, $config, $repo);
5341 }
5342 }
5343
5344 if (isset($options['stability'])) {
5345 $options['minimum-stability'] = $options['stability'];
5346 unset($options['stability']);
5347 }
5348
5349 $options['require'] = isset($options['require']) ? $this->formatRequirements($options['require']) : new \stdClass;
5350 if (array() === $options['require']) {
5351 $options['require'] = new \stdClass;
5352 }
5353
5354 if (isset($options['require-dev'])) {
5355 $options['require-dev'] = $this->formatRequirements($options['require-dev']);
5356 if (array() === $options['require-dev']) {
5357 $options['require-dev'] = new \stdClass;
5358 }
5359 }
5360
5361 $file = new JsonFile(Factory::getComposerFile());
5362 $json = $file->encode($options);
5363
5364 if ($input->isInteractive()) {
5365 $io->writeError(array('', $json, ''));
5366 if (!$io->askConfirmation('Do you confirm generation [<comment>yes</comment>]? ', true)) {
5367 $io->writeError('<error>Command aborted</error>');
5368
5369 return 1;
5370 }
5371 }
5372
5373 $file->write($options);
5374
5375 if ($input->isInteractive() && is_dir('.git')) {
5376 $ignoreFile = realpath('.gitignore');
5377
5378 if (false === $ignoreFile) {
5379 $ignoreFile = realpath('.') . '/.gitignore';
5380 }
5381
5382 if (!$this->hasVendorIgnore($ignoreFile)) {
5383 $question = 'Would you like the <info>vendor</info> directory added to your <info>.gitignore</info> [<comment>yes</comment>]? ';
5384
5385 if ($io->askConfirmation($question, true)) {
5386 $this->addVendorIgnore($ignoreFile);
5387 }
5388 }
5389 }
5390
5391 $question = 'Would you like to install dependencies now [<comment>yes</comment>]? ';
5392 if ($input->isInteractive() && $this->hasDependencies($options) && $io->askConfirmation($question, true)) {
5393 $this->installDependencies($output);
5394 }
5395
5396 return 0;
5397 }
5398
5399
5400
5401
5402 protected function interact(InputInterface $input, OutputInterface $output)
5403 {
5404 $git = $this->getGitConfig();
5405 $io = $this->getIO();
5406 $formatter = $this->getHelperSet()->get('formatter');
5407
5408
5409 $repositories = $input->getOption('repository');
5410 if ($repositories) {
5411 $config = Factory::createConfig($io);
5412 $repos = array(new PlatformRepository);
5413 $createDefaultPackagistRepo = true;
5414 foreach ($repositories as $repo) {
5415 $repoConfig = RepositoryFactory::configFromString($io, $config, $repo);
5416 if (
5417 (isset($repoConfig['packagist']) && $repoConfig === array('packagist' => false))
5418 || (isset($repoConfig['packagist.org']) && $repoConfig === array('packagist.org' => false))
5419 ) {
5420 $createDefaultPackagistRepo = false;
5421 continue;
5422 }
5423 $repos[] = RepositoryFactory::createRepo($io, $config, $repoConfig);
5424 }
5425
5426 if ($createDefaultPackagistRepo) {
5427 $repos[] = RepositoryFactory::createRepo($io, $config, array(
5428 'type' => 'composer',
5429 'url' => 'https://repo.packagist.org',
5430 ));
5431 }
5432
5433 $this->repos = new CompositeRepository($repos);
5434 unset($repos, $config, $repositories);
5435 }
5436
5437 $io->writeError(array(
5438 '',
5439 $formatter->formatBlock('Welcome to the Composer config generator', 'bg=blue;fg=white', true),
5440 '',
5441 ));
5442
5443
5444 $io->writeError(array(
5445 '',
5446 'This command will guide you through creating your composer.json config.',
5447 '',
5448 ));
5449
5450 $cwd = realpath(".");
5451
5452 if (!$name = $input->getOption('name')) {
5453 $name = basename($cwd);
5454 $name = preg_replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $name);
5455 $name = strtolower($name);
5456 if (!empty($_SERVER['COMPOSER_DEFAULT_VENDOR'])) {
5457 $name = $_SERVER['COMPOSER_DEFAULT_VENDOR'] . '/' . $name;
5458 } elseif (isset($git['github.user'])) {
5459 $name = $git['github.user'] . '/' . $name;
5460 } elseif (!empty($_SERVER['USERNAME'])) {
5461 $name = $_SERVER['USERNAME'] . '/' . $name;
5462 } elseif (!empty($_SERVER['USER'])) {
5463 $name = $_SERVER['USER'] . '/' . $name;
5464 } elseif (get_current_user()) {
5465 $name = get_current_user() . '/' . $name;
5466 } else {
5467
5468 $name .= '/' . $name;
5469 }
5470 $name = strtolower($name);
5471 } else {
5472 if (!preg_match('{^[a-z0-9_.-]+/[a-z0-9_.-]+$}D', $name)) {
5473 throw new \InvalidArgumentException(
5474 'The package name '.$name.' is invalid, it should be lowercase and have a vendor name, a forward slash, and a package name, matching: [a-z0-9_.-]+/[a-z0-9_.-]+'
5475 );
5476 }
5477 }
5478
5479 $name = $io->askAndValidate(
5480 'Package name (<vendor>/<name>) [<comment>'.$name.'</comment>]: ',
5481 function ($value) use ($name) {
5482 if (null === $value) {
5483 return $name;
5484 }
5485
5486 if (!preg_match('{^[a-z0-9_.-]+/[a-z0-9_.-]+$}D', $value)) {
5487 throw new \InvalidArgumentException(
5488 'The package name '.$value.' is invalid, it should be lowercase and have a vendor name, a forward slash, and a package name, matching: [a-z0-9_.-]+/[a-z0-9_.-]+'
5489 );
5490 }
5491
5492 return $value;
5493 },
5494 null,
5495 $name
5496 );
5497 $input->setOption('name', $name);
5498
5499 $description = $input->getOption('description') ?: false;
5500 $description = $io->ask(
5501 'Description [<comment>'.$description.'</comment>]: ',
5502 $description
5503 );
5504 $input->setOption('description', $description);
5505
5506 if (null === $author = $input->getOption('author')) {
5507 if (!empty($_SERVER['COMPOSER_DEFAULT_AUTHOR'])) {
5508 $author_name = $_SERVER['COMPOSER_DEFAULT_AUTHOR'];
5509 } elseif (isset($git['user.name'])) {
5510 $author_name = $git['user.name'];
5511 }
5512
5513 if (!empty($_SERVER['COMPOSER_DEFAULT_EMAIL'])) {
5514 $author_email = $_SERVER['COMPOSER_DEFAULT_EMAIL'];
5515 } elseif (isset($git['user.email'])) {
5516 $author_email = $git['user.email'];
5517 }
5518
5519 if (isset($author_name) && isset($author_email)) {
5520 $author = sprintf('%s <%s>', $author_name, $author_email);
5521 }
5522 }
5523
5524 $self = $this;
5525 $author = $io->askAndValidate(
5526 'Author [<comment>'.$author.'</comment>, n to skip]: ',
5527 function ($value) use ($self, $author) {
5528 if ($value === 'n' || $value === 'no') {
5529 return;
5530 }
5531 $value = $value ?: $author;
5532 $author = $self->parseAuthorString($value);
5533
5534 return sprintf('%s <%s>', $author['name'], $author['email']);
5535 },
5536 null,
5537 $author
5538 );
5539 $input->setOption('author', $author);
5540
5541 $minimumStability = $input->getOption('stability') ?: null;
5542 $minimumStability = $io->askAndValidate(
5543 'Minimum Stability [<comment>'.$minimumStability.'</comment>]: ',
5544 function ($value) use ($minimumStability) {
5545 if (null === $value) {
5546 return $minimumStability;
5547 }
5548
5549 if (!isset(BasePackage::$stabilities[$value])) {
5550 throw new \InvalidArgumentException(
5551 'Invalid minimum stability "'.$value.'". Must be empty or one of: '.
5552 implode(', ', array_keys(BasePackage::$stabilities))
5553 );
5554 }
5555
5556 return $value;
5557 },
5558 null,
5559 $minimumStability
5560 );
5561 $input->setOption('stability', $minimumStability);
5562
5563 $type = $input->getOption('type') ?: false;
5564 $type = $io->ask(
5565 'Package Type (e.g. library, project, metapackage, composer-plugin) [<comment>'.$type.'</comment>]: ',
5566 $type
5567 );
5568 $input->setOption('type', $type);
5569
5570 if (null === $license = $input->getOption('license')) {
5571 if (!empty($_SERVER['COMPOSER_DEFAULT_LICENSE'])) {
5572 $license = $_SERVER['COMPOSER_DEFAULT_LICENSE'];
5573 }
5574 }
5575
5576 $license = $io->ask(
5577 'License [<comment>'.$license.'</comment>]: ',
5578 $license
5579 );
5580 $input->setOption('license', $license);
5581
5582 $io->writeError(array('', 'Define your dependencies.', ''));
5583
5584
5585 $repos = $this->getRepos();
5586 $preferredStability = $minimumStability ?: 'stable';
5587 $phpVersion = $repos->findPackage('php', '*')->getPrettyVersion();
5588
5589 $question = 'Would you like to define your dependencies (require) interactively [<comment>yes</comment>]? ';
5590 $require = $input->getOption('require');
5591 $requirements = array();
5592 if ($require || $io->askConfirmation($question, true)) {
5593 $requirements = $this->determineRequirements($input, $output, $require, $phpVersion, $preferredStability);
5594 }
5595 $input->setOption('require', $requirements);
5596
5597 $question = 'Would you like to define your dev dependencies (require-dev) interactively [<comment>yes</comment>]? ';
5598 $requireDev = $input->getOption('require-dev');
5599 $devRequirements = array();
5600 if ($requireDev || $io->askConfirmation($question, true)) {
5601 $devRequirements = $this->determineRequirements($input, $output, $requireDev, $phpVersion, $preferredStability);
5602 }
5603 $input->setOption('require-dev', $devRequirements);
5604 }
5605
5606
5607
5608
5609
5610
5611 public function parseAuthorString($author)
5612 {
5613 if (preg_match('/^(?P<name>[- .,\p{L}\p{N}\p{Mn}\'’"()]+) <(?P<email>.+?)>$/u', $author, $match)) {
5614 if ($this->isValidEmail($match['email'])) {
5615 return array(
5616 'name' => trim($match['name']),
5617 'email' => $match['email'],
5618 );
5619 }
5620 }
5621
5622 throw new \InvalidArgumentException(
5623 'Invalid author string.  Must be in the format: '.
5624 'John Smith <john@example.com>'
5625 );
5626 }
5627
5628 protected function findPackages($name)
5629 {
5630 return $this->getRepos()->search($name);
5631 }
5632
5633 protected function getRepos()
5634 {
5635 if (!$this->repos) {
5636 $this->repos = new CompositeRepository(array_merge(
5637 array(new PlatformRepository),
5638 RepositoryFactory::defaultRepos($this->getIO())
5639 ));
5640 }
5641
5642 return $this->repos;
5643 }
5644
5645 final protected function determineRequirements(InputInterface $input, OutputInterface $output, $requires = array(), $phpVersion = null, $preferredStability = 'stable', $checkProvidedVersions = true, $fixed = false)
5646 {
5647 if ($requires) {
5648 $requires = $this->normalizeRequirements($requires);
5649 $result = array();
5650 $io = $this->getIO();
5651
5652 foreach ($requires as $requirement) {
5653 if (!isset($requirement['version'])) {
5654
5655 list($name, $version) = $this->findBestVersionAndNameForPackage($input, $requirement['name'], $phpVersion, $preferredStability, null, null, $fixed);
5656 $requirement['version'] = $version;
5657
5658
5659 $requirement['name'] = $name;
5660
5661 $io->writeError(sprintf(
5662 'Using version <info>%s</info> for <info>%s</info>',
5663 $requirement['version'],
5664 $requirement['name']
5665 ));
5666 } else {
5667
5668 list($name, $version) = $this->findBestVersionAndNameForPackage($input, $requirement['name'], $phpVersion, $preferredStability, $checkProvidedVersions ? $requirement['version'] : null, 'dev', $fixed);
5669
5670
5671 $requirement['name'] = $name;
5672 }
5673
5674 $result[] = $requirement['name'] . ' ' . $requirement['version'];
5675 }
5676
5677 return $result;
5678 }
5679
5680 $versionParser = new VersionParser();
5681
5682
5683 $composer = $this->getComposer(false);
5684 $installedRepo = $composer ? $composer->getRepositoryManager()->getLocalRepository() : null;
5685 $existingPackages = array();
5686 if ($installedRepo) {
5687 foreach ($installedRepo->getPackages() as $package) {
5688 $existingPackages[] = $package->getName();
5689 }
5690 }
5691 unset($composer, $installedRepo);
5692
5693 $io = $this->getIO();
5694 while (null !== $package = $io->ask('Search for a package: ')) {
5695 $matches = $this->findPackages($package);
5696
5697 if (count($matches)) {
5698
5699 foreach ($matches as $position => $foundPackage) {
5700 if (in_array($foundPackage['name'], $existingPackages, true)) {
5701 unset($matches[$position]);
5702 }
5703 }
5704 $matches = array_values($matches);
5705
5706 $exactMatch = null;
5707 $choices = array();
5708 foreach ($matches as $position => $foundPackage) {
5709 $abandoned = '';
5710 if (isset($foundPackage['abandoned'])) {
5711 if (is_string($foundPackage['abandoned'])) {
5712 $replacement = sprintf('Use %s instead', $foundPackage['abandoned']);
5713 } else {
5714 $replacement = 'No replacement was suggested';
5715 }
5716 $abandoned = sprintf('<warning>Abandoned. %s.</warning>', $replacement);
5717 }
5718
5719 $choices[] = sprintf(' <info>%5s</info> %s %s', "[$position]", $foundPackage['name'], $abandoned);
5720 if ($foundPackage['name'] === $package) {
5721 $exactMatch = true;
5722 break;
5723 }
5724 }
5725
5726
5727 if (!$exactMatch) {
5728 $io->writeError(array(
5729 '',
5730 sprintf('Found <info>%s</info> packages matching <info>%s</info>', count($matches), $package),
5731 '',
5732 ));
5733
5734 $io->writeError($choices);
5735 $io->writeError('');
5736
5737 $validator = function ($selection) use ($matches, $versionParser) {
5738 if ('' === $selection) {
5739 return false;
5740 }
5741
5742 if (is_numeric($selection) && isset($matches[(int) $selection])) {
5743 $package = $matches[(int) $selection];
5744
5745 return $package['name'];
5746 }
5747
5748 if (preg_match('{^\s*(?P<name>[\S/]+)(?:\s+(?P<version>\S+))?\s*$}', $selection, $packageMatches)) {
5749 if (isset($packageMatches['version'])) {
5750
5751
5752
5753 $versionParser->parseConstraints($packageMatches['version']);
5754
5755 return $packageMatches['name'].' '.$packageMatches['version'];
5756 }
5757
5758
5759 return $packageMatches['name'];
5760 }
5761
5762 throw new \Exception('Not a valid selection');
5763 };
5764
5765 $package = $io->askAndValidate(
5766 'Enter package # to add, or the complete package name if it is not listed: ',
5767 $validator,
5768 3,
5769 false
5770 );
5771 }
5772
5773
5774 if (false !== $package && false === strpos($package, ' ')) {
5775 $validator = function ($input) {
5776 $input = trim($input);
5777
5778 return $input ?: false;
5779 };
5780
5781 $constraint = $io->askAndValidate(
5782 'Enter the version constraint to require (or leave blank to use the latest version): ',
5783 $validator,
5784 3,
5785 false
5786 );
5787
5788 if (false === $constraint) {
5789 list($name, $constraint) = $this->findBestVersionAndNameForPackage($input, $package, $phpVersion, $preferredStability);
5790
5791 $io->writeError(sprintf(
5792 'Using version <info>%s</info> for <info>%s</info>',
5793 $constraint,
5794 $package
5795 ));
5796 }
5797
5798 $package .= ' '.$constraint;
5799 }
5800
5801 if (false !== $package) {
5802 $requires[] = $package;
5803 $existingPackages[] = substr($package, 0, strpos($package, ' '));
5804 }
5805 }
5806 }
5807
5808 return $requires;
5809 }
5810
5811 protected function formatAuthors($author)
5812 {
5813 return array($this->parseAuthorString($author));
5814 }
5815
5816 protected function formatRequirements(array $requirements)
5817 {
5818 $requires = array();
5819 $requirements = $this->normalizeRequirements($requirements);
5820 foreach ($requirements as $requirement) {
5821 $requires[$requirement['name']] = $requirement['version'];
5822 }
5823
5824 return $requires;
5825 }
5826
5827 protected function getGitConfig()
5828 {
5829 if (null !== $this->gitConfig) {
5830 return $this->gitConfig;
5831 }
5832
5833 $finder = new ExecutableFinder();
5834 $gitBin = $finder->find('git');
5835
5836
5837 if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
5838 $cmd = new Process(array($gitBin, 'config', '-l'));
5839 } else {
5840 $cmd = new Process(sprintf('%s config -l', ProcessExecutor::escape($gitBin)));
5841 }
5842 $cmd->run();
5843
5844 if ($cmd->isSuccessful()) {
5845 $this->gitConfig = array();
5846 preg_match_all('{^([^=]+)=(.*)$}m', $cmd->getOutput(), $matches, PREG_SET_ORDER);
5847 foreach ($matches as $match) {
5848 $this->gitConfig[$match[1]] = $match[2];
5849 }
5850
5851 return $this->gitConfig;
5852 }
5853
5854 return $this->gitConfig = array();
5855 }
5856
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
5867
5868
5869
5870
5871
5872
5873 protected function hasVendorIgnore($ignoreFile, $vendor = 'vendor')
5874 {
5875 if (!file_exists($ignoreFile)) {
5876 return false;
5877 }
5878
5879 $pattern = sprintf('{^/?%s(/\*?)?$}', preg_quote($vendor));
5880
5881 $lines = file($ignoreFile, FILE_IGNORE_NEW_LINES);
5882 foreach ($lines as $line) {
5883 if (preg_match($pattern, $line)) {
5884 return true;
5885 }
5886 }
5887
5888 return false;
5889 }
5890
5891 protected function normalizeRequirements(array $requirements)
5892 {
5893 $parser = new VersionParser();
5894
5895 return $parser->parseNameVersionPairs($requirements);
5896 }
5897
5898 protected function addVendorIgnore($ignoreFile, $vendor = '/vendor/')
5899 {
5900 $contents = "";
5901 if (file_exists($ignoreFile)) {
5902 $contents = file_get_contents($ignoreFile);
5903
5904 if ("\n" !== substr($contents, 0, -1)) {
5905 $contents .= "\n";
5906 }
5907 }
5908
5909 file_put_contents($ignoreFile, $contents . $vendor. "\n");
5910 }
5911
5912 protected function isValidEmail($email)
5913 {
5914
5915 if (!function_exists('filter_var')) {
5916 return true;
5917 }
5918
5919
5920 if (PHP_VERSION_ID < 50303) {
5921 return true;
5922 }
5923
5924 return false !== filter_var($email, FILTER_VALIDATE_EMAIL);
5925 }
5926
5927 private function getPool(InputInterface $input, $minimumStability = null)
5928 {
5929 $key = $minimumStability ?: 'default';
5930
5931 if (!isset($this->pools[$key])) {
5932 $this->pools[$key] = $pool = new Pool($minimumStability ?: $this->getMinimumStability($input));
5933 $pool->addRepository($this->getRepos());
5934 }
5935
5936 return $this->pools[$key];
5937 }
5938
5939 private function getMinimumStability(InputInterface $input)
5940 {
5941 if ($input->hasOption('stability')) {
5942 return VersionParser::normalizeStability($input->getOption('stability') ?: 'stable');
5943 }
5944
5945 $file = Factory::getComposerFile();
5946 if (is_file($file) && is_readable($file) && is_array($composer = json_decode(file_get_contents($file), true))) {
5947 if (!empty($composer['minimum-stability'])) {
5948 return VersionParser::normalizeStability($composer['minimum-stability']);
5949 }
5950 }
5951
5952 return 'stable';
5953 }
5954
5955
5956
5957
5958
5959
5960
5961
5962
5963
5964
5965
5966
5967
5968
5969
5970 private function findBestVersionAndNameForPackage(InputInterface $input, $name, $phpVersion, $preferredStability = 'stable', $requiredVersion = null, $minimumStability = null, $fixed = null)
5971 {
5972
5973 $versionSelector = new VersionSelector($this->getPool($input, $minimumStability));
5974 $ignorePlatformReqs = $input->hasOption('ignore-platform-reqs') && $input->getOption('ignore-platform-reqs');
5975
5976
5977 if ($ignorePlatformReqs) {
5978 $phpVersion = null;
5979 }
5980
5981 $package = $versionSelector->findBestCandidate($name, $requiredVersion, $phpVersion, $preferredStability);
5982
5983 if (!$package) {
5984
5985
5986 if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name)) {
5987 return array($name, $requiredVersion ?: '*');
5988 }
5989
5990
5991 if ($phpVersion && $versionSelector->findBestCandidate($name, $requiredVersion, null, $preferredStability)) {
5992 throw new \InvalidArgumentException(sprintf(
5993 'Package %s at version %s has a PHP requirement incompatible with your PHP version (%s)',
5994 $name,
5995 $requiredVersion,
5996 $phpVersion
5997 ));
5998 }
5999
6000 if ($requiredVersion && $versionSelector->findBestCandidate($name, null, $phpVersion, $preferredStability)) {
6001 throw new \InvalidArgumentException(sprintf(
6002 'Could not find package %s in a version matching %s',
6003 $name,
6004 $requiredVersion
6005 ));
6006 }
6007
6008 if ($phpVersion && $versionSelector->findBestCandidate($name)) {
6009 throw new \InvalidArgumentException(sprintf(
6010 'Could not find package %s in any version matching your PHP version (%s)',
6011 $name,
6012 $phpVersion
6013 ));
6014 }
6015
6016
6017 $similar = $this->findSimilar($name);
6018 if ($similar) {
6019
6020 if ($requiredVersion === null && in_array($name, $similar, true)) {
6021 throw new \InvalidArgumentException(sprintf(
6022 'Could not find a version of package %s matching your minimum-stability (%s). Require it with an explicit version constraint allowing its desired stability.',
6023 $name,
6024 $this->getMinimumStability($input)
6025 ));
6026 }
6027
6028 throw new \InvalidArgumentException(sprintf(
6029 "Could not find package %s.\n\nDid you mean " . (count($similar) > 1 ? 'one of these' : 'this') . "?\n    %s",
6030 $name,
6031 implode("\n    ", $similar)
6032 ));
6033 }
6034
6035 throw new \InvalidArgumentException(sprintf(
6036 'Could not find a matching version of package %s. Check the package spelling, your version constraint and that the package is available in a stability which matches your minimum-stability (%s).',
6037 $name,
6038 $this->getMinimumStability($input)
6039 ));
6040 }
6041
6042 return array(
6043 $package->getPrettyName(),
6044 $fixed ? $package->getPrettyVersion() : $versionSelector->findRecommendedRequireVersion($package),
6045 );
6046 }
6047
6048 private function findSimilar($package)
6049 {
6050 try {
6051 $results = $this->repos->search($package);
6052 } catch (\Exception $e) {
6053
6054 return array();
6055 }
6056 $similarPackages = array();
6057
6058 $installedRepo = $this->getComposer()->getRepositoryManager()->getLocalRepository();
6059
6060 foreach ($results as $result) {
6061 if ($installedRepo->findPackage($result['name'], '*')) {
6062
6063 continue;
6064 }
6065 $similarPackages[$result['name']] = levenshtein($package, $result['name']);
6066 }
6067 asort($similarPackages);
6068
6069 return array_keys(array_slice($similarPackages, 0, 5));
6070 }
6071
6072 private function installDependencies($output)
6073 {
6074 try {
6075 $installCommand = $this->getApplication()->find('install');
6076 $installCommand->run(new ArrayInput(array()), $output);
6077 } catch (\Exception $e) {
6078 $this->getIO()->writeError('Could not install dependencies. Run `composer install` to see more information.');
6079 }
6080
6081 }
6082
6083 private function hasDependencies($options)
6084 {
6085 $requires = (array) $options['require'];
6086 $devRequires = isset($options['require-dev']) ? (array) $options['require-dev'] : array();
6087
6088 return !empty($requires) || !empty($devRequires);
6089 }
6090 }
6091 <?php
6092
6093
6094
6095
6096
6097
6098
6099
6100
6101
6102
6103 namespace Composer\Command;
6104
6105 use Composer\Installer;
6106 use Composer\Plugin\CommandEvent;
6107 use Composer\Plugin\PluginEvents;
6108 use Symfony\Component\Console\Input\InputInterface;
6109 use Symfony\Component\Console\Input\InputOption;
6110 use Symfony\Component\Console\Input\InputArgument;
6111 use Symfony\Component\Console\Output\OutputInterface;
6112
6113
6114
6115
6116
6117
6118
6119 class InstallCommand extends BaseCommand
6120 {
6121 protected function configure()
6122 {
6123 $this
6124 ->setName('install')
6125 ->setAliases(array('i'))
6126 ->setDescription('Installs the project dependencies from the composer.lock file if present, or falls back on the composer.json.')
6127 ->setDefinition(array(
6128 new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
6129 new InputOption('prefer-dist', null, InputOption::VALUE_NONE, 'Forces installation from package dist even for dev versions.'),
6130 new InputOption('dry-run', null, InputOption::VALUE_NONE, 'Outputs the operations but will not execute anything (implicitly enables --verbose).'),
6131 new InputOption('dev', null, InputOption::VALUE_NONE, 'Enables installation of require-dev packages (enabled by default, only present for BC).'),
6132 new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables installation of require-dev packages.'),
6133 new InputOption('no-custom-installers', null, InputOption::VALUE_NONE, 'DEPRECATED: Use no-plugins instead.'),
6134 new InputOption('no-autoloader', null, InputOption::VALUE_NONE, 'Skips autoloader generation'),
6135 new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.'),
6136 new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
6137 new InputOption('no-suggest', null, InputOption::VALUE_NONE, 'Do not show package suggestions.'),
6138 new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Shows more details including new commits pulled in when updating packages.'),
6139 new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump'),
6140 new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'),
6141 new InputOption('apcu-autoloader', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'),
6142 new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'),
6143 new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Should not be provided, use composer require instead to add a given package to composer.json.'),
6144 ))
6145 ->setHelp(
6146 <<<EOT
6147 The <info>install</info> command reads the composer.lock file from
6148 the current directory, processes it, and downloads and installs all the
6149 libraries and dependencies outlined in that file. If the file does not
6150 exist it will look for composer.json and do the same.
6151
6152 <info>php composer.phar install</info>
6153
6154 Read more at https://getcomposer.org/doc/03-cli.md#install-i
6155 EOT
6156 )
6157 ;
6158 }
6159
6160 protected function execute(InputInterface $input, OutputInterface $output)
6161 {
6162 $io = $this->getIO();
6163 if ($args = $input->getArgument('packages')) {
6164 $io->writeError('<error>Invalid argument '.implode(' ', $args).'. Use "composer require '.implode(' ', $args).'" instead to add packages to your composer.json.</error>');
6165
6166 return 1;
6167 }
6168
6169 if ($input->getOption('no-custom-installers')) {
6170 $io->writeError('<warning>You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.</warning>');
6171 $input->setOption('no-plugins', true);
6172 }
6173
6174 if ($input->getOption('dev')) {
6175 $io->writeError('<warning>You are using the deprecated option "dev". Dev packages are installed by default now.</warning>');
6176 }
6177
6178 $composer = $this->getComposer(true, $input->getOption('no-plugins'));
6179 $composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress'));
6180
6181 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'install', $input, $output);
6182 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
6183
6184 $install = Installer::create($io, $composer);
6185
6186 $config = $composer->getConfig();
6187 list($preferSource, $preferDist) = $this->getPreferredInstallOptions($config, $input);
6188
6189 $optimize = $input->getOption('optimize-autoloader') || $config->get('optimize-autoloader');
6190 $authoritative = $input->getOption('classmap-authoritative') || $config->get('classmap-authoritative');
6191 $apcu = $input->getOption('apcu-autoloader') || $config->get('apcu-autoloader');
6192
6193 $install
6194 ->setDryRun($input->getOption('dry-run'))
6195 ->setVerbose($input->getOption('verbose'))
6196 ->setPreferSource($preferSource)
6197 ->setPreferDist($preferDist)
6198 ->setDevMode(!$input->getOption('no-dev'))
6199 ->setDumpAutoloader(!$input->getOption('no-autoloader'))
6200 ->setRunScripts(!$input->getOption('no-scripts'))
6201 ->setSkipSuggest($input->getOption('no-suggest'))
6202 ->setOptimizeAutoloader($optimize)
6203 ->setClassMapAuthoritative($authoritative)
6204 ->setApcuAutoloader($apcu)
6205 ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs'))
6206 ;
6207
6208 if ($input->getOption('no-plugins')) {
6209 $install->disablePlugins();
6210 }
6211
6212 return $install->run();
6213 }
6214 }
6215 <?php
6216
6217
6218
6219
6220
6221
6222
6223
6224
6225
6226
6227 namespace Composer\Command;
6228
6229 use Composer\Json\JsonFile;
6230 use Composer\Plugin\CommandEvent;
6231 use Composer\Plugin\PluginEvents;
6232 use Composer\Package\PackageInterface;
6233 use Composer\Repository\RepositoryInterface;
6234 use Symfony\Component\Console\Helper\Table;
6235 use Symfony\Component\Console\Input\InputInterface;
6236 use Symfony\Component\Console\Input\InputOption;
6237 use Symfony\Component\Console\Output\OutputInterface;
6238
6239
6240
6241
6242 class LicensesCommand extends BaseCommand
6243 {
6244 protected function configure()
6245 {
6246 $this
6247 ->setName('licenses')
6248 ->setDescription('Shows information about licenses of dependencies.')
6249 ->setDefinition(array(
6250 new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text'),
6251 new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables search in require-dev packages.'),
6252 ))
6253 ->setHelp(
6254 <<<EOT
6255 The license command displays detailed information about the licenses of
6256 the installed dependencies.
6257
6258 Read more at https://getcomposer.org/doc/03-cli.md#licenses
6259 EOT
6260 )
6261 ;
6262 }
6263
6264 protected function execute(InputInterface $input, OutputInterface $output)
6265 {
6266 $composer = $this->getComposer();
6267
6268 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'licenses', $input, $output);
6269 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
6270
6271 $root = $composer->getPackage();
6272 $repo = $composer->getRepositoryManager()->getLocalRepository();
6273
6274 if ($input->getOption('no-dev')) {
6275 $packages = $this->filterRequiredPackages($repo, $root);
6276 } else {
6277 $packages = $this->appendPackages($repo->getPackages(), array());
6278 }
6279
6280 ksort($packages);
6281 $io = $this->getIO();
6282
6283 switch ($format = $input->getOption('format')) {
6284 case 'text':
6285 $io->write('Name: <comment>'.$root->getPrettyName().'</comment>');
6286 $io->write('Version: <comment>'.$root->getFullPrettyVersion().'</comment>');
6287 $io->write('Licenses: <comment>'.(implode(', ', $root->getLicense()) ?: 'none').'</comment>');
6288 $io->write('Dependencies:');
6289 $io->write('');
6290
6291 $table = new Table($output);
6292 $table->setStyle('compact');
6293 $tableStyle = $table->getStyle();
6294 if (method_exists($tableStyle, 'setVerticalBorderChars')) {
6295 $tableStyle->setVerticalBorderChars('');
6296 } else {
6297 $tableStyle->setVerticalBorderChar('');
6298 }
6299 $tableStyle->setCellRowContentFormat('%s  ');
6300 $table->setHeaders(array('Name', 'Version', 'License'));
6301 foreach ($packages as $package) {
6302 $table->addRow(array(
6303 $package->getPrettyName(),
6304 $package->getFullPrettyVersion(),
6305 implode(', ', $package->getLicense()) ?: 'none',
6306 ));
6307 }
6308 $table->render();
6309 break;
6310
6311 case 'json':
6312 $dependencies = array();
6313 foreach ($packages as $package) {
6314 $dependencies[$package->getPrettyName()] = array(
6315 'version' => $package->getFullPrettyVersion(),
6316 'license' => $package->getLicense(),
6317 );
6318 }
6319
6320 $io->write(JsonFile::encode(array(
6321 'name' => $root->getPrettyName(),
6322 'version' => $root->getFullPrettyVersion(),
6323 'license' => $root->getLicense(),
6324 'dependencies' => $dependencies,
6325 )));
6326 break;
6327
6328 default:
6329 throw new \RuntimeException(sprintf('Unsupported format "%s".  See help for supported formats.', $format));
6330 }
6331
6332 return 0;
6333 }
6334
6335
6336
6337
6338
6339
6340
6341
6342
6343 private function filterRequiredPackages(RepositoryInterface $repo, PackageInterface $package, $bucket = array())
6344 {
6345 $requires = array_keys($package->getRequires());
6346
6347 $packageListNames = array_keys($bucket);
6348 $packages = array_filter(
6349 $repo->getPackages(),
6350 function ($package) use ($requires, $packageListNames) {
6351 return in_array($package->getName(), $requires) && !in_array($package->getName(), $packageListNames);
6352 }
6353 );
6354
6355 $bucket = $this->appendPackages($packages, $bucket);
6356
6357 foreach ($packages as $package) {
6358 $bucket = $this->filterRequiredPackages($repo, $package, $bucket);
6359 }
6360
6361 return $bucket;
6362 }
6363
6364
6365
6366
6367
6368
6369
6370
6371 public function appendPackages(array $packages, array $bucket)
6372 {
6373 foreach ($packages as $package) {
6374 $bucket[$package->getName()] = $package;
6375 }
6376
6377 return $bucket;
6378 }
6379 }
6380 <?php
6381
6382
6383
6384
6385
6386
6387
6388
6389
6390
6391
6392 namespace Composer\Command;
6393
6394 use Symfony\Component\Console\Input\InputInterface;
6395 use Symfony\Component\Console\Input\InputArgument;
6396 use Symfony\Component\Console\Input\ArrayInput;
6397 use Symfony\Component\Console\Input\InputOption;
6398 use Symfony\Component\Console\Output\OutputInterface;
6399
6400
6401
6402
6403 class OutdatedCommand extends ShowCommand
6404 {
6405 protected function configure()
6406 {
6407 $this
6408 ->setName('outdated')
6409 ->setDescription('Shows a list of installed packages that have updates available, including their latest version.')
6410 ->setDefinition(array(
6411 new InputArgument('package', InputArgument::OPTIONAL, 'Package to inspect. Or a name including a wildcard (*) to filter lists of packages instead.'),
6412 new InputOption('outdated', 'o', InputOption::VALUE_NONE, 'Show only packages that are outdated (this is the default, but present here for compat with `show`'),
6413 new InputOption('all', 'a', InputOption::VALUE_NONE, 'Show all installed packages with their latest versions'),
6414 new InputOption('direct', 'D', InputOption::VALUE_NONE, 'Shows only packages that are directly required by the root package'),
6415 new InputOption('strict', null, InputOption::VALUE_NONE, 'Return a non-zero exit code when there are outdated packages'),
6416 new InputOption('minor-only', 'm', InputOption::VALUE_NONE, 'Show only packages that have minor SemVer-compatible updates. Use with the --outdated option.'),
6417 new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text'),
6418 new InputOption('ignore', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore specified package(s). Use it with the --outdated option if you don\'t want to be informed about new versions of some packages.'),
6419 ))
6420 ->setHelp(
6421 <<<EOT
6422 The outdated command is just a proxy for `composer show -l`
6423
6424 The color coding (or signage if you have ANSI colors disabled) for dependency versions is as such:
6425
6426 - <info>green</info> (=): Dependency is in the latest version and is up to date.
6427 - <comment>yellow</comment> (~): Dependency has a new version available that includes backwards
6428   compatibility breaks according to semver, so upgrade when you can but it
6429   may involve work.
6430 - <highlight>red</highlight> (!): Dependency has a new version that is semver-compatible and you should upgrade it.
6431
6432 Read more at https://getcomposer.org/doc/03-cli.md#outdated
6433 EOT
6434 )
6435 ;
6436 }
6437
6438 protected function execute(InputInterface $input, OutputInterface $output)
6439 {
6440 $args = array(
6441 'command' => 'show',
6442 '--latest' => true,
6443 );
6444 if (!$input->getOption('all')) {
6445 $args['--outdated'] = true;
6446 }
6447 if ($input->getOption('direct')) {
6448 $args['--direct'] = true;
6449 }
6450 if ($input->getArgument('package')) {
6451 $args['package'] = $input->getArgument('package');
6452 }
6453 if ($input->getOption('strict')) {
6454 $args['--strict'] = true;
6455 }
6456 if ($input->getOption('minor-only')) {
6457 $args['--minor-only'] = true;
6458 }
6459 $args['--format'] = $input->getOption('format');
6460 $args['--ignore'] = $input->getOption('ignore');
6461
6462 $input = new ArrayInput($args);
6463
6464 return $this->getApplication()->run($input, $output);
6465 }
6466
6467
6468
6469
6470 public function isProxyCommand()
6471 {
6472 return true;
6473 }
6474 }
6475 <?php
6476
6477
6478
6479
6480
6481
6482
6483
6484
6485
6486
6487 namespace Composer\Command;
6488
6489 use Symfony\Component\Console\Input\InputInterface;
6490 use Symfony\Component\Console\Output\OutputInterface;
6491
6492
6493
6494
6495 class ProhibitsCommand extends BaseDependencyCommand
6496 {
6497
6498
6499
6500 protected function configure()
6501 {
6502 parent::configure();
6503
6504 $this
6505 ->setName('prohibits')
6506 ->setAliases(array('why-not'))
6507 ->setDescription('Shows which packages prevent the given package from being installed.')
6508 ->setHelp(
6509 <<<EOT
6510 Displays detailed information about why a package cannot be installed.
6511
6512 <info>php composer.phar prohibits composer/composer</info>
6513
6514 Read more at https://getcomposer.org/doc/03-cli.md#prohibits-why-not-
6515 EOT
6516 )
6517 ;
6518 }
6519
6520
6521
6522
6523
6524
6525
6526
6527 protected function execute(InputInterface $input, OutputInterface $output)
6528 {
6529 return parent::doExecute($input, $output, true);
6530 }
6531 }
6532 <?php
6533
6534
6535
6536
6537
6538
6539
6540
6541
6542
6543
6544 namespace Composer\Command;
6545
6546 use Composer\Config\JsonConfigSource;
6547 use Composer\Installer;
6548 use Composer\Plugin\CommandEvent;
6549 use Composer\Plugin\PluginEvents;
6550 use Composer\Json\JsonFile;
6551 use Composer\Factory;
6552 use Symfony\Component\Console\Input\InputInterface;
6553 use Symfony\Component\Console\Input\InputOption;
6554 use Symfony\Component\Console\Input\InputArgument;
6555 use Symfony\Component\Console\Output\OutputInterface;
6556 use Composer\Package\BasePackage;
6557
6558
6559
6560
6561
6562 class RemoveCommand extends BaseCommand
6563 {
6564 protected function configure()
6565 {
6566 $this
6567 ->setName('remove')
6568 ->setDescription('Removes a package from the require or require-dev.')
6569 ->setDefinition(array(
6570 new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'Packages that should be removed.'),
6571 new InputOption('dev', null, InputOption::VALUE_NONE, 'Removes a package from the require-dev section.'),
6572 new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
6573 new InputOption('no-update', null, InputOption::VALUE_NONE, 'Disables the automatic update of the dependencies.'),
6574 new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.'),
6575 new InputOption('update-no-dev', null, InputOption::VALUE_NONE, 'Run the dependency update with the --no-dev option.'),
6576 new InputOption('update-with-dependencies', null, InputOption::VALUE_NONE, 'Allows inherited dependencies to be updated with explicit dependencies. (Deprecrated, is now default behavior)'),
6577 new InputOption('no-update-with-dependencies', null, InputOption::VALUE_NONE, 'Does not allow inherited dependencies to be updated with explicit dependencies.'),
6578 new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'),
6579 new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump'),
6580 new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'),
6581 new InputOption('apcu-autoloader', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'),
6582 ))
6583 ->setHelp(
6584 <<<EOT
6585 The <info>remove</info> command removes a package from the current
6586 list of installed packages
6587
6588 <info>php composer.phar remove</info>
6589
6590 Read more at https://getcomposer.org/doc/03-cli.md#remove
6591 EOT
6592 )
6593 ;
6594 }
6595
6596 protected function execute(InputInterface $input, OutputInterface $output)
6597 {
6598 $packages = $input->getArgument('packages');
6599 $packages = array_map('strtolower', $packages);
6600
6601 $file = Factory::getComposerFile();
6602
6603 $jsonFile = new JsonFile($file);
6604 $composer = $jsonFile->read();
6605 $composerBackup = file_get_contents($jsonFile->getPath());
6606
6607 $json = new JsonConfigSource($jsonFile);
6608
6609 $type = $input->getOption('dev') ? 'require-dev' : 'require';
6610 $altType = !$input->getOption('dev') ? 'require-dev' : 'require';
6611 $io = $this->getIO();
6612
6613 if ($input->getOption('update-with-dependencies')) {
6614 $io->writeError('<warning>You are using the deprecated option "update-with-dependencies". This is now default behaviour. The --no-update-with-dependencies option can be used to remove a package without its dependencies.</warning>');
6615 }
6616
6617
6618 foreach (array('require', 'require-dev') as $linkType) {
6619 if (isset($composer[$linkType])) {
6620 foreach ($composer[$linkType] as $name => $version) {
6621 $composer[$linkType][strtolower($name)] = $name;
6622 }
6623 }
6624 }
6625
6626 foreach ($packages as $package) {
6627 if (isset($composer[$type][$package])) {
6628 $json->removeLink($type, $composer[$type][$package]);
6629 } elseif (isset($composer[$altType][$package])) {
6630 $io->writeError('<warning>' . $composer[$altType][$package] . ' could not be found in ' . $type . ' but it is present in ' . $altType . '</warning>');
6631 if ($io->isInteractive()) {
6632 if ($io->askConfirmation('Do you want to remove it from ' . $altType . ' [<comment>yes</comment>]? ', true)) {
6633 $json->removeLink($altType, $composer[$altType][$package]);
6634 }
6635 }
6636 } elseif (isset($composer[$type]) && $matches = preg_grep(BasePackage::packageNameToRegexp($package), array_keys($composer[$type]))) {
6637 foreach ($matches as $matchedPackage) {
6638 $json->removeLink($type, $matchedPackage);
6639 }
6640 } elseif (isset($composer[$altType]) && $matches = preg_grep(BasePackage::packageNameToRegexp($package), array_keys($composer[$altType]))) {
6641 foreach ($matches as $matchedPackage) {
6642 $io->writeError('<warning>' . $matchedPackage . ' could not be found in ' . $type . ' but it is present in ' . $altType . '</warning>');
6643 if ($io->isInteractive()) {
6644 if ($io->askConfirmation('Do you want to remove it from ' . $altType . ' [<comment>yes</comment>]? ', true)) {
6645 $json->removeLink($altType, $matchedPackage);
6646 }
6647 }
6648 }
6649 } else {
6650 $io->writeError('<warning>'.$package.' is not required in your composer.json and has not been removed</warning>');
6651 }
6652 }
6653
6654 if ($input->getOption('no-update')) {
6655 return 0;
6656 }
6657
6658
6659 $this->resetComposer();
6660 $composer = $this->getComposer(true, $input->getOption('no-plugins'));
6661 $composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress'));
6662
6663 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'remove', $input, $output);
6664 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
6665
6666 $install = Installer::create($io, $composer);
6667
6668 $updateDevMode = !$input->getOption('update-no-dev');
6669 $optimize = $input->getOption('optimize-autoloader') || $composer->getConfig()->get('optimize-autoloader');
6670 $authoritative = $input->getOption('classmap-authoritative') || $composer->getConfig()->get('classmap-authoritative');
6671 $apcu = $input->getOption('apcu-autoloader') || $composer->getConfig()->get('apcu-autoloader');
6672
6673 $install
6674 ->setVerbose($input->getOption('verbose'))
6675 ->setDevMode($updateDevMode)
6676 ->setOptimizeAutoloader($optimize)
6677 ->setClassMapAuthoritative($authoritative)
6678 ->setApcuAutoloader($apcu)
6679 ->setUpdate(true)
6680 ->setUpdateAllowList($packages)
6681 ->setAllowListTransitiveDependencies(!$input->getOption('no-update-with-dependencies'))
6682 ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs'))
6683 ->setRunScripts(!$input->getOption('no-scripts'))
6684 ;
6685
6686 $status = $install->run();
6687 if ($status !== 0) {
6688 $io->writeError("\n".'<error>Removal failed, reverting '.$file.' to its original content.</error>');
6689 file_put_contents($jsonFile->getPath(), $composerBackup);
6690 }
6691
6692 return $status;
6693 }
6694 }
6695 <?php
6696
6697
6698
6699
6700
6701
6702
6703
6704
6705
6706
6707 namespace Composer\Command;
6708
6709 use Symfony\Component\Console\Input\InputInterface;
6710 use Symfony\Component\Console\Input\InputArgument;
6711 use Symfony\Component\Console\Input\InputOption;
6712 use Symfony\Component\Console\Output\OutputInterface;
6713 use Composer\Factory;
6714 use Composer\Installer;
6715 use Composer\Json\JsonFile;
6716 use Composer\Json\JsonManipulator;
6717 use Composer\Package\Version\VersionParser;
6718 use Composer\Plugin\CommandEvent;
6719 use Composer\Plugin\PluginEvents;
6720 use Composer\Repository\CompositeRepository;
6721 use Composer\Repository\PlatformRepository;
6722 use Composer\IO\IOInterface;
6723 use Composer\Util\Silencer;
6724
6725
6726
6727
6728
6729 class RequireCommand extends InitCommand
6730 {
6731 private $newlyCreated;
6732 private $json;
6733 private $file;
6734 private $composerBackup;
6735
6736 protected function configure()
6737 {
6738 $this
6739 ->setName('require')
6740 ->setDescription('Adds required packages to your composer.json and installs them.')
6741 ->setDefinition(array(
6742 new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Optional package name can also include a version constraint, e.g. foo/bar or foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"'),
6743 new InputOption('dev', null, InputOption::VALUE_NONE, 'Add requirement to require-dev.'),
6744 new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
6745 new InputOption('prefer-dist', null, InputOption::VALUE_NONE, 'Forces installation from package dist even for dev versions.'),
6746 new InputOption('fixed', null, InputOption::VALUE_NONE, 'Write fixed version to the composer.json.'),
6747 new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
6748 new InputOption('no-suggest', null, InputOption::VALUE_NONE, 'Do not show package suggestions.'),
6749 new InputOption('no-update', null, InputOption::VALUE_NONE, 'Disables the automatic update of the dependencies.'),
6750 new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.'),
6751 new InputOption('update-no-dev', null, InputOption::VALUE_NONE, 'Run the dependency update with the --no-dev option.'),
6752 new InputOption('update-with-dependencies', null, InputOption::VALUE_NONE, 'Allows inherited dependencies to be updated, except those that are root requirements.'),
6753 new InputOption('update-with-all-dependencies', null, InputOption::VALUE_NONE, 'Allows all inherited dependencies to be updated, including those that are root requirements.'),
6754 new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'),
6755 new InputOption('prefer-stable', null, InputOption::VALUE_NONE, 'Prefer stable versions of dependencies.'),
6756 new InputOption('prefer-lowest', null, InputOption::VALUE_NONE, 'Prefer lowest versions of dependencies.'),
6757 new InputOption('sort-packages', null, InputOption::VALUE_NONE, 'Sorts packages when adding/updating a new dependency'),
6758 new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump'),
6759 new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'),
6760 new InputOption('apcu-autoloader', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'),
6761 ))
6762 ->setHelp(
6763 <<<EOT
6764 The require command adds required packages to your composer.json and installs them.
6765
6766 If you do not specify a package, composer will prompt you to search for a package, and given results, provide a list of
6767 matches to require.
6768
6769 If you do not specify a version constraint, composer will choose a suitable one based on the available package versions.
6770
6771 If you do not want to install the new dependencies immediately you can call it with --no-update
6772
6773 Read more at https://getcomposer.org/doc/03-cli.md#require
6774 EOT
6775 )
6776 ;
6777 }
6778
6779 protected function execute(InputInterface $input, OutputInterface $output)
6780 {
6781 if (function_exists('pcntl_async_signals') && function_exists('pcntl_signal')) {
6782 pcntl_async_signals(true);
6783 pcntl_signal(SIGINT, array($this, 'revertComposerFile'));
6784 pcntl_signal(SIGTERM, array($this, 'revertComposerFile'));
6785 pcntl_signal(SIGHUP, array($this, 'revertComposerFile'));
6786 }
6787
6788 $this->file = Factory::getComposerFile();
6789 $io = $this->getIO();
6790
6791 $this->newlyCreated = !file_exists($this->file);
6792 if ($this->newlyCreated && !file_put_contents($this->file, "{\n}\n")) {
6793 $io->writeError('<error>'.$this->file.' could not be created.</error>');
6794
6795 return 1;
6796 }
6797
6798
6799 if (!is_readable($this->file) && false === Silencer::call('file_get_contents', $this->file)) {
6800 $io->writeError('<error>'.$this->file.' is not readable.</error>');
6801
6802 return 1;
6803 }
6804
6805 if (filesize($this->file) === 0) {
6806 file_put_contents($this->file, "{\n}\n");
6807 }
6808
6809 $this->json = new JsonFile($this->file);
6810 $this->composerBackup = file_get_contents($this->json->getPath());
6811
6812
6813
6814 if (!is_writable($this->file) && !Silencer::call('file_put_contents', $this->file, $this->composerBackup)) {
6815 $io->writeError('<error>'.$this->file.' is not writable.</error>');
6816
6817 return 1;
6818 }
6819
6820 if ($input->getOption('fixed') === true) {
6821 $config = $this->json->read();
6822
6823 $packageType = empty($config['type']) ? 'library' : $config['type'];
6824
6825
6826
6827
6828 if ($packageType !== 'project') {
6829 $io->writeError('<error>"--fixed" option is allowed for "project" package types only to prevent possible misuses.</error>');
6830
6831 if (empty($config['type'])) {
6832 $io->writeError('<error>If your package is not library, you should explicitly specify "type" parameter in composer.json.</error>');
6833 }
6834
6835 return 1;
6836 }
6837 }
6838
6839 $composer = $this->getComposer(true, $input->getOption('no-plugins'));
6840 $repos = $composer->getRepositoryManager()->getRepositories();
6841
6842 $platformOverrides = $composer->getConfig()->get('platform') ?: array();
6843
6844 $this->repos = new CompositeRepository(array_merge(
6845 array(new PlatformRepository(array(), $platformOverrides)),
6846 $repos
6847 ));
6848
6849 if ($composer->getPackage()->getPreferStable()) {
6850 $preferredStability = 'stable';
6851 } else {
6852 $preferredStability = $composer->getPackage()->getMinimumStability();
6853 }
6854
6855 $phpVersion = $this->repos->findPackage('php', '*')->getPrettyVersion();
6856 try {
6857 $requirements = $this->determineRequirements($input, $output, $input->getArgument('packages'), $phpVersion, $preferredStability, !$input->getOption('no-update'), $input->getOption('fixed'));
6858 } catch (\Exception $e) {
6859 if ($this->newlyCreated) {
6860 throw new \RuntimeException('No composer.json present in the current directory, this may be the cause of the following exception.', 0, $e);
6861 }
6862
6863 throw $e;
6864 }
6865
6866 $requireKey = $input->getOption('dev') ? 'require-dev' : 'require';
6867 $removeKey = $input->getOption('dev') ? 'require' : 'require-dev';
6868 $requirements = $this->formatRequirements($requirements);
6869
6870
6871 $versionParser = new VersionParser();
6872 foreach ($requirements as $package => $constraint) {
6873 if (strtolower($package) === $composer->getPackage()->getName()) {
6874 $io->writeError(sprintf('<error>Root package \'%s\' cannot require itself in its composer.json</error>', $package));
6875
6876 return 1;
6877 }
6878 $versionParser->parseConstraints($constraint);
6879 }
6880
6881 $sortPackages = $input->getOption('sort-packages') || $composer->getConfig()->get('sort-packages');
6882
6883 if (!$this->updateFileCleanly($this->json, $requirements, $requireKey, $removeKey, $sortPackages)) {
6884 $composerDefinition = $this->json->read();
6885 foreach ($requirements as $package => $version) {
6886 $composerDefinition[$requireKey][$package] = $version;
6887 unset($composerDefinition[$removeKey][$package]);
6888 }
6889 $this->json->write($composerDefinition);
6890 }
6891
6892 $io->writeError('<info>'.$this->file.' has been '.($this->newlyCreated ? 'created' : 'updated').'</info>');
6893
6894 if ($input->getOption('no-update')) {
6895 return 0;
6896 }
6897
6898 try {
6899 return $this->doUpdate($input, $output, $io, $requirements);
6900 } catch (\Exception $e) {
6901 $this->revertComposerFile(false);
6902 throw $e;
6903 }
6904 }
6905
6906 private function doUpdate(InputInterface $input, OutputInterface $output, IOInterface $io, array $requirements)
6907 {
6908
6909 $this->resetComposer();
6910 $composer = $this->getComposer(true, $input->getOption('no-plugins'));
6911 $composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress'));
6912
6913 $updateDevMode = !$input->getOption('update-no-dev');
6914 $optimize = $input->getOption('optimize-autoloader') || $composer->getConfig()->get('optimize-autoloader');
6915 $authoritative = $input->getOption('classmap-authoritative') || $composer->getConfig()->get('classmap-authoritative');
6916 $apcu = $input->getOption('apcu-autoloader') || $composer->getConfig()->get('apcu-autoloader');
6917
6918 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'require', $input, $output);
6919 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
6920
6921 $install = Installer::create($io, $composer);
6922
6923 $install
6924 ->setVerbose($input->getOption('verbose'))
6925 ->setPreferSource($input->getOption('prefer-source'))
6926 ->setPreferDist($input->getOption('prefer-dist'))
6927 ->setDevMode($updateDevMode)
6928 ->setRunScripts(!$input->getOption('no-scripts'))
6929 ->setSkipSuggest($input->getOption('no-suggest'))
6930 ->setOptimizeAutoloader($optimize)
6931 ->setClassMapAuthoritative($authoritative)
6932 ->setApcuAutoloader($apcu)
6933 ->setUpdate(true)
6934 ->setUpdateAllowList(array_keys($requirements))
6935 ->setAllowListTransitiveDependencies($input->getOption('update-with-dependencies'))
6936 ->setAllowListAllDependencies($input->getOption('update-with-all-dependencies'))
6937 ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs'))
6938 ->setPreferStable($input->getOption('prefer-stable'))
6939 ->setPreferLowest($input->getOption('prefer-lowest'))
6940 ;
6941
6942 $status = $install->run();
6943 if ($status !== 0) {
6944 $this->revertComposerFile(false);
6945 }
6946
6947 return $status;
6948 }
6949
6950 private function updateFileCleanly($json, array $new, $requireKey, $removeKey, $sortPackages)
6951 {
6952 $contents = file_get_contents($json->getPath());
6953
6954 $manipulator = new JsonManipulator($contents);
6955
6956 foreach ($new as $package => $constraint) {
6957 if (!$manipulator->addLink($requireKey, $package, $constraint, $sortPackages)) {
6958 return false;
6959 }
6960 if (!$manipulator->removeSubNode($removeKey, $package)) {
6961 return false;
6962 }
6963 }
6964
6965 file_put_contents($json->getPath(), $manipulator->getContents());
6966
6967 return true;
6968 }
6969
6970 protected function interact(InputInterface $input, OutputInterface $output)
6971 {
6972 return;
6973 }
6974
6975 public function revertComposerFile($hardExit = true)
6976 {
6977 $io = $this->getIO();
6978
6979 if ($this->newlyCreated) {
6980 $io->writeError("\n".'<error>Installation failed, deleting '.$this->file.'.</error>');
6981 unlink($this->json->getPath());
6982 } else {
6983 $io->writeError("\n".'<error>Installation failed, reverting '.$this->file.' to its original content.</error>');
6984 file_put_contents($this->json->getPath(), $this->composerBackup);
6985 }
6986
6987 if ($hardExit) {
6988 exit(1);
6989 }
6990 }
6991 }
6992 <?php
6993
6994
6995
6996
6997
6998
6999
7000
7001
7002
7003
7004 namespace Composer\Command;
7005
7006 use Composer\Script\Event as ScriptEvent;
7007 use Composer\Script\ScriptEvents;
7008 use Composer\Util\ProcessExecutor;
7009 use Symfony\Component\Console\Input\InputInterface;
7010 use Symfony\Component\Console\Input\InputOption;
7011 use Symfony\Component\Console\Input\InputArgument;
7012 use Symfony\Component\Console\Output\OutputInterface;
7013 use Symfony\Component\Console\Helper\Table;
7014
7015
7016
7017
7018 class RunScriptCommand extends BaseCommand
7019 {
7020
7021
7022
7023 protected $scriptEvents = array(
7024 ScriptEvents::PRE_INSTALL_CMD,
7025 ScriptEvents::POST_INSTALL_CMD,
7026 ScriptEvents::PRE_UPDATE_CMD,
7027 ScriptEvents::POST_UPDATE_CMD,
7028 ScriptEvents::PRE_STATUS_CMD,
7029 ScriptEvents::POST_STATUS_CMD,
7030 ScriptEvents::POST_ROOT_PACKAGE_INSTALL,
7031 ScriptEvents::POST_CREATE_PROJECT_CMD,
7032 ScriptEvents::PRE_ARCHIVE_CMD,
7033 ScriptEvents::POST_ARCHIVE_CMD,
7034 ScriptEvents::PRE_AUTOLOAD_DUMP,
7035 ScriptEvents::POST_AUTOLOAD_DUMP,
7036 );
7037
7038 protected function configure()
7039 {
7040 $this
7041 ->setName('run-script')
7042 ->setAliases(array('run'))
7043 ->setDescription('Runs the scripts defined in composer.json.')
7044 ->setDefinition(array(
7045 new InputArgument('script', InputArgument::OPTIONAL, 'Script name to run.'),
7046 new InputArgument('args', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, ''),
7047 new InputOption('timeout', null, InputOption::VALUE_REQUIRED, 'Sets script timeout in seconds, or 0 for never.'),
7048 new InputOption('dev', null, InputOption::VALUE_NONE, 'Sets the dev mode.'),
7049 new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables the dev mode.'),
7050 new InputOption('list', 'l', InputOption::VALUE_NONE, 'List scripts.'),
7051 ))
7052 ->setHelp(
7053 <<<EOT
7054 The <info>run-script</info> command runs scripts defined in composer.json:
7055
7056 <info>php composer.phar run-script post-update-cmd</info>
7057
7058 Read more at https://getcomposer.org/doc/03-cli.md#run-script
7059 EOT
7060 )
7061 ;
7062 }
7063
7064 protected function execute(InputInterface $input, OutputInterface $output)
7065 {
7066 if ($input->getOption('list')) {
7067 return $this->listScripts($output);
7068 } elseif (!$input->getArgument('script')) {
7069 throw new \RuntimeException('Missing required argument "script"');
7070 }
7071
7072 $script = $input->getArgument('script');
7073 if (!in_array($script, $this->scriptEvents)) {
7074 if (defined('Composer\Script\ScriptEvents::'.str_replace('-', '_', strtoupper($script)))) {
7075 throw new \InvalidArgumentException(sprintf('Script "%s" cannot be run with this command', $script));
7076 }
7077 }
7078
7079 $composer = $this->getComposer();
7080 $devMode = $input->getOption('dev') || !$input->getOption('no-dev');
7081 $event = new ScriptEvent($script, $composer, $this->getIO(), $devMode);
7082 $hasListeners = $composer->getEventDispatcher()->hasEventListeners($event);
7083 if (!$hasListeners) {
7084 throw new \InvalidArgumentException(sprintf('Script "%s" is not defined in this package', $script));
7085 }
7086
7087 $args = $input->getArgument('args');
7088
7089 if (null !== $timeout = $input->getOption('timeout')) {
7090 if (!ctype_digit($timeout)) {
7091 throw new \RuntimeException('Timeout value must be numeric and positive if defined, or 0 for forever');
7092 }
7093
7094 ProcessExecutor::setTimeout((int) $timeout);
7095 }
7096
7097 return $composer->getEventDispatcher()->dispatchScript($script, $devMode, $args);
7098 }
7099
7100 protected function listScripts(OutputInterface $output)
7101 {
7102 $scripts = $this->getComposer()->getPackage()->getScripts();
7103
7104 if (!count($scripts)) {
7105 return 0;
7106 }
7107
7108 $io = $this->getIO();
7109 $io->writeError('<info>scripts:</info>');
7110 $table = array();
7111 foreach ($scripts as $name => $script) {
7112 $description = '';
7113 try {
7114 $cmd = $this->getApplication()->find($name);
7115 if ($cmd instanceof ScriptAliasCommand) {
7116 $description = $cmd->getDescription();
7117 }
7118 } catch (\Symfony\Component\Console\Exception\CommandNotFoundException $e) {
7119
7120 }
7121 $table[] = array('  '.$name, $description);
7122 }
7123
7124 $renderer = new Table($output);
7125 $renderer->setStyle('compact');
7126 $rendererStyle = $renderer->getStyle();
7127 if (method_exists($rendererStyle, 'setVerticalBorderChars')) {
7128 $rendererStyle->setVerticalBorderChars('');
7129 } else {
7130 $rendererStyle->setVerticalBorderChar('');
7131 }
7132 $rendererStyle->setCellRowContentFormat('%s  ');
7133 $renderer->setRows($table)->render();
7134
7135 return 0;
7136 }
7137 }
7138 <?php
7139
7140
7141
7142
7143
7144
7145
7146
7147
7148
7149
7150 namespace Composer\Command;
7151
7152 use Symfony\Component\Console\Input\InputInterface;
7153 use Symfony\Component\Console\Input\InputOption;
7154 use Symfony\Component\Console\Input\InputArgument;
7155 use Symfony\Component\Console\Output\OutputInterface;
7156
7157
7158
7159
7160 class ScriptAliasCommand extends BaseCommand
7161 {
7162 private $script;
7163 private $description;
7164
7165 public function __construct($script, $description)
7166 {
7167 $this->script = $script;
7168 $this->description = empty($description) ? 'Runs the '.$script.' script as defined in composer.json.' : $description;
7169
7170 parent::__construct();
7171 }
7172
7173 protected function configure()
7174 {
7175 $this
7176 ->setName($this->script)
7177 ->setDescription($this->description)
7178 ->setDefinition(array(
7179 new InputOption('dev', null, InputOption::VALUE_NONE, 'Sets the dev mode.'),
7180 new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables the dev mode.'),
7181 new InputArgument('args', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, ''),
7182 ))
7183 ->setHelp(
7184 <<<EOT
7185 The <info>run-script</info> command runs scripts defined in composer.json:
7186
7187 <info>php composer.phar run-script post-update-cmd</info>
7188
7189 Read more at https://getcomposer.org/doc/03-cli.md#run-script
7190 EOT
7191 )
7192 ;
7193 }
7194
7195 protected function execute(InputInterface $input, OutputInterface $output)
7196 {
7197 $composer = $this->getComposer();
7198
7199 $args = $input->getArguments();
7200
7201 return $composer->getEventDispatcher()->dispatchScript($this->script, $input->getOption('dev') || !$input->getOption('no-dev'), $args['args']);
7202 }
7203 }
7204 <?php
7205
7206
7207
7208
7209
7210
7211
7212
7213
7214
7215
7216 namespace Composer\Command;
7217
7218 use Composer\Factory;
7219 use Symfony\Component\Console\Input\InputInterface;
7220 use Symfony\Component\Console\Input\InputArgument;
7221 use Symfony\Component\Console\Input\InputOption;
7222 use Symfony\Component\Console\Output\OutputInterface;
7223 use Composer\Repository\CompositeRepository;
7224 use Composer\Repository\PlatformRepository;
7225 use Composer\Repository\RepositoryInterface;
7226 use Composer\Plugin\CommandEvent;
7227 use Composer\Plugin\PluginEvents;
7228
7229
7230
7231
7232 class SearchCommand extends BaseCommand
7233 {
7234 protected $matches;
7235 protected $lowMatches = array();
7236 protected $tokens;
7237 protected $output;
7238 protected $onlyName;
7239
7240 protected function configure()
7241 {
7242 $this
7243 ->setName('search')
7244 ->setDescription('Searches for packages.')
7245 ->setDefinition(array(
7246 new InputOption('only-name', 'N', InputOption::VALUE_NONE, 'Search only in name'),
7247 new InputOption('type', 't', InputOption::VALUE_REQUIRED, 'Search for a specific package type'),
7248 new InputArgument('tokens', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'tokens to search for'),
7249 ))
7250 ->setHelp(
7251 <<<EOT
7252 The search command searches for packages by its name
7253 <info>php composer.phar search symfony composer</info>
7254
7255 Read more at https://getcomposer.org/doc/03-cli.md#search
7256 EOT
7257 )
7258 ;
7259 }
7260
7261 protected function execute(InputInterface $input, OutputInterface $output)
7262 {
7263
7264 $platformRepo = new PlatformRepository;
7265 $io = $this->getIO();
7266 if (!($composer = $this->getComposer(false))) {
7267 $composer = Factory::create($this->getIO(), array(), $input->hasParameterOption('--no-plugins'));
7268 }
7269 $localRepo = $composer->getRepositoryManager()->getLocalRepository();
7270 $installedRepo = new CompositeRepository(array($localRepo, $platformRepo));
7271 $repos = new CompositeRepository(array_merge(array($installedRepo), $composer->getRepositoryManager()->getRepositories()));
7272
7273 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'search', $input, $output);
7274 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
7275
7276 $onlyName = $input->getOption('only-name');
7277 $type = $input->getOption('type') ?: null;
7278
7279 $flags = $onlyName ? RepositoryInterface::SEARCH_NAME : RepositoryInterface::SEARCH_FULLTEXT;
7280 $results = $repos->search(implode(' ', $input->getArgument('tokens')), $flags, $type);
7281
7282 foreach ($results as $result) {
7283 $io->write($result['name'] . (isset($result['description']) ? ' '. $result['description'] : ''));
7284 }
7285
7286 return 0;
7287 }
7288 }
7289 <?php
7290
7291
7292
7293
7294
7295
7296
7297
7298
7299
7300
7301 namespace Composer\Command;
7302
7303 use Composer\Composer;
7304 use Composer\Factory;
7305 use Composer\Config;
7306 use Composer\Util\Filesystem;
7307 use Composer\Util\Platform;
7308 use Composer\SelfUpdate\Keys;
7309 use Composer\SelfUpdate\Versions;
7310 use Composer\IO\IOInterface;
7311 use Composer\Downloader\FilesystemException;
7312 use Symfony\Component\Console\Input\InputInterface;
7313 use Symfony\Component\Console\Input\InputOption;
7314 use Symfony\Component\Console\Input\InputArgument;
7315 use Symfony\Component\Console\Output\OutputInterface;
7316 use Symfony\Component\Finder\Finder;
7317
7318
7319
7320
7321
7322
7323 class SelfUpdateCommand extends BaseCommand
7324 {
7325 const HOMEPAGE = 'getcomposer.org';
7326 const OLD_INSTALL_EXT = '-old.phar';
7327
7328 protected function configure()
7329 {
7330 $this
7331 ->setName('self-update')
7332 ->setAliases(array('selfupdate'))
7333 ->setDescription('Updates composer.phar to the latest version.')
7334 ->setDefinition(array(
7335 new InputOption('rollback', 'r', InputOption::VALUE_NONE, 'Revert to an older installation of composer'),
7336 new InputOption('clean-backups', null, InputOption::VALUE_NONE, 'Delete old backups during an update. This makes the current version of composer the only backup available after the update'),
7337 new InputArgument('version', InputArgument::OPTIONAL, 'The version to update to'),
7338 new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
7339 new InputOption('update-keys', null, InputOption::VALUE_NONE, 'Prompt user for a key update'),
7340 new InputOption('stable', null, InputOption::VALUE_NONE, 'Force an update to the stable channel'),
7341 new InputOption('preview', null, InputOption::VALUE_NONE, 'Force an update to the preview channel'),
7342 new InputOption('snapshot', null, InputOption::VALUE_NONE, 'Force an update to the snapshot channel'),
7343 new InputOption('1', null, InputOption::VALUE_NONE, 'Force an update to the stable channel, but only use 1.x versions'),
7344 new InputOption('2', null, InputOption::VALUE_NONE, 'Force an update to the stable channel, but only use 2.x versions'),
7345 new InputOption('set-channel-only', null, InputOption::VALUE_NONE, 'Only store the channel as the default one and then exit'),
7346 ))
7347 ->setHelp(
7348 <<<EOT
7349 The <info>self-update</info> command checks getcomposer.org for newer
7350 versions of composer and if found, installs the latest.
7351
7352 <info>php composer.phar self-update</info>
7353
7354 Read more at https://getcomposer.org/doc/03-cli.md#self-update-selfupdate-
7355 EOT
7356 )
7357 ;
7358 }
7359
7360 protected function execute(InputInterface $input, OutputInterface $output)
7361 {
7362 $config = Factory::createConfig();
7363
7364 if ($config->get('disable-tls') === true) {
7365 $baseUrl = 'http://' . self::HOMEPAGE;
7366 } else {
7367 $baseUrl = 'https://' . self::HOMEPAGE;
7368 }
7369
7370 $io = $this->getIO();
7371 $remoteFilesystem = Factory::createRemoteFilesystem($io, $config);
7372
7373 $versionsUtil = new Versions($config, $remoteFilesystem);
7374
7375
7376 $requestedChannel = null;
7377 foreach (Versions::$channels as $channel) {
7378 if ($input->getOption($channel)) {
7379 $requestedChannel = $channel;
7380 $versionsUtil->setChannel($channel);
7381 break;
7382 }
7383 }
7384
7385 if ($input->getOption('set-channel-only')) {
7386 return 0;
7387 }
7388
7389 $cacheDir = $config->get('cache-dir');
7390 $rollbackDir = $config->get('data-dir');
7391 $home = $config->get('home');
7392 $localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0];
7393
7394 if ($input->getOption('update-keys')) {
7395 return $this->fetchKeys($io, $config);
7396 }
7397
7398
7399 if (!file_exists($localFilename)) {
7400 throw new FilesystemException('Composer update failed: the "'.$localFilename.'" is not accessible');
7401 }
7402
7403
7404 $tmpDir = is_writable(dirname($localFilename)) ? dirname($localFilename) : $cacheDir;
7405
7406
7407 if (!is_writable($tmpDir)) {
7408 throw new FilesystemException('Composer update failed: the "'.$tmpDir.'" directory used to download the temp file could not be written');
7409 }
7410
7411
7412 if (function_exists('posix_getpwuid') && function_exists('posix_geteuid')) {
7413 $composeUser = posix_getpwuid(posix_geteuid());
7414 $homeOwner = posix_getpwuid(fileowner($home));
7415 if (isset($composeUser['name']) && isset($homeOwner['name']) && $composeUser['name'] !== $homeOwner['name']) {
7416 $io->writeError('<warning>You are running composer as "'.$composeUser['name'].'", while "'.$home.'" is owned by "'.$homeOwner['name'].'"</warning>');
7417 }
7418 }
7419
7420 if ($input->getOption('rollback')) {
7421 return $this->rollback($output, $rollbackDir, $localFilename);
7422 }
7423
7424 $latest = $versionsUtil->getLatest();
7425 $latestStable = $versionsUtil->getLatest('stable');
7426 try {
7427 $latestPreview = $versionsUtil->getLatest('preview');
7428 } catch (\UnexpectedValueException $e) {
7429 $latestPreview = $latestStable;
7430 }
7431 $latestVersion = $latest['version'];
7432 $updateVersion = $input->getArgument('version') ?: $latestVersion;
7433 $currentMajorVersion = preg_replace('{^(\d+).*}', '$1', Composer::getVersion());
7434 $updateMajorVersion = preg_replace('{^(\d+).*}', '$1', $updateVersion);
7435 $previewMajorVersion = preg_replace('{^(\d+).*}', '$1', $latestPreview['version']);
7436
7437 if ($versionsUtil->getChannel() === 'stable' && !$input->getArgument('version')) {
7438
7439
7440 if ($currentMajorVersion < $updateMajorVersion) {
7441 $skippedVersion = $updateVersion;
7442
7443 $versionsUtil->setChannel($currentMajorVersion);
7444
7445 $latest = $versionsUtil->getLatest();
7446 $latestStable = $versionsUtil->getLatest('stable');
7447 $latestVersion = $latest['version'];
7448 $updateVersion = $latestVersion;
7449
7450 $io->writeError('<warning>A new stable major version of Composer is available ('.$skippedVersion.'), run "composer self-update --'.$updateMajorVersion.'" to update to it. See also https://getcomposer.org/'.$updateMajorVersion.'</warning>');
7451 } elseif ($currentMajorVersion < $previewMajorVersion) {
7452
7453 $io->writeError('<warning>A preview release of the next major version of Composer is available ('.$latestPreview['version'].'), run "composer self-update --preview" to give it a try. See also https://github.com/composer/composer/releases for changelogs.</warning>');
7454 }
7455 }
7456
7457 if ($requestedChannel && is_numeric($requestedChannel) && substr($latestStable['version'], 0, 1) !== $requestedChannel) {
7458 $io->writeError('<warning>Warning: You forced the install of '.$latestVersion.' via --'.$requestedChannel.', but '.$latestStable['version'].' is the latest stable version. Updating to it via composer self-update --stable is recommended.</warning>');
7459 }
7460
7461 if (preg_match('{^[0-9a-f]{40}$}', $updateVersion) && $updateVersion !== $latestVersion) {
7462 $io->writeError('<error>You can not update to a specific SHA-1 as those phars are not available for download</error>');
7463
7464 return 1;
7465 }
7466
7467 $channelString = $versionsUtil->getChannel();
7468 if (is_numeric($channelString)) {
7469 $channelString .= '.x';
7470 }
7471
7472 if (Composer::VERSION === $updateVersion) {
7473 $io->writeError(
7474 sprintf(
7475 '<info>You are already using composer version %s (%s channel).</info>',
7476 $updateVersion,
7477 $channelString
7478 )
7479 );
7480
7481
7482 if ($input->getOption('clean-backups')) {
7483 $this->cleanBackups($rollbackDir, $this->getLastBackupVersion($rollbackDir));
7484 }
7485
7486 return 0;
7487 }
7488
7489 $tempFilename = $tmpDir . '/' . basename($localFilename, '.phar').'-temp.phar';
7490 $backupFile = sprintf(
7491 '%s/%s-%s%s',
7492 $rollbackDir,
7493 strtr(Composer::RELEASE_DATE, ' :', '_-'),
7494 preg_replace('{^([0-9a-f]{7})[0-9a-f]{33}$}', '$1', Composer::VERSION),
7495 self::OLD_INSTALL_EXT
7496 );
7497
7498 $updatingToTag = !preg_match('{^[0-9a-f]{40}$}', $updateVersion);
7499
7500 $io->write(sprintf("Updating to version <info>%s</info> (%s channel).", $updateVersion, $channelString));
7501 $remoteFilename = $baseUrl . ($updatingToTag ? "/download/{$updateVersion}/composer.phar" : '/composer.phar');
7502 $signature = $remoteFilesystem->getContents(self::HOMEPAGE, $remoteFilename.'.sig', false);
7503 $io->writeError('   ', false);
7504 $remoteFilesystem->copy(self::HOMEPAGE, $remoteFilename, $tempFilename, !$input->getOption('no-progress'));
7505 $io->writeError('');
7506
7507 if (!file_exists($tempFilename) || !$signature) {
7508 $io->writeError('<error>The download of the new composer version failed for an unexpected reason</error>');
7509
7510 return 1;
7511 }
7512
7513
7514 if (!extension_loaded('openssl') && $config->get('disable-tls')) {
7515 $io->writeError('<warning>Skipping phar signature verification as you have disabled OpenSSL via config.disable-tls</warning>');
7516 } else {
7517 if (!extension_loaded('openssl')) {
7518 throw new \RuntimeException('The openssl extension is required for phar signatures to be verified but it is not available. '
7519 . 'If you can not enable the openssl extension, you can disable this error, at your own risk, by setting the \'disable-tls\' option to true.');
7520 }
7521
7522 $sigFile = 'file://'.$home.'/' . ($updatingToTag ? 'keys.tags.pub' : 'keys.dev.pub');
7523 if (!file_exists($sigFile)) {
7524 file_put_contents(
7525 $home.'/keys.dev.pub',
7526 <<<DEVPUBKEY
7527 -----BEGIN PUBLIC KEY-----
7528 MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnBDHjZS6e0ZMoK3xTD7f
7529 FNCzlXjX/Aie2dit8QXA03pSrOTbaMnxON3hUL47Lz3g1SC6YJEMVHr0zYq4elWi
7530 i3ecFEgzLcj+pZM5X6qWu2Ozz4vWx3JYo1/a/HYdOuW9e3lwS8VtS0AVJA+U8X0A
7531 hZnBmGpltHhO8hPKHgkJtkTUxCheTcbqn4wGHl8Z2SediDcPTLwqezWKUfrYzu1f
7532 o/j3WFwFs6GtK4wdYtiXr+yspBZHO3y1udf8eFFGcb2V3EaLOrtfur6XQVizjOuk
7533 8lw5zzse1Qp/klHqbDRsjSzJ6iL6F4aynBc6Euqt/8ccNAIz0rLjLhOraeyj4eNn
7534 8iokwMKiXpcrQLTKH+RH1JCuOVxQ436bJwbSsp1VwiqftPQieN+tzqy+EiHJJmGf
7535 TBAbWcncicCk9q2md+AmhNbvHO4PWbbz9TzC7HJb460jyWeuMEvw3gNIpEo2jYa9
7536 pMV6cVqnSa+wOc0D7pC9a6bne0bvLcm3S+w6I5iDB3lZsb3A9UtRiSP7aGSo7D72
7537 8tC8+cIgZcI7k9vjvOqH+d7sdOU2yPCnRY6wFh62/g8bDnUpr56nZN1G89GwM4d4
7538 r/TU7BQQIzsZgAiqOGXvVklIgAMiV0iucgf3rNBLjjeNEwNSTTG9F0CtQ+7JLwaE
7539 wSEuAuRm+pRqi8BRnQ/GKUcCAwEAAQ==
7540 -----END PUBLIC KEY-----
7541 DEVPUBKEY
7542 );
7543
7544 file_put_contents(
7545 $home.'/keys.tags.pub',
7546 <<<TAGSPUBKEY
7547 -----BEGIN PUBLIC KEY-----
7548 MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0Vi/2K6apCVj76nCnCl2
7549 MQUPdK+A9eqkYBacXo2wQBYmyVlXm2/n/ZsX6pCLYPQTHyr5jXbkQzBw8SKqPdlh
7550 vA7NpbMeNCz7wP/AobvUXM8xQuXKbMDTY2uZ4O7sM+PfGbptKPBGLe8Z8d2sUnTO
7551 bXtX6Lrj13wkRto7st/w/Yp33RHe9SlqkiiS4MsH1jBkcIkEHsRaveZzedUaxY0M
7552 mba0uPhGUInpPzEHwrYqBBEtWvP97t2vtfx8I5qv28kh0Y6t+jnjL1Urid2iuQZf
7553 noCMFIOu4vksK5HxJxxrN0GOmGmwVQjOOtxkwikNiotZGPR4KsVj8NnBrLX7oGuM
7554 nQvGciiu+KoC2r3HDBrpDeBVdOWxDzT5R4iI0KoLzFh2pKqwbY+obNPS2bj+2dgJ
7555 rV3V5Jjry42QOCBN3c88wU1PKftOLj2ECpewY6vnE478IipiEu7EAdK8Zwj2LmTr
7556 RKQUSa9k7ggBkYZWAeO/2Ag0ey3g2bg7eqk+sHEq5ynIXd5lhv6tC5PBdHlWipDK
7557 tl2IxiEnejnOmAzGVivE1YGduYBjN+mjxDVy8KGBrjnz1JPgAvgdwJ2dYw4Rsc/e
7558 TzCFWGk/HM6a4f0IzBWbJ5ot0PIi4amk07IotBXDWwqDiQTwyuGCym5EqWQ2BD95
7559 RGv89BPD+2DLnJysngsvVaUCAwEAAQ==
7560 -----END PUBLIC KEY-----
7561 TAGSPUBKEY
7562 );
7563 }
7564
7565 $pubkeyid = openssl_pkey_get_public($sigFile);
7566 $algo = defined('OPENSSL_ALGO_SHA384') ? OPENSSL_ALGO_SHA384 : 'SHA384';
7567 if (!in_array('sha384', array_map('strtolower', openssl_get_md_methods()))) {
7568 throw new \RuntimeException('SHA384 is not supported by your openssl extension, could not verify the phar file integrity');
7569 }
7570 $signature = json_decode($signature, true);
7571 $signature = base64_decode($signature['sha384']);
7572 $verified = 1 === openssl_verify(file_get_contents($tempFilename), $signature, $pubkeyid, $algo);
7573
7574
7575 if (PHP_VERSION_ID < 80000) {
7576 openssl_free_key($pubkeyid);
7577 }
7578
7579 if (!$verified) {
7580 throw new \RuntimeException('The phar signature did not match the file you downloaded, this means your public keys are outdated or that the phar file is corrupt/has been modified');
7581 }
7582 }
7583
7584
7585 if ($input->getOption('clean-backups')) {
7586 $this->cleanBackups($rollbackDir);
7587 }
7588
7589 if (!$this->setLocalPhar($localFilename, $tempFilename, $backupFile)) {
7590 @unlink($tempFilename);
7591
7592 return 1;
7593 }
7594
7595 if (file_exists($backupFile)) {
7596 $io->writeError(sprintf(
7597 'Use <info>composer self-update --rollback</info> to return to version <comment>%s</comment>',
7598 Composer::VERSION
7599 ));
7600 } else {
7601 $io->writeError('<warning>A backup of the current version could not be written to '.$backupFile.', no rollback possible</warning>');
7602 }
7603
7604 return 0;
7605 }
7606
7607 protected function fetchKeys(IOInterface $io, Config $config)
7608 {
7609 if (!$io->isInteractive()) {
7610 throw new \RuntimeException('Public keys can not be fetched in non-interactive mode, please run Composer interactively');
7611 }
7612
7613 $io->write('Open <info>https://composer.github.io/pubkeys.html</info> to find the latest keys');
7614
7615 $validator = function ($value) {
7616 if (!preg_match('{^-----BEGIN PUBLIC KEY-----$}', trim($value))) {
7617 throw new \UnexpectedValueException('Invalid input');
7618 }
7619
7620 return trim($value)."\n";
7621 };
7622
7623 $devKey = '';
7624 while (!preg_match('{(-----BEGIN PUBLIC KEY-----.+?-----END PUBLIC KEY-----)}s', $devKey, $match)) {
7625 $devKey = $io->askAndValidate('Enter Dev / Snapshot Public Key (including lines with -----): ', $validator);
7626 while ($line = $io->ask('')) {
7627 $devKey .= trim($line)."\n";
7628 if (trim($line) === '-----END PUBLIC KEY-----') {
7629 break;
7630 }
7631 }
7632 }
7633 file_put_contents($keyPath = $config->get('home').'/keys.dev.pub', $match[0]);
7634 $io->write('Stored key with fingerprint: ' . Keys::fingerprint($keyPath));
7635
7636 $tagsKey = '';
7637 while (!preg_match('{(-----BEGIN PUBLIC KEY-----.+?-----END PUBLIC KEY-----)}s', $tagsKey, $match)) {
7638 $tagsKey = $io->askAndValidate('Enter Tags Public Key (including lines with -----): ', $validator);
7639 while ($line = $io->ask('')) {
7640 $tagsKey .= trim($line)."\n";
7641 if (trim($line) === '-----END PUBLIC KEY-----') {
7642 break;
7643 }
7644 }
7645 }
7646 file_put_contents($keyPath = $config->get('home').'/keys.tags.pub', $match[0]);
7647 $io->write('Stored key with fingerprint: ' . Keys::fingerprint($keyPath));
7648
7649 $io->write('Public keys stored in '.$config->get('home'));
7650 }
7651
7652 protected function rollback(OutputInterface $output, $rollbackDir, $localFilename)
7653 {
7654 $rollbackVersion = $this->getLastBackupVersion($rollbackDir);
7655 if (!$rollbackVersion) {
7656 throw new \UnexpectedValueException('Composer rollback failed: no installation to roll back to in "'.$rollbackDir.'"');
7657 }
7658
7659 $oldFile = $rollbackDir . '/' . $rollbackVersion . self::OLD_INSTALL_EXT;
7660
7661 if (!is_file($oldFile)) {
7662 throw new FilesystemException('Composer rollback failed: "'.$oldFile.'" could not be found');
7663 }
7664 if (!is_readable($oldFile)) {
7665 throw new FilesystemException('Composer rollback failed: "'.$oldFile.'" could not be read');
7666 }
7667
7668 $io = $this->getIO();
7669 $io->writeError(sprintf("Rolling back to version <info>%s</info>.", $rollbackVersion));
7670 if (!$this->setLocalPhar($localFilename, $oldFile)) {
7671 return 1;
7672 }
7673
7674 return 0;
7675 }
7676
7677
7678
7679
7680
7681
7682
7683
7684
7685
7686 protected function setLocalPhar($localFilename, $newFilename, $backupTarget = null)
7687 {
7688 $io = $this->getIO();
7689 @chmod($newFilename, fileperms($localFilename));
7690
7691
7692 if (!$this->validatePhar($newFilename, $error)) {
7693 $io->writeError('<error>The '.($backupTarget ? 'update' : 'backup').' file is corrupted ('.$error.')</error>');
7694
7695 if ($backupTarget) {
7696 $io->writeError('<error>Please re-run the self-update command to try again.</error>');
7697 }
7698
7699 return false;
7700 }
7701
7702
7703 if ($backupTarget) {
7704 @copy($localFilename, $backupTarget);
7705 }
7706
7707 try {
7708 rename($newFilename, $localFilename);
7709
7710 return true;
7711 } catch (\Exception $e) {
7712
7713 if (!is_writable(dirname($localFilename))
7714 && $io->isInteractive()
7715 && $this->isWindowsNonAdminUser()) {
7716 return $this->tryAsWindowsAdmin($localFilename, $newFilename);
7717 }
7718
7719 $action = 'Composer '.($backupTarget ? 'update' : 'rollback');
7720 throw new FilesystemException($action.' failed: "'.$localFilename.'" could not be written.'.PHP_EOL.$e->getMessage());
7721 }
7722 }
7723
7724 protected function cleanBackups($rollbackDir, $except = null)
7725 {
7726 $finder = $this->getOldInstallationFinder($rollbackDir);
7727 $io = $this->getIO();
7728 $fs = new Filesystem;
7729
7730 foreach ($finder as $file) {
7731 if ($except && $file->getBasename(self::OLD_INSTALL_EXT) === $except) {
7732 continue;
7733 }
7734 $file = (string) $file;
7735 $io->writeError('<info>Removing: '.$file.'</info>');
7736 $fs->remove($file);
7737 }
7738 }
7739
7740 protected function getLastBackupVersion($rollbackDir)
7741 {
7742 $finder = $this->getOldInstallationFinder($rollbackDir);
7743 $finder->sortByName();
7744 $files = iterator_to_array($finder);
7745
7746 if (count($files)) {
7747 return basename(end($files), self::OLD_INSTALL_EXT);
7748 }
7749
7750 return false;
7751 }
7752
7753 protected function getOldInstallationFinder($rollbackDir)
7754 {
7755 $finder = Finder::create()
7756 ->depth(0)
7757 ->files()
7758 ->name('*' . self::OLD_INSTALL_EXT)
7759 ->in($rollbackDir);
7760
7761 return $finder;
7762 }
7763
7764
7765
7766
7767
7768
7769
7770
7771
7772
7773
7774
7775
7776 protected function validatePhar($pharFile, &$error)
7777 {
7778 if (ini_get('phar.readonly')) {
7779 return true;
7780 }
7781
7782 try {
7783
7784 $phar = new \Phar($pharFile);
7785
7786 unset($phar);
7787 $result = true;
7788 } catch (\Exception $e) {
7789 if (!$e instanceof \UnexpectedValueException && !$e instanceof \PharException) {
7790 throw $e;
7791 }
7792 $error = $e->getMessage();
7793 $result = false;
7794 }
7795
7796 return $result;
7797 }
7798
7799
7800
7801
7802
7803
7804 protected function isWindowsNonAdminUser()
7805 {
7806 if (!Platform::isWindows()) {
7807 return false;
7808 }
7809
7810
7811 exec('fltmc.exe filters', $output, $exitCode);
7812
7813 return $exitCode !== 0;
7814 }
7815
7816
7817
7818
7819
7820
7821
7822
7823
7824
7825 protected function tryAsWindowsAdmin($localFilename, $newFilename)
7826 {
7827 $io = $this->getIO();
7828
7829 $io->writeError('<error>Unable to write "'.$localFilename.'". Access is denied.</error>');
7830 $helpMessage = 'Please run the self-update command as an Administrator.';
7831 $question = 'Complete this operation with Administrator privileges [<comment>Y,n</comment>]? ';
7832
7833 if (!$io->askConfirmation($question, false)) {
7834 $io->writeError('<warning>Operation cancelled. '.$helpMessage.'</warning>');
7835
7836 return false;
7837 }
7838
7839 $tmpFile = tempnam(sys_get_temp_dir(), '');
7840 $script = $tmpFile.'.vbs';
7841 rename($tmpFile, $script);
7842
7843 $checksum = hash_file('sha256', $newFilename);
7844
7845
7846 $source = str_replace('/', '\\', $newFilename);
7847 $destination = str_replace('/', '\\', $localFilename);
7848
7849 $vbs = <<<EOT
7850 Set UAC = CreateObject("Shell.Application")
7851 UAC.ShellExecute "cmd.exe", "/c move /y ""$source"" ""$destination""", "", "runas", 0
7852 Wscript.Sleep(300)
7853 EOT;
7854
7855 file_put_contents($script, $vbs);
7856 exec('"'.$script.'"');
7857 @unlink($script);
7858
7859
7860 if ($result = (hash_file('sha256', $localFilename) === $checksum)) {
7861 $io->writeError('<info>Operation succeeded.</info>');
7862 } else {
7863 $io->writeError('<error>Operation failed (file not written). '.$helpMessage.'</error>');
7864 };
7865
7866 return $result;
7867 }
7868 }
7869 <?php
7870
7871
7872
7873
7874
7875
7876
7877
7878
7879
7880
7881 namespace Composer\Command;
7882
7883 use Composer\Composer;
7884 use Composer\DependencyResolver\DefaultPolicy;
7885 use Composer\DependencyResolver\Pool;
7886 use Composer\Json\JsonFile;
7887 use Composer\Package\BasePackage;
7888 use Composer\Package\CompletePackageInterface;
7889 use Composer\Package\PackageInterface;
7890 use Composer\Package\Version\VersionParser;
7891 use Composer\Package\Version\VersionSelector;
7892 use Composer\Plugin\CommandEvent;
7893 use Composer\Plugin\PluginEvents;
7894 use Composer\Repository\ArrayRepository;
7895 use Composer\Repository\ComposerRepository;
7896 use Composer\Repository\CompositeRepository;
7897 use Composer\Repository\PlatformRepository;
7898 use Composer\Repository\RepositoryFactory;
7899 use Composer\Repository\RepositoryInterface;
7900 use Composer\Semver\Constraint\ConstraintInterface;
7901 use Composer\Semver\Semver;
7902 use Composer\Spdx\SpdxLicenses;
7903 use Composer\Util\Platform;
7904 use Symfony\Component\Console\Formatter\OutputFormatterStyle;
7905 use Symfony\Component\Console\Input\InputArgument;
7906 use Symfony\Component\Console\Input\InputInterface;
7907 use Symfony\Component\Console\Input\InputOption;
7908 use Symfony\Component\Console\Output\OutputInterface;
7909 use Symfony\Component\Console\Terminal;
7910
7911
7912
7913
7914
7915
7916
7917 class ShowCommand extends BaseCommand
7918 {
7919
7920 protected $versionParser;
7921 protected $colors;
7922
7923
7924 private $pool;
7925
7926 protected function configure()
7927 {
7928 $this
7929 ->setName('show')
7930 ->setAliases(array('info'))
7931 ->setDescription('Shows information about packages.')
7932 ->setDefinition(array(
7933 new InputArgument('package', InputArgument::OPTIONAL, 'Package to inspect. Or a name including a wildcard (*) to filter lists of packages instead.'),
7934 new InputArgument('version', InputArgument::OPTIONAL, 'Version or version constraint to inspect'),
7935 new InputOption('all', null, InputOption::VALUE_NONE, 'List all packages'),
7936 new InputOption('installed', 'i', InputOption::VALUE_NONE, 'List installed packages only (enabled by default, only present for BC).'),
7937 new InputOption('platform', 'p', InputOption::VALUE_NONE, 'List platform packages only'),
7938 new InputOption('available', 'a', InputOption::VALUE_NONE, 'List available packages only'),
7939 new InputOption('self', 's', InputOption::VALUE_NONE, 'Show the root package information'),
7940 new InputOption('name-only', 'N', InputOption::VALUE_NONE, 'List package names only'),
7941 new InputOption('path', 'P', InputOption::VALUE_NONE, 'Show package paths'),
7942 new InputOption('tree', 't', InputOption::VALUE_NONE, 'List the dependencies as a tree'),
7943 new InputOption('latest', 'l', InputOption::VALUE_NONE, 'Show the latest version'),
7944 new InputOption('outdated', 'o', InputOption::VALUE_NONE, 'Show the latest version but only for packages that are outdated'),
7945 new InputOption('ignore', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore specified package(s). Use it with the --outdated option if you don\'t want to be informed about new versions of some packages.'),
7946 new InputOption('minor-only', 'm', InputOption::VALUE_NONE, 'Show only packages that have minor SemVer-compatible updates. Use with the --outdated option.'),
7947 new InputOption('direct', 'D', InputOption::VALUE_NONE, 'Shows only packages that are directly required by the root package'),
7948 new InputOption('strict', null, InputOption::VALUE_NONE, 'Return a non-zero exit code when there are outdated packages'),
7949 new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text'),
7950 ))
7951 ->setHelp(
7952 <<<EOT
7953 The show command displays detailed information about a package, or
7954 lists all packages available.
7955
7956 Read more at https://getcomposer.org/doc/03-cli.md#show
7957 EOT
7958 )
7959 ;
7960 }
7961
7962 protected function execute(InputInterface $input, OutputInterface $output)
7963 {
7964 $this->versionParser = new VersionParser;
7965 if ($input->getOption('tree')) {
7966 $this->initStyles($output);
7967 }
7968
7969 $composer = $this->getComposer(false);
7970 $io = $this->getIO();
7971
7972 if ($input->getOption('installed')) {
7973 $io->writeError('<warning>You are using the deprecated option "installed". Only installed packages are shown by default now. The --all option can be used to show all packages.</warning>');
7974 }
7975
7976 if ($input->getOption('outdated')) {
7977 $input->setOption('latest', true);
7978 } elseif ($input->getOption('ignore')) {
7979 $io->writeError('<warning>You are using the option "ignore" for action other than "outdated", it will be ignored.</warning>');
7980 }
7981
7982 if ($input->getOption('direct') && ($input->getOption('all') || $input->getOption('available') || $input->getOption('platform'))) {
7983 $io->writeError('The --direct (-D) option is not usable in combination with --all, --platform (-p) or --available (-a)');
7984
7985 return 1;
7986 }
7987
7988 if ($input->getOption('tree') && ($input->getOption('all') || $input->getOption('available'))) {
7989 $io->writeError('The --tree (-t) option is not usable in combination with --all or --available (-a)');
7990
7991 return 1;
7992 }
7993
7994 if ($input->getOption('tree') && $input->getOption('latest')) {
7995 $io->writeError('The --tree (-t) option is not usable in combination with --latest (-l)');
7996
7997 return 1;
7998 }
7999
8000 if ($input->getOption('tree') && $input->getOption('path')) {
8001 $io->writeError('The --tree (-t) option is not usable in combination with --path (-P)');
8002
8003 return 1;
8004 }
8005
8006 $format = $input->getOption('format');
8007 if (!in_array($format, array('text', 'json'))) {
8008 $io->writeError(sprintf('Unsupported format "%s". See help for supported formats.', $format));
8009
8010 return 1;
8011 }
8012
8013
8014 $platformOverrides = array();
8015 if ($composer) {
8016 $platformOverrides = $composer->getConfig()->get('platform') ?: array();
8017 }
8018 $platformRepo = new PlatformRepository(array(), $platformOverrides);
8019 $phpVersion = $platformRepo->findPackage('php', '*')->getVersion();
8020
8021 if ($input->getOption('self')) {
8022 $package = $this->getComposer()->getPackage();
8023 if ($input->getOption('name-only')) {
8024 $io->write($package->getName());
8025 return 0;
8026 }
8027 $repos = $installedRepo = new ArrayRepository(array($package));
8028 } elseif ($input->getOption('platform')) {
8029 $repos = $installedRepo = $platformRepo;
8030 } elseif ($input->getOption('available')) {
8031 $installedRepo = $platformRepo;
8032 if ($composer) {
8033 $repos = new CompositeRepository($composer->getRepositoryManager()->getRepositories());
8034 } else {
8035 $defaultRepos = RepositoryFactory::defaultRepos($io);
8036 $repos = new CompositeRepository($defaultRepos);
8037 $io->writeError('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
8038 }
8039 } elseif ($input->getOption('all') && $composer) {
8040 $localRepo = $composer->getRepositoryManager()->getLocalRepository();
8041 $installedRepo = new CompositeRepository(array($localRepo, $platformRepo));
8042 $repos = new CompositeRepository(array_merge(array($installedRepo), $composer->getRepositoryManager()->getRepositories()));
8043 } elseif ($input->getOption('all')) {
8044 $defaultRepos = RepositoryFactory::defaultRepos($io);
8045 $io->writeError('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
8046 $installedRepo = $platformRepo;
8047 $repos = new CompositeRepository(array_merge(array($installedRepo), $defaultRepos));
8048 } else {
8049 $repos = $installedRepo = $this->getComposer()->getRepositoryManager()->getLocalRepository();
8050 $rootPkg = $this->getComposer()->getPackage();
8051 if (!$installedRepo->getPackages() && ($rootPkg->getRequires() || $rootPkg->getDevRequires())) {
8052 $io->writeError('<warning>No dependencies installed. Try running composer install or update.</warning>');
8053 }
8054 }
8055
8056 if ($composer) {
8057 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'show', $input, $output);
8058 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
8059 }
8060
8061 if ($input->getOption('latest') && null === $composer) {
8062 $io->writeError('No composer.json found in the current directory, disabling "latest" option');
8063 $input->setOption('latest', false);
8064 }
8065
8066 $packageFilter = $input->getArgument('package');
8067
8068
8069 if (($packageFilter && false === strpos($packageFilter, '*')) || !empty($package)) {
8070 if (empty($package)) {
8071 list($package, $versions) = $this->getPackage($installedRepo, $repos, $input->getArgument('package'), $input->getArgument('version'));
8072
8073 if (empty($package)) {
8074 $options = $input->getOptions();
8075 if (!isset($options['working-dir']) || !file_exists('composer.json')) {
8076 if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $input->getArgument('package')) && !$input->getOption('platform')) {
8077 throw new \InvalidArgumentException('Package ' . $packageFilter . ' not found, try using --platform (-p) to show platform packages.');
8078 }
8079 throw new \InvalidArgumentException('Package ' . $packageFilter . ' not found');
8080 }
8081
8082 $io->writeError('Package ' . $packageFilter . ' not found in ' . $options['working-dir'] . '/composer.json');
8083
8084 return 1;
8085 }
8086 } else {
8087 $versions = array($package->getPrettyVersion() => $package->getVersion());
8088 }
8089
8090 $exitCode = 0;
8091 if ($input->getOption('tree')) {
8092 $arrayTree = $this->generatePackageTree($package, $installedRepo, $repos);
8093
8094 if ('json' === $format) {
8095 $io->write(JsonFile::encode(array('installed' => array($arrayTree))));
8096 } else {
8097 $this->displayPackageTree(array($arrayTree));
8098 }
8099 } else {
8100 $latestPackage = null;
8101 if ($input->getOption('latest')) {
8102 $latestPackage = $this->findLatestPackage($package, $composer, $phpVersion);
8103 }
8104 if ($input->getOption('outdated') && $input->getOption('strict') && $latestPackage && $latestPackage->getFullPrettyVersion() !== $package->getFullPrettyVersion() && !$latestPackage->isAbandoned()) {
8105 $exitCode = 1;
8106 }
8107 if ($input->getOption('path')) {
8108 $io->write($package->getName(), false);
8109 $io->write(' ' . strtok(realpath($composer->getInstallationManager()->getInstallPath($package)), "\r\n"));
8110
8111 return $exitCode;
8112 }
8113
8114 if ('json' === $format) {
8115 $this->printPackageInfoAsJson($package, $versions, $installedRepo, $latestPackage ?: null);
8116 } else {
8117 $this->printPackageInfo($package, $versions, $installedRepo, $latestPackage ?: null);
8118 }
8119 }
8120
8121 return $exitCode;
8122 }
8123
8124
8125 if ($input->getOption('tree')) {
8126 $rootRequires = $this->getRootRequires();
8127 $packages = $installedRepo->getPackages();
8128 usort($packages, 'strcmp');
8129 $arrayTree = array();
8130 foreach ($packages as $package) {
8131 if (in_array($package->getName(), $rootRequires, true)) {
8132 $arrayTree[] = $this->generatePackageTree($package, $installedRepo, $repos);
8133 }
8134 }
8135
8136 if ('json' === $format) {
8137 $io->write(JsonFile::encode(array('installed' => $arrayTree)));
8138 } else {
8139 $this->displayPackageTree($arrayTree);
8140 }
8141
8142 return 0;
8143 }
8144
8145 if ($repos instanceof CompositeRepository) {
8146 $repos = $repos->getRepositories();
8147 } elseif (!is_array($repos)) {
8148 $repos = array($repos);
8149 }
8150
8151
8152 $packages = array();
8153 if (null !== $packageFilter) {
8154 $packageFilter = '{^'.str_replace('\\*', '.*?', preg_quote($packageFilter)).'$}i';
8155 }
8156
8157 $packageListFilter = array();
8158 if ($input->getOption('direct')) {
8159 $packageListFilter = $this->getRootRequires();
8160 }
8161
8162 if (class_exists('Symfony\Component\Console\Terminal')) {
8163 $terminal = new Terminal();
8164 $width = $terminal->getWidth();
8165 } else {
8166
8167 list($width) = $this->getApplication()->getTerminalDimensions();
8168 }
8169 if (null === $width) {
8170
8171
8172 $width = PHP_INT_MAX;
8173 }
8174 if (Platform::isWindows()) {
8175 $width--;
8176 } else {
8177 $width = max(80, $width);
8178 }
8179
8180 if ($input->getOption('path') && null === $composer) {
8181 $io->writeError('No composer.json found in the current directory, disabling "path" option');
8182 $input->setOption('path', false);
8183 }
8184
8185 foreach ($repos as $repo) {
8186 if ($repo === $platformRepo) {
8187 $type = 'platform';
8188 } elseif (
8189 $repo === $installedRepo
8190 || ($installedRepo instanceof CompositeRepository && in_array($repo, $installedRepo->getRepositories(), true))
8191 ) {
8192 $type = 'installed';
8193 } else {
8194 $type = 'available';
8195 }
8196 if ($repo instanceof ComposerRepository && $repo->hasProviders()) {
8197 foreach ($repo->getProviderNames() as $name) {
8198 if (!$packageFilter || preg_match($packageFilter, $name)) {
8199 $packages[$type][$name] = $name;
8200 }
8201 }
8202 } else {
8203 foreach ($repo->getPackages() as $package) {
8204 if (!isset($packages[$type][$package->getName()])
8205 || !is_object($packages[$type][$package->getName()])
8206 || version_compare($packages[$type][$package->getName()]->getVersion(), $package->getVersion(), '<')
8207 ) {
8208 if (!$packageFilter || preg_match($packageFilter, $package->getName())) {
8209 if (!$packageListFilter || in_array($package->getName(), $packageListFilter, true)) {
8210 $packages[$type][$package->getName()] = $package;
8211 }
8212 }
8213 }
8214 }
8215 }
8216 }
8217
8218 $showAllTypes = $input->getOption('all');
8219 $showLatest = $input->getOption('latest');
8220 $showMinorOnly = $input->getOption('minor-only');
8221 $ignoredPackages = array_map('strtolower', $input->getOption('ignore'));
8222 $indent = $showAllTypes ? '  ' : '';
8223 $latestPackages = array();
8224 $exitCode = 0;
8225 $viewData = array();
8226 $viewMetaData = array();
8227 foreach (array('platform' => true, 'available' => false, 'installed' => true) as $type => $showVersion) {
8228 if (isset($packages[$type])) {
8229 ksort($packages[$type]);
8230
8231 $nameLength = $versionLength = $latestLength = 0;
8232
8233 if ($showLatest && $showVersion) {
8234 foreach ($packages[$type] as $package) {
8235 if (is_object($package)) {
8236 $latestPackage = $this->findLatestPackage($package, $composer, $phpVersion, $showMinorOnly);
8237 if ($latestPackage === false) {
8238 continue;
8239 }
8240
8241 $latestPackages[$package->getPrettyName()] = $latestPackage;
8242 }
8243 }
8244 }
8245
8246 $writePath = !$input->getOption('name-only') && $input->getOption('path');
8247 $writeVersion = !$input->getOption('name-only') && !$input->getOption('path') && $showVersion;
8248 $writeLatest = $writeVersion && $showLatest;
8249 $writeDescription = !$input->getOption('name-only') && !$input->getOption('path');
8250
8251 $hasOutdatedPackages = false;
8252
8253 $viewData[$type] = array();
8254 foreach ($packages[$type] as $package) {
8255 $packageViewData = array();
8256 if (is_object($package)) {
8257 $latestPackage = null;
8258 if ($showLatest && isset($latestPackages[$package->getPrettyName()])) {
8259 $latestPackage = $latestPackages[$package->getPrettyName()];
8260 }
8261
8262
8263 $packageIsUpToDate = $latestPackage && $latestPackage->getFullPrettyVersion() === $package->getFullPrettyVersion() && !$latestPackage->isAbandoned();
8264 $packageIsIgnored = \in_array($package->getPrettyName(), $ignoredPackages, true);
8265 if ($input->getOption('outdated') && ($packageIsUpToDate || $packageIsIgnored)) {
8266 continue;
8267 } elseif ($input->getOption('outdated') || $input->getOption('strict')) {
8268 $hasOutdatedPackages = true;
8269 }
8270
8271 $packageViewData['name'] = $package->getPrettyName();
8272 $nameLength = max($nameLength, strlen($package->getPrettyName()));
8273 if ($writeVersion) {
8274 $packageViewData['version'] = $package->getFullPrettyVersion();
8275 $versionLength = max($versionLength, strlen($package->getFullPrettyVersion()));
8276 }
8277 if ($writeLatest && $latestPackage) {
8278 $packageViewData['latest'] = $latestPackage->getFullPrettyVersion();
8279 $packageViewData['latest-status'] = $this->getUpdateStatus($latestPackage, $package);
8280 $latestLength = max($latestLength, strlen($latestPackage->getFullPrettyVersion()));
8281 }
8282 if ($writeDescription) {
8283 $packageViewData['description'] = $package->getDescription();
8284 }
8285 if ($writePath) {
8286 $packageViewData['path'] = strtok(realpath($composer->getInstallationManager()->getInstallPath($package)), "\r\n");
8287 }
8288
8289 if ($latestPackage && $latestPackage->isAbandoned()) {
8290 $replacement = is_string($latestPackage->getReplacementPackage())
8291 ? 'Use ' . $latestPackage->getReplacementPackage() . ' instead'
8292 : 'No replacement was suggested';
8293 $packageWarning = sprintf(
8294 'Package %s is abandoned, you should avoid using it. %s.',
8295 $package->getPrettyName(),
8296 $replacement
8297 );
8298 $packageViewData['warning'] = $packageWarning;
8299 }
8300 } else {
8301 $packageViewData['name'] = $package;
8302 $nameLength = max($nameLength, strlen($package));
8303 }
8304 $viewData[$type][] = $packageViewData;
8305 }
8306 $viewMetaData[$type] = array(
8307 'nameLength' => $nameLength,
8308 'versionLength' => $versionLength,
8309 'latestLength' => $latestLength,
8310 );
8311 if ($input->getOption('strict') && $hasOutdatedPackages) {
8312 $exitCode = 1;
8313 break;
8314 }
8315 }
8316 }
8317
8318 if ('json' === $format) {
8319 $io->write(JsonFile::encode($viewData));
8320 } else {
8321 foreach ($viewData as $type => $packages) {
8322 $nameLength = $viewMetaData[$type]['nameLength'];
8323 $versionLength = $viewMetaData[$type]['versionLength'];
8324 $latestLength = $viewMetaData[$type]['latestLength'];
8325
8326 $writeVersion = $nameLength + $versionLength + 3 <= $width;
8327 $writeLatest = $nameLength + $versionLength + $latestLength + 3 <= $width;
8328 $writeDescription = $nameLength + $versionLength + $latestLength + 24 <= $width;
8329
8330 if ($writeLatest && !$io->isDecorated()) {
8331 $latestLength += 2;
8332 }
8333
8334 if ($showAllTypes) {
8335 if ('available' === $type) {
8336 $io->write('<comment>' . $type . '</comment>:');
8337 } else {
8338 $io->write('<info>' . $type . '</info>:');
8339 }
8340 }
8341
8342 foreach ($packages as $package) {
8343 $io->write($indent . str_pad($package['name'], $nameLength, ' '), false);
8344 if (isset($package['version']) && $writeVersion) {
8345 $io->write(' ' . str_pad($package['version'], $versionLength, ' '), false);
8346 }
8347 if (isset($package['latest']) && $writeLatest) {
8348 $latestVersion = $package['latest'];
8349 $updateStatus = $package['latest-status'];
8350 $style = $this->updateStatusToVersionStyle($updateStatus);
8351 if (!$io->isDecorated()) {
8352 $latestVersion = str_replace(array('up-to-date', 'semver-safe-update', 'update-possible'), array('=', '!', '~'), $updateStatus) . ' ' . $latestVersion;
8353 }
8354 $io->write(' <' . $style . '>' . str_pad($latestVersion, $latestLength, ' ') . '</' . $style . '>', false);
8355 }
8356 if (isset($package['description']) && $writeDescription) {
8357 $description = strtok($package['description'], "\r\n");
8358 $remaining = $width - $nameLength - $versionLength - 4;
8359 if ($writeLatest) {
8360 $remaining -= $latestLength;
8361 }
8362 if (strlen($description) > $remaining) {
8363 $description = substr($description, 0, $remaining - 3) . '...';
8364 }
8365 $io->write(' ' . $description, false);
8366 }
8367 if (isset($package['path'])) {
8368 $io->write(' ' . $package['path'], false);
8369 }
8370 $io->write('');
8371 if (isset($package['warning'])) {
8372 $io->write('<warning>' . $package['warning'] . '</warning>');
8373 }
8374 }
8375
8376 if ($showAllTypes) {
8377 $io->write('');
8378 }
8379 }
8380 }
8381
8382 return $exitCode;
8383 }
8384
8385 protected function getRootRequires()
8386 {
8387 $rootPackage = $this->getComposer()->getPackage();
8388
8389 return array_map(
8390 'strtolower',
8391 array_keys(array_merge($rootPackage->getRequires(), $rootPackage->getDevRequires()))
8392 );
8393 }
8394
8395 protected function getVersionStyle(PackageInterface $latestPackage, PackageInterface $package)
8396 {
8397 return $this->updateStatusToVersionStyle($this->getUpdateStatus($latestPackage, $package));
8398 }
8399
8400
8401
8402
8403
8404
8405
8406
8407
8408
8409
8410 protected function getPackage(RepositoryInterface $installedRepo, RepositoryInterface $repos, $name, $version = null)
8411 {
8412 $name = strtolower($name);
8413 $constraint = is_string($version) ? $this->versionParser->parseConstraints($version) : $version;
8414
8415 $policy = new DefaultPolicy();
8416 $pool = new Pool('dev');
8417 $pool->addRepository($repos);
8418
8419 $matchedPackage = null;
8420 $versions = array();
8421 $matches = $pool->whatProvides($name, $constraint);
8422 foreach ($matches as $index => $package) {
8423
8424 if ($package->getName() !== $name) {
8425 unset($matches[$index]);
8426 continue;
8427 }
8428
8429
8430 if (null === $version && $installedRepo->hasPackage($package)) {
8431 $matchedPackage = $package;
8432 }
8433
8434 $versions[$package->getPrettyVersion()] = $package->getVersion();
8435 $matches[$index] = $package->getId();
8436 }
8437
8438
8439 if (!$matchedPackage && $matches && $preferred = $policy->selectPreferredPackages($pool, array(), $matches)) {
8440 $matchedPackage = $pool->literalToPackage($preferred[0]);
8441 }
8442
8443 return array($matchedPackage, $versions);
8444 }
8445
8446
8447
8448
8449
8450
8451
8452
8453
8454 protected function printPackageInfo(CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo, PackageInterface $latestPackage = null)
8455 {
8456 $io = $this->getIO();
8457
8458 $this->printMeta($package, $versions, $installedRepo, $latestPackage ?: null);
8459 $this->printLinks($package, 'requires');
8460 $this->printLinks($package, 'devRequires', 'requires (dev)');
8461
8462 if ($package->getSuggests()) {
8463 $io->write("\n<info>suggests</info>");
8464 foreach ($package->getSuggests() as $suggested => $reason) {
8465 $io->write($suggested . ' <comment>' . $reason . '</comment>');
8466 }
8467 }
8468
8469 $this->printLinks($package, 'provides');
8470 $this->printLinks($package, 'conflicts');
8471 $this->printLinks($package, 'replaces');
8472 }
8473
8474
8475
8476
8477
8478
8479
8480
8481
8482 protected function printMeta(CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo, PackageInterface $latestPackage = null)
8483 {
8484 $io = $this->getIO();
8485 $io->write('<info>name</info>     : ' . $package->getPrettyName());
8486 $io->write('<info>descrip.</info> : ' . $package->getDescription());
8487 $io->write('<info>keywords</info> : ' . implode(', ', $package->getKeywords() ?: array()));
8488 $this->printVersions($package, $versions, $installedRepo);
8489 if ($latestPackage) {
8490 $style = $this->getVersionStyle($latestPackage, $package);
8491 $io->write('<info>latest</info>   : <'.$style.'>' . $latestPackage->getPrettyVersion() . '</'.$style.'>');
8492 } else {
8493 $latestPackage = $package;
8494 }
8495 $io->write('<info>type</info>     : ' . $package->getType());
8496 $this->printLicenses($package);
8497 $io->write('<info>homepage</info> : ' . $package->getHomepage());
8498 $io->write('<info>source</info>   : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getSourceType(), $package->getSourceUrl(), $package->getSourceReference()));
8499 $io->write('<info>dist</info>     : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getDistType(), $package->getDistUrl(), $package->getDistReference()));
8500 if ($installedRepo->hasPackage($package)) {
8501 $io->write('<info>path</info>     : ' . sprintf('%s', realpath($this->getComposer()->getInstallationManager()->getInstallPath($package))));
8502 }
8503 $io->write('<info>names</info>    : ' . implode(', ', $package->getNames()));
8504
8505 if ($latestPackage->isAbandoned()) {
8506 $replacement = ($latestPackage->getReplacementPackage() !== null)
8507 ? ' The author suggests using the ' . $latestPackage->getReplacementPackage(). ' package instead.'
8508 : null;
8509
8510 $io->writeError(
8511 sprintf('<warning>Attention: This package is abandoned and no longer maintained.%s</warning>', $replacement)
8512 );
8513 }
8514
8515 if ($package->getSupport()) {
8516 $io->write("\n<info>support</info>");
8517 foreach ($package->getSupport() as $type => $value) {
8518 $io->write('<comment>' . $type . '</comment> : '.$value);
8519 }
8520 }
8521
8522 if ($package->getAutoload()) {
8523 $io->write("\n<info>autoload</info>");
8524 foreach ($package->getAutoload() as $type => $autoloads) {
8525 $io->write('<comment>' . $type . '</comment>');
8526
8527 if ($type === 'psr-0') {
8528 foreach ($autoloads as $name => $path) {
8529 $io->write(($name ?: '*') . ' => ' . (is_array($path) ? implode(', ', $path) : ($path ?: '.')));
8530 }
8531 } elseif ($type === 'psr-4') {
8532 foreach ($autoloads as $name => $path) {
8533 $io->write(($name ?: '*') . ' => ' . (is_array($path) ? implode(', ', $path) : ($path ?: '.')));
8534 }
8535 } elseif ($type === 'classmap') {
8536 $io->write(implode(', ', $autoloads));
8537 }
8538 }
8539 if ($package->getIncludePaths()) {
8540 $io->write('<comment>include-path</comment>');
8541 $io->write(implode(', ', $package->getIncludePaths()));
8542 }
8543 }
8544 }
8545
8546
8547
8548
8549
8550
8551
8552
8553 protected function printVersions(CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo)
8554 {
8555 uasort($versions, 'version_compare');
8556 $versions = array_keys(array_reverse($versions));
8557
8558
8559 if ($installedRepo->hasPackage($package)) {
8560 $installedVersion = $package->getPrettyVersion();
8561 $key = array_search($installedVersion, $versions);
8562 if (false !== $key) {
8563 $versions[$key] = '<info>* ' . $installedVersion . '</info>';
8564 }
8565 }
8566
8567 $versions = implode(', ', $versions);
8568
8569 $this->getIO()->write('<info>versions</info> : ' . $versions);
8570 }
8571
8572
8573
8574
8575
8576
8577
8578
8579 protected function printLinks(CompletePackageInterface $package, $linkType, $title = null)
8580 {
8581 $title = $title ?: $linkType;
8582 $io = $this->getIO();
8583 if ($links = $package->{'get'.ucfirst($linkType)}()) {
8584 $io->write("\n<info>" . $title . "</info>");
8585
8586 foreach ($links as $link) {
8587 $io->write($link->getTarget() . ' <comment>' . $link->getPrettyConstraint() . '</comment>');
8588 }
8589 }
8590 }
8591
8592
8593
8594
8595
8596
8597 protected function printLicenses(CompletePackageInterface $package)
8598 {
8599 $spdxLicenses = new SpdxLicenses();
8600
8601 $licenses = $package->getLicense();
8602 $io = $this->getIO();
8603
8604 foreach ($licenses as $licenseId) {
8605 $license = $spdxLicenses->getLicenseByIdentifier($licenseId); 
8606
8607 if (!$license) {
8608 $out = $licenseId;
8609 } else {
8610
8611 if ($license[1] === true) {
8612 $out = sprintf('%s (%s) (OSI approved) %s', $license[0], $licenseId, $license[2]);
8613 } else {
8614 $out = sprintf('%s (%s) %s', $license[0], $licenseId, $license[2]);
8615 }
8616 }
8617
8618 $io->write('<info>license</info>  : ' . $out);
8619 }
8620 }
8621
8622
8623
8624
8625
8626
8627
8628
8629
8630 protected function printPackageInfoAsJson(CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo, PackageInterface $latestPackage = null)
8631 {
8632 $json = array(
8633 'name' => $package->getPrettyName(),
8634 'description' => $package->getDescription(),
8635 'keywords' => $package->getKeywords() ?: array(),
8636 'type' => $package->getType(),
8637 'homepage' => $package->getHomepage(),
8638 'names' => $package->getNames()
8639 );
8640
8641 $json = $this->appendVersions($json, $versions);
8642 $json = $this->appendLicenses($json, $package);
8643
8644 if ($latestPackage) {
8645 $json['latest'] = $latestPackage->getPrettyVersion();
8646 } else {
8647 $latestPackage = $package;
8648 }
8649
8650 if ($package->getSourceType()) {
8651 $json['source'] = array(
8652 'type' => $package->getSourceType(),
8653 'url' => $package->getSourceUrl(),
8654 'reference' => $package->getSourceReference()
8655 );
8656 }
8657
8658 if ($package->getDistType()) {
8659 $json['dist'] = array(
8660 'type' => $package->getDistType(),
8661 'url' => $package->getDistUrl(),
8662 'reference' => $package->getDistReference()
8663 );
8664 }
8665
8666 if ($installedRepo->hasPackage($package)) {
8667 $json['path'] = realpath($this->getComposer()->getInstallationManager()->getInstallPath($package));
8668 if ($json['path'] === false) {
8669 unset($json['path']);
8670 }
8671 }
8672
8673 if ($latestPackage->isAbandoned()) {
8674 $json['replacement'] = $latestPackage->getReplacementPackage();
8675 }
8676
8677 if ($package->getSuggests()) {
8678 $json['suggests'] = $package->getSuggests();
8679 }
8680
8681 if ($package->getSupport()) {
8682 $json['support'] = $package->getSupport();
8683 }
8684
8685 $json = $this->appendAutoload($json, $package);
8686
8687 if ($package->getIncludePaths()) {
8688 $json['include_path'] = $package->getIncludePaths();
8689 }
8690
8691 $json = $this->appendLinks($json, $package);
8692
8693 $this->getIO()->write(JsonFile::encode($json));
8694 }
8695
8696 private function appendVersions($json, array $versions)
8697 {
8698 uasort($versions, 'version_compare');
8699 $versions = array_keys(array_reverse($versions));
8700 $json['versions'] = $versions;
8701
8702 return $json;
8703 }
8704
8705 private function appendLicenses($json, CompletePackageInterface $package)
8706 {
8707 if ($licenses = $package->getLicense()) {
8708 $spdxLicenses = new SpdxLicenses();
8709
8710 $json['licenses'] = array_map(function ($licenseId) use ($spdxLicenses) {
8711 $license = $spdxLicenses->getLicenseByIdentifier($licenseId); 
8712
8713 if (!$license) {
8714 return $licenseId;
8715 }
8716
8717 return array(
8718 'name' => $license[0],
8719 'osi' => $licenseId,
8720 'url' => $license[2]
8721 );
8722 }, $licenses);
8723 }
8724
8725 return $json;
8726 }
8727
8728 private function appendAutoload($json, CompletePackageInterface $package)
8729 {
8730 if ($package->getAutoload()) {
8731 $autoload = array();
8732
8733 foreach ($package->getAutoload() as $type => $autoloads) {
8734 if ($type === 'psr-0' || $type === 'psr-4') {
8735 $psr = array();
8736
8737 foreach ($autoloads as $name => $path) {
8738 if (!$path) {
8739 $path = '.';
8740 }
8741
8742 $psr[$name ?: '*'] = $path;
8743 }
8744
8745 $autoload[$type] = $psr;
8746 } elseif ($type === 'classmap') {
8747 $autoload['classmap'] = $autoloads;
8748 }
8749 }
8750
8751 $json['autoload'] = $autoload;
8752 }
8753
8754 return $json;
8755 }
8756
8757 private function appendLinks($json, CompletePackageInterface $package)
8758 {
8759 foreach (array('requires', 'devRequires', 'provides', 'conflicts', 'replaces') as $linkType) {
8760 $json = $this->appendLink($json, $package, $linkType);
8761 }
8762
8763 return $json;
8764 }
8765
8766 private function appendLink($json, CompletePackageInterface $package, $linkType)
8767 {
8768 $links = $package->{'get' . ucfirst($linkType)}();
8769
8770 if ($links) {
8771 $json[$linkType] = array();
8772
8773 foreach ($links as $link) {
8774 $json[$linkType][$link->getTarget()] = $link->getPrettyConstraint();
8775 }
8776 }
8777
8778 return $json;
8779 }
8780
8781
8782
8783
8784
8785
8786 protected function initStyles(OutputInterface $output)
8787 {
8788 $this->colors = array(
8789 'green',
8790 'yellow',
8791 'cyan',
8792 'magenta',
8793 'blue',
8794 );
8795
8796 foreach ($this->colors as $color) {
8797 $style = new OutputFormatterStyle($color);
8798 $output->getFormatter()->setStyle($color, $style);
8799 }
8800 }
8801
8802
8803
8804
8805
8806
8807 protected function displayPackageTree(array $arrayTree)
8808 {
8809 $io = $this->getIO();
8810 foreach ($arrayTree as $package) {
8811 $io->write(sprintf('<info>%s</info>', $package['name']), false);
8812 $io->write(' ' . $package['version'], false);
8813 $io->write(' ' . strtok($package['description'], "\r\n"));
8814
8815 if (isset($package['requires'])) {
8816 $requires = $package['requires'];
8817 $treeBar = '├';
8818 $j = 0;
8819 $total = count($requires);
8820 foreach ($requires as $require) {
8821 $requireName = $require['name'];
8822 $j++;
8823 if ($j === $total) {
8824 $treeBar = '└';
8825 }
8826 $level = 1;
8827 $color = $this->colors[$level];
8828 $info = sprintf(
8829 '%s──<%s>%s</%s> %s',
8830 $treeBar,
8831 $color,
8832 $requireName,
8833 $color,
8834 $require['version']
8835 );
8836 $this->writeTreeLine($info);
8837
8838 $treeBar = str_replace('└', ' ', $treeBar);
8839 $packagesInTree = array($package['name'], $requireName);
8840
8841 $this->displayTree($require, $packagesInTree, $treeBar, $level + 1);
8842 }
8843 }
8844 }
8845 }
8846
8847
8848
8849
8850
8851
8852
8853
8854
8855 protected function generatePackageTree(
8856 PackageInterface $package,
8857 RepositoryInterface $installedRepo,
8858 RepositoryInterface $distantRepos
8859 ) {
8860 $requires = $package->getRequires();
8861 ksort($requires);
8862 $children = array();
8863 foreach ($requires as $requireName => $require) {
8864 $packagesInTree = array($package->getName(), $requireName);
8865
8866 $treeChildDesc = array(
8867 'name' => $requireName,
8868 'version' => $require->getPrettyConstraint(),
8869 );
8870
8871 $deepChildren = $this->addTree($requireName, $require, $installedRepo, $distantRepos, $packagesInTree);
8872
8873 if ($deepChildren) {
8874 $treeChildDesc['requires'] = $deepChildren;
8875 }
8876
8877 $children[] = $treeChildDesc;
8878 }
8879 $tree = array(
8880 'name' => $package->getPrettyName(),
8881 'version' => $package->getPrettyVersion(),
8882 'description' => $package->getDescription(),
8883 );
8884
8885 if ($children) {
8886 $tree['requires'] = $children;
8887 }
8888
8889 return $tree;
8890 }
8891
8892
8893
8894
8895
8896
8897
8898
8899
8900 protected function displayTree(
8901 $package,
8902 array $packagesInTree,
8903 $previousTreeBar = '├',
8904 $level = 1
8905 ) {
8906 $previousTreeBar = str_replace('├', '│', $previousTreeBar);
8907 if (isset($package['requires'])) {
8908 $requires = $package['requires'];
8909 $treeBar = $previousTreeBar . '  ├';
8910 $i = 0;
8911 $total = count($requires);
8912 foreach ($requires as $require) {
8913 $currentTree = $packagesInTree;
8914 $i++;
8915 if ($i === $total) {
8916 $treeBar = $previousTreeBar . '  └';
8917 }
8918 $colorIdent = $level % count($this->colors);
8919 $color = $this->colors[$colorIdent];
8920
8921 $circularWarn = in_array(
8922 $require['name'],
8923 $currentTree,
8924 true
8925 ) ? '(circular dependency aborted here)' : '';
8926 $info = rtrim(sprintf(
8927 '%s──<%s>%s</%s> %s %s',
8928 $treeBar,
8929 $color,
8930 $require['name'],
8931 $color,
8932 $require['version'],
8933 $circularWarn
8934 ));
8935 $this->writeTreeLine($info);
8936
8937 $treeBar = str_replace('└', ' ', $treeBar);
8938
8939 $currentTree[] = $require['name'];
8940 $this->displayTree($require, $currentTree, $treeBar, $level + 1);
8941 }
8942 }
8943 }
8944
8945
8946
8947
8948
8949
8950
8951
8952
8953
8954
8955 protected function addTree(
8956 $name,
8957 $package,
8958 RepositoryInterface $installedRepo,
8959 RepositoryInterface $distantRepos,
8960 array $packagesInTree
8961 ) {
8962 $children = array();
8963 list($package, $versions) = $this->getPackage(
8964 $installedRepo,
8965 $distantRepos,
8966 $name,
8967 $package->getPrettyConstraint() === 'self.version' ? $package->getConstraint() : $package->getPrettyConstraint()
8968 );
8969 if (is_object($package)) {
8970 $requires = $package->getRequires();
8971 ksort($requires);
8972 foreach ($requires as $requireName => $require) {
8973 $currentTree = $packagesInTree;
8974
8975 $treeChildDesc = array(
8976 'name' => $requireName,
8977 'version' => $require->getPrettyConstraint(),
8978 );
8979
8980 if (!in_array($requireName, $currentTree, true)) {
8981 $currentTree[] = $requireName;
8982 $deepChildren = $this->addTree($requireName, $require, $installedRepo, $distantRepos, $currentTree);
8983 if ($deepChildren) {
8984 $treeChildDesc['requires'] = $deepChildren;
8985 }
8986 }
8987
8988 $children[] = $treeChildDesc;
8989 }
8990 }
8991
8992 return $children;
8993 }
8994
8995 private function updateStatusToVersionStyle($updateStatus)
8996 {
8997
8998
8999
9000 return str_replace(array('up-to-date', 'semver-safe-update', 'update-possible'), array('info', 'highlight', 'comment'), $updateStatus);
9001 }
9002
9003 private function getUpdateStatus(PackageInterface $latestPackage, PackageInterface $package)
9004 {
9005 if ($latestPackage->getFullPrettyVersion() === $package->getFullPrettyVersion()) {
9006 return 'up-to-date';
9007 }
9008
9009 $constraint = $package->getVersion();
9010 if (0 !== strpos($constraint, 'dev-')) {
9011 $constraint = '^'.$constraint;
9012 }
9013 if ($latestPackage->getVersion() && Semver::satisfies($latestPackage->getVersion(), $constraint)) {
9014
9015 return 'semver-safe-update';
9016 }
9017
9018
9019 return 'update-possible';
9020 }
9021
9022 private function writeTreeLine($line)
9023 {
9024 $io = $this->getIO();
9025 if (!$io->isDecorated()) {
9026 $line = str_replace(array('└', '├', '──', '│'), array('`-', '|-', '-', '|'), $line);
9027 }
9028
9029 $io->write($line);
9030 }
9031
9032
9033
9034
9035
9036
9037
9038
9039
9040
9041
9042 private function findLatestPackage(PackageInterface $package, Composer $composer, $phpVersion, $minorOnly = false)
9043 {
9044
9045 $name = $package->getName();
9046 $versionSelector = new VersionSelector($this->getPool($composer));
9047 $stability = $composer->getPackage()->getMinimumStability();
9048 $flags = $composer->getPackage()->getStabilityFlags();
9049 if (isset($flags[$name])) {
9050 $stability = array_search($flags[$name], BasePackage::$stabilities, true);
9051 }
9052
9053 $bestStability = $stability;
9054 if ($composer->getPackage()->getPreferStable()) {
9055 $bestStability = $package->getStability();
9056 }
9057
9058 $targetVersion = null;
9059 if (0 === strpos($package->getVersion(), 'dev-')) {
9060 $targetVersion = $package->getVersion();
9061 }
9062
9063 if ($targetVersion === null && $minorOnly) {
9064 $targetVersion = '^' . $package->getVersion();
9065 }
9066
9067 return $versionSelector->findBestCandidate($name, $targetVersion, $phpVersion, $bestStability);
9068 }
9069
9070 private function getPool(Composer $composer)
9071 {
9072 if (!$this->pool) {
9073 $this->pool = new Pool($composer->getPackage()->getMinimumStability(), $composer->getPackage()->getStabilityFlags());
9074 $this->pool->addRepository(new CompositeRepository($composer->getRepositoryManager()->getRepositories()));
9075 }
9076
9077 return $this->pool;
9078 }
9079 }
9080 <?php
9081
9082
9083
9084
9085
9086
9087
9088
9089
9090
9091
9092 namespace Composer\Command;
9093
9094 use Symfony\Component\Console\Input\InputInterface;
9095 use Symfony\Component\Console\Input\InputOption;
9096 use Symfony\Component\Console\Output\OutputInterface;
9097 use Composer\Downloader\ChangeReportInterface;
9098 use Composer\Downloader\DvcsDownloaderInterface;
9099 use Composer\Downloader\VcsCapableDownloaderInterface;
9100 use Composer\Package\Dumper\ArrayDumper;
9101 use Composer\Package\Version\VersionGuesser;
9102 use Composer\Package\Version\VersionParser;
9103 use Composer\Plugin\CommandEvent;
9104 use Composer\Plugin\PluginEvents;
9105 use Composer\Script\ScriptEvents;
9106 use Composer\Util\ProcessExecutor;
9107
9108
9109
9110
9111
9112 class StatusCommand extends BaseCommand
9113 {
9114 const EXIT_CODE_ERRORS = 1;
9115 const EXIT_CODE_UNPUSHED_CHANGES = 2;
9116 const EXIT_CODE_VERSION_CHANGES = 4;
9117
9118
9119
9120
9121 protected function configure()
9122 {
9123 $this
9124 ->setName('status')
9125 ->setDescription('Shows a list of locally modified packages.')
9126 ->setDefinition(array(
9127 new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Show modified files for each directory that contains changes.'),
9128 ))
9129 ->setHelp(
9130 <<<EOT
9131 The status command displays a list of dependencies that have
9132 been modified locally.
9133
9134 Read more at https://getcomposer.org/doc/03-cli.md#status
9135 EOT
9136 )
9137 ;
9138 }
9139
9140
9141
9142
9143
9144
9145 protected function execute(InputInterface $input, OutputInterface $output)
9146 {
9147 $composer = $this->getComposer();
9148
9149 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'status', $input, $output);
9150 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
9151
9152
9153 $composer->getEventDispatcher()->dispatchScript(ScriptEvents::PRE_STATUS_CMD, true);
9154
9155 $exitCode = $this->doExecute($input, $output);
9156
9157
9158 $composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_STATUS_CMD, true);
9159
9160 return $exitCode;
9161 }
9162
9163
9164
9165
9166
9167
9168 private function doExecute(InputInterface $input, OutputInterface $output)
9169 {
9170
9171 $composer = $this->getComposer();
9172
9173 $installedRepo = $composer->getRepositoryManager()->getLocalRepository();
9174
9175 $dm = $composer->getDownloadManager();
9176 $im = $composer->getInstallationManager();
9177
9178 $errors = array();
9179 $io = $this->getIO();
9180 $unpushedChanges = array();
9181 $vcsVersionChanges = array();
9182
9183 $parser = new VersionParser;
9184 $guesser = new VersionGuesser($composer->getConfig(), new ProcessExecutor($io), $parser);
9185 $dumper = new ArrayDumper;
9186
9187
9188 foreach ($installedRepo->getCanonicalPackages() as $package) {
9189 $downloader = $dm->getDownloaderForInstalledPackage($package);
9190 $targetDir = $im->getInstallPath($package);
9191
9192 if ($downloader instanceof ChangeReportInterface) {
9193 if (is_link($targetDir)) {
9194 $errors[$targetDir] = $targetDir . ' is a symbolic link.';
9195 }
9196
9197 if ($changes = $downloader->getLocalChanges($package, $targetDir)) {
9198 $errors[$targetDir] = $changes;
9199 }
9200 }
9201
9202 if ($downloader instanceof VcsCapableDownloaderInterface) {
9203 if ($currentRef = $downloader->getVcsReference($package, $targetDir)) {
9204 switch ($package->getInstallationSource()) {
9205 case 'source':
9206 $previousRef = $package->getSourceReference();
9207 break;
9208 case 'dist':
9209 $previousRef = $package->getDistReference();
9210 break;
9211 default:
9212 $previousRef = null;
9213 }
9214
9215 $currentVersion = $guesser->guessVersion($dumper->dump($package), $targetDir);
9216
9217 if ($previousRef && $currentVersion && $currentVersion['commit'] !== $previousRef) {
9218 $vcsVersionChanges[$targetDir] = array(
9219 'previous' => array(
9220 'version' => $package->getPrettyVersion(),
9221 'ref' => $previousRef,
9222 ),
9223 'current' => array(
9224 'version' => $currentVersion['pretty_version'],
9225 'ref' => $currentVersion['commit'],
9226 ),
9227 );
9228 }
9229 }
9230 }
9231
9232 if ($downloader instanceof DvcsDownloaderInterface) {
9233 if ($unpushed = $downloader->getUnpushedChanges($package, $targetDir)) {
9234 $unpushedChanges[$targetDir] = $unpushed;
9235 }
9236 }
9237 }
9238
9239
9240 if (!$errors && !$unpushedChanges && !$vcsVersionChanges) {
9241 $io->writeError('<info>No local changes</info>');
9242
9243 return 0;
9244 }
9245
9246 if ($errors) {
9247 $io->writeError('<error>You have changes in the following dependencies:</error>');
9248
9249 foreach ($errors as $path => $changes) {
9250 if ($input->getOption('verbose')) {
9251 $indentedChanges = implode("\n", array_map(function ($line) {
9252 return '    ' . ltrim($line);
9253 }, explode("\n", $changes)));
9254 $io->write('<info>'.$path.'</info>:');
9255 $io->write($indentedChanges);
9256 } else {
9257 $io->write($path);
9258 }
9259 }
9260 }
9261
9262 if ($unpushedChanges) {
9263 $io->writeError('<warning>You have unpushed changes on the current branch in the following dependencies:</warning>');
9264
9265 foreach ($unpushedChanges as $path => $changes) {
9266 if ($input->getOption('verbose')) {
9267 $indentedChanges = implode("\n", array_map(function ($line) {
9268 return '    ' . ltrim($line);
9269 }, explode("\n", $changes)));
9270 $io->write('<info>'.$path.'</info>:');
9271 $io->write($indentedChanges);
9272 } else {
9273 $io->write($path);
9274 }
9275 }
9276 }
9277
9278 if ($vcsVersionChanges) {
9279 $io->writeError('<warning>You have version variations in the following dependencies:</warning>');
9280
9281 foreach ($vcsVersionChanges as $path => $changes) {
9282 if ($input->getOption('verbose')) {
9283
9284 $currentVersion = $changes['current']['version'] ?: $changes['current']['ref'];
9285 $previousVersion = $changes['previous']['version'] ?: $changes['previous']['ref'];
9286
9287 if ($io->isVeryVerbose()) {
9288
9289 $currentVersion .= sprintf(' (%s)', $changes['current']['ref']);
9290 $previousVersion .= sprintf(' (%s)', $changes['previous']['ref']);
9291 }
9292
9293 $io->write('<info>'.$path.'</info>:');
9294 $io->write(sprintf('    From <comment>%s</comment> to <comment>%s</comment>', $previousVersion, $currentVersion));
9295 } else {
9296 $io->write($path);
9297 }
9298 }
9299 }
9300
9301 if (($errors || $unpushedChanges || $vcsVersionChanges) && !$input->getOption('verbose')) {
9302 $io->writeError('Use --verbose (-v) to see a list of files');
9303 }
9304
9305 return ($errors ? self::EXIT_CODE_ERRORS : 0) + ($unpushedChanges ? self::EXIT_CODE_UNPUSHED_CHANGES : 0) + ($vcsVersionChanges ? self::EXIT_CODE_VERSION_CHANGES : 0);
9306 }
9307 }
9308 <?php
9309
9310
9311
9312
9313
9314
9315
9316
9317
9318
9319
9320 namespace Composer\Command;
9321
9322 use Composer\Repository\PlatformRepository;
9323 use Symfony\Component\Console\Input\InputArgument;
9324 use Symfony\Component\Console\Input\InputInterface;
9325 use Symfony\Component\Console\Input\InputOption;
9326 use Symfony\Component\Console\Output\OutputInterface;
9327
9328 class SuggestsCommand extends BaseCommand
9329 {
9330 protected function configure()
9331 {
9332 $this
9333 ->setName('suggests')
9334 ->setDescription('Shows package suggestions.')
9335 ->setDefinition(array(
9336 new InputOption('by-package', null, InputOption::VALUE_NONE, 'Groups output by suggesting package'),
9337 new InputOption('by-suggestion', null, InputOption::VALUE_NONE, 'Groups output by suggested package'),
9338 new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Exclude suggestions from require-dev packages'),
9339 new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Packages that you want to list suggestions from.'),
9340 ))
9341 ->setHelp(
9342 <<<EOT
9343
9344 The <info>%command.name%</info> command shows a sorted list of suggested packages.
9345
9346 Enabling <info>-v</info> implies <info>--by-package --by-suggestion</info>, showing both lists.
9347
9348 Read more at https://getcomposer.org/doc/03-cli.md#suggests
9349 EOT
9350 )
9351 ;
9352 }
9353
9354 protected function execute(InputInterface $input, OutputInterface $output)
9355 {
9356 $lock = $this->getComposer()->getLocker()->getLockData();
9357
9358 if (empty($lock)) {
9359 throw new \RuntimeException('Lockfile seems to be empty?');
9360 }
9361
9362 $packages = $lock['packages'];
9363
9364 if (!$input->getOption('no-dev')) {
9365 $packages += $lock['packages-dev'];
9366 }
9367
9368 $filter = $input->getArgument('packages');
9369
9370
9371 $installed = array();
9372 foreach ($packages as $package) {
9373 $installed[] = $package['name'];
9374
9375 if (!empty($package['provide'])) {
9376 $installed = array_merge($installed, array_keys($package['provide']));
9377 }
9378
9379 if (!empty($package['replace'])) {
9380 $installed = array_merge($installed, array_keys($package['replace']));
9381 }
9382 }
9383
9384
9385 $installed = array_flip($installed);
9386 ksort($installed);
9387
9388
9389 $platform = new PlatformRepository(array(), $this->getComposer()->getConfig()->get('platform') ?: array());
9390
9391
9392 $suggesters = array();
9393 $suggested = array();
9394 foreach ($packages as $package) {
9395 $packageName = $package['name'];
9396 if ((!empty($filter) && !in_array($packageName, $filter)) || empty($package['suggest'])) {
9397 continue;
9398 }
9399 foreach ($package['suggest'] as $suggestion => $reason) {
9400 if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $suggestion) && null !== $platform->findPackage($suggestion, '*')) {
9401 continue;
9402 }
9403 if (!isset($installed[$suggestion])) {
9404 $suggesters[$packageName][$suggestion] = $reason;
9405 $suggested[$suggestion][$packageName] = $reason;
9406 }
9407 }
9408 }
9409 ksort($suggesters);
9410 ksort($suggested);
9411
9412
9413 $mode = 0;
9414 $io = $this->getIO();
9415 if ($input->getOption('by-package') || $io->isVerbose()) {
9416 $mode |= 1;
9417 }
9418 if ($input->getOption('by-suggestion')) {
9419 $mode |= 2;
9420 }
9421
9422
9423 if ($mode === 0) {
9424 foreach (array_keys($suggested) as $suggestion) {
9425 $io->write(sprintf('<info>%s</info>', $suggestion));
9426 }
9427
9428 return 0;
9429 }
9430
9431
9432 if ($mode & 1) {
9433 foreach ($suggesters as $suggester => $suggestions) {
9434 $io->write(sprintf('<comment>%s</comment> suggests:', $suggester));
9435
9436 foreach ($suggestions as $suggestion => $reason) {
9437 $io->write(sprintf(' - <info>%s</info>: %s', $suggestion, $reason ?: '*'));
9438 }
9439 $io->write('');
9440 }
9441 }
9442
9443
9444 if ($mode & 2) {
9445
9446 if ($mode & 1) {
9447 $io->write(str_repeat('-', 78));
9448 }
9449 foreach ($suggested as $suggestion => $suggesters) {
9450 $io->write(sprintf('<comment>%s</comment> is suggested by:', $suggestion));
9451
9452 foreach ($suggesters as $suggester => $reason) {
9453 $io->write(sprintf(' - <info>%s</info>: %s', $suggester, $reason ?: '*'));
9454 }
9455 $io->write('');
9456 }
9457 }
9458
9459 return 0;
9460 }
9461 }
9462 <?php
9463
9464
9465
9466
9467
9468
9469
9470
9471
9472
9473
9474 namespace Composer\Command;
9475
9476 use Composer\Composer;
9477 use Composer\Installer;
9478 use Composer\IO\IOInterface;
9479 use Composer\Plugin\CommandEvent;
9480 use Composer\Plugin\PluginEvents;
9481 use Symfony\Component\Console\Helper\Table;
9482 use Symfony\Component\Console\Input\InputInterface;
9483 use Symfony\Component\Console\Input\InputOption;
9484 use Symfony\Component\Console\Input\InputArgument;
9485 use Symfony\Component\Console\Output\OutputInterface;
9486 use Symfony\Component\Console\Question\Question;
9487
9488
9489
9490
9491
9492 class UpdateCommand extends BaseCommand
9493 {
9494 protected function configure()
9495 {
9496 $this
9497 ->setName('update')
9498 ->setAliases(array('u', 'upgrade'))
9499 ->setDescription('Upgrades your dependencies to the latest version according to composer.json, and updates the composer.lock file.')
9500 ->setDefinition(array(
9501 new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Packages that should be updated, if not provided all packages are.'),
9502 new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
9503 new InputOption('prefer-dist', null, InputOption::VALUE_NONE, 'Forces installation from package dist even for dev versions.'),
9504 new InputOption('dry-run', null, InputOption::VALUE_NONE, 'Outputs the operations but will not execute anything (implicitly enables --verbose).'),
9505 new InputOption('dev', null, InputOption::VALUE_NONE, 'Enables installation of require-dev packages (enabled by default, only present for BC).'),
9506 new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables installation of require-dev packages.'),
9507 new InputOption('lock', null, InputOption::VALUE_NONE, 'Only updates the lock file hash to suppress warning about the lock file being out of date.'),
9508 new InputOption('no-custom-installers', null, InputOption::VALUE_NONE, 'DEPRECATED: Use no-plugins instead.'),
9509 new InputOption('no-autoloader', null, InputOption::VALUE_NONE, 'Skips autoloader generation'),
9510 new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.'),
9511 new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
9512 new InputOption('no-suggest', null, InputOption::VALUE_NONE, 'Do not show package suggestions.'),
9513 new InputOption('with-dependencies', null, InputOption::VALUE_NONE, 'Add also dependencies of allowed packages to the allow list, except those defined in root package.'),
9514 new InputOption('with-all-dependencies', null, InputOption::VALUE_NONE, 'Add also all dependencies of allowed packages to the allow list, including those defined in root package.'),
9515 new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Shows more details including new commits pulled in when updating packages.'),
9516 new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump.'),
9517 new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'),
9518 new InputOption('apcu-autoloader', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'),
9519 new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'),
9520 new InputOption('prefer-stable', null, InputOption::VALUE_NONE, 'Prefer stable versions of dependencies.'),
9521 new InputOption('prefer-lowest', null, InputOption::VALUE_NONE, 'Prefer lowest versions of dependencies.'),
9522 new InputOption('interactive', 'i', InputOption::VALUE_NONE, 'Interactive interface with autocompletion to select the packages to update.'),
9523 new InputOption('root-reqs', null, InputOption::VALUE_NONE, 'Restricts the update to your first degree dependencies.'),
9524 ))
9525 ->setHelp(
9526 <<<EOT
9527 The <info>update</info> command reads the composer.json file from the
9528 current directory, processes it, and updates, removes or installs all the
9529 dependencies.
9530
9531 <info>php composer.phar update</info>
9532
9533 To limit the update operation to a few packages, you can list the package(s)
9534 you want to update as such:
9535
9536 <info>php composer.phar update vendor/package1 foo/mypackage [...]</info>
9537
9538 You may also use an asterisk (*) pattern to limit the update operation to package(s)
9539 from a specific vendor:
9540
9541 <info>php composer.phar update vendor/package1 foo/* [...]</info>
9542
9543 To select packages names interactively with auto-completion use <info>-i</info>.
9544
9545 Read more at https://getcomposer.org/doc/03-cli.md#update-u
9546 EOT
9547 )
9548 ;
9549 }
9550
9551 protected function execute(InputInterface $input, OutputInterface $output)
9552 {
9553 $io = $this->getIO();
9554 if ($input->getOption('no-custom-installers')) {
9555 $io->writeError('<warning>You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.</warning>');
9556 $input->setOption('no-plugins', true);
9557 }
9558
9559 if ($input->getOption('dev')) {
9560 $io->writeError('<warning>You are using the deprecated option "dev". Dev packages are installed by default now.</warning>');
9561 }
9562
9563 $composer = $this->getComposer(true, $input->getOption('no-plugins'));
9564
9565 $packages = $input->getArgument('packages');
9566
9567 if ($input->getOption('interactive')) {
9568 $packages = $this->getPackagesInteractively($io, $input, $output, $composer, $packages);
9569 }
9570
9571 if ($input->getOption('root-reqs')) {
9572 $require = array_keys($composer->getPackage()->getRequires());
9573 if (!$input->getOption('no-dev')) {
9574 $requireDev = array_keys($composer->getPackage()->getDevRequires());
9575 $require = array_merge($require, $requireDev);
9576 }
9577
9578 if (!empty($packages)) {
9579 $packages = array_intersect($packages, $require);
9580 } else {
9581 $packages = $require;
9582 }
9583 }
9584
9585 $composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress'));
9586
9587 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'update', $input, $output);
9588 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
9589
9590 $install = Installer::create($io, $composer);
9591
9592 $config = $composer->getConfig();
9593 list($preferSource, $preferDist) = $this->getPreferredInstallOptions($config, $input);
9594
9595 $optimize = $input->getOption('optimize-autoloader') || $config->get('optimize-autoloader');
9596 $authoritative = $input->getOption('classmap-authoritative') || $config->get('classmap-authoritative');
9597 $apcu = $input->getOption('apcu-autoloader') || $config->get('apcu-autoloader');
9598
9599 $install
9600 ->setDryRun($input->getOption('dry-run'))
9601 ->setVerbose($input->getOption('verbose'))
9602 ->setPreferSource($preferSource)
9603 ->setPreferDist($preferDist)
9604 ->setDevMode(!$input->getOption('no-dev'))
9605 ->setDumpAutoloader(!$input->getOption('no-autoloader'))
9606 ->setRunScripts(!$input->getOption('no-scripts'))
9607 ->setSkipSuggest($input->getOption('no-suggest'))
9608 ->setOptimizeAutoloader($optimize)
9609 ->setClassMapAuthoritative($authoritative)
9610 ->setApcuAutoloader($apcu)
9611 ->setUpdate(true)
9612 ->setUpdateAllowList($input->getOption('lock') ? array('lock') : $packages)
9613 ->setAllowListTransitiveDependencies($input->getOption('with-dependencies'))
9614 ->setAllowListAllDependencies($input->getOption('with-all-dependencies'))
9615 ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs'))
9616 ->setPreferStable($input->getOption('prefer-stable'))
9617 ->setPreferLowest($input->getOption('prefer-lowest'))
9618 ;
9619
9620 if ($input->getOption('no-plugins')) {
9621 $install->disablePlugins();
9622 }
9623
9624 return $install->run();
9625 }
9626
9627 private function getPackagesInteractively(IOInterface $io, InputInterface $input, OutputInterface $output, Composer $composer, array $packages)
9628 {
9629 if (!$input->isInteractive()) {
9630 throw new \InvalidArgumentException('--interactive cannot be used in non-interactive terminals.');
9631 }
9632
9633 $requires = array_merge(
9634 $composer->getPackage()->getRequires(),
9635 $composer->getPackage()->getDevRequires()
9636 );
9637 $autocompleterValues = array();
9638 foreach ($requires as $require) {
9639 $target = $require->getTarget();
9640 $autocompleterValues[strtolower($target)] = $target;
9641 }
9642
9643 $installedPackages = $composer->getRepositoryManager()->getLocalRepository()->getPackages();
9644 foreach ($installedPackages as $package) {
9645 $autocompleterValues[$package->getName()] = $package->getPrettyName();
9646 }
9647
9648 $helper = $this->getHelper('question');
9649 $question = new Question('<comment>Enter package name: </comment>', null);
9650
9651 $io->writeError('<info>Press enter without value to end submission</info>');
9652
9653 do {
9654 $autocompleterValues = array_diff($autocompleterValues, $packages);
9655 $question->setAutocompleterValues($autocompleterValues);
9656 $addedPackage = $helper->ask($input, $output, $question);
9657
9658 if (!is_string($addedPackage) || empty($addedPackage)) {
9659 break;
9660 }
9661
9662 $addedPackage = strtolower($addedPackage);
9663 if (!in_array($addedPackage, $packages)) {
9664 $packages[] = $addedPackage;
9665 }
9666 } while (true);
9667
9668 $packages = array_filter($packages);
9669 if (!$packages) {
9670 throw new \InvalidArgumentException('You must enter minimum one package.');
9671 }
9672
9673 $table = new Table($output);
9674 $table->setHeaders(array('Selected packages'));
9675 foreach ($packages as $package) {
9676 $table->addRow(array($package));
9677 }
9678 $table->render();
9679
9680 if ($io->askConfirmation(sprintf(
9681 'Would you like to continue and update the above package%s [<comment>yes</comment>]? ',
9682 1 === count($packages) ? '' : 's'
9683 ), true)) {
9684 return $packages;
9685 }
9686
9687 throw new \RuntimeException('Installation aborted.');
9688 }
9689 }
9690 <?php
9691
9692
9693
9694
9695
9696
9697
9698
9699
9700
9701
9702 namespace Composer\Command;
9703
9704 use Composer\Factory;
9705 use Composer\Package\Loader\ValidatingArrayLoader;
9706 use Composer\Plugin\CommandEvent;
9707 use Composer\Plugin\PluginEvents;
9708 use Composer\Util\ConfigValidator;
9709 use Symfony\Component\Console\Input\InputArgument;
9710 use Symfony\Component\Console\Input\InputInterface;
9711 use Symfony\Component\Console\Input\InputOption;
9712 use Symfony\Component\Console\Output\OutputInterface;
9713
9714
9715
9716
9717
9718
9719
9720 class ValidateCommand extends BaseCommand
9721 {
9722
9723
9724
9725 protected function configure()
9726 {
9727 $this
9728 ->setName('validate')
9729 ->setDescription('Validates a composer.json and composer.lock.')
9730 ->setDefinition(array(
9731 new InputOption('no-check-all', null, InputOption::VALUE_NONE, 'Do not validate requires for overly strict/loose constraints'),
9732 new InputOption('no-check-lock', null, InputOption::VALUE_NONE, 'Do not check if lock file is up to date'),
9733 new InputOption('no-check-publish', null, InputOption::VALUE_NONE, 'Do not check for publish errors'),
9734 new InputOption('with-dependencies', 'A', InputOption::VALUE_NONE, 'Also validate the composer.json of all installed dependencies'),
9735 new InputOption('strict', null, InputOption::VALUE_NONE, 'Return a non-zero exit code for warnings as well as errors'),
9736 new InputArgument('file', InputArgument::OPTIONAL, 'path to composer.json file'),
9737 ))
9738 ->setHelp(
9739 <<<EOT
9740 The validate command validates a given composer.json and composer.lock
9741
9742 Exit codes in case of errors are:
9743 1 validation warning(s), only when --strict is given
9744 2 validation error(s)
9745 3 file unreadable or missing
9746
9747 Read more at https://getcomposer.org/doc/03-cli.md#validate
9748 EOT
9749 );
9750 }
9751
9752
9753
9754
9755
9756
9757
9758 protected function execute(InputInterface $input, OutputInterface $output)
9759 {
9760 $file = $input->getArgument('file') ?: Factory::getComposerFile();
9761 $io = $this->getIO();
9762
9763 if (!file_exists($file)) {
9764 $io->writeError('<error>' . $file . ' not found.</error>');
9765
9766 return 3;
9767 }
9768 if (!is_readable($file)) {
9769 $io->writeError('<error>' . $file . ' is not readable.</error>');
9770
9771 return 3;
9772 }
9773
9774 $validator = new ConfigValidator($io);
9775 $checkAll = $input->getOption('no-check-all') ? 0 : ValidatingArrayLoader::CHECK_ALL;
9776 $checkPublish = !$input->getOption('no-check-publish');
9777 $checkLock = !$input->getOption('no-check-lock');
9778 $isStrict = $input->getOption('strict');
9779 list($errors, $publishErrors, $warnings) = $validator->validate($file, $checkAll);
9780
9781 $lockErrors = array();
9782 $composer = Factory::create($io, $file, $input->hasParameterOption('--no-plugins'));
9783 $locker = $composer->getLocker();
9784 if ($locker->isLocked() && !$locker->isFresh()) {
9785 $lockErrors[] = 'The lock file is not up to date with the latest changes in composer.json, it is recommended that you run `composer update` or `composer update <package name>`.';
9786 }
9787
9788 $this->outputResult($io, $file, $errors, $warnings, $checkPublish, $publishErrors, $checkLock, $lockErrors, true);
9789
9790
9791 $exitCode = $errors ? 2 : ($isStrict && $warnings ? 1 : 0);
9792
9793 if ($input->getOption('with-dependencies')) {
9794 $localRepo = $composer->getRepositoryManager()->getLocalRepository();
9795 foreach ($localRepo->getPackages() as $package) {
9796 $path = $composer->getInstallationManager()->getInstallPath($package);
9797 $file = $path . '/composer.json';
9798 if (is_dir($path) && file_exists($file)) {
9799 list($errors, $publishErrors, $warnings) = $validator->validate($file, $checkAll);
9800
9801 $this->outputResult($io, $package->getPrettyName(), $errors, $warnings, $checkPublish, $publishErrors);
9802
9803
9804 $depCode = $errors ? 2 : ($isStrict && $warnings ? 1 : 0);
9805 $exitCode = max($depCode, $exitCode);
9806 }
9807 }
9808 }
9809
9810 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'validate', $input, $output);
9811 $eventCode = $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
9812 $exitCode = max($eventCode, $exitCode);
9813
9814 return $exitCode;
9815 }
9816
9817 private function outputResult($io, $name, &$errors, &$warnings, $checkPublish = false, $publishErrors = array(), $checkLock = false, $lockErrors = array(), $printSchemaUrl = false)
9818 {
9819 $doPrintSchemaUrl = false;
9820
9821 if ($errors) {
9822 $io->writeError('<error>' . $name . ' is invalid, the following errors/warnings were found:</error>');
9823 } elseif ($publishErrors) {
9824 $io->writeError('<info>' . $name . ' is valid for simple usage with composer but has</info>');
9825 $io->writeError('<info>strict errors that make it unable to be published as a package:</info>');
9826 $doPrintSchemaUrl = $printSchemaUrl;
9827 } elseif ($warnings) {
9828 $io->writeError('<info>' . $name . ' is valid, but with a few warnings</info>');
9829 $doPrintSchemaUrl = $printSchemaUrl;
9830 } else {
9831 $io->write('<info>' . $name . ' is valid</info>');
9832
9833 }
9834
9835 if ($doPrintSchemaUrl) {
9836 $io->writeError('<warning>See https://getcomposer.org/doc/04-schema.md for details on the schema</warning>');
9837 }
9838
9839
9840 $extraWarnings = array();
9841
9842
9843 if ($checkPublish) {
9844 $errors = array_merge($errors, $publishErrors);
9845 } else {
9846 $extraWarnings = array_merge($extraWarnings, $publishErrors);
9847 }
9848
9849
9850 if ($checkLock) {
9851 $errors = array_merge($errors, $lockErrors);
9852 } else {
9853 $extraWarnings = array_merge($extraWarnings, $lockErrors);
9854 }
9855
9856 $messages = array(
9857 'error' => $errors,
9858 'warning' => array_merge($warnings, $extraWarnings),
9859 );
9860
9861 foreach ($messages as $style => $msgs) {
9862 foreach ($msgs as $msg) {
9863 $io->writeError('<' . $style . '>' . $msg . '</' . $style . '>');
9864 }
9865 }
9866 }
9867 }
9868 <?php
9869
9870
9871
9872
9873
9874
9875
9876
9877
9878
9879
9880 namespace Composer;
9881
9882 use Composer\Package\RootPackageInterface;
9883 use Composer\Package\Locker;
9884 use Composer\Repository\RepositoryManager;
9885 use Composer\Installer\InstallationManager;
9886 use Composer\Plugin\PluginManager;
9887 use Composer\Downloader\DownloadManager;
9888 use Composer\EventDispatcher\EventDispatcher;
9889 use Composer\Autoload\AutoloadGenerator;
9890 use Composer\Package\Archiver\ArchiveManager;
9891
9892
9893
9894
9895
9896
9897 class Composer
9898 {
9899
9900
9901
9902
9903
9904
9905
9906
9907
9908
9909
9910
9911
9912
9913
9914
9915
9916
9917
9918
9919
9920 const VERSION = '1.10.20';
9921 const BRANCH_ALIAS_VERSION = '';
9922 const RELEASE_DATE = '2021-01-27 15:41:06';
9923 const SOURCE_VERSION = '';
9924
9925
9926
9927
9928
9929
9930
9931
9932
9933
9934 const RUNTIME_API_VERSION = '1.0.0';
9935
9936 public static function getVersion()
9937 {
9938
9939 if (self::VERSION === '@package_version'.'@') {
9940 return self::SOURCE_VERSION;
9941 }
9942
9943
9944 if (self::BRANCH_ALIAS_VERSION !== '' && preg_match('{^[a-f0-9]{40}$}', self::VERSION)) {
9945 return self::BRANCH_ALIAS_VERSION.'+'.self::VERSION;
9946 }
9947
9948 return self::VERSION;
9949 }
9950
9951
9952
9953
9954 private $package;
9955
9956
9957
9958
9959 private $locker;
9960
9961
9962
9963
9964 private $repositoryManager;
9965
9966
9967
9968
9969 private $downloadManager;
9970
9971
9972
9973
9974 private $installationManager;
9975
9976
9977
9978
9979 private $pluginManager;
9980
9981
9982
9983
9984 private $config;
9985
9986
9987
9988
9989 private $eventDispatcher;
9990
9991
9992
9993
9994 private $autoloadGenerator;
9995
9996
9997
9998
9999 private $archiveManager;
10000
10001
10002
10003
10004
10005 public function setPackage(RootPackageInterface $package)
10006 {
10007 $this->package = $package;
10008 }
10009
10010
10011
10012
10013 public function getPackage()
10014 {
10015 return $this->package;
10016 }
10017
10018
10019
10020
10021 public function setConfig(Config $config)
10022 {
10023 $this->config = $config;
10024 }
10025
10026
10027
10028
10029 public function getConfig()
10030 {
10031 return $this->config;
10032 }
10033
10034
10035
10036
10037 public function setLocker(Locker $locker)
10038 {
10039 $this->locker = $locker;
10040 }
10041
10042
10043
10044
10045 public function getLocker()
10046 {
10047 return $this->locker;
10048 }
10049
10050
10051
10052
10053 public function setRepositoryManager(RepositoryManager $manager)
10054 {
10055 $this->repositoryManager = $manager;
10056 }
10057
10058
10059
10060
10061 public function getRepositoryManager()
10062 {
10063 return $this->repositoryManager;
10064 }
10065
10066
10067
10068
10069 public function setDownloadManager(DownloadManager $manager)
10070 {
10071 $this->downloadManager = $manager;
10072 }
10073
10074
10075
10076
10077 public function getDownloadManager()
10078 {
10079 return $this->downloadManager;
10080 }
10081
10082
10083
10084
10085 public function setArchiveManager(ArchiveManager $manager)
10086 {
10087 $this->archiveManager = $manager;
10088 }
10089
10090
10091
10092
10093 public function getArchiveManager()
10094 {
10095 return $this->archiveManager;
10096 }
10097
10098
10099
10100
10101 public function setInstallationManager(InstallationManager $manager)
10102 {
10103 $this->installationManager = $manager;
10104 }
10105
10106
10107
10108
10109 public function getInstallationManager()
10110 {
10111 return $this->installationManager;
10112 }
10113
10114
10115
10116
10117 public function setPluginManager(PluginManager $manager)
10118 {
10119 $this->pluginManager = $manager;
10120 }
10121
10122
10123
10124
10125 public function getPluginManager()
10126 {
10127 return $this->pluginManager;
10128 }
10129
10130
10131
10132
10133 public function setEventDispatcher(EventDispatcher $eventDispatcher)
10134 {
10135 $this->eventDispatcher = $eventDispatcher;
10136 }
10137
10138
10139
10140
10141 public function getEventDispatcher()
10142 {
10143 return $this->eventDispatcher;
10144 }
10145
10146
10147
10148
10149 public function setAutoloadGenerator(AutoloadGenerator $autoloadGenerator)
10150 {
10151 $this->autoloadGenerator = $autoloadGenerator;
10152 }
10153
10154
10155
10156
10157 public function getAutoloadGenerator()
10158 {
10159 return $this->autoloadGenerator;
10160 }
10161 }
10162 <?php
10163
10164
10165
10166
10167
10168
10169
10170
10171
10172
10173
10174 namespace Composer;
10175
10176 use Composer\Config\ConfigSourceInterface;
10177 use Composer\Downloader\TransportException;
10178 use Composer\IO\IOInterface;
10179 use Composer\Util\Platform;
10180 use Composer\Util\ProcessExecutor;
10181
10182
10183
10184
10185 class Config
10186 {
10187 const RELATIVE_PATHS = 1;
10188
10189 public static $defaultConfig = array(
10190 'process-timeout' => 300,
10191 'use-include-path' => false,
10192 'preferred-install' => 'auto',
10193 'notify-on-install' => true,
10194 'github-protocols' => array('https', 'ssh', 'git'),
10195 'vendor-dir' => 'vendor',
10196 'bin-dir' => '{$vendor-dir}/bin',
10197 'cache-dir' => '{$home}/cache',
10198 'data-dir' => '{$home}',
10199 'cache-files-dir' => '{$cache-dir}/files',
10200 'cache-repo-dir' => '{$cache-dir}/repo',
10201 'cache-vcs-dir' => '{$cache-dir}/vcs',
10202 'cache-ttl' => 15552000, 
10203 'cache-files-ttl' => null, 
10204 'cache-files-maxsize' => '300MiB',
10205 'bin-compat' => 'auto',
10206 'discard-changes' => false,
10207 'autoloader-suffix' => null,
10208 'sort-packages' => false,
10209 'optimize-autoloader' => false,
10210 'classmap-authoritative' => false,
10211 'apcu-autoloader' => false,
10212 'prepend-autoloader' => true,
10213 'github-domains' => array('github.com'),
10214 'bitbucket-expose-hostname' => true,
10215 'disable-tls' => false,
10216 'secure-http' => true,
10217 'cafile' => null,
10218 'capath' => null,
10219 'github-expose-hostname' => true,
10220 'gitlab-domains' => array('gitlab.com'),
10221 'store-auths' => 'prompt',
10222 'platform' => array(),
10223 'archive-format' => 'tar',
10224 'archive-dir' => '.',
10225 'htaccess-protect' => true,
10226 'use-github-api' => true,
10227 'lock' => true,
10228
10229
10230
10231
10232
10233
10234
10235 );
10236
10237 public static $defaultRepositories = array(
10238 'packagist.org' => array(
10239 'type' => 'composer',
10240 'url' => 'https?://repo.packagist.org',
10241 'allow_ssl_downgrade' => true,
10242 ),
10243 );
10244
10245 private $config;
10246 private $baseDir;
10247 private $repositories;
10248
10249 private $configSource;
10250
10251 private $authConfigSource;
10252 private $useEnvironment;
10253 private $warnedHosts = array();
10254
10255
10256
10257
10258
10259 public function __construct($useEnvironment = true, $baseDir = null)
10260 {
10261
10262 $this->config = static::$defaultConfig;
10263 $this->repositories = static::$defaultRepositories;
10264 $this->useEnvironment = (bool) $useEnvironment;
10265 $this->baseDir = $baseDir;
10266 }
10267
10268 public function setConfigSource(ConfigSourceInterface $source)
10269 {
10270 $this->configSource = $source;
10271 }
10272
10273 public function getConfigSource()
10274 {
10275 return $this->configSource;
10276 }
10277
10278 public function setAuthConfigSource(ConfigSourceInterface $source)
10279 {
10280 $this->authConfigSource = $source;
10281 }
10282
10283 public function getAuthConfigSource()
10284 {
10285 return $this->authConfigSource;
10286 }
10287
10288
10289
10290
10291
10292
10293 public function merge($config)
10294 {
10295
10296 if (!empty($config['config']) && is_array($config['config'])) {
10297 foreach ($config['config'] as $key => $val) {
10298 if (in_array($key, array('bitbucket-oauth', 'github-oauth', 'gitlab-oauth', 'gitlab-token', 'http-basic', 'bearer')) && isset($this->config[$key])) {
10299 $this->config[$key] = array_merge($this->config[$key], $val);
10300 } elseif ('preferred-install' === $key && isset($this->config[$key])) {
10301 if (is_array($val) || is_array($this->config[$key])) {
10302 if (is_string($val)) {
10303 $val = array('*' => $val);
10304 }
10305 if (is_string($this->config[$key])) {
10306 $this->config[$key] = array('*' => $this->config[$key]);
10307 }
10308 $this->config[$key] = array_merge($this->config[$key], $val);
10309
10310 if (isset($this->config[$key]['*'])) {
10311 $wildcard = $this->config[$key]['*'];
10312 unset($this->config[$key]['*']);
10313 $this->config[$key]['*'] = $wildcard;
10314 }
10315 } else {
10316 $this->config[$key] = $val;
10317 }
10318 } else {
10319 $this->config[$key] = $val;
10320 }
10321 }
10322 }
10323
10324 if (!empty($config['repositories']) && is_array($config['repositories'])) {
10325 $this->repositories = array_reverse($this->repositories, true);
10326 $newRepos = array_reverse($config['repositories'], true);
10327 foreach ($newRepos as $name => $repository) {
10328
10329 if (false === $repository) {
10330 $this->disableRepoByName($name);
10331 continue;
10332 }
10333
10334
10335 if (is_array($repository) && 1 === count($repository) && false === current($repository)) {
10336 $this->disableRepoByName(key($repository));
10337 continue;
10338 }
10339
10340
10341 if (is_int($name)) {
10342 $this->repositories[] = $repository;
10343 } else {
10344 if ($name === 'packagist') { 
10345 $this->repositories[$name . '.org'] = $repository;
10346 } else {
10347 $this->repositories[$name] = $repository;
10348 }
10349 }
10350 }
10351 $this->repositories = array_reverse($this->repositories, true);
10352 }
10353 }
10354
10355
10356
10357
10358 public function getRepositories()
10359 {
10360 return $this->repositories;
10361 }
10362
10363
10364
10365
10366
10367
10368
10369
10370
10371 public function get($key, $flags = 0)
10372 {
10373 switch ($key) {
10374 case 'vendor-dir':
10375 case 'bin-dir':
10376 case 'process-timeout':
10377 case 'data-dir':
10378 case 'cache-dir':
10379 case 'cache-files-dir':
10380 case 'cache-repo-dir':
10381 case 'cache-vcs-dir':
10382 case 'cafile':
10383 case 'capath':
10384
10385 $env = 'COMPOSER_' . strtoupper(strtr($key, '-', '_'));
10386
10387 $val = $this->getComposerEnv($env);
10388 $val = rtrim((string) $this->process(false !== $val ? $val : $this->config[$key], $flags), '/\\');
10389 $val = Platform::expandPath($val);
10390
10391 if (substr($key, -4) !== '-dir') {
10392 return $val;
10393 }
10394
10395 return (($flags & self::RELATIVE_PATHS) == self::RELATIVE_PATHS) ? $val : $this->realpath($val);
10396
10397 case 'htaccess-protect':
10398 $value = $this->getComposerEnv('COMPOSER_HTACCESS_PROTECT');
10399 if (false === $value) {
10400 $value = $this->config[$key];
10401 }
10402 return $value !== 'false' && (bool) $value;
10403
10404 case 'cache-ttl':
10405 return (int) $this->config[$key];
10406
10407 case 'cache-files-maxsize':
10408 if (!preg_match('/^\s*([0-9.]+)\s*(?:([kmg])(?:i?b)?)?\s*$/i', $this->config[$key], $matches)) {
10409 throw new \RuntimeException(
10410 "Could not parse the value of 'cache-files-maxsize': {$this->config[$key]}"
10411 );
10412 }
10413 $size = $matches[1];
10414 if (isset($matches[2])) {
10415 switch (strtolower($matches[2])) {
10416 case 'g':
10417 $size *= 1024;
10418
10419
10420 case 'm':
10421 $size *= 1024;
10422
10423
10424 case 'k':
10425 $size *= 1024;
10426 break;
10427 }
10428 }
10429
10430 return $size;
10431
10432 case 'cache-files-ttl':
10433 if (isset($this->config[$key])) {
10434 return (int) $this->config[$key];
10435 }
10436
10437 return (int) $this->config['cache-ttl'];
10438
10439 case 'home':
10440 $val = preg_replace('#^(\$HOME|~)(/|$)#', rtrim(getenv('HOME') ?: getenv('USERPROFILE'), '/\\') . '/', $this->config[$key]);
10441
10442 return rtrim($this->process($val, $flags), '/\\');
10443
10444 case 'bin-compat':
10445 $value = $this->getComposerEnv('COMPOSER_BIN_COMPAT') ?: $this->config[$key];
10446
10447 if (!in_array($value, array('auto', 'full'))) {
10448 throw new \RuntimeException(
10449 "Invalid value for 'bin-compat': {$value}. Expected auto, full"
10450 );
10451 }
10452
10453 return $value;
10454
10455 case 'discard-changes':
10456 if ($env = $this->getComposerEnv('COMPOSER_DISCARD_CHANGES')) {
10457 if (!in_array($env, array('stash', 'true', 'false', '1', '0'), true)) {
10458 throw new \RuntimeException(
10459 "Invalid value for COMPOSER_DISCARD_CHANGES: {$env}. Expected 1, 0, true, false or stash"
10460 );
10461 }
10462 if ('stash' === $env) {
10463 return 'stash';
10464 }
10465
10466
10467 return $env !== 'false' && (bool) $env;
10468 }
10469
10470 if (!in_array($this->config[$key], array(true, false, 'stash'), true)) {
10471 throw new \RuntimeException(
10472 "Invalid value for 'discard-changes': {$this->config[$key]}. Expected true, false or stash"
10473 );
10474 }
10475
10476 return $this->config[$key];
10477
10478 case 'github-protocols':
10479 $protos = $this->config['github-protocols'];
10480 if ($this->config['secure-http'] && false !== ($index = array_search('git', $protos))) {
10481 unset($protos[$index]);
10482 }
10483 if (reset($protos) === 'http') {
10484 throw new \RuntimeException('The http protocol for github is not available anymore, update your config\'s github-protocols to use "https", "git" or "ssh"');
10485 }
10486
10487 return $protos;
10488
10489 case 'disable-tls':
10490 return $this->config[$key] !== 'false' && (bool) $this->config[$key];
10491 case 'secure-http':
10492 if ($this->get('disable-tls') === true) {
10493 return false;
10494 }
10495
10496 return $this->config[$key] !== 'false' && (bool) $this->config[$key];
10497 case 'use-github-api':
10498 return $this->config[$key] !== 'false' && (bool) $this->config[$key];
10499 case 'lock':
10500 return $this->config[$key] !== 'false' && (bool) $this->config[$key];
10501 default:
10502 if (!isset($this->config[$key])) {
10503 return null;
10504 }
10505
10506 return $this->process($this->config[$key], $flags);
10507 }
10508 }
10509
10510 public function all($flags = 0)
10511 {
10512 $all = array(
10513 'repositories' => $this->getRepositories(),
10514 );
10515 foreach (array_keys($this->config) as $key) {
10516 $all['config'][$key] = $this->get($key, $flags);
10517 }
10518
10519 return $all;
10520 }
10521
10522 public function raw()
10523 {
10524 return array(
10525 'repositories' => $this->getRepositories(),
10526 'config' => $this->config,
10527 );
10528 }
10529
10530
10531
10532
10533
10534
10535
10536 public function has($key)
10537 {
10538 return array_key_exists($key, $this->config);
10539 }
10540
10541
10542
10543
10544
10545
10546
10547
10548 private function process($value, $flags)
10549 {
10550 $config = $this;
10551
10552 if (!is_string($value)) {
10553 return $value;
10554 }
10555
10556 return preg_replace_callback('#\{\$(.+)\}#', function ($match) use ($config, $flags) {
10557 return $config->get($match[1], $flags);
10558 }, $value);
10559 }
10560
10561
10562
10563
10564
10565
10566
10567
10568
10569 private function realpath($path)
10570 {
10571 if (preg_match('{^(?:/|[a-z]:|[a-z0-9.]+://)}i', $path)) {
10572 return $path;
10573 }
10574
10575 return $this->baseDir . '/' . $path;
10576 }
10577
10578
10579
10580
10581
10582
10583
10584
10585
10586
10587 private function getComposerEnv($var)
10588 {
10589 if ($this->useEnvironment) {
10590 return getenv($var);
10591 }
10592
10593 return false;
10594 }
10595
10596 private function disableRepoByName($name)
10597 {
10598 if (isset($this->repositories[$name])) {
10599 unset($this->repositories[$name]);
10600 } elseif ($name === 'packagist') { 
10601 unset($this->repositories['packagist.org']);
10602 }
10603 }
10604
10605
10606
10607
10608
10609
10610
10611 public function prohibitUrlByConfig($url, IOInterface $io = null)
10612 {
10613
10614 if (false === filter_var($url, FILTER_VALIDATE_URL)) {
10615 return;
10616 }
10617
10618
10619 $scheme = parse_url($url, PHP_URL_SCHEME);
10620 if (in_array($scheme, array('http', 'git', 'ftp', 'svn'))) {
10621 if ($this->get('secure-http')) {
10622 throw new TransportException("Your configuration does not allow connections to $url. See https://getcomposer.org/doc/06-config.md#secure-http for details.");
10623 } elseif ($io) {
10624 $host = parse_url($url, PHP_URL_HOST);
10625 if (!isset($this->warnedHosts[$host])) {
10626 $io->writeError("<warning>Warning: Accessing $host over $scheme which is an insecure protocol.</warning>");
10627 }
10628 $this->warnedHosts[$host] = true;
10629 }
10630 }
10631 }
10632
10633
10634
10635
10636
10637
10638
10639
10640
10641
10642
10643 public static function disableProcessTimeout()
10644 {
10645
10646 ProcessExecutor::setTimeout(0);
10647 }
10648 }
10649 <?php
10650
10651
10652
10653
10654
10655
10656
10657
10658
10659
10660
10661 namespace Composer\Config;
10662
10663
10664
10665
10666
10667
10668
10669 interface ConfigSourceInterface
10670 {
10671
10672
10673
10674
10675
10676
10677 public function addRepository($name, $config);
10678
10679
10680
10681
10682
10683
10684 public function removeRepository($name);
10685
10686
10687
10688
10689
10690
10691
10692 public function addConfigSetting($name, $value);
10693
10694
10695
10696
10697
10698
10699 public function removeConfigSetting($name);
10700
10701
10702
10703
10704
10705
10706
10707 public function addProperty($name, $value);
10708
10709
10710
10711
10712
10713
10714 public function removeProperty($name);
10715
10716
10717
10718
10719
10720
10721
10722
10723 public function addLink($type, $name, $value);
10724
10725
10726
10727
10728
10729
10730
10731 public function removeLink($type, $name);
10732
10733
10734
10735
10736
10737
10738 public function getName();
10739 }
10740 <?php
10741
10742
10743
10744
10745
10746
10747
10748
10749
10750
10751
10752 namespace Composer\Config;
10753
10754 use Composer\Json\JsonFile;
10755 use Composer\Json\JsonManipulator;
10756 use Composer\Util\Silencer;
10757
10758
10759
10760
10761
10762
10763
10764 class JsonConfigSource implements ConfigSourceInterface
10765 {
10766
10767
10768
10769 private $file;
10770
10771
10772
10773
10774 private $authConfig;
10775
10776
10777
10778
10779
10780
10781
10782 public function __construct(JsonFile $file, $authConfig = false)
10783 {
10784 $this->file = $file;
10785 $this->authConfig = $authConfig;
10786 }
10787
10788
10789
10790
10791 public function getName()
10792 {
10793 return $this->file->getPath();
10794 }
10795
10796
10797
10798
10799 public function addRepository($name, $config)
10800 {
10801 $this->manipulateJson('addRepository', $name, $config, function (&$config, $repo, $repoConfig) {
10802
10803
10804 if (isset($config['repositories'])) {
10805 foreach ($config['repositories'] as $index => $val) {
10806 if ($index === $repo) {
10807 continue;
10808 }
10809 if (is_numeric($index) && ($val === array('packagist' => false) || $val === array('packagist.org' => false))) {
10810 unset($config['repositories'][$index]);
10811 $config['repositories']['packagist.org'] = false;
10812 break;
10813 }
10814 }
10815 }
10816
10817 $config['repositories'][$repo] = $repoConfig;
10818 });
10819 }
10820
10821
10822
10823
10824 public function removeRepository($name)
10825 {
10826 $this->manipulateJson('removeRepository', $name, function (&$config, $repo) {
10827 unset($config['repositories'][$repo]);
10828 });
10829 }
10830
10831
10832
10833
10834 public function addConfigSetting($name, $value)
10835 {
10836 $authConfig = $this->authConfig;
10837 $this->manipulateJson('addConfigSetting', $name, $value, function (&$config, $key, $val) use ($authConfig) {
10838 if (preg_match('{^(bitbucket-oauth|github-oauth|gitlab-oauth|gitlab-token|bearer|http-basic|platform)\.}', $key)) {
10839 list($key, $host) = explode('.', $key, 2);
10840 if ($authConfig) {
10841 $config[$key][$host] = $val;
10842 } else {
10843 $config['config'][$key][$host] = $val;
10844 }
10845 } else {
10846 $config['config'][$key] = $val;
10847 }
10848 });
10849 }
10850
10851
10852
10853
10854 public function removeConfigSetting($name)
10855 {
10856 $authConfig = $this->authConfig;
10857 $this->manipulateJson('removeConfigSetting', $name, function (&$config, $key) use ($authConfig) {
10858 if (preg_match('{^(bitbucket-oauth|github-oauth|gitlab-oauth|gitlab-token|bearer|http-basic|platform)\.}', $key)) {
10859 list($key, $host) = explode('.', $key, 2);
10860 if ($authConfig) {
10861 unset($config[$key][$host]);
10862 } else {
10863 unset($config['config'][$key][$host]);
10864 }
10865 } else {
10866 unset($config['config'][$key]);
10867 }
10868 });
10869 }
10870
10871
10872
10873
10874 public function addProperty($name, $value)
10875 {
10876 $this->manipulateJson('addProperty', $name, $value, function (&$config, $key, $val) {
10877 if (substr($key, 0, 6) === 'extra.' || substr($key, 0, 8) === 'scripts.') {
10878 $bits = explode('.', $key);
10879 $last = array_pop($bits);
10880 $arr = &$config[reset($bits)];
10881 foreach ($bits as $bit) {
10882 if (!isset($arr[$bit])) {
10883 $arr[$bit] = array();
10884 }
10885 $arr = &$arr[$bit];
10886 }
10887 $arr[$last] = $val;
10888 } else {
10889 $config[$key] = $val;
10890 }
10891 });
10892 }
10893
10894
10895
10896
10897 public function removeProperty($name)
10898 {
10899 $authConfig = $this->authConfig;
10900 $this->manipulateJson('removeProperty', $name, function (&$config, $key) {
10901 if (substr($key, 0, 6) === 'extra.' || substr($key, 0, 8) === 'scripts.') {
10902 $bits = explode('.', $key);
10903 $last = array_pop($bits);
10904 $arr = &$config[reset($bits)];
10905 foreach ($bits as $bit) {
10906 if (!isset($arr[$bit])) {
10907 return;
10908 }
10909 $arr = &$arr[$bit];
10910 }
10911 unset($arr[$last]);
10912 } else {
10913 unset($config[$key]);
10914 }
10915 });
10916 }
10917
10918
10919
10920
10921 public function addLink($type, $name, $value)
10922 {
10923 $this->manipulateJson('addLink', $type, $name, $value, function (&$config, $type, $name, $value) {
10924 $config[$type][$name] = $value;
10925 });
10926 }
10927
10928
10929
10930
10931 public function removeLink($type, $name)
10932 {
10933 $this->manipulateJson('removeSubNode', $type, $name, function (&$config, $type, $name) {
10934 unset($config[$type][$name]);
10935
10936 if (0 === count($config[$type])) {
10937 unset($config[$type]);
10938 }
10939 });
10940 }
10941
10942 protected function manipulateJson($method, $args, $fallback)
10943 {
10944 $args = func_get_args();
10945
10946 array_shift($args);
10947 $fallback = array_pop($args);
10948
10949 if ($this->file->exists()) {
10950 if (!is_writable($this->file->getPath())) {
10951 throw new \RuntimeException(sprintf('The file "%s" is not writable.', $this->file->getPath()));
10952 }
10953
10954 if (!is_readable($this->file->getPath())) {
10955 throw new \RuntimeException(sprintf('The file "%s" is not readable.', $this->file->getPath()));
10956 }
10957
10958 $contents = file_get_contents($this->file->getPath());
10959 } elseif ($this->authConfig) {
10960 $contents = "{\n}\n";
10961 } else {
10962 $contents = "{\n    \"config\": {\n    }\n}\n";
10963 }
10964
10965 $manipulator = new JsonManipulator($contents);
10966
10967 $newFile = !$this->file->exists();
10968
10969
10970 if ($this->authConfig && $method === 'addConfigSetting') {
10971 $method = 'addSubNode';
10972 list($mainNode, $name) = explode('.', $args[0], 2);
10973 $args = array($mainNode, $name, $args[1]);
10974 } elseif ($this->authConfig && $method === 'removeConfigSetting') {
10975 $method = 'removeSubNode';
10976 list($mainNode, $name) = explode('.', $args[0], 2);
10977 $args = array($mainNode, $name);
10978 }
10979
10980
10981 if (call_user_func_array(array($manipulator, $method), $args)) {
10982 file_put_contents($this->file->getPath(), $manipulator->getContents());
10983 } else {
10984
10985 $config = $this->file->read();
10986 $this->arrayUnshiftRef($args, $config);
10987 call_user_func_array($fallback, $args);
10988
10989 foreach (array('require', 'require-dev', 'conflict', 'provide', 'replace', 'suggest', 'config', 'autoload', 'autoload-dev') as $linkType) {
10990 if (isset($config[$linkType]) && $config[$linkType] === array()) {
10991 $config[$linkType] = new \stdClass;
10992 }
10993 }
10994 $this->file->write($config);
10995 }
10996
10997 if ($newFile) {
10998 Silencer::call('chmod', $this->file->getPath(), 0600);
10999 }
11000 }
11001
11002
11003
11004
11005
11006
11007
11008
11009 private function arrayUnshiftRef(&$array, &$value)
11010 {
11011 $return = array_unshift($array, '');
11012 $array[0] = &$value;
11013
11014 return $return;
11015 }
11016 }
11017 <?php
11018
11019
11020
11021
11022
11023
11024
11025
11026
11027
11028
11029 namespace Composer\Console;
11030
11031 use Composer\IO\NullIO;
11032 use Composer\Util\Platform;
11033 use Composer\Util\Silencer;
11034 use Symfony\Component\Console\Application as BaseApplication;
11035 use Symfony\Component\Console\Exception\CommandNotFoundException;
11036 use Symfony\Component\Console\Helper\HelperSet;
11037 use Symfony\Component\Console\Helper\QuestionHelper;
11038 use Symfony\Component\Console\Input\InputInterface;
11039 use Symfony\Component\Console\Input\InputOption;
11040 use Symfony\Component\Console\Output\OutputInterface;
11041 use Composer\Command;
11042 use Composer\Composer;
11043 use Composer\Factory;
11044 use Composer\IO\IOInterface;
11045 use Composer\IO\ConsoleIO;
11046 use Composer\Json\JsonValidationException;
11047 use Composer\Util\ErrorHandler;
11048 use Composer\EventDispatcher\ScriptExecutionException;
11049 use Composer\Exception\NoSslException;
11050
11051
11052
11053
11054
11055
11056
11057
11058 class Application extends BaseApplication
11059 {
11060
11061
11062
11063 protected $composer;
11064
11065
11066
11067
11068 protected $io;
11069
11070 private static $logo = '   ______
11071   / ____/___  ____ ___  ____  ____  ________  _____
11072  / /   / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
11073 / /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /
11074 \____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
11075                     /_/
11076 ';
11077
11078 private $hasPluginCommands = false;
11079 private $disablePluginsByDefault = false;
11080
11081
11082
11083
11084 private $initialWorkingDirectory = '';
11085
11086 public function __construct()
11087 {
11088 static $shutdownRegistered = false;
11089
11090 if (function_exists('ini_set') && extension_loaded('xdebug')) {
11091 ini_set('xdebug.show_exception_trace', false);
11092 ini_set('xdebug.scream', false);
11093 }
11094
11095 if (function_exists('date_default_timezone_set') && function_exists('date_default_timezone_get')) {
11096 date_default_timezone_set(Silencer::call('date_default_timezone_get'));
11097 }
11098
11099 if (!$shutdownRegistered) {
11100 $shutdownRegistered = true;
11101
11102 register_shutdown_function(function () {
11103 $lastError = error_get_last();
11104
11105 if ($lastError && $lastError['message'] &&
11106 (strpos($lastError['message'], 'Allowed memory') !== false  ||
11107 strpos($lastError['message'], 'exceeded memory') !== false )) {
11108 echo "\n". 'Check https://getcomposer.org/doc/articles/troubleshooting.md#memory-limit-errors for more info on how to handle out of memory errors.';
11109 }
11110 });
11111 }
11112
11113 $this->io = new NullIO();
11114
11115 $this->initialWorkingDirectory = getcwd();
11116
11117 parent::__construct('Composer', Composer::getVersion());
11118 }
11119
11120
11121
11122
11123 public function run(InputInterface $input = null, OutputInterface $output = null)
11124 {
11125 if (null === $output) {
11126 $output = Factory::createOutput();
11127 }
11128
11129 return parent::run($input, $output);
11130 }
11131
11132
11133
11134
11135 public function doRun(InputInterface $input, OutputInterface $output)
11136 {
11137 $this->disablePluginsByDefault = $input->hasParameterOption('--no-plugins');
11138
11139 if (getenv('COMPOSER_NO_INTERACTION')) {
11140 $input->setInteractive(false);
11141 }
11142
11143 $io = $this->io = new ConsoleIO($input, $output, new HelperSet(array(
11144 new QuestionHelper(),
11145 )));
11146 ErrorHandler::register($io);
11147
11148 if ($input->hasParameterOption('--no-cache')) {
11149 $io->writeError('Disabling cache usage', true, IOInterface::DEBUG);
11150 $_SERVER['COMPOSER_CACHE_DIR'] = Platform::isWindows() ? 'nul' : '/dev/null';
11151 putenv('COMPOSER_CACHE_DIR='.$_SERVER['COMPOSER_CACHE_DIR']);
11152 }
11153
11154
11155 if ($newWorkDir = $this->getNewWorkingDir($input)) {
11156 $oldWorkingDir = getcwd();
11157 chdir($newWorkDir);
11158 $this->initialWorkingDirectory = $newWorkDir;
11159 $io->writeError('Changed CWD to ' . getcwd(), true, IOInterface::DEBUG);
11160 }
11161
11162
11163 $commandName = '';
11164 if ($name = $this->getCommandName($input)) {
11165 try {
11166 $commandName = $this->find($name)->getName();
11167 } catch (CommandNotFoundException $e) {
11168
11169 $commandName = false;
11170 } catch (\InvalidArgumentException $e) {
11171 }
11172 }
11173
11174
11175 if ($io->isInteractive() && !$newWorkDir && !in_array($commandName, array('', 'list', 'init', 'about', 'help', 'diagnose', 'self-update', 'global', 'create-project', 'outdated'), true) && !file_exists(Factory::getComposerFile())) {
11176 $dir = dirname(getcwd());
11177 $home = realpath(getenv('HOME') ?: getenv('USERPROFILE') ?: '/');
11178
11179
11180 while (dirname($dir) !== $dir && $dir !== $home) {
11181 if (file_exists($dir.'/'.Factory::getComposerFile())) {
11182 if ($io->askConfirmation('<info>No composer.json in current directory, do you want to use the one at '.$dir.'?</info> [<comment>Y,n</comment>]? ', true)) {
11183 $oldWorkingDir = getcwd();
11184 chdir($dir);
11185 }
11186 break;
11187 }
11188 $dir = dirname($dir);
11189 }
11190 }
11191
11192 if (!$this->disablePluginsByDefault && !$this->hasPluginCommands && 'global' !== $commandName) {
11193 try {
11194 foreach ($this->getPluginCommands() as $command) {
11195 if ($this->has($command->getName())) {
11196 $io->writeError('<warning>Plugin command '.$command->getName().' ('.get_class($command).') would override a Composer command and has been skipped</warning>');
11197 } else {
11198 $this->add($command);
11199 }
11200 }
11201 } catch (NoSslException $e) {
11202
11203 }
11204
11205 $this->hasPluginCommands = true;
11206 }
11207
11208
11209 $isProxyCommand = false;
11210 if ($name = $this->getCommandName($input)) {
11211 try {
11212 $command = $this->find($name);
11213 $commandName = $command->getName();
11214 $isProxyCommand = ($command instanceof Command\BaseCommand && $command->isProxyCommand());
11215 } catch (\InvalidArgumentException $e) {
11216 }
11217 }
11218
11219 if (!$isProxyCommand) {
11220 $io->writeError(sprintf(
11221 'Running %s (%s) with %s on %s',
11222 Composer::getVersion(),
11223 Composer::RELEASE_DATE,
11224 defined('HHVM_VERSION') ? 'HHVM '.HHVM_VERSION : 'PHP '.PHP_VERSION,
11225 function_exists('php_uname') ? php_uname('s') . ' / ' . php_uname('r') : 'Unknown OS'
11226 ), true, IOInterface::DEBUG);
11227
11228 if (PHP_VERSION_ID < 50302) {
11229 $io->writeError('<warning>Composer only officially supports PHP 5.3.2 and above, you will most likely encounter problems with your PHP '.PHP_VERSION.', upgrading is strongly recommended.</warning>');
11230 }
11231
11232 if (extension_loaded('xdebug') && !getenv('COMPOSER_DISABLE_XDEBUG_WARN')) {
11233 $io->writeError('<warning>You are running composer with Xdebug enabled. This has a major impact on runtime performance. See https://getcomposer.org/xdebug</warning>');
11234 }
11235
11236 if (defined('COMPOSER_DEV_WARNING_TIME') && $commandName !== 'self-update' && $commandName !== 'selfupdate' && time() > COMPOSER_DEV_WARNING_TIME) {
11237 $io->writeError(sprintf('<warning>Warning: This development build of composer is over 60 days old. It is recommended to update it by running "%s self-update" to get the latest version.</warning>', $_SERVER['PHP_SELF']));
11238 }
11239
11240 if (
11241 !Platform::isWindows()
11242 && function_exists('exec')
11243 && !getenv('COMPOSER_ALLOW_SUPERUSER')
11244 && (ini_get('open_basedir') || !file_exists('/.dockerenv'))
11245 ) {
11246 if (function_exists('posix_getuid') && posix_getuid() === 0) {
11247 if ($commandName !== 'self-update' && $commandName !== 'selfupdate') {
11248 $io->writeError('<warning>Do not run Composer as root/super user! See https://getcomposer.org/root for details</warning>');
11249 }
11250 if ($uid = (int) getenv('SUDO_UID')) {
11251
11252
11253 Silencer::call('exec', "sudo -u \\#{$uid} sudo -K > /dev/null 2>&1");
11254 }
11255 }
11256
11257 Silencer::call('exec', 'sudo -K > /dev/null 2>&1');
11258 }
11259
11260
11261 Silencer::call(function () use ($io) {
11262 $tempfile = sys_get_temp_dir() . '/temp-' . md5(microtime());
11263 if (!(file_put_contents($tempfile, __FILE__) && (file_get_contents($tempfile) == __FILE__) && unlink($tempfile) && !file_exists($tempfile))) {
11264 $io->writeError(sprintf('<error>PHP temp directory (%s) does not exist or is not writable to Composer. Set sys_temp_dir in your php.ini</error>', sys_get_temp_dir()));
11265 }
11266 });
11267
11268
11269 $file = Factory::getComposerFile();
11270 if (is_file($file) && is_readable($file) && is_array($composer = json_decode(file_get_contents($file), true))) {
11271 if (isset($composer['scripts']) && is_array($composer['scripts'])) {
11272 foreach ($composer['scripts'] as $script => $dummy) {
11273 if (!defined('Composer\Script\ScriptEvents::'.str_replace('-', '_', strtoupper($script)))) {
11274 if ($this->has($script)) {
11275 $io->writeError('<warning>A script named '.$script.' would override a Composer command and has been skipped</warning>');
11276 } else {
11277 $description = null;
11278
11279 if (isset($composer['scripts-descriptions'][$script])) {
11280 $description = $composer['scripts-descriptions'][$script];
11281 }
11282
11283 $this->add(new Command\ScriptAliasCommand($script, $description));
11284 }
11285 }
11286 }
11287 }
11288 }
11289 }
11290
11291 try {
11292 if ($input->hasParameterOption('--profile')) {
11293 $startTime = microtime(true);
11294 $this->io->enableDebugging($startTime);
11295 }
11296
11297 $result = parent::doRun($input, $output);
11298
11299 if (isset($oldWorkingDir)) {
11300 chdir($oldWorkingDir);
11301 }
11302
11303 if (isset($startTime)) {
11304 $io->writeError('<info>Memory usage: '.round(memory_get_usage() / 1024 / 1024, 2).'MiB (peak: '.round(memory_get_peak_usage() / 1024 / 1024, 2).'MiB), time: '.round(microtime(true) - $startTime, 2).'s');
11305 }
11306
11307 restore_error_handler();
11308
11309 return $result;
11310 } catch (ScriptExecutionException $e) {
11311 return $e->getCode();
11312 } catch (\Exception $e) {
11313 $this->hintCommonErrors($e);
11314 restore_error_handler();
11315 throw $e;
11316 }
11317 }
11318
11319
11320
11321
11322
11323
11324 private function getNewWorkingDir(InputInterface $input)
11325 {
11326 $workingDir = $input->getParameterOption(array('--working-dir', '-d'));
11327 if (false !== $workingDir && !is_dir($workingDir)) {
11328 throw new \RuntimeException('Invalid working directory specified, '.$workingDir.' does not exist.');
11329 }
11330
11331 return $workingDir;
11332 }
11333
11334
11335
11336
11337 private function hintCommonErrors($exception)
11338 {
11339 $io = $this->getIO();
11340
11341 Silencer::suppress();
11342 try {
11343 $composer = $this->getComposer(false, true);
11344 if ($composer) {
11345 $config = $composer->getConfig();
11346
11347 $minSpaceFree = 1024 * 1024;
11348 if ((($df = disk_free_space($dir = $config->get('home'))) !== false && $df < $minSpaceFree)
11349 || (($df = disk_free_space($dir = $config->get('vendor-dir'))) !== false && $df < $minSpaceFree)
11350 || (($df = disk_free_space($dir = sys_get_temp_dir())) !== false && $df < $minSpaceFree)
11351 ) {
11352 $io->writeError('<error>The disk hosting '.$dir.' is full, this may be the cause of the following exception</error>', true, IOInterface::QUIET);
11353 }
11354 }
11355 } catch (\Exception $e) {
11356 }
11357 Silencer::restore();
11358
11359 if (Platform::isWindows() && false !== strpos($exception->getMessage(), 'The system cannot find the path specified')) {
11360 $io->writeError('<error>The following exception may be caused by a stale entry in your cmd.exe AutoRun</error>', true, IOInterface::QUIET);
11361 $io->writeError('<error>Check https://getcomposer.org/doc/articles/troubleshooting.md#-the-system-cannot-find-the-path-specified-windows- for details</error>', true, IOInterface::QUIET);
11362 }
11363
11364 if (false !== strpos($exception->getMessage(), 'fork failed - Cannot allocate memory')) {
11365 $io->writeError('<error>The following exception is caused by a lack of memory or swap, or not having swap configured</error>', true, IOInterface::QUIET);
11366 $io->writeError('<error>Check https://getcomposer.org/doc/articles/troubleshooting.md#proc-open-fork-failed-errors for details</error>', true, IOInterface::QUIET);
11367 }
11368 }
11369
11370
11371
11372
11373
11374
11375
11376 public function getComposer($required = true, $disablePlugins = null)
11377 {
11378 if (null === $disablePlugins) {
11379 $disablePlugins = $this->disablePluginsByDefault;
11380 }
11381
11382 if (null === $this->composer) {
11383 try {
11384 $this->composer = Factory::create($this->io, null, $disablePlugins);
11385 } catch (\InvalidArgumentException $e) {
11386 if ($required) {
11387 $this->io->writeError($e->getMessage());
11388 exit(1);
11389 }
11390 } catch (JsonValidationException $e) {
11391 $errors = ' - ' . implode(PHP_EOL . ' - ', $e->getErrors());
11392 $message = $e->getMessage() . ':' . PHP_EOL . $errors;
11393 throw new JsonValidationException($message);
11394 }
11395 }
11396
11397 return $this->composer;
11398 }
11399
11400
11401
11402
11403 public function resetComposer()
11404 {
11405 $this->composer = null;
11406 if ($this->getIO() && method_exists($this->getIO(), 'resetAuthentications')) {
11407 $this->getIO()->resetAuthentications();
11408 }
11409 }
11410
11411
11412
11413
11414 public function getIO()
11415 {
11416 return $this->io;
11417 }
11418
11419 public function getHelp()
11420 {
11421 return self::$logo . parent::getHelp();
11422 }
11423
11424
11425
11426
11427 protected function getDefaultCommands()
11428 {
11429 $commands = array_merge(parent::getDefaultCommands(), array(
11430 new Command\AboutCommand(),
11431 new Command\ConfigCommand(),
11432 new Command\DependsCommand(),
11433 new Command\ProhibitsCommand(),
11434 new Command\InitCommand(),
11435 new Command\InstallCommand(),
11436 new Command\CreateProjectCommand(),
11437 new Command\UpdateCommand(),
11438 new Command\SearchCommand(),
11439 new Command\ValidateCommand(),
11440 new Command\ShowCommand(),
11441 new Command\SuggestsCommand(),
11442 new Command\RequireCommand(),
11443 new Command\DumpAutoloadCommand(),
11444 new Command\StatusCommand(),
11445 new Command\ArchiveCommand(),
11446 new Command\DiagnoseCommand(),
11447 new Command\RunScriptCommand(),
11448 new Command\LicensesCommand(),
11449 new Command\GlobalCommand(),
11450 new Command\ClearCacheCommand(),
11451 new Command\RemoveCommand(),
11452 new Command\HomeCommand(),
11453 new Command\ExecCommand(),
11454 new Command\OutdatedCommand(),
11455 new Command\CheckPlatformReqsCommand(),
11456 new Command\FundCommand(),
11457 ));
11458
11459 if ('phar:' === substr(__FILE__, 0, 5)) {
11460 $commands[] = new Command\SelfUpdateCommand();
11461 }
11462
11463 return $commands;
11464 }
11465
11466
11467
11468
11469 public function getLongVersion()
11470 {
11471 if (Composer::BRANCH_ALIAS_VERSION && Composer::BRANCH_ALIAS_VERSION !== '@package_branch_alias_version'.'@') {
11472 return sprintf(
11473 '<info>%s</info> version <comment>%s (%s)</comment> %s',
11474 $this->getName(),
11475 Composer::BRANCH_ALIAS_VERSION,
11476 $this->getVersion(),
11477 Composer::RELEASE_DATE
11478 );
11479 }
11480
11481 return parent::getLongVersion() . ' ' . Composer::RELEASE_DATE;
11482 }
11483
11484
11485
11486
11487 protected function getDefaultInputDefinition()
11488 {
11489 $definition = parent::getDefaultInputDefinition();
11490 $definition->addOption(new InputOption('--profile', null, InputOption::VALUE_NONE, 'Display timing and memory usage information'));
11491 $definition->addOption(new InputOption('--no-plugins', null, InputOption::VALUE_NONE, 'Whether to disable plugins.'));
11492 $definition->addOption(new InputOption('--working-dir', '-d', InputOption::VALUE_REQUIRED, 'If specified, use the given directory as working directory.'));
11493 $definition->addOption(new InputOption('--no-cache', null, InputOption::VALUE_NONE, 'Prevent use of the cache'));
11494
11495 return $definition;
11496 }
11497
11498 private function getPluginCommands()
11499 {
11500 $commands = array();
11501
11502 $composer = $this->getComposer(false, false);
11503 if (null === $composer) {
11504 $composer = Factory::createGlobal($this->io, false);
11505 }
11506
11507 if (null !== $composer) {
11508 $pm = $composer->getPluginManager();
11509 foreach ($pm->getPluginCapabilities('Composer\Plugin\Capability\CommandProvider', array('composer' => $composer, 'io' => $this->io)) as $capability) {
11510 $newCommands = $capability->getCommands();
11511 if (!is_array($newCommands)) {
11512 throw new \UnexpectedValueException('Plugin capability '.get_class($capability).' failed to return an array from getCommands');
11513 }
11514 foreach ($newCommands as $command) {
11515 if (!$command instanceof Command\BaseCommand) {
11516 throw new \UnexpectedValueException('Plugin capability '.get_class($capability).' returned an invalid value, we expected an array of Composer\Command\BaseCommand objects');
11517 }
11518 }
11519 $commands = array_merge($commands, $newCommands);
11520 }
11521 }
11522
11523 return $commands;
11524 }
11525
11526
11527
11528
11529
11530
11531 public function getInitialWorkingDirectory()
11532 {
11533 return $this->initialWorkingDirectory;
11534 }
11535 }
11536 <?php
11537
11538
11539
11540
11541
11542
11543
11544
11545
11546
11547
11548 namespace Composer\Console;
11549
11550 use Symfony\Component\Console\Formatter\OutputFormatter;
11551
11552
11553
11554
11555 class HtmlOutputFormatter extends OutputFormatter
11556 {
11557 private static $availableForegroundColors = array(
11558 30 => 'black',
11559 31 => 'red',
11560 32 => 'green',
11561 33 => 'yellow',
11562 34 => 'blue',
11563 35 => 'magenta',
11564 36 => 'cyan',
11565 37 => 'white',
11566 );
11567 private static $availableBackgroundColors = array(
11568 40 => 'black',
11569 41 => 'red',
11570 42 => 'green',
11571 43 => 'yellow',
11572 44 => 'blue',
11573 45 => 'magenta',
11574 46 => 'cyan',
11575 47 => 'white',
11576 );
11577 private static $availableOptions = array(
11578 1 => 'bold',
11579 4 => 'underscore',
11580
11581
11582
11583 );
11584
11585
11586
11587
11588 public function __construct(array $styles = array())
11589 {
11590 parent::__construct(true, $styles);
11591 }
11592
11593 public function format($message)
11594 {
11595 $formatted = parent::format($message);
11596
11597 $clearEscapeCodes = '(?:39|49|0|22|24|25|27|28)';
11598
11599 return preg_replace_callback("{\033\[([0-9;]+)m(.*?)\033\[(?:".$clearEscapeCodes.";)*?".$clearEscapeCodes."m}s", array($this, 'formatHtml'), $formatted);
11600 }
11601
11602 private function formatHtml($matches)
11603 {
11604 $out = '<span style="';
11605 foreach (explode(';', $matches[1]) as $code) {
11606 if (isset(self::$availableForegroundColors[$code])) {
11607 $out .= 'color:'.self::$availableForegroundColors[$code].';';
11608 } elseif (isset(self::$availableBackgroundColors[$code])) {
11609 $out .= 'background-color:'.self::$availableBackgroundColors[$code].';';
11610 } elseif (isset(self::$availableOptions[$code])) {
11611 switch (self::$availableOptions[$code]) {
11612 case 'bold':
11613 $out .= 'font-weight:bold;';
11614 break;
11615
11616 case 'underscore':
11617 $out .= 'text-decoration:underline;';
11618 break;
11619 }
11620 }
11621 }
11622
11623 return $out.'">'.$matches[2].'</span>';
11624 }
11625 }
11626 <?php
11627
11628
11629
11630
11631
11632
11633
11634
11635
11636
11637
11638 namespace Composer\DependencyResolver;
11639
11640
11641
11642
11643
11644
11645 class Decisions implements \Iterator, \Countable
11646 {
11647 const DECISION_LITERAL = 0;
11648 const DECISION_REASON = 1;
11649
11650 protected $pool;
11651 protected $decisionMap;
11652 protected $decisionQueue = array();
11653
11654 public function __construct($pool)
11655 {
11656 $this->pool = $pool;
11657 $this->decisionMap = array();
11658 }
11659
11660 public function decide($literal, $level, $why)
11661 {
11662 $this->addDecision($literal, $level);
11663 $this->decisionQueue[] = array(
11664 self::DECISION_LITERAL => $literal,
11665 self::DECISION_REASON => $why,
11666 );
11667 }
11668
11669 public function satisfy($literal)
11670 {
11671 $packageId = abs($literal);
11672
11673 return (
11674 $literal > 0 && isset($this->decisionMap[$packageId]) && $this->decisionMap[$packageId] > 0 ||
11675 $literal < 0 && isset($this->decisionMap[$packageId]) && $this->decisionMap[$packageId] < 0
11676 );
11677 }
11678
11679 public function conflict($literal)
11680 {
11681 $packageId = abs($literal);
11682
11683 return (
11684 (isset($this->decisionMap[$packageId]) && $this->decisionMap[$packageId] > 0 && $literal < 0) ||
11685 (isset($this->decisionMap[$packageId]) && $this->decisionMap[$packageId] < 0 && $literal > 0)
11686 );
11687 }
11688
11689 public function decided($literalOrPackageId)
11690 {
11691 return !empty($this->decisionMap[abs($literalOrPackageId)]);
11692 }
11693
11694 public function undecided($literalOrPackageId)
11695 {
11696 return empty($this->decisionMap[abs($literalOrPackageId)]);
11697 }
11698
11699 public function decidedInstall($literalOrPackageId)
11700 {
11701 $packageId = abs($literalOrPackageId);
11702
11703 return isset($this->decisionMap[$packageId]) && $this->decisionMap[$packageId] > 0;
11704 }
11705
11706 public function decisionLevel($literalOrPackageId)
11707 {
11708 $packageId = abs($literalOrPackageId);
11709 if (isset($this->decisionMap[$packageId])) {
11710 return abs($this->decisionMap[$packageId]);
11711 }
11712
11713 return 0;
11714 }
11715
11716 public function decisionRule($literalOrPackageId)
11717 {
11718 $packageId = abs($literalOrPackageId);
11719
11720 foreach ($this->decisionQueue as $i => $decision) {
11721 if ($packageId === abs($decision[self::DECISION_LITERAL])) {
11722 return $decision[self::DECISION_REASON];
11723 }
11724 }
11725
11726 return null;
11727 }
11728
11729 public function atOffset($queueOffset)
11730 {
11731 return $this->decisionQueue[$queueOffset];
11732 }
11733
11734 public function validOffset($queueOffset)
11735 {
11736 return $queueOffset >= 0 && $queueOffset < count($this->decisionQueue);
11737 }
11738
11739 public function lastReason()
11740 {
11741 return $this->decisionQueue[count($this->decisionQueue) - 1][self::DECISION_REASON];
11742 }
11743
11744 public function lastLiteral()
11745 {
11746 return $this->decisionQueue[count($this->decisionQueue) - 1][self::DECISION_LITERAL];
11747 }
11748
11749 public function reset()
11750 {
11751 while ($decision = array_pop($this->decisionQueue)) {
11752 $this->decisionMap[abs($decision[self::DECISION_LITERAL])] = 0;
11753 }
11754 }
11755
11756 public function resetToOffset($offset)
11757 {
11758 while (count($this->decisionQueue) > $offset + 1) {
11759 $decision = array_pop($this->decisionQueue);
11760 $this->decisionMap[abs($decision[self::DECISION_LITERAL])] = 0;
11761 }
11762 }
11763
11764 public function revertLast()
11765 {
11766 $this->decisionMap[abs($this->lastLiteral())] = 0;
11767 array_pop($this->decisionQueue);
11768 }
11769
11770 public function count()
11771 {
11772 return count($this->decisionQueue);
11773 }
11774
11775 public function rewind()
11776 {
11777 end($this->decisionQueue);
11778 }
11779
11780 public function current()
11781 {
11782 return current($this->decisionQueue);
11783 }
11784
11785 public function key()
11786 {
11787 return key($this->decisionQueue);
11788 }
11789
11790 public function next()
11791 {
11792 return prev($this->decisionQueue);
11793 }
11794
11795 public function valid()
11796 {
11797 return false !== current($this->decisionQueue);
11798 }
11799
11800 public function isEmpty()
11801 {
11802 return count($this->decisionQueue) === 0;
11803 }
11804
11805 protected function addDecision($literal, $level)
11806 {
11807 $packageId = abs($literal);
11808
11809 $previousDecision = isset($this->decisionMap[$packageId]) ? $this->decisionMap[$packageId] : null;
11810 if ($previousDecision != 0) {
11811 $literalString = $this->pool->literalToPrettyString($literal, array());
11812 $package = $this->pool->literalToPackage($literal);
11813 throw new SolverBugException(
11814 "Trying to decide $literalString on level $level, even though $package was previously decided as ".(int) $previousDecision."."
11815 );
11816 }
11817
11818 if ($literal > 0) {
11819 $this->decisionMap[$packageId] = $level;
11820 } else {
11821 $this->decisionMap[$packageId] = -$level;
11822 }
11823 }
11824
11825 public function __toString()
11826 {
11827 $decisionMap = $this->decisionMap;
11828 ksort($decisionMap);
11829 $str = '[';
11830 foreach ($decisionMap as $packageId => $level) {
11831 $str .= $packageId.':'.$level.',';
11832 }
11833 $str .= ']';
11834 return $str;
11835 }
11836 }
11837 <?php
11838
11839
11840
11841
11842
11843
11844
11845
11846
11847
11848
11849 namespace Composer\DependencyResolver;
11850
11851 use Composer\Package\PackageInterface;
11852 use Composer\Package\AliasPackage;
11853 use Composer\Package\BasePackage;
11854 use Composer\Semver\Constraint\Constraint;
11855
11856
11857
11858
11859
11860 class DefaultPolicy implements PolicyInterface
11861 {
11862 private $preferStable;
11863 private $preferLowest;
11864
11865 public function __construct($preferStable = false, $preferLowest = false)
11866 {
11867 $this->preferStable = $preferStable;
11868 $this->preferLowest = $preferLowest;
11869 }
11870
11871 public function versionCompare(PackageInterface $a, PackageInterface $b, $operator)
11872 {
11873 if ($this->preferStable && ($stabA = $a->getStability()) !== ($stabB = $b->getStability())) {
11874 return BasePackage::$stabilities[$stabA] < BasePackage::$stabilities[$stabB];
11875 }
11876
11877 $constraint = new Constraint($operator, $b->getVersion());
11878 $version = new Constraint('==', $a->getVersion());
11879
11880 return $constraint->matchSpecific($version, true);
11881 }
11882
11883 public function findUpdatePackages(Pool $pool, array $installedMap, PackageInterface $package, $mustMatchName = false)
11884 {
11885 $packages = array();
11886
11887 foreach ($pool->whatProvides($package->getName(), null, $mustMatchName) as $candidate) {
11888 if ($candidate !== $package) {
11889 $packages[] = $candidate;
11890 }
11891 }
11892
11893 return $packages;
11894 }
11895
11896 public function getPriority(Pool $pool, PackageInterface $package)
11897 {
11898 return $pool->getPriority($package->getRepository());
11899 }
11900
11901 public function selectPreferredPackages(Pool $pool, array $installedMap, array $literals, $requiredPackage = null)
11902 {
11903 $packages = $this->groupLiteralsByNamePreferInstalled($pool, $installedMap, $literals);
11904
11905 foreach ($packages as &$literals) {
11906 $policy = $this;
11907 usort($literals, function ($a, $b) use ($policy, $pool, $installedMap, $requiredPackage) {
11908 return $policy->compareByPriorityPreferInstalled($pool, $installedMap, $pool->literalToPackage($a), $pool->literalToPackage($b), $requiredPackage, true);
11909 });
11910 }
11911
11912 foreach ($packages as &$literals) {
11913 $literals = $this->pruneToHighestPriorityOrInstalled($pool, $installedMap, $literals);
11914
11915 $literals = $this->pruneToBestVersion($pool, $literals);
11916
11917 $literals = $this->pruneRemoteAliases($pool, $literals);
11918 }
11919
11920 $selected = call_user_func_array('array_merge', array_values($packages));
11921
11922
11923 usort($selected, function ($a, $b) use ($policy, $pool, $installedMap, $requiredPackage) {
11924 return $policy->compareByPriorityPreferInstalled($pool, $installedMap, $pool->literalToPackage($a), $pool->literalToPackage($b), $requiredPackage);
11925 });
11926
11927 return $selected;
11928 }
11929
11930 protected function groupLiteralsByNamePreferInstalled(Pool $pool, array $installedMap, $literals)
11931 {
11932 $packages = array();
11933 foreach ($literals as $literal) {
11934 $packageName = $pool->literalToPackage($literal)->getName();
11935
11936 if (!isset($packages[$packageName])) {
11937 $packages[$packageName] = array();
11938 }
11939
11940 if (isset($installedMap[abs($literal)])) {
11941 array_unshift($packages[$packageName], $literal);
11942 } else {
11943 $packages[$packageName][] = $literal;
11944 }
11945 }
11946
11947 return $packages;
11948 }
11949
11950
11951
11952
11953 public function compareByPriorityPreferInstalled(Pool $pool, array $installedMap, PackageInterface $a, PackageInterface $b, $requiredPackage = null, $ignoreReplace = false)
11954 {
11955 if ($a->getRepository() === $b->getRepository()) {
11956
11957 if ($a->getName() === $b->getName()) {
11958 $aAliased = $a instanceof AliasPackage;
11959 $bAliased = $b instanceof AliasPackage;
11960 if ($aAliased && !$bAliased) {
11961 return -1; 
11962 }
11963 if (!$aAliased && $bAliased) {
11964 return 1; 
11965 }
11966 }
11967
11968 if (!$ignoreReplace) {
11969
11970 if ($this->replaces($a, $b)) {
11971 return 1; 
11972 }
11973 if ($this->replaces($b, $a)) {
11974 return -1; 
11975 }
11976
11977
11978
11979 if ($requiredPackage && false !== ($pos = strpos($requiredPackage, '/'))) {
11980 $requiredVendor = substr($requiredPackage, 0, $pos);
11981
11982 $aIsSameVendor = substr($a->getName(), 0, $pos) === $requiredVendor;
11983 $bIsSameVendor = substr($b->getName(), 0, $pos) === $requiredVendor;
11984
11985 if ($bIsSameVendor !== $aIsSameVendor) {
11986 return $aIsSameVendor ? -1 : 1;
11987 }
11988 }
11989 }
11990
11991
11992 if ($a->id === $b->id) {
11993 return 0;
11994 }
11995
11996 return ($a->id < $b->id) ? -1 : 1;
11997 }
11998
11999 if (isset($installedMap[$a->id])) {
12000 return -1;
12001 }
12002
12003 if (isset($installedMap[$b->id])) {
12004 return 1;
12005 }
12006
12007 return ($this->getPriority($pool, $a) > $this->getPriority($pool, $b)) ? -1 : 1;
12008 }
12009
12010
12011
12012
12013
12014
12015
12016
12017
12018
12019
12020 protected function replaces(PackageInterface $source, PackageInterface $target)
12021 {
12022 foreach ($source->getReplaces() as $link) {
12023 if ($link->getTarget() === $target->getName()
12024
12025
12026 ) {
12027 return true;
12028 }
12029 }
12030
12031 return false;
12032 }
12033
12034 protected function pruneToBestVersion(Pool $pool, $literals)
12035 {
12036 $operator = $this->preferLowest ? '<' : '>';
12037 $bestLiterals = array($literals[0]);
12038 $bestPackage = $pool->literalToPackage($literals[0]);
12039 foreach ($literals as $i => $literal) {
12040 if (0 === $i) {
12041 continue;
12042 }
12043
12044 $package = $pool->literalToPackage($literal);
12045
12046 if ($this->versionCompare($package, $bestPackage, $operator)) {
12047 $bestPackage = $package;
12048 $bestLiterals = array($literal);
12049 } elseif ($this->versionCompare($package, $bestPackage, '==')) {
12050 $bestLiterals[] = $literal;
12051 }
12052 }
12053
12054 return $bestLiterals;
12055 }
12056
12057
12058
12059
12060 protected function pruneToHighestPriorityOrInstalled(Pool $pool, array $installedMap, array $literals)
12061 {
12062 $selected = array();
12063
12064 $priority = null;
12065
12066 foreach ($literals as $literal) {
12067 $package = $pool->literalToPackage($literal);
12068
12069 if (isset($installedMap[$package->id])) {
12070 $selected[] = $literal;
12071 continue;
12072 }
12073
12074 if (null === $priority) {
12075 $priority = $this->getPriority($pool, $package);
12076 }
12077
12078 if ($this->getPriority($pool, $package) != $priority) {
12079 break;
12080 }
12081
12082 $selected[] = $literal;
12083 }
12084
12085 return $selected;
12086 }
12087
12088
12089
12090
12091
12092
12093 protected function pruneRemoteAliases(Pool $pool, array $literals)
12094 {
12095 $hasLocalAlias = false;
12096
12097 foreach ($literals as $literal) {
12098 $package = $pool->literalToPackage($literal);
12099
12100 if ($package instanceof AliasPackage && $package->isRootPackageAlias()) {
12101 $hasLocalAlias = true;
12102 break;
12103 }
12104 }
12105
12106 if (!$hasLocalAlias) {
12107 return $literals;
12108 }
12109
12110 $selected = array();
12111 foreach ($literals as $literal) {
12112 $package = $pool->literalToPackage($literal);
12113
12114 if ($package instanceof AliasPackage && $package->isRootPackageAlias()) {
12115 $selected[] = $literal;
12116 }
12117 }
12118
12119 return $selected;
12120 }
12121 }
12122 <?php
12123
12124
12125
12126
12127
12128
12129
12130
12131
12132
12133
12134 namespace Composer\DependencyResolver;
12135
12136 use Composer\Package\PackageInterface;
12137 use Composer\Package\Link;
12138
12139
12140
12141
12142 class GenericRule extends Rule
12143 {
12144 protected $literals;
12145
12146
12147
12148
12149
12150
12151
12152 public function __construct(array $literals, $reason, $reasonData, $job = null)
12153 {
12154 parent::__construct($reason, $reasonData, $job);
12155
12156
12157 sort($literals);
12158
12159 $this->literals = $literals;
12160 }
12161
12162 public function getLiterals()
12163 {
12164 return $this->literals;
12165 }
12166
12167 public function getHash()
12168 {
12169 $data = unpack('ihash', md5(implode(',', $this->literals), true));
12170
12171 return $data['hash'];
12172 }
12173
12174
12175
12176
12177
12178
12179
12180
12181
12182 public function equals(Rule $rule)
12183 {
12184 return $this->literals === $rule->getLiterals();
12185 }
12186
12187 public function isAssertion()
12188 {
12189 return 1 === count($this->literals);
12190 }
12191
12192
12193
12194
12195
12196
12197 public function __toString()
12198 {
12199 $result = $this->isDisabled() ? 'disabled(' : '(';
12200
12201 foreach ($this->literals as $i => $literal) {
12202 if ($i != 0) {
12203 $result .= '|';
12204 }
12205 $result .= $literal;
12206 }
12207
12208 $result .= ')';
12209
12210 return $result;
12211 }
12212 }
12213 <?php
12214
12215
12216
12217
12218
12219
12220
12221
12222
12223
12224
12225 namespace Composer\DependencyResolver\Operation;
12226
12227 use Composer\Package\PackageInterface;
12228
12229
12230
12231
12232
12233
12234 class InstallOperation extends SolverOperation
12235 {
12236 protected $package;
12237
12238
12239
12240
12241
12242
12243
12244 public function __construct(PackageInterface $package, $reason = null)
12245 {
12246 parent::__construct($reason);
12247
12248 $this->package = $package;
12249 }
12250
12251
12252
12253
12254
12255
12256 public function getPackage()
12257 {
12258 return $this->package;
12259 }
12260
12261
12262
12263
12264
12265
12266 public function getJobType()
12267 {
12268 return 'install';
12269 }
12270
12271
12272
12273
12274 public function __toString()
12275 {
12276 return 'Installing '.$this->package->getPrettyName().' ('.$this->formatVersion($this->package).')';
12277 }
12278 }
12279 <?php
12280
12281
12282
12283
12284
12285
12286
12287
12288
12289
12290
12291 namespace Composer\DependencyResolver\Operation;
12292
12293 use Composer\Package\AliasPackage;
12294 use Composer\Package\PackageInterface;
12295
12296
12297
12298
12299
12300
12301 class MarkAliasInstalledOperation extends SolverOperation
12302 {
12303 protected $package;
12304
12305
12306
12307
12308
12309
12310
12311 public function __construct(AliasPackage $package, $reason = null)
12312 {
12313 parent::__construct($reason);
12314
12315 $this->package = $package;
12316 }
12317
12318
12319
12320
12321
12322
12323 public function getPackage()
12324 {
12325 return $this->package;
12326 }
12327
12328
12329
12330
12331
12332
12333 public function getJobType()
12334 {
12335 return 'markAliasInstalled';
12336 }
12337
12338
12339
12340
12341 public function __toString()
12342 {
12343 return 'Marking '.$this->package->getPrettyName().' ('.$this->formatVersion($this->package).') as installed, alias of '.$this->package->getAliasOf()->getPrettyName().' ('.$this->formatVersion($this->package->getAliasOf()).')';
12344 }
12345 }
12346 <?php
12347
12348
12349
12350
12351
12352
12353
12354
12355
12356
12357
12358 namespace Composer\DependencyResolver\Operation;
12359
12360 use Composer\Package\AliasPackage;
12361 use Composer\Package\PackageInterface;
12362
12363
12364
12365
12366
12367
12368 class MarkAliasUninstalledOperation extends SolverOperation
12369 {
12370 protected $package;
12371
12372
12373
12374
12375
12376
12377
12378 public function __construct(AliasPackage $package, $reason = null)
12379 {
12380 parent::__construct($reason);
12381
12382 $this->package = $package;
12383 }
12384
12385
12386
12387
12388
12389
12390 public function getPackage()
12391 {
12392 return $this->package;
12393 }
12394
12395
12396
12397
12398
12399
12400 public function getJobType()
12401 {
12402 return 'markAliasUninstalled';
12403 }
12404
12405
12406
12407
12408 public function __toString()
12409 {
12410 return 'Marking '.$this->package->getPrettyName().' ('.$this->formatVersion($this->package).') as uninstalled, alias of '.$this->package->getAliasOf()->getPrettyName().' ('.$this->formatVersion($this->package->getAliasOf()).')';
12411 }
12412 }
12413 <?php
12414
12415
12416
12417
12418
12419
12420
12421
12422
12423
12424
12425 namespace Composer\DependencyResolver\Operation;
12426
12427
12428
12429
12430
12431
12432 interface OperationInterface
12433 {
12434
12435
12436
12437
12438
12439 public function getJobType();
12440
12441
12442
12443
12444
12445
12446 public function getReason();
12447
12448
12449
12450
12451
12452
12453 public function __toString();
12454 }
12455 <?php
12456
12457
12458
12459
12460
12461
12462
12463
12464
12465
12466
12467 namespace Composer\DependencyResolver\Operation;
12468
12469 use Composer\Package\PackageInterface;
12470
12471
12472
12473
12474
12475
12476 abstract class SolverOperation implements OperationInterface
12477 {
12478 protected $reason;
12479
12480
12481
12482
12483
12484
12485 public function __construct($reason = null)
12486 {
12487 $this->reason = $reason;
12488 }
12489
12490
12491
12492
12493
12494
12495 public function getReason()
12496 {
12497 return $this->reason;
12498 }
12499
12500 protected function formatVersion(PackageInterface $package)
12501 {
12502 return $package->getFullPrettyVersion();
12503 }
12504 }
12505 <?php
12506
12507
12508
12509
12510
12511
12512
12513
12514
12515
12516
12517 namespace Composer\DependencyResolver\Operation;
12518
12519 use Composer\Package\PackageInterface;
12520
12521
12522
12523
12524
12525
12526 class UninstallOperation extends SolverOperation
12527 {
12528 protected $package;
12529
12530
12531
12532
12533
12534
12535
12536 public function __construct(PackageInterface $package, $reason = null)
12537 {
12538 parent::__construct($reason);
12539
12540 $this->package = $package;
12541 }
12542
12543
12544
12545
12546
12547
12548 public function getPackage()
12549 {
12550 return $this->package;
12551 }
12552
12553
12554
12555
12556
12557
12558 public function getJobType()
12559 {
12560 return 'uninstall';
12561 }
12562
12563
12564
12565
12566 public function __toString()
12567 {
12568 return 'Uninstalling '.$this->package->getPrettyName().' ('.$this->formatVersion($this->package).')';
12569 }
12570 }
12571 <?php
12572
12573
12574
12575
12576
12577
12578
12579
12580
12581
12582
12583 namespace Composer\DependencyResolver\Operation;
12584
12585 use Composer\Package\PackageInterface;
12586 use Composer\Package\Version\VersionParser;
12587
12588
12589
12590
12591
12592
12593 class UpdateOperation extends SolverOperation
12594 {
12595 protected $initialPackage;
12596 protected $targetPackage;
12597
12598
12599
12600
12601
12602
12603
12604
12605 public function __construct(PackageInterface $initial, PackageInterface $target, $reason = null)
12606 {
12607 parent::__construct($reason);
12608
12609 $this->initialPackage = $initial;
12610 $this->targetPackage = $target;
12611 }
12612
12613
12614
12615
12616
12617
12618 public function getInitialPackage()
12619 {
12620 return $this->initialPackage;
12621 }
12622
12623
12624
12625
12626
12627
12628 public function getTargetPackage()
12629 {
12630 return $this->targetPackage;
12631 }
12632
12633
12634
12635
12636
12637
12638 public function getJobType()
12639 {
12640 return 'update';
12641 }
12642
12643
12644
12645
12646 public function __toString()
12647 {
12648 $actionName = VersionParser::isUpgrade($this->initialPackage->getVersion(), $this->targetPackage->getVersion()) ? 'Updating' : 'Downgrading';
12649
12650 return $actionName.' '.$this->initialPackage->getPrettyName().' ('.$this->formatVersion($this->initialPackage).') to '.
12651 $this->targetPackage->getPrettyName(). ' ('.$this->formatVersion($this->targetPackage).')';
12652 }
12653 }
12654 <?php
12655
12656
12657
12658
12659
12660
12661
12662
12663
12664
12665
12666 namespace Composer\DependencyResolver;
12667
12668 use Composer\Package\PackageInterface;
12669
12670
12671
12672
12673 interface PolicyInterface
12674 {
12675 public function versionCompare(PackageInterface $a, PackageInterface $b, $operator);
12676
12677 public function findUpdatePackages(Pool $pool, array $installedMap, PackageInterface $package);
12678
12679 public function selectPreferredPackages(Pool $pool, array $installedMap, array $literals, $requiredPackage = null);
12680 }
12681 <?php
12682
12683
12684
12685
12686
12687
12688
12689
12690
12691
12692
12693 namespace Composer\DependencyResolver;
12694
12695 use Composer\Package\BasePackage;
12696 use Composer\Package\AliasPackage;
12697 use Composer\Package\Version\VersionParser;
12698 use Composer\Semver\Constraint\ConstraintInterface;
12699 use Composer\Semver\Constraint\Constraint;
12700 use Composer\Semver\Constraint\EmptyConstraint;
12701 use Composer\Repository\RepositoryInterface;
12702 use Composer\Repository\CompositeRepository;
12703 use Composer\Repository\ComposerRepository;
12704 use Composer\Repository\InstalledRepositoryInterface;
12705 use Composer\Repository\PlatformRepository;
12706 use Composer\Package\PackageInterface;
12707
12708
12709
12710
12711
12712
12713
12714 class Pool implements \Countable
12715 {
12716 const MATCH_NAME = -1;
12717 const MATCH_NONE = 0;
12718 const MATCH = 1;
12719 const MATCH_PROVIDE = 2;
12720 const MATCH_REPLACE = 3;
12721 const MATCH_FILTERED = 4;
12722
12723 protected $repositories = array();
12724 protected $providerRepos = array();
12725 protected $packages = array();
12726 protected $packageByName = array();
12727 protected $packageByExactName = array();
12728 protected $acceptableStabilities;
12729 protected $stabilityFlags;
12730 protected $versionParser;
12731 protected $providerCache = array();
12732 protected $filterRequires;
12733 protected $whitelist = null; 
12734 protected $id = 1;
12735
12736 public function __construct($minimumStability = 'stable', array $stabilityFlags = array(), array $filterRequires = array())
12737 {
12738 $this->versionParser = new VersionParser;
12739 $this->acceptableStabilities = array();
12740 foreach (BasePackage::$stabilities as $stability => $value) {
12741 if ($value <= BasePackage::$stabilities[$minimumStability]) {
12742 $this->acceptableStabilities[$stability] = $value;
12743 }
12744 }
12745 $this->stabilityFlags = $stabilityFlags;
12746 $this->filterRequires = $filterRequires;
12747 foreach ($filterRequires as $name => $constraint) {
12748 if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name)) {
12749 unset($this->filterRequires[$name]);
12750 }
12751 }
12752 }
12753
12754 public function setAllowList($allowList)
12755 {
12756
12757 $this->setWhitelist($allowList);
12758 }
12759
12760
12761
12762
12763 public function setWhitelist($whitelist)
12764 {
12765 $this->whitelist = $whitelist;
12766 $this->providerCache = array();
12767 }
12768
12769
12770
12771
12772
12773
12774
12775 public function addRepository(RepositoryInterface $repo, $rootAliases = array())
12776 {
12777 if ($repo instanceof CompositeRepository) {
12778 $repos = $repo->getRepositories();
12779 } else {
12780 $repos = array($repo);
12781 }
12782
12783 foreach ($repos as $repo) {
12784 $this->repositories[] = $repo;
12785
12786 $exempt = $repo instanceof PlatformRepository || $repo instanceof InstalledRepositoryInterface;
12787
12788 if ($repo instanceof ComposerRepository && $repo->hasProviders()) {
12789 $this->providerRepos[] = $repo;
12790 $repo->setRootAliases($rootAliases);
12791 $repo->resetPackageIds();
12792 } else {
12793 foreach ($repo->getPackages() as $package) {
12794 $names = $package->getNames();
12795 $stability = $package->getStability();
12796 if ($exempt || $this->isPackageAcceptable($names, $stability)) {
12797 $package->setId($this->id++);
12798 $this->packages[] = $package;
12799 $this->packageByExactName[$package->getName()][$package->id] = $package;
12800
12801 foreach ($names as $provided) {
12802 $this->packageByName[$provided][] = $package;
12803 }
12804
12805
12806 $name = $package->getName();
12807 if (isset($rootAliases[$name][$package->getVersion()])) {
12808 $alias = $rootAliases[$name][$package->getVersion()];
12809 if ($package instanceof AliasPackage) {
12810 $package = $package->getAliasOf();
12811 }
12812 $aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias']);
12813 $aliasPackage->setRootPackageAlias(true);
12814 $aliasPackage->setId($this->id++);
12815
12816 $package->getRepository()->addPackage($aliasPackage);
12817 $this->packages[] = $aliasPackage;
12818 $this->packageByExactName[$aliasPackage->getName()][$aliasPackage->id] = $aliasPackage;
12819
12820 foreach ($aliasPackage->getNames() as $name) {
12821 $this->packageByName[$name][] = $aliasPackage;
12822 }
12823 }
12824 }
12825 }
12826 }
12827 }
12828 }
12829
12830 public function getPriority(RepositoryInterface $repo)
12831 {
12832 $priority = array_search($repo, $this->repositories, true);
12833
12834 if (false === $priority) {
12835 throw new \RuntimeException("Could not determine repository priority. The repository was not registered in the pool.");
12836 }
12837
12838 return -$priority;
12839 }
12840
12841
12842
12843
12844
12845
12846
12847 public function packageById($id)
12848 {
12849 return $this->packages[$id - 1];
12850 }
12851
12852
12853
12854
12855 public function count()
12856 {
12857 return count($this->packages);
12858 }
12859
12860
12861
12862
12863
12864
12865
12866
12867
12868
12869
12870
12871 public function whatProvides($name, ConstraintInterface $constraint = null, $mustMatchName = false, $bypassFilters = false)
12872 {
12873 if ($bypassFilters) {
12874 return $this->computeWhatProvides($name, $constraint, $mustMatchName, true);
12875 }
12876
12877 $key = ((int) $mustMatchName).$constraint;
12878 if (isset($this->providerCache[$name][$key])) {
12879 return $this->providerCache[$name][$key];
12880 }
12881
12882 return $this->providerCache[$name][$key] = $this->computeWhatProvides($name, $constraint, $mustMatchName, $bypassFilters);
12883 }
12884
12885
12886
12887
12888 private function computeWhatProvides($name, $constraint, $mustMatchName = false, $bypassFilters = false)
12889 {
12890 $candidates = array();
12891
12892 foreach ($this->providerRepos as $repo) {
12893 foreach ($repo->whatProvides($this, $name, $bypassFilters) as $candidate) {
12894 $candidates[] = $candidate;
12895 if ($candidate->id < 1) {
12896 $candidate->setId($this->id++);
12897 $this->packages[$this->id - 2] = $candidate;
12898 }
12899 }
12900 }
12901
12902 if ($mustMatchName) {
12903 $candidates = array_filter($candidates, function ($candidate) use ($name) {
12904 return $candidate->getName() == $name;
12905 });
12906 if (isset($this->packageByExactName[$name])) {
12907 $candidates = array_merge($candidates, $this->packageByExactName[$name]);
12908 }
12909 } elseif (isset($this->packageByName[$name])) {
12910 $candidates = array_merge($candidates, $this->packageByName[$name]);
12911 }
12912
12913 $matches = $provideMatches = array();
12914 $nameMatch = false;
12915
12916 foreach ($candidates as $candidate) {
12917 $aliasOfCandidate = null;
12918
12919
12920
12921 if ($candidate instanceof AliasPackage) {
12922 $aliasOfCandidate = $candidate->getAliasOf();
12923 }
12924
12925 if ($this->whitelist !== null && !$bypassFilters && (
12926 (!($candidate instanceof AliasPackage) && !isset($this->whitelist[$candidate->id])) ||
12927 ($candidate instanceof AliasPackage && !isset($this->whitelist[$aliasOfCandidate->id]))
12928 )) {
12929 continue;
12930 }
12931 switch ($this->match($candidate, $name, $constraint, $bypassFilters)) {
12932 case self::MATCH_NONE:
12933 break;
12934
12935 case self::MATCH_NAME:
12936 $nameMatch = true;
12937 break;
12938
12939 case self::MATCH:
12940 $nameMatch = true;
12941 $matches[] = $candidate;
12942 break;
12943
12944 case self::MATCH_PROVIDE:
12945 $provideMatches[] = $candidate;
12946 break;
12947
12948 case self::MATCH_REPLACE:
12949 $matches[] = $candidate;
12950 break;
12951
12952 case self::MATCH_FILTERED:
12953 break;
12954
12955 default:
12956 throw new \UnexpectedValueException('Unexpected match type');
12957 }
12958 }
12959
12960
12961 if ($nameMatch) {
12962 return $matches;
12963 }
12964
12965 return array_merge($matches, $provideMatches);
12966 }
12967
12968 public function literalToPackage($literal)
12969 {
12970 $packageId = abs($literal);
12971
12972 return $this->packageById($packageId);
12973 }
12974
12975 public function literalToPrettyString($literal, $installedMap)
12976 {
12977 $package = $this->literalToPackage($literal);
12978
12979 if (isset($installedMap[$package->id])) {
12980 $prefix = ($literal > 0 ? 'keep' : 'remove');
12981 } else {
12982 $prefix = ($literal > 0 ? 'install' : 'don\'t install');
12983 }
12984
12985 return $prefix.' '.$package->getPrettyString();
12986 }
12987
12988 public function isPackageAcceptable($name, $stability)
12989 {
12990 foreach ((array) $name as $n) {
12991
12992 if (!isset($this->stabilityFlags[$n]) && isset($this->acceptableStabilities[$stability])) {
12993 return true;
12994 }
12995
12996
12997 if (isset($this->stabilityFlags[$n]) && BasePackage::$stabilities[$stability] <= $this->stabilityFlags[$n]) {
12998 return true;
12999 }
13000 }
13001
13002 return false;
13003 }
13004
13005
13006
13007
13008
13009
13010
13011
13012
13013
13014 public function match($candidate, $name, ConstraintInterface $constraint = null, $bypassFilters)
13015 {
13016 $candidateName = $candidate->getName();
13017 $candidateVersion = $candidate->getVersion();
13018 $isDev = $candidate->getStability() === 'dev';
13019 $isAlias = $candidate instanceof AliasPackage;
13020
13021 if (!$bypassFilters && !$isDev && !$isAlias && isset($this->filterRequires[$name])) {
13022 $requireFilter = $this->filterRequires[$name];
13023 } else {
13024 $requireFilter = new EmptyConstraint;
13025 }
13026
13027 if ($candidateName === $name) {
13028 $pkgConstraint = new Constraint('==', $candidateVersion);
13029
13030 if ($constraint === null || $constraint->matches($pkgConstraint)) {
13031 return $requireFilter->matches($pkgConstraint) ? self::MATCH : self::MATCH_FILTERED;
13032 }
13033
13034 return self::MATCH_NAME;
13035 }
13036
13037 $provides = $candidate->getProvides();
13038 $replaces = $candidate->getReplaces();
13039
13040
13041 if (isset($replaces[0]) || isset($provides[0])) {
13042 foreach ($provides as $link) {
13043 if ($link->getTarget() === $name && ($constraint === null || $constraint->matches($link->getConstraint()))) {
13044 return $requireFilter->matches($link->getConstraint()) ? self::MATCH_PROVIDE : self::MATCH_FILTERED;
13045 }
13046 }
13047
13048 foreach ($replaces as $link) {
13049 if ($link->getTarget() === $name && ($constraint === null || $constraint->matches($link->getConstraint()))) {
13050 return $requireFilter->matches($link->getConstraint()) ? self::MATCH_REPLACE : self::MATCH_FILTERED;
13051 }
13052 }
13053
13054 return self::MATCH_NONE;
13055 }
13056
13057 if (isset($provides[$name]) && ($constraint === null || $constraint->matches($provides[$name]->getConstraint()))) {
13058 return $requireFilter->matches($provides[$name]->getConstraint()) ? self::MATCH_PROVIDE : self::MATCH_FILTERED;
13059 }
13060
13061 if (isset($replaces[$name]) && ($constraint === null || $constraint->matches($replaces[$name]->getConstraint()))) {
13062 return $requireFilter->matches($replaces[$name]->getConstraint()) ? self::MATCH_REPLACE : self::MATCH_FILTERED;
13063 }
13064
13065 return self::MATCH_NONE;
13066 }
13067 }
13068 <?php
13069
13070
13071
13072
13073
13074
13075
13076
13077
13078
13079
13080 namespace Composer\DependencyResolver;
13081
13082 use Composer\Package\CompletePackageInterface;
13083
13084
13085
13086
13087
13088
13089 class Problem
13090 {
13091
13092
13093
13094
13095 protected $reasonSeen;
13096
13097
13098
13099
13100
13101 protected $reasons = array();
13102
13103 protected $section = 0;
13104
13105 protected $pool;
13106
13107 public function __construct(Pool $pool)
13108 {
13109 $this->pool = $pool;
13110 }
13111
13112
13113
13114
13115
13116
13117 public function addRule(Rule $rule)
13118 {
13119 $this->addReason(spl_object_hash($rule), array(
13120 'rule' => $rule,
13121 'job' => $rule->getJob(),
13122 ));
13123 }
13124
13125
13126
13127
13128
13129
13130 public function getReasons()
13131 {
13132 return $this->reasons;
13133 }
13134
13135
13136
13137
13138
13139
13140
13141 public function getPrettyString(array $installedMap = array())
13142 {
13143 $reasons = call_user_func_array('array_merge', array_reverse($this->reasons));
13144
13145 if (count($reasons) === 1) {
13146 reset($reasons);
13147 $reason = current($reasons);
13148
13149 $job = $reason['job'];
13150
13151 $packageName = $job['packageName'];
13152 $constraint = $job['constraint'];
13153
13154 if (isset($constraint)) {
13155 $packages = $this->pool->whatProvides($packageName, $constraint);
13156 } else {
13157 $packages = array();
13158 }
13159
13160 if ($job && $job['cmd'] === 'install' && empty($packages)) {
13161
13162
13163 if ($packageName === 'php' || $packageName === 'php-64bit' || $packageName === 'hhvm') {
13164 $version = phpversion();
13165 $available = $this->pool->whatProvides($packageName);
13166
13167 if (count($available)) {
13168 $firstAvailable = reset($available);
13169 $version = $firstAvailable->getPrettyVersion();
13170 $extra = $firstAvailable->getExtra();
13171 if ($firstAvailable instanceof CompletePackageInterface && isset($extra['config.platform']) && $extra['config.platform'] === true) {
13172 $version .= '; ' . $firstAvailable->getDescription();
13173 }
13174 }
13175
13176 $msg = "\n    - This package requires ".$packageName.$this->constraintToText($constraint).' but ';
13177
13178 if (defined('HHVM_VERSION') || (count($available) && $packageName === 'hhvm')) {
13179 return $msg . 'your HHVM version does not satisfy that requirement.';
13180 }
13181
13182 if ($packageName === 'hhvm') {
13183 return $msg . 'you are running this with PHP and not HHVM.';
13184 }
13185
13186 return $msg . 'your PHP version ('. $version .') does not satisfy that requirement.';
13187 }
13188
13189
13190 if (0 === stripos($packageName, 'ext-')) {
13191 if (false !== strpos($packageName, ' ')) {
13192 return "\n    - The requested PHP extension ".$packageName.' should be required as '.str_replace(' ', '-', $packageName).'.';
13193 }
13194
13195 $ext = substr($packageName, 4);
13196 $error = extension_loaded($ext) ? 'has the wrong version ('.(phpversion($ext) ?: '0').') installed' : 'is missing from your system';
13197
13198 return "\n    - The requested PHP extension ".$packageName.$this->constraintToText($constraint).' '.$error.'. Install or enable PHP\'s '.$ext.' extension.';
13199 }
13200
13201
13202 if (0 === stripos($packageName, 'lib-')) {
13203 if (strtolower($packageName) === 'lib-icu') {
13204 $error = extension_loaded('intl') ? 'has the wrong version installed, try upgrading the intl extension.' : 'is missing from your system, make sure the intl extension is loaded.';
13205
13206 return "\n    - The requested linked library ".$packageName.$this->constraintToText($constraint).' '.$error;
13207 }
13208
13209 return "\n    - The requested linked library ".$packageName.$this->constraintToText($constraint).' has the wrong version installed or is missing from your system, make sure to load the extension providing it.';
13210 }
13211
13212 if (!preg_match('{^[A-Za-z0-9_./-]+$}', $packageName)) {
13213 $illegalChars = preg_replace('{[A-Za-z0-9_./-]+}', '', $packageName);
13214
13215 return "\n    - The requested package ".$packageName.' could not be found, it looks like its name is invalid, "'.$illegalChars.'" is not allowed in package names.';
13216 }
13217
13218 if ($providers = $this->pool->whatProvides($packageName, $constraint, true, true)) {
13219 return "\n    - The requested package ".$packageName.$this->constraintToText($constraint).' is satisfiable by '.$this->getPackageList($providers).' but these conflict with your requirements or minimum-stability.';
13220 }
13221
13222 if ($providers = $this->pool->whatProvides($packageName, null, true, true)) {
13223 return "\n    - The requested package ".$packageName.$this->constraintToText($constraint).' exists as '.$this->getPackageList($providers).' but these are rejected by your constraint.';
13224 }
13225
13226 return "\n    - The requested package ".$packageName.' could not be found in any version, there may be a typo in the package name.';
13227 }
13228 }
13229
13230 $messages = array();
13231
13232 foreach ($reasons as $reason) {
13233 $rule = $reason['rule'];
13234 $job = $reason['job'];
13235
13236 if ($job) {
13237 $messages[] = $this->jobToText($job);
13238 } elseif ($rule) {
13239 if ($rule instanceof Rule) {
13240 $messages[] = $rule->getPrettyString($this->pool, $installedMap);
13241 }
13242 }
13243 }
13244
13245 return "\n    - ".implode("\n    - ", $messages);
13246 }
13247
13248
13249
13250
13251
13252
13253
13254 protected function addReason($id, $reason)
13255 {
13256 if (!isset($this->reasonSeen[$id])) {
13257 $this->reasonSeen[$id] = true;
13258 $this->reasons[$this->section][] = $reason;
13259 }
13260 }
13261
13262 public function nextSection()
13263 {
13264 $this->section++;
13265 }
13266
13267
13268
13269
13270
13271
13272
13273 protected function jobToText($job)
13274 {
13275 $packageName = $job['packageName'];
13276 $constraint = $job['constraint'];
13277 switch ($job['cmd']) {
13278 case 'install':
13279 $packages = $this->pool->whatProvides($packageName, $constraint);
13280 if (!$packages) {
13281 return 'No package found to satisfy install request for '.$packageName.$this->constraintToText($constraint);
13282 }
13283
13284 return 'Installation request for '.$packageName.$this->constraintToText($constraint).' -> satisfiable by '.$this->getPackageList($packages).'.';
13285 case 'update':
13286 return 'Update request for '.$packageName.$this->constraintToText($constraint).'.';
13287 case 'remove':
13288 return 'Removal request for '.$packageName.$this->constraintToText($constraint).'';
13289 }
13290
13291 if (isset($constraint)) {
13292 $packages = $this->pool->whatProvides($packageName, $constraint);
13293 } else {
13294 $packages = array();
13295 }
13296
13297 return 'Job(cmd='.$job['cmd'].', target='.$packageName.', packages=['.$this->getPackageList($packages).'])';
13298 }
13299
13300 protected function getPackageList($packages)
13301 {
13302 $prepared = array();
13303 foreach ($packages as $package) {
13304 $prepared[$package->getName()]['name'] = $package->getPrettyName();
13305 $prepared[$package->getName()]['versions'][$package->getVersion()] = $package->getPrettyVersion();
13306 }
13307 foreach ($prepared as $name => $package) {
13308 $prepared[$name] = $package['name'].'['.implode(', ', $package['versions']).']';
13309 }
13310
13311 return implode(', ', $prepared);
13312 }
13313
13314
13315
13316
13317
13318
13319
13320 protected function constraintToText($constraint)
13321 {
13322 return $constraint ? ' '.$constraint->getPrettyString() : '';
13323 }
13324 }
13325 <?php
13326
13327
13328
13329
13330
13331
13332
13333
13334
13335
13336
13337 namespace Composer\DependencyResolver;
13338
13339 use Composer\Semver\Constraint\ConstraintInterface;
13340
13341
13342
13343
13344 class Request
13345 {
13346 protected $jobs;
13347
13348 public function __construct()
13349 {
13350 $this->jobs = array();
13351 }
13352
13353 public function install($packageName, ConstraintInterface $constraint = null)
13354 {
13355 $this->addJob($packageName, 'install', $constraint);
13356 }
13357
13358 public function update($packageName, ConstraintInterface $constraint = null)
13359 {
13360 $this->addJob($packageName, 'update', $constraint);
13361 }
13362
13363 public function remove($packageName, ConstraintInterface $constraint = null)
13364 {
13365 $this->addJob($packageName, 'remove', $constraint);
13366 }
13367
13368
13369
13370
13371
13372
13373
13374
13375
13376 public function fix($packageName, ConstraintInterface $constraint = null)
13377 {
13378 $this->addJob($packageName, 'install', $constraint, true);
13379 }
13380
13381 protected function addJob($packageName, $cmd, ConstraintInterface $constraint = null, $fixed = false)
13382 {
13383 $packageName = strtolower($packageName);
13384
13385 $this->jobs[] = array(
13386 'cmd' => $cmd,
13387 'packageName' => $packageName,
13388 'constraint' => $constraint,
13389 'fixed' => $fixed,
13390 );
13391 }
13392
13393 public function updateAll()
13394 {
13395 $this->jobs[] = array('cmd' => 'update-all');
13396 }
13397
13398 public function getJobs()
13399 {
13400 return $this->jobs;
13401 }
13402 }
13403 <?php
13404
13405
13406
13407
13408
13409
13410
13411
13412
13413
13414
13415 namespace Composer\DependencyResolver;
13416
13417 use Composer\Package\CompletePackage;
13418 use Composer\Package\Link;
13419 use Composer\Package\PackageInterface;
13420
13421
13422
13423
13424
13425 abstract class Rule
13426 {
13427
13428 const RULE_INTERNAL_ALLOW_UPDATE = 1;
13429 const RULE_JOB_INSTALL = 2;
13430 const RULE_JOB_REMOVE = 3;
13431 const RULE_PACKAGE_CONFLICT = 6;
13432 const RULE_PACKAGE_REQUIRES = 7;
13433 const RULE_PACKAGE_OBSOLETES = 8;
13434 const RULE_INSTALLED_PACKAGE_OBSOLETES = 9;
13435 const RULE_PACKAGE_SAME_NAME = 10;
13436 const RULE_PACKAGE_IMPLICIT_OBSOLETES = 11;
13437 const RULE_LEARNED = 12;
13438 const RULE_PACKAGE_ALIAS = 13;
13439
13440
13441 const BITFIELD_TYPE = 0;
13442 const BITFIELD_REASON = 8;
13443 const BITFIELD_DISABLED = 16;
13444
13445 protected $bitfield;
13446 protected $job;
13447 protected $reasonData;
13448
13449
13450
13451
13452
13453
13454 public function __construct($reason, $reasonData, $job = null)
13455 {
13456 $this->reasonData = $reasonData;
13457
13458 if ($job) {
13459 $this->job = $job;
13460 }
13461
13462 $this->bitfield = (0 << self::BITFIELD_DISABLED) |
13463 ($reason << self::BITFIELD_REASON) |
13464 (255 << self::BITFIELD_TYPE);
13465 }
13466
13467 abstract public function getLiterals();
13468
13469 abstract public function getHash();
13470
13471 public function getJob()
13472 {
13473 return $this->job;
13474 }
13475
13476 abstract public function equals(Rule $rule);
13477
13478 public function getReason()
13479 {
13480 return ($this->bitfield & (255 << self::BITFIELD_REASON)) >> self::BITFIELD_REASON;
13481 }
13482
13483 public function getReasonData()
13484 {
13485 return $this->reasonData;
13486 }
13487
13488 public function getRequiredPackage()
13489 {
13490 if ($this->getReason() === self::RULE_JOB_INSTALL) {
13491 return $this->reasonData;
13492 }
13493
13494 if ($this->getReason() === self::RULE_PACKAGE_REQUIRES) {
13495 return $this->reasonData->getTarget();
13496 }
13497 }
13498
13499 public function setType($type)
13500 {
13501 $this->bitfield = ($this->bitfield & ~(255 << self::BITFIELD_TYPE)) | ((255 & $type) << self::BITFIELD_TYPE);
13502 }
13503
13504 public function getType()
13505 {
13506 return ($this->bitfield & (255 << self::BITFIELD_TYPE)) >> self::BITFIELD_TYPE;
13507 }
13508
13509 public function disable()
13510 {
13511 $this->bitfield = ($this->bitfield & ~(255 << self::BITFIELD_DISABLED)) | (1 << self::BITFIELD_DISABLED);
13512 }
13513
13514 public function enable()
13515 {
13516 $this->bitfield &= ~(255 << self::BITFIELD_DISABLED);
13517 }
13518
13519 public function isDisabled()
13520 {
13521 return (bool) (($this->bitfield & (255 << self::BITFIELD_DISABLED)) >> self::BITFIELD_DISABLED);
13522 }
13523
13524 public function isEnabled()
13525 {
13526 return !(($this->bitfield & (255 << self::BITFIELD_DISABLED)) >> self::BITFIELD_DISABLED);
13527 }
13528
13529 abstract public function isAssertion();
13530
13531 public function getPrettyString(Pool $pool, array $installedMap = array())
13532 {
13533 $literals = $this->getLiterals();
13534
13535 $ruleText = '';
13536 foreach ($literals as $i => $literal) {
13537 if ($i != 0) {
13538 $ruleText .= '|';
13539 }
13540 $ruleText .= $pool->literalToPrettyString($literal, $installedMap);
13541 }
13542
13543 switch ($this->getReason()) {
13544 case self::RULE_INTERNAL_ALLOW_UPDATE:
13545 return $ruleText;
13546
13547 case self::RULE_JOB_INSTALL:
13548 return "Install command rule ($ruleText)";
13549
13550 case self::RULE_JOB_REMOVE:
13551 return "Remove command rule ($ruleText)";
13552
13553 case self::RULE_PACKAGE_CONFLICT:
13554 $package1 = $pool->literalToPackage($literals[0]);
13555 $package2 = $pool->literalToPackage($literals[1]);
13556
13557 return $package1->getPrettyString().' conflicts with '.$this->formatPackagesUnique($pool, array($package2)).'.';
13558
13559 case self::RULE_PACKAGE_REQUIRES:
13560 $sourceLiteral = array_shift($literals);
13561 $sourcePackage = $pool->literalToPackage($sourceLiteral);
13562
13563 $requires = array();
13564 foreach ($literals as $literal) {
13565 $requires[] = $pool->literalToPackage($literal);
13566 }
13567
13568 $text = $this->reasonData->getPrettyString($sourcePackage);
13569 if ($requires) {
13570 $text .= ' -> satisfiable by ' . $this->formatPackagesUnique($pool, $requires) . '.';
13571 } else {
13572 $targetName = $this->reasonData->getTarget();
13573
13574 if ($targetName === 'php' || $targetName === 'php-64bit' || $targetName === 'hhvm') {
13575
13576 if (defined('HHVM_VERSION')) {
13577 return $text . ' -> your HHVM version does not satisfy that requirement.';
13578 }
13579
13580 $packages = $pool->whatProvides($targetName);
13581 $package = count($packages) ? current($packages) : phpversion();
13582
13583 if ($targetName === 'hhvm') {
13584 if ($package instanceof CompletePackage) {
13585 return $text . ' -> your HHVM version ('.$package->getPrettyVersion().') does not satisfy that requirement.';
13586 } else {
13587 return $text . ' -> you are running this with PHP and not HHVM.';
13588 }
13589 }
13590
13591
13592 if (!($package instanceof CompletePackage)) {
13593 return $text . ' -> your PHP version ('.phpversion().') does not satisfy that requirement.';
13594 }
13595
13596 $extra = $package->getExtra();
13597
13598 if (!empty($extra['config.platform'])) {
13599 $text .= ' -> your PHP version ('.phpversion().') overridden by "config.platform.php" version ('.$package->getPrettyVersion().') does not satisfy that requirement.';
13600 } else {
13601 $text .= ' -> your PHP version ('.$package->getPrettyVersion().') does not satisfy that requirement.';
13602 }
13603
13604 return $text;
13605 }
13606
13607 if (0 === strpos($targetName, 'ext-')) {
13608
13609 $ext = substr($targetName, 4);
13610 $error = extension_loaded($ext) ? 'has the wrong version ('.(phpversion($ext) ?: '0').') installed' : 'is missing from your system';
13611
13612 return $text . ' -> the requested PHP extension '.$ext.' '.$error.'.';
13613 }
13614
13615 if (0 === strpos($targetName, 'lib-')) {
13616
13617 $lib = substr($targetName, 4);
13618
13619 return $text . ' -> the requested linked library '.$lib.' has the wrong version installed or is missing from your system, make sure to have the extension providing it.';
13620 }
13621
13622 if ($providers = $pool->whatProvides($targetName, $this->reasonData->getConstraint(), true, true)) {
13623 return $text . ' -> satisfiable by ' . $this->formatPackagesUnique($pool, $providers) .' but these conflict with your requirements or minimum-stability.';
13624 }
13625
13626 return $text . ' -> no matching package found.';
13627 }
13628
13629 return $text;
13630
13631 case self::RULE_PACKAGE_OBSOLETES:
13632 return $ruleText;
13633 case self::RULE_INSTALLED_PACKAGE_OBSOLETES:
13634 return $ruleText;
13635 case self::RULE_PACKAGE_SAME_NAME:
13636 return 'Can only install one of: ' . $this->formatPackagesUnique($pool, $literals) . '.';
13637 case self::RULE_PACKAGE_IMPLICIT_OBSOLETES:
13638 return $ruleText;
13639 case self::RULE_LEARNED:
13640 return 'Conclusion: '.$ruleText;
13641 case self::RULE_PACKAGE_ALIAS:
13642 return $ruleText;
13643 default:
13644 return '('.$ruleText.')';
13645 }
13646 }
13647
13648
13649
13650
13651
13652
13653
13654 protected function formatPackagesUnique($pool, array $packages)
13655 {
13656 $prepared = array();
13657 foreach ($packages as $package) {
13658 if (!is_object($package)) {
13659 $package = $pool->literalToPackage($package);
13660 }
13661 $prepared[$package->getName()]['name'] = $package->getPrettyName();
13662 $prepared[$package->getName()]['versions'][$package->getVersion()] = $package->getPrettyVersion();
13663 }
13664 foreach ($prepared as $name => $package) {
13665 $prepared[$name] = $package['name'].'['.implode(', ', $package['versions']).']';
13666 }
13667
13668 return implode(', ', $prepared);
13669 }
13670 }
13671 <?php
13672
13673
13674
13675
13676
13677
13678
13679
13680
13681
13682
13683 namespace Composer\DependencyResolver;
13684
13685 use Composer\Package\PackageInterface;
13686 use Composer\Package\Link;
13687
13688
13689
13690
13691 class Rule2Literals extends Rule
13692 {
13693 protected $literal1;
13694 protected $literal2;
13695
13696
13697
13698
13699
13700
13701
13702
13703 public function __construct($literal1, $literal2, $reason, $reasonData, $job = null)
13704 {
13705 parent::__construct($reason, $reasonData, $job);
13706
13707 if ($literal1 < $literal2) {
13708 $this->literal1 = $literal1;
13709 $this->literal2 = $literal2;
13710 } else {
13711 $this->literal1 = $literal2;
13712 $this->literal2 = $literal1;
13713 }
13714 }
13715
13716 public function getLiterals()
13717 {
13718 return array($this->literal1, $this->literal2);
13719 }
13720
13721 public function getHash()
13722 {
13723 return $this->literal1.','.$this->literal2;
13724 }
13725
13726
13727
13728
13729
13730
13731
13732
13733
13734 public function equals(Rule $rule)
13735 {
13736
13737 if ($rule instanceof self) {
13738 if ($this->literal1 !== $rule->literal1) {
13739 return false;
13740 }
13741
13742 if ($this->literal2 !== $rule->literal2) {
13743 return false;
13744 }
13745
13746 return true;
13747 }
13748
13749 $literals = $rule->getLiterals();
13750 if (2 != count($literals)) {
13751 return false;
13752 }
13753
13754 if ($this->literal1 !== $literals[0]) {
13755 return false;
13756 }
13757
13758 if ($this->literal2 !== $literals[1]) {
13759 return false;
13760 }
13761
13762 return true;
13763 }
13764
13765 public function isAssertion()
13766 {
13767 return false;
13768 }
13769
13770
13771
13772
13773
13774
13775 public function __toString()
13776 {
13777 $result = $this->isDisabled() ? 'disabled(' : '(';
13778
13779 $result .= $this->literal1 . '|' . $this->literal2 . ')';
13780
13781 return $result;
13782 }
13783 }
13784 <?php
13785
13786
13787
13788
13789
13790
13791
13792
13793
13794
13795
13796 namespace Composer\DependencyResolver;
13797
13798
13799
13800
13801 class RuleSet implements \IteratorAggregate, \Countable
13802 {
13803
13804 const TYPE_PACKAGE = 0;
13805 const TYPE_JOB = 1;
13806 const TYPE_LEARNED = 4;
13807
13808
13809
13810
13811
13812
13813 public $ruleById;
13814
13815 protected static $types = array(
13816 255 => 'UNKNOWN',
13817 self::TYPE_PACKAGE => 'PACKAGE',
13818 self::TYPE_JOB => 'JOB',
13819 self::TYPE_LEARNED => 'LEARNED',
13820 );
13821
13822 protected $rules;
13823 protected $nextRuleId;
13824
13825 protected $rulesByHash;
13826
13827 public function __construct()
13828 {
13829 $this->nextRuleId = 0;
13830
13831 foreach ($this->getTypes() as $type) {
13832 $this->rules[$type] = array();
13833 }
13834
13835 $this->rulesByHash = array();
13836 }
13837
13838 public function add(Rule $rule, $type)
13839 {
13840 if (!isset(self::$types[$type])) {
13841 throw new \OutOfBoundsException('Unknown rule type: ' . $type);
13842 }
13843
13844 $hash = $rule->getHash();
13845
13846
13847 if (isset($this->rulesByHash[$hash])) {
13848 $potentialDuplicates = $this->rulesByHash[$hash];
13849 if (is_array($potentialDuplicates)) {
13850 foreach ($potentialDuplicates as $potentialDuplicate) {
13851 if ($rule->equals($potentialDuplicate)) {
13852 return;
13853 }
13854 }
13855 } else {
13856 if ($rule->equals($potentialDuplicates)) {
13857 return;
13858 }
13859 }
13860 }
13861
13862 if (!isset($this->rules[$type])) {
13863 $this->rules[$type] = array();
13864 }
13865
13866 $this->rules[$type][] = $rule;
13867 $this->ruleById[$this->nextRuleId] = $rule;
13868 $rule->setType($type);
13869
13870 $this->nextRuleId++;
13871
13872 if (!isset($this->rulesByHash[$hash])) {
13873 $this->rulesByHash[$hash] = $rule;
13874 } elseif (is_array($this->rulesByHash[$hash])) {
13875 $this->rulesByHash[$hash][] = $rule;
13876 } else {
13877 $originalRule = $this->rulesByHash[$hash];
13878 $this->rulesByHash[$hash] = array($originalRule, $rule);
13879 }
13880 }
13881
13882 public function count()
13883 {
13884 return $this->nextRuleId;
13885 }
13886
13887 public function ruleById($id)
13888 {
13889 return $this->ruleById[$id];
13890 }
13891
13892 public function getRules()
13893 {
13894 return $this->rules;
13895 }
13896
13897 public function getIterator()
13898 {
13899 return new RuleSetIterator($this->getRules());
13900 }
13901
13902 public function getIteratorFor($types)
13903 {
13904 if (!is_array($types)) {
13905 $types = array($types);
13906 }
13907
13908 $allRules = $this->getRules();
13909 $rules = array();
13910
13911 foreach ($types as $type) {
13912 $rules[$type] = $allRules[$type];
13913 }
13914
13915 return new RuleSetIterator($rules);
13916 }
13917
13918 public function getIteratorWithout($types)
13919 {
13920 if (!is_array($types)) {
13921 $types = array($types);
13922 }
13923
13924 $rules = $this->getRules();
13925
13926 foreach ($types as $type) {
13927 unset($rules[$type]);
13928 }
13929
13930 return new RuleSetIterator($rules);
13931 }
13932
13933 public function getTypes()
13934 {
13935 $types = self::$types;
13936 unset($types[255]);
13937
13938 return array_keys($types);
13939 }
13940
13941 public function getPrettyString(Pool $pool = null)
13942 {
13943 $string = "\n";
13944 foreach ($this->rules as $type => $rules) {
13945 $string .= str_pad(self::$types[$type], 8, ' ') . ": ";
13946 foreach ($rules as $rule) {
13947 $string .= ($pool ? $rule->getPrettyString($pool) : $rule)."\n";
13948 }
13949 $string .= "\n\n";
13950 }
13951
13952 return $string;
13953 }
13954
13955 public function __toString()
13956 {
13957 return $this->getPrettyString(null);
13958 }
13959 }
13960 <?php
13961
13962
13963
13964
13965
13966
13967
13968
13969
13970
13971
13972 namespace Composer\DependencyResolver;
13973
13974 use Composer\Package\PackageInterface;
13975 use Composer\Package\AliasPackage;
13976 use Composer\Repository\PlatformRepository;
13977
13978
13979
13980
13981 class RuleSetGenerator
13982 {
13983 protected $policy;
13984 protected $pool;
13985 protected $rules;
13986 protected $jobs;
13987 protected $installedMap;
13988 protected $allowListedMap;
13989 protected $addedMap;
13990 protected $conflictAddedMap;
13991 protected $addedPackages;
13992 protected $addedPackagesByNames;
13993
13994 public function __construct(PolicyInterface $policy, Pool $pool)
13995 {
13996 $this->policy = $policy;
13997 $this->pool = $pool;
13998 }
13999
14000
14001
14002
14003
14004
14005
14006
14007
14008
14009
14010
14011
14012
14013
14014 protected function createRequireRule(PackageInterface $package, array $providers, $reason, $reasonData = null)
14015 {
14016 $literals = array(-$package->id);
14017
14018 foreach ($providers as $provider) {
14019
14020 if ($provider === $package) {
14021 return null;
14022 }
14023 $literals[] = $provider->id;
14024 }
14025
14026 return new GenericRule($literals, $reason, $reasonData);
14027 }
14028
14029
14030
14031
14032
14033
14034
14035
14036
14037
14038
14039
14040
14041 protected function createInstallOneOfRule(array $packages, $reason, $job)
14042 {
14043 $literals = array();
14044 foreach ($packages as $package) {
14045 $literals[] = $package->id;
14046 }
14047
14048 return new GenericRule($literals, $reason, $job['packageName'], $job);
14049 }
14050
14051
14052
14053
14054
14055
14056
14057
14058
14059
14060
14061
14062 protected function createRemoveRule(PackageInterface $package, $reason, $job)
14063 {
14064 return new GenericRule(array(-$package->id), $reason, $job['packageName'], $job);
14065 }
14066
14067
14068
14069
14070
14071
14072
14073
14074
14075
14076
14077
14078
14079
14080
14081 protected function createRule2Literals(PackageInterface $issuer, PackageInterface $provider, $reason, $reasonData = null)
14082 {
14083
14084 if ($issuer === $provider) {
14085 return null;
14086 }
14087
14088 return new Rule2Literals(-$issuer->id, -$provider->id, $reason, $reasonData);
14089 }
14090
14091
14092
14093
14094
14095
14096
14097
14098
14099
14100 private function addRule($type, Rule $newRule = null)
14101 {
14102 if (!$newRule) {
14103 return;
14104 }
14105
14106 $this->rules->add($newRule, $type);
14107 }
14108
14109 protected function allowListFromPackage(PackageInterface $package)
14110 {
14111
14112 $this->whitelistFromPackage($package);
14113 }
14114
14115
14116
14117
14118 protected function whitelistFromPackage(PackageInterface $package)
14119 {
14120 $workQueue = new \SplQueue;
14121 $workQueue->enqueue($package);
14122
14123 while (!$workQueue->isEmpty()) {
14124 $package = $workQueue->dequeue();
14125 if (isset($this->allowListedMap[$package->id])) {
14126 continue;
14127 }
14128
14129 $this->allowListedMap[$package->id] = true;
14130
14131 foreach ($package->getRequires() as $link) {
14132 $possibleRequires = $this->pool->whatProvides($link->getTarget(), $link->getConstraint(), true);
14133
14134 foreach ($possibleRequires as $require) {
14135 $workQueue->enqueue($require);
14136 }
14137 }
14138
14139 $obsoleteProviders = $this->pool->whatProvides($package->getName(), null, true);
14140
14141 foreach ($obsoleteProviders as $provider) {
14142 if ($provider === $package) {
14143 continue;
14144 }
14145
14146 if (($package instanceof AliasPackage) && $package->getAliasOf() === $provider) {
14147 $workQueue->enqueue($provider);
14148 }
14149 }
14150 }
14151 }
14152
14153 protected function addRulesForPackage(PackageInterface $package, $ignorePlatformReqs)
14154 {
14155 $workQueue = new \SplQueue;
14156 $workQueue->enqueue($package);
14157
14158 while (!$workQueue->isEmpty()) {
14159
14160 $package = $workQueue->dequeue();
14161 if (isset($this->addedMap[$package->id])) {
14162 continue;
14163 }
14164
14165 $this->addedMap[$package->id] = true;
14166
14167 $this->addedPackages[] = $package;
14168 foreach ($package->getNames() as $name) {
14169 $this->addedPackagesByNames[$name][] = $package;
14170 }
14171
14172 foreach ($package->getRequires() as $link) {
14173 if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $link->getTarget())) {
14174 continue;
14175 }
14176
14177 $possibleRequires = $this->pool->whatProvides($link->getTarget(), $link->getConstraint());
14178
14179 $this->addRule(RuleSet::TYPE_PACKAGE, $this->createRequireRule($package, $possibleRequires, Rule::RULE_PACKAGE_REQUIRES, $link));
14180
14181 foreach ($possibleRequires as $require) {
14182 $workQueue->enqueue($require);
14183 }
14184 }
14185
14186 $packageName = $package->getName();
14187 $obsoleteProviders = $this->pool->whatProvides($packageName, null);
14188
14189 foreach ($obsoleteProviders as $provider) {
14190 if ($provider === $package) {
14191 continue;
14192 }
14193
14194 if (($package instanceof AliasPackage) && $package->getAliasOf() === $provider) {
14195 $this->addRule(RuleSet::TYPE_PACKAGE, $this->createRequireRule($package, array($provider), Rule::RULE_PACKAGE_ALIAS, $package));
14196 } elseif (!$this->obsoleteImpossibleForAlias($package, $provider)) {
14197 $reason = ($packageName == $provider->getName()) ? Rule::RULE_PACKAGE_SAME_NAME : Rule::RULE_PACKAGE_IMPLICIT_OBSOLETES;
14198 $this->addRule(RuleSet::TYPE_PACKAGE, $this->createRule2Literals($package, $provider, $reason, $package));
14199 }
14200 }
14201 }
14202 }
14203
14204 protected function addConflictRules($ignorePlatformReqs = false)
14205 {
14206
14207 foreach ($this->addedPackages as $package) {
14208 foreach ($package->getConflicts() as $link) {
14209 if (!isset($this->addedPackagesByNames[$link->getTarget()])) {
14210 continue;
14211 }
14212
14213 if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $link->getTarget())) {
14214 continue;
14215 }
14216
14217
14218 foreach ($this->addedPackagesByNames[$link->getTarget()] as $possibleConflict) {
14219 $conflictMatch = $this->pool->match($possibleConflict, $link->getTarget(), $link->getConstraint(), true);
14220
14221 if ($conflictMatch === Pool::MATCH || $conflictMatch === Pool::MATCH_REPLACE) {
14222 $this->addRule(RuleSet::TYPE_PACKAGE, $this->createRule2Literals($package, $possibleConflict, Rule::RULE_PACKAGE_CONFLICT, $link));
14223 }
14224
14225 }
14226 }
14227
14228
14229 $isInstalled = isset($this->installedMap[$package->id]);
14230
14231 foreach ($package->getReplaces() as $link) {
14232 if (!isset($this->addedPackagesByNames[$link->getTarget()])) {
14233 continue;
14234 }
14235
14236
14237 foreach ($this->addedPackagesByNames[$link->getTarget()] as $provider) {
14238 if ($provider === $package) {
14239 continue;
14240 }
14241
14242 if (!$this->obsoleteImpossibleForAlias($package, $provider)) {
14243 $reason = $isInstalled ? Rule::RULE_INSTALLED_PACKAGE_OBSOLETES : Rule::RULE_PACKAGE_OBSOLETES;
14244 $this->addRule(RuleSet::TYPE_PACKAGE, $this->createRule2Literals($package, $provider, $reason, $link));
14245 }
14246 }
14247 }
14248 }
14249 }
14250
14251 protected function obsoleteImpossibleForAlias($package, $provider)
14252 {
14253 $packageIsAlias = $package instanceof AliasPackage;
14254 $providerIsAlias = $provider instanceof AliasPackage;
14255
14256 $impossible = (
14257 ($packageIsAlias && $package->getAliasOf() === $provider) ||
14258 ($providerIsAlias && $provider->getAliasOf() === $package) ||
14259 ($packageIsAlias && $providerIsAlias && $provider->getAliasOf() === $package->getAliasOf())
14260 );
14261
14262 return $impossible;
14263 }
14264
14265 protected function allowListFromJobs()
14266 {
14267
14268 $this->whitelistFromJobs();
14269 }
14270
14271
14272
14273
14274 protected function whitelistFromJobs()
14275 {
14276 foreach ($this->jobs as $job) {
14277 switch ($job['cmd']) {
14278 case 'install':
14279 $packages = $this->pool->whatProvides($job['packageName'], $job['constraint'], true);
14280 foreach ($packages as $package) {
14281 $this->allowListFromPackage($package);
14282 }
14283 break;
14284 }
14285 }
14286 }
14287
14288 protected function addRulesForJobs($ignorePlatformReqs)
14289 {
14290 foreach ($this->jobs as $job) {
14291 switch ($job['cmd']) {
14292 case 'install':
14293 if (!$job['fixed'] && $ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $job['packageName'])) {
14294 break;
14295 }
14296
14297 $packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
14298 if ($packages) {
14299 foreach ($packages as $package) {
14300 if (!isset($this->installedMap[$package->id])) {
14301 $this->addRulesForPackage($package, $ignorePlatformReqs);
14302 }
14303 }
14304
14305 $rule = $this->createInstallOneOfRule($packages, Rule::RULE_JOB_INSTALL, $job);
14306 $this->addRule(RuleSet::TYPE_JOB, $rule);
14307 }
14308 break;
14309 case 'remove':
14310
14311
14312 $packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
14313 foreach ($packages as $package) {
14314 $rule = $this->createRemoveRule($package, Rule::RULE_JOB_REMOVE, $job);
14315 $this->addRule(RuleSet::TYPE_JOB, $rule);
14316 }
14317 break;
14318 }
14319 }
14320 }
14321
14322 public function getRulesFor($jobs, $installedMap, $ignorePlatformReqs = false)
14323 {
14324 $this->jobs = $jobs;
14325 $this->rules = new RuleSet;
14326 $this->installedMap = $installedMap;
14327
14328 $this->allowListedMap = array();
14329 foreach ($this->installedMap as $package) {
14330 $this->allowListFromPackage($package);
14331 }
14332 $this->allowListFromJobs();
14333
14334 $this->pool->setAllowList($this->allowListedMap);
14335
14336 $this->addedMap = array();
14337 $this->conflictAddedMap = array();
14338 $this->addedPackages = array();
14339 $this->addedPackagesByNames = array();
14340 foreach ($this->installedMap as $package) {
14341 $this->addRulesForPackage($package, $ignorePlatformReqs);
14342 }
14343
14344 $this->addRulesForJobs($ignorePlatformReqs);
14345
14346 $this->addConflictRules($ignorePlatformReqs);
14347
14348
14349 $this->addedPackages = $this->addedPackagesByNames = null;
14350
14351 return $this->rules;
14352 }
14353 }
14354 <?php
14355
14356
14357
14358
14359
14360
14361
14362
14363
14364
14365
14366 namespace Composer\DependencyResolver;
14367
14368
14369
14370
14371 class RuleSetIterator implements \Iterator
14372 {
14373 protected $rules;
14374 protected $types;
14375
14376 protected $currentOffset;
14377 protected $currentType;
14378 protected $currentTypeOffset;
14379
14380 public function __construct(array $rules)
14381 {
14382 $this->rules = $rules;
14383 $this->types = array_keys($rules);
14384 sort($this->types);
14385
14386 $this->rewind();
14387 }
14388
14389 public function current()
14390 {
14391 return $this->rules[$this->currentType][$this->currentOffset];
14392 }
14393
14394 public function key()
14395 {
14396 return $this->currentType;
14397 }
14398
14399 public function next()
14400 {
14401 $this->currentOffset++;
14402
14403 if (!isset($this->rules[$this->currentType])) {
14404 return;
14405 }
14406
14407 if ($this->currentOffset >= count($this->rules[$this->currentType])) {
14408 $this->currentOffset = 0;
14409
14410 do {
14411 $this->currentTypeOffset++;
14412
14413 if (!isset($this->types[$this->currentTypeOffset])) {
14414 $this->currentType = -1;
14415 break;
14416 }
14417
14418 $this->currentType = $this->types[$this->currentTypeOffset];
14419 } while (isset($this->types[$this->currentTypeOffset]) && !count($this->rules[$this->currentType]));
14420 }
14421 }
14422
14423 public function rewind()
14424 {
14425 $this->currentOffset = 0;
14426
14427 $this->currentTypeOffset = -1;
14428 $this->currentType = -1;
14429
14430 do {
14431 $this->currentTypeOffset++;
14432
14433 if (!isset($this->types[$this->currentTypeOffset])) {
14434 $this->currentType = -1;
14435 break;
14436 }
14437
14438 $this->currentType = $this->types[$this->currentTypeOffset];
14439 } while (isset($this->types[$this->currentTypeOffset]) && !count($this->rules[$this->currentType]));
14440 }
14441
14442 public function valid()
14443 {
14444 return isset($this->rules[$this->currentType])
14445 && isset($this->rules[$this->currentType][$this->currentOffset]);
14446 }
14447 }
14448 <?php
14449
14450
14451
14452
14453
14454
14455
14456
14457
14458
14459
14460 namespace Composer\DependencyResolver;
14461
14462
14463
14464
14465
14466
14467
14468
14469
14470 class RuleWatchChain extends \SplDoublyLinkedList
14471 {
14472 protected $offset = 0;
14473
14474
14475
14476
14477
14478
14479 public function seek($offset)
14480 {
14481 $this->rewind();
14482 for ($i = 0; $i < $offset; $i++, $this->next());
14483 }
14484
14485
14486
14487
14488
14489
14490
14491
14492
14493 public function remove()
14494 {
14495 $offset = $this->key();
14496 $this->offsetUnset($offset);
14497 $this->seek($offset);
14498 }
14499 }
14500 <?php
14501
14502
14503
14504
14505
14506
14507
14508
14509
14510
14511
14512 namespace Composer\DependencyResolver;
14513
14514
14515
14516
14517
14518
14519
14520
14521
14522
14523
14524 class RuleWatchGraph
14525 {
14526 protected $watchChains = array();
14527
14528
14529
14530
14531
14532
14533
14534
14535
14536
14537
14538
14539
14540 public function insert(RuleWatchNode $node)
14541 {
14542 if ($node->getRule()->isAssertion()) {
14543 return;
14544 }
14545
14546 foreach (array($node->watch1, $node->watch2) as $literal) {
14547 if (!isset($this->watchChains[$literal])) {
14548 $this->watchChains[$literal] = new RuleWatchChain;
14549 }
14550
14551 $this->watchChains[$literal]->unshift($node);
14552 }
14553 }
14554
14555
14556
14557
14558
14559
14560
14561
14562
14563
14564
14565
14566
14567
14568
14569
14570
14571
14572
14573
14574
14575
14576
14577
14578 public function propagateLiteral($decidedLiteral, $level, $decisions)
14579 {
14580
14581
14582
14583 $literal = -$decidedLiteral;
14584
14585 if (!isset($this->watchChains[$literal])) {
14586 return null;
14587 }
14588
14589 $chain = $this->watchChains[$literal];
14590
14591 $chain->rewind();
14592 while ($chain->valid()) {
14593 $node = $chain->current();
14594 $otherWatch = $node->getOtherWatch($literal);
14595
14596 if (!$node->getRule()->isDisabled() && !$decisions->satisfy($otherWatch)) {
14597 $ruleLiterals = $node->getRule()->getLiterals();
14598
14599 $alternativeLiterals = array_filter($ruleLiterals, function ($ruleLiteral) use ($literal, $otherWatch, $decisions) {
14600 return $literal !== $ruleLiteral &&
14601 $otherWatch !== $ruleLiteral &&
14602 !$decisions->conflict($ruleLiteral);
14603 });
14604
14605 if ($alternativeLiterals) {
14606 reset($alternativeLiterals);
14607 $this->moveWatch($literal, current($alternativeLiterals), $node);
14608 continue;
14609 }
14610
14611 if ($decisions->conflict($otherWatch)) {
14612 return $node->getRule();
14613 }
14614
14615 $decisions->decide($otherWatch, $level, $node->getRule());
14616 }
14617
14618 $chain->next();
14619 }
14620
14621 return null;
14622 }
14623
14624
14625
14626
14627
14628
14629
14630
14631
14632
14633 protected function moveWatch($fromLiteral, $toLiteral, $node)
14634 {
14635 if (!isset($this->watchChains[$toLiteral])) {
14636 $this->watchChains[$toLiteral] = new RuleWatchChain;
14637 }
14638
14639 $node->moveWatch($fromLiteral, $toLiteral);
14640 $this->watchChains[$fromLiteral]->remove();
14641 $this->watchChains[$toLiteral]->unshift($node);
14642 }
14643 }
14644 <?php
14645
14646
14647
14648
14649
14650
14651
14652
14653
14654
14655
14656 namespace Composer\DependencyResolver;
14657
14658
14659
14660
14661
14662
14663
14664
14665 class RuleWatchNode
14666 {
14667 public $watch1;
14668 public $watch2;
14669
14670 protected $rule;
14671
14672
14673
14674
14675
14676
14677 public function __construct($rule)
14678 {
14679 $this->rule = $rule;
14680
14681 $literals = $rule->getLiterals();
14682
14683 $literalCount = count($literals);
14684 $this->watch1 = $literalCount > 0 ? $literals[0] : 0;
14685 $this->watch2 = $literalCount > 1 ? $literals[1] : 0;
14686 }
14687
14688
14689
14690
14691
14692
14693
14694
14695
14696 public function watch2OnHighest(Decisions $decisions)
14697 {
14698 $literals = $this->rule->getLiterals();
14699
14700
14701 if (count($literals) < 3) {
14702 return;
14703 }
14704
14705 $watchLevel = 0;
14706
14707 foreach ($literals as $literal) {
14708 $level = $decisions->decisionLevel($literal);
14709
14710 if ($level > $watchLevel) {
14711 $this->watch2 = $literal;
14712 $watchLevel = $level;
14713 }
14714 }
14715 }
14716
14717
14718
14719
14720
14721
14722 public function getRule()
14723 {
14724 return $this->rule;
14725 }
14726
14727
14728
14729
14730
14731
14732
14733 public function getOtherWatch($literal)
14734 {
14735 if ($this->watch1 == $literal) {
14736 return $this->watch2;
14737 }
14738
14739 return $this->watch1;
14740 }
14741
14742
14743
14744
14745
14746
14747
14748 public function moveWatch($from, $to)
14749 {
14750 if ($this->watch1 == $from) {
14751 $this->watch1 = $to;
14752 } else {
14753 $this->watch2 = $to;
14754 }
14755 }
14756 }
14757 <?php
14758
14759
14760
14761
14762
14763
14764
14765
14766
14767
14768
14769 namespace Composer\DependencyResolver;
14770
14771 use Composer\IO\IOInterface;
14772 use Composer\Repository\RepositoryInterface;
14773 use Composer\Repository\PlatformRepository;
14774
14775
14776
14777
14778 class Solver
14779 {
14780 const BRANCH_LITERALS = 0;
14781 const BRANCH_LEVEL = 1;
14782
14783
14784 protected $policy;
14785
14786 protected $pool;
14787
14788 protected $installed;
14789
14790 protected $rules;
14791
14792 protected $ruleSetGenerator;
14793
14794 protected $jobs;
14795
14796
14797 protected $updateMap = array();
14798
14799 protected $watchGraph;
14800
14801 protected $decisions;
14802
14803 protected $installedMap;
14804
14805
14806 protected $propagateIndex;
14807
14808 protected $branches = array();
14809
14810 protected $problems = array();
14811
14812 protected $learnedPool = array();
14813
14814 protected $learnedWhy = array();
14815
14816
14817 public $testFlagLearnedPositiveLiteral = false;
14818
14819
14820 protected $io;
14821
14822
14823
14824
14825
14826
14827
14828 public function __construct(PolicyInterface $policy, Pool $pool, RepositoryInterface $installed, IOInterface $io)
14829 {
14830 $this->io = $io;
14831 $this->policy = $policy;
14832 $this->pool = $pool;
14833 $this->installed = $installed;
14834 $this->ruleSetGenerator = new RuleSetGenerator($policy, $pool);
14835 }
14836
14837
14838
14839
14840 public function getRuleSetSize()
14841 {
14842 return count($this->rules);
14843 }
14844
14845
14846
14847 private function makeAssertionRuleDecisions()
14848 {
14849 $decisionStart = count($this->decisions) - 1;
14850
14851 $rulesCount = count($this->rules);
14852 for ($ruleIndex = 0; $ruleIndex < $rulesCount; $ruleIndex++) {
14853 $rule = $this->rules->ruleById[$ruleIndex];
14854
14855 if (!$rule->isAssertion() || $rule->isDisabled()) {
14856 continue;
14857 }
14858
14859 $literals = $rule->getLiterals();
14860 $literal = $literals[0];
14861
14862 if (!$this->decisions->decided($literal)) {
14863 $this->decisions->decide($literal, 1, $rule);
14864 continue;
14865 }
14866
14867 if ($this->decisions->satisfy($literal)) {
14868 continue;
14869 }
14870
14871
14872 if (RuleSet::TYPE_LEARNED === $rule->getType()) {
14873 $rule->disable();
14874 continue;
14875 }
14876
14877 $conflict = $this->decisions->decisionRule($literal);
14878
14879 if ($conflict && RuleSet::TYPE_PACKAGE === $conflict->getType()) {
14880 $problem = new Problem($this->pool);
14881
14882 $problem->addRule($rule);
14883 $problem->addRule($conflict);
14884 $this->disableProblem($rule);
14885 $this->problems[] = $problem;
14886 continue;
14887 }
14888
14889
14890 $problem = new Problem($this->pool);
14891 $problem->addRule($rule);
14892 $problem->addRule($conflict);
14893
14894
14895
14896 foreach ($this->rules->getIteratorFor(RuleSet::TYPE_JOB) as $assertRule) {
14897 if ($assertRule->isDisabled() || !$assertRule->isAssertion()) {
14898 continue;
14899 }
14900
14901 $assertRuleLiterals = $assertRule->getLiterals();
14902 $assertRuleLiteral = $assertRuleLiterals[0];
14903
14904 if (abs($literal) !== abs($assertRuleLiteral)) {
14905 continue;
14906 }
14907
14908 $problem->addRule($assertRule);
14909 $this->disableProblem($assertRule);
14910 }
14911 $this->problems[] = $problem;
14912
14913 $this->decisions->resetToOffset($decisionStart);
14914 $ruleIndex = -1;
14915 }
14916 }
14917
14918 protected function setupInstalledMap()
14919 {
14920 $this->installedMap = array();
14921 foreach ($this->installed->getPackages() as $package) {
14922 $this->installedMap[$package->id] = $package;
14923 }
14924 }
14925
14926
14927
14928
14929 protected function checkForRootRequireProblems($ignorePlatformReqs)
14930 {
14931 foreach ($this->jobs as $job) {
14932 switch ($job['cmd']) {
14933 case 'update':
14934 $packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
14935 foreach ($packages as $package) {
14936 if (isset($this->installedMap[$package->id])) {
14937 $this->updateMap[$package->id] = true;
14938 }
14939 }
14940 break;
14941
14942 case 'update-all':
14943 foreach ($this->installedMap as $package) {
14944 $this->updateMap[$package->id] = true;
14945 }
14946 break;
14947
14948 case 'install':
14949 if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $job['packageName'])) {
14950 break;
14951 }
14952
14953 if (!$this->pool->whatProvides($job['packageName'], $job['constraint'])) {
14954 $problem = new Problem($this->pool);
14955 $problem->addRule(new GenericRule(array(), null, null, $job));
14956 $this->problems[] = $problem;
14957 }
14958 break;
14959 }
14960 }
14961 }
14962
14963
14964
14965
14966
14967
14968 public function solve(Request $request, $ignorePlatformReqs = false)
14969 {
14970 $this->jobs = $request->getJobs();
14971
14972 $this->setupInstalledMap();
14973 $this->rules = $this->ruleSetGenerator->getRulesFor($this->jobs, $this->installedMap, $ignorePlatformReqs);
14974 $this->checkForRootRequireProblems($ignorePlatformReqs);
14975 $this->decisions = new Decisions($this->pool);
14976 $this->watchGraph = new RuleWatchGraph;
14977
14978 foreach ($this->rules as $rule) {
14979 $this->watchGraph->insert(new RuleWatchNode($rule));
14980 }
14981
14982
14983 $this->makeAssertionRuleDecisions();
14984
14985 $this->io->writeError('Resolving dependencies through SAT', true, IOInterface::DEBUG);
14986 $before = microtime(true);
14987 $this->runSat(true);
14988 $this->io->writeError('', true, IOInterface::DEBUG);
14989 $this->io->writeError(sprintf('Dependency resolution completed in %.3f seconds', microtime(true) - $before), true, IOInterface::VERBOSE);
14990
14991
14992 foreach ($this->installedMap as $packageId => $void) {
14993 if ($this->decisions->undecided($packageId)) {
14994 $this->decisions->decide(-$packageId, 1, null);
14995 }
14996 }
14997
14998 if ($this->problems) {
14999 throw new SolverProblemsException($this->problems, $this->installedMap);
15000 }
15001
15002 $transaction = new Transaction($this->policy, $this->pool, $this->installedMap, $this->decisions);
15003
15004 return $transaction->getOperations();
15005 }
15006
15007
15008
15009
15010
15011
15012
15013
15014
15015
15016 protected function propagate($level)
15017 {
15018 while ($this->decisions->validOffset($this->propagateIndex)) {
15019 $decision = $this->decisions->atOffset($this->propagateIndex);
15020
15021 $conflict = $this->watchGraph->propagateLiteral(
15022 $decision[Decisions::DECISION_LITERAL],
15023 $level,
15024 $this->decisions
15025 );
15026
15027 $this->propagateIndex++;
15028
15029 if ($conflict) {
15030 return $conflict;
15031 }
15032 }
15033
15034 return null;
15035 }
15036
15037
15038
15039
15040
15041
15042 private function revert($level)
15043 {
15044 while (!$this->decisions->isEmpty()) {
15045 $literal = $this->decisions->lastLiteral();
15046
15047 if ($this->decisions->undecided($literal)) {
15048 break;
15049 }
15050
15051 $decisionLevel = $this->decisions->decisionLevel($literal);
15052
15053 if ($decisionLevel <= $level) {
15054 break;
15055 }
15056
15057 $this->decisions->revertLast();
15058 $this->propagateIndex = count($this->decisions);
15059 }
15060
15061 while (!empty($this->branches) && $this->branches[count($this->branches) - 1][self::BRANCH_LEVEL] >= $level) {
15062 array_pop($this->branches);
15063 }
15064 }
15065
15066
15067
15068
15069
15070
15071
15072
15073
15074
15075
15076
15077
15078
15079
15080
15081
15082
15083
15084
15085 private function setPropagateLearn($level, $literal, $disableRules, Rule $rule)
15086 {
15087 $level++;
15088
15089 $this->decisions->decide($literal, $level, $rule);
15090
15091 while (true) {
15092 $rule = $this->propagate($level);
15093
15094 if (!$rule) {
15095 break;
15096 }
15097
15098 if ($level == 1) {
15099 return $this->analyzeUnsolvable($rule, $disableRules);
15100 }
15101
15102
15103 list($learnLiteral, $newLevel, $newRule, $why) = $this->analyze($level, $rule);
15104
15105 if ($newLevel <= 0 || $newLevel >= $level) {
15106 throw new SolverBugException(
15107 "Trying to revert to invalid level ".(int) $newLevel." from level ".(int) $level."."
15108 );
15109 } elseif (!$newRule) {
15110 throw new SolverBugException(
15111 "No rule was learned from analyzing $rule at level $level."
15112 );
15113 }
15114
15115 $level = $newLevel;
15116
15117 $this->revert($level);
15118
15119 $this->rules->add($newRule, RuleSet::TYPE_LEARNED);
15120
15121 $this->learnedWhy[spl_object_hash($newRule)] = $why;
15122
15123 $ruleNode = new RuleWatchNode($newRule);
15124 $ruleNode->watch2OnHighest($this->decisions);
15125 $this->watchGraph->insert($ruleNode);
15126
15127 $this->decisions->decide($learnLiteral, $level, $newRule);
15128 }
15129
15130 return $level;
15131 }
15132
15133
15134
15135
15136
15137
15138
15139
15140 private function selectAndInstall($level, array $decisionQueue, $disableRules, Rule $rule)
15141 {
15142
15143 $literals = $this->policy->selectPreferredPackages($this->pool, $this->installedMap, $decisionQueue, $rule->getRequiredPackage());
15144
15145 $selectedLiteral = array_shift($literals);
15146
15147
15148 if (count($literals)) {
15149 $this->branches[] = array($literals, $level);
15150 }
15151
15152 return $this->setPropagateLearn($level, $selectedLiteral, $disableRules, $rule);
15153 }
15154
15155
15156
15157
15158
15159
15160 protected function analyze($level, Rule $rule)
15161 {
15162 $analyzedRule = $rule;
15163 $ruleLevel = 1;
15164 $num = 0;
15165 $l1num = 0;
15166 $seen = array();
15167 $learnedLiterals = array(null);
15168
15169 $decisionId = count($this->decisions);
15170
15171 $this->learnedPool[] = array();
15172
15173 while (true) {
15174 $this->learnedPool[count($this->learnedPool) - 1][] = $rule;
15175
15176 foreach ($rule->getLiterals() as $literal) {
15177
15178 if ($this->decisions->satisfy($literal)) {
15179 continue;
15180 }
15181
15182 if (isset($seen[abs($literal)])) {
15183 continue;
15184 }
15185 $seen[abs($literal)] = true;
15186
15187 $l = $this->decisions->decisionLevel($literal);
15188
15189 if (1 === $l) {
15190 $l1num++;
15191 } elseif ($level === $l) {
15192 $num++;
15193 } else {
15194
15195 $learnedLiterals[] = $literal;
15196
15197 if ($l > $ruleLevel) {
15198 $ruleLevel = $l;
15199 }
15200 }
15201 }
15202
15203 $l1retry = true;
15204 while ($l1retry) {
15205 $l1retry = false;
15206
15207 if (!$num && !--$l1num) {
15208
15209 break 2;
15210 }
15211
15212 while (true) {
15213 if ($decisionId <= 0) {
15214 throw new SolverBugException(
15215 "Reached invalid decision id $decisionId while looking through $rule for a literal present in the analyzed rule $analyzedRule."
15216 );
15217 }
15218
15219 $decisionId--;
15220
15221 $decision = $this->decisions->atOffset($decisionId);
15222 $literal = $decision[Decisions::DECISION_LITERAL];
15223
15224 if (isset($seen[abs($literal)])) {
15225 break;
15226 }
15227 }
15228
15229 unset($seen[abs($literal)]);
15230
15231 if ($num && 0 === --$num) {
15232 if ($literal < 0) {
15233 $this->testFlagLearnedPositiveLiteral = true;
15234 }
15235 $learnedLiterals[0] = -$literal;
15236
15237 if (!$l1num) {
15238 break 2;
15239 }
15240
15241 foreach ($learnedLiterals as $i => $learnedLiteral) {
15242 if ($i !== 0) {
15243 unset($seen[abs($learnedLiteral)]);
15244 }
15245 }
15246
15247 $l1num++;
15248 $l1retry = true;
15249 }
15250 }
15251
15252 $decision = $this->decisions->atOffset($decisionId);
15253 $rule = $decision[Decisions::DECISION_REASON];
15254 }
15255
15256 $why = count($this->learnedPool) - 1;
15257
15258 if (!$learnedLiterals[0]) {
15259 throw new SolverBugException(
15260 "Did not find a learnable literal in analyzed rule $analyzedRule."
15261 );
15262 }
15263
15264 $newRule = new GenericRule($learnedLiterals, Rule::RULE_LEARNED, $why);
15265
15266 return array($learnedLiterals[0], $ruleLevel, $newRule, $why);
15267 }
15268
15269
15270
15271
15272
15273 private function analyzeUnsolvableRule(Problem $problem, Rule $conflictRule)
15274 {
15275 if ($conflictRule->getType() == RuleSet::TYPE_LEARNED) {
15276 $why = spl_object_hash($conflictRule);
15277 $learnedWhy = $this->learnedWhy[$why];
15278 $problemRules = $this->learnedPool[$learnedWhy];
15279
15280 foreach ($problemRules as $problemRule) {
15281 $this->analyzeUnsolvableRule($problem, $problemRule);
15282 }
15283
15284 return;
15285 }
15286
15287 if ($conflictRule->getType() == RuleSet::TYPE_PACKAGE) {
15288
15289 return;
15290 }
15291
15292 $problem->nextSection();
15293 $problem->addRule($conflictRule);
15294 }
15295
15296
15297
15298
15299
15300
15301 private function analyzeUnsolvable(Rule $conflictRule, $disableRules)
15302 {
15303 $problem = new Problem($this->pool);
15304 $problem->addRule($conflictRule);
15305
15306 $this->analyzeUnsolvableRule($problem, $conflictRule);
15307
15308 $this->problems[] = $problem;
15309
15310 $seen = array();
15311 $literals = $conflictRule->getLiterals();
15312
15313 foreach ($literals as $literal) {
15314
15315 if ($this->decisions->satisfy($literal)) {
15316 continue;
15317 }
15318 $seen[abs($literal)] = true;
15319 }
15320
15321 foreach ($this->decisions as $decision) {
15322 $literal = $decision[Decisions::DECISION_LITERAL];
15323
15324
15325 if (!isset($seen[abs($literal)])) {
15326 continue;
15327 }
15328
15329 $why = $decision[Decisions::DECISION_REASON];
15330
15331 $problem->addRule($why);
15332 $this->analyzeUnsolvableRule($problem, $why);
15333
15334 $literals = $why->getLiterals();
15335
15336 foreach ($literals as $literal) {
15337
15338 if ($this->decisions->satisfy($literal)) {
15339 continue;
15340 }
15341 $seen[abs($literal)] = true;
15342 }
15343 }
15344
15345 if ($disableRules) {
15346 foreach ($this->problems[count($this->problems) - 1] as $reason) {
15347 $this->disableProblem($reason['rule']);
15348 }
15349
15350 $this->resetSolver();
15351
15352 return 1;
15353 }
15354
15355 return 0;
15356 }
15357
15358
15359
15360
15361 private function disableProblem(Rule $why)
15362 {
15363 $job = $why->getJob();
15364
15365 if (!$job) {
15366 $why->disable();
15367
15368 return;
15369 }
15370
15371
15372 foreach ($this->rules as $rule) {
15373
15374 if ($job === $rule->getJob()) {
15375 $rule->disable();
15376 }
15377 }
15378 }
15379
15380 private function resetSolver()
15381 {
15382 $this->decisions->reset();
15383
15384 $this->propagateIndex = 0;
15385 $this->branches = array();
15386
15387 $this->enableDisableLearnedRules();
15388 $this->makeAssertionRuleDecisions();
15389 }
15390
15391
15392
15393
15394
15395
15396
15397
15398 private function enableDisableLearnedRules()
15399 {
15400 foreach ($this->rules->getIteratorFor(RuleSet::TYPE_LEARNED) as $rule) {
15401 $why = $this->learnedWhy[spl_object_hash($rule)];
15402 $problemRules = $this->learnedPool[$why];
15403
15404 $foundDisabled = false;
15405 foreach ($problemRules as $problemRule) {
15406 if ($problemRule->isDisabled()) {
15407 $foundDisabled = true;
15408 break;
15409 }
15410 }
15411
15412 if ($foundDisabled && $rule->isEnabled()) {
15413 $rule->disable();
15414 } elseif (!$foundDisabled && $rule->isDisabled()) {
15415 $rule->enable();
15416 }
15417 }
15418 }
15419
15420
15421
15422
15423 private function runSat($disableRules = true)
15424 {
15425 $this->propagateIndex = 0;
15426
15427
15428
15429
15430
15431
15432
15433
15434
15435
15436
15437 $decisionQueue = array();
15438
15439
15440
15441 $disableRules = array();
15442
15443 $level = 1;
15444 $systemLevel = $level + 1;
15445
15446 while (true) {
15447 if (1 === $level) {
15448 $conflictRule = $this->propagate($level);
15449 if (null !== $conflictRule) {
15450 if ($this->analyzeUnsolvable($conflictRule, $disableRules)) {
15451 continue;
15452 }
15453
15454 return;
15455 }
15456 }
15457
15458
15459 if ($level < $systemLevel) {
15460 $iterator = $this->rules->getIteratorFor(RuleSet::TYPE_JOB);
15461 foreach ($iterator as $rule) {
15462 if ($rule->isEnabled()) {
15463 $decisionQueue = array();
15464 $noneSatisfied = true;
15465
15466 foreach ($rule->getLiterals() as $literal) {
15467 if ($this->decisions->satisfy($literal)) {
15468 $noneSatisfied = false;
15469 break;
15470 }
15471 if ($literal > 0 && $this->decisions->undecided($literal)) {
15472 $decisionQueue[] = $literal;
15473 }
15474 }
15475
15476 if ($noneSatisfied && count($decisionQueue)) {
15477
15478
15479 if (count($this->installed) != count($this->updateMap)) {
15480 $prunedQueue = array();
15481 foreach ($decisionQueue as $literal) {
15482 if (isset($this->installedMap[abs($literal)])) {
15483 $prunedQueue[] = $literal;
15484 if (isset($this->updateMap[abs($literal)])) {
15485 $prunedQueue = $decisionQueue;
15486 break;
15487 }
15488 }
15489 }
15490 $decisionQueue = $prunedQueue;
15491 }
15492 }
15493
15494 if ($noneSatisfied && count($decisionQueue)) {
15495 $oLevel = $level;
15496 $level = $this->selectAndInstall($level, $decisionQueue, $disableRules, $rule);
15497
15498 if (0 === $level) {
15499 return;
15500 }
15501 if ($level <= $oLevel) {
15502 break;
15503 }
15504 }
15505 }
15506 }
15507
15508 $systemLevel = $level + 1;
15509
15510
15511 $iterator->next();
15512 if ($iterator->valid()) {
15513 continue;
15514 }
15515 }
15516
15517 if ($level < $systemLevel) {
15518 $systemLevel = $level;
15519 }
15520
15521 $rulesCount = count($this->rules);
15522 $pass = 1;
15523
15524 $this->io->writeError('Looking at all rules.', true, IOInterface::DEBUG);
15525 for ($i = 0, $n = 0; $n < $rulesCount; $i++, $n++) {
15526 if ($i == $rulesCount) {
15527 if (1 === $pass) {
15528 $this->io->writeError("Something's changed, looking at all rules again (pass #$pass)", false, IOInterface::DEBUG);
15529 } else {
15530 $this->io->overwriteError("Something's changed, looking at all rules again (pass #$pass)", false, null, IOInterface::DEBUG);
15531 }
15532
15533 $i = 0;
15534 $pass++;
15535 }
15536
15537 $rule = $this->rules->ruleById[$i];
15538 $literals = $rule->getLiterals();
15539
15540 if ($rule->isDisabled()) {
15541 continue;
15542 }
15543
15544 $decisionQueue = array();
15545
15546
15547
15548
15549
15550
15551
15552 foreach ($literals as $literal) {
15553 if ($literal <= 0) {
15554 if (!$this->decisions->decidedInstall($literal)) {
15555 continue 2; 
15556 }
15557 } else {
15558 if ($this->decisions->decidedInstall($literal)) {
15559 continue 2; 
15560 }
15561 if ($this->decisions->undecided($literal)) {
15562 $decisionQueue[] = $literal;
15563 }
15564 }
15565 }
15566
15567
15568 if (count($decisionQueue) < 2) {
15569 continue;
15570 }
15571
15572 $level = $this->selectAndInstall($level, $decisionQueue, $disableRules, $rule);
15573
15574 if (0 === $level) {
15575 return;
15576 }
15577
15578
15579 $rulesCount = count($this->rules);
15580 $n = -1;
15581 }
15582
15583 if ($level < $systemLevel) {
15584 continue;
15585 }
15586
15587
15588 if (count($this->branches)) {
15589 $lastLiteral = null;
15590 $lastLevel = null;
15591 $lastBranchIndex = 0;
15592 $lastBranchOffset = 0;
15593
15594 for ($i = count($this->branches) - 1; $i >= 0; $i--) {
15595 list($literals, $l) = $this->branches[$i];
15596
15597 foreach ($literals as $offset => $literal) {
15598 if ($literal && $literal > 0 && $this->decisions->decisionLevel($literal) > $l + 1) {
15599 $lastLiteral = $literal;
15600 $lastBranchIndex = $i;
15601 $lastBranchOffset = $offset;
15602 $lastLevel = $l;
15603 }
15604 }
15605 }
15606
15607 if ($lastLiteral) {
15608 unset($this->branches[$lastBranchIndex][self::BRANCH_LITERALS][$lastBranchOffset]);
15609
15610 $level = $lastLevel;
15611 $this->revert($level);
15612
15613 $why = $this->decisions->lastReason();
15614
15615 $level = $this->setPropagateLearn($level, $lastLiteral, $disableRules, $why);
15616
15617 if ($level == 0) {
15618 return;
15619 }
15620
15621 continue;
15622 }
15623 }
15624
15625 break;
15626 }
15627 }
15628 }
15629 <?php
15630
15631
15632
15633
15634
15635
15636
15637
15638
15639
15640
15641 namespace Composer\DependencyResolver;
15642
15643
15644
15645
15646 class SolverBugException extends \RuntimeException
15647 {
15648 public function __construct($message)
15649 {
15650 parent::__construct(
15651 $message."\nThis exception was most likely caused by a bug in Composer.\n".
15652 "Please report the command you ran, the exact error you received, and your composer.json on https://github.com/composer/composer/issues - thank you!\n"
15653 );
15654 }
15655 }
15656 <?php
15657
15658
15659
15660
15661
15662
15663
15664
15665
15666
15667
15668 namespace Composer\DependencyResolver;
15669
15670 use Composer\Util\IniHelper;
15671
15672
15673
15674
15675 class SolverProblemsException extends \RuntimeException
15676 {
15677 protected $problems;
15678 protected $installedMap;
15679
15680 public function __construct(array $problems, array $installedMap)
15681 {
15682 $this->problems = $problems;
15683 $this->installedMap = $installedMap;
15684
15685 parent::__construct($this->createMessage(), 2);
15686 }
15687
15688 protected function createMessage()
15689 {
15690 $text = "\n";
15691 $hasExtensionProblems = false;
15692 foreach ($this->problems as $i => $problem) {
15693 $text .= "  Problem ".($i + 1).$problem->getPrettyString($this->installedMap)."\n";
15694
15695 if (!$hasExtensionProblems && $this->hasExtensionProblems($problem->getReasons())) {
15696 $hasExtensionProblems = true;
15697 }
15698 }
15699
15700 if (strpos($text, 'could not be found') || strpos($text, 'no matching package found')) {
15701 $text .= "\nPotential causes:\n - A typo in the package name\n - The package is not available in a stable-enough version according to your minimum-stability setting\n   see <https://getcomposer.org/doc/04-schema.md#minimum-stability> for more details.\n - It's a private package and you forgot to add a custom repository to find it\n\nRead <https://getcomposer.org/doc/articles/troubleshooting.md> for further common problems.";
15702 }
15703
15704 if ($hasExtensionProblems) {
15705 $text .= $this->createExtensionHint();
15706 }
15707
15708 return $text;
15709 }
15710
15711 public function getProblems()
15712 {
15713 return $this->problems;
15714 }
15715
15716 private function createExtensionHint()
15717 {
15718 $paths = IniHelper::getAll();
15719
15720 if (count($paths) === 1 && empty($paths[0])) {
15721 return '';
15722 }
15723
15724 $text = "\n  To enable extensions, verify that they are enabled in your .ini files:\n    - ";
15725 $text .= implode("\n    - ", $paths);
15726 $text .= "\n  You can also run `php --ini` inside terminal to see which files are used by PHP in CLI mode.";
15727
15728 return $text;
15729 }
15730
15731 private function hasExtensionProblems(array $reasonSets)
15732 {
15733 foreach ($reasonSets as $reasonSet) {
15734 foreach ($reasonSet as $reason) {
15735 if (isset($reason["rule"]) && 0 === strpos($reason["rule"]->getRequiredPackage(), 'ext-')) {
15736 return true;
15737 }
15738 }
15739 }
15740
15741 return false;
15742 }
15743 }
15744 <?php
15745
15746
15747
15748
15749
15750
15751
15752
15753
15754
15755
15756 namespace Composer\DependencyResolver;
15757
15758 use Composer\Package\AliasPackage;
15759
15760
15761
15762
15763 class Transaction
15764 {
15765 protected $policy;
15766 protected $pool;
15767 protected $installedMap;
15768 protected $decisions;
15769 protected $transaction;
15770
15771 public function __construct($policy, $pool, $installedMap, $decisions)
15772 {
15773 $this->policy = $policy;
15774 $this->pool = $pool;
15775 $this->installedMap = $installedMap;
15776 $this->decisions = $decisions;
15777 $this->transaction = array();
15778 }
15779
15780 public function getOperations()
15781 {
15782 $installMeansUpdateMap = $this->findUpdates();
15783
15784 $updateMap = array();
15785 $installMap = array();
15786 $uninstallMap = array();
15787
15788 foreach ($this->decisions as $i => $decision) {
15789 $literal = $decision[Decisions::DECISION_LITERAL];
15790 $reason = $decision[Decisions::DECISION_REASON];
15791
15792 $package = $this->pool->literalToPackage($literal);
15793
15794
15795 if (($literal > 0) == isset($this->installedMap[$package->id])) {
15796 continue;
15797 }
15798
15799 if ($literal > 0) {
15800 if (isset($installMeansUpdateMap[abs($literal)]) && !$package instanceof AliasPackage) {
15801 $source = $installMeansUpdateMap[abs($literal)];
15802
15803 $updateMap[$package->id] = array(
15804 'package' => $package,
15805 'source' => $source,
15806 'reason' => $reason,
15807 );
15808
15809
15810 unset($installMeansUpdateMap[abs($literal)]);
15811 $ignoreRemove[$source->id] = true;
15812 } else {
15813 $installMap[$package->id] = array(
15814 'package' => $package,
15815 'reason' => $reason,
15816 );
15817 }
15818 }
15819 }
15820
15821 foreach ($this->decisions as $i => $decision) {
15822 $literal = $decision[Decisions::DECISION_LITERAL];
15823 $reason = $decision[Decisions::DECISION_REASON];
15824 $package = $this->pool->literalToPackage($literal);
15825
15826 if ($literal <= 0 &&
15827 isset($this->installedMap[$package->id]) &&
15828 !isset($ignoreRemove[$package->id])) {
15829 $uninstallMap[$package->id] = array(
15830 'package' => $package,
15831 'reason' => $reason,
15832 );
15833 }
15834 }
15835
15836 $this->transactionFromMaps($installMap, $updateMap, $uninstallMap);
15837
15838 return $this->transaction;
15839 }
15840
15841 protected function transactionFromMaps($installMap, $updateMap, $uninstallMap)
15842 {
15843 $queue = array_map(
15844 function ($operation) {
15845 return $operation['package'];
15846 },
15847 $this->findRootPackages($installMap, $updateMap)
15848 );
15849
15850 $visited = array();
15851
15852 while (!empty($queue)) {
15853 $package = array_pop($queue);
15854 $packageId = $package->id;
15855
15856 if (!isset($visited[$packageId])) {
15857 $queue[] = $package;
15858
15859 if ($package instanceof AliasPackage) {
15860 $queue[] = $package->getAliasOf();
15861 } else {
15862 foreach ($package->getRequires() as $link) {
15863 $possibleRequires = $this->pool->whatProvides($link->getTarget(), $link->getConstraint());
15864
15865 foreach ($possibleRequires as $require) {
15866 $queue[] = $require;
15867 }
15868 }
15869 }
15870
15871 $visited[$package->id] = true;
15872 } else {
15873 if (isset($installMap[$packageId])) {
15874 $this->install(
15875 $installMap[$packageId]['package'],
15876 $installMap[$packageId]['reason']
15877 );
15878 unset($installMap[$packageId]);
15879 }
15880 if (isset($updateMap[$packageId])) {
15881 $this->update(
15882 $updateMap[$packageId]['source'],
15883 $updateMap[$packageId]['package'],
15884 $updateMap[$packageId]['reason']
15885 );
15886 unset($updateMap[$packageId]);
15887 }
15888 }
15889 }
15890
15891 foreach ($uninstallMap as $uninstall) {
15892 $this->uninstall($uninstall['package'], $uninstall['reason']);
15893 }
15894 }
15895
15896 protected function findRootPackages($installMap, $updateMap)
15897 {
15898 $packages = $installMap + $updateMap;
15899 $roots = $packages;
15900
15901 foreach ($packages as $packageId => $operation) {
15902 $package = $operation['package'];
15903
15904 if (!isset($roots[$packageId])) {
15905 continue;
15906 }
15907
15908 foreach ($package->getRequires() as $link) {
15909 $possibleRequires = $this->pool->whatProvides($link->getTarget(), $link->getConstraint());
15910
15911 foreach ($possibleRequires as $require) {
15912 if ($require !== $package) {
15913 unset($roots[$require->id]);
15914 }
15915 }
15916 }
15917 }
15918
15919 return $roots;
15920 }
15921
15922 protected function findUpdates()
15923 {
15924 $installMeansUpdateMap = array();
15925
15926 foreach ($this->decisions as $i => $decision) {
15927 $literal = $decision[Decisions::DECISION_LITERAL];
15928 $package = $this->pool->literalToPackage($literal);
15929
15930 if ($package instanceof AliasPackage) {
15931 continue;
15932 }
15933
15934
15935 if ($literal <= 0 && isset($this->installedMap[$package->id])) {
15936 $updates = $this->policy->findUpdatePackages($this->pool, $this->installedMap, $package);
15937
15938 $literals = array($package->id);
15939
15940 foreach ($updates as $update) {
15941 $literals[] = $update->id;
15942 }
15943
15944 foreach ($literals as $updateLiteral) {
15945 if ($updateLiteral !== $literal) {
15946 $installMeansUpdateMap[abs($updateLiteral)] = $package;
15947 }
15948 }
15949 }
15950 }
15951
15952 return $installMeansUpdateMap;
15953 }
15954
15955 protected function install($package, $reason)
15956 {
15957 if ($package instanceof AliasPackage) {
15958 return $this->markAliasInstalled($package, $reason);
15959 }
15960
15961 $this->transaction[] = new Operation\InstallOperation($package, $reason);
15962 }
15963
15964 protected function update($from, $to, $reason)
15965 {
15966 $this->transaction[] = new Operation\UpdateOperation($from, $to, $reason);
15967 }
15968
15969 protected function uninstall($package, $reason)
15970 {
15971 if ($package instanceof AliasPackage) {
15972 return $this->markAliasUninstalled($package, $reason);
15973 }
15974
15975 $this->transaction[] = new Operation\UninstallOperation($package, $reason);
15976 }
15977
15978 protected function markAliasInstalled($package, $reason)
15979 {
15980 $this->transaction[] = new Operation\MarkAliasInstalledOperation($package, $reason);
15981 }
15982
15983 protected function markAliasUninstalled($package, $reason)
15984 {
15985 $this->transaction[] = new Operation\MarkAliasUninstalledOperation($package, $reason);
15986 }
15987 }
15988 <?php
15989
15990
15991
15992
15993
15994
15995
15996
15997
15998
15999
16000 namespace Composer\Downloader;
16001
16002 use Composer\Package\PackageInterface;
16003 use Symfony\Component\Finder\Finder;
16004 use Composer\IO\IOInterface;
16005
16006
16007
16008
16009
16010
16011
16012
16013 abstract class ArchiveDownloader extends FileDownloader
16014 {
16015
16016
16017
16018
16019
16020 public function download(PackageInterface $package, $path, $output = true)
16021 {
16022 $temporaryDir = $this->config->get('vendor-dir').'/composer/'.substr(md5(uniqid('', true)), 0, 8);
16023 $retries = 3;
16024 while ($retries--) {
16025 $fileName = parent::download($package, $path, $output);
16026
16027 if ($output) {
16028 $this->io->writeError(' Extracting archive', false, IOInterface::VERBOSE);
16029 }
16030
16031 try {
16032 $this->filesystem->ensureDirectoryExists($temporaryDir);
16033 try {
16034 $this->extract($fileName, $temporaryDir);
16035 } catch (\Exception $e) {
16036
16037 parent::clearLastCacheWrite($package);
16038 throw $e;
16039 }
16040
16041 $this->filesystem->unlink($fileName);
16042
16043 $contentDir = $this->getFolderContent($temporaryDir);
16044
16045
16046 if (1 === count($contentDir) && is_dir(reset($contentDir))) {
16047 $contentDir = $this->getFolderContent((string) reset($contentDir));
16048 }
16049
16050
16051 foreach ($contentDir as $file) {
16052 $file = (string) $file;
16053 $this->filesystem->rename($file, $path . '/' . basename($file));
16054 }
16055
16056 $this->filesystem->removeDirectory($temporaryDir);
16057 if ($this->filesystem->isDirEmpty($this->config->get('vendor-dir').'/composer/')) {
16058 $this->filesystem->removeDirectory($this->config->get('vendor-dir').'/composer/');
16059 }
16060 if ($this->filesystem->isDirEmpty($this->config->get('vendor-dir'))) {
16061 $this->filesystem->removeDirectory($this->config->get('vendor-dir'));
16062 }
16063 } catch (\Exception $e) {
16064
16065 $this->filesystem->removeDirectory($path);
16066 $this->filesystem->removeDirectory($temporaryDir);
16067
16068
16069 if ($retries && $e instanceof \UnexpectedValueException && class_exists('ZipArchive') && $e->getCode() === \ZipArchive::ER_NOZIP) {
16070 $this->io->writeError('');
16071 if ($this->io->isDebug()) {
16072 $this->io->writeError('    Invalid zip file ('.$e->getMessage().'), retrying...');
16073 } else {
16074 $this->io->writeError('    Invalid zip file, retrying...');
16075 }
16076 usleep(500000);
16077 continue;
16078 }
16079
16080 throw $e;
16081 }
16082
16083 break;
16084 }
16085 }
16086
16087
16088
16089
16090 protected function getFileName(PackageInterface $package, $path)
16091 {
16092 return rtrim($path.'/'.md5($path.spl_object_hash($package)).'.'.pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_EXTENSION), '.');
16093 }
16094
16095
16096
16097
16098
16099
16100
16101
16102
16103 abstract protected function extract($file, $path);
16104
16105
16106
16107
16108
16109
16110
16111 private function getFolderContent($dir)
16112 {
16113 $finder = Finder::create()
16114 ->ignoreVCS(false)
16115 ->ignoreDotFiles(false)
16116 ->notName('.DS_Store')
16117 ->depth(0)
16118 ->in($dir);
16119
16120 return iterator_to_array($finder);
16121 }
16122 }
16123 <?php
16124
16125
16126
16127
16128
16129
16130
16131
16132
16133
16134
16135 namespace Composer\Downloader;
16136
16137 use Composer\Package\PackageInterface;
16138
16139
16140
16141
16142
16143
16144 interface ChangeReportInterface
16145 {
16146
16147
16148
16149
16150
16151
16152
16153 public function getLocalChanges(PackageInterface $package, $path);
16154 }
16155 <?php
16156
16157
16158
16159
16160
16161
16162
16163
16164
16165
16166
16167 namespace Composer\Downloader;
16168
16169 use Composer\Package\PackageInterface;
16170 use Composer\IO\IOInterface;
16171 use Composer\Util\Filesystem;
16172
16173
16174
16175
16176
16177
16178 class DownloadManager
16179 {
16180 private $io;
16181 private $preferDist = false;
16182 private $preferSource = false;
16183 private $packagePreferences = array();
16184 private $filesystem;
16185 private $downloaders = array();
16186
16187
16188
16189
16190
16191
16192
16193
16194 public function __construct(IOInterface $io, $preferSource = false, Filesystem $filesystem = null)
16195 {
16196 $this->io = $io;
16197 $this->preferSource = $preferSource;
16198 $this->filesystem = $filesystem ?: new Filesystem();
16199 }
16200
16201
16202
16203
16204
16205
16206
16207 public function setPreferSource($preferSource)
16208 {
16209 $this->preferSource = $preferSource;
16210
16211 return $this;
16212 }
16213
16214
16215
16216
16217
16218
16219
16220 public function setPreferDist($preferDist)
16221 {
16222 $this->preferDist = $preferDist;
16223
16224 return $this;
16225 }
16226
16227
16228
16229
16230
16231
16232
16233 public function setPreferences(array $preferences)
16234 {
16235 $this->packagePreferences = $preferences;
16236
16237 return $this;
16238 }
16239
16240
16241
16242
16243
16244
16245
16246
16247 public function setOutputProgress($outputProgress)
16248 {
16249 foreach ($this->downloaders as $downloader) {
16250 $downloader->setOutputProgress($outputProgress);
16251 }
16252
16253 return $this;
16254 }
16255
16256
16257
16258
16259
16260
16261
16262
16263 public function setDownloader($type, DownloaderInterface $downloader)
16264 {
16265 $type = strtolower($type);
16266 $this->downloaders[$type] = $downloader;
16267
16268 return $this;
16269 }
16270
16271
16272
16273
16274
16275
16276
16277
16278 public function getDownloader($type)
16279 {
16280 $type = strtolower($type);
16281 if (!isset($this->downloaders[$type])) {
16282 throw new \InvalidArgumentException(sprintf('Unknown downloader type: %s. Available types: %s.', $type, implode(', ', array_keys($this->downloaders))));
16283 }
16284
16285 return $this->downloaders[$type];
16286 }
16287
16288
16289
16290
16291
16292
16293
16294
16295
16296
16297 public function getDownloaderForInstalledPackage(PackageInterface $package)
16298 {
16299 $installationSource = $package->getInstallationSource();
16300
16301 if ('metapackage' === $package->getType()) {
16302 return;
16303 }
16304
16305 if ('dist' === $installationSource) {
16306 $downloader = $this->getDownloader($package->getDistType());
16307 } elseif ('source' === $installationSource) {
16308 $downloader = $this->getDownloader($package->getSourceType());
16309 } else {
16310 throw new \InvalidArgumentException(
16311 'Package '.$package.' seems not been installed properly'
16312 );
16313 }
16314
16315 if ($installationSource !== $downloader->getInstallationSource()) {
16316 throw new \LogicException(sprintf(
16317 'Downloader "%s" is a %s type downloader and can not be used to download %s for package %s',
16318 get_class($downloader),
16319 $downloader->getInstallationSource(),
16320 $installationSource,
16321 $package
16322 ));
16323 }
16324
16325 return $downloader;
16326 }
16327
16328
16329
16330
16331
16332
16333
16334
16335
16336
16337
16338 public function download(PackageInterface $package, $targetDir, $preferSource = null)
16339 {
16340 $preferSource = null !== $preferSource ? $preferSource : $this->preferSource;
16341 $sourceType = $package->getSourceType();
16342 $distType = $package->getDistType();
16343
16344 $sources = array();
16345 if ($sourceType) {
16346 $sources[] = 'source';
16347 }
16348 if ($distType) {
16349 $sources[] = 'dist';
16350 }
16351
16352 if (empty($sources)) {
16353 throw new \InvalidArgumentException('Package '.$package.' must have a source or dist specified');
16354 }
16355
16356 if (!$preferSource && ($this->preferDist || 'dist' === $this->resolvePackageInstallPreference($package))) {
16357 $sources = array_reverse($sources);
16358 }
16359
16360 $this->filesystem->ensureDirectoryExists($targetDir);
16361
16362 foreach ($sources as $i => $source) {
16363 if (isset($e)) {
16364 $this->io->writeError('    <warning>Now trying to download from ' . $source . '</warning>');
16365 }
16366 $package->setInstallationSource($source);
16367 try {
16368 $downloader = $this->getDownloaderForInstalledPackage($package);
16369 if ($downloader) {
16370 $downloader->download($package, $targetDir);
16371 }
16372 break;
16373 } catch (\RuntimeException $e) {
16374 if ($i === count($sources) - 1) {
16375 throw $e;
16376 }
16377
16378 $this->io->writeError(
16379 '    <warning>Failed to download '.
16380 $package->getPrettyName().
16381 ' from ' . $source . ': '.
16382 $e->getMessage().'</warning>'
16383 );
16384 }
16385 }
16386 }
16387
16388
16389
16390
16391
16392
16393
16394
16395
16396
16397 public function update(PackageInterface $initial, PackageInterface $target, $targetDir)
16398 {
16399 $downloader = $this->getDownloaderForInstalledPackage($initial);
16400 if (!$downloader) {
16401 return;
16402 }
16403
16404 $installationSource = $initial->getInstallationSource();
16405
16406 if ('dist' === $installationSource) {
16407 $initialType = $initial->getDistType();
16408 $targetType = $target->getDistType();
16409 } else {
16410 $initialType = $initial->getSourceType();
16411 $targetType = $target->getSourceType();
16412 }
16413
16414
16415 if ($target->isDev() && 'dist' === $installationSource) {
16416 $downloader->remove($initial, $targetDir);
16417 $this->download($target, $targetDir);
16418
16419 return;
16420 }
16421
16422 if ($initialType === $targetType) {
16423 $target->setInstallationSource($installationSource);
16424 try {
16425 $downloader->update($initial, $target, $targetDir);
16426
16427 return;
16428 } catch (\RuntimeException $e) {
16429 if (!$this->io->isInteractive()) {
16430 throw $e;
16431 }
16432 $this->io->writeError('<error>    Update failed ('.$e->getMessage().')</error>');
16433 if (!$this->io->askConfirmation('    Would you like to try reinstalling the package instead [<comment>yes</comment>]? ', true)) {
16434 throw $e;
16435 }
16436 }
16437 }
16438
16439 $downloader->remove($initial, $targetDir);
16440 $this->download($target, $targetDir, 'source' === $installationSource);
16441 }
16442
16443
16444
16445
16446
16447
16448
16449 public function remove(PackageInterface $package, $targetDir)
16450 {
16451 $downloader = $this->getDownloaderForInstalledPackage($package);
16452 if ($downloader) {
16453 $downloader->remove($package, $targetDir);
16454 }
16455 }
16456
16457
16458
16459
16460
16461
16462
16463
16464 protected function resolvePackageInstallPreference(PackageInterface $package)
16465 {
16466 foreach ($this->packagePreferences as $pattern => $preference) {
16467 $pattern = '{^'.str_replace('\\*', '.*', preg_quote($pattern)).'$}i';
16468 if (preg_match($pattern, $package->getName())) {
16469 if ('dist' === $preference || (!$package->isDev() && 'auto' === $preference)) {
16470 return 'dist';
16471 }
16472
16473 return 'source';
16474 }
16475 }
16476
16477 return $package->isDev() ? 'source' : 'dist';
16478 }
16479 }
16480 <?php
16481
16482
16483
16484
16485
16486
16487
16488
16489
16490
16491
16492 namespace Composer\Downloader;
16493
16494 use Composer\Package\PackageInterface;
16495
16496
16497
16498
16499
16500
16501
16502 interface DownloaderInterface
16503 {
16504
16505
16506
16507
16508
16509 public function getInstallationSource();
16510
16511
16512
16513
16514
16515
16516
16517 public function download(PackageInterface $package, $path);
16518
16519
16520
16521
16522
16523
16524
16525
16526 public function update(PackageInterface $initial, PackageInterface $target, $path);
16527
16528
16529
16530
16531
16532
16533
16534 public function remove(PackageInterface $package, $path);
16535
16536
16537
16538
16539
16540
16541
16542 public function setOutputProgress($outputProgress);
16543 }
16544 <?php
16545
16546
16547
16548
16549
16550
16551
16552
16553
16554
16555
16556 namespace Composer\Downloader;
16557
16558 use Composer\Package\PackageInterface;
16559
16560
16561
16562
16563
16564
16565 interface DvcsDownloaderInterface
16566 {
16567
16568
16569
16570
16571
16572
16573
16574 public function getUnpushedChanges(PackageInterface $package, $path);
16575 }
16576 <?php
16577
16578
16579
16580
16581
16582
16583
16584
16585
16586
16587
16588 namespace Composer\Downloader;
16589
16590 use Composer\Config;
16591 use Composer\Cache;
16592 use Composer\Factory;
16593 use Composer\IO\IOInterface;
16594 use Composer\IO\NullIO;
16595 use Composer\Package\Comparer\Comparer;
16596 use Composer\Package\PackageInterface;
16597 use Composer\Package\Version\VersionParser;
16598 use Composer\Plugin\PluginEvents;
16599 use Composer\Plugin\PreFileDownloadEvent;
16600 use Composer\EventDispatcher\EventDispatcher;
16601 use Composer\Util\Filesystem;
16602 use Composer\Util\RemoteFilesystem;
16603 use Composer\Util\Url as UrlUtil;
16604
16605
16606
16607
16608
16609
16610
16611
16612
16613 class FileDownloader implements DownloaderInterface, ChangeReportInterface
16614 {
16615 protected $io;
16616 protected $config;
16617 protected $rfs;
16618 protected $filesystem;
16619 protected $cache;
16620 protected $outputProgress = true;
16621 private $lastCacheWrites = array();
16622 private $eventDispatcher;
16623
16624
16625
16626
16627
16628
16629
16630
16631
16632
16633
16634 public function __construct(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, Cache $cache = null, RemoteFilesystem $rfs = null, Filesystem $filesystem = null)
16635 {
16636 $this->io = $io;
16637 $this->config = $config;
16638 $this->eventDispatcher = $eventDispatcher;
16639 $this->rfs = $rfs ?: Factory::createRemoteFilesystem($this->io, $config);
16640 $this->filesystem = $filesystem ?: new Filesystem();
16641 $this->cache = $cache;
16642
16643 if ($this->cache && $this->cache->gcIsNecessary()) {
16644 $this->cache->gc($config->get('cache-files-ttl'), $config->get('cache-files-maxsize'));
16645 }
16646 }
16647
16648
16649
16650
16651 public function getInstallationSource()
16652 {
16653 return 'dist';
16654 }
16655
16656
16657
16658
16659 public function download(PackageInterface $package, $path, $output = true)
16660 {
16661 if (!$package->getDistUrl()) {
16662 throw new \InvalidArgumentException('The given package is missing url information');
16663 }
16664
16665 if ($output) {
16666 $this->io->writeError("  - Installing <info>" . $package->getName() . "</info> (<comment>" . $package->getFullPrettyVersion() . "</comment>): ", false);
16667 }
16668
16669 $urls = $package->getDistUrls();
16670 while ($url = array_shift($urls)) {
16671 try {
16672 $fileName = $this->doDownload($package, $path, $url);
16673 break;
16674 } catch (\Exception $e) {
16675 if ($this->io->isDebug()) {
16676 $this->io->writeError('');
16677 $this->io->writeError('Failed: ['.get_class($e).'] '.$e->getCode().': '.$e->getMessage());
16678 } elseif (count($urls)) {
16679 $this->io->writeError('');
16680 $this->io->writeError(' Failed, trying the next URL ('.$e->getCode().': '.$e->getMessage().')', false);
16681 }
16682
16683 if (!count($urls)) {
16684 throw $e;
16685 }
16686 }
16687 }
16688
16689 if ($output) {
16690 $this->io->writeError('');
16691 }
16692
16693 return $fileName;
16694 }
16695
16696 protected function doDownload(PackageInterface $package, $path, $url)
16697 {
16698 $this->filesystem->emptyDirectory($path);
16699
16700 $fileName = $this->getFileName($package, $path);
16701
16702 $processedUrl = $this->processUrl($package, $url);
16703 $origin = RemoteFilesystem::getOrigin($processedUrl);
16704
16705 $preFileDownloadEvent = new PreFileDownloadEvent(PluginEvents::PRE_FILE_DOWNLOAD, $this->rfs, $processedUrl);
16706 if ($this->eventDispatcher) {
16707 $this->eventDispatcher->dispatch($preFileDownloadEvent->getName(), $preFileDownloadEvent);
16708 }
16709 $rfs = $preFileDownloadEvent->getRemoteFilesystem();
16710
16711 try {
16712 $checksum = $package->getDistSha1Checksum();
16713 $cacheKey = $this->getCacheKey($package, $processedUrl);
16714
16715
16716 if ($this->cache && (!$checksum || $checksum === $this->cache->sha1($cacheKey)) && $this->cache->copyTo($cacheKey, $fileName)) {
16717 $this->io->writeError('Loading from cache', false);
16718 } else {
16719
16720 if (!$this->outputProgress) {
16721 $this->io->writeError('Downloading', false);
16722 }
16723
16724
16725 $retries = 3;
16726 while ($retries--) {
16727 try {
16728 $rfs->copy($origin, $processedUrl, $fileName, $this->outputProgress, $package->getTransportOptions());
16729 break;
16730 } catch (TransportException $e) {
16731
16732 if ((0 !== $e->getCode() && !in_array($e->getCode(), array(500, 502, 503, 504))) || !$retries) {
16733 throw $e;
16734 }
16735 $this->io->writeError('');
16736 $this->io->writeError('    Download failed, retrying...', true, IOInterface::VERBOSE);
16737 usleep(500000);
16738 }
16739 }
16740
16741 if (!$this->outputProgress) {
16742 $this->io->writeError(' (<comment>100%</comment>)', false);
16743 }
16744
16745 if ($this->cache) {
16746 $this->lastCacheWrites[$package->getName()] = $cacheKey;
16747 $this->cache->copyFrom($cacheKey, $fileName);
16748 }
16749 }
16750
16751 if (!file_exists($fileName)) {
16752 throw new \UnexpectedValueException($url.' could not be saved to '.$fileName.', make sure the'
16753 .' directory is writable and you have internet connectivity');
16754 }
16755
16756 if ($checksum && hash_file('sha1', $fileName) !== $checksum) {
16757 throw new \UnexpectedValueException('The checksum verification of the file failed (downloaded from '.$url.')');
16758 }
16759 } catch (\Exception $e) {
16760
16761 $this->filesystem->removeDirectory($path);
16762 $this->clearLastCacheWrite($package);
16763 throw $e;
16764 }
16765
16766 return $fileName;
16767 }
16768
16769
16770
16771
16772 public function setOutputProgress($outputProgress)
16773 {
16774 $this->outputProgress = $outputProgress;
16775
16776 return $this;
16777 }
16778
16779 protected function clearLastCacheWrite(PackageInterface $package)
16780 {
16781 if ($this->cache && isset($this->lastCacheWrites[$package->getName()])) {
16782 $this->cache->remove($this->lastCacheWrites[$package->getName()]);
16783 unset($this->lastCacheWrites[$package->getName()]);
16784 }
16785 }
16786
16787
16788
16789
16790 public function update(PackageInterface $initial, PackageInterface $target, $path)
16791 {
16792 $name = $target->getName();
16793 $from = $initial->getFullPrettyVersion();
16794 $to = $target->getFullPrettyVersion();
16795
16796 $actionName = VersionParser::isUpgrade($initial->getVersion(), $target->getVersion()) ? 'Updating' : 'Downgrading';
16797 $this->io->writeError("  - " . $actionName . " <info>" . $name . "</info> (<comment>" . $from . "</comment> => <comment>" . $to . "</comment>): ", false);
16798
16799 $this->remove($initial, $path, false);
16800 $this->download($target, $path, false);
16801
16802 $this->io->writeError('');
16803 }
16804
16805
16806
16807
16808 public function remove(PackageInterface $package, $path, $output = true)
16809 {
16810 if ($output) {
16811 $this->io->writeError("  - Removing <info>" . $package->getName() . "</info> (<comment>" . $package->getFullPrettyVersion() . "</comment>)");
16812 }
16813 if (!$this->filesystem->removeDirectory($path)) {
16814 throw new \RuntimeException('Could not completely delete '.$path.', aborting.');
16815 }
16816 }
16817
16818
16819
16820
16821
16822
16823
16824
16825 protected function getFileName(PackageInterface $package, $path)
16826 {
16827 return $path.'/'.pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_BASENAME);
16828 }
16829
16830
16831
16832
16833
16834
16835
16836
16837
16838 protected function processUrl(PackageInterface $package, $url)
16839 {
16840 if (!extension_loaded('openssl') && 0 === strpos($url, 'https:')) {
16841 throw new \RuntimeException('You must enable the openssl extension to download files via https');
16842 }
16843
16844 if ($package->getDistReference()) {
16845 $url = UrlUtil::updateDistReference($this->config, $url, $package->getDistReference());
16846 }
16847
16848 return $url;
16849 }
16850
16851 private function getCacheKey(PackageInterface $package, $processedUrl)
16852 {
16853
16854
16855
16856
16857 $cacheKey = sha1($processedUrl);
16858
16859 return $package->getName().'/'.$cacheKey.'.'.$package->getDistType();
16860 }
16861
16862
16863
16864
16865
16866 public function getLocalChanges(PackageInterface $package, $targetDir)
16867 {
16868 $prevIO = $this->io;
16869 $prevProgress = $this->outputProgress;
16870
16871 $this->io = new NullIO;
16872 $this->io->loadConfiguration($this->config);
16873 $this->outputProgress = false;
16874 $e = null;
16875
16876 try {
16877 $this->download($package, $targetDir.'_compare', false);
16878
16879 $comparer = new Comparer();
16880 $comparer->setSource($targetDir.'_compare');
16881 $comparer->setUpdate($targetDir);
16882 $comparer->doCompare();
16883 $output = $comparer->getChanged(true, true);
16884 $this->filesystem->removeDirectory($targetDir.'_compare');
16885 } catch (\Exception $e) {
16886 }
16887
16888 $this->io = $prevIO;
16889 $this->outputProgress = $prevProgress;
16890
16891 if ($e) {
16892 throw $e;
16893 }
16894
16895 return trim($output);
16896 }
16897 }
16898 <?php
16899
16900
16901
16902
16903
16904
16905
16906
16907
16908
16909
16910 namespace Composer\Downloader;
16911
16912
16913
16914
16915
16916
16917 class FilesystemException extends \Exception
16918 {
16919 public function __construct($message = '', $code = 0, \Exception $previous = null)
16920 {
16921 parent::__construct("Filesystem exception: \n".$message, $code, $previous);
16922 }
16923 }
16924 <?php
16925
16926
16927
16928
16929
16930
16931
16932
16933
16934
16935
16936 namespace Composer\Downloader;
16937
16938 use Composer\Package\PackageInterface;
16939 use Composer\Util\ProcessExecutor;
16940
16941
16942
16943
16944 class FossilDownloader extends VcsDownloader
16945 {
16946
16947
16948
16949 public function doDownload(PackageInterface $package, $path, $url)
16950 {
16951
16952 $this->config->prohibitUrlByConfig($url, $this->io);
16953
16954 $url = ProcessExecutor::escape($url);
16955 $ref = ProcessExecutor::escape($package->getSourceReference());
16956 $repoFile = $path . '.fossil';
16957 $this->io->writeError("Cloning ".$package->getSourceReference());
16958 $command = sprintf('fossil clone %s %s', $url, ProcessExecutor::escape($repoFile));
16959 if (0 !== $this->process->execute($command, $ignoredOutput)) {
16960 throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
16961 }
16962 $command = sprintf('fossil open %s --nested', ProcessExecutor::escape($repoFile));
16963 if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) {
16964 throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
16965 }
16966 $command = sprintf('fossil update %s', $ref);
16967 if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) {
16968 throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
16969 }
16970 }
16971
16972
16973
16974
16975 public function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url)
16976 {
16977
16978 $this->config->prohibitUrlByConfig($url, $this->io);
16979
16980 $url = ProcessExecutor::escape($url);
16981 $ref = ProcessExecutor::escape($target->getSourceReference());
16982 $this->io->writeError(" Updating to ".$target->getSourceReference());
16983
16984 if (!$this->hasMetadataRepository($path)) {
16985 throw new \RuntimeException('The .fslckout file is missing from '.$path.', see https://getcomposer.org/commit-deps for more information');
16986 }
16987
16988 $command = sprintf('fossil pull && fossil up %s', $ref);
16989 if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) {
16990 throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
16991 }
16992 }
16993
16994
16995
16996
16997 public function getLocalChanges(PackageInterface $package, $path)
16998 {
16999 if (!$this->hasMetadataRepository($path)) {
17000 return null;
17001 }
17002
17003 $this->process->execute('fossil changes', $output, realpath($path));
17004
17005 return trim($output) ?: null;
17006 }
17007
17008
17009
17010
17011 protected function getCommitLogs($fromReference, $toReference, $path)
17012 {
17013 $command = sprintf('fossil timeline -t ci -W 0 -n 0 before %s', ProcessExecutor::escape($toReference));
17014
17015 if (0 !== $this->process->execute($command, $output, realpath($path))) {
17016 throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
17017 }
17018
17019 $log = '';
17020 $match = '/\d\d:\d\d:\d\d\s+\[' . $toReference . '\]/';
17021
17022 foreach ($this->process->splitLines($output) as $line) {
17023 if (preg_match($match, $line)) {
17024 break;
17025 }
17026 $log .= $line;
17027 }
17028
17029 return $log;
17030 }
17031
17032
17033
17034
17035 protected function hasMetadataRepository($path)
17036 {
17037 return is_file($path . '/.fslckout') || is_file($path . '/_FOSSIL_');
17038 }
17039 }
17040 <?php
17041
17042
17043
17044
17045
17046
17047
17048
17049
17050
17051
17052 namespace Composer\Downloader;
17053
17054 use Composer\Config;
17055 use Composer\IO\IOInterface;
17056 use Composer\Package\PackageInterface;
17057 use Composer\Util\Filesystem;
17058 use Composer\Util\Git as GitUtil;
17059 use Composer\Util\Platform;
17060 use Composer\Util\ProcessExecutor;
17061 use Composer\Cache;
17062
17063
17064
17065
17066 class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
17067 {
17068 private $hasStashedChanges = false;
17069 private $hasDiscardedChanges = false;
17070 private $gitUtil;
17071
17072 public function __construct(IOInterface $io, Config $config, ProcessExecutor $process = null, Filesystem $fs = null)
17073 {
17074 parent::__construct($io, $config, $process, $fs);
17075 $this->gitUtil = new GitUtil($this->io, $this->config, $this->process, $this->filesystem);
17076 }
17077
17078
17079
17080
17081 public function doDownload(PackageInterface $package, $path, $url)
17082 {
17083 GitUtil::cleanEnv();
17084 $path = $this->normalizePath($path);
17085 $cachePath = $this->config->get('cache-vcs-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $url).'/';
17086 $ref = $package->getSourceReference();
17087 $flag = Platform::isWindows() ? '/D ' : '';
17088
17089
17090 $gitVersion = GitUtil::getVersion($this->process);
17091 $msg = "Cloning ".$this->getShortHash($ref);
17092
17093 $command = 'git clone --no-checkout %url% %path% && cd '.$flag.'%path% && git remote add composer %url% && git fetch composer && git remote set-url origin %sanitizedUrl% && git remote set-url composer %sanitizedUrl%';
17094 if ($gitVersion && version_compare($gitVersion, '2.3.0-rc0', '>=') && Cache::isUsable($cachePath)) {
17095 $this->io->writeError('', true, IOInterface::DEBUG);
17096 $this->io->writeError(sprintf('    Cloning to cache at %s', ProcessExecutor::escape($cachePath)), true, IOInterface::DEBUG);
17097 try {
17098 if (!$this->gitUtil->fetchRefOrSyncMirror($url, $cachePath, $ref)) {
17099 $this->io->writeError('<error>Failed to update '.$url.' in cache, package installation for '.$package->getPrettyName().' might fail.</error>');
17100 }
17101 if (is_dir($cachePath)) {
17102 $command =
17103 'git clone --no-checkout %cachePath% %path% --dissociate --reference %cachePath% '
17104 . '&& cd '.$flag.'%path% '
17105 . '&& git remote set-url origin %sanitizedUrl% && git remote add composer %sanitizedUrl%';
17106 $msg = "Cloning ".$this->getShortHash($ref).' from cache';
17107 }
17108 } catch (\RuntimeException $e) {
17109 if (0 === strpos(get_class($e), 'PHPUnit')) {
17110 throw $e;
17111 }
17112 }
17113 }
17114 $this->io->writeError($msg);
17115
17116 $commandCallable = function ($url) use ($path, $command, $cachePath) {
17117 return str_replace(
17118 array('%url%', '%path%', '%cachePath%', '%sanitizedUrl%'),
17119 array(
17120 ProcessExecutor::escape($url),
17121 ProcessExecutor::escape($path),
17122 ProcessExecutor::escape($cachePath),
17123 ProcessExecutor::escape(preg_replace('{://([^@]+?):(.+?)@}', '://', $url)),
17124 ),
17125 $command
17126 );
17127 };
17128
17129 $this->gitUtil->runCommand($commandCallable, $url, $path, true);
17130 if ($url !== $package->getSourceUrl()) {
17131 $this->updateOriginUrl($path, $package->getSourceUrl());
17132 } else {
17133 $this->setPushUrl($path, $url);
17134 }
17135
17136 if ($newRef = $this->updateToCommit($path, $ref, $package->getPrettyVersion(), $package->getReleaseDate())) {
17137 if ($package->getDistReference() === $package->getSourceReference()) {
17138 $package->setDistReference($newRef);
17139 }
17140 $package->setSourceReference($newRef);
17141 }
17142 }
17143
17144
17145
17146
17147 public function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url)
17148 {
17149 GitUtil::cleanEnv();
17150 if (!$this->hasMetadataRepository($path)) {
17151 throw new \RuntimeException('The .git directory is missing from '.$path.', see https://getcomposer.org/commit-deps for more information');
17152 }
17153
17154 $updateOriginUrl = false;
17155 if (
17156 0 === $this->process->execute('git remote -v', $output, $path)
17157 && preg_match('{^origin\s+(?P<url>\S+)}m', $output, $originMatch)
17158 && preg_match('{^composer\s+(?P<url>\S+)}m', $output, $composerMatch)
17159 ) {
17160 if ($originMatch['url'] === $composerMatch['url'] && $composerMatch['url'] !== $target->getSourceUrl()) {
17161 $updateOriginUrl = true;
17162 }
17163 }
17164
17165 $ref = $target->getSourceReference();
17166 $this->io->writeError(" Checking out ".$this->getShortHash($ref));
17167 $command = '(git remote set-url composer %s && git rev-parse --quiet --verify %s || (git fetch composer && git fetch --tags composer)) && git remote set-url composer %s';
17168
17169 $commandCallable = function ($url) use ($command, $ref) {
17170 return sprintf(
17171 $command,
17172 ProcessExecutor::escape($url),
17173 ProcessExecutor::escape($ref.'^{commit}'),
17174 ProcessExecutor::escape(preg_replace('{://([^@]+?):(.+?)@}', '://', $url))
17175 );
17176 };
17177
17178 $this->gitUtil->runCommand($commandCallable, $url, $path);
17179 if ($newRef = $this->updateToCommit($path, $ref, $target->getPrettyVersion(), $target->getReleaseDate())) {
17180 if ($target->getDistReference() === $target->getSourceReference()) {
17181 $target->setDistReference($newRef);
17182 }
17183 $target->setSourceReference($newRef);
17184 }
17185
17186 if ($updateOriginUrl) {
17187 $this->updateOriginUrl($path, $target->getSourceUrl());
17188 }
17189 }
17190
17191
17192
17193
17194 public function getLocalChanges(PackageInterface $package, $path)
17195 {
17196 GitUtil::cleanEnv();
17197 if (!$this->hasMetadataRepository($path)) {
17198 return;
17199 }
17200
17201 $command = 'git status --porcelain --untracked-files=no';
17202 if (0 !== $this->process->execute($command, $output, $path)) {
17203 throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
17204 }
17205
17206 return trim($output) ?: null;
17207 }
17208
17209 public function getUnpushedChanges(PackageInterface $package, $path)
17210 {
17211 GitUtil::cleanEnv();
17212 $path = $this->normalizePath($path);
17213 if (!$this->hasMetadataRepository($path)) {
17214 return;
17215 }
17216
17217 $command = 'git show-ref --head -d';
17218 if (0 !== $this->process->execute($command, $output, $path)) {
17219 throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
17220 }
17221
17222 $refs = trim($output);
17223 if (!preg_match('{^([a-f0-9]+) HEAD$}mi', $refs, $match)) {
17224
17225 return;
17226 }
17227
17228 $headRef = $match[1];
17229 if (!preg_match_all('{^'.$headRef.' refs/heads/(.+)$}mi', $refs, $matches)) {
17230
17231 return;
17232 }
17233
17234
17235 $branch = $matches[1][0];
17236 $unpushedChanges = null;
17237
17238
17239 for ($i = 0; $i <= 1; $i++) {
17240
17241 foreach ($matches[1] as $candidate) {
17242 if (preg_match('{^[a-f0-9]+ refs/remotes/((?:composer|origin)/'.preg_quote($candidate).')$}mi', $refs, $match)) {
17243 $branch = $candidate;
17244 $remoteBranch = $match[1];
17245 break;
17246 }
17247 }
17248
17249
17250
17251
17252 if (!isset($remoteBranch)) {
17253 $unpushedChanges = 'Branch ' . $branch . ' could not be found on the origin remote and appears to be unpushed';
17254 } else {
17255 $command = sprintf('git diff --name-status %s...%s --', $remoteBranch, $branch);
17256 if (0 !== $this->process->execute($command, $output, $path)) {
17257 throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
17258 }
17259
17260 $unpushedChanges = trim($output) ?: null;
17261 }
17262
17263
17264
17265 if ($unpushedChanges && $i === 0) {
17266 $this->process->execute('git fetch composer && git fetch origin', $output, $path);
17267 }
17268
17269
17270 if (!$unpushedChanges) {
17271 break;
17272 }
17273 }
17274
17275 return $unpushedChanges;
17276 }
17277
17278
17279
17280
17281 protected function cleanChanges(PackageInterface $package, $path, $update)
17282 {
17283 GitUtil::cleanEnv();
17284 $path = $this->normalizePath($path);
17285
17286 $unpushed = $this->getUnpushedChanges($package, $path);
17287 if ($unpushed && ($this->io->isInteractive() || $this->config->get('discard-changes') !== true)) {
17288 throw new \RuntimeException('Source directory ' . $path . ' has unpushed changes on the current branch: '."\n".$unpushed);
17289 }
17290
17291 if (!$changes = $this->getLocalChanges($package, $path)) {
17292 return;
17293 }
17294
17295 if (!$this->io->isInteractive()) {
17296 $discardChanges = $this->config->get('discard-changes');
17297 if (true === $discardChanges) {
17298 return $this->discardChanges($path);
17299 }
17300 if ('stash' === $discardChanges) {
17301 if (!$update) {
17302 return parent::cleanChanges($package, $path, $update);
17303 }
17304
17305 return $this->stashChanges($path);
17306 }
17307
17308 return parent::cleanChanges($package, $path, $update);
17309 }
17310
17311 $changes = array_map(function ($elem) {
17312 return '    '.$elem;
17313 }, preg_split('{\s*\r?\n\s*}', $changes));
17314 $this->io->writeError('    <error>The package has modified files:</error>');
17315 $this->io->writeError(array_slice($changes, 0, 10));
17316 if (count($changes) > 10) {
17317 $this->io->writeError('    <info>' . (count($changes) - 10) . ' more files modified, choose "v" to view the full list</info>');
17318 }
17319
17320 while (true) {
17321 switch ($this->io->ask('    <info>Discard changes [y,n,v,d,'.($update ? 's,' : '').'?]?</info> ', '?')) {
17322 case 'y':
17323 $this->discardChanges($path);
17324 break 2;
17325
17326 case 's':
17327 if (!$update) {
17328 goto help;
17329 }
17330
17331 $this->stashChanges($path);
17332 break 2;
17333
17334 case 'n':
17335 throw new \RuntimeException('Update aborted');
17336
17337 case 'v':
17338 $this->io->writeError($changes);
17339 break;
17340
17341 case 'd':
17342 $this->viewDiff($path);
17343 break;
17344
17345 case '?':
17346 default:
17347 help:
17348 $this->io->writeError(array(
17349 '    y - discard changes and apply the '.($update ? 'update' : 'uninstall'),
17350 '    n - abort the '.($update ? 'update' : 'uninstall').' and let you manually clean things up',
17351 '    v - view modified files',
17352 '    d - view local modifications (diff)',
17353 ));
17354 if ($update) {
17355 $this->io->writeError('    s - stash changes and try to reapply them after the update');
17356 }
17357 $this->io->writeError('    ? - print help');
17358 break;
17359 }
17360 }
17361 }
17362
17363
17364
17365
17366 protected function reapplyChanges($path)
17367 {
17368 $path = $this->normalizePath($path);
17369 if ($this->hasStashedChanges) {
17370 $this->hasStashedChanges = false;
17371 $this->io->writeError('    <info>Re-applying stashed changes</info>');
17372 if (0 !== $this->process->execute('git stash pop', $output, $path)) {
17373 throw new \RuntimeException("Failed to apply stashed changes:\n\n".$this->process->getErrorOutput());
17374 }
17375 }
17376
17377 $this->hasDiscardedChanges = false;
17378 }
17379
17380
17381
17382
17383
17384
17385
17386
17387
17388
17389
17390 protected function updateToCommit($path, $reference, $branch, $date)
17391 {
17392 $force = $this->hasDiscardedChanges || $this->hasStashedChanges ? '-f ' : '';
17393
17394
17395
17396
17397
17398
17399 $template = 'git checkout '.$force.'%s -- && git reset --hard %1$s --';
17400 $branch = preg_replace('{(?:^dev-|(?:\.x)?-dev$)}i', '', $branch);
17401
17402 $branches = null;
17403 if (0 === $this->process->execute('git branch -r', $output, $path)) {
17404 $branches = $output;
17405 }
17406
17407
17408 $gitRef = $reference;
17409 if (!preg_match('{^[a-f0-9]{40}$}', $reference)
17410 && $branches
17411 && preg_match('{^\s+composer/'.preg_quote($reference).'$}m', $branches)
17412 ) {
17413 $command = sprintf('git checkout '.$force.'-B %s %s -- && git reset --hard %2$s --', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/'.$reference));
17414 if (0 === $this->process->execute($command, $output, $path)) {
17415 return;
17416 }
17417 }
17418
17419
17420 if (preg_match('{^[a-f0-9]{40}$}', $reference)) {
17421
17422 if (!preg_match('{^\s+composer/'.preg_quote($branch).'$}m', $branches) && preg_match('{^\s+composer/v'.preg_quote($branch).'$}m', $branches)) {
17423 $branch = 'v' . $branch;
17424 }
17425
17426 $command = sprintf('git checkout %s --', ProcessExecutor::escape($branch));
17427 $fallbackCommand = sprintf('git checkout '.$force.'-B %s %s --', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/'.$branch));
17428 if (0 === $this->process->execute($command, $output, $path)
17429 || 0 === $this->process->execute($fallbackCommand, $output, $path)
17430 ) {
17431 $command = sprintf('git reset --hard %s --', ProcessExecutor::escape($reference));
17432 if (0 === $this->process->execute($command, $output, $path)) {
17433 return;
17434 }
17435 }
17436 }
17437
17438 $command = sprintf($template, ProcessExecutor::escape($gitRef));
17439 if (0 === $this->process->execute($command, $output, $path)) {
17440 return;
17441 }
17442
17443
17444 if (false !== strpos($this->process->getErrorOutput(), $reference)) {
17445 $this->io->writeError('    <warning>'.$reference.' is gone (history was rewritten?)</warning>');
17446 }
17447
17448 throw new \RuntimeException(GitUtil::sanitizeUrl('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()));
17449 }
17450
17451 protected function updateOriginUrl($path, $url)
17452 {
17453 $this->process->execute(sprintf('git remote set-url origin %s', ProcessExecutor::escape($url)), $output, $path);
17454 $this->setPushUrl($path, $url);
17455 }
17456
17457 protected function setPushUrl($path, $url)
17458 {
17459
17460 if (preg_match('{^(?:https?|git)://'.GitUtil::getGitHubDomainsRegex($this->config).'/([^/]+)/([^/]+?)(?:\.git)?$}', $url, $match)) {
17461 $protocols = $this->config->get('github-protocols');
17462 $pushUrl = 'git@'.$match[1].':'.$match[2].'/'.$match[3].'.git';
17463 if (!in_array('ssh', $protocols, true)) {
17464 $pushUrl = 'https://' . $match[1] . '/'.$match[2].'/'.$match[3].'.git';
17465 }
17466 $cmd = sprintf('git remote set-url --push origin %s', ProcessExecutor::escape($pushUrl));
17467 $this->process->execute($cmd, $ignoredOutput, $path);
17468 }
17469 }
17470
17471
17472
17473
17474 protected function getCommitLogs($fromReference, $toReference, $path)
17475 {
17476 $path = $this->normalizePath($path);
17477 $command = sprintf('git log %s..%s --pretty=format:"%%h - %%an: %%s"'.GitUtil::getNoShowSignatureFlag($this->process), ProcessExecutor::escape($fromReference), ProcessExecutor::escape($toReference));
17478
17479 if (0 !== $this->process->execute($command, $output, $path)) {
17480 throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
17481 }
17482
17483 return $output;
17484 }
17485
17486
17487
17488
17489
17490 protected function discardChanges($path)
17491 {
17492 $path = $this->normalizePath($path);
17493 if (0 !== $this->process->execute('git clean -df && git reset --hard', $output, $path)) {
17494 throw new \RuntimeException("Could not reset changes\n\n:".$this->process->getErrorOutput());
17495 }
17496
17497 $this->hasDiscardedChanges = true;
17498 }
17499
17500
17501
17502
17503
17504 protected function stashChanges($path)
17505 {
17506 $path = $this->normalizePath($path);
17507 if (0 !== $this->process->execute('git stash --include-untracked', $output, $path)) {
17508 throw new \RuntimeException("Could not stash changes\n\n:".$this->process->getErrorOutput());
17509 }
17510
17511 $this->hasStashedChanges = true;
17512 }
17513
17514
17515
17516
17517
17518 protected function viewDiff($path)
17519 {
17520 $path = $this->normalizePath($path);
17521 if (0 !== $this->process->execute('git diff HEAD', $output, $path)) {
17522 throw new \RuntimeException("Could not view diff\n\n:".$this->process->getErrorOutput());
17523 }
17524
17525 $this->io->writeError($output);
17526 }
17527
17528 protected function normalizePath($path)
17529 {
17530 if (Platform::isWindows() && strlen($path) > 0) {
17531 $basePath = $path;
17532 $removed = array();
17533
17534 while (!is_dir($basePath) && $basePath !== '\\') {
17535 array_unshift($removed, basename($basePath));
17536 $basePath = dirname($basePath);
17537 }
17538
17539 if ($basePath === '\\') {
17540 return $path;
17541 }
17542
17543 $path = rtrim(realpath($basePath) . '/' . implode('/', $removed), '/');
17544 }
17545
17546 return $path;
17547 }
17548
17549
17550
17551
17552 protected function hasMetadataRepository($path)
17553 {
17554 $path = $this->normalizePath($path);
17555
17556 return is_dir($path.'/.git');
17557 }
17558
17559 protected function getShortHash($reference)
17560 {
17561 if (!$this->io->isVerbose() && preg_match('{^[0-9a-f]{40}$}', $reference)) {
17562 return substr($reference, 0, 10);
17563 }
17564
17565 return $reference;
17566 }
17567 }
17568 <?php
17569
17570
17571
17572
17573
17574
17575
17576
17577
17578
17579
17580 namespace Composer\Downloader;
17581
17582 use Composer\Config;
17583 use Composer\Cache;
17584 use Composer\EventDispatcher\EventDispatcher;
17585 use Composer\Package\PackageInterface;
17586 use Composer\Util\Platform;
17587 use Composer\Util\ProcessExecutor;
17588 use Composer\Util\RemoteFilesystem;
17589 use Composer\IO\IOInterface;
17590
17591
17592
17593
17594
17595
17596 class GzipDownloader extends ArchiveDownloader
17597 {
17598 protected $process;
17599
17600 public function __construct(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, Cache $cache = null, ProcessExecutor $process = null, RemoteFilesystem $rfs = null)
17601 {
17602 $this->process = $process ?: new ProcessExecutor($io);
17603 parent::__construct($io, $config, $eventDispatcher, $cache, $rfs);
17604 }
17605
17606 protected function extract($file, $path)
17607 {
17608 $targetFilepath = $path . DIRECTORY_SEPARATOR . basename(substr($file, 0, -3));
17609
17610
17611 if (!Platform::isWindows()) {
17612 $command = 'gzip -cd ' . ProcessExecutor::escape($file) . ' > ' . ProcessExecutor::escape($targetFilepath);
17613
17614 if (0 === $this->process->execute($command, $ignoredOutput)) {
17615 return;
17616 }
17617
17618 if (extension_loaded('zlib')) {
17619
17620 $this->extractUsingExt($file, $targetFilepath);
17621
17622 return;
17623 }
17624
17625 $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput();
17626 throw new \RuntimeException($processError);
17627 }
17628
17629
17630 $this->extractUsingExt($file, $targetFilepath);
17631 }
17632
17633
17634
17635
17636 protected function getFileName(PackageInterface $package, $path)
17637 {
17638 return $path.'/'.pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_BASENAME);
17639 }
17640
17641 private function extractUsingExt($file, $targetFilepath)
17642 {
17643 $archiveFile = gzopen($file, 'rb');
17644 $targetFile = fopen($targetFilepath, 'wb');
17645 while ($string = gzread($archiveFile, 4096)) {
17646 fwrite($targetFile, $string, Platform::strlen($string));
17647 }
17648 gzclose($archiveFile);
17649 fclose($targetFile);
17650 }
17651 }
17652 <?php
17653
17654
17655
17656
17657
17658
17659
17660
17661
17662
17663
17664 namespace Composer\Downloader;
17665
17666 use Composer\Package\PackageInterface;
17667 use Composer\Util\ProcessExecutor;
17668 use Composer\Util\Hg as HgUtils;
17669
17670
17671
17672
17673 class HgDownloader extends VcsDownloader
17674 {
17675
17676
17677
17678 public function doDownload(PackageInterface $package, $path, $url)
17679 {
17680 $hgUtils = new HgUtils($this->io, $this->config, $this->process);
17681
17682 $cloneCommand = function ($url) use ($path) {
17683 return sprintf('hg clone %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($path));
17684 };
17685
17686 $hgUtils->runCommand($cloneCommand, $url, $path);
17687
17688 $ref = ProcessExecutor::escape($package->getSourceReference());
17689 $command = sprintf('hg up %s', $ref);
17690 if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) {
17691 throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
17692 }
17693 }
17694
17695
17696
17697
17698 public function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url)
17699 {
17700 $hgUtils = new HgUtils($this->io, $this->config, $this->process);
17701
17702 $ref = $target->getSourceReference();
17703 $this->io->writeError(" Updating to ".$target->getSourceReference());
17704
17705 if (!$this->hasMetadataRepository($path)) {
17706 throw new \RuntimeException('The .hg directory is missing from '.$path.', see https://getcomposer.org/commit-deps for more information');
17707 }
17708
17709 $command = function ($url) use ($ref) {
17710 return sprintf('hg pull %s && hg up %s', ProcessExecutor::escape($url), ProcessExecutor::escape($ref));
17711 };
17712
17713 $hgUtils->runCommand($command, $url, $path);
17714 }
17715
17716
17717
17718
17719 public function getLocalChanges(PackageInterface $package, $path)
17720 {
17721 if (!is_dir($path.'/.hg')) {
17722 return null;
17723 }
17724
17725 $this->process->execute('hg st', $output, realpath($path));
17726
17727 return trim($output) ?: null;
17728 }
17729
17730
17731
17732
17733 protected function getCommitLogs($fromReference, $toReference, $path)
17734 {
17735 $command = sprintf('hg log -r %s:%s --style compact', ProcessExecutor::escape($fromReference), ProcessExecutor::escape($toReference));
17736
17737 if (0 !== $this->process->execute($command, $output, realpath($path))) {
17738 throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
17739 }
17740
17741 return $output;
17742 }
17743
17744
17745
17746
17747 protected function hasMetadataRepository($path)
17748 {
17749 return is_dir($path . '/.hg');
17750 }
17751 }
17752 <?php
17753
17754
17755
17756
17757
17758
17759
17760
17761
17762
17763
17764 namespace Composer\Downloader;
17765
17766 use Composer\Package\Archiver\ArchivableFilesFinder;
17767 use Composer\Package\Dumper\ArrayDumper;
17768 use Composer\Package\PackageInterface;
17769 use Composer\Package\Version\VersionGuesser;
17770 use Composer\Package\Version\VersionParser;
17771 use Composer\Util\Platform;
17772 use Composer\Util\ProcessExecutor;
17773 use Composer\Util\Filesystem as ComposerFilesystem;
17774 use Symfony\Component\Filesystem\Exception\IOException;
17775 use Symfony\Component\Filesystem\Filesystem;
17776
17777
17778
17779
17780
17781
17782
17783 class PathDownloader extends FileDownloader implements VcsCapableDownloaderInterface
17784 {
17785 const STRATEGY_SYMLINK = 10;
17786 const STRATEGY_MIRROR = 20;
17787
17788
17789
17790
17791 public function download(PackageInterface $package, $path, $output = true)
17792 {
17793 $url = $package->getDistUrl();
17794 $realUrl = realpath($url);
17795 if (false === $realUrl || !file_exists($realUrl) || !is_dir($realUrl)) {
17796 throw new \RuntimeException(sprintf(
17797 'Source path "%s" is not found for package %s',
17798 $url,
17799 $package->getName()
17800 ));
17801 }
17802
17803 if (realpath($path) === $realUrl) {
17804 if ($output) {
17805 $this->io->writeError(sprintf(
17806 '  - Installing <info>%s</info> (<comment>%s</comment>): Source already present',
17807 $package->getName(),
17808 $package->getFullPrettyVersion()
17809 ));
17810 }
17811
17812 return;
17813 }
17814
17815 if (strpos(realpath($path) . DIRECTORY_SEPARATOR, $realUrl . DIRECTORY_SEPARATOR) === 0) {
17816
17817
17818
17819
17820 throw new \RuntimeException(sprintf(
17821 'Package %s cannot install to "%s" inside its source at "%s"',
17822 $package->getName(),
17823 realpath($path),
17824 $realUrl
17825 ));
17826 }
17827
17828
17829 $transportOptions = $package->getTransportOptions() + array('symlink' => null, 'relative' => true);
17830
17831
17832 $currentStrategy = self::STRATEGY_SYMLINK;
17833 $allowedStrategies = array(self::STRATEGY_SYMLINK, self::STRATEGY_MIRROR);
17834
17835 $mirrorPathRepos = getenv('COMPOSER_MIRROR_PATH_REPOS');
17836 if ($mirrorPathRepos) {
17837 $currentStrategy = self::STRATEGY_MIRROR;
17838 }
17839
17840 if (true === $transportOptions['symlink']) {
17841 $currentStrategy = self::STRATEGY_SYMLINK;
17842 $allowedStrategies = array(self::STRATEGY_SYMLINK);
17843 } elseif (false === $transportOptions['symlink']) {
17844 $currentStrategy = self::STRATEGY_MIRROR;
17845 $allowedStrategies = array(self::STRATEGY_MIRROR);
17846 }
17847
17848
17849 if (Platform::isWindows() && self::STRATEGY_SYMLINK === $currentStrategy && !$this->safeJunctions()) {
17850 $currentStrategy = self::STRATEGY_MIRROR;
17851 $allowedStrategies = array(self::STRATEGY_MIRROR);
17852 }
17853
17854 $fileSystem = new Filesystem();
17855 $this->filesystem->removeDirectory($path);
17856
17857 if ($output) {
17858 $this->io->writeError(sprintf(
17859 '  - Installing <info>%s</info> (<comment>%s</comment>): ',
17860 $package->getName(),
17861 $package->getFullPrettyVersion()
17862 ), false);
17863 }
17864
17865 $isFallback = false;
17866 if (self::STRATEGY_SYMLINK == $currentStrategy) {
17867 try {
17868 if (Platform::isWindows()) {
17869
17870 $this->io->writeError(sprintf('Junctioning from %s', $url), false);
17871 $this->filesystem->junction($realUrl, $path);
17872 } else {
17873 $absolutePath = $path;
17874 if (!$this->filesystem->isAbsolutePath($absolutePath)) {
17875 $absolutePath = getcwd() . DIRECTORY_SEPARATOR . $path;
17876 }
17877 $shortestPath = $this->filesystem->findShortestPath($absolutePath, $realUrl);
17878 $path = rtrim($path, "/");
17879 $this->io->writeError(sprintf('Symlinking from %s', $url), false);
17880 if ($transportOptions['relative']) {
17881 $fileSystem->symlink($shortestPath, $path);
17882 } else {
17883 $fileSystem->symlink($realUrl, $path);
17884 }
17885 }
17886 } catch (IOException $e) {
17887 if (in_array(self::STRATEGY_MIRROR, $allowedStrategies)) {
17888 $this->io->writeError('');
17889 $this->io->writeError('    <error>Symlink failed, fallback to use mirroring!</error>');
17890 $currentStrategy = self::STRATEGY_MIRROR;
17891 $isFallback = true;
17892 } else {
17893 throw new \RuntimeException(sprintf('Symlink from "%s" to "%s" failed!', $realUrl, $path));
17894 }
17895 }
17896 }
17897
17898
17899 if (self::STRATEGY_MIRROR == $currentStrategy) {
17900 $fs = new ComposerFilesystem();
17901 $realUrl = $fs->normalizePath($realUrl);
17902
17903 $this->io->writeError(sprintf('%sMirroring from %s', $isFallback ? '    ' : '', $url), false);
17904 $iterator = new ArchivableFilesFinder($realUrl, array());
17905 $fileSystem->mirror($realUrl, $path, $iterator);
17906 }
17907
17908 $this->io->writeError('');
17909 }
17910
17911
17912
17913
17914 public function remove(PackageInterface $package, $path, $output = true)
17915 {
17916 $realUrl = realpath($package->getDistUrl());
17917
17918 if (realpath($path) === $realUrl) {
17919 if ($output) {
17920 $this->io->writeError("  - Removing <info>" . $package->getName() . "</info> (<comment>" . $package->getFullPrettyVersion() . "</comment>), source is still present in $path");
17921 }
17922
17923 return;
17924 }
17925
17926
17927
17928
17929
17930
17931 if (Platform::isWindows() && $this->filesystem->isJunction($path)) {
17932 if ($output) {
17933 $this->io->writeError("  - Removing junction for <info>" . $package->getName() . "</info> (<comment>" . $package->getFullPrettyVersion() . "</comment>)");
17934 }
17935 if (!$this->filesystem->removeJunction($path)) {
17936 $this->io->writeError("    <warning>Could not remove junction at " . $path . " - is another process locking it?</warning>");
17937 throw new \RuntimeException('Could not reliably remove junction for package ' . $package->getName());
17938 }
17939 } else {
17940 parent::remove($package, $path, $output);
17941 }
17942 }
17943
17944
17945
17946
17947 public function getVcsReference(PackageInterface $package, $path)
17948 {
17949 $parser = new VersionParser;
17950 $guesser = new VersionGuesser($this->config, new ProcessExecutor($this->io), $parser);
17951 $dumper = new ArrayDumper;
17952
17953 $packageConfig = $dumper->dump($package);
17954 if ($packageVersion = $guesser->guessVersion($packageConfig, $path)) {
17955 return $packageVersion['commit'];
17956 }
17957 }
17958
17959
17960
17961
17962
17963
17964
17965
17966
17967
17968
17969
17970
17971
17972 private function safeJunctions()
17973 {
17974
17975 return function_exists('proc_open') &&
17976 (PHP_WINDOWS_VERSION_MAJOR > 6 ||
17977 (PHP_WINDOWS_VERSION_MAJOR === 6 && PHP_WINDOWS_VERSION_MINOR >= 1));
17978 }
17979 }
17980 <?php
17981
17982
17983
17984
17985
17986
17987
17988
17989
17990
17991
17992 namespace Composer\Downloader;
17993
17994 use Composer\Util\Filesystem;
17995
17996
17997
17998
17999
18000
18001
18002
18003
18004
18005 class PearPackageExtractor
18006 {
18007 private static $rolesWithoutPackageNamePrefix = array('php', 'script', 'www');
18008
18009 private $filesystem;
18010 private $file;
18011
18012 public function __construct($file)
18013 {
18014 if (!is_file($file)) {
18015 throw new \UnexpectedValueException('PEAR package file is not found at '.$file);
18016 }
18017
18018 $this->filesystem = new Filesystem();
18019 $this->file = $file;
18020 }
18021
18022
18023
18024
18025
18026
18027
18028
18029
18030
18031 public function extractTo($target, array $roles = array('php' => '/', 'script' => '/bin'), $vars = array())
18032 {
18033 $extractionPath = $target.'/tarball';
18034
18035 try {
18036 $archive = new \PharData($this->file);
18037 $archive->extractTo($extractionPath, null, true);
18038
18039 if (!is_file($this->combine($extractionPath, '/package.xml'))) {
18040 throw new \RuntimeException('Invalid PEAR package. It must contain package.xml file.');
18041 }
18042
18043 $fileCopyActions = $this->buildCopyActions($extractionPath, $roles, $vars);
18044 $this->copyFiles($fileCopyActions, $extractionPath, $target, $roles, $vars);
18045 $this->filesystem->removeDirectory($extractionPath);
18046 } catch (\Exception $exception) {
18047 throw new \UnexpectedValueException(sprintf('Failed to extract PEAR package %s to %s. Reason: %s', $this->file, $target, $exception->getMessage()), 0, $exception);
18048 }
18049 }
18050
18051
18052
18053
18054
18055
18056
18057
18058
18059
18060 private function copyFiles($files, $source, $target, $roles, $vars)
18061 {
18062 foreach ($files as $file) {
18063 $from = $this->combine($source, $file['from']);
18064 $to = $this->combine($target, $roles[$file['role']]);
18065 $to = $this->combine($to, $file['to']);
18066 $tasks = $file['tasks'];
18067 $this->copyFile($from, $to, $tasks, $vars);
18068 }
18069 }
18070
18071 private function copyFile($from, $to, $tasks, $vars)
18072 {
18073 if (!is_file($from)) {
18074 throw new \RuntimeException('Invalid PEAR package. package.xml defines file that is not located inside tarball.');
18075 }
18076
18077 $this->filesystem->ensureDirectoryExists(dirname($to));
18078
18079 if (0 == count($tasks)) {
18080 $copied = copy($from, $to);
18081 } else {
18082 $content = file_get_contents($from);
18083 $replacements = array();
18084 foreach ($tasks as $task) {
18085 $pattern = $task['from'];
18086 $varName = $task['to'];
18087 if (isset($vars[$varName])) {
18088 if ($varName === 'php_bin' && false === strpos($to, '.bat')) {
18089 $replacements[$pattern] = preg_replace('{\.bat$}', '', $vars[$varName]);
18090 } else {
18091 $replacements[$pattern] = $vars[$varName];
18092 }
18093 }
18094 }
18095 $content = strtr($content, $replacements);
18096
18097 $copied = file_put_contents($to, $content);
18098 }
18099
18100 if (false === $copied) {
18101 throw new \RuntimeException(sprintf('Failed to copy %s to %s', $from, $to));
18102 }
18103 }
18104
18105
18106
18107
18108
18109
18110
18111
18112
18113
18114
18115 private function buildCopyActions($source, array $roles, $vars)
18116 {
18117
18118 $package = simplexml_load_string(file_get_contents($this->combine($source, 'package.xml')));
18119 if (false === $package) {
18120 throw new \RuntimeException('Package definition file is not valid.');
18121 }
18122
18123 $packageSchemaVersion = $package['version'];
18124 if ('1.0' == $packageSchemaVersion) {
18125 $children = $package->release->filelist->children();
18126 $packageName = (string) $package->name;
18127 $packageVersion = (string) $package->release->version;
18128 $sourceDir = $packageName . '-' . $packageVersion;
18129 $result = $this->buildSourceList10($children, $roles, $sourceDir, '', null, $packageName);
18130 } elseif ('2.0' == $packageSchemaVersion || '2.1' == $packageSchemaVersion) {
18131 $children = $package->contents->children();
18132 $packageName = (string) $package->name;
18133 $packageVersion = (string) $package->version->release;
18134 $sourceDir = $packageName . '-' . $packageVersion;
18135 $result = $this->buildSourceList20($children, $roles, $sourceDir, '', null, $packageName);
18136
18137 $namespaces = $package->getNamespaces();
18138 $package->registerXPathNamespace('ns', $namespaces['']);
18139 $releaseNodes = $package->xpath('ns:phprelease');
18140 $this->applyRelease($result, $releaseNodes, $vars);
18141 } else {
18142 throw new \RuntimeException('Unsupported schema version of package definition file.');
18143 }
18144
18145 return $result;
18146 }
18147
18148 private function applyRelease(&$actions, $releaseNodes, $vars)
18149 {
18150 foreach ($releaseNodes as $releaseNode) {
18151 $requiredOs = $releaseNode->installconditions && $releaseNode->installconditions->os && $releaseNode->installconditions->os->name ? (string) $releaseNode->installconditions->os->name : '';
18152 if ($requiredOs && $vars['os'] != $requiredOs) {
18153 continue;
18154 }
18155
18156 if ($releaseNode->filelist) {
18157 foreach ($releaseNode->filelist->children() as $action) {
18158 if ('install' == $action->getName()) {
18159 $name = (string) $action['name'];
18160 $as = (string) $action['as'];
18161 if (isset($actions[$name])) {
18162 $actions[$name]['to'] = $as;
18163 }
18164 } elseif ('ignore' == $action->getName()) {
18165 $name = (string) $action['name'];
18166 unset($actions[$name]);
18167 } else {
18168
18169 }
18170 }
18171 }
18172 break;
18173 }
18174 }
18175
18176 private function buildSourceList10($children, $targetRoles, $source, $target, $role, $packageName)
18177 {
18178 $result = array();
18179
18180
18181 foreach ($children as $child) {
18182
18183 if ($child->getName() == 'dir') {
18184 $dirSource = $this->combine($source, (string) $child['name']);
18185 $dirTarget = $child['baseinstalldir'] ?: $target;
18186 $dirRole = $child['role'] ?: $role;
18187 $dirFiles = $this->buildSourceList10($child->children(), $targetRoles, $dirSource, $dirTarget, $dirRole, $packageName);
18188 $result = array_merge($result, $dirFiles);
18189 } elseif ($child->getName() == 'file') {
18190 $fileRole = (string) $child['role'] ?: $role;
18191 if (isset($targetRoles[$fileRole])) {
18192 $fileName = (string) ($child['name'] ?: $child[0]); 
18193 $fileSource = $this->combine($source, $fileName);
18194 $fileTarget = $this->combine((string) $child['baseinstalldir'] ?: $target, $fileName);
18195 if (!in_array($fileRole, self::$rolesWithoutPackageNamePrefix)) {
18196 $fileTarget = $packageName . '/' . $fileTarget;
18197 }
18198 $result[(string) $child['name']] = array('from' => $fileSource, 'to' => $fileTarget, 'role' => $fileRole, 'tasks' => array());
18199 }
18200 }
18201 }
18202
18203 return $result;
18204 }
18205
18206 private function buildSourceList20($children, $targetRoles, $source, $target, $role, $packageName)
18207 {
18208 $result = array();
18209
18210
18211 foreach ($children as $child) {
18212
18213 if ('dir' == $child->getName()) {
18214 $dirSource = $this->combine($source, $child['name']);
18215 $dirTarget = $child['baseinstalldir'] ?: $target;
18216 $dirRole = $child['role'] ?: $role;
18217 $dirFiles = $this->buildSourceList20($child->children(), $targetRoles, $dirSource, $dirTarget, $dirRole, $packageName);
18218 $result = array_merge($result, $dirFiles);
18219 } elseif ('file' == $child->getName()) {
18220 $fileRole = (string) $child['role'] ?: $role;
18221 if (isset($targetRoles[$fileRole])) {
18222 $fileSource = $this->combine($source, (string) $child['name']);
18223 $fileTarget = $this->combine((string) ($child['baseinstalldir'] ?: $target), (string) $child['name']);
18224 $fileTasks = array();
18225 foreach ($child->children('http://pear.php.net/dtd/tasks-1.0') as $taskNode) {
18226 if ('replace' == $taskNode->getName()) {
18227 $fileTasks[] = array('from' => (string) $taskNode->attributes()->from, 'to' => (string) $taskNode->attributes()->to);
18228 }
18229 }
18230 if (!in_array($fileRole, self::$rolesWithoutPackageNamePrefix)) {
18231 $fileTarget = $packageName . '/' . $fileTarget;
18232 }
18233 $result[(string) $child['name']] = array('from' => $fileSource, 'to' => $fileTarget, 'role' => $fileRole, 'tasks' => $fileTasks);
18234 }
18235 }
18236 }
18237
18238 return $result;
18239 }
18240
18241 private function combine($left, $right)
18242 {
18243 return rtrim($left, '/') . '/' . ltrim($right, '/');
18244 }
18245 }
18246 <?php
18247
18248
18249
18250
18251
18252
18253
18254
18255
18256
18257
18258 namespace Composer\Downloader;
18259
18260 use Composer\Package\PackageInterface;
18261 use Composer\Repository\VcsRepository;
18262 use Composer\Util\Perforce;
18263
18264
18265
18266
18267 class PerforceDownloader extends VcsDownloader
18268 {
18269
18270 protected $perforce;
18271
18272
18273
18274
18275 public function doDownload(PackageInterface $package, $path, $url)
18276 {
18277 $ref = $package->getSourceReference();
18278 $label = $this->getLabelFromSourceReference($ref);
18279
18280 $this->io->writeError('Cloning ' . $ref);
18281 $this->initPerforce($package, $path, $url);
18282 $this->perforce->setStream($ref);
18283 $this->perforce->p4Login();
18284 $this->perforce->writeP4ClientSpec();
18285 $this->perforce->connectClient();
18286 $this->perforce->syncCodeBase($label);
18287 $this->perforce->cleanupClientSpec();
18288 }
18289
18290 private function getLabelFromSourceReference($ref)
18291 {
18292 $pos = strpos($ref, '@');
18293 if (false !== $pos) {
18294 return substr($ref, $pos + 1);
18295 }
18296
18297 return null;
18298 }
18299
18300 public function initPerforce(PackageInterface $package, $path, $url)
18301 {
18302 if (!empty($this->perforce)) {
18303 $this->perforce->initializePath($path);
18304
18305 return;
18306 }
18307
18308 $repository = $package->getRepository();
18309 $repoConfig = null;
18310 if ($repository instanceof VcsRepository) {
18311 $repoConfig = $this->getRepoConfig($repository);
18312 }
18313 $this->perforce = Perforce::create($repoConfig, $url, $path, $this->process, $this->io);
18314 }
18315
18316 private function getRepoConfig(VcsRepository $repository)
18317 {
18318 return $repository->getRepoConfig();
18319 }
18320
18321
18322
18323
18324 public function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url)
18325 {
18326 $this->doDownload($target, $path, $url);
18327 }
18328
18329
18330
18331
18332 public function getLocalChanges(PackageInterface $package, $path)
18333 {
18334 $this->io->writeError('Perforce driver does not check for local changes before overriding', true);
18335 }
18336
18337
18338
18339
18340 protected function getCommitLogs($fromReference, $toReference, $path)
18341 {
18342 return $this->perforce->getCommitLogs($fromReference, $toReference);
18343 }
18344
18345 public function setPerforce($perforce)
18346 {
18347 $this->perforce = $perforce;
18348 }
18349
18350
18351
18352
18353 protected function hasMetadataRepository($path)
18354 {
18355 return true;
18356 }
18357 }
18358 <?php
18359
18360
18361
18362
18363
18364
18365
18366
18367
18368
18369
18370 namespace Composer\Downloader;
18371
18372
18373
18374
18375
18376
18377 class PharDownloader extends ArchiveDownloader
18378 {
18379
18380
18381
18382 protected function extract($file, $path)
18383 {
18384
18385 $archive = new \Phar($file);
18386 $archive->extractTo($path, null, true);
18387
18388
18389
18390
18391
18392 }
18393 }
18394 <?php
18395
18396
18397
18398
18399
18400
18401
18402
18403
18404
18405
18406 namespace Composer\Downloader;
18407
18408 use Composer\Config;
18409 use Composer\Cache;
18410 use Composer\EventDispatcher\EventDispatcher;
18411 use Composer\Util\IniHelper;
18412 use Composer\Util\Platform;
18413 use Composer\Util\ProcessExecutor;
18414 use Composer\Util\RemoteFilesystem;
18415 use Composer\IO\IOInterface;
18416 use RarArchive;
18417
18418
18419
18420
18421
18422
18423
18424
18425 class RarDownloader extends ArchiveDownloader
18426 {
18427 protected $process;
18428
18429 public function __construct(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, Cache $cache = null, ProcessExecutor $process = null, RemoteFilesystem $rfs = null)
18430 {
18431 $this->process = $process ?: new ProcessExecutor($io);
18432 parent::__construct($io, $config, $eventDispatcher, $cache, $rfs);
18433 }
18434
18435 protected function extract($file, $path)
18436 {
18437 $processError = null;
18438
18439
18440 if (!Platform::isWindows()) {
18441 $command = 'unrar x ' . ProcessExecutor::escape($file) . ' ' . ProcessExecutor::escape($path) . ' >/dev/null && chmod -R u+w ' . ProcessExecutor::escape($path);
18442
18443 if (0 === $this->process->execute($command, $ignoredOutput)) {
18444 return;
18445 }
18446
18447 $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput();
18448 }
18449
18450 if (!class_exists('RarArchive')) {
18451
18452 $iniMessage = IniHelper::getMessage();
18453
18454 $error = "Could not decompress the archive, enable the PHP rar extension or install unrar.\n"
18455 . $iniMessage . "\n" . $processError;
18456
18457 if (!Platform::isWindows()) {
18458 $error = "Could not decompress the archive, enable the PHP rar extension.\n" . $iniMessage;
18459 }
18460
18461 throw new \RuntimeException($error);
18462 }
18463
18464 $rarArchive = RarArchive::open($file);
18465
18466 if (false === $rarArchive) {
18467 throw new \UnexpectedValueException('Could not open RAR archive: ' . $file);
18468 }
18469
18470 $entries = $rarArchive->getEntries();
18471
18472 if (false === $entries) {
18473 throw new \RuntimeException('Could not retrieve RAR archive entries');
18474 }
18475
18476 foreach ($entries as $entry) {
18477 if (false === $entry->extract($path)) {
18478 throw new \RuntimeException('Could not extract entry');
18479 }
18480 }
18481
18482 $rarArchive->close();
18483 }
18484 }
18485 <?php
18486
18487
18488
18489
18490
18491
18492
18493
18494
18495
18496
18497 namespace Composer\Downloader;
18498
18499 use Composer\Package\PackageInterface;
18500 use Composer\Util\Svn as SvnUtil;
18501 use Composer\Repository\VcsRepository;
18502 use Composer\Util\ProcessExecutor;
18503
18504
18505
18506
18507
18508 class SvnDownloader extends VcsDownloader
18509 {
18510 protected $cacheCredentials = true;
18511
18512
18513
18514
18515 public function doDownload(PackageInterface $package, $path, $url)
18516 {
18517 SvnUtil::cleanEnv();
18518 $ref = $package->getSourceReference();
18519
18520 $repo = $package->getRepository();
18521 if ($repo instanceof VcsRepository) {
18522 $repoConfig = $repo->getRepoConfig();
18523 if (array_key_exists('svn-cache-credentials', $repoConfig)) {
18524 $this->cacheCredentials = (bool) $repoConfig['svn-cache-credentials'];
18525 }
18526 }
18527
18528 $this->io->writeError(" Checking out ".$package->getSourceReference());
18529 $this->execute($url, "svn co", sprintf("%s/%s", $url, $ref), null, $path);
18530 }
18531
18532
18533
18534
18535 public function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url)
18536 {
18537 SvnUtil::cleanEnv();
18538 $ref = $target->getSourceReference();
18539
18540 if (!$this->hasMetadataRepository($path)) {
18541 throw new \RuntimeException('The .svn directory is missing from '.$path.', see https://getcomposer.org/commit-deps for more information');
18542 }
18543
18544 $util = new SvnUtil($url, $this->io, $this->config);
18545 $flags = "";
18546 if (version_compare($util->binaryVersion(), '1.7.0', '>=')) {
18547 $flags .= ' --ignore-ancestry';
18548 }
18549
18550 $this->io->writeError(" Checking out " . $ref);
18551 $this->execute($url, "svn switch" . $flags, sprintf("%s/%s", $url, $ref), $path);
18552 }
18553
18554
18555
18556
18557 public function getLocalChanges(PackageInterface $package, $path)
18558 {
18559 if (!$this->hasMetadataRepository($path)) {
18560 return null;
18561 }
18562
18563 $this->process->execute('svn status --ignore-externals', $output, $path);
18564
18565 return preg_match('{^ *[^X ] +}m', $output) ? $output : null;
18566 }
18567
18568
18569
18570
18571
18572
18573
18574
18575
18576
18577
18578
18579
18580 protected function execute($baseUrl, $command, $url, $cwd = null, $path = null)
18581 {
18582 $util = new SvnUtil($baseUrl, $this->io, $this->config);
18583 $util->setCacheCredentials($this->cacheCredentials);
18584 try {
18585 return $util->execute($command, $url, $cwd, $path, $this->io->isVerbose());
18586 } catch (\RuntimeException $e) {
18587 throw new \RuntimeException(
18588 'Package could not be downloaded, '.$e->getMessage()
18589 );
18590 }
18591 }
18592
18593
18594
18595
18596 protected function cleanChanges(PackageInterface $package, $path, $update)
18597 {
18598 if (!$changes = $this->getLocalChanges($package, $path)) {
18599 return;
18600 }
18601
18602 if (!$this->io->isInteractive()) {
18603 if (true === $this->config->get('discard-changes')) {
18604 return $this->discardChanges($path);
18605 }
18606
18607 return parent::cleanChanges($package, $path, $update);
18608 }
18609
18610 $changes = array_map(function ($elem) {
18611 return '    '.$elem;
18612 }, preg_split('{\s*\r?\n\s*}', $changes));
18613 $countChanges = count($changes);
18614 $this->io->writeError(sprintf('    <error>The package has modified file%s:</error>', $countChanges === 1 ? '' : 's'));
18615 $this->io->writeError(array_slice($changes, 0, 10));
18616 if ($countChanges > 10) {
18617 $remainingChanges = $countChanges - 10;
18618 $this->io->writeError(
18619 sprintf(
18620 '    <info>'.$remainingChanges.' more file%s modified, choose "v" to view the full list</info>',
18621 $remainingChanges === 1 ? '' : 's'
18622 )
18623 );
18624 }
18625
18626 while (true) {
18627 switch ($this->io->ask('    <info>Discard changes [y,n,v,?]?</info> ', '?')) {
18628 case 'y':
18629 $this->discardChanges($path);
18630 break 2;
18631
18632 case 'n':
18633 throw new \RuntimeException('Update aborted');
18634
18635 case 'v':
18636 $this->io->writeError($changes);
18637 break;
18638
18639 case '?':
18640 default:
18641 $this->io->writeError(array(
18642 '    y - discard changes and apply the '.($update ? 'update' : 'uninstall'),
18643 '    n - abort the '.($update ? 'update' : 'uninstall').' and let you manually clean things up',
18644 '    v - view modified files',
18645 '    ? - print help',
18646 ));
18647 break;
18648 }
18649 }
18650 }
18651
18652
18653
18654
18655 protected function getCommitLogs($fromReference, $toReference, $path)
18656 {
18657 if (preg_match('{.*@(\d+)$}', $fromReference) && preg_match('{.*@(\d+)$}', $toReference)) {
18658
18659 $command = sprintf('svn info --non-interactive --xml %s', ProcessExecutor::escape($path));
18660 if (0 !== $this->process->execute($command, $output, $path)) {
18661 throw new \RuntimeException(
18662 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()
18663 );
18664 }
18665
18666 $urlPattern = '#<url>(.*)</url>#';
18667 if (preg_match($urlPattern, $output, $matches)) {
18668 $baseUrl = $matches[1];
18669 } else {
18670 throw new \RuntimeException(
18671 'Unable to determine svn url for path '. $path
18672 );
18673 }
18674
18675
18676 $fromRevision = preg_replace('{.*@(\d+)$}', '$1', $fromReference);
18677 $toRevision = preg_replace('{.*@(\d+)$}', '$1', $toReference);
18678
18679 $command = sprintf('svn log -r%s:%s --incremental', ProcessExecutor::escape($fromRevision), ProcessExecutor::escape($toRevision));
18680
18681 $util = new SvnUtil($baseUrl, $this->io, $this->config);
18682 $util->setCacheCredentials($this->cacheCredentials);
18683 try {
18684 return $util->executeLocal($command, $path, null, $this->io->isVerbose());
18685 } catch (\RuntimeException $e) {
18686 throw new \RuntimeException(
18687 'Failed to execute ' . $command . "\n\n".$e->getMessage()
18688 );
18689 }
18690 }
18691
18692 return "Could not retrieve changes between $fromReference and $toReference due to missing revision information";
18693 }
18694
18695 protected function discardChanges($path)
18696 {
18697 if (0 !== $this->process->execute('svn revert -R .', $output, $path)) {
18698 throw new \RuntimeException("Could not reset changes\n\n:".$this->process->getErrorOutput());
18699 }
18700 }
18701
18702
18703
18704
18705 protected function hasMetadataRepository($path)
18706 {
18707 return is_dir($path.'/.svn');
18708 }
18709 }
18710 <?php
18711
18712
18713
18714
18715
18716
18717
18718
18719
18720
18721
18722 namespace Composer\Downloader;
18723
18724
18725
18726
18727
18728
18729 class TarDownloader extends ArchiveDownloader
18730 {
18731
18732
18733
18734 protected function extract($file, $path)
18735 {
18736
18737 $archive = new \PharData($file);
18738 $archive->extractTo($path, null, true);
18739 }
18740 }
18741 <?php
18742
18743
18744
18745
18746
18747
18748
18749
18750
18751
18752
18753 namespace Composer\Downloader;
18754
18755
18756
18757
18758 class TransportException extends \RuntimeException
18759 {
18760 protected $headers;
18761 protected $response;
18762 protected $statusCode;
18763
18764 public function setHeaders($headers)
18765 {
18766 $this->headers = $headers;
18767 }
18768
18769 public function getHeaders()
18770 {
18771 return $this->headers;
18772 }
18773
18774 public function setResponse($response)
18775 {
18776 $this->response = $response;
18777 }
18778
18779 public function getResponse()
18780 {
18781 return $this->response;
18782 }
18783
18784 public function setStatusCode($statusCode)
18785 {
18786 $this->statusCode = $statusCode;
18787 }
18788
18789 public function getStatusCode()
18790 {
18791 return $this->statusCode;
18792 }
18793 }
18794 <?php
18795
18796
18797
18798
18799
18800
18801
18802
18803
18804
18805
18806 namespace Composer\Downloader;
18807
18808 use Composer\Package\PackageInterface;
18809
18810
18811
18812
18813
18814
18815 interface VcsCapableDownloaderInterface
18816 {
18817
18818
18819
18820
18821
18822
18823
18824 public function getVcsReference(PackageInterface $package, $path);
18825 }
18826 <?php
18827
18828
18829
18830
18831
18832
18833
18834
18835
18836
18837
18838 namespace Composer\Downloader;
18839
18840 use Composer\Config;
18841 use Composer\Package\Dumper\ArrayDumper;
18842 use Composer\Package\PackageInterface;
18843 use Composer\Package\Version\VersionGuesser;
18844 use Composer\Package\Version\VersionParser;
18845 use Composer\Util\ProcessExecutor;
18846 use Composer\IO\IOInterface;
18847 use Composer\Util\Filesystem;
18848
18849
18850
18851
18852 abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterface, VcsCapableDownloaderInterface
18853 {
18854
18855 protected $io;
18856
18857 protected $config;
18858
18859 protected $process;
18860
18861 protected $filesystem;
18862
18863 public function __construct(IOInterface $io, Config $config, ProcessExecutor $process = null, Filesystem $fs = null)
18864 {
18865 $this->io = $io;
18866 $this->config = $config;
18867 $this->process = $process ?: new ProcessExecutor($io);
18868 $this->filesystem = $fs ?: new Filesystem($this->process);
18869 }
18870
18871
18872
18873
18874 public function getInstallationSource()
18875 {
18876 return 'source';
18877 }
18878
18879
18880
18881
18882 public function download(PackageInterface $package, $path)
18883 {
18884 if (!$package->getSourceReference()) {
18885 throw new \InvalidArgumentException('Package '.$package->getPrettyName().' is missing reference information');
18886 }
18887
18888 $this->io->writeError("  - Installing <info>" . $package->getName() . "</info> (<comment>" . $package->getFullPrettyVersion() . "</comment>): ", false);
18889 $this->filesystem->emptyDirectory($path);
18890
18891 $urls = $package->getSourceUrls();
18892 while ($url = array_shift($urls)) {
18893 try {
18894 if (Filesystem::isLocalPath($url)) {
18895
18896
18897 $needle = 'file://';
18898 $isFileProtocol = false;
18899 if (0 === strpos($url, $needle)) {
18900 $url = substr($url, strlen($needle));
18901 $isFileProtocol = true;
18902 }
18903
18904
18905 if (false !== strpos($url, '%')) {
18906 $url = rawurldecode($url);
18907 }
18908
18909 $url = realpath($url);
18910
18911 if ($isFileProtocol) {
18912 $url = $needle . $url;
18913 }
18914 }
18915 $this->doDownload($package, $path, $url);
18916 break;
18917 } catch (\Exception $e) {
18918
18919 if ($e instanceof \PHPUnit_Framework_Exception) {
18920 throw $e;
18921 }
18922 if ($this->io->isDebug()) {
18923 $this->io->writeError('Failed: ['.get_class($e).'] '.$e->getMessage());
18924 } elseif (count($urls)) {
18925 $this->io->writeError('    Failed, trying the next URL');
18926 }
18927 if (!count($urls)) {
18928 throw $e;
18929 }
18930 }
18931 }
18932 }
18933
18934
18935
18936
18937 public function update(PackageInterface $initial, PackageInterface $target, $path)
18938 {
18939 if (!$target->getSourceReference()) {
18940 throw new \InvalidArgumentException('Package '.$target->getPrettyName().' is missing reference information');
18941 }
18942
18943 $name = $target->getName();
18944 if ($initial->getPrettyVersion() == $target->getPrettyVersion()) {
18945 if ($target->getSourceType() === 'svn') {
18946 $from = $initial->getSourceReference();
18947 $to = $target->getSourceReference();
18948 } else {
18949 $from = substr($initial->getSourceReference(), 0, 7);
18950 $to = substr($target->getSourceReference(), 0, 7);
18951 }
18952 $name .= ' '.$initial->getPrettyVersion();
18953 } else {
18954 $from = $initial->getFullPrettyVersion();
18955 $to = $target->getFullPrettyVersion();
18956 }
18957
18958 $actionName = VersionParser::isUpgrade($initial->getVersion(), $target->getVersion()) ? 'Updating' : 'Downgrading';
18959 $this->io->writeError("  - " . $actionName . " <info>" . $name . "</info> (<comment>" . $from . "</comment> => <comment>" . $to . "</comment>): ", false);
18960
18961 $this->cleanChanges($initial, $path, true);
18962 $urls = $target->getSourceUrls();
18963
18964 $exception = null;
18965 while ($url = array_shift($urls)) {
18966 try {
18967 if (Filesystem::isLocalPath($url)) {
18968 $url = realpath($url);
18969 }
18970 $this->doUpdate($initial, $target, $path, $url);
18971
18972 $exception = null;
18973 break;
18974 } catch (\Exception $exception) {
18975
18976 if ($exception instanceof \PHPUnit_Framework_Exception) {
18977 throw $exception;
18978 }
18979 if ($this->io->isDebug()) {
18980 $this->io->writeError('Failed: ['.get_class($exception).'] '.$exception->getMessage());
18981 } elseif (count($urls)) {
18982 $this->io->writeError('    Failed, trying the next URL');
18983 }
18984 }
18985 }
18986
18987 $this->reapplyChanges($path);
18988
18989
18990
18991 if (!$exception && $this->io->isVerbose() && $this->hasMetadataRepository($path)) {
18992 $message = 'Pulling in changes:';
18993 $logs = $this->getCommitLogs($initial->getSourceReference(), $target->getSourceReference(), $path);
18994
18995 if (!trim($logs)) {
18996 $message = 'Rolling back changes:';
18997 $logs = $this->getCommitLogs($target->getSourceReference(), $initial->getSourceReference(), $path);
18998 }
18999
19000 if (trim($logs)) {
19001 $logs = implode("\n", array_map(function ($line) {
19002 return '      ' . $line;
19003 }, explode("\n", $logs)));
19004
19005
19006 $logs = str_replace('<', '\<', $logs);
19007
19008 $this->io->writeError('    '.$message);
19009 $this->io->writeError($logs);
19010 }
19011 }
19012
19013 if (!$urls && $exception) {
19014 throw $exception;
19015 }
19016 }
19017
19018
19019
19020
19021 public function remove(PackageInterface $package, $path)
19022 {
19023 $this->io->writeError("  - Removing <info>" . $package->getName() . "</info> (<comment>" . $package->getPrettyVersion() . "</comment>)");
19024 $this->cleanChanges($package, $path, false);
19025 if (!$this->filesystem->removeDirectory($path)) {
19026 throw new \RuntimeException('Could not completely delete '.$path.', aborting.');
19027 }
19028 }
19029
19030
19031
19032
19033
19034 public function setOutputProgress($outputProgress)
19035 {
19036 return $this;
19037 }
19038
19039
19040
19041
19042 public function getVcsReference(PackageInterface $package, $path)
19043 {
19044 $parser = new VersionParser;
19045 $guesser = new VersionGuesser($this->config, $this->process, $parser);
19046 $dumper = new ArrayDumper;
19047
19048 $packageConfig = $dumper->dump($package);
19049 if ($packageVersion = $guesser->guessVersion($packageConfig, $path)) {
19050 return $packageVersion['commit'];
19051 }
19052 }
19053
19054
19055
19056
19057
19058
19059
19060
19061
19062
19063 protected function cleanChanges(PackageInterface $package, $path, $update)
19064 {
19065
19066 if (null !== $this->getLocalChanges($package, $path)) {
19067 throw new \RuntimeException('Source directory ' . $path . ' has uncommitted changes.');
19068 }
19069 }
19070
19071
19072
19073
19074
19075
19076
19077 protected function reapplyChanges($path)
19078 {
19079 }
19080
19081
19082
19083
19084
19085
19086
19087
19088 abstract protected function doDownload(PackageInterface $package, $path, $url);
19089
19090
19091
19092
19093
19094
19095
19096
19097
19098 abstract protected function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url);
19099
19100
19101
19102
19103
19104
19105
19106
19107
19108 abstract protected function getCommitLogs($fromReference, $toReference, $path);
19109
19110
19111
19112
19113
19114
19115
19116
19117 abstract protected function hasMetadataRepository($path);
19118 }
19119 <?php
19120
19121
19122
19123
19124
19125
19126
19127
19128
19129
19130
19131 namespace Composer\Downloader;
19132
19133 use Composer\Config;
19134 use Composer\Cache;
19135 use Composer\EventDispatcher\EventDispatcher;
19136 use Composer\Package\PackageInterface;
19137 use Composer\Util\ProcessExecutor;
19138 use Composer\Util\RemoteFilesystem;
19139 use Composer\IO\IOInterface;
19140
19141
19142
19143
19144
19145
19146
19147 class XzDownloader extends ArchiveDownloader
19148 {
19149 protected $process;
19150
19151 public function __construct(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, Cache $cache = null, ProcessExecutor $process = null, RemoteFilesystem $rfs = null)
19152 {
19153 $this->process = $process ?: new ProcessExecutor($io);
19154
19155 parent::__construct($io, $config, $eventDispatcher, $cache, $rfs);
19156 }
19157
19158 protected function extract($file, $path)
19159 {
19160 $command = 'tar -xJf ' . ProcessExecutor::escape($file) . ' -C ' . ProcessExecutor::escape($path);
19161
19162 if (0 === $this->process->execute($command, $ignoredOutput)) {
19163 return;
19164 }
19165
19166 $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput();
19167
19168 throw new \RuntimeException($processError);
19169 }
19170
19171
19172
19173
19174 protected function getFileName(PackageInterface $package, $path)
19175 {
19176 return $path.'/'.pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_BASENAME);
19177 }
19178 }
19179 <?php
19180
19181
19182
19183
19184
19185
19186
19187
19188
19189
19190
19191 namespace Composer\Downloader;
19192
19193 use Composer\Config;
19194 use Composer\Cache;
19195 use Composer\EventDispatcher\EventDispatcher;
19196 use Composer\Package\PackageInterface;
19197 use Composer\Util\IniHelper;
19198 use Composer\Util\Platform;
19199 use Composer\Util\ProcessExecutor;
19200 use Composer\Util\RemoteFilesystem;
19201 use Composer\IO\IOInterface;
19202 use Symfony\Component\Process\ExecutableFinder;
19203 use ZipArchive;
19204
19205
19206
19207
19208 class ZipDownloader extends ArchiveDownloader
19209 {
19210 protected static $hasSystemUnzip;
19211 private static $hasZipArchive;
19212 private static $isWindows;
19213
19214 protected $process;
19215 private $zipArchiveObject;
19216
19217 public function __construct(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, Cache $cache = null, ProcessExecutor $process = null, RemoteFilesystem $rfs = null)
19218 {
19219 $this->process = $process ?: new ProcessExecutor($io);
19220 parent::__construct($io, $config, $eventDispatcher, $cache, $rfs);
19221 }
19222
19223
19224
19225
19226 public function download(PackageInterface $package, $path, $output = true)
19227 {
19228 if (null === self::$hasSystemUnzip) {
19229 $finder = new ExecutableFinder;
19230 self::$hasSystemUnzip = (bool) $finder->find('unzip');
19231 }
19232
19233 if (null === self::$hasZipArchive) {
19234 self::$hasZipArchive = class_exists('ZipArchive');
19235 }
19236
19237 if (!self::$hasZipArchive && !self::$hasSystemUnzip) {
19238
19239 $iniMessage = IniHelper::getMessage();
19240 $error = "The zip extension and unzip command are both missing, skipping.\n" . $iniMessage;
19241
19242 throw new \RuntimeException($error);
19243 }
19244
19245 if (null === self::$isWindows) {
19246 self::$isWindows = Platform::isWindows();
19247
19248 if (!self::$isWindows && !self::$hasSystemUnzip) {
19249 $this->io->writeError("<warning>As there is no 'unzip' command installed zip files are being unpacked using the PHP zip extension.</warning>");
19250 $this->io->writeError("<warning>This may cause invalid reports of corrupted archives. Besides, any UNIX permissions (e.g. executable) defined in the archives will be lost.</warning>");
19251 $this->io->writeError("<warning>Installing 'unzip' may remediate them.</warning>");
19252 }
19253 }
19254
19255 return parent::download($package, $path, $output);
19256 }
19257
19258
19259
19260
19261
19262
19263
19264
19265
19266 protected function extractWithSystemUnzip($file, $path, $isLastChance)
19267 {
19268 if (!self::$hasZipArchive) {
19269
19270 $isLastChance = true;
19271 }
19272
19273 if (!self::$hasSystemUnzip && !$isLastChance) {
19274
19275
19276 return $this->extractWithZipArchive($file, $path, true);
19277 }
19278
19279 $processError = null;
19280
19281 $overwrite = $isLastChance ? '-o' : '';
19282
19283 $command = 'unzip -qq '.$overwrite.' '.ProcessExecutor::escape($file).' -d '.ProcessExecutor::escape($path);
19284
19285 try {
19286 if (0 === $exitCode = $this->process->execute($command, $ignoredOutput)) {
19287 return true;
19288 }
19289
19290 $processError = new \RuntimeException('Failed to execute ('.$exitCode.') '.$command."\n\n".$this->process->getErrorOutput());
19291 } catch (\Exception $e) {
19292 $processError = $e;
19293 }
19294
19295 if ($isLastChance) {
19296 throw $processError;
19297 }
19298
19299 $this->io->writeError('    '.$processError->getMessage());
19300 $this->io->writeError('    The archive may contain identical file names with different capitalization (which fails on case insensitive filesystems)');
19301 $this->io->writeError('    Unzip with unzip command failed, falling back to ZipArchive class');
19302
19303 return $this->extractWithZipArchive($file, $path, true);
19304 }
19305
19306
19307
19308
19309
19310
19311
19312
19313
19314 protected function extractWithZipArchive($file, $path, $isLastChance)
19315 {
19316 if (!self::$hasSystemUnzip) {
19317
19318 $isLastChance = true;
19319 }
19320
19321 if (!self::$hasZipArchive && !$isLastChance) {
19322
19323
19324 return $this->extractWithSystemUnzip($file, $path, true);
19325 }
19326
19327 $processError = null;
19328 $zipArchive = $this->zipArchiveObject ?: new ZipArchive();
19329
19330 try {
19331 if (true === ($retval = $zipArchive->open($file))) {
19332 $extractResult = $zipArchive->extractTo($path);
19333
19334 if (true === $extractResult) {
19335 $zipArchive->close();
19336
19337 return true;
19338 }
19339
19340 $processError = new \RuntimeException(rtrim("There was an error extracting the ZIP file, it is either corrupted or using an invalid format.\n"));
19341 } else {
19342 $processError = new \UnexpectedValueException(rtrim($this->getErrorMessage($retval, $file)."\n"), $retval);
19343 }
19344 } catch (\ErrorException $e) {
19345 $processError = new \RuntimeException('The archive may contain identical file names with different capitalization (which fails on case insensitive filesystems): '.$e->getMessage(), 0, $e);
19346 } catch (\Exception $e) {
19347 $processError = $e;
19348 }
19349
19350 if ($isLastChance) {
19351 throw $processError;
19352 }
19353
19354 $this->io->writeError('    '.$processError->getMessage());
19355 $this->io->writeError('    Unzip with ZipArchive class failed, falling back to unzip command');
19356
19357 return $this->extractWithSystemUnzip($file, $path, true);
19358 }
19359
19360
19361
19362
19363
19364
19365
19366 public function extract($file, $path)
19367 {
19368
19369 if (self::$isWindows) {
19370 $this->extractWithZipArchive($file, $path, false);
19371 } else {
19372 $this->extractWithSystemUnzip($file, $path, false);
19373 }
19374 }
19375
19376
19377
19378
19379
19380
19381
19382
19383 protected function getErrorMessage($retval, $file)
19384 {
19385 switch ($retval) {
19386 case ZipArchive::ER_EXISTS:
19387 return sprintf("File '%s' already exists.", $file);
19388 case ZipArchive::ER_INCONS:
19389 return sprintf("Zip archive '%s' is inconsistent.", $file);
19390 case ZipArchive::ER_INVAL:
19391 return sprintf("Invalid argument (%s)", $file);
19392 case ZipArchive::ER_MEMORY:
19393 return sprintf("Malloc failure (%s)", $file);
19394 case ZipArchive::ER_NOENT:
19395 return sprintf("No such zip file: '%s'", $file);
19396 case ZipArchive::ER_NOZIP:
19397 return sprintf("'%s' is not a zip archive.", $file);
19398 case ZipArchive::ER_OPEN:
19399 return sprintf("Can't open zip file: %s", $file);
19400 case ZipArchive::ER_READ:
19401 return sprintf("Zip read error (%s)", $file);
19402 case ZipArchive::ER_SEEK:
19403 return sprintf("Zip seek error (%s)", $file);
19404 default:
19405 return sprintf("'%s' is not a valid zip archive, got error code: %s", $file, $retval);
19406 }
19407 }
19408 }
19409 <?php
19410
19411
19412
19413
19414
19415
19416
19417
19418
19419
19420
19421 namespace Composer\EventDispatcher;
19422
19423
19424
19425
19426
19427
19428 class Event
19429 {
19430
19431
19432
19433 protected $name;
19434
19435
19436
19437
19438 protected $args;
19439
19440
19441
19442
19443 protected $flags;
19444
19445
19446
19447
19448 private $propagationStopped = false;
19449
19450
19451
19452
19453
19454
19455
19456
19457 public function __construct($name, array $args = array(), array $flags = array())
19458 {
19459 $this->name = $name;
19460 $this->args = $args;
19461 $this->flags = $flags;
19462 }
19463
19464
19465
19466
19467
19468
19469 public function getName()
19470 {
19471 return $this->name;
19472 }
19473
19474
19475
19476
19477
19478
19479 public function getArguments()
19480 {
19481 return $this->args;
19482 }
19483
19484
19485
19486
19487
19488
19489 public function getFlags()
19490 {
19491 return $this->flags;
19492 }
19493
19494
19495
19496
19497
19498
19499 public function isPropagationStopped()
19500 {
19501 return $this->propagationStopped;
19502 }
19503
19504
19505
19506
19507 public function stopPropagation()
19508 {
19509 $this->propagationStopped = true;
19510 }
19511 }
19512 <?php
19513
19514
19515
19516
19517
19518
19519
19520
19521
19522
19523
19524 namespace Composer\EventDispatcher;
19525
19526 use Composer\DependencyResolver\PolicyInterface;
19527 use Composer\DependencyResolver\Pool;
19528 use Composer\DependencyResolver\Request;
19529 use Composer\Installer\InstallerEvent;
19530 use Composer\IO\IOInterface;
19531 use Composer\Composer;
19532 use Composer\DependencyResolver\Operation\OperationInterface;
19533 use Composer\Repository\CompositeRepository;
19534 use Composer\Script;
19535 use Composer\Installer\PackageEvent;
19536 use Composer\Installer\BinaryInstaller;
19537 use Composer\Util\ProcessExecutor;
19538 use Composer\Script\Event as ScriptEvent;
19539 use Symfony\Component\Process\PhpExecutableFinder;
19540
19541
19542
19543
19544
19545
19546
19547
19548
19549
19550
19551
19552
19553
19554 class EventDispatcher
19555 {
19556 protected $composer;
19557 protected $io;
19558 protected $loader;
19559 protected $process;
19560 protected $listeners;
19561 private $eventStack;
19562
19563
19564
19565
19566
19567
19568
19569
19570 public function __construct(Composer $composer, IOInterface $io, ProcessExecutor $process = null)
19571 {
19572 $this->composer = $composer;
19573 $this->io = $io;
19574 $this->process = $process ?: new ProcessExecutor($io);
19575 $this->eventStack = array();
19576 }
19577
19578
19579
19580
19581
19582
19583
19584
19585
19586 public function dispatch($eventName, Event $event = null)
19587 {
19588 if (null === $event) {
19589 $event = new Event($eventName);
19590 }
19591
19592 return $this->doDispatch($event);
19593 }
19594
19595
19596
19597
19598
19599
19600
19601
19602
19603
19604
19605 public function dispatchScript($eventName, $devMode = false, $additionalArgs = array(), $flags = array())
19606 {
19607 return $this->doDispatch(new Script\Event($eventName, $this->composer, $this->io, $devMode, $additionalArgs, $flags));
19608 }
19609
19610
19611
19612
19613
19614
19615
19616
19617
19618
19619
19620
19621
19622
19623
19624
19625 public function dispatchPackageEvent($eventName, $devMode, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations, OperationInterface $operation)
19626 {
19627 return $this->doDispatch(new PackageEvent($eventName, $this->composer, $this->io, $devMode, $policy, $pool, $installedRepo, $request, $operations, $operation));
19628 }
19629
19630
19631
19632
19633
19634
19635
19636
19637
19638
19639
19640
19641
19642
19643
19644 public function dispatchInstallerEvent($eventName, $devMode, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations = array())
19645 {
19646 return $this->doDispatch(new InstallerEvent($eventName, $this->composer, $this->io, $devMode, $policy, $pool, $installedRepo, $request, $operations));
19647 }
19648
19649
19650
19651
19652
19653
19654
19655
19656
19657 protected function doDispatch(Event $event)
19658 {
19659 $listeners = $this->getListeners($event);
19660
19661 $this->pushEvent($event);
19662
19663 $return = 0;
19664 foreach ($listeners as $callable) {
19665
19666 $this->ensureBinDirIsInPath();
19667
19668 if (!is_string($callable)) {
19669 if (!is_callable($callable)) {
19670 $className = is_object($callable[0]) ? get_class($callable[0]) : $callable[0];
19671
19672 throw new \RuntimeException('Subscriber '.$className.'::'.$callable[1].' for event '.$event->getName().' is not callable, make sure the function is defined and public');
19673 }
19674 $event = $this->checkListenerExpectedEvent($callable, $event);
19675 $return = false === call_user_func($callable, $event) ? 1 : 0;
19676 } elseif ($this->isComposerScript($callable)) {
19677 $this->io->writeError(sprintf('> %s: %s', $event->getName(), $callable), true, IOInterface::VERBOSE);
19678
19679 $script = explode(' ', substr($callable, 1));
19680 $scriptName = $script[0];
19681 unset($script[0]);
19682
19683 $args = array_merge($script, $event->getArguments());
19684 $flags = $event->getFlags();
19685 if (substr($callable, 0, 10) === '@composer ') {
19686 $exec = $this->getPhpExecCommand() . ' ' . ProcessExecutor::escape(getenv('COMPOSER_BINARY')) . substr($callable, 9);
19687 if (0 !== ($exitCode = $this->process->execute($exec))) {
19688 $this->io->writeError(sprintf('<error>Script %s handling the %s event returned with error code '.$exitCode.'</error>', $callable, $event->getName()), true, IOInterface::QUIET);
19689
19690 throw new ScriptExecutionException('Error Output: '.$this->process->getErrorOutput(), $exitCode);
19691 }
19692 } else {
19693 if (!$this->getListeners(new Event($scriptName))) {
19694 $this->io->writeError(sprintf('<warning>You made a reference to a non-existent script %s</warning>', $callable), true, IOInterface::QUIET);
19695 }
19696
19697 try {
19698 $scriptEvent = new Script\Event($scriptName, $event->getComposer(), $event->getIO(), $event->isDevMode(), $args, $flags);
19699 $scriptEvent->setOriginatingEvent($event);
19700 $return = $this->dispatch($scriptName, $scriptEvent);
19701 } catch (ScriptExecutionException $e) {
19702 $this->io->writeError(sprintf('<error>Script %s was called via %s</error>', $callable, $event->getName()), true, IOInterface::QUIET);
19703 throw $e;
19704 }
19705 }
19706 } elseif ($this->isPhpScript($callable)) {
19707 $className = substr($callable, 0, strpos($callable, '::'));
19708 $methodName = substr($callable, strpos($callable, '::') + 2);
19709
19710 if (!class_exists($className)) {
19711 $this->io->writeError('<warning>Class '.$className.' is not autoloadable, can not call '.$event->getName().' script</warning>', true, IOInterface::QUIET);
19712 continue;
19713 }
19714 if (!is_callable($callable)) {
19715 $this->io->writeError('<warning>Method '.$callable.' is not callable, can not call '.$event->getName().' script</warning>', true, IOInterface::QUIET);
19716 continue;
19717 }
19718
19719 try {
19720 $return = false === $this->executeEventPhpScript($className, $methodName, $event) ? 1 : 0;
19721 } catch (\Exception $e) {
19722 $message = "Script %s handling the %s event terminated with an exception";
19723 $this->io->writeError('<error>'.sprintf($message, $callable, $event->getName()).'</error>', true, IOInterface::QUIET);
19724 throw $e;
19725 }
19726 } else {
19727 $args = implode(' ', array_map(array('Composer\Util\ProcessExecutor', 'escape'), $event->getArguments()));
19728 $exec = $callable . ($args === '' ? '' : ' '.$args);
19729 if ($this->io->isVerbose()) {
19730 $this->io->writeError(sprintf('> %s: %s', $event->getName(), $exec));
19731 } else {
19732 $this->io->writeError(sprintf('> %s', $exec));
19733 }
19734
19735 $possibleLocalBinaries = $this->composer->getPackage()->getBinaries();
19736 if ($possibleLocalBinaries) {
19737 foreach ($possibleLocalBinaries as $localExec) {
19738 if (preg_match('{\b'.preg_quote($callable).'$}', $localExec)) {
19739 $caller = BinaryInstaller::determineBinaryCaller($localExec);
19740 $exec = preg_replace('{^'.preg_quote($callable).'}', $caller . ' ' . $localExec, $exec);
19741 break;
19742 }
19743 }
19744 }
19745
19746 if (substr($exec, 0, 8) === '@putenv ') {
19747 putenv(substr($exec, 8));
19748 list($var, $value) = explode('=', substr($exec, 8), 2);
19749 $_SERVER[$var] = $value;
19750
19751 continue;
19752 } elseif (substr($exec, 0, 5) === '@php ') {
19753 $exec = $this->getPhpExecCommand() . ' ' . substr($exec, 5);
19754 } else {
19755 $finder = new PhpExecutableFinder();
19756 $phpPath = $finder->find(false);
19757 if ($phpPath) {
19758 $_SERVER['PHP_BINARY'] = $phpPath;
19759 putenv('PHP_BINARY=' . $_SERVER['PHP_BINARY']);
19760 }
19761 }
19762
19763
19764
19765
19766 if (substr($exec, 0, 9) === 'composer ') {
19767 $exec = $this->getPhpExecCommand() . ' ' . ProcessExecutor::escape(getenv('COMPOSER_BINARY')) . substr($exec, 8);
19768 }
19769
19770 if (0 !== ($exitCode = $this->process->execute($exec))) {
19771 $this->io->writeError(sprintf('<error>Script %s handling the %s event returned with error code '.$exitCode.'</error>', $callable, $event->getName()), true, IOInterface::QUIET);
19772
19773 throw new ScriptExecutionException('Error Output: '.$this->process->getErrorOutput(), $exitCode);
19774 }
19775 }
19776
19777 if ($event->isPropagationStopped()) {
19778 break;
19779 }
19780 }
19781
19782 $this->popEvent();
19783
19784 return $return;
19785 }
19786
19787 protected function getPhpExecCommand()
19788 {
19789 $finder = new PhpExecutableFinder();
19790 $phpPath = $finder->find(false);
19791 if (!$phpPath) {
19792 throw new \RuntimeException('Failed to locate PHP binary to execute '.$phpPath);
19793 }
19794 $phpArgs = $finder->findArguments();
19795 $phpArgs = $phpArgs ? ' ' . implode(' ', $phpArgs) : '';
19796 $allowUrlFOpenFlag = ' -d allow_url_fopen=' . ProcessExecutor::escape(ini_get('allow_url_fopen'));
19797 $disableFunctionsFlag = ' -d disable_functions=' . ProcessExecutor::escape(ini_get('disable_functions'));
19798 $memoryLimitFlag = ' -d memory_limit=' . ProcessExecutor::escape(ini_get('memory_limit'));
19799
19800 return ProcessExecutor::escape($phpPath) . $phpArgs . $allowUrlFOpenFlag . $disableFunctionsFlag . $memoryLimitFlag;
19801 }
19802
19803
19804
19805
19806
19807
19808 protected function executeEventPhpScript($className, $methodName, Event $event)
19809 {
19810 $event = $this->checkListenerExpectedEvent(array($className, $methodName), $event);
19811
19812 if ($this->io->isVerbose()) {
19813 $this->io->writeError(sprintf('> %s: %s::%s', $event->getName(), $className, $methodName));
19814 } else {
19815 $this->io->writeError(sprintf('> %s::%s', $className, $methodName));
19816 }
19817
19818 return $className::$methodName($event);
19819 }
19820
19821
19822
19823
19824
19825
19826 protected function checkListenerExpectedEvent($target, Event $event)
19827 {
19828 if (in_array($event->getName(), array(
19829 'init',
19830 'command',
19831 'pre-file-download',
19832 ), true)) {
19833 return $event;
19834 }
19835
19836 try {
19837 $reflected = new \ReflectionParameter($target, 0);
19838 } catch (\Exception $e) {
19839 return $event;
19840 }
19841
19842 $expected = null;
19843 $isClass = false;
19844 if (\PHP_VERSION_ID >= 70000) {
19845 $reflectionType = $reflected->getType();
19846 if ($reflectionType) {
19847 $expected = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : (string)$reflectionType;
19848 $isClass = !$reflectionType->isBuiltin();
19849 }
19850 } else {
19851 $expected = $reflected->getClass() ? $reflected->getClass()->getName() : null;
19852 $isClass = null !== $expected;
19853 }
19854
19855 if (!$isClass) {
19856 return $event;
19857 }
19858
19859
19860 if (!$event instanceof $expected && $expected === 'Composer\Script\CommandEvent') {
19861 trigger_error('The callback '.$this->serializeCallback($target).' declared at '.$reflected->getDeclaringFunction()->getFileName().' accepts a '.$expected.' but '.$event->getName().' events use a '.get_class($event).' instance. Please adjust your type hint accordingly, see https://getcomposer.org/doc/articles/scripts.md#event-classes', E_USER_DEPRECATED);
19862 $event = new \Composer\Script\CommandEvent(
19863 $event->getName(),
19864 $event->getComposer(),
19865 $event->getIO(),
19866 $event->isDevMode(),
19867 $event->getArguments()
19868 );
19869 }
19870 if (!$event instanceof $expected && $expected === 'Composer\Script\PackageEvent') {
19871 trigger_error('The callback '.$this->serializeCallback($target).' declared at '.$reflected->getDeclaringFunction()->getFileName().' accepts a '.$expected.' but '.$event->getName().' events use a '.get_class($event).' instance. Please adjust your type hint accordingly, see https://getcomposer.org/doc/articles/scripts.md#event-classes', E_USER_DEPRECATED);
19872 $event = new \Composer\Script\PackageEvent(
19873 $event->getName(),
19874 $event->getComposer(),
19875 $event->getIO(),
19876 $event->isDevMode(),
19877 $event->getPolicy(),
19878 $event->getPool(),
19879 $event->getInstalledRepo(),
19880 $event->getRequest(),
19881 $event->getOperations(),
19882 $event->getOperation()
19883 );
19884 }
19885 if (!$event instanceof $expected && $expected === 'Composer\Script\Event') {
19886 trigger_error('The callback '.$this->serializeCallback($target).' declared at '.$reflected->getDeclaringFunction()->getFileName().' accepts a '.$expected.' but '.$event->getName().' events use a '.get_class($event).' instance. Please adjust your type hint accordingly, see https://getcomposer.org/doc/articles/scripts.md#event-classes', E_USER_DEPRECATED);
19887 $event = new \Composer\Script\Event(
19888 $event->getName(),
19889 $event->getComposer(),
19890 $event->getIO(),
19891 $event->isDevMode(),
19892 $event->getArguments(),
19893 $event->getFlags()
19894 );
19895 }
19896
19897 return $event;
19898 }
19899
19900 private function serializeCallback($cb)
19901 {
19902 if (is_array($cb) && count($cb) === 2) {
19903 if (is_object($cb[0])) {
19904 $cb[0] = get_class($cb[0]);
19905 }
19906 if (is_string($cb[0]) && is_string($cb[1])) {
19907 $cb = implode('::', $cb);
19908 }
19909 }
19910 if (is_string($cb)) {
19911 return $cb;
19912 }
19913
19914 return var_export($cb, true);
19915 }
19916
19917
19918
19919
19920
19921
19922
19923
19924 public function addListener($eventName, $listener, $priority = 0)
19925 {
19926 $this->listeners[$eventName][$priority][] = $listener;
19927 }
19928
19929
19930
19931
19932
19933
19934
19935
19936 public function addSubscriber(EventSubscriberInterface $subscriber)
19937 {
19938 foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
19939 if (is_string($params)) {
19940 $this->addListener($eventName, array($subscriber, $params));
19941 } elseif (is_string($params[0])) {
19942 $this->addListener($eventName, array($subscriber, $params[0]), isset($params[1]) ? $params[1] : 0);
19943 } else {
19944 foreach ($params as $listener) {
19945 $this->addListener($eventName, array($subscriber, $listener[0]), isset($listener[1]) ? $listener[1] : 0);
19946 }
19947 }
19948 }
19949 }
19950
19951
19952
19953
19954
19955
19956
19957 protected function getListeners(Event $event)
19958 {
19959 $scriptListeners = $this->getScriptListeners($event);
19960
19961 if (!isset($this->listeners[$event->getName()][0])) {
19962 $this->listeners[$event->getName()][0] = array();
19963 }
19964 krsort($this->listeners[$event->getName()]);
19965
19966 $listeners = $this->listeners;
19967 $listeners[$event->getName()][0] = array_merge($listeners[$event->getName()][0], $scriptListeners);
19968
19969 return call_user_func_array('array_merge', $listeners[$event->getName()]);
19970 }
19971
19972
19973
19974
19975
19976
19977
19978 public function hasEventListeners(Event $event)
19979 {
19980 $listeners = $this->getListeners($event);
19981
19982 return count($listeners) > 0;
19983 }
19984
19985
19986
19987
19988
19989
19990
19991 protected function getScriptListeners(Event $event)
19992 {
19993 $package = $this->composer->getPackage();
19994 $scripts = $package->getScripts();
19995
19996 if (empty($scripts[$event->getName()])) {
19997 return array();
19998 }
19999
20000 if ($this->loader) {
20001 $this->loader->unregister();
20002 }
20003
20004 $generator = $this->composer->getAutoloadGenerator();
20005 if ($event instanceof ScriptEvent) {
20006 $generator->setDevMode($event->isDevMode());
20007 }
20008
20009 $packages = $this->composer->getRepositoryManager()->getLocalRepository()->getCanonicalPackages();
20010 $packageMap = $generator->buildPackageMap($this->composer->getInstallationManager(), $package, $packages);
20011 $map = $generator->parseAutoloads($packageMap, $package);
20012 $this->loader = $generator->createLoader($map);
20013 $this->loader->register();
20014
20015 return $scripts[$event->getName()];
20016 }
20017
20018
20019
20020
20021
20022
20023
20024 protected function isPhpScript($callable)
20025 {
20026 return false === strpos($callable, ' ') && false !== strpos($callable, '::');
20027 }
20028
20029
20030
20031
20032
20033
20034
20035 protected function isComposerScript($callable)
20036 {
20037 return '@' === substr($callable, 0, 1) && '@php ' !== substr($callable, 0, 5) && '@putenv ' !== substr($callable, 0, 8);
20038 }
20039
20040
20041
20042
20043
20044
20045
20046
20047 protected function pushEvent(Event $event)
20048 {
20049 $eventName = $event->getName();
20050 if (in_array($eventName, $this->eventStack)) {
20051 throw new \RuntimeException(sprintf("Circular call to script handler '%s' detected", $eventName));
20052 }
20053
20054 return array_push($this->eventStack, $eventName);
20055 }
20056
20057
20058
20059
20060
20061
20062 protected function popEvent()
20063 {
20064 return array_pop($this->eventStack);
20065 }
20066
20067 private function ensureBinDirIsInPath()
20068 {
20069 $pathStr = 'PATH';
20070 if (!isset($_SERVER[$pathStr]) && isset($_SERVER['Path'])) {
20071 $pathStr = 'Path';
20072 }
20073
20074
20075 $binDir = $this->composer->getConfig()->get('bin-dir');
20076 if (is_dir($binDir)) {
20077 $binDir = realpath($binDir);
20078 if (isset($_SERVER[$pathStr]) && !preg_match('{(^|'.PATH_SEPARATOR.')'.preg_quote($binDir).'($|'.PATH_SEPARATOR.')}', $_SERVER[$pathStr])) {
20079 $_SERVER[$pathStr] = $binDir.PATH_SEPARATOR.getenv($pathStr);
20080 putenv($pathStr.'='.$_SERVER[$pathStr]);
20081 }
20082 }
20083 }
20084 }
20085 <?php
20086
20087
20088
20089
20090
20091
20092
20093
20094
20095
20096
20097 namespace Composer\EventDispatcher;
20098
20099
20100
20101
20102
20103
20104
20105
20106
20107
20108
20109
20110
20111 interface EventSubscriberInterface
20112 {
20113
20114
20115
20116
20117
20118
20119
20120
20121
20122
20123
20124
20125
20126
20127
20128
20129
20130
20131 public static function getSubscribedEvents();
20132 }
20133 <?php
20134
20135
20136
20137
20138
20139
20140
20141
20142
20143
20144
20145 namespace Composer\EventDispatcher;
20146
20147
20148
20149
20150 class ScriptExecutionException extends \RuntimeException
20151 {
20152 }
20153 <?php
20154
20155
20156
20157
20158
20159
20160
20161
20162
20163
20164
20165 namespace Composer\Exception;
20166
20167
20168
20169
20170 class NoSslException extends \RuntimeException
20171 {
20172 }
20173 <?php
20174
20175
20176
20177
20178
20179
20180
20181
20182
20183
20184
20185 namespace Composer;
20186
20187 use Composer\Config\JsonConfigSource;
20188 use Composer\Json\JsonFile;
20189 use Composer\IO\IOInterface;
20190 use Composer\Package\Archiver;
20191 use Composer\Package\Version\VersionGuesser;
20192 use Composer\Repository\RepositoryManager;
20193 use Composer\Repository\RepositoryFactory;
20194 use Composer\Repository\WritableRepositoryInterface;
20195 use Composer\Util\Filesystem;
20196 use Composer\Util\Platform;
20197 use Composer\Util\ProcessExecutor;
20198 use Composer\Util\RemoteFilesystem;
20199 use Composer\Util\Silencer;
20200 use Composer\Plugin\PluginEvents;
20201 use Composer\EventDispatcher\Event;
20202 use Seld\JsonLint\DuplicateKeyException;
20203 use Symfony\Component\Console\Formatter\OutputFormatter;
20204 use Symfony\Component\Console\Formatter\OutputFormatterStyle;
20205 use Symfony\Component\Console\Output\ConsoleOutput;
20206 use Composer\EventDispatcher\EventDispatcher;
20207 use Composer\Autoload\AutoloadGenerator;
20208 use Composer\Package\Version\VersionParser;
20209 use Composer\Downloader\TransportException;
20210 use Seld\JsonLint\JsonParser;
20211
20212
20213
20214
20215
20216
20217
20218
20219
20220 class Factory
20221 {
20222
20223
20224
20225
20226 protected static function getHomeDir()
20227 {
20228 $home = getenv('COMPOSER_HOME');
20229 if ($home) {
20230 return $home;
20231 }
20232
20233 if (Platform::isWindows()) {
20234 if (!getenv('APPDATA')) {
20235 throw new \RuntimeException('The APPDATA or COMPOSER_HOME environment variable must be set for composer to run correctly');
20236 }
20237
20238 return rtrim(strtr(getenv('APPDATA'), '\\', '/'), '/') . '/Composer';
20239 }
20240
20241 $userDir = self::getUserDir();
20242 if (is_dir($userDir . '/.composer')) {
20243 return $userDir . '/.composer';
20244 }
20245
20246 if (self::useXdg()) {
20247
20248 $xdgConfig = getenv('XDG_CONFIG_HOME') ?: $userDir . '/.config';
20249
20250 return $xdgConfig . '/composer';
20251 }
20252
20253 return $userDir . '/.composer';
20254 }
20255
20256
20257
20258
20259
20260 protected static function getCacheDir($home)
20261 {
20262 $cacheDir = getenv('COMPOSER_CACHE_DIR');
20263 if ($cacheDir) {
20264 return $cacheDir;
20265 }
20266
20267 $homeEnv = getenv('COMPOSER_HOME');
20268 if ($homeEnv) {
20269 return $homeEnv . '/cache';
20270 }
20271
20272 if (Platform::isWindows()) {
20273 if ($cacheDir = getenv('LOCALAPPDATA')) {
20274 $cacheDir .= '/Composer';
20275 } else {
20276 $cacheDir = $home . '/cache';
20277 }
20278
20279 return rtrim(strtr($cacheDir, '\\', '/'), '/');
20280 }
20281
20282 $userDir = self::getUserDir();
20283 if ($home === $userDir . '/.composer' && is_dir($home . '/cache')) {
20284 return $home . '/cache';
20285 }
20286
20287 if (self::useXdg()) {
20288 $xdgCache = getenv('XDG_CACHE_HOME') ?: $userDir . '/.cache';
20289
20290 return $xdgCache . '/composer';
20291 }
20292
20293 return $home . '/cache';
20294 }
20295
20296
20297
20298
20299
20300 protected static function getDataDir($home)
20301 {
20302 $homeEnv = getenv('COMPOSER_HOME');
20303 if ($homeEnv) {
20304 return $homeEnv;
20305 }
20306
20307 if (Platform::isWindows()) {
20308 return strtr($home, '\\', '/');
20309 }
20310
20311 $userDir = self::getUserDir();
20312 if ($home !== $userDir . '/.composer' && self::useXdg()) {
20313 $xdgData = getenv('XDG_DATA_HOME') ?: $userDir . '/.local/share';
20314
20315 return $xdgData . '/composer';
20316 }
20317
20318 return $home;
20319 }
20320
20321
20322
20323
20324
20325 public static function createConfig(IOInterface $io = null, $cwd = null)
20326 {
20327 $cwd = $cwd ?: getcwd();
20328
20329 $config = new Config(true, $cwd);
20330
20331
20332 $home = self::getHomeDir();
20333 $config->merge(array('config' => array(
20334 'home' => $home,
20335 'cache-dir' => self::getCacheDir($home),
20336 'data-dir' => self::getDataDir($home),
20337 )));
20338
20339
20340 $file = new JsonFile($config->get('home').'/config.json');
20341 if ($file->exists()) {
20342 if ($io && $io->isDebug()) {
20343 $io->writeError('Loading config file ' . $file->getPath());
20344 }
20345 $config->merge($file->read());
20346 }
20347 $config->setConfigSource(new JsonConfigSource($file));
20348
20349 $htaccessProtect = (bool) $config->get('htaccess-protect');
20350 if ($htaccessProtect) {
20351
20352
20353
20354 $dirs = array($config->get('home'), $config->get('cache-dir'), $config->get('data-dir'));
20355 foreach ($dirs as $dir) {
20356 if (!file_exists($dir . '/.htaccess')) {
20357 if (!is_dir($dir)) {
20358 Silencer::call('mkdir', $dir, 0777, true);
20359 }
20360 Silencer::call('file_put_contents', $dir . '/.htaccess', 'Deny from all');
20361 }
20362 }
20363 }
20364
20365
20366 $file = new JsonFile($config->get('home').'/auth.json');
20367 if ($file->exists()) {
20368 if ($io && $io->isDebug()) {
20369 $io->writeError('Loading config file ' . $file->getPath());
20370 }
20371 $config->merge(array('config' => $file->read()));
20372 }
20373 $config->setAuthConfigSource(new JsonConfigSource($file, true));
20374
20375
20376 if ($composerAuthEnv = getenv('COMPOSER_AUTH')) {
20377 $authData = json_decode($composerAuthEnv, true);
20378
20379 if (null === $authData) {
20380 throw new \UnexpectedValueException('COMPOSER_AUTH environment variable is malformed, should be a valid JSON object');
20381 }
20382
20383 if ($io && $io->isDebug()) {
20384 $io->writeError('Loading auth config from COMPOSER_AUTH');
20385 }
20386 $config->merge(array('config' => $authData));
20387 }
20388
20389 return $config;
20390 }
20391
20392 public static function getComposerFile()
20393 {
20394 return trim(getenv('COMPOSER')) ?: './composer.json';
20395 }
20396
20397 public static function createAdditionalStyles()
20398 {
20399 return array(
20400 'highlight' => new OutputFormatterStyle('red'),
20401 'warning' => new OutputFormatterStyle('black', 'yellow'),
20402 );
20403 }
20404
20405
20406
20407
20408
20409
20410 public static function createOutput()
20411 {
20412 $styles = self::createAdditionalStyles();
20413 $formatter = new OutputFormatter(false, $styles);
20414
20415 return new ConsoleOutput(ConsoleOutput::VERBOSITY_NORMAL, null, $formatter);
20416 }
20417
20418
20419
20420
20421 public static function createDefaultRepositories(IOInterface $io = null, Config $config = null, RepositoryManager $rm = null)
20422 {
20423 return RepositoryFactory::defaultRepos($io, $config, $rm);
20424 }
20425
20426
20427
20428
20429
20430
20431
20432
20433
20434
20435
20436
20437
20438 public function createComposer(IOInterface $io, $localConfig = null, $disablePlugins = false, $cwd = null, $fullLoad = true)
20439 {
20440 $cwd = $cwd ?: getcwd();
20441
20442
20443 if (null === $localConfig) {
20444 $localConfig = static::getComposerFile();
20445 }
20446
20447 if (is_string($localConfig)) {
20448 $composerFile = $localConfig;
20449
20450 $file = new JsonFile($localConfig, null, $io);
20451
20452 if (!$file->exists()) {
20453 if ($localConfig === './composer.json' || $localConfig === 'composer.json') {
20454 $message = 'Composer could not find a composer.json file in '.$cwd;
20455 } else {
20456 $message = 'Composer could not find the config file: '.$localConfig;
20457 }
20458 $instructions = 'To initialize a project, please create a composer.json file as described in the https://getcomposer.org/ "Getting Started" section';
20459 throw new \InvalidArgumentException($message.PHP_EOL.$instructions);
20460 }
20461
20462 $file->validateSchema(JsonFile::LAX_SCHEMA);
20463 $jsonParser = new JsonParser;
20464 try {
20465 $jsonParser->parse(file_get_contents($localConfig), JsonParser::DETECT_KEY_CONFLICTS);
20466 } catch (DuplicateKeyException $e) {
20467 $details = $e->getDetails();
20468 $io->writeError('<warning>Key '.$details['key'].' is a duplicate in '.$localConfig.' at line '.$details['line'].'</warning>');
20469 }
20470
20471 $localConfig = $file->read();
20472 }
20473
20474
20475 $config = static::createConfig($io, $cwd);
20476 $config->merge($localConfig);
20477 if (isset($composerFile)) {
20478 $io->writeError('Loading config file ' . $composerFile, true, IOInterface::DEBUG);
20479 $config->setConfigSource(new JsonConfigSource(new JsonFile(realpath($composerFile), null, $io)));
20480
20481 $localAuthFile = new JsonFile(dirname(realpath($composerFile)) . '/auth.json', null, $io);
20482 if ($localAuthFile->exists()) {
20483 $io->writeError('Loading config file ' . $localAuthFile->getPath(), true, IOInterface::DEBUG);
20484 $config->merge(array('config' => $localAuthFile->read()));
20485 $config->setAuthConfigSource(new JsonConfigSource($localAuthFile, true));
20486 }
20487 }
20488
20489 $vendorDir = $config->get('vendor-dir');
20490
20491
20492 $composer = new Composer();
20493 $composer->setConfig($config);
20494
20495 if ($fullLoad) {
20496
20497 $io->loadConfiguration($config);
20498 }
20499
20500 $rfs = self::createRemoteFilesystem($io, $config);
20501
20502
20503 $dispatcher = new EventDispatcher($composer, $io);
20504 $composer->setEventDispatcher($dispatcher);
20505
20506
20507 $rm = RepositoryFactory::manager($io, $config, $dispatcher, $rfs);
20508 $composer->setRepositoryManager($rm);
20509
20510
20511 $this->addLocalRepository($io, $rm, $vendorDir);
20512
20513
20514
20515 if (!$fullLoad && !isset($localConfig['version'])) {
20516 $localConfig['version'] = '1.0.0';
20517 }
20518
20519
20520 $parser = new VersionParser;
20521 $guesser = new VersionGuesser($config, new ProcessExecutor($io), $parser);
20522 $loader = new Package\Loader\RootPackageLoader($rm, $config, $parser, $guesser, $io);
20523 $package = $loader->load($localConfig, 'Composer\Package\RootPackage', $cwd);
20524 $composer->setPackage($package);
20525
20526
20527 $im = $this->createInstallationManager();
20528 $composer->setInstallationManager($im);
20529
20530 if ($fullLoad) {
20531
20532 $dm = $this->createDownloadManager($io, $config, $dispatcher, $rfs);
20533 $composer->setDownloadManager($dm);
20534
20535
20536 $generator = new AutoloadGenerator($dispatcher, $io);
20537 $composer->setAutoloadGenerator($generator);
20538
20539
20540 $am = $this->createArchiveManager($config, $dm);
20541 $composer->setArchiveManager($am);
20542 }
20543
20544
20545 $this->createDefaultInstallers($im, $composer, $io);
20546
20547 if ($fullLoad) {
20548 $globalComposer = null;
20549 if (realpath($config->get('home')) !== $cwd) {
20550 $globalComposer = $this->createGlobalComposer($io, $config, $disablePlugins);
20551 }
20552
20553 $pm = $this->createPluginManager($io, $composer, $globalComposer, $disablePlugins);
20554 $composer->setPluginManager($pm);
20555
20556 $pm->loadInstalledPlugins();
20557 }
20558
20559
20560 if ($fullLoad && isset($composerFile)) {
20561 $lockFile = "json" === pathinfo($composerFile, PATHINFO_EXTENSION)
20562 ? substr($composerFile, 0, -4).'lock'
20563 : $composerFile . '.lock';
20564
20565 $locker = new Package\Locker($io, new JsonFile($lockFile, null, $io), $rm, $im, file_get_contents($composerFile));
20566 $composer->setLocker($locker);
20567 }
20568
20569 if ($fullLoad) {
20570 $initEvent = new Event(PluginEvents::INIT);
20571 $composer->getEventDispatcher()->dispatch($initEvent->getName(), $initEvent);
20572
20573
20574
20575 if ($rm->getLocalRepository()) {
20576 $this->purgePackages($rm->getLocalRepository(), $im);
20577 }
20578 }
20579
20580 return $composer;
20581 }
20582
20583
20584
20585
20586
20587
20588 public static function createGlobal(IOInterface $io, $disablePlugins = false)
20589 {
20590 $factory = new static();
20591
20592 return $factory->createGlobalComposer($io, static::createConfig($io), $disablePlugins, true);
20593 }
20594
20595
20596
20597
20598
20599 protected function addLocalRepository(IOInterface $io, RepositoryManager $rm, $vendorDir)
20600 {
20601 $rm->setLocalRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/composer/installed.json', null, $io)));
20602 }
20603
20604
20605
20606
20607
20608 protected function createGlobalComposer(IOInterface $io, Config $config, $disablePlugins, $fullLoad = false)
20609 {
20610 $composer = null;
20611 try {
20612 $composer = $this->createComposer($io, $config->get('home') . '/composer.json', $disablePlugins, $config->get('home'), $fullLoad);
20613 } catch (\Exception $e) {
20614 $io->writeError('Failed to initialize global composer: '.$e->getMessage(), true, IOInterface::DEBUG);
20615 }
20616
20617 return $composer;
20618 }
20619
20620
20621
20622
20623
20624
20625
20626 public function createDownloadManager(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, RemoteFilesystem $rfs = null)
20627 {
20628 $cache = null;
20629 if ($config->get('cache-files-ttl') > 0) {
20630 $cache = new Cache($io, $config->get('cache-files-dir'), 'a-z0-9_./');
20631 }
20632
20633 $dm = new Downloader\DownloadManager($io);
20634 switch ($preferred = $config->get('preferred-install')) {
20635 case 'dist':
20636 $dm->setPreferDist(true);
20637 break;
20638 case 'source':
20639 $dm->setPreferSource(true);
20640 break;
20641 case 'auto':
20642 default:
20643
20644 break;
20645 }
20646
20647 if (is_array($preferred)) {
20648 $dm->setPreferences($preferred);
20649 }
20650
20651 $executor = new ProcessExecutor($io);
20652 $fs = new Filesystem($executor);
20653
20654 $dm->setDownloader('git', new Downloader\GitDownloader($io, $config, $executor, $fs));
20655 $dm->setDownloader('svn', new Downloader\SvnDownloader($io, $config, $executor, $fs));
20656 $dm->setDownloader('fossil', new Downloader\FossilDownloader($io, $config, $executor, $fs));
20657 $dm->setDownloader('hg', new Downloader\HgDownloader($io, $config, $executor, $fs));
20658 $dm->setDownloader('perforce', new Downloader\PerforceDownloader($io, $config));
20659 $dm->setDownloader('zip', new Downloader\ZipDownloader($io, $config, $eventDispatcher, $cache, $executor, $rfs));
20660 $dm->setDownloader('rar', new Downloader\RarDownloader($io, $config, $eventDispatcher, $cache, $executor, $rfs));
20661 $dm->setDownloader('tar', new Downloader\TarDownloader($io, $config, $eventDispatcher, $cache, $rfs));
20662 $dm->setDownloader('gzip', new Downloader\GzipDownloader($io, $config, $eventDispatcher, $cache, $executor, $rfs));
20663 $dm->setDownloader('xz', new Downloader\XzDownloader($io, $config, $eventDispatcher, $cache, $executor, $rfs));
20664 $dm->setDownloader('phar', new Downloader\PharDownloader($io, $config, $eventDispatcher, $cache, $rfs));
20665 $dm->setDownloader('file', new Downloader\FileDownloader($io, $config, $eventDispatcher, $cache, $rfs));
20666 $dm->setDownloader('path', new Downloader\PathDownloader($io, $config, $eventDispatcher, $cache, $rfs));
20667
20668 return $dm;
20669 }
20670
20671
20672
20673
20674
20675
20676 public function createArchiveManager(Config $config, Downloader\DownloadManager $dm = null)
20677 {
20678 if (null === $dm) {
20679 $io = new IO\NullIO();
20680 $io->loadConfiguration($config);
20681 $dm = $this->createDownloadManager($io, $config);
20682 }
20683
20684 $am = new Archiver\ArchiveManager($dm);
20685 $am->addArchiver(new Archiver\ZipArchiver);
20686 $am->addArchiver(new Archiver\PharArchiver);
20687
20688 return $am;
20689 }
20690
20691
20692
20693
20694
20695
20696
20697
20698 protected function createPluginManager(IOInterface $io, Composer $composer, Composer $globalComposer = null, $disablePlugins = false)
20699 {
20700 return new Plugin\PluginManager($io, $composer, $globalComposer, $disablePlugins);
20701 }
20702
20703
20704
20705
20706 protected function createInstallationManager()
20707 {
20708 return new Installer\InstallationManager();
20709 }
20710
20711
20712
20713
20714
20715
20716 protected function createDefaultInstallers(Installer\InstallationManager $im, Composer $composer, IOInterface $io)
20717 {
20718 $im->addInstaller(new Installer\LibraryInstaller($io, $composer, null));
20719 $im->addInstaller(new Installer\PearInstaller($io, $composer, 'pear-library'));
20720 $im->addInstaller(new Installer\PluginInstaller($io, $composer));
20721 $im->addInstaller(new Installer\MetapackageInstaller($io));
20722 }
20723
20724
20725
20726
20727
20728 protected function purgePackages(WritableRepositoryInterface $repo, Installer\InstallationManager $im)
20729 {
20730 foreach ($repo->getPackages() as $package) {
20731 if (!$im->isPackageInstalled($repo, $package)) {
20732 $repo->removePackage($package);
20733 }
20734 }
20735 }
20736
20737
20738
20739
20740
20741
20742
20743
20744 public static function create(IOInterface $io, $config = null, $disablePlugins = false)
20745 {
20746 $factory = new static();
20747
20748 return $factory->createComposer($io, $config, $disablePlugins);
20749 }
20750
20751
20752
20753
20754
20755
20756
20757 public static function createRemoteFilesystem(IOInterface $io, Config $config = null, $options = array())
20758 {
20759 static $warned = false;
20760 $disableTls = false;
20761
20762 if (isset($_SERVER['argv']) && in_array('disable-tls', $_SERVER['argv']) && (in_array('conf', $_SERVER['argv']) || in_array('config', $_SERVER['argv']))) {
20763 $warned = true;
20764 $disableTls = !extension_loaded('openssl');
20765 } elseif ($config && $config->get('disable-tls') === true) {
20766 if (!$warned) {
20767 $io->writeError('<warning>You are running Composer with SSL/TLS protection disabled.</warning>');
20768 }
20769 $warned = true;
20770 $disableTls = true;
20771 } elseif (!extension_loaded('openssl')) {
20772 throw new Exception\NoSslException('The openssl extension is required for SSL/TLS protection but is not available. '
20773 . 'If you can not enable the openssl extension, you can disable this error, at your own risk, by setting the \'disable-tls\' option to true.');
20774 }
20775 $remoteFilesystemOptions = array();
20776 if ($disableTls === false) {
20777 if ($config && $config->get('cafile')) {
20778 $remoteFilesystemOptions['ssl']['cafile'] = $config->get('cafile');
20779 }
20780 if ($config && $config->get('capath')) {
20781 $remoteFilesystemOptions['ssl']['capath'] = $config->get('capath');
20782 }
20783 $remoteFilesystemOptions = array_replace_recursive($remoteFilesystemOptions, $options);
20784 }
20785 try {
20786 $remoteFilesystem = new RemoteFilesystem($io, $config, $remoteFilesystemOptions, $disableTls);
20787 } catch (TransportException $e) {
20788 if (false !== strpos($e->getMessage(), 'cafile')) {
20789 $io->write('<error>Unable to locate a valid CA certificate file. You must set a valid \'cafile\' option.</error>');
20790 $io->write('<error>A valid CA certificate file is required for SSL/TLS protection.</error>');
20791 if (PHP_VERSION_ID < 50600) {
20792 $io->write('<error>It is recommended you upgrade to PHP 5.6+ which can detect your system CA file automatically.</error>');
20793 }
20794 $io->write('<error>You can disable this error, at your own risk, by setting the \'disable-tls\' option to true.</error>');
20795 }
20796 throw $e;
20797 }
20798
20799 return $remoteFilesystem;
20800 }
20801
20802
20803
20804
20805 private static function useXdg()
20806 {
20807 foreach (array_keys($_SERVER) as $key) {
20808 if (substr($key, 0, 4) === 'XDG_') {
20809 return true;
20810 }
20811 }
20812
20813 return false;
20814 }
20815
20816
20817
20818
20819
20820 private static function getUserDir()
20821 {
20822 $home = getenv('HOME');
20823 if (!$home) {
20824 throw new \RuntimeException('The HOME or COMPOSER_HOME environment variable must be set for composer to run correctly');
20825 }
20826
20827 return rtrim(strtr($home, '\\', '/'), '/');
20828 }
20829 }
20830 <?php
20831
20832
20833
20834
20835
20836
20837
20838
20839
20840
20841
20842 namespace Composer\IO;
20843
20844 use Composer\Config;
20845 use Composer\Util\ProcessExecutor;
20846 use Psr\Log\LoggerInterface;
20847 use Psr\Log\LogLevel;
20848
20849 abstract class BaseIO implements IOInterface, LoggerInterface
20850 {
20851 protected $authentications = array();
20852
20853
20854
20855
20856 public function getAuthentications()
20857 {
20858 return $this->authentications;
20859 }
20860
20861
20862
20863
20864 public function resetAuthentications()
20865 {
20866 $this->authentications = array();
20867 }
20868
20869
20870
20871
20872 public function hasAuthentication($repositoryName)
20873 {
20874 return isset($this->authentications[$repositoryName]);
20875 }
20876
20877
20878
20879
20880 public function getAuthentication($repositoryName)
20881 {
20882 if (isset($this->authentications[$repositoryName])) {
20883 return $this->authentications[$repositoryName];
20884 }
20885
20886 return array('username' => null, 'password' => null);
20887 }
20888
20889
20890
20891
20892 public function setAuthentication($repositoryName, $username, $password = null)
20893 {
20894 $this->authentications[$repositoryName] = array('username' => $username, 'password' => $password);
20895 }
20896
20897
20898
20899
20900 public function writeRaw($messages, $newline = true, $verbosity = self::NORMAL)
20901 {
20902 $this->write($messages, $newline, $verbosity);
20903 }
20904
20905
20906
20907
20908 public function writeErrorRaw($messages, $newline = true, $verbosity = self::NORMAL)
20909 {
20910 $this->writeError($messages, $newline, $verbosity);
20911 }
20912
20913
20914
20915
20916
20917
20918
20919
20920 protected function checkAndSetAuthentication($repositoryName, $username, $password = null)
20921 {
20922 if ($this->hasAuthentication($repositoryName)) {
20923 $auth = $this->getAuthentication($repositoryName);
20924 if ($auth['username'] === $username && $auth['password'] === $password) {
20925 return;
20926 }
20927
20928 $this->writeError(
20929 sprintf(
20930 "<warning>Warning: You should avoid overwriting already defined auth settings for %s.</warning>",
20931 $repositoryName
20932 )
20933 );
20934 }
20935 $this->setAuthentication($repositoryName, $username, $password);
20936 }
20937
20938
20939
20940
20941 public function loadConfiguration(Config $config)
20942 {
20943 $bitbucketOauth = $config->get('bitbucket-oauth') ?: array();
20944 $githubOauth = $config->get('github-oauth') ?: array();
20945 $gitlabOauth = $config->get('gitlab-oauth') ?: array();
20946 $gitlabToken = $config->get('gitlab-token') ?: array();
20947 $httpBasic = $config->get('http-basic') ?: array();
20948 $bearerToken = $config->get('bearer') ?: array();
20949
20950
20951
20952 foreach ($bitbucketOauth as $domain => $cred) {
20953 $this->checkAndSetAuthentication($domain, $cred['consumer-key'], $cred['consumer-secret']);
20954 }
20955
20956 foreach ($githubOauth as $domain => $token) {
20957 if (!preg_match('{^[.a-z0-9]+$}', $token)) {
20958 throw new \UnexpectedValueException('Your github oauth token for '.$domain.' contains invalid characters: "'.$token.'"');
20959 }
20960 $this->checkAndSetAuthentication($domain, $token, 'x-oauth-basic');
20961 }
20962
20963 foreach ($gitlabOauth as $domain => $token) {
20964 $this->checkAndSetAuthentication($domain, $token, 'oauth2');
20965 }
20966
20967 foreach ($gitlabToken as $domain => $token) {
20968 $this->checkAndSetAuthentication($domain, $token, 'private-token');
20969 }
20970
20971
20972 foreach ($httpBasic as $domain => $cred) {
20973 $this->checkAndSetAuthentication($domain, $cred['username'], $cred['password']);
20974 }
20975
20976 foreach ($bearerToken as $domain => $token) {
20977 $this->checkAndSetAuthentication($domain, $token, 'bearer');
20978 }
20979
20980
20981 ProcessExecutor::setTimeout((int) $config->get('process-timeout'));
20982 }
20983
20984
20985
20986
20987
20988
20989
20990
20991 public function emergency($message, array $context = array())
20992 {
20993 return $this->log(LogLevel::EMERGENCY, $message, $context);
20994 }
20995
20996
20997
20998
20999
21000
21001
21002
21003
21004
21005
21006 public function alert($message, array $context = array())
21007 {
21008 return $this->log(LogLevel::ALERT, $message, $context);
21009 }
21010
21011
21012
21013
21014
21015
21016
21017
21018
21019
21020 public function critical($message, array $context = array())
21021 {
21022 return $this->log(LogLevel::CRITICAL, $message, $context);
21023 }
21024
21025
21026
21027
21028
21029
21030
21031
21032
21033 public function error($message, array $context = array())
21034 {
21035 return $this->log(LogLevel::ERROR, $message, $context);
21036 }
21037
21038
21039
21040
21041
21042
21043
21044
21045
21046
21047
21048 public function warning($message, array $context = array())
21049 {
21050 return $this->log(LogLevel::WARNING, $message, $context);
21051 }
21052
21053
21054
21055
21056
21057
21058
21059
21060 public function notice($message, array $context = array())
21061 {
21062 return $this->log(LogLevel::NOTICE, $message, $context);
21063 }
21064
21065
21066
21067
21068
21069
21070
21071
21072
21073
21074 public function info($message, array $context = array())
21075 {
21076 return $this->log(LogLevel::INFO, $message, $context);
21077 }
21078
21079
21080
21081
21082
21083
21084
21085
21086 public function debug($message, array $context = array())
21087 {
21088 return $this->log(LogLevel::DEBUG, $message, $context);
21089 }
21090
21091
21092
21093
21094
21095
21096
21097
21098
21099 public function log($level, $message, array $context = array())
21100 {
21101 if (in_array($level, array(LogLevel::EMERGENCY, LogLevel::ALERT, LogLevel::CRITICAL, LogLevel::ERROR))) {
21102 $this->writeError('<error>'.$message.'</error>', true, self::NORMAL);
21103 } elseif ($level === LogLevel::WARNING) {
21104 $this->writeError('<warning>'.$message.'</warning>', true, self::NORMAL);
21105 } elseif ($level === LogLevel::NOTICE) {
21106 $this->writeError('<info>'.$message.'</info>', true, self::VERBOSE);
21107 } elseif ($level === LogLevel::INFO) {
21108 $this->writeError('<info>'.$message.'</info>', true, self::VERY_VERBOSE);
21109 } else {
21110 $this->writeError($message, true, self::DEBUG);
21111 }
21112 }
21113 }
21114 <?php
21115
21116
21117
21118
21119
21120
21121
21122
21123
21124
21125
21126 namespace Composer\IO;
21127
21128 use Symfony\Component\Console\Helper\QuestionHelper;
21129 use Symfony\Component\Console\Output\StreamOutput;
21130 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
21131 use Symfony\Component\Console\Input\StreamableInputInterface;
21132 use Symfony\Component\Console\Input\StringInput;
21133 use Symfony\Component\Console\Helper\HelperSet;
21134
21135
21136
21137
21138 class BufferIO extends ConsoleIO
21139 {
21140
21141
21142
21143
21144
21145 public function __construct($input = '', $verbosity = StreamOutput::VERBOSITY_NORMAL, OutputFormatterInterface $formatter = null)
21146 {
21147 $input = new StringInput($input);
21148 $input->setInteractive(false);
21149
21150 $output = new StreamOutput(fopen('php://memory', 'rw'), $verbosity, $formatter ? $formatter->isDecorated() : false, $formatter);
21151
21152 parent::__construct($input, $output, new HelperSet(array(
21153 new QuestionHelper(),
21154 )));
21155 }
21156
21157 public function getOutput()
21158 {
21159 fseek($this->output->getStream(), 0);
21160
21161 $output = stream_get_contents($this->output->getStream());
21162
21163 $output = preg_replace_callback("{(?<=^|\n|\x08)(.+?)(\x08+)}", function ($matches) {
21164 $pre = strip_tags($matches[1]);
21165
21166 if (strlen($pre) === strlen($matches[2])) {
21167 return '';
21168 }
21169
21170
21171 return rtrim($matches[1])."\n";
21172 }, $output);
21173
21174 return $output;
21175 }
21176
21177 public function setUserInputs(array $inputs)
21178 {
21179 if (!$this->input instanceof StreamableInputInterface) {
21180 throw new \RuntimeException('Setting the user inputs requires at least the version 3.2 of the symfony/console component.');
21181 }
21182
21183 $this->input->setStream($this->createStream($inputs));
21184 $this->input->setInteractive(true);
21185 }
21186
21187 private function createStream(array $inputs)
21188 {
21189 $stream = fopen('php://memory', 'r+', false);
21190
21191 foreach ($inputs as $input) {
21192 fwrite($stream, $input.PHP_EOL);
21193 }
21194
21195 rewind($stream);
21196
21197 return $stream;
21198 }
21199 }
21200 <?php
21201
21202
21203
21204
21205
21206
21207
21208
21209
21210
21211
21212 namespace Composer\IO;
21213
21214 use Composer\Question\StrictConfirmationQuestion;
21215 use Symfony\Component\Console\Helper\HelperSet;
21216 use Symfony\Component\Console\Input\InputInterface;
21217 use Symfony\Component\Console\Output\ConsoleOutputInterface;
21218 use Symfony\Component\Console\Output\OutputInterface;
21219 use Symfony\Component\Console\Question\ChoiceQuestion;
21220 use Symfony\Component\Console\Question\Question;
21221
21222
21223
21224
21225
21226
21227
21228 class ConsoleIO extends BaseIO
21229 {
21230
21231 protected $input;
21232
21233 protected $output;
21234
21235 protected $helperSet;
21236
21237 protected $lastMessage;
21238
21239 protected $lastMessageErr;
21240
21241
21242 private $startTime;
21243
21244 private $verbosityMap;
21245
21246
21247
21248
21249
21250
21251
21252
21253 public function __construct(InputInterface $input, OutputInterface $output, HelperSet $helperSet)
21254 {
21255 $this->input = $input;
21256 $this->output = $output;
21257 $this->helperSet = $helperSet;
21258 $this->verbosityMap = array(
21259 self::QUIET => OutputInterface::VERBOSITY_QUIET,
21260 self::NORMAL => OutputInterface::VERBOSITY_NORMAL,
21261 self::VERBOSE => OutputInterface::VERBOSITY_VERBOSE,
21262 self::VERY_VERBOSE => OutputInterface::VERBOSITY_VERY_VERBOSE,
21263 self::DEBUG => OutputInterface::VERBOSITY_DEBUG,
21264 );
21265 }
21266
21267
21268
21269
21270 public function enableDebugging($startTime)
21271 {
21272 $this->startTime = $startTime;
21273 }
21274
21275
21276
21277
21278 public function isInteractive()
21279 {
21280 return $this->input->isInteractive();
21281 }
21282
21283
21284
21285
21286 public function isDecorated()
21287 {
21288 return $this->output->isDecorated();
21289 }
21290
21291
21292
21293
21294 public function isVerbose()
21295 {
21296 return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE;
21297 }
21298
21299
21300
21301
21302 public function isVeryVerbose()
21303 {
21304 return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE;
21305 }
21306
21307
21308
21309
21310 public function isDebug()
21311 {
21312 return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_DEBUG;
21313 }
21314
21315
21316
21317
21318 public function write($messages, $newline = true, $verbosity = self::NORMAL)
21319 {
21320 $this->doWrite($messages, $newline, false, $verbosity);
21321 }
21322
21323
21324
21325
21326 public function writeError($messages, $newline = true, $verbosity = self::NORMAL)
21327 {
21328 $this->doWrite($messages, $newline, true, $verbosity);
21329 }
21330
21331
21332
21333
21334 public function writeRaw($messages, $newline = true, $verbosity = self::NORMAL)
21335 {
21336 $this->doWrite($messages, $newline, false, $verbosity, true);
21337 }
21338
21339
21340
21341
21342 public function writeErrorRaw($messages, $newline = true, $verbosity = self::NORMAL)
21343 {
21344 $this->doWrite($messages, $newline, true, $verbosity, true);
21345 }
21346
21347
21348
21349
21350
21351
21352
21353 private function doWrite($messages, $newline, $stderr, $verbosity, $raw = false)
21354 {
21355 $sfVerbosity = $this->verbosityMap[$verbosity];
21356 if ($sfVerbosity > $this->output->getVerbosity()) {
21357 return;
21358 }
21359
21360
21361
21362
21363 if (OutputInterface::VERBOSITY_QUIET === 0) {
21364 $sfVerbosity = OutputInterface::OUTPUT_NORMAL;
21365 }
21366
21367 if ($raw) {
21368 if ($sfVerbosity === OutputInterface::OUTPUT_NORMAL) {
21369 $sfVerbosity = OutputInterface::OUTPUT_RAW;
21370 } else {
21371 $sfVerbosity |= OutputInterface::OUTPUT_RAW;
21372 }
21373 }
21374
21375 if (null !== $this->startTime) {
21376 $memoryUsage = memory_get_usage() / 1024 / 1024;
21377 $timeSpent = microtime(true) - $this->startTime;
21378 $messages = array_map(function ($message) use ($memoryUsage, $timeSpent) {
21379 return sprintf('[%.1fMiB/%.2fs] %s', $memoryUsage, $timeSpent, $message);
21380 }, (array) $messages);
21381 }
21382
21383 if (true === $stderr && $this->output instanceof ConsoleOutputInterface) {
21384 $this->output->getErrorOutput()->write($messages, $newline, $sfVerbosity);
21385 $this->lastMessageErr = implode($newline ? "\n" : '', (array) $messages);
21386
21387 return;
21388 }
21389
21390 $this->output->write($messages, $newline, $sfVerbosity);
21391 $this->lastMessage = implode($newline ? "\n" : '', (array) $messages);
21392 }
21393
21394
21395
21396
21397 public function overwrite($messages, $newline = true, $size = null, $verbosity = self::NORMAL)
21398 {
21399 $this->doOverwrite($messages, $newline, $size, false, $verbosity);
21400 }
21401
21402
21403
21404
21405 public function overwriteError($messages, $newline = true, $size = null, $verbosity = self::NORMAL)
21406 {
21407 $this->doOverwrite($messages, $newline, $size, true, $verbosity);
21408 }
21409
21410
21411
21412
21413
21414
21415
21416
21417 private function doOverwrite($messages, $newline, $size, $stderr, $verbosity)
21418 {
21419
21420 $messages = implode($newline ? "\n" : '', (array) $messages);
21421
21422
21423 if (!isset($size)) {
21424
21425 $size = strlen(strip_tags($stderr ? $this->lastMessageErr : $this->lastMessage));
21426 }
21427
21428 $this->doWrite(str_repeat("\x08", $size), false, $stderr, $verbosity);
21429
21430
21431 $this->doWrite($messages, false, $stderr, $verbosity);
21432
21433
21434
21435
21436 $fill = $size - strlen(strip_tags($messages));
21437 if ($fill > 0) {
21438
21439 $this->doWrite(str_repeat(' ', $fill), false, $stderr, $verbosity);
21440
21441 $this->doWrite(str_repeat("\x08", $fill), false, $stderr, $verbosity);
21442 }
21443
21444 if ($newline) {
21445 $this->doWrite('', true, $stderr, $verbosity);
21446 }
21447
21448 if ($stderr) {
21449 $this->lastMessageErr = $messages;
21450 } else {
21451 $this->lastMessage = $messages;
21452 }
21453 }
21454
21455
21456
21457
21458 public function ask($question, $default = null)
21459 {
21460
21461 $helper = $this->helperSet->get('question');
21462 $question = new Question($question, $default);
21463
21464 return $helper->ask($this->input, $this->getErrorOutput(), $question);
21465 }
21466
21467
21468
21469
21470 public function askConfirmation($question, $default = true)
21471 {
21472
21473 $helper = $this->helperSet->get('question');
21474 $question = new StrictConfirmationQuestion($question, $default);
21475
21476 return $helper->ask($this->input, $this->getErrorOutput(), $question);
21477 }
21478
21479
21480
21481
21482 public function askAndValidate($question, $validator, $attempts = null, $default = null)
21483 {
21484
21485 $helper = $this->helperSet->get('question');
21486 $question = new Question($question, $default);
21487 $question->setValidator($validator);
21488 $question->setMaxAttempts($attempts);
21489
21490 return $helper->ask($this->input, $this->getErrorOutput(), $question);
21491 }
21492
21493
21494
21495
21496 public function askAndHideAnswer($question)
21497 {
21498
21499 $helper = $this->helperSet->get('question');
21500 $question = new Question($question);
21501 $question->setHidden(true);
21502
21503 return $helper->ask($this->input, $this->getErrorOutput(), $question);
21504 }
21505
21506
21507
21508
21509 public function select($question, $choices, $default, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false)
21510 {
21511
21512 $helper = $this->helperSet->get('question');
21513 $question = new ChoiceQuestion($question, $choices, $default);
21514 $question->setMaxAttempts($attempts ?: null); 
21515 $question->setErrorMessage($errorMessage);
21516 $question->setMultiselect($multiselect);
21517
21518 $result = $helper->ask($this->input, $this->getErrorOutput(), $question);
21519
21520 if (!is_array($result)) {
21521 return (string) array_search($result, $choices, true);
21522 }
21523
21524 $results = array();
21525 foreach ($choices as $index => $choice) {
21526 if (in_array($choice, $result, true)) {
21527 $results[] = (string) $index;
21528 }
21529 }
21530
21531 return $results;
21532 }
21533
21534
21535
21536
21537 private function getErrorOutput()
21538 {
21539 if ($this->output instanceof ConsoleOutputInterface) {
21540 return $this->output->getErrorOutput();
21541 }
21542
21543 return $this->output;
21544 }
21545 }
21546 <?php
21547
21548
21549
21550
21551
21552
21553
21554
21555
21556
21557
21558 namespace Composer\IO;
21559
21560 use Composer\Config;
21561
21562
21563
21564
21565
21566
21567 interface IOInterface
21568 {
21569 const QUIET = 1;
21570 const NORMAL = 2;
21571 const VERBOSE = 4;
21572 const VERY_VERBOSE = 8;
21573 const DEBUG = 16;
21574
21575
21576
21577
21578
21579
21580 public function isInteractive();
21581
21582
21583
21584
21585
21586
21587 public function isVerbose();
21588
21589
21590
21591
21592
21593
21594 public function isVeryVerbose();
21595
21596
21597
21598
21599
21600
21601 public function isDebug();
21602
21603
21604
21605
21606
21607
21608 public function isDecorated();
21609
21610
21611
21612
21613
21614
21615
21616
21617 public function write($messages, $newline = true, $verbosity = self::NORMAL);
21618
21619
21620
21621
21622
21623
21624
21625
21626 public function writeError($messages, $newline = true, $verbosity = self::NORMAL);
21627
21628
21629
21630
21631
21632
21633
21634
21635
21636 public function overwrite($messages, $newline = true, $size = null, $verbosity = self::NORMAL);
21637
21638
21639
21640
21641
21642
21643
21644
21645
21646 public function overwriteError($messages, $newline = true, $size = null, $verbosity = self::NORMAL);
21647
21648
21649
21650
21651
21652
21653
21654
21655
21656
21657 public function ask($question, $default = null);
21658
21659
21660
21661
21662
21663
21664
21665
21666
21667
21668
21669 public function askConfirmation($question, $default = true);
21670
21671
21672
21673
21674
21675
21676
21677
21678
21679
21680
21681
21682
21683
21684
21685
21686 public function askAndValidate($question, $validator, $attempts = null, $default = null);
21687
21688
21689
21690
21691
21692
21693
21694
21695 public function askAndHideAnswer($question);
21696
21697
21698
21699
21700
21701
21702
21703
21704
21705
21706
21707
21708
21709
21710 public function select($question, $choices, $default, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false);
21711
21712
21713
21714
21715
21716
21717 public function getAuthentications();
21718
21719
21720
21721
21722
21723
21724
21725
21726 public function hasAuthentication($repositoryName);
21727
21728
21729
21730
21731
21732
21733
21734
21735 public function getAuthentication($repositoryName);
21736
21737
21738
21739
21740
21741
21742
21743
21744 public function setAuthentication($repositoryName, $username, $password = null);
21745
21746
21747
21748
21749
21750
21751 public function loadConfiguration(Config $config);
21752 }
21753 <?php
21754
21755
21756
21757
21758
21759
21760
21761
21762
21763
21764
21765 namespace Composer\IO;
21766
21767
21768
21769
21770
21771
21772 class NullIO extends BaseIO
21773 {
21774
21775
21776
21777 public function isInteractive()
21778 {
21779 return false;
21780 }
21781
21782
21783
21784
21785 public function isVerbose()
21786 {
21787 return false;
21788 }
21789
21790
21791
21792
21793 public function isVeryVerbose()
21794 {
21795 return false;
21796 }
21797
21798
21799
21800
21801 public function isDebug()
21802 {
21803 return false;
21804 }
21805
21806
21807
21808
21809 public function isDecorated()
21810 {
21811 return false;
21812 }
21813
21814
21815
21816
21817 public function write($messages, $newline = true, $verbosity = self::NORMAL)
21818 {
21819 }
21820
21821
21822
21823
21824 public function writeError($messages, $newline = true, $verbosity = self::NORMAL)
21825 {
21826 }
21827
21828
21829
21830
21831 public function overwrite($messages, $newline = true, $size = 80, $verbosity = self::NORMAL)
21832 {
21833 }
21834
21835
21836
21837
21838 public function overwriteError($messages, $newline = true, $size = 80, $verbosity = self::NORMAL)
21839 {
21840 }
21841
21842
21843
21844
21845 public function ask($question, $default = null)
21846 {
21847 return $default;
21848 }
21849
21850
21851
21852
21853 public function askConfirmation($question, $default = true)
21854 {
21855 return $default;
21856 }
21857
21858
21859
21860
21861 public function askAndValidate($question, $validator, $attempts = false, $default = null)
21862 {
21863 return $default;
21864 }
21865
21866
21867
21868
21869 public function askAndHideAnswer($question)
21870 {
21871 return null;
21872 }
21873
21874
21875
21876
21877 public function select($question, $choices, $default, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false)
21878 {
21879 return $default;
21880 }
21881 }
21882 <?php
21883
21884
21885
21886
21887
21888
21889
21890
21891
21892
21893
21894 namespace Composer;
21895
21896 use Composer\Autoload\AutoloadGenerator;
21897 use Composer\DependencyResolver\DefaultPolicy;
21898 use Composer\DependencyResolver\Operation\UpdateOperation;
21899 use Composer\DependencyResolver\Operation\InstallOperation;
21900 use Composer\DependencyResolver\Operation\UninstallOperation;
21901 use Composer\DependencyResolver\Operation\MarkAliasUninstalledOperation;
21902 use Composer\DependencyResolver\Operation\OperationInterface;
21903 use Composer\DependencyResolver\PolicyInterface;
21904 use Composer\DependencyResolver\Pool;
21905 use Composer\DependencyResolver\Request;
21906 use Composer\DependencyResolver\Rule;
21907 use Composer\DependencyResolver\Solver;
21908 use Composer\DependencyResolver\SolverProblemsException;
21909 use Composer\Downloader\DownloadManager;
21910 use Composer\EventDispatcher\EventDispatcher;
21911 use Composer\Installer\InstallationManager;
21912 use Composer\Installer\InstallerEvents;
21913 use Composer\Installer\NoopInstaller;
21914 use Composer\Installer\SuggestedPackagesReporter;
21915 use Composer\IO\IOInterface;
21916 use Composer\Package\AliasPackage;
21917 use Composer\Package\BasePackage;
21918 use Composer\Package\CompletePackage;
21919 use Composer\Package\CompletePackageInterface;
21920 use Composer\Package\Link;
21921 use Composer\Package\Loader\ArrayLoader;
21922 use Composer\Package\Dumper\ArrayDumper;
21923 use Composer\Semver\Constraint\Constraint;
21924 use Composer\Package\Locker;
21925 use Composer\Package\PackageInterface;
21926 use Composer\Package\RootPackageInterface;
21927 use Composer\Repository\CompositeRepository;
21928 use Composer\Repository\InstalledArrayRepository;
21929 use Composer\Repository\PlatformRepository;
21930 use Composer\Repository\RepositoryInterface;
21931 use Composer\Repository\RepositoryManager;
21932 use Composer\Repository\WritableRepositoryInterface;
21933 use Composer\Script\ScriptEvents;
21934
21935
21936
21937
21938
21939
21940
21941 class Installer
21942 {
21943
21944
21945
21946 protected $io;
21947
21948
21949
21950
21951 protected $config;
21952
21953
21954
21955
21956 protected $package;
21957
21958
21959
21960
21961 protected $downloadManager;
21962
21963
21964
21965
21966 protected $repositoryManager;
21967
21968
21969
21970
21971 protected $locker;
21972
21973
21974
21975
21976 protected $installationManager;
21977
21978
21979
21980
21981 protected $eventDispatcher;
21982
21983
21984
21985
21986 protected $autoloadGenerator;
21987
21988 protected $preferSource = false;
21989 protected $preferDist = false;
21990 protected $optimizeAutoloader = false;
21991 protected $classMapAuthoritative = false;
21992 protected $apcuAutoloader = false;
21993 protected $devMode = false;
21994 protected $dryRun = false;
21995 protected $verbose = false;
21996 protected $update = false;
21997 protected $dumpAutoloader = true;
21998 protected $runScripts = true;
21999 protected $ignorePlatformReqs = false;
22000 protected $preferStable = false;
22001 protected $preferLowest = false;
22002 protected $skipSuggest = false;
22003 protected $writeLock;
22004 protected $executeOperations = true;
22005
22006
22007
22008
22009
22010
22011 protected $updateWhitelist = null; 
22012 protected $whitelistDependencies = false; 
22013 protected $whitelistAllDependencies = false; 
22014
22015
22016
22017
22018 protected $suggestedPackagesReporter;
22019
22020
22021
22022
22023 protected $additionalInstalledRepository;
22024
22025
22026
22027
22028
22029
22030
22031
22032
22033
22034
22035
22036
22037
22038 public function __construct(IOInterface $io, Config $config, RootPackageInterface $package, DownloadManager $downloadManager, RepositoryManager $repositoryManager, Locker $locker, InstallationManager $installationManager, EventDispatcher $eventDispatcher, AutoloadGenerator $autoloadGenerator)
22039 {
22040 $this->io = $io;
22041 $this->config = $config;
22042 $this->package = $package;
22043 $this->downloadManager = $downloadManager;
22044 $this->repositoryManager = $repositoryManager;
22045 $this->locker = $locker;
22046 $this->installationManager = $installationManager;
22047 $this->eventDispatcher = $eventDispatcher;
22048 $this->autoloadGenerator = $autoloadGenerator;
22049
22050 $this->writeLock = $config->get('lock');
22051 }
22052
22053
22054
22055
22056
22057
22058
22059 public function run()
22060 {
22061
22062
22063
22064
22065 gc_collect_cycles();
22066 gc_disable();
22067
22068
22069 if (!$this->update && !$this->locker->isLocked()) {
22070 $this->update = true;
22071 }
22072
22073 if ($this->dryRun) {
22074 $this->verbose = true;
22075 $this->runScripts = false;
22076 $this->executeOperations = false;
22077 $this->writeLock = false;
22078 $this->dumpAutoloader = false;
22079 $this->installationManager->addInstaller(new NoopInstaller);
22080 $this->mockLocalRepositories($this->repositoryManager);
22081 }
22082
22083 if ($this->runScripts) {
22084 $_SERVER['COMPOSER_DEV_MODE'] = $this->devMode ? '1' : '0';
22085 putenv('COMPOSER_DEV_MODE='.$_SERVER['COMPOSER_DEV_MODE']);
22086
22087
22088 $eventName = $this->update ? ScriptEvents::PRE_UPDATE_CMD : ScriptEvents::PRE_INSTALL_CMD;
22089 $this->eventDispatcher->dispatchScript($eventName, $this->devMode);
22090 }
22091
22092 $this->downloadManager->setPreferSource($this->preferSource);
22093 $this->downloadManager->setPreferDist($this->preferDist);
22094
22095
22096 $localRepo = $this->repositoryManager->getLocalRepository();
22097 if ($this->update) {
22098 $platformOverrides = $this->config->get('platform') ?: array();
22099 } else {
22100 $platformOverrides = $this->locker->getPlatformOverrides();
22101 }
22102 $platformRepo = new PlatformRepository(array(), $platformOverrides);
22103 $installedRepo = $this->createInstalledRepo($localRepo, $platformRepo);
22104
22105 $aliases = $this->getRootAliases();
22106 $this->aliasPlatformPackages($platformRepo, $aliases);
22107
22108 if (!$this->suggestedPackagesReporter) {
22109 $this->suggestedPackagesReporter = new SuggestedPackagesReporter($this->io);
22110 }
22111
22112 try {
22113 list($res, $devPackages) = $this->doInstall($localRepo, $installedRepo, $platformRepo, $aliases);
22114 if ($res !== 0) {
22115 return $res;
22116 }
22117 } catch (\Exception $e) {
22118 if ($this->executeOperations && $this->config->get('notify-on-install')) {
22119 $this->installationManager->notifyInstalls($this->io);
22120 }
22121
22122 throw $e;
22123 }
22124 if ($this->executeOperations && $this->config->get('notify-on-install')) {
22125 $this->installationManager->notifyInstalls($this->io);
22126 }
22127
22128
22129 if ($this->devMode && !$this->skipSuggest) {
22130 $this->suggestedPackagesReporter->output($installedRepo);
22131 }
22132
22133
22134 foreach ($localRepo->getPackages() as $package) {
22135 if (!$package instanceof CompletePackage || !$package->isAbandoned()) {
22136 continue;
22137 }
22138
22139 $replacement = is_string($package->getReplacementPackage())
22140 ? 'Use ' . $package->getReplacementPackage() . ' instead'
22141 : 'No replacement was suggested';
22142
22143 $this->io->writeError(
22144 sprintf(
22145 "<warning>Package %s is abandoned, you should avoid using it. %s.</warning>",
22146 $package->getPrettyName(),
22147 $replacement
22148 )
22149 );
22150 }
22151
22152
22153 if ($this->update && $this->writeLock) {
22154 $localRepo->reload();
22155
22156 $platformReqs = $this->extractPlatformRequirements($this->package->getRequires());
22157 $platformDevReqs = $this->extractPlatformRequirements($this->package->getDevRequires());
22158
22159 $updatedLock = $this->locker->setLockData(
22160 array_diff($localRepo->getCanonicalPackages(), $devPackages),
22161 $devPackages,
22162 $platformReqs,
22163 $platformDevReqs,
22164 $aliases,
22165 $this->package->getMinimumStability(),
22166 $this->package->getStabilityFlags(),
22167 $this->preferStable || $this->package->getPreferStable(),
22168 $this->preferLowest,
22169 $this->config->get('platform') ?: array()
22170 );
22171 if ($updatedLock) {
22172 $this->io->writeError('<info>Writing lock file</info>');
22173 }
22174 }
22175
22176 if ($this->dumpAutoloader) {
22177
22178 if ($this->optimizeAutoloader) {
22179 $this->io->writeError('<info>Generating optimized autoload files</info>');
22180 } else {
22181 $this->io->writeError('<info>Generating autoload files</info>');
22182 }
22183
22184 $this->autoloadGenerator->setDevMode($this->devMode);
22185 $this->autoloadGenerator->setClassMapAuthoritative($this->classMapAuthoritative);
22186 $this->autoloadGenerator->setApcu($this->apcuAutoloader);
22187 $this->autoloadGenerator->setRunScripts($this->runScripts);
22188 $this->autoloadGenerator->dump($this->config, $localRepo, $this->package, $this->installationManager, 'composer', $this->optimizeAutoloader);
22189 }
22190
22191 if ($this->executeOperations) {
22192
22193 foreach ($localRepo->getPackages() as $package) {
22194 $this->installationManager->ensureBinariesPresence($package);
22195 }
22196 }
22197
22198 $fundingCount = 0;
22199 foreach ($localRepo->getPackages() as $package) {
22200 if ($package instanceof CompletePackageInterface && !$package instanceof AliasPackage && $package->getFunding()) {
22201 $fundingCount++;
22202 }
22203 }
22204 if ($fundingCount) {
22205 $this->io->writeError(array(
22206 sprintf(
22207 "<info>%d package%s you are using %s looking for funding.</info>",
22208 $fundingCount,
22209 1 === $fundingCount ? '' : 's',
22210 1 === $fundingCount ? 'is' : 'are'
22211 ),
22212 '<info>Use the `composer fund` command to find out more!</info>',
22213 ));
22214 }
22215
22216 if ($this->runScripts) {
22217
22218 $eventName = $this->update ? ScriptEvents::POST_UPDATE_CMD : ScriptEvents::POST_INSTALL_CMD;
22219 $this->eventDispatcher->dispatchScript($eventName, $this->devMode);
22220 }
22221
22222
22223 if (!defined('HHVM_VERSION')) {
22224 gc_enable();
22225 }
22226
22227 return 0;
22228 }
22229
22230
22231
22232
22233
22234
22235
22236
22237 protected function doInstall($localRepo, $installedRepo, $platformRepo, $aliases)
22238 {
22239
22240 $lockedRepository = null;
22241 $repositories = null;
22242
22243
22244
22245
22246 if (!$this->update || (!empty($this->updateWhitelist) && $this->locker->isLocked())) {
22247 try {
22248 $lockedRepository = $this->locker->getLockedRepository($this->devMode);
22249 } catch (\RuntimeException $e) {
22250
22251 if ($this->package->getDevRequires()) {
22252 throw $e;
22253 }
22254
22255 $lockedRepository = $this->locker->getLockedRepository();
22256 }
22257 }
22258
22259 $this->allowListUpdateDependencies(
22260 $lockedRepository ?: $localRepo,
22261 $this->package->getRequires(),
22262 $this->package->getDevRequires()
22263 );
22264
22265 $this->io->writeError('<info>Loading composer repositories with package information</info>');
22266
22267
22268 $policy = $this->createPolicy();
22269 $pool = $this->createPool($this->update ? null : $lockedRepository);
22270 $pool->addRepository($installedRepo, $aliases);
22271 if ($this->update) {
22272 $repositories = $this->repositoryManager->getRepositories();
22273 foreach ($repositories as $repository) {
22274 $pool->addRepository($repository, $aliases);
22275 }
22276 }
22277
22278
22279
22280 if ($lockedRepository) {
22281 $pool->addRepository($lockedRepository, $aliases);
22282 }
22283
22284
22285 $request = $this->createRequest($this->package, $platformRepo);
22286
22287 if ($this->update) {
22288
22289 $removedUnstablePackages = array();
22290 foreach ($localRepo->getPackages() as $package) {
22291 if (
22292 !$pool->isPackageAcceptable($package->getNames(), $package->getStability())
22293 && $this->installationManager->isPackageInstalled($localRepo, $package)
22294 ) {
22295 $removedUnstablePackages[$package->getName()] = true;
22296 $request->remove($package->getName(), new Constraint('=', $package->getVersion()));
22297 }
22298 }
22299
22300 $this->io->writeError('<info>Updating dependencies'.($this->devMode ? ' (including require-dev)' : '').'</info>');
22301
22302 $request->updateAll();
22303
22304 $links = array_merge($this->package->getRequires(), $this->package->getDevRequires());
22305
22306 foreach ($links as $link) {
22307 $request->install($link->getTarget(), $link->getConstraint());
22308 }
22309
22310
22311
22312 if ($this->updateWhitelist) {
22313 $currentPackages = $this->getCurrentPackages($installedRepo);
22314
22315
22316 $candidates = array();
22317 foreach ($links as $link) {
22318 $candidates[$link->getTarget()] = true;
22319 $rootRequires[$link->getTarget()] = $link;
22320 }
22321 foreach ($currentPackages as $package) {
22322 $candidates[$package->getName()] = true;
22323 }
22324
22325
22326 foreach ($candidates as $candidate => $dummy) {
22327 foreach ($currentPackages as $curPackage) {
22328 if ($curPackage->getName() === $candidate) {
22329 if (!$this->isUpdateable($curPackage) && !isset($removedUnstablePackages[$curPackage->getName()])) {
22330 $constraint = new Constraint('=', $curPackage->getVersion());
22331 $description = $this->locker->isLocked() ? '(locked at' : '(installed at';
22332 $requiredAt = isset($rootRequires[$candidate]) ? ', required as ' . $rootRequires[$candidate]->getPrettyConstraint() : '';
22333 $constraint->setPrettyString($description . ' ' . $curPackage->getPrettyVersion() . $requiredAt . ')');
22334 $request->install($curPackage->getName(), $constraint);
22335 }
22336 break;
22337 }
22338 }
22339 }
22340 }
22341 } else {
22342 $this->io->writeError('<info>Installing dependencies'.($this->devMode ? ' (including require-dev)' : '').' from lock file</info>');
22343
22344 if (!$this->locker->isFresh()) {
22345 $this->io->writeError('<warning>Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. It is recommended that you run `composer update` or `composer update <package name>`.</warning>', true, IOInterface::QUIET);
22346 }
22347
22348 foreach ($lockedRepository->getPackages() as $package) {
22349 $version = $package->getVersion();
22350 if (isset($aliases[$package->getName()][$version])) {
22351 $version = $aliases[$package->getName()][$version]['alias_normalized'];
22352 }
22353 $constraint = new Constraint('=', $version);
22354 $constraint->setPrettyString($package->getPrettyVersion());
22355 $request->install($package->getName(), $constraint);
22356 }
22357
22358 foreach ($this->locker->getPlatformRequirements($this->devMode) as $link) {
22359 $request->install($link->getTarget(), $link->getConstraint());
22360 }
22361 }
22362
22363
22364 $this->processDevPackages($localRepo, $pool, $policy, $repositories, $installedRepo, $lockedRepository, 'force-links');
22365
22366
22367 $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, $this->devMode, $policy, $pool, $installedRepo, $request);
22368 $solver = new Solver($policy, $pool, $installedRepo, $this->io);
22369 try {
22370 $operations = $solver->solve($request, $this->ignorePlatformReqs);
22371 $ruleSetSize = $solver->getRuleSetSize();
22372 $solver = null;
22373 } catch (SolverProblemsException $e) {
22374 $this->io->writeError('<error>Your requirements could not be resolved to an installable set of packages.</error>', true, IOInterface::QUIET);
22375 $this->io->writeError($e->getMessage());
22376 if ($this->update && !$this->devMode) {
22377 $this->io->writeError('<warning>Running update with --no-dev does not mean require-dev is ignored, it just means the packages will not be installed. If dev requirements are blocking the update you have to resolve those problems.</warning>', true, IOInterface::QUIET);
22378 }
22379
22380 return array(max(1, $e->getCode()), array());
22381 }
22382
22383
22384 $operations = $this->processDevPackages($localRepo, $pool, $policy, $repositories, $installedRepo, $lockedRepository, 'force-updates', $operations);
22385
22386 $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $this->devMode, $policy, $pool, $installedRepo, $request, $operations);
22387
22388 $this->io->writeError("Analyzed ".count($pool)." packages to resolve dependencies", true, IOInterface::VERBOSE);
22389 $this->io->writeError("Analyzed ".$ruleSetSize." rules to resolve dependencies", true, IOInterface::VERBOSE);
22390
22391
22392 if (!$operations) {
22393 $this->io->writeError('Nothing to install or update');
22394 }
22395
22396 $operations = $this->movePluginsToFront($operations);
22397 $operations = $this->moveUninstallsToFront($operations);
22398
22399
22400
22401 if ($this->update) {
22402 $devPackages = $this->extractDevPackages($operations, $localRepo, $platformRepo, $aliases);
22403 if (!$this->devMode) {
22404 $operations = $this->filterDevPackageOperations($devPackages, $operations, $localRepo);
22405 }
22406 } else {
22407 $devPackages = null;
22408 }
22409
22410 if ($operations) {
22411 $installs = $updates = $uninstalls = array();
22412 foreach ($operations as $operation) {
22413 if ($operation instanceof InstallOperation) {
22414 $installs[] = $operation->getPackage()->getPrettyName().':'.$operation->getPackage()->getFullPrettyVersion();
22415 } elseif ($operation instanceof UpdateOperation) {
22416 $updates[] = $operation->getTargetPackage()->getPrettyName().':'.$operation->getTargetPackage()->getFullPrettyVersion();
22417 } elseif ($operation instanceof UninstallOperation) {
22418 $uninstalls[] = $operation->getPackage()->getPrettyName();
22419 }
22420 }
22421
22422 $this->io->writeError(sprintf(
22423 "<info>Package operations: %d install%s, %d update%s, %d removal%s</info>",
22424 count($installs),
22425 1 === count($installs) ? '' : 's',
22426 count($updates),
22427 1 === count($updates) ? '' : 's',
22428 count($uninstalls),
22429 1 === count($uninstalls) ? '' : 's'
22430 ));
22431 if ($installs) {
22432 $this->io->writeError("Installs: ".implode(', ', $installs), true, IOInterface::VERBOSE);
22433 }
22434 if ($updates) {
22435 $this->io->writeError("Updates: ".implode(', ', $updates), true, IOInterface::VERBOSE);
22436 }
22437 if ($uninstalls) {
22438 $this->io->writeError("Removals: ".implode(', ', $uninstalls), true, IOInterface::VERBOSE);
22439 }
22440 }
22441
22442 foreach ($operations as $operation) {
22443
22444 $jobType = $operation->getJobType();
22445 if ('install' === $jobType) {
22446 $this->suggestedPackagesReporter->addSuggestionsFromPackage($operation->getPackage());
22447 }
22448
22449
22450 if ($this->update) {
22451 $package = null;
22452 if ('update' === $jobType) {
22453 $package = $operation->getTargetPackage();
22454 } elseif ('install' === $jobType) {
22455 $package = $operation->getPackage();
22456 }
22457 if ($package && $package->isDev()) {
22458 $references = $this->package->getReferences();
22459 if (isset($references[$package->getName()])) {
22460 $this->updateInstallReferences($package, $references[$package->getName()]);
22461 }
22462 }
22463 if ('update' === $jobType) {
22464 $targetPackage = $operation->getTargetPackage();
22465 if ($targetPackage->isDev()) {
22466 $initialPackage = $operation->getInitialPackage();
22467 if ($targetPackage->getVersion() === $initialPackage->getVersion()
22468 && (!$targetPackage->getSourceReference() || $targetPackage->getSourceReference() === $initialPackage->getSourceReference())
22469 && (!$targetPackage->getDistReference() || $targetPackage->getDistReference() === $initialPackage->getDistReference())
22470 ) {
22471 $this->io->writeError('  - Skipping update of ' . $targetPackage->getPrettyName() . ' to the same reference-locked version', true, IOInterface::DEBUG);
22472 $this->io->writeError('', true, IOInterface::DEBUG);
22473
22474 continue;
22475 }
22476 }
22477 }
22478 }
22479
22480 $event = 'Composer\Installer\PackageEvents::PRE_PACKAGE_'.strtoupper($jobType);
22481 if (defined($event) && $this->runScripts) {
22482 $this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $policy, $pool, $installedRepo, $request, $operations, $operation);
22483 }
22484
22485
22486 if (!$this->executeOperations && false === strpos($operation->getJobType(), 'Alias')) {
22487 $this->io->writeError('  - ' . $operation);
22488 } elseif ($this->io->isDebug() && false !== strpos($operation->getJobType(), 'Alias')) {
22489 $this->io->writeError('  - ' . $operation);
22490 }
22491
22492 $this->installationManager->execute($localRepo, $operation);
22493
22494
22495 if ($this->verbose && $this->io->isVeryVerbose() && in_array($jobType, array('install', 'update'))) {
22496 $reason = $operation->getReason();
22497 if ($reason instanceof Rule) {
22498 switch ($reason->getReason()) {
22499 case Rule::RULE_JOB_INSTALL:
22500 $this->io->writeError('    REASON: Required by the root package: '.$reason->getPrettyString($pool));
22501 $this->io->writeError('');
22502 break;
22503 case Rule::RULE_PACKAGE_REQUIRES:
22504 $this->io->writeError('    REASON: '.$reason->getPrettyString($pool));
22505 $this->io->writeError('');
22506 break;
22507 }
22508 }
22509 }
22510
22511 if ($this->executeOperations || $this->writeLock) {
22512 $localRepo->write();
22513 }
22514
22515 $event = 'Composer\Installer\PackageEvents::POST_PACKAGE_'.strtoupper($jobType);
22516 if (defined($event) && $this->runScripts) {
22517 $this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $policy, $pool, $installedRepo, $request, $operations, $operation);
22518 }
22519 }
22520
22521 if ($this->executeOperations) {
22522
22523 $this->processPackageUrls($pool, $policy, $localRepo, $repositories);
22524 $localRepo->write();
22525 }
22526
22527
22528 if ($operations) {
22529 $vendorDir = $this->config->get('vendor-dir');
22530 if (is_dir($vendorDir)) {
22531
22532
22533 @touch($vendorDir);
22534 }
22535 }
22536
22537 return array(0, $devPackages);
22538 }
22539
22540
22541
22542
22543
22544
22545
22546
22547
22548
22549
22550 private function extractDevPackages(array $operations, RepositoryInterface $localRepo, PlatformRepository $platformRepo, array $aliases)
22551 {
22552 if (!$this->package->getDevRequires()) {
22553 return array();
22554 }
22555
22556
22557 $tempLocalRepo = clone $localRepo;
22558 foreach ($operations as $operation) {
22559 switch ($operation->getJobType()) {
22560 case 'install':
22561 case 'markAliasInstalled':
22562 if (!$tempLocalRepo->hasPackage($operation->getPackage())) {
22563 $tempLocalRepo->addPackage(clone $operation->getPackage());
22564 }
22565 break;
22566
22567 case 'uninstall':
22568 case 'markAliasUninstalled':
22569 $tempLocalRepo->removePackage($operation->getPackage());
22570 break;
22571
22572 case 'update':
22573 $tempLocalRepo->removePackage($operation->getInitialPackage());
22574 if (!$tempLocalRepo->hasPackage($operation->getTargetPackage())) {
22575 $tempLocalRepo->addPackage(clone $operation->getTargetPackage());
22576 }
22577 break;
22578
22579 default:
22580 throw new \LogicException('Unknown type: '.$operation->getJobType());
22581 }
22582 }
22583
22584
22585
22586
22587 $localRepo = new InstalledArrayRepository(array());
22588 $loader = new ArrayLoader(null, true);
22589 $dumper = new ArrayDumper();
22590 foreach ($tempLocalRepo->getCanonicalPackages() as $pkg) {
22591 $localRepo->addPackage($loader->load($dumper->dump($pkg)));
22592 }
22593 unset($tempLocalRepo, $loader, $dumper);
22594
22595 $policy = $this->createPolicy();
22596 $pool = $this->createPool();
22597 $installedRepo = $this->createInstalledRepo($localRepo, $platformRepo);
22598 $pool->addRepository($installedRepo, $aliases);
22599
22600
22601 $request = $this->createRequest($this->package, $platformRepo);
22602 $request->updateAll();
22603 foreach ($this->package->getRequires() as $link) {
22604 $request->install($link->getTarget(), $link->getConstraint());
22605 }
22606
22607
22608 $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, false, $policy, $pool, $installedRepo, $request);
22609 $solver = new Solver($policy, $pool, $installedRepo, $this->io);
22610 $ops = $solver->solve($request, $this->ignorePlatformReqs);
22611 $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, false, $policy, $pool, $installedRepo, $request, $ops);
22612
22613 $devPackages = array();
22614 foreach ($ops as $op) {
22615 if ($op->getJobType() === 'uninstall') {
22616 $devPackages[] = $op->getPackage();
22617 }
22618 }
22619
22620 return $devPackages;
22621 }
22622
22623
22624
22625
22626 private function filterDevPackageOperations(array $devPackages, array $operations, RepositoryInterface $localRepo)
22627 {
22628 $finalOps = array();
22629 $packagesToSkip = array();
22630 foreach ($devPackages as $pkg) {
22631 $packagesToSkip[$pkg->getName()] = true;
22632 if ($installedDevPkg = $localRepo->findPackage($pkg->getName(), '*')) {
22633 if ($installedDevPkg instanceof AliasPackage) {
22634 $finalOps[] = new MarkAliasUninstalledOperation($installedDevPkg, 'non-dev install removing it');
22635 $installedDevPkg = $installedDevPkg->getAliasOf();
22636 }
22637 $finalOps[] = new UninstallOperation($installedDevPkg, 'non-dev install removing it');
22638 }
22639 }
22640
22641
22642 foreach ($operations as $op) {
22643 $package = $op->getJobType() === 'update' ? $op->getTargetPackage() : $op->getPackage();
22644 if (isset($packagesToSkip[$package->getName()])) {
22645 continue;
22646 }
22647
22648 $finalOps[] = $op;
22649 }
22650
22651 return $finalOps;
22652 }
22653
22654
22655
22656
22657
22658
22659
22660
22661
22662
22663
22664
22665
22666
22667 private function movePluginsToFront(array $operations)
22668 {
22669 $pluginsNoDeps = array();
22670 $pluginsWithDeps = array();
22671 $pluginRequires = array();
22672
22673 foreach (array_reverse($operations, true) as $idx => $op) {
22674 if ($op instanceof InstallOperation) {
22675 $package = $op->getPackage();
22676 } elseif ($op instanceof UpdateOperation) {
22677 $package = $op->getTargetPackage();
22678 } else {
22679 continue;
22680 }
22681
22682
22683 $isPlugin = $package->getType() === 'composer-plugin' || $package->getType() === 'composer-installer';
22684
22685
22686 if ($isPlugin || count(array_intersect($package->getNames(), $pluginRequires))) {
22687
22688 $requires = array_filter(array_keys($package->getRequires()), function ($req) {
22689 return $req !== 'composer-plugin-api' && !preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $req);
22690 });
22691
22692
22693 if ($isPlugin && !count($requires)) {
22694
22695 array_unshift($pluginsNoDeps, $op);
22696 } else {
22697
22698 $pluginRequires = array_merge($pluginRequires, $requires);
22699
22700 array_unshift($pluginsWithDeps, $op);
22701 }
22702
22703 unset($operations[$idx]);
22704 }
22705 }
22706
22707 return array_merge($pluginsNoDeps, $pluginsWithDeps, $operations);
22708 }
22709
22710
22711
22712
22713
22714
22715
22716
22717 private function moveUninstallsToFront(array $operations)
22718 {
22719 $uninstOps = array();
22720 foreach ($operations as $idx => $op) {
22721 if ($op instanceof UninstallOperation) {
22722 $uninstOps[] = $op;
22723 unset($operations[$idx]);
22724 }
22725 }
22726
22727 return array_merge($uninstOps, $operations);
22728 }
22729
22730
22731
22732
22733 private function createInstalledRepo(RepositoryInterface $localRepo, PlatformRepository $platformRepo)
22734 {
22735
22736
22737
22738 $installedRootPackage = clone $this->package;
22739 $installedRootPackage->setRequires(array());
22740 $installedRootPackage->setDevRequires(array());
22741
22742 $repos = array(
22743 $localRepo,
22744 new InstalledArrayRepository(array($installedRootPackage)),
22745 $platformRepo,
22746 );
22747 $installedRepo = new CompositeRepository($repos);
22748 if ($this->additionalInstalledRepository) {
22749 $installedRepo->addRepository($this->additionalInstalledRepository);
22750 }
22751
22752 return $installedRepo;
22753 }
22754
22755
22756
22757
22758
22759 private function createPool(RepositoryInterface $lockedRepository = null)
22760 {
22761 if ($this->update) {
22762 $minimumStability = $this->package->getMinimumStability();
22763 $stabilityFlags = $this->package->getStabilityFlags();
22764
22765 $requires = array_merge($this->package->getRequires(), $this->package->getDevRequires());
22766 } else {
22767 $minimumStability = $this->locker->getMinimumStability();
22768 $stabilityFlags = $this->locker->getStabilityFlags();
22769
22770 $requires = array();
22771 foreach ($lockedRepository->getPackages() as $package) {
22772 $constraint = new Constraint('=', $package->getVersion());
22773 $constraint->setPrettyString($package->getPrettyVersion());
22774 $requires[$package->getName()] = $constraint;
22775 }
22776 }
22777
22778 $rootConstraints = array();
22779 foreach ($requires as $req => $constraint) {
22780
22781 if ($this->ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $req)) {
22782 continue;
22783 }
22784 if ($constraint instanceof Link) {
22785 $rootConstraints[$req] = $constraint->getConstraint();
22786 } else {
22787 $rootConstraints[$req] = $constraint;
22788 }
22789 }
22790
22791 return new Pool($minimumStability, $stabilityFlags, $rootConstraints);
22792 }
22793
22794
22795
22796
22797 private function createPolicy()
22798 {
22799 $preferStable = null;
22800 $preferLowest = null;
22801 if (!$this->update) {
22802 $preferStable = $this->locker->getPreferStable();
22803 $preferLowest = $this->locker->getPreferLowest();
22804 }
22805
22806
22807 if (null === $preferStable) {
22808 $preferStable = $this->preferStable || $this->package->getPreferStable();
22809 }
22810 if (null === $preferLowest) {
22811 $preferLowest = $this->preferLowest;
22812 }
22813
22814 return new DefaultPolicy($preferStable, $preferLowest);
22815 }
22816
22817
22818
22819
22820
22821
22822 private function createRequest(RootPackageInterface $rootPackage, PlatformRepository $platformRepo)
22823 {
22824 $request = new Request();
22825
22826 $constraint = new Constraint('=', $rootPackage->getVersion());
22827 $constraint->setPrettyString($rootPackage->getPrettyVersion());
22828 $request->install($rootPackage->getName(), $constraint);
22829
22830 $fixedPackages = $platformRepo->getPackages();
22831 if ($this->additionalInstalledRepository) {
22832 $additionalFixedPackages = $this->additionalInstalledRepository->getPackages();
22833 $fixedPackages = array_merge($fixedPackages, $additionalFixedPackages);
22834 }
22835
22836
22837
22838 $provided = $rootPackage->getProvides();
22839 foreach ($fixedPackages as $package) {
22840 $constraint = new Constraint('=', $package->getVersion());
22841 $constraint->setPrettyString($package->getPrettyVersion());
22842
22843
22844 if ($package->getRepository() !== $platformRepo
22845 || !isset($provided[$package->getName()])
22846 || !$provided[$package->getName()]->getConstraint()->matches($constraint)
22847 ) {
22848 $request->fix($package->getName(), $constraint);
22849 }
22850 }
22851
22852 return $request;
22853 }
22854
22855
22856
22857
22858
22859
22860
22861
22862
22863
22864
22865
22866 private function processDevPackages($localRepo, $pool, $policy, $repositories, $installedRepo, $lockedRepository, $task, array $operations = null)
22867 {
22868 if ($task === 'force-updates' && null === $operations) {
22869 throw new \InvalidArgumentException('Missing operations argument');
22870 }
22871 if ($task === 'force-links') {
22872 $operations = array();
22873 }
22874
22875 if ($this->update && $this->updateWhitelist) {
22876 $currentPackages = $this->getCurrentPackages($installedRepo);
22877 }
22878
22879 foreach ($localRepo->getCanonicalPackages() as $package) {
22880
22881 if (!$package->isDev()) {
22882 continue;
22883 }
22884
22885
22886 foreach ($operations as $operation) {
22887 if (('update' === $operation->getJobType() && $operation->getInitialPackage()->equals($package))
22888 || ('uninstall' === $operation->getJobType() && $operation->getPackage()->equals($package))
22889 ) {
22890 continue 2;
22891 }
22892 }
22893
22894 if ($this->update) {
22895
22896 if ($this->updateWhitelist && !$this->isUpdateable($package)) {
22897
22898 foreach ($currentPackages as $curPackage) {
22899 if ($curPackage->isDev() && $curPackage->getName() === $package->getName() && $curPackage->getVersion() === $package->getVersion()) {
22900 if ($task === 'force-links') {
22901 $package->setRequires($curPackage->getRequires());
22902 $package->setConflicts($curPackage->getConflicts());
22903 $package->setProvides($curPackage->getProvides());
22904 $package->setReplaces($curPackage->getReplaces());
22905 } elseif ($task === 'force-updates') {
22906 if (($curPackage->getSourceReference() && $curPackage->getSourceReference() !== $package->getSourceReference())
22907 || ($curPackage->getDistReference() && $curPackage->getDistReference() !== $package->getDistReference())
22908 ) {
22909 $operations[] = new UpdateOperation($package, $curPackage);
22910 }
22911 }
22912
22913 break;
22914 }
22915 }
22916
22917 continue;
22918 }
22919
22920
22921 $matches = $pool->whatProvides($package->getName(), new Constraint('=', $package->getVersion()));
22922 foreach ($matches as $index => $match) {
22923
22924 if (!in_array($match->getRepository(), $repositories, true)) {
22925 unset($matches[$index]);
22926 continue;
22927 }
22928
22929
22930 if ($match->getName() !== $package->getName()) {
22931 unset($matches[$index]);
22932 continue;
22933 }
22934
22935 $matches[$index] = $match->getId();
22936 }
22937
22938
22939 if ($matches && $matches = $policy->selectPreferredPackages($pool, array(), $matches)) {
22940 $newPackage = $pool->literalToPackage($matches[0]);
22941
22942 if ($task === 'force-links' && $newPackage) {
22943 $package->setRequires($newPackage->getRequires());
22944 $package->setConflicts($newPackage->getConflicts());
22945 $package->setProvides($newPackage->getProvides());
22946 $package->setReplaces($newPackage->getReplaces());
22947 }
22948
22949 if (
22950 $task === 'force-updates'
22951 && $newPackage
22952 && (
22953 ($newPackage->getSourceReference() && $newPackage->getSourceReference() !== $package->getSourceReference())
22954 || ($newPackage->getDistReference() && $newPackage->getDistReference() !== $package->getDistReference())
22955 )
22956 ) {
22957 $operations[] = new UpdateOperation($package, $newPackage);
22958
22959 continue;
22960 }
22961 }
22962
22963 if ($task === 'force-updates') {
22964
22965 $references = $this->package->getReferences();
22966
22967 if (isset($references[$package->getName()]) && $references[$package->getName()] !== $package->getSourceReference()) {
22968
22969 $operations[] = new UpdateOperation($package, clone $package);
22970 }
22971 }
22972 } else {
22973
22974 foreach ($lockedRepository->findPackages($package->getName()) as $lockedPackage) {
22975 if ($lockedPackage->isDev() && $lockedPackage->getVersion() === $package->getVersion()) {
22976 if ($task === 'force-links') {
22977 $package->setRequires($lockedPackage->getRequires());
22978 $package->setConflicts($lockedPackage->getConflicts());
22979 $package->setProvides($lockedPackage->getProvides());
22980 $package->setReplaces($lockedPackage->getReplaces());
22981 } elseif ($task === 'force-updates') {
22982 if (($lockedPackage->getSourceReference() && $lockedPackage->getSourceReference() !== $package->getSourceReference())
22983 || ($lockedPackage->getDistReference() && $lockedPackage->getDistReference() !== $package->getDistReference())
22984 ) {
22985 $operations[] = new UpdateOperation($package, $lockedPackage);
22986 }
22987 }
22988
22989 break;
22990 }
22991 }
22992 }
22993 }
22994
22995 return $operations;
22996 }
22997
22998
22999
23000
23001
23002
23003 private function getCurrentPackages($installedRepo)
23004 {
23005 if ($this->locker->isLocked()) {
23006 try {
23007 return $this->locker->getLockedRepository(true)->getPackages();
23008 } catch (\RuntimeException $e) {
23009
23010 return $this->locker->getLockedRepository()->getPackages();
23011 }
23012 }
23013
23014 return $installedRepo->getPackages();
23015 }
23016
23017
23018
23019
23020 private function getRootAliases()
23021 {
23022 if ($this->update) {
23023 $aliases = $this->package->getAliases();
23024 } else {
23025 $aliases = $this->locker->getAliases();
23026 }
23027
23028 $normalizedAliases = array();
23029
23030 foreach ($aliases as $alias) {
23031 $normalizedAliases[$alias['package']][$alias['version']] = array(
23032 'alias' => $alias['alias'],
23033 'alias_normalized' => $alias['alias_normalized'],
23034 );
23035 }
23036
23037 return $normalizedAliases;
23038 }
23039
23040
23041
23042
23043
23044
23045
23046 private function processPackageUrls($pool, $policy, $localRepo, $repositories)
23047 {
23048 if (!$this->update) {
23049 return;
23050 }
23051
23052 $rootRefs = $this->package->getReferences();
23053
23054 foreach ($localRepo->getCanonicalPackages() as $package) {
23055
23056 $matches = $pool->whatProvides($package->getName(), new Constraint('=', $package->getVersion()));
23057 foreach ($matches as $index => $match) {
23058
23059 if (!in_array($match->getRepository(), $repositories, true)) {
23060 unset($matches[$index]);
23061 continue;
23062 }
23063
23064
23065 if ($match->getName() !== $package->getName()) {
23066 unset($matches[$index]);
23067 continue;
23068 }
23069
23070 $matches[$index] = $match->getId();
23071 }
23072
23073
23074 if ($matches && $matches = $policy->selectPreferredPackages($pool, array(), $matches)) {
23075 $newPackage = $pool->literalToPackage($matches[0]);
23076
23077
23078 $sourceUrl = $package->getSourceUrl();
23079 $newSourceUrl = $newPackage->getSourceUrl();
23080 $newReference = $newPackage->getSourceReference();
23081
23082 if ($package->isDev() && isset($rootRefs[$package->getName()]) && $package->getSourceReference() === $rootRefs[$package->getName()]) {
23083 $newReference = $rootRefs[$package->getName()];
23084 }
23085
23086 $this->updatePackageUrl($package, $newSourceUrl, $newPackage->getSourceType(), $newReference, $newPackage->getDistUrl(), $newPackage->getDistType(), $newPackage->getDistSha1Checksum());
23087
23088 if ($package instanceof CompletePackage && $newPackage instanceof CompletePackage) {
23089 $package->setAbandoned($newPackage->getReplacementPackage() ?: $newPackage->isAbandoned());
23090 }
23091
23092 $package->setDistMirrors($newPackage->getDistMirrors());
23093 $package->setSourceMirrors($newPackage->getSourceMirrors());
23094 $package->setTransportOptions($newPackage->getTransportOptions());
23095 }
23096 }
23097 }
23098
23099 private function updatePackageUrl(PackageInterface $package, $sourceUrl, $sourceType, $sourceReference, $distUrl, $distType, $distShaSum)
23100 {
23101 $oldSourceRef = $package->getSourceReference();
23102
23103 if ($package->getSourceUrl() !== $sourceUrl) {
23104 $package->setSourceType($sourceType);
23105 $package->setSourceUrl($sourceUrl);
23106 $package->setSourceReference($sourceReference);
23107 }
23108
23109
23110
23111 if (preg_match('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com|(?:www\.)?gitlab\.com)/}i', $distUrl)) {
23112 $package->setDistUrl($distUrl);
23113 $package->setDistType($distType);
23114 $package->setDistSha1Checksum($distShaSum);
23115 $this->updateInstallReferences($package, $sourceReference);
23116 }
23117
23118 if ($this->updateWhitelist && !$this->isUpdateable($package)) {
23119 $this->updateInstallReferences($package, $oldSourceRef);
23120 }
23121 }
23122
23123 private function updateInstallReferences(PackageInterface $package, $reference)
23124 {
23125 if (!$reference) {
23126 return;
23127 }
23128
23129 $package->setSourceReference($reference);
23130
23131 if (preg_match('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com|(?:www\.)?gitlab\.com)/}i', $package->getDistUrl())) {
23132 $package->setDistReference($reference);
23133 $package->setDistUrl(preg_replace('{(?<=/|sha=)[a-f0-9]{40}(?=/|$)}i', $reference, $package->getDistUrl()));
23134 } elseif ($package->getDistReference()) { 
23135 $package->setDistReference($reference);
23136 }
23137 }
23138
23139
23140
23141
23142
23143 private function aliasPlatformPackages(PlatformRepository $platformRepo, $aliases)
23144 {
23145 foreach ($aliases as $package => $versions) {
23146 foreach ($versions as $version => $alias) {
23147 $packages = $platformRepo->findPackages($package, $version);
23148 foreach ($packages as $package) {
23149 $aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias']);
23150 $aliasPackage->setRootPackageAlias(true);
23151 $platformRepo->addPackage($aliasPackage);
23152 }
23153 }
23154 }
23155 }
23156
23157
23158
23159
23160
23161 private function isUpdateable(PackageInterface $package)
23162 {
23163 if (!$this->updateWhitelist) {
23164 throw new \LogicException('isUpdateable should only be called when an allow list is present');
23165 }
23166
23167 foreach ($this->updateWhitelist as $pattern => $void) {
23168 $patternRegexp = BasePackage::packageNameToRegexp($pattern);
23169 if (preg_match($patternRegexp, $package->getName())) {
23170 return true;
23171 }
23172 }
23173
23174 return false;
23175 }
23176
23177
23178
23179
23180
23181 private function extractPlatformRequirements($links)
23182 {
23183 $platformReqs = array();
23184 foreach ($links as $link) {
23185 if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $link->getTarget())) {
23186 $platformReqs[$link->getTarget()] = $link->getPrettyConstraint();
23187 }
23188 }
23189
23190 return $platformReqs;
23191 }
23192
23193
23194
23195
23196
23197
23198
23199
23200
23201
23202
23203
23204
23205
23206 private function allowListUpdateDependencies($localOrLockRepo, array $rootRequires, array $rootDevRequires)
23207 {
23208 if (!$this->updateWhitelist) {
23209 return;
23210 }
23211
23212 $rootRequires = array_merge($rootRequires, $rootDevRequires);
23213
23214 $skipPackages = array();
23215 if (!$this->whitelistAllDependencies) {
23216 foreach ($rootRequires as $require) {
23217 $skipPackages[$require->getTarget()] = true;
23218 }
23219 }
23220
23221 $pool = new Pool('dev');
23222 $pool->addRepository($localOrLockRepo);
23223
23224 $seen = array();
23225
23226 $rootRequiredPackageNames = array_keys($rootRequires);
23227
23228 foreach ($this->updateWhitelist as $packageName => $void) {
23229 $packageQueue = new \SplQueue;
23230 $nameMatchesRequiredPackage = false;
23231
23232 $depPackages = $pool->whatProvides($packageName);
23233 $matchesByPattern = array();
23234
23235 if (empty($depPackages)) {
23236
23237 $allowListPatternSearchRegexp = BasePackage::packageNameToRegexp($packageName, '^%s$');
23238 foreach ($localOrLockRepo->search($allowListPatternSearchRegexp) as $installedPackage) {
23239 $matchesByPattern[] = $pool->whatProvides($installedPackage['name']);
23240 }
23241
23242
23243 $allowListPatternRegexp = BasePackage::packageNameToRegexp($packageName);
23244 foreach ($rootRequiredPackageNames as $rootRequiredPackageName) {
23245 if (preg_match($allowListPatternRegexp, $rootRequiredPackageName)) {
23246 $nameMatchesRequiredPackage = true;
23247 break;
23248 }
23249 }
23250 }
23251
23252 if (!empty($matchesByPattern)) {
23253 $depPackages = array_merge($depPackages, call_user_func_array('array_merge', $matchesByPattern));
23254 }
23255
23256 if (count($depPackages) == 0 && !$nameMatchesRequiredPackage && !in_array($packageName, array('nothing', 'lock', 'mirrors'))) {
23257 $this->io->writeError('<warning>Package "' . $packageName . '" listed for update is not installed. Ignoring.</warning>');
23258 }
23259
23260 foreach ($depPackages as $depPackage) {
23261 $packageQueue->enqueue($depPackage);
23262 }
23263
23264 while (!$packageQueue->isEmpty()) {
23265 $package = $packageQueue->dequeue();
23266 if (isset($seen[$package->getId()])) {
23267 continue;
23268 }
23269
23270 $seen[$package->getId()] = true;
23271 $this->updateWhitelist[$package->getName()] = true;
23272
23273 if (!$this->whitelistDependencies && !$this->whitelistAllDependencies) {
23274 continue;
23275 }
23276
23277 $requires = $package->getRequires();
23278
23279 foreach ($requires as $require) {
23280 $requirePackages = $pool->whatProvides($require->getTarget());
23281
23282 foreach ($requirePackages as $requirePackage) {
23283 if (isset($this->updateWhitelist[$requirePackage->getName()])) {
23284 continue;
23285 }
23286
23287 if (isset($skipPackages[$requirePackage->getName()]) && !preg_match(BasePackage::packageNameToRegexp($packageName), $requirePackage->getName())) {
23288 $this->io->writeError('<warning>Dependency "' . $requirePackage->getName() . '" is also a root requirement, but is not explicitly allowed. Ignoring.</warning>');
23289 continue;
23290 }
23291
23292 $packageQueue->enqueue($requirePackage);
23293 }
23294 }
23295 }
23296 }
23297 }
23298
23299
23300
23301
23302
23303
23304
23305
23306 private function mockLocalRepositories(RepositoryManager $rm)
23307 {
23308 $packages = array();
23309 foreach ($rm->getLocalRepository()->getPackages() as $package) {
23310 $packages[(string) $package] = clone $package;
23311 }
23312 foreach ($packages as $key => $package) {
23313 if ($package instanceof AliasPackage) {
23314 $alias = (string) $package->getAliasOf();
23315 $packages[$key] = new AliasPackage($packages[$alias], $package->getVersion(), $package->getPrettyVersion());
23316 }
23317 }
23318 $rm->setLocalRepository(
23319 new InstalledArrayRepository($packages)
23320 );
23321 }
23322
23323
23324
23325
23326
23327
23328
23329
23330 public static function create(IOInterface $io, Composer $composer)
23331 {
23332 return new static(
23333 $io,
23334 $composer->getConfig(),
23335 $composer->getPackage(),
23336 $composer->getDownloadManager(),
23337 $composer->getRepositoryManager(),
23338 $composer->getLocker(),
23339 $composer->getInstallationManager(),
23340 $composer->getEventDispatcher(),
23341 $composer->getAutoloadGenerator()
23342 );
23343 }
23344
23345
23346
23347
23348
23349 public function setAdditionalInstalledRepository(RepositoryInterface $additionalInstalledRepository)
23350 {
23351 $this->additionalInstalledRepository = $additionalInstalledRepository;
23352
23353 return $this;
23354 }
23355
23356
23357
23358
23359
23360
23361
23362 public function setDryRun($dryRun = true)
23363 {
23364 $this->dryRun = (bool) $dryRun;
23365
23366 return $this;
23367 }
23368
23369
23370
23371
23372
23373
23374 public function isDryRun()
23375 {
23376 return $this->dryRun;
23377 }
23378
23379
23380
23381
23382
23383
23384
23385 public function setPreferSource($preferSource = true)
23386 {
23387 $this->preferSource = (bool) $preferSource;
23388
23389 return $this;
23390 }
23391
23392
23393
23394
23395
23396
23397
23398 public function setPreferDist($preferDist = true)
23399 {
23400 $this->preferDist = (bool) $preferDist;
23401
23402 return $this;
23403 }
23404
23405
23406
23407
23408
23409
23410
23411 public function setOptimizeAutoloader($optimizeAutoloader = false)
23412 {
23413 $this->optimizeAutoloader = (bool) $optimizeAutoloader;
23414 if (!$this->optimizeAutoloader) {
23415
23416
23417 $this->setClassMapAuthoritative(false);
23418 }
23419
23420 return $this;
23421 }
23422
23423
23424
23425
23426
23427
23428
23429
23430 public function setClassMapAuthoritative($classMapAuthoritative = false)
23431 {
23432 $this->classMapAuthoritative = (bool) $classMapAuthoritative;
23433 if ($this->classMapAuthoritative) {
23434
23435 $this->setOptimizeAutoloader(true);
23436 }
23437
23438 return $this;
23439 }
23440
23441
23442
23443
23444
23445
23446
23447 public function setApcuAutoloader($apcuAutoloader = false)
23448 {
23449 $this->apcuAutoloader = (bool) $apcuAutoloader;
23450
23451 return $this;
23452 }
23453
23454
23455
23456
23457
23458
23459
23460 public function setUpdate($update = true)
23461 {
23462 $this->update = (bool) $update;
23463
23464 return $this;
23465 }
23466
23467
23468
23469
23470
23471
23472
23473 public function setDevMode($devMode = true)
23474 {
23475 $this->devMode = (bool) $devMode;
23476
23477 return $this;
23478 }
23479
23480
23481
23482
23483
23484
23485
23486
23487
23488 public function setDumpAutoloader($dumpAutoloader = true)
23489 {
23490 $this->dumpAutoloader = (bool) $dumpAutoloader;
23491
23492 return $this;
23493 }
23494
23495
23496
23497
23498
23499
23500
23501
23502
23503 public function setRunScripts($runScripts = true)
23504 {
23505 $this->runScripts = (bool) $runScripts;
23506
23507 return $this;
23508 }
23509
23510
23511
23512
23513
23514
23515
23516 public function setConfig(Config $config)
23517 {
23518 $this->config = $config;
23519
23520 return $this;
23521 }
23522
23523
23524
23525
23526
23527
23528
23529 public function setVerbose($verbose = true)
23530 {
23531 $this->verbose = (bool) $verbose;
23532
23533 return $this;
23534 }
23535
23536
23537
23538
23539
23540
23541 public function isVerbose()
23542 {
23543 return $this->verbose;
23544 }
23545
23546
23547
23548
23549
23550
23551
23552 public function setIgnorePlatformRequirements($ignorePlatformReqs = false)
23553 {
23554 $this->ignorePlatformReqs = (bool) $ignorePlatformReqs;
23555
23556 return $this;
23557 }
23558
23559
23560
23561
23562
23563
23564
23565
23566
23567
23568 public function setUpdateWhitelist(array $packages)
23569 {
23570 $this->updateWhitelist = array_flip(array_map('strtolower', $packages));
23571
23572 return $this;
23573 }
23574
23575
23576
23577
23578
23579
23580
23581
23582 public function setUpdateAllowList(array $packages)
23583 {
23584
23585 return $this->setUpdateWhitelist($packages);
23586 }
23587
23588
23589
23590
23591 public function setWhitelistDependencies($updateDependencies = true)
23592 {
23593 return $this->setWhitelistTransitiveDependencies($updateDependencies);
23594 }
23595
23596
23597
23598
23599
23600
23601
23602
23603
23604
23605
23606
23607 public function setWhitelistTransitiveDependencies($updateTransitiveDependencies = true)
23608 {
23609 $this->whitelistDependencies = (bool) $updateTransitiveDependencies;
23610
23611 return $this;
23612 }
23613
23614
23615
23616
23617
23618
23619
23620
23621
23622
23623 public function setAllowListTransitiveDependencies($updateTransitiveDependencies = true)
23624 {
23625
23626 return $this->setWhitelistTransitiveDependencies($updateTransitiveDependencies);
23627 }
23628
23629
23630
23631
23632
23633
23634
23635
23636
23637
23638
23639
23640 public function setWhitelistAllDependencies($updateAllDependencies = true)
23641 {
23642 $this->whitelistAllDependencies = (bool) $updateAllDependencies;
23643
23644 return $this;
23645 }
23646
23647
23648
23649
23650
23651
23652
23653
23654
23655
23656 public function setAllowListAllDependencies($updateAllDependencies = true)
23657 {
23658
23659 return $this->setWhitelistAllDependencies($updateAllDependencies);
23660 }
23661
23662
23663
23664
23665
23666
23667
23668 public function setPreferStable($preferStable = true)
23669 {
23670 $this->preferStable = (bool) $preferStable;
23671
23672 return $this;
23673 }
23674
23675
23676
23677
23678
23679
23680
23681 public function setPreferLowest($preferLowest = true)
23682 {
23683 $this->preferLowest = (bool) $preferLowest;
23684
23685 return $this;
23686 }
23687
23688
23689
23690
23691
23692
23693
23694
23695
23696 public function setWriteLock($writeLock = true)
23697 {
23698 $this->writeLock = (bool) $writeLock;
23699
23700 return $this;
23701 }
23702
23703
23704
23705
23706
23707
23708
23709
23710
23711 public function setExecuteOperations($executeOperations = true)
23712 {
23713 $this->executeOperations = (bool) $executeOperations;
23714
23715 return $this;
23716 }
23717
23718
23719
23720
23721
23722
23723
23724 public function setSkipSuggest($skipSuggest = true)
23725 {
23726 $this->skipSuggest = (bool) $skipSuggest;
23727
23728 return $this;
23729 }
23730
23731
23732
23733
23734
23735
23736
23737
23738
23739
23740 public function disablePlugins()
23741 {
23742 $this->installationManager->disablePlugins();
23743
23744 return $this;
23745 }
23746
23747
23748
23749
23750
23751 public function setSuggestedPackagesReporter(SuggestedPackagesReporter $suggestedPackagesReporter)
23752 {
23753 $this->suggestedPackagesReporter = $suggestedPackagesReporter;
23754
23755 return $this;
23756 }
23757 }
23758 <?php
23759
23760
23761
23762
23763
23764
23765
23766
23767
23768
23769
23770 namespace Composer\Installer;
23771
23772 use Composer\IO\IOInterface;
23773 use Composer\Package\PackageInterface;
23774 use Composer\Util\Filesystem;
23775 use Composer\Util\Platform;
23776 use Composer\Util\ProcessExecutor;
23777 use Composer\Util\Silencer;
23778
23779
23780
23781
23782
23783
23784
23785
23786 class BinaryInstaller
23787 {
23788 protected $binDir;
23789 protected $binCompat;
23790 protected $io;
23791 protected $filesystem;
23792
23793
23794
23795
23796
23797
23798
23799 public function __construct(IOInterface $io, $binDir, $binCompat, Filesystem $filesystem = null)
23800 {
23801 $this->binDir = $binDir;
23802 $this->binCompat = $binCompat;
23803 $this->io = $io;
23804 $this->filesystem = $filesystem ?: new Filesystem();
23805 }
23806
23807 public function installBinaries(PackageInterface $package, $installPath, $warnOnOverwrite = true)
23808 {
23809 $binaries = $this->getBinaries($package);
23810 if (!$binaries) {
23811 return;
23812 }
23813 foreach ($binaries as $bin) {
23814 $binPath = $installPath.'/'.$bin;
23815 if (!file_exists($binPath)) {
23816 $this->io->writeError('    <warning>Skipped installation of bin '.$bin.' for package '.$package->getName().': file not found in package</warning>');
23817 continue;
23818 }
23819
23820
23821
23822
23823
23824 $binPath = realpath($binPath);
23825
23826 $this->initializeBinDir();
23827 $link = $this->binDir.'/'.basename($bin);
23828 if (file_exists($link)) {
23829 if (is_link($link)) {
23830
23831
23832
23833 Silencer::call('chmod', $link, 0777 & ~umask());
23834 }
23835 if ($warnOnOverwrite) {
23836 $this->io->writeError('    Skipped installation of bin '.$bin.' for package '.$package->getName().': name conflicts with an existing file');
23837 }
23838 continue;
23839 }
23840
23841 if ($this->binCompat === "auto") {
23842 if (Platform::isWindows()) {
23843 $this->installFullBinaries($binPath, $link, $bin, $package);
23844 } else {
23845 $this->installSymlinkBinaries($binPath, $link);
23846 }
23847 } elseif ($this->binCompat === "full") {
23848 $this->installFullBinaries($binPath, $link, $bin, $package);
23849 }
23850 Silencer::call('chmod', $link, 0777 & ~umask());
23851 }
23852 }
23853
23854 public function removeBinaries(PackageInterface $package)
23855 {
23856 $this->initializeBinDir();
23857
23858 $binaries = $this->getBinaries($package);
23859 if (!$binaries) {
23860 return;
23861 }
23862 foreach ($binaries as $bin) {
23863 $link = $this->binDir.'/'.basename($bin);
23864 if (is_link($link) || file_exists($link)) {
23865 $this->filesystem->unlink($link);
23866 }
23867 if (file_exists($link.'.bat')) {
23868 $this->filesystem->unlink($link.'.bat');
23869 }
23870 }
23871
23872
23873 if (is_dir($this->binDir) && $this->filesystem->isDirEmpty($this->binDir)) {
23874 Silencer::call('rmdir', $this->binDir);
23875 }
23876 }
23877
23878 public static function determineBinaryCaller($bin)
23879 {
23880 if ('.bat' === substr($bin, -4) || '.exe' === substr($bin, -4)) {
23881 return 'call';
23882 }
23883
23884 $handle = fopen($bin, 'r');
23885 $line = fgets($handle);
23886 fclose($handle);
23887 if (preg_match('{^#!/(?:usr/bin/env )?(?:[^/]+/)*(.+)$}m', $line, $match)) {
23888 return trim($match[1]);
23889 }
23890
23891 return 'php';
23892 }
23893
23894 protected function getBinaries(PackageInterface $package)
23895 {
23896 return $package->getBinaries();
23897 }
23898
23899 protected function installFullBinaries($binPath, $link, $bin, PackageInterface $package)
23900 {
23901
23902 if ('.bat' !== substr($binPath, -4)) {
23903 $this->installUnixyProxyBinaries($binPath, $link);
23904 @chmod($link, 0777 & ~umask());
23905 $link .= '.bat';
23906 if (file_exists($link)) {
23907 $this->io->writeError('    Skipped installation of bin '.$bin.'.bat proxy for package '.$package->getName().': a .bat proxy was already installed');
23908 }
23909 }
23910 if (!file_exists($link)) {
23911 file_put_contents($link, $this->generateWindowsProxyCode($binPath, $link));
23912 }
23913 }
23914
23915 protected function installSymlinkBinaries($binPath, $link)
23916 {
23917 if (!$this->filesystem->relativeSymlink($binPath, $link)) {
23918 $this->installUnixyProxyBinaries($binPath, $link);
23919 }
23920 }
23921
23922 protected function installUnixyProxyBinaries($binPath, $link)
23923 {
23924 file_put_contents($link, $this->generateUnixyProxyCode($binPath, $link));
23925 }
23926
23927 protected function initializeBinDir()
23928 {
23929 $this->filesystem->ensureDirectoryExists($this->binDir);
23930 $this->binDir = realpath($this->binDir);
23931 }
23932
23933 protected function generateWindowsProxyCode($bin, $link)
23934 {
23935 $binPath = $this->filesystem->findShortestPath($link, $bin);
23936 $caller = self::determineBinaryCaller($bin);
23937
23938 return "@ECHO OFF\r\n".
23939 "setlocal DISABLEDELAYEDEXPANSION\r\n".
23940 "SET BIN_TARGET=%~dp0/".trim(ProcessExecutor::escape($binPath), '"\'')."\r\n".
23941 "{$caller} \"%BIN_TARGET%\" %*\r\n";
23942 }
23943
23944 protected function generateUnixyProxyCode($bin, $link)
23945 {
23946 $binPath = $this->filesystem->findShortestPath($link, $bin);
23947
23948 $binDir = ProcessExecutor::escape(dirname($binPath));
23949 $binFile = basename($binPath);
23950
23951 $proxyCode = <<<PROXY
23952 #!/usr/bin/env sh
23953
23954 dir=\$(cd "\${0%[/\\\\]*}" > /dev/null; cd $binDir && pwd)
23955
23956 if [ -d /proc/cygdrive ]; then
23957     case \$(which php) in
23958         \$(readlink -n /proc/cygdrive)/*)
23959             # We are in Cygwin using Windows php, so the path must be translated
23960             dir=\$(cygpath -m "\$dir");
23961             ;;
23962     esac
23963 fi
23964
23965 "\${dir}/$binFile" "\$@"
23966
23967 PROXY;
23968
23969 return $proxyCode;
23970 }
23971 }
23972 <?php
23973
23974
23975
23976
23977
23978
23979
23980
23981
23982
23983
23984 namespace Composer\Installer;
23985
23986 use Composer\Package\PackageInterface;
23987
23988
23989
23990
23991
23992
23993 interface BinaryPresenceInterface
23994 {
23995
23996
23997
23998
23999
24000 public function ensureBinariesPresence(PackageInterface $package);
24001 }
24002 <?php
24003
24004
24005
24006
24007
24008
24009
24010
24011
24012
24013
24014 namespace Composer\Installer;
24015
24016 use Composer\IO\IOInterface;
24017 use Composer\Package\PackageInterface;
24018 use Composer\Package\AliasPackage;
24019 use Composer\Repository\RepositoryInterface;
24020 use Composer\Repository\InstalledRepositoryInterface;
24021 use Composer\DependencyResolver\Operation\OperationInterface;
24022 use Composer\DependencyResolver\Operation\InstallOperation;
24023 use Composer\DependencyResolver\Operation\UpdateOperation;
24024 use Composer\DependencyResolver\Operation\UninstallOperation;
24025 use Composer\DependencyResolver\Operation\MarkAliasInstalledOperation;
24026 use Composer\DependencyResolver\Operation\MarkAliasUninstalledOperation;
24027 use Composer\Util\StreamContextFactory;
24028
24029
24030
24031
24032
24033
24034
24035
24036 class InstallationManager
24037 {
24038 private $installers = array();
24039 private $cache = array();
24040 private $notifiablePackages = array();
24041
24042 public function reset()
24043 {
24044 $this->notifiablePackages = array();
24045 }
24046
24047
24048
24049
24050
24051
24052 public function addInstaller(InstallerInterface $installer)
24053 {
24054 array_unshift($this->installers, $installer);
24055 $this->cache = array();
24056 }
24057
24058
24059
24060
24061
24062
24063 public function removeInstaller(InstallerInterface $installer)
24064 {
24065 if (false !== ($key = array_search($installer, $this->installers, true))) {
24066 array_splice($this->installers, $key, 1);
24067 $this->cache = array();
24068 }
24069 }
24070
24071
24072
24073
24074
24075
24076
24077
24078 public function disablePlugins()
24079 {
24080 foreach ($this->installers as $i => $installer) {
24081 if (!$installer instanceof PluginInstaller) {
24082 continue;
24083 }
24084
24085 unset($this->installers[$i]);
24086 }
24087 }
24088
24089
24090
24091
24092
24093
24094
24095
24096
24097 public function getInstaller($type)
24098 {
24099 $type = strtolower($type);
24100
24101 if (isset($this->cache[$type])) {
24102 return $this->cache[$type];
24103 }
24104
24105 foreach ($this->installers as $installer) {
24106 if ($installer->supports($type)) {
24107 return $this->cache[$type] = $installer;
24108 }
24109 }
24110
24111 throw new \InvalidArgumentException('Unknown installer type: '.$type);
24112 }
24113
24114
24115
24116
24117
24118
24119
24120
24121
24122 public function isPackageInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
24123 {
24124 if ($package instanceof AliasPackage) {
24125 return $repo->hasPackage($package) && $this->isPackageInstalled($repo, $package->getAliasOf());
24126 }
24127
24128 return $this->getInstaller($package->getType())->isInstalled($repo, $package);
24129 }
24130
24131
24132
24133
24134
24135
24136
24137 public function ensureBinariesPresence(PackageInterface $package)
24138 {
24139 try {
24140 $installer = $this->getInstaller($package->getType());
24141 } catch (\InvalidArgumentException $e) {
24142
24143 return;
24144 }
24145
24146
24147 if ($installer instanceof BinaryPresenceInterface) {
24148 $installer->ensureBinariesPresence($package);
24149 }
24150 }
24151
24152
24153
24154
24155
24156
24157
24158 public function execute(RepositoryInterface $repo, OperationInterface $operation)
24159 {
24160 $method = $operation->getJobType();
24161 $this->$method($repo, $operation);
24162 }
24163
24164
24165
24166
24167
24168
24169
24170 public function install(RepositoryInterface $repo, InstallOperation $operation)
24171 {
24172 $package = $operation->getPackage();
24173 $installer = $this->getInstaller($package->getType());
24174 $installer->install($repo, $package);
24175 $this->markForNotification($package);
24176 }
24177
24178
24179
24180
24181
24182
24183
24184 public function update(RepositoryInterface $repo, UpdateOperation $operation)
24185 {
24186 $initial = $operation->getInitialPackage();
24187 $target = $operation->getTargetPackage();
24188
24189 $initialType = $initial->getType();
24190 $targetType = $target->getType();
24191
24192 if ($initialType === $targetType) {
24193 $installer = $this->getInstaller($initialType);
24194 $installer->update($repo, $initial, $target);
24195 $this->markForNotification($target);
24196 } else {
24197 $this->getInstaller($initialType)->uninstall($repo, $initial);
24198 $this->getInstaller($targetType)->install($repo, $target);
24199 }
24200 }
24201
24202
24203
24204
24205
24206
24207
24208 public function uninstall(RepositoryInterface $repo, UninstallOperation $operation)
24209 {
24210 $package = $operation->getPackage();
24211 $installer = $this->getInstaller($package->getType());
24212 $installer->uninstall($repo, $package);
24213 }
24214
24215
24216
24217
24218
24219
24220
24221 public function markAliasInstalled(RepositoryInterface $repo, MarkAliasInstalledOperation $operation)
24222 {
24223 $package = $operation->getPackage();
24224
24225 if (!$repo->hasPackage($package)) {
24226 $repo->addPackage(clone $package);
24227 }
24228 }
24229
24230
24231
24232
24233
24234
24235
24236 public function markAliasUninstalled(RepositoryInterface $repo, MarkAliasUninstalledOperation $operation)
24237 {
24238 $package = $operation->getPackage();
24239
24240 $repo->removePackage($package);
24241 }
24242
24243
24244
24245
24246
24247
24248
24249 public function getInstallPath(PackageInterface $package)
24250 {
24251 $installer = $this->getInstaller($package->getType());
24252
24253 return $installer->getInstallPath($package);
24254 }
24255
24256 public function notifyInstalls(IOInterface $io)
24257 {
24258 foreach ($this->notifiablePackages as $repoUrl => $packages) {
24259 $repositoryName = parse_url($repoUrl, PHP_URL_HOST);
24260 if ($io->hasAuthentication($repositoryName)) {
24261 $auth = $io->getAuthentication($repositoryName);
24262 $authStr = base64_encode($auth['username'] . ':' . $auth['password']);
24263 $authHeader = 'Authorization: Basic '.$authStr;
24264 }
24265
24266
24267 if (strpos($repoUrl, '%package%')) {
24268 foreach ($packages as $package) {
24269 $url = str_replace('%package%', $package->getPrettyName(), $repoUrl);
24270
24271 $params = array(
24272 'version' => $package->getPrettyVersion(),
24273 'version_normalized' => $package->getVersion(),
24274 );
24275 $opts = array('http' =>
24276 array(
24277 'method' => 'POST',
24278 'header' => array('Content-type: application/x-www-form-urlencoded'),
24279 'content' => http_build_query($params, '', '&'),
24280 'timeout' => 3,
24281 ),
24282 );
24283 if (isset($authHeader)) {
24284 $opts['http']['header'][] = $authHeader;
24285 }
24286
24287 $context = StreamContextFactory::getContext($url, $opts);
24288 @file_get_contents($url, false, $context);
24289 }
24290
24291 continue;
24292 }
24293
24294 $postData = array('downloads' => array());
24295 foreach ($packages as $package) {
24296 $postData['downloads'][] = array(
24297 'name' => $package->getPrettyName(),
24298 'version' => $package->getVersion(),
24299 );
24300 }
24301
24302 $opts = array('http' =>
24303 array(
24304 'method' => 'POST',
24305 'header' => array('Content-Type: application/json'),
24306 'content' => json_encode($postData),
24307 'timeout' => 6,
24308 ),
24309 );
24310 if (isset($authHeader)) {
24311 $opts['http']['header'][] = $authHeader;
24312 }
24313
24314 $context = StreamContextFactory::getContext($repoUrl, $opts);
24315 @file_get_contents($repoUrl, false, $context);
24316 }
24317
24318 $this->reset();
24319 }
24320
24321 private function markForNotification(PackageInterface $package)
24322 {
24323 if ($package->getNotificationUrl()) {
24324 $this->notifiablePackages[$package->getNotificationUrl()][$package->getName()] = $package;
24325 }
24326 }
24327 }
24328 <?php
24329
24330
24331
24332
24333
24334
24335
24336
24337
24338
24339
24340 namespace Composer\Installer;
24341
24342 use Composer\Composer;
24343 use Composer\DependencyResolver\PolicyInterface;
24344 use Composer\DependencyResolver\Operation\OperationInterface;
24345 use Composer\DependencyResolver\Pool;
24346 use Composer\DependencyResolver\Request;
24347 use Composer\EventDispatcher\Event;
24348 use Composer\IO\IOInterface;
24349 use Composer\Repository\CompositeRepository;
24350
24351
24352
24353
24354
24355
24356 class InstallerEvent extends Event
24357 {
24358
24359
24360
24361 private $composer;
24362
24363
24364
24365
24366 private $io;
24367
24368
24369
24370
24371 private $devMode;
24372
24373
24374
24375
24376 private $policy;
24377
24378
24379
24380
24381 private $pool;
24382
24383
24384
24385
24386 private $installedRepo;
24387
24388
24389
24390
24391 private $request;
24392
24393
24394
24395
24396 private $operations;
24397
24398
24399
24400
24401
24402
24403
24404
24405
24406
24407
24408
24409
24410
24411 public function __construct($eventName, Composer $composer, IOInterface $io, $devMode, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations = array())
24412 {
24413 parent::__construct($eventName);
24414
24415 $this->composer = $composer;
24416 $this->io = $io;
24417 $this->devMode = $devMode;
24418 $this->policy = $policy;
24419 $this->pool = $pool;
24420 $this->installedRepo = $installedRepo;
24421 $this->request = $request;
24422 $this->operations = $operations;
24423 }
24424
24425
24426
24427
24428 public function getComposer()
24429 {
24430 return $this->composer;
24431 }
24432
24433
24434
24435
24436 public function getIO()
24437 {
24438 return $this->io;
24439 }
24440
24441
24442
24443
24444 public function isDevMode()
24445 {
24446 return $this->devMode;
24447 }
24448
24449
24450
24451
24452 public function getPolicy()
24453 {
24454 return $this->policy;
24455 }
24456
24457
24458
24459
24460 public function getPool()
24461 {
24462 return $this->pool;
24463 }
24464
24465
24466
24467
24468 public function getInstalledRepo()
24469 {
24470 return $this->installedRepo;
24471 }
24472
24473
24474
24475
24476 public function getRequest()
24477 {
24478 return $this->request;
24479 }
24480
24481
24482
24483
24484 public function getOperations()
24485 {
24486 return $this->operations;
24487 }
24488 }
24489 <?php
24490
24491
24492
24493
24494
24495
24496
24497
24498
24499
24500
24501 namespace Composer\Installer;
24502
24503
24504
24505
24506
24507
24508 class InstallerEvents
24509 {
24510
24511
24512
24513
24514
24515
24516
24517
24518
24519 const PRE_DEPENDENCIES_SOLVING = 'pre-dependencies-solving';
24520
24521
24522
24523
24524
24525
24526
24527
24528
24529
24530 const POST_DEPENDENCIES_SOLVING = 'post-dependencies-solving';
24531 }
24532 <?php
24533
24534
24535
24536
24537
24538
24539
24540
24541
24542
24543
24544 namespace Composer\Installer;
24545
24546 use Composer\Package\PackageInterface;
24547 use Composer\Repository\InstalledRepositoryInterface;
24548 use InvalidArgumentException;
24549
24550
24551
24552
24553
24554
24555
24556 interface InstallerInterface
24557 {
24558
24559
24560
24561
24562
24563
24564 public function supports($packageType);
24565
24566
24567
24568
24569
24570
24571
24572
24573
24574 public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package);
24575
24576
24577
24578
24579
24580
24581
24582 public function install(InstalledRepositoryInterface $repo, PackageInterface $package);
24583
24584
24585
24586
24587
24588
24589
24590
24591
24592
24593 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target);
24594
24595
24596
24597
24598
24599
24600
24601 public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package);
24602
24603
24604
24605
24606
24607
24608
24609 public function getInstallPath(PackageInterface $package);
24610 }
24611 <?php
24612
24613
24614
24615
24616
24617
24618
24619
24620
24621
24622
24623 namespace Composer\Installer;
24624
24625 use Composer\Composer;
24626 use Composer\IO\IOInterface;
24627 use Composer\Repository\InstalledRepositoryInterface;
24628 use Composer\Package\PackageInterface;
24629 use Composer\Util\Filesystem;
24630 use Composer\Util\Silencer;
24631 use Composer\Util\Platform;
24632
24633
24634
24635
24636
24637
24638
24639 class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
24640 {
24641 protected $composer;
24642 protected $vendorDir;
24643 protected $binDir;
24644 protected $downloadManager;
24645 protected $io;
24646 protected $type;
24647 protected $filesystem;
24648 protected $binCompat;
24649 protected $binaryInstaller;
24650
24651
24652
24653
24654
24655
24656
24657
24658
24659
24660 public function __construct(IOInterface $io, Composer $composer, $type = 'library', Filesystem $filesystem = null, BinaryInstaller $binaryInstaller = null)
24661 {
24662 $this->composer = $composer;
24663 $this->downloadManager = $composer->getDownloadManager();
24664 $this->io = $io;
24665 $this->type = $type;
24666
24667 $this->filesystem = $filesystem ?: new Filesystem();
24668 $this->vendorDir = rtrim($composer->getConfig()->get('vendor-dir'), '/');
24669 $this->binaryInstaller = $binaryInstaller ?: new BinaryInstaller($this->io, rtrim($composer->getConfig()->get('bin-dir'), '/'), $composer->getConfig()->get('bin-compat'), $this->filesystem);
24670 }
24671
24672
24673
24674
24675 public function supports($packageType)
24676 {
24677 return $packageType === $this->type || null === $this->type;
24678 }
24679
24680
24681
24682
24683 public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
24684 {
24685 if (!$repo->hasPackage($package)) {
24686 return false;
24687 }
24688
24689 $installPath = $this->getInstallPath($package);
24690
24691 if (is_readable($installPath)) {
24692 return true;
24693 }
24694
24695 return (Platform::isWindows() && $this->filesystem->isJunction($installPath)) || is_link($installPath);
24696 }
24697
24698
24699
24700
24701 public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
24702 {
24703 $this->initializeVendorDir();
24704 $downloadPath = $this->getInstallPath($package);
24705
24706
24707 if (!is_readable($downloadPath) && $repo->hasPackage($package)) {
24708 $this->binaryInstaller->removeBinaries($package);
24709 }
24710
24711 $this->installCode($package);
24712 $this->binaryInstaller->installBinaries($package, $this->getInstallPath($package));
24713 if (!$repo->hasPackage($package)) {
24714 $repo->addPackage(clone $package);
24715 }
24716 }
24717
24718
24719
24720
24721 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
24722 {
24723 if (!$repo->hasPackage($initial)) {
24724 throw new \InvalidArgumentException('Package is not installed: '.$initial);
24725 }
24726
24727 $this->initializeVendorDir();
24728
24729 $this->binaryInstaller->removeBinaries($initial);
24730 $this->updateCode($initial, $target);
24731 $this->binaryInstaller->installBinaries($target, $this->getInstallPath($target));
24732 $repo->removePackage($initial);
24733 if (!$repo->hasPackage($target)) {
24734 $repo->addPackage(clone $target);
24735 }
24736 }
24737
24738
24739
24740
24741 public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
24742 {
24743 if (!$repo->hasPackage($package)) {
24744 throw new \InvalidArgumentException('Package is not installed: '.$package);
24745 }
24746
24747 $this->removeCode($package);
24748 $this->binaryInstaller->removeBinaries($package);
24749 $repo->removePackage($package);
24750
24751 $downloadPath = $this->getPackageBasePath($package);
24752 if (strpos($package->getName(), '/')) {
24753 $packageVendorDir = dirname($downloadPath);
24754 if (is_dir($packageVendorDir) && $this->filesystem->isDirEmpty($packageVendorDir)) {
24755 Silencer::call('rmdir', $packageVendorDir);
24756 }
24757 }
24758 }
24759
24760
24761
24762
24763 public function getInstallPath(PackageInterface $package)
24764 {
24765 $this->initializeVendorDir();
24766
24767 $basePath = ($this->vendorDir ? $this->vendorDir.'/' : '') . $package->getPrettyName();
24768 $targetDir = $package->getTargetDir();
24769
24770 return $basePath . ($targetDir ? '/'.$targetDir : '');
24771 }
24772
24773
24774
24775
24776
24777
24778 public function ensureBinariesPresence(PackageInterface $package)
24779 {
24780 $this->binaryInstaller->installBinaries($package, $this->getInstallPath($package), false);
24781 }
24782
24783
24784
24785
24786
24787
24788
24789
24790
24791
24792 protected function getPackageBasePath(PackageInterface $package)
24793 {
24794 $installPath = $this->getInstallPath($package);
24795 $targetDir = $package->getTargetDir();
24796
24797 if ($targetDir) {
24798 return preg_replace('{/*'.str_replace('/', '/+', preg_quote($targetDir)).'/?$}', '', $installPath);
24799 }
24800
24801 return $installPath;
24802 }
24803
24804 protected function installCode(PackageInterface $package)
24805 {
24806 $downloadPath = $this->getInstallPath($package);
24807 $this->downloadManager->download($package, $downloadPath);
24808 }
24809
24810 protected function updateCode(PackageInterface $initial, PackageInterface $target)
24811 {
24812 $initialDownloadPath = $this->getInstallPath($initial);
24813 $targetDownloadPath = $this->getInstallPath($target);
24814 if ($targetDownloadPath !== $initialDownloadPath) {
24815
24816
24817 if (substr($initialDownloadPath, 0, strlen($targetDownloadPath)) === $targetDownloadPath
24818 || substr($targetDownloadPath, 0, strlen($initialDownloadPath)) === $initialDownloadPath
24819 ) {
24820 $this->removeCode($initial);
24821 $this->installCode($target);
24822
24823 return;
24824 }
24825
24826 $this->filesystem->rename($initialDownloadPath, $targetDownloadPath);
24827 }
24828 $this->downloadManager->update($initial, $target, $targetDownloadPath);
24829 }
24830
24831 protected function removeCode(PackageInterface $package)
24832 {
24833 $downloadPath = $this->getPackageBasePath($package);
24834 $this->downloadManager->remove($package, $downloadPath);
24835 }
24836
24837 protected function initializeVendorDir()
24838 {
24839 $this->filesystem->ensureDirectoryExists($this->vendorDir);
24840 $this->vendorDir = realpath($this->vendorDir);
24841 }
24842 }
24843 <?php
24844
24845
24846
24847
24848
24849
24850
24851
24852
24853
24854
24855 namespace Composer\Installer;
24856
24857 use Composer\Repository\InstalledRepositoryInterface;
24858 use Composer\Package\PackageInterface;
24859 use Composer\Package\Version\VersionParser;
24860 use Composer\IO\IOInterface;
24861
24862
24863
24864
24865
24866
24867 class MetapackageInstaller implements InstallerInterface
24868 {
24869 private $io;
24870
24871 public function __construct(IOInterface $io)
24872 {
24873 $this->io = $io;
24874 }
24875
24876
24877
24878
24879 public function supports($packageType)
24880 {
24881 return $packageType === 'metapackage';
24882 }
24883
24884
24885
24886
24887 public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
24888 {
24889 return $repo->hasPackage($package);
24890 }
24891
24892
24893
24894
24895 public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
24896 {
24897 $this->io->writeError("  - Installing <info>" . $package->getName() . "</info> (<comment>" . $package->getFullPrettyVersion() . "</comment>)");
24898
24899 $repo->addPackage(clone $package);
24900 }
24901
24902
24903
24904
24905 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
24906 {
24907 if (!$repo->hasPackage($initial)) {
24908 throw new \InvalidArgumentException('Package is not installed: '.$initial);
24909 }
24910
24911 $name = $target->getName();
24912 $from = $initial->getFullPrettyVersion();
24913 $to = $target->getFullPrettyVersion();
24914 $actionName = VersionParser::isUpgrade($initial->getVersion(), $target->getVersion()) ? 'Updating' : 'Downgrading';
24915 $this->io->writeError("  - " . $actionName . " <info>" . $name . "</info> (<comment>" . $from . "</comment> => <comment>" . $to . "</comment>)");
24916
24917 $repo->removePackage($initial);
24918 $repo->addPackage(clone $target);
24919 }
24920
24921
24922
24923
24924 public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
24925 {
24926 if (!$repo->hasPackage($package)) {
24927 throw new \InvalidArgumentException('Package is not installed: '.$package);
24928 }
24929
24930 $this->io->writeError("  - Removing <info>" . $package->getName() . "</info> (<comment>" . $package->getFullPrettyVersion() . "</comment>)");
24931
24932 $repo->removePackage($package);
24933 }
24934
24935
24936
24937
24938 public function getInstallPath(PackageInterface $package)
24939 {
24940 return '';
24941 }
24942 }
24943 <?php
24944
24945
24946
24947
24948
24949
24950
24951
24952
24953
24954
24955 namespace Composer\Installer;
24956
24957 use Composer\Repository\InstalledRepositoryInterface;
24958 use Composer\Package\PackageInterface;
24959
24960
24961
24962
24963
24964
24965
24966
24967 class NoopInstaller implements InstallerInterface
24968 {
24969
24970
24971
24972 public function supports($packageType)
24973 {
24974 return true;
24975 }
24976
24977
24978
24979
24980 public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
24981 {
24982 return $repo->hasPackage($package);
24983 }
24984
24985
24986
24987
24988 public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
24989 {
24990 if (!$repo->hasPackage($package)) {
24991 $repo->addPackage(clone $package);
24992 }
24993 }
24994
24995
24996
24997
24998 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
24999 {
25000 if (!$repo->hasPackage($initial)) {
25001 throw new \InvalidArgumentException('Package is not installed: '.$initial);
25002 }
25003
25004 $repo->removePackage($initial);
25005 if (!$repo->hasPackage($target)) {
25006 $repo->addPackage(clone $target);
25007 }
25008 }
25009
25010
25011
25012
25013 public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
25014 {
25015 if (!$repo->hasPackage($package)) {
25016 throw new \InvalidArgumentException('Package is not installed: '.$package);
25017 }
25018 $repo->removePackage($package);
25019 }
25020
25021
25022
25023
25024 public function getInstallPath(PackageInterface $package)
25025 {
25026 $targetDir = $package->getTargetDir();
25027
25028 return $package->getPrettyName() . ($targetDir ? '/'.$targetDir : '');
25029 }
25030 }
25031 <?php
25032
25033
25034
25035
25036
25037
25038
25039
25040
25041
25042
25043 namespace Composer\Installer;
25044
25045 use Composer\Composer;
25046 use Composer\IO\IOInterface;
25047 use Composer\DependencyResolver\Operation\OperationInterface;
25048 use Composer\DependencyResolver\PolicyInterface;
25049 use Composer\DependencyResolver\Pool;
25050 use Composer\DependencyResolver\Request;
25051 use Composer\Repository\CompositeRepository;
25052
25053
25054
25055
25056
25057
25058 class PackageEvent extends InstallerEvent
25059 {
25060
25061
25062
25063 private $operation;
25064
25065
25066
25067
25068
25069
25070
25071
25072
25073
25074
25075
25076
25077
25078
25079 public function __construct($eventName, Composer $composer, IOInterface $io, $devMode, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations, OperationInterface $operation)
25080 {
25081 parent::__construct($eventName, $composer, $io, $devMode, $policy, $pool, $installedRepo, $request, $operations);
25082
25083 $this->operation = $operation;
25084 }
25085
25086
25087
25088
25089
25090
25091 public function getOperation()
25092 {
25093 return $this->operation;
25094 }
25095 }
25096 <?php
25097
25098
25099
25100
25101
25102
25103
25104
25105
25106
25107
25108 namespace Composer\Installer;
25109
25110
25111
25112
25113
25114
25115 class PackageEvents
25116 {
25117
25118
25119
25120
25121
25122
25123
25124 const PRE_PACKAGE_INSTALL = 'pre-package-install';
25125
25126
25127
25128
25129
25130
25131
25132
25133 const POST_PACKAGE_INSTALL = 'post-package-install';
25134
25135
25136
25137
25138
25139
25140
25141
25142 const PRE_PACKAGE_UPDATE = 'pre-package-update';
25143
25144
25145
25146
25147
25148
25149
25150
25151 const POST_PACKAGE_UPDATE = 'post-package-update';
25152
25153
25154
25155
25156
25157
25158
25159
25160 const PRE_PACKAGE_UNINSTALL = 'pre-package-uninstall';
25161
25162
25163
25164
25165
25166
25167
25168
25169 const POST_PACKAGE_UNINSTALL = 'post-package-uninstall';
25170 }
25171 <?php
25172
25173
25174
25175
25176
25177
25178
25179
25180
25181
25182
25183 namespace Composer\Installer;
25184
25185 use Composer\IO\IOInterface;
25186 use Composer\Package\PackageInterface;
25187 use Composer\Util\Filesystem;
25188 use Composer\Util\ProcessExecutor;
25189
25190
25191
25192
25193
25194
25195 class PearBinaryInstaller extends BinaryInstaller
25196 {
25197 private $installer;
25198 private $vendorDir;
25199
25200
25201
25202
25203
25204
25205
25206
25207
25208 public function __construct(IOInterface $io, $binDir, $vendorDir, $binCompat, Filesystem $filesystem, PearInstaller $installer)
25209 {
25210 parent::__construct($io, $binDir, $binCompat, $filesystem);
25211 $this->installer = $installer;
25212 $this->vendorDir = $vendorDir;
25213 }
25214
25215 protected function getBinaries(PackageInterface $package)
25216 {
25217 $binariesPath = $this->installer->getInstallPath($package) . '/bin/';
25218 $binaries = array();
25219 if (file_exists($binariesPath)) {
25220 foreach (new \FilesystemIterator($binariesPath, \FilesystemIterator::KEY_AS_FILENAME | \FilesystemIterator::CURRENT_AS_FILEINFO) as $fileName => $value) {
25221 if (!$value->isDir()) {
25222 $binaries[] = 'bin/'.$fileName;
25223 }
25224 }
25225 }
25226
25227 return $binaries;
25228 }
25229
25230 protected function initializeBinDir()
25231 {
25232 parent::initializeBinDir();
25233 file_put_contents($this->binDir.'/composer-php', $this->generateUnixyPhpProxyCode());
25234 @chmod($this->binDir.'/composer-php', 0777 & ~umask());
25235 file_put_contents($this->binDir.'/composer-php.bat', $this->generateWindowsPhpProxyCode());
25236 @chmod($this->binDir.'/composer-php.bat', 0777 & ~umask());
25237 }
25238
25239 protected function generateWindowsProxyCode($bin, $link)
25240 {
25241 $binPath = $this->filesystem->findShortestPath($link, $bin);
25242 if ('.bat' === substr($bin, -4)) {
25243 $caller = 'call';
25244 } else {
25245 $handle = fopen($bin, 'r');
25246 $line = fgets($handle);
25247 fclose($handle);
25248 if (preg_match('{^#!/(?:usr/bin/env )?(?:[^/]+/)*(.+)$}m', $line, $match)) {
25249 $caller = trim($match[1]);
25250 } else {
25251 $caller = 'php';
25252 }
25253
25254 if ($caller === 'php') {
25255 return "@echo off\r\n".
25256 "pushd .\r\n".
25257 "cd %~dp0\r\n".
25258 "set PHP_PROXY=%CD%\\composer-php.bat\r\n".
25259 "cd ".ProcessExecutor::escape(dirname($binPath))."\r\n".
25260 "set BIN_TARGET=%CD%\\".basename($binPath)."\r\n".
25261 "popd\r\n".
25262 "%PHP_PROXY% \"%BIN_TARGET%\" %*\r\n";
25263 }
25264 }
25265
25266 return "@echo off\r\n".
25267 "pushd .\r\n".
25268 "cd %~dp0\r\n".
25269 "cd ".ProcessExecutor::escape(dirname($binPath))."\r\n".
25270 "set BIN_TARGET=%CD%\\".basename($binPath)."\r\n".
25271 "popd\r\n".
25272 $caller." \"%BIN_TARGET%\" %*\r\n";
25273 }
25274
25275 private function generateWindowsPhpProxyCode()
25276 {
25277 $binToVendor = $this->filesystem->findShortestPath($this->binDir, $this->vendorDir, true);
25278
25279 return
25280 "@echo off\r\n" .
25281 "setlocal enabledelayedexpansion\r\n" .
25282 "set BIN_DIR=%~dp0\r\n" .
25283 "set VENDOR_DIR=%BIN_DIR%\\".$binToVendor."\r\n" .
25284 "set DIRS=.\r\n" .
25285 "FOR /D %%V IN (%VENDOR_DIR%\\*) DO (\r\n" .
25286 "    FOR /D %%P IN (%%V\\*) DO (\r\n" .
25287 "        set DIRS=!DIRS!;%%~fP\r\n" .
25288 "    )\r\n" .
25289 ")\r\n" .
25290 "php.exe -d include_path=!DIRS! %*\r\n";
25291 }
25292
25293 private function generateUnixyPhpProxyCode()
25294 {
25295 $binToVendor = $this->filesystem->findShortestPath($this->binDir, $this->vendorDir, true);
25296
25297 return
25298 "#!/usr/bin/env sh\n".
25299 "SRC_DIR=`pwd`\n".
25300 "BIN_DIR=`dirname $0`\n".
25301 "VENDOR_DIR=\$BIN_DIR/".escapeshellarg($binToVendor)."\n".
25302 "DIRS=\"\"\n".
25303 "for vendor in \$VENDOR_DIR/*; do\n".
25304 "    if [ -d \"\$vendor\" ]; then\n".
25305 "        for package in \$vendor/*; do\n".
25306 "            if [ -d \"\$package\" ]; then\n".
25307 "                DIRS=\"\${DIRS}:\${package}\"\n".
25308 "            fi\n".
25309 "        done\n".
25310 "    fi\n".
25311 "done\n".
25312 "php -d include_path=\".\$DIRS\" $@\n";
25313 }
25314 }
25315 <?php
25316
25317
25318
25319
25320
25321
25322
25323
25324
25325
25326
25327 namespace Composer\Installer;
25328
25329 use Composer\IO\IOInterface;
25330 use Composer\Composer;
25331 use Composer\Downloader\PearPackageExtractor;
25332 use Composer\Repository\InstalledRepositoryInterface;
25333 use Composer\Package\PackageInterface;
25334 use Composer\Util\Platform;
25335 use Composer\Util\Filesystem;
25336
25337
25338
25339
25340
25341
25342
25343 class PearInstaller extends LibraryInstaller
25344 {
25345
25346
25347
25348
25349
25350
25351
25352 public function __construct(IOInterface $io, Composer $composer, $type = 'pear-library')
25353 {
25354 $filesystem = new Filesystem();
25355 $binaryInstaller = new PearBinaryInstaller($io, rtrim($composer->getConfig()->get('bin-dir'), '/'), rtrim($composer->getConfig()->get('vendor-dir'), '/'), $composer->getConfig()->get('bin-compat'), $filesystem, $this);
25356
25357 parent::__construct($io, $composer, $type, $filesystem, $binaryInstaller);
25358 }
25359
25360
25361
25362
25363 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
25364 {
25365 $this->uninstall($repo, $initial);
25366 $this->install($repo, $target);
25367 }
25368
25369 protected function installCode(PackageInterface $package)
25370 {
25371 parent::installCode($package);
25372
25373 $isWindows = Platform::isWindows();
25374 $php_bin = $this->binDir . ($isWindows ? '/composer-php.bat' : '/composer-php');
25375
25376 if (!$isWindows) {
25377 $php_bin = '/usr/bin/env ' . $php_bin;
25378 }
25379
25380 $installPath = $this->getInstallPath($package);
25381 $vars = array(
25382 'os' => $isWindows ? 'windows' : 'linux',
25383 'php_bin' => $php_bin,
25384 'pear_php' => $installPath,
25385 'php_dir' => $installPath,
25386 'bin_dir' => $installPath . '/bin',
25387 'data_dir' => $installPath . '/data',
25388 'version' => $package->getPrettyVersion(),
25389 );
25390
25391 $packageArchive = $this->getInstallPath($package).'/'.pathinfo($package->getDistUrl(), PATHINFO_BASENAME);
25392 $pearExtractor = new PearPackageExtractor($packageArchive);
25393 $pearExtractor->extractTo($this->getInstallPath($package), array('php' => '/', 'script' => '/bin', 'data' => '/data'), $vars);
25394
25395 $this->io->writeError('    Cleaning up', true, IOInterface::VERBOSE);
25396 $this->filesystem->unlink($packageArchive);
25397 }
25398 }
25399 <?php
25400
25401
25402
25403
25404
25405
25406
25407
25408
25409
25410
25411 namespace Composer\Installer;
25412
25413 use Composer\Composer;
25414 use Composer\IO\IOInterface;
25415 use Composer\Repository\InstalledRepositoryInterface;
25416 use Composer\Package\PackageInterface;
25417
25418
25419
25420
25421
25422
25423
25424 class PluginInstaller extends LibraryInstaller
25425 {
25426 private $installationManager;
25427
25428
25429
25430
25431
25432
25433
25434 public function __construct(IOInterface $io, Composer $composer)
25435 {
25436 parent::__construct($io, $composer, 'composer-plugin');
25437 $this->installationManager = $composer->getInstallationManager();
25438 }
25439
25440
25441
25442
25443 public function supports($packageType)
25444 {
25445 return $packageType === 'composer-plugin' || $packageType === 'composer-installer';
25446 }
25447
25448
25449
25450
25451 public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
25452 {
25453 $extra = $package->getExtra();
25454 if (empty($extra['class'])) {
25455 throw new \UnexpectedValueException('Error while installing '.$package->getPrettyName().', composer-plugin packages should have a class defined in their extra key to be usable.');
25456 }
25457
25458 parent::install($repo, $package);
25459 try {
25460 $this->composer->getPluginManager()->registerPackage($package, true);
25461 } catch (\Exception $e) {
25462
25463 $this->io->writeError('Plugin installation failed ('.$e->getMessage().'), rolling back');
25464 parent::uninstall($repo, $package);
25465 throw $e;
25466 }
25467 }
25468
25469
25470
25471
25472 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
25473 {
25474 $extra = $target->getExtra();
25475 if (empty($extra['class'])) {
25476 throw new \UnexpectedValueException('Error while installing '.$target->getPrettyName().', composer-plugin packages should have a class defined in their extra key to be usable.');
25477 }
25478
25479 parent::update($repo, $initial, $target);
25480 $this->composer->getPluginManager()->registerPackage($target, true);
25481 }
25482 }
25483 <?php
25484
25485
25486
25487
25488
25489
25490
25491
25492
25493
25494
25495 namespace Composer\Installer;
25496
25497 use Composer\Package\PackageInterface;
25498 use Composer\Downloader\DownloadManager;
25499 use Composer\Repository\InstalledRepositoryInterface;
25500 use Composer\Util\Filesystem;
25501
25502
25503
25504
25505
25506
25507
25508 class ProjectInstaller implements InstallerInterface
25509 {
25510 private $installPath;
25511 private $downloadManager;
25512 private $filesystem;
25513
25514 public function __construct($installPath, DownloadManager $dm)
25515 {
25516 $this->installPath = rtrim(strtr($installPath, '\\', '/'), '/').'/';
25517 $this->downloadManager = $dm;
25518 $this->filesystem = new Filesystem;
25519 }
25520
25521
25522
25523
25524
25525
25526
25527 public function supports($packageType)
25528 {
25529 return true;
25530 }
25531
25532
25533
25534
25535 public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
25536 {
25537 return false;
25538 }
25539
25540
25541
25542
25543 public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
25544 {
25545 $installPath = $this->installPath;
25546 if (file_exists($installPath) && !$this->filesystem->isDirEmpty($installPath)) {
25547 throw new \InvalidArgumentException("Project directory $installPath is not empty.");
25548 }
25549 if (!is_dir($installPath)) {
25550 mkdir($installPath, 0777, true);
25551 }
25552 $this->downloadManager->download($package, $installPath);
25553 }
25554
25555
25556
25557
25558 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
25559 {
25560 throw new \InvalidArgumentException("not supported");
25561 }
25562
25563
25564
25565
25566 public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
25567 {
25568 throw new \InvalidArgumentException("not supported");
25569 }
25570
25571
25572
25573
25574
25575
25576
25577 public function getInstallPath(PackageInterface $package)
25578 {
25579 return $this->installPath;
25580 }
25581 }
25582 <?php
25583
25584
25585
25586
25587
25588
25589
25590
25591
25592
25593
25594 namespace Composer\Installer;
25595
25596 use Composer\IO\IOInterface;
25597 use Composer\Package\PackageInterface;
25598 use Composer\Repository\RepositoryInterface;
25599 use Symfony\Component\Console\Formatter\OutputFormatter;
25600
25601
25602
25603
25604
25605
25606 class SuggestedPackagesReporter
25607 {
25608
25609
25610
25611 protected $suggestedPackages = array();
25612
25613
25614
25615
25616 private $io;
25617
25618 public function __construct(IOInterface $io)
25619 {
25620 $this->io = $io;
25621 }
25622
25623
25624
25625
25626 public function getPackages()
25627 {
25628 return $this->suggestedPackages;
25629 }
25630
25631
25632
25633
25634
25635
25636
25637
25638
25639
25640
25641
25642 public function addPackage($source, $target, $reason)
25643 {
25644 $this->suggestedPackages[] = array(
25645 'source' => $source,
25646 'target' => $target,
25647 'reason' => $reason,
25648 );
25649
25650 return $this;
25651 }
25652
25653
25654
25655
25656
25657
25658
25659 public function addSuggestionsFromPackage(PackageInterface $package)
25660 {
25661 $source = $package->getPrettyName();
25662 foreach ($package->getSuggests() as $target => $reason) {
25663 $this->addPackage(
25664 $source,
25665 $target,
25666 $reason
25667 );
25668 }
25669
25670 return $this;
25671 }
25672
25673
25674
25675
25676
25677
25678
25679
25680 public function output(RepositoryInterface $installedRepo = null)
25681 {
25682 $suggestedPackages = $this->getPackages();
25683 $installedPackages = array();
25684 if (null !== $installedRepo && ! empty($suggestedPackages)) {
25685 foreach ($installedRepo->getPackages() as $package) {
25686 $installedPackages = array_merge(
25687 $installedPackages,
25688 $package->getNames()
25689 );
25690 }
25691 }
25692
25693 foreach ($suggestedPackages as $suggestion) {
25694 if (in_array($suggestion['target'], $installedPackages)) {
25695 continue;
25696 }
25697
25698 $this->io->writeError(sprintf(
25699 '%s suggests installing %s%s',
25700 $suggestion['source'],
25701 $this->escapeOutput($suggestion['target']),
25702 $this->escapeOutput('' !== $suggestion['reason'] ? ' ('.$suggestion['reason'].')' : '')
25703 ));
25704 }
25705
25706 return $this;
25707 }
25708
25709
25710
25711
25712
25713 private function escapeOutput($string)
25714 {
25715 return OutputFormatter::escape(
25716 $this->removeControlCharacters($string)
25717 );
25718 }
25719
25720
25721
25722
25723
25724 private function removeControlCharacters($string)
25725 {
25726 return preg_replace(
25727 '/[[:cntrl:]]/',
25728 '',
25729 str_replace("\n", ' ', $string)
25730 );
25731 }
25732 }
25733 <?php
25734
25735
25736
25737
25738
25739
25740
25741
25742
25743
25744
25745 namespace Composer\Json;
25746
25747 use JsonSchema\Validator;
25748 use Seld\JsonLint\JsonParser;
25749 use Seld\JsonLint\ParsingException;
25750 use Composer\Util\RemoteFilesystem;
25751 use Composer\IO\IOInterface;
25752 use Composer\Downloader\TransportException;
25753
25754
25755
25756
25757
25758
25759
25760 class JsonFile
25761 {
25762 const LAX_SCHEMA = 1;
25763 const STRICT_SCHEMA = 2;
25764
25765 const JSON_UNESCAPED_SLASHES = 64;
25766 const JSON_PRETTY_PRINT = 128;
25767 const JSON_UNESCAPED_UNICODE = 256;
25768
25769 const COMPOSER_SCHEMA_PATH = '/../../../res/composer-schema.json';
25770
25771 private $path;
25772 private $rfs;
25773 private $io;
25774
25775
25776
25777
25778
25779
25780
25781
25782
25783 public function __construct($path, RemoteFilesystem $rfs = null, IOInterface $io = null)
25784 {
25785 $this->path = $path;
25786
25787 if (null === $rfs && preg_match('{^https?://}i', $path)) {
25788 throw new \InvalidArgumentException('http urls require a RemoteFilesystem instance to be passed');
25789 }
25790 $this->rfs = $rfs;
25791 $this->io = $io;
25792 }
25793
25794
25795
25796
25797 public function getPath()
25798 {
25799 return $this->path;
25800 }
25801
25802
25803
25804
25805
25806
25807 public function exists()
25808 {
25809 return is_file($this->path);
25810 }
25811
25812
25813
25814
25815
25816
25817
25818 public function read()
25819 {
25820 try {
25821 if ($this->rfs) {
25822 $json = $this->rfs->getContents($this->path, $this->path, false);
25823 } else {
25824 if ($this->io && $this->io->isDebug()) {
25825 $this->io->writeError('Reading ' . $this->path);
25826 }
25827 $json = file_get_contents($this->path);
25828 }
25829 } catch (TransportException $e) {
25830 throw new \RuntimeException($e->getMessage(), 0, $e);
25831 } catch (\Exception $e) {
25832 throw new \RuntimeException('Could not read '.$this->path."\n\n".$e->getMessage());
25833 }
25834
25835 return static::parseJson($json, $this->path);
25836 }
25837
25838
25839
25840
25841
25842
25843
25844
25845 public function write(array $hash, $options = 448)
25846 {
25847 $dir = dirname($this->path);
25848 if (!is_dir($dir)) {
25849 if (file_exists($dir)) {
25850 throw new \UnexpectedValueException(
25851 $dir.' exists and is not a directory.'
25852 );
25853 }
25854 if (!@mkdir($dir, 0777, true)) {
25855 throw new \UnexpectedValueException(
25856 $dir.' does not exist and could not be created.'
25857 );
25858 }
25859 }
25860
25861 $retries = 3;
25862 while ($retries--) {
25863 try {
25864 $this->filePutContentsIfModified($this->path, static::encode($hash, $options). ($options & self::JSON_PRETTY_PRINT ? "\n" : ''));
25865 break;
25866 } catch (\Exception $e) {
25867 if ($retries) {
25868 usleep(500000);
25869 continue;
25870 }
25871
25872 throw $e;
25873 }
25874 }
25875 }
25876
25877
25878
25879
25880 private function filePutContentsIfModified($path, $content)
25881 {
25882 $currentContent = @file_get_contents($path);
25883 if (!$currentContent || ($currentContent != $content)) {
25884 return file_put_contents($path, $content);
25885 }
25886
25887 return 0;
25888 }
25889
25890
25891
25892
25893
25894
25895
25896
25897
25898 public function validateSchema($schema = self::STRICT_SCHEMA, $schemaFile = null)
25899 {
25900 $content = file_get_contents($this->path);
25901 $data = json_decode($content);
25902
25903 if (null === $data && 'null' !== $content) {
25904 self::validateSyntax($content, $this->path);
25905 }
25906
25907 if (null === $schemaFile) {
25908 $schemaFile = __DIR__ . self::COMPOSER_SCHEMA_PATH;
25909 }
25910
25911
25912 if (false === strpos($schemaFile, '://')) {
25913 $schemaFile = 'file://' . $schemaFile;
25914 }
25915
25916 $schemaData = (object) array('$ref' => $schemaFile);
25917
25918 if ($schema === self::LAX_SCHEMA) {
25919 $schemaData->additionalProperties = true;
25920 $schemaData->required = array();
25921 }
25922
25923 $validator = new Validator();
25924 $validator->check($data, $schemaData);
25925
25926
25927
25928 if (!$validator->isValid()) {
25929 $errors = array();
25930 foreach ((array) $validator->getErrors() as $error) {
25931 $errors[] = ($error['property'] ? $error['property'].' : ' : '').$error['message'];
25932 }
25933 throw new JsonValidationException('"'.$this->path.'" does not match the expected JSON schema', $errors);
25934 }
25935
25936 return true;
25937 }
25938
25939
25940
25941
25942
25943
25944
25945
25946 public static function encode($data, $options = 448)
25947 {
25948 if (PHP_VERSION_ID >= 50400) {
25949 $json = json_encode($data, $options);
25950 if (false === $json) {
25951 self::throwEncodeError(json_last_error());
25952 }
25953
25954
25955 if (PHP_VERSION_ID < 50428 || (PHP_VERSION_ID >= 50500 && PHP_VERSION_ID < 50512) || (defined('JSON_C_VERSION') && version_compare(phpversion('json'), '1.3.6', '<'))) {
25956 $json = preg_replace('/\[\s+\]/', '[]', $json);
25957 $json = preg_replace('/\{\s+\}/', '{}', $json);
25958 }
25959
25960 return $json;
25961 }
25962
25963 $json = json_encode($data);
25964 if (false === $json) {
25965 self::throwEncodeError(json_last_error());
25966 }
25967
25968 $prettyPrint = (bool) ($options & self::JSON_PRETTY_PRINT);
25969 $unescapeUnicode = (bool) ($options & self::JSON_UNESCAPED_UNICODE);
25970 $unescapeSlashes = (bool) ($options & self::JSON_UNESCAPED_SLASHES);
25971
25972 if (!$prettyPrint && !$unescapeUnicode && !$unescapeSlashes) {
25973 return $json;
25974 }
25975
25976 return JsonFormatter::format($json, $unescapeUnicode, $unescapeSlashes);
25977 }
25978
25979
25980
25981
25982
25983
25984
25985 private static function throwEncodeError($code)
25986 {
25987 switch ($code) {
25988 case JSON_ERROR_DEPTH:
25989 $msg = 'Maximum stack depth exceeded';
25990 break;
25991 case JSON_ERROR_STATE_MISMATCH:
25992 $msg = 'Underflow or the modes mismatch';
25993 break;
25994 case JSON_ERROR_CTRL_CHAR:
25995 $msg = 'Unexpected control character found';
25996 break;
25997 case JSON_ERROR_UTF8:
25998 $msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
25999 break;
26000 default:
26001 $msg = 'Unknown error';
26002 }
26003
26004 throw new \RuntimeException('JSON encoding failed: '.$msg);
26005 }
26006
26007
26008
26009
26010
26011
26012
26013
26014
26015 public static function parseJson($json, $file = null)
26016 {
26017 if (null === $json) {
26018 return;
26019 }
26020 $data = json_decode($json, true);
26021 if (null === $data && JSON_ERROR_NONE !== json_last_error()) {
26022 self::validateSyntax($json, $file);
26023 }
26024
26025 return $data;
26026 }
26027
26028
26029
26030
26031
26032
26033
26034
26035
26036
26037 protected static function validateSyntax($json, $file = null)
26038 {
26039 $parser = new JsonParser();
26040 $result = $parser->lint($json);
26041 if (null === $result) {
26042 if (defined('JSON_ERROR_UTF8') && JSON_ERROR_UTF8 === json_last_error()) {
26043 throw new \UnexpectedValueException('"'.$file.'" is not UTF-8, could not parse as JSON');
26044 }
26045
26046 return true;
26047 }
26048
26049 throw new ParsingException('"'.$file.'" does not contain valid JSON'."\n".$result->getMessage(), $result->getDetails());
26050 }
26051 }
26052 <?php
26053
26054
26055
26056
26057
26058
26059
26060
26061
26062
26063
26064 namespace Composer\Json;
26065
26066
26067
26068
26069
26070
26071
26072
26073
26074 class JsonFormatter
26075 {
26076
26077
26078
26079
26080
26081
26082
26083
26084
26085
26086
26087
26088 public static function format($json, $unescapeUnicode, $unescapeSlashes)
26089 {
26090 $result = '';
26091 $pos = 0;
26092 $strLen = strlen($json);
26093 $indentStr = '    ';
26094 $newLine = "\n";
26095 $outOfQuotes = true;
26096 $buffer = '';
26097 $noescape = true;
26098
26099 for ($i = 0; $i < $strLen; $i++) {
26100
26101 $char = substr($json, $i, 1);
26102
26103
26104 if ('"' === $char && $noescape) {
26105 $outOfQuotes = !$outOfQuotes;
26106 }
26107
26108 if (!$outOfQuotes) {
26109 $buffer .= $char;
26110 $noescape = '\\' === $char ? !$noescape : true;
26111 continue;
26112 } elseif ('' !== $buffer) {
26113 if ($unescapeSlashes) {
26114 $buffer = str_replace('\\/', '/', $buffer);
26115 }
26116
26117 if ($unescapeUnicode && function_exists('mb_convert_encoding')) {
26118
26119 $buffer = preg_replace_callback('/(\\\\+)u([0-9a-f]{4})/i', function ($match) {
26120 $l = strlen($match[1]);
26121
26122 if ($l % 2) {
26123 $code = hexdec($match[2]);
26124
26125
26126 if (0xD800 <= $code && 0xDFFF >= $code) {
26127 return $match[0];
26128 }
26129
26130 return str_repeat('\\', $l - 1) . mb_convert_encoding(
26131 pack('H*', $match[2]),
26132 'UTF-8',
26133 'UCS-2BE'
26134 );
26135 }
26136
26137 return $match[0];
26138 }, $buffer);
26139 }
26140
26141 $result .= $buffer.$char;
26142 $buffer = '';
26143 continue;
26144 }
26145
26146 if (':' === $char) {
26147
26148 $char .= ' ';
26149 } elseif ('}' === $char || ']' === $char) {
26150 $pos--;
26151 $prevChar = substr($json, $i - 1, 1);
26152
26153 if ('{' !== $prevChar && '[' !== $prevChar) {
26154
26155
26156 $result .= $newLine;
26157 for ($j = 0; $j < $pos; $j++) {
26158 $result .= $indentStr;
26159 }
26160 } else {
26161
26162 $result = rtrim($result);
26163 }
26164 }
26165
26166 $result .= $char;
26167
26168
26169
26170 if (',' === $char || '{' === $char || '[' === $char) {
26171 $result .= $newLine;
26172
26173 if ('{' === $char || '[' === $char) {
26174 $pos++;
26175 }
26176
26177 for ($j = 0; $j < $pos; $j++) {
26178 $result .= $indentStr;
26179 }
26180 }
26181 }
26182
26183 return $result;
26184 }
26185 }
26186 <?php
26187
26188
26189
26190
26191
26192
26193
26194
26195
26196
26197
26198 namespace Composer\Json;
26199
26200 use Composer\Repository\PlatformRepository;
26201
26202
26203
26204
26205 class JsonManipulator
26206 {
26207 private static $DEFINES = '(?(DEFINE)
26208        (?<number>   -? (?= [1-9]|0(?!\d) ) \d+ (\.\d+)? ([eE] [+-]? \d+)? )
26209        (?<boolean>   true | false | null )
26210        (?<string>    " ([^"\\\\]* | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9A-Fa-f]{4} )* " )
26211        (?<array>     \[  (?:  (?&json) \s* (?: , (?&json) \s* )*  )?  \s* \] )
26212        (?<pair>      \s* (?&string) \s* : (?&json) \s* )
26213        (?<object>    \{  (?:  (?&pair)  (?: , (?&pair)  )*  )?  \s* \} )
26214        (?<json>   \s* (?: (?&number) | (?&boolean) | (?&string) | (?&array) | (?&object) ) )
26215     )';
26216
26217 private $contents;
26218 private $newline;
26219 private $indent;
26220
26221 public function __construct($contents)
26222 {
26223 $contents = trim($contents);
26224 if ($contents === '') {
26225 $contents = '{}';
26226 }
26227 if (!$this->pregMatch('#^\{(.*)\}$#s', $contents)) {
26228 throw new \InvalidArgumentException('The json file must be an object ({})');
26229 }
26230 $this->newline = false !== strpos($contents, "\r\n") ? "\r\n" : "\n";
26231 $this->contents = $contents === '{}' ? '{' . $this->newline . '}' : $contents;
26232 $this->detectIndenting();
26233 }
26234
26235 public function getContents()
26236 {
26237 return $this->contents . $this->newline;
26238 }
26239
26240 public function addLink($type, $package, $constraint, $sortPackages = false)
26241 {
26242 $decoded = JsonFile::parseJson($this->contents);
26243
26244
26245 if (!isset($decoded[$type])) {
26246 return $this->addMainKey($type, array($package => $constraint));
26247 }
26248
26249 $regex = '{'.self::$DEFINES.'^(?P<start>\s*\{\s*(?:(?&string)\s*:\s*(?&json)\s*,\s*)*?)'.
26250 '(?P<property>'.preg_quote(JsonFile::encode($type)).'\s*:\s*)(?P<value>(?&json))(?P<end>.*)}sx';
26251 if (!$this->pregMatch($regex, $this->contents, $matches)) {
26252 return false;
26253 }
26254
26255 $links = $matches['value'];
26256
26257
26258 $packageRegex = str_replace('/', '\\\\?/', preg_quote($package));
26259 $regex = '{'.self::$DEFINES.'"(?P<package>'.$packageRegex.')"(\s*:\s*)(?&string)}ix';
26260 if ($this->pregMatch($regex, $links, $packageMatches)) {
26261
26262 $existingPackage = $packageMatches['package'];
26263 $packageRegex = str_replace('/', '\\\\?/', preg_quote($existingPackage));
26264 $links = preg_replace_callback('{'.self::$DEFINES.'"'.$packageRegex.'"(?P<separator>\s*:\s*)(?&string)}ix', function ($m) use ($existingPackage, $constraint) {
26265 return JsonFile::encode(str_replace('\\/', '/', $existingPackage)) . $m['separator'] . '"' . $constraint . '"';
26266 }, $links);
26267 } else {
26268 if ($this->pregMatch('#^\s*\{\s*\S+.*?(\s*\}\s*)$#s', $links, $match)) {
26269
26270 $links = preg_replace(
26271 '{'.preg_quote($match[1]).'$}',
26272
26273 addcslashes(',' . $this->newline . $this->indent . $this->indent . JsonFile::encode($package).': '.JsonFile::encode($constraint) . $match[1], '\\$'),
26274 $links
26275 );
26276 } else {
26277
26278 $links = '{' . $this->newline .
26279 $this->indent . $this->indent . JsonFile::encode($package).': '.JsonFile::encode($constraint) . $this->newline .
26280 $this->indent . '}';
26281 }
26282 }
26283
26284 if (true === $sortPackages) {
26285 $requirements = json_decode($links, true);
26286 $this->sortPackages($requirements);
26287 $links = $this->format($requirements);
26288 }
26289
26290 $this->contents = $matches['start'] . $matches['property'] . $links . $matches['end'];
26291
26292 return true;
26293 }
26294
26295
26296
26297
26298
26299
26300
26301
26302 private function sortPackages(array &$packages = array())
26303 {
26304 $prefix = function ($requirement) {
26305 if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $requirement)) {
26306 return preg_replace(
26307 array(
26308 '/^php/',
26309 '/^hhvm/',
26310 '/^ext/',
26311 '/^lib/',
26312 '/^\D/',
26313 ),
26314 array(
26315 '0-$0',
26316 '1-$0',
26317 '2-$0',
26318 '3-$0',
26319 '4-$0',
26320 ),
26321 $requirement
26322 );
26323 }
26324
26325 return '5-'.$requirement;
26326 };
26327
26328 uksort($packages, function ($a, $b) use ($prefix) {
26329 return strnatcmp($prefix($a), $prefix($b));
26330 });
26331 }
26332
26333 public function addRepository($name, $config)
26334 {
26335 return $this->addSubNode('repositories', $name, $config);
26336 }
26337
26338 public function removeRepository($name)
26339 {
26340 return $this->removeSubNode('repositories', $name);
26341 }
26342
26343 public function addConfigSetting($name, $value)
26344 {
26345 return $this->addSubNode('config', $name, $value);
26346 }
26347
26348 public function removeConfigSetting($name)
26349 {
26350 return $this->removeSubNode('config', $name);
26351 }
26352
26353 public function addProperty($name, $value)
26354 {
26355 if (substr($name, 0, 8) === 'suggest.') {
26356 return $this->addSubNode('suggest', substr($name, 8), $value);
26357 }
26358
26359 if (substr($name, 0, 6) === 'extra.') {
26360 return $this->addSubNode('extra', substr($name, 6), $value);
26361 }
26362
26363 if (substr($name, 0, 8) === 'scripts.') {
26364 return $this->addSubNode('scripts', substr($name, 8), $value);
26365 }
26366
26367 return $this->addMainKey($name, $value);
26368 }
26369
26370 public function removeProperty($name)
26371 {
26372 if (substr($name, 0, 8) === 'suggest.') {
26373 return $this->removeSubNode('suggest', substr($name, 8));
26374 }
26375
26376 if (substr($name, 0, 6) === 'extra.') {
26377 return $this->removeSubNode('extra', substr($name, 6));
26378 }
26379
26380 if (substr($name, 0, 8) === 'scripts.') {
26381 return $this->removeSubNode('scripts', substr($name, 8));
26382 }
26383
26384 return $this->removeMainKey($name);
26385 }
26386
26387 public function addSubNode($mainNode, $name, $value)
26388 {
26389 $decoded = JsonFile::parseJson($this->contents);
26390
26391 $subName = null;
26392 if (in_array($mainNode, array('config', 'extra', 'scripts')) && false !== strpos($name, '.')) {
26393 list($name, $subName) = explode('.', $name, 2);
26394 }
26395
26396
26397 if (!isset($decoded[$mainNode])) {
26398 if ($subName !== null) {
26399 $this->addMainKey($mainNode, array($name => array($subName => $value)));
26400 } else {
26401 $this->addMainKey($mainNode, array($name => $value));
26402 }
26403
26404 return true;
26405 }
26406
26407
26408 $nodeRegex = '{'.self::$DEFINES.'^(?P<start> \s* \{ \s* (?: (?&string) \s* : (?&json) \s* , \s* )*?'.
26409 preg_quote(JsonFile::encode($mainNode)).'\s*:\s*)(?P<content>(?&object))(?P<end>.*)}sx';
26410
26411 try {
26412 if (!$this->pregMatch($nodeRegex, $this->contents, $match)) {
26413 return false;
26414 }
26415 } catch (\RuntimeException $e) {
26416 if ($e->getCode() === PREG_BACKTRACK_LIMIT_ERROR) {
26417 return false;
26418 }
26419 throw $e;
26420 }
26421
26422 $children = $match['content'];
26423
26424 if (!@json_decode($children)) {
26425 return false;
26426 }
26427
26428 $that = $this;
26429
26430
26431 $childRegex = '{'.self::$DEFINES.'(?P<start>"'.preg_quote($name).'"\s*:\s*)(?P<content>(?&json))(?P<end>,?)}x';
26432 if ($this->pregMatch($childRegex, $children, $matches)) {
26433 $children = preg_replace_callback($childRegex, function ($matches) use ($subName, $value, $that) {
26434 if ($subName !== null) {
26435 $curVal = json_decode($matches['content'], true);
26436 if (!is_array($curVal)) {
26437 $curVal = array();
26438 }
26439 $curVal[$subName] = $value;
26440 $value = $curVal;
26441 }
26442
26443 return $matches['start'] . $that->format($value, 1) . $matches['end'];
26444 }, $children);
26445 } else {
26446 $this->pregMatch('#^{ \s*? (?P<content>\S+.*?)? (?P<trailingspace>\s*) }$#sx', $children, $match);
26447
26448 $whitespace = '';
26449 if (!empty($match['trailingspace'])) {
26450 $whitespace = $match['trailingspace'];
26451 }
26452
26453 if (!empty($match['content'])) {
26454 if ($subName !== null) {
26455 $value = array($subName => $value);
26456 }
26457
26458
26459 $children = preg_replace(
26460 '#'.$whitespace.'}$#',
26461 addcslashes(',' . $this->newline . $this->indent . $this->indent . JsonFile::encode($name).': '.$this->format($value, 1) . $whitespace . '}', '\\$'),
26462 $children
26463 );
26464 } else {
26465 if ($subName !== null) {
26466 $value = array($subName => $value);
26467 }
26468
26469
26470 $children = '{' . $this->newline . $this->indent . $this->indent . JsonFile::encode($name).': '.$this->format($value, 1) . $whitespace . '}';
26471 }
26472 }
26473
26474 $this->contents = preg_replace_callback($nodeRegex, function ($m) use ($children) {
26475 return $m['start'] . $children . $m['end'];
26476 }, $this->contents);
26477
26478 return true;
26479 }
26480
26481 public function removeSubNode($mainNode, $name)
26482 {
26483 $decoded = JsonFile::parseJson($this->contents);
26484
26485
26486 if (empty($decoded[$mainNode])) {
26487 return true;
26488 }
26489
26490
26491 $nodeRegex = '{'.self::$DEFINES.'^(?P<start> \s* \{ \s* (?: (?&string) \s* : (?&json) \s* , \s* )*?'.
26492 preg_quote(JsonFile::encode($mainNode)).'\s*:\s*)(?P<content>(?&object))(?P<end>.*)}sx';
26493 try {
26494 if (!$this->pregMatch($nodeRegex, $this->contents, $match)) {
26495 return false;
26496 }
26497 } catch (\RuntimeException $e) {
26498 if ($e->getCode() === PREG_BACKTRACK_LIMIT_ERROR) {
26499 return false;
26500 }
26501 throw $e;
26502 }
26503
26504 $children = $match['content'];
26505
26506
26507 if (!@json_decode($children, true)) {
26508 return false;
26509 }
26510
26511 $subName = null;
26512 if (in_array($mainNode, array('config', 'extra', 'scripts')) && false !== strpos($name, '.')) {
26513 list($name, $subName) = explode('.', $name, 2);
26514 }
26515
26516
26517 if (!isset($decoded[$mainNode][$name]) || ($subName && !isset($decoded[$mainNode][$name][$subName]))) {
26518 return true;
26519 }
26520
26521
26522 $keyRegex = str_replace('/', '\\\\?/', preg_quote($name));
26523 if ($this->pregMatch('{"'.$keyRegex.'"\s*:}i', $children)) {
26524
26525 if (preg_match_all('{'.self::$DEFINES.'"'.$keyRegex.'"\s*:\s*(?:(?&json))}x', $children, $matches)) {
26526 $bestMatch = '';
26527 foreach ($matches[0] as $match) {
26528 if (strlen($bestMatch) < strlen($match)) {
26529 $bestMatch = $match;
26530 }
26531 }
26532 $childrenClean = preg_replace('{,\s*'.preg_quote($bestMatch).'}i', '', $children, -1, $count);
26533 if (1 !== $count) {
26534 $childrenClean = preg_replace('{'.preg_quote($bestMatch).'\s*,?\s*}i', '', $childrenClean, -1, $count);
26535 if (1 !== $count) {
26536 return false;
26537 }
26538 }
26539 }
26540 } else {
26541 $childrenClean = $children;
26542 }
26543
26544
26545 $this->pregMatch('#^{ \s*? (?P<content>\S+.*?)? (?P<trailingspace>\s*) }$#sx', $childrenClean, $match);
26546 if (empty($match['content'])) {
26547 $newline = $this->newline;
26548 $indent = $this->indent;
26549
26550 $this->contents = preg_replace_callback($nodeRegex, function ($matches) use ($indent, $newline) {
26551 return $matches['start'] . '{' . $newline . $indent . '}' . $matches['end'];
26552 }, $this->contents);
26553
26554
26555 if ($subName !== null) {
26556 $curVal = json_decode($children, true);
26557 unset($curVal[$name][$subName]);
26558 $this->addSubNode($mainNode, $name, $curVal[$name]);
26559 }
26560
26561 return true;
26562 }
26563
26564 $that = $this;
26565 $this->contents = preg_replace_callback($nodeRegex, function ($matches) use ($that, $name, $subName, $childrenClean) {
26566 if ($subName !== null) {
26567 $curVal = json_decode($matches['content'], true);
26568 unset($curVal[$name][$subName]);
26569 $childrenClean = $that->format($curVal, 0);
26570 }
26571
26572 return $matches['start'] . $childrenClean . $matches['end'];
26573 }, $this->contents);
26574
26575 return true;
26576 }
26577
26578 public function addMainKey($key, $content)
26579 {
26580 $decoded = JsonFile::parseJson($this->contents);
26581 $content = $this->format($content);
26582
26583
26584 $regex = '{'.self::$DEFINES.'^(?P<start>\s*\{\s*(?:(?&string)\s*:\s*(?&json)\s*,\s*)*?)'.
26585 '(?P<key>'.preg_quote(JsonFile::encode($key)).'\s*:\s*(?&json))(?P<end>.*)}sx';
26586 if (isset($decoded[$key]) && $this->pregMatch($regex, $this->contents, $matches)) {
26587
26588 if (!@json_decode('{'.$matches['key'].'}')) {
26589 return false;
26590 }
26591
26592 $this->contents = $matches['start'] . JsonFile::encode($key).': '.$content . $matches['end'];
26593
26594 return true;
26595 }
26596
26597
26598 if ($this->pregMatch('#[^{\s](\s*)\}$#', $this->contents, $match)) {
26599 $this->contents = preg_replace(
26600 '#'.$match[1].'\}$#',
26601 addcslashes(',' . $this->newline . $this->indent . JsonFile::encode($key). ': '. $content . $this->newline . '}', '\\$'),
26602 $this->contents
26603 );
26604
26605 return true;
26606 }
26607
26608
26609 $this->contents = preg_replace(
26610 '#\}$#',
26611 addcslashes($this->indent . JsonFile::encode($key). ': '.$content . $this->newline . '}', '\\$'),
26612 $this->contents
26613 );
26614
26615 return true;
26616 }
26617
26618 public function removeMainKey($key)
26619 {
26620 $decoded = JsonFile::parseJson($this->contents);
26621
26622 if (!array_key_exists($key, $decoded)) {
26623 return true;
26624 }
26625
26626
26627 $regex = '{'.self::$DEFINES.'^(?P<start>\s*\{\s*(?:(?&string)\s*:\s*(?&json)\s*,\s*)*?)'.
26628 '(?P<removal>'.preg_quote(JsonFile::encode($key)).'\s*:\s*(?&json))\s*,?\s*(?P<end>.*)}sx';
26629 if ($this->pregMatch($regex, $this->contents, $matches)) {
26630
26631 if (!@json_decode('{'.$matches['removal'].'}')) {
26632 return false;
26633 }
26634
26635
26636 if (preg_match('#,\s*$#', $matches['start']) && preg_match('#^\}$#', $matches['end'])) {
26637 $matches['start'] = rtrim(preg_replace('#,(\s*)$#', '$1', $matches['start']), $this->indent);
26638 }
26639
26640 $this->contents = $matches['start'] . $matches['end'];
26641 if (preg_match('#^\{\s*\}\s*$#', $this->contents)) {
26642 $this->contents = "{\n}";
26643 }
26644
26645 return true;
26646 }
26647
26648 return false;
26649 }
26650
26651 public function format($data, $depth = 0)
26652 {
26653 if (is_array($data)) {
26654 reset($data);
26655
26656 if (is_numeric(key($data))) {
26657 foreach ($data as $key => $val) {
26658 $data[$key] = $this->format($val, $depth + 1);
26659 }
26660
26661 return '['.implode(', ', $data).']';
26662 }
26663
26664 $out = '{' . $this->newline;
26665 $elems = array();
26666 foreach ($data as $key => $val) {
26667 $elems[] = str_repeat($this->indent, $depth + 2) . JsonFile::encode($key). ': '.$this->format($val, $depth + 1);
26668 }
26669
26670 return $out . implode(','.$this->newline, $elems) . $this->newline . str_repeat($this->indent, $depth + 1) . '}';
26671 }
26672
26673 return JsonFile::encode($data);
26674 }
26675
26676 protected function detectIndenting()
26677 {
26678 if ($this->pregMatch('{^([ \t]+)"}m', $this->contents, $match)) {
26679 $this->indent = $match[1];
26680 } else {
26681 $this->indent = '    ';
26682 }
26683 }
26684
26685 protected function pregMatch($re, $str, &$matches = array())
26686 {
26687 $count = preg_match($re, $str, $matches);
26688
26689 if ($count === false) {
26690 switch (preg_last_error()) {
26691 case PREG_NO_ERROR:
26692 throw new \RuntimeException('Failed to execute regex: PREG_NO_ERROR', PREG_NO_ERROR);
26693 case PREG_INTERNAL_ERROR:
26694 throw new \RuntimeException('Failed to execute regex: PREG_INTERNAL_ERROR', PREG_INTERNAL_ERROR);
26695 case PREG_BACKTRACK_LIMIT_ERROR:
26696 throw new \RuntimeException('Failed to execute regex: PREG_BACKTRACK_LIMIT_ERROR', PREG_BACKTRACK_LIMIT_ERROR);
26697 case PREG_RECURSION_LIMIT_ERROR:
26698 throw new \RuntimeException('Failed to execute regex: PREG_RECURSION_LIMIT_ERROR', PREG_RECURSION_LIMIT_ERROR);
26699 case PREG_BAD_UTF8_ERROR:
26700 throw new \RuntimeException('Failed to execute regex: PREG_BAD_UTF8_ERROR', PREG_BAD_UTF8_ERROR);
26701 case PREG_BAD_UTF8_OFFSET_ERROR:
26702 throw new \RuntimeException('Failed to execute regex: PREG_BAD_UTF8_OFFSET_ERROR', PREG_BAD_UTF8_OFFSET_ERROR);
26703 case 6: 
26704 if (PHP_VERSION_ID > 70000) {
26705 throw new \RuntimeException('Failed to execute regex: PREG_JIT_STACKLIMIT_ERROR', 6);
26706 }
26707
26708 default:
26709 throw new \RuntimeException('Failed to execute regex: Unknown error');
26710 }
26711 }
26712
26713 return $count;
26714 }
26715 }
26716 <?php
26717
26718
26719
26720
26721
26722
26723
26724
26725
26726
26727
26728 namespace Composer\Json;
26729
26730 use Exception;
26731
26732
26733
26734
26735 class JsonValidationException extends Exception
26736 {
26737 protected $errors;
26738
26739 public function __construct($message, $errors = array(), Exception $previous = null)
26740 {
26741 $this->errors = $errors;
26742 parent::__construct($message, 0, $previous);
26743 }
26744
26745 public function getErrors()
26746 {
26747 return $this->errors;
26748 }
26749 }
26750 <?php
26751
26752
26753
26754
26755
26756
26757
26758
26759
26760
26761
26762 namespace Composer\Package;
26763
26764 use Composer\Semver\Constraint\Constraint;
26765 use Composer\Package\Version\VersionParser;
26766
26767
26768
26769
26770 class AliasPackage extends BasePackage implements CompletePackageInterface
26771 {
26772 protected $version;
26773 protected $prettyVersion;
26774 protected $dev;
26775 protected $rootPackageAlias = false;
26776 protected $stability;
26777
26778
26779 protected $aliasOf;
26780
26781 protected $requires;
26782
26783 protected $devRequires;
26784
26785 protected $conflicts;
26786
26787 protected $provides;
26788
26789 protected $replaces;
26790
26791
26792
26793
26794
26795
26796
26797
26798 public function __construct(PackageInterface $aliasOf, $version, $prettyVersion)
26799 {
26800 parent::__construct($aliasOf->getName());
26801
26802 $this->version = $version;
26803 $this->prettyVersion = $prettyVersion;
26804 $this->aliasOf = $aliasOf;
26805 $this->stability = VersionParser::parseStability($version);
26806 $this->dev = $this->stability === 'dev';
26807
26808 foreach (array('requires', 'devRequires', 'conflicts', 'provides', 'replaces') as $type) {
26809 $links = $aliasOf->{'get' . ucfirst($type)}();
26810 $this->$type = $this->replaceSelfVersionDependencies($links, $type);
26811 }
26812 }
26813
26814
26815
26816
26817 public function getAliasOf()
26818 {
26819 return $this->aliasOf;
26820 }
26821
26822
26823
26824
26825 public function getVersion()
26826 {
26827 return $this->version;
26828 }
26829
26830
26831
26832
26833 public function getStability()
26834 {
26835 return $this->stability;
26836 }
26837
26838
26839
26840
26841 public function getPrettyVersion()
26842 {
26843 return $this->prettyVersion;
26844 }
26845
26846
26847
26848
26849 public function isDev()
26850 {
26851 return $this->dev;
26852 }
26853
26854
26855
26856
26857 public function getRequires()
26858 {
26859 return $this->requires;
26860 }
26861
26862
26863
26864
26865 public function getConflicts()
26866 {
26867 return $this->conflicts;
26868 }
26869
26870
26871
26872
26873 public function getProvides()
26874 {
26875 return $this->provides;
26876 }
26877
26878
26879
26880
26881 public function getReplaces()
26882 {
26883 return $this->replaces;
26884 }
26885
26886
26887
26888
26889 public function getDevRequires()
26890 {
26891 return $this->devRequires;
26892 }
26893
26894
26895
26896
26897
26898
26899
26900
26901
26902
26903 public function setRootPackageAlias($value)
26904 {
26905 return $this->rootPackageAlias = $value;
26906 }
26907
26908
26909
26910
26911
26912 public function isRootPackageAlias()
26913 {
26914 return $this->rootPackageAlias;
26915 }
26916
26917
26918
26919
26920
26921
26922
26923 protected function replaceSelfVersionDependencies(array $links, $linkType)
26924 {
26925 if (in_array($linkType, array('conflicts', 'provides', 'replaces'), true)) {
26926 $newLinks = array();
26927 foreach ($links as $link) {
26928
26929 if ('self.version' === $link->getPrettyConstraint()) {
26930 $newLinks[] = new Link($link->getSource(), $link->getTarget(), new Constraint('=', $this->version), $linkType, $this->prettyVersion);
26931 }
26932 }
26933 $links = array_merge($links, $newLinks);
26934 } else {
26935 foreach ($links as $index => $link) {
26936 if ('self.version' === $link->getPrettyConstraint()) {
26937 $links[$index] = new Link($link->getSource(), $link->getTarget(), new Constraint('=', $this->version), $linkType, $this->prettyVersion);
26938 }
26939 }
26940 }
26941
26942 return $links;
26943 }
26944
26945
26946
26947
26948
26949 public function getType()
26950 {
26951 return $this->aliasOf->getType();
26952 }
26953
26954 public function getTargetDir()
26955 {
26956 return $this->aliasOf->getTargetDir();
26957 }
26958
26959 public function getExtra()
26960 {
26961 return $this->aliasOf->getExtra();
26962 }
26963
26964 public function setInstallationSource($type)
26965 {
26966 $this->aliasOf->setInstallationSource($type);
26967 }
26968
26969 public function getInstallationSource()
26970 {
26971 return $this->aliasOf->getInstallationSource();
26972 }
26973
26974 public function getSourceType()
26975 {
26976 return $this->aliasOf->getSourceType();
26977 }
26978
26979 public function getSourceUrl()
26980 {
26981 return $this->aliasOf->getSourceUrl();
26982 }
26983
26984 public function getSourceUrls()
26985 {
26986 return $this->aliasOf->getSourceUrls();
26987 }
26988
26989 public function getSourceReference()
26990 {
26991 return $this->aliasOf->getSourceReference();
26992 }
26993
26994 public function setSourceReference($reference)
26995 {
26996 return $this->aliasOf->setSourceReference($reference);
26997 }
26998
26999 public function setSourceMirrors($mirrors)
27000 {
27001 return $this->aliasOf->setSourceMirrors($mirrors);
27002 }
27003
27004 public function getSourceMirrors()
27005 {
27006 return $this->aliasOf->getSourceMirrors();
27007 }
27008
27009 public function getDistType()
27010 {
27011 return $this->aliasOf->getDistType();
27012 }
27013
27014 public function getDistUrl()
27015 {
27016 return $this->aliasOf->getDistUrl();
27017 }
27018
27019 public function getDistUrls()
27020 {
27021 return $this->aliasOf->getDistUrls();
27022 }
27023
27024 public function getDistReference()
27025 {
27026 return $this->aliasOf->getDistReference();
27027 }
27028
27029 public function setDistReference($reference)
27030 {
27031 return $this->aliasOf->setDistReference($reference);
27032 }
27033
27034 public function getDistSha1Checksum()
27035 {
27036 return $this->aliasOf->getDistSha1Checksum();
27037 }
27038
27039 public function setTransportOptions(array $options)
27040 {
27041 return $this->aliasOf->setTransportOptions($options);
27042 }
27043
27044 public function getTransportOptions()
27045 {
27046 return $this->aliasOf->getTransportOptions();
27047 }
27048
27049 public function setDistMirrors($mirrors)
27050 {
27051 return $this->aliasOf->setDistMirrors($mirrors);
27052 }
27053
27054 public function getDistMirrors()
27055 {
27056 return $this->aliasOf->getDistMirrors();
27057 }
27058
27059 public function getScripts()
27060 {
27061 return $this->aliasOf->getScripts();
27062 }
27063
27064 public function getLicense()
27065 {
27066 return $this->aliasOf->getLicense();
27067 }
27068
27069 public function getAutoload()
27070 {
27071 return $this->aliasOf->getAutoload();
27072 }
27073
27074 public function getDevAutoload()
27075 {
27076 return $this->aliasOf->getDevAutoload();
27077 }
27078
27079 public function getIncludePaths()
27080 {
27081 return $this->aliasOf->getIncludePaths();
27082 }
27083
27084 public function getRepositories()
27085 {
27086 return $this->aliasOf->getRepositories();
27087 }
27088
27089 public function getReleaseDate()
27090 {
27091 return $this->aliasOf->getReleaseDate();
27092 }
27093
27094 public function getBinaries()
27095 {
27096 return $this->aliasOf->getBinaries();
27097 }
27098
27099 public function getKeywords()
27100 {
27101 return $this->aliasOf->getKeywords();
27102 }
27103
27104 public function getDescription()
27105 {
27106 return $this->aliasOf->getDescription();
27107 }
27108
27109 public function getHomepage()
27110 {
27111 return $this->aliasOf->getHomepage();
27112 }
27113
27114 public function getSuggests()
27115 {
27116 return $this->aliasOf->getSuggests();
27117 }
27118
27119 public function getAuthors()
27120 {
27121 return $this->aliasOf->getAuthors();
27122 }
27123
27124 public function getSupport()
27125 {
27126 return $this->aliasOf->getSupport();
27127 }
27128
27129 public function getFunding()
27130 {
27131 return $this->aliasOf->getFunding();
27132 }
27133
27134 public function getNotificationUrl()
27135 {
27136 return $this->aliasOf->getNotificationUrl();
27137 }
27138
27139 public function getArchiveExcludes()
27140 {
27141 return $this->aliasOf->getArchiveExcludes();
27142 }
27143
27144 public function isAbandoned()
27145 {
27146 return $this->aliasOf->isAbandoned();
27147 }
27148
27149 public function getReplacementPackage()
27150 {
27151 return $this->aliasOf->getReplacementPackage();
27152 }
27153
27154 public function __toString()
27155 {
27156 return parent::__toString().' (alias of '.$this->aliasOf->getVersion().')';
27157 }
27158
27159 public function setDistUrl($url)
27160 {
27161 return $this->aliasOf->setDistUrl($url);
27162 }
27163
27164 public function setDistType($type)
27165 {
27166 return $this->aliasOf->setDistType($type);
27167 }
27168 }
27169 <?php
27170
27171
27172
27173
27174
27175
27176
27177
27178
27179
27180
27181 namespace Composer\Package\Archiver;
27182
27183 use FilterIterator;
27184 use PharData;
27185
27186 class ArchivableFilesFilter extends FilterIterator
27187 {
27188 private $dirs = array();
27189
27190
27191
27192
27193 public function accept()
27194 {
27195 $file = $this->getInnerIterator()->current();
27196 if ($file->isDir()) {
27197 $this->dirs[] = (string) $file;
27198
27199 return false;
27200 }
27201
27202 return true;
27203 }
27204
27205 public function addEmptyDir(PharData $phar, $sources)
27206 {
27207 foreach ($this->dirs as $filepath) {
27208 $localname = str_replace($sources . "/", '', $filepath);
27209 $phar->addEmptyDir($localname);
27210 }
27211 }
27212 }
27213 <?php
27214
27215
27216
27217
27218
27219
27220
27221
27222
27223
27224
27225 namespace Composer\Package\Archiver;
27226
27227 use Composer\Util\Filesystem;
27228 use FilesystemIterator;
27229 use Symfony\Component\Finder\Finder;
27230 use Symfony\Component\Finder\SplFileInfo;
27231
27232
27233
27234
27235
27236
27237
27238
27239
27240 class ArchivableFilesFinder extends \FilterIterator
27241 {
27242
27243
27244
27245 protected $finder;
27246
27247
27248
27249
27250
27251
27252
27253
27254 public function __construct($sources, array $excludes, $ignoreFilters = false)
27255 {
27256 $fs = new Filesystem();
27257
27258 $sources = $fs->normalizePath(realpath($sources));
27259
27260 if ($ignoreFilters) {
27261 $filters = array();
27262 } else {
27263 $filters = array(
27264 new HgExcludeFilter($sources),
27265 new GitExcludeFilter($sources),
27266 new ComposerExcludeFilter($sources, $excludes),
27267 );
27268 }
27269
27270 $this->finder = new Finder();
27271
27272 $filter = function (\SplFileInfo $file) use ($sources, $filters, $fs) {
27273 if ($file->isLink() && strpos($file->getRealPath(), $sources) !== 0) {
27274 return false;
27275 }
27276
27277 $relativePath = preg_replace(
27278 '#^'.preg_quote($sources, '#').'#',
27279 '',
27280 $fs->normalizePath($file->getRealPath())
27281 );
27282
27283 $exclude = false;
27284 foreach ($filters as $filter) {
27285 $exclude = $filter->filter($relativePath, $exclude);
27286 }
27287
27288 return !$exclude;
27289 };
27290
27291 if (method_exists($filter, 'bindTo')) {
27292 $filter = $filter->bindTo(null);
27293 }
27294
27295 $this->finder
27296 ->in($sources)
27297 ->filter($filter)
27298 ->ignoreVCS(true)
27299 ->ignoreDotFiles(false);
27300
27301 parent::__construct($this->finder->getIterator());
27302 }
27303
27304 public function accept()
27305 {
27306
27307 $current = $this->getInnerIterator()->current();
27308
27309 if (!$current->isDir()) {
27310 return true;
27311 }
27312
27313 $iterator = new FilesystemIterator($current, FilesystemIterator::SKIP_DOTS);
27314
27315 return !$iterator->valid();
27316 }
27317 }
27318 <?php
27319
27320
27321
27322
27323
27324
27325
27326
27327
27328
27329
27330 namespace Composer\Package\Archiver;
27331
27332 use Composer\Downloader\DownloadManager;
27333 use Composer\Package\PackageInterface;
27334 use Composer\Package\RootPackageInterface;
27335 use Composer\Util\Filesystem;
27336 use Composer\Json\JsonFile;
27337
27338
27339
27340
27341
27342 class ArchiveManager
27343 {
27344 protected $downloadManager;
27345
27346 protected $archivers = array();
27347
27348
27349
27350
27351 protected $overwriteFiles = true;
27352
27353
27354
27355
27356 public function __construct(DownloadManager $downloadManager)
27357 {
27358 $this->downloadManager = $downloadManager;
27359 }
27360
27361
27362
27363
27364 public function addArchiver(ArchiverInterface $archiver)
27365 {
27366 $this->archivers[] = $archiver;
27367 }
27368
27369
27370
27371
27372
27373
27374
27375
27376 public function setOverwriteFiles($overwriteFiles)
27377 {
27378 $this->overwriteFiles = $overwriteFiles;
27379
27380 return $this;
27381 }
27382
27383
27384
27385
27386
27387
27388
27389
27390 public function getPackageFilename(PackageInterface $package)
27391 {
27392 $nameParts = array(preg_replace('#[^a-z0-9-_]#i', '-', $package->getName()));
27393
27394 if (preg_match('{^[a-f0-9]{40}$}', $package->getDistReference())) {
27395 array_push($nameParts, $package->getDistReference(), $package->getDistType());
27396 } else {
27397 array_push($nameParts, $package->getPrettyVersion(), $package->getDistReference());
27398 }
27399
27400 if ($package->getSourceReference()) {
27401 $nameParts[] = substr(sha1($package->getSourceReference()), 0, 6);
27402 }
27403
27404 $name = implode('-', array_filter($nameParts, function ($p) {
27405 return !empty($p);
27406 }));
27407
27408 return str_replace('/', '-', $name);
27409 }
27410
27411
27412
27413
27414
27415
27416
27417
27418
27419
27420
27421
27422
27423
27424 public function archive(PackageInterface $package, $format, $targetDir, $fileName = null, $ignoreFilters = false)
27425 {
27426 if (empty($format)) {
27427 throw new \InvalidArgumentException('Format must be specified');
27428 }
27429
27430
27431 $usableArchiver = null;
27432 foreach ($this->archivers as $archiver) {
27433 if ($archiver->supports($format, $package->getSourceType())) {
27434 $usableArchiver = $archiver;
27435 break;
27436 }
27437 }
27438
27439
27440 if (null === $usableArchiver) {
27441 throw new \RuntimeException(sprintf('No archiver found to support %s format', $format));
27442 }
27443
27444 $filesystem = new Filesystem();
27445 if (null === $fileName) {
27446 $packageName = $this->getPackageFilename($package);
27447 } else {
27448 $packageName = $fileName;
27449 }
27450
27451
27452 $filesystem->ensureDirectoryExists($targetDir);
27453 $target = realpath($targetDir).'/'.$packageName.'.'.$format;
27454 $filesystem->ensureDirectoryExists(dirname($target));
27455
27456 if (!$this->overwriteFiles && file_exists($target)) {
27457 return $target;
27458 }
27459
27460 if ($package instanceof RootPackageInterface) {
27461 $sourcePath = realpath('.');
27462 } else {
27463
27464 $sourcePath = sys_get_temp_dir().'/composer_archive'.uniqid();
27465 $filesystem->ensureDirectoryExists($sourcePath);
27466
27467 try {
27468
27469 $this->downloadManager->download($package, $sourcePath);
27470 } catch (\Exception $e) {
27471 $filesystem->removeDirectory($sourcePath);
27472 throw $e;
27473 }
27474
27475
27476 if (file_exists($composerJsonPath = $sourcePath.'/composer.json')) {
27477 $jsonFile = new JsonFile($composerJsonPath);
27478 $jsonData = $jsonFile->read();
27479 if (!empty($jsonData['archive']['exclude'])) {
27480 $package->setArchiveExcludes($jsonData['archive']['exclude']);
27481 }
27482 }
27483 }
27484
27485
27486 $tempTarget = sys_get_temp_dir().'/composer_archive'.uniqid().'.'.$format;
27487 $filesystem->ensureDirectoryExists(dirname($tempTarget));
27488
27489 $archivePath = $usableArchiver->archive($sourcePath, $tempTarget, $format, $package->getArchiveExcludes(), $ignoreFilters);
27490 $filesystem->rename($archivePath, $target);
27491
27492
27493 if (!$package instanceof RootPackageInterface) {
27494 $filesystem->removeDirectory($sourcePath);
27495 }
27496 $filesystem->remove($tempTarget);
27497
27498 return $target;
27499 }
27500 }
27501 <?php
27502
27503
27504
27505
27506
27507
27508
27509
27510
27511
27512
27513 namespace Composer\Package\Archiver;
27514
27515
27516
27517
27518
27519
27520 interface ArchiverInterface
27521 {
27522
27523
27524
27525
27526
27527
27528
27529
27530
27531
27532 public function archive($sources, $target, $format, array $excludes = array(), $ignoreFilters = false);
27533
27534
27535
27536
27537
27538
27539
27540
27541
27542 public function supports($format, $sourceType);
27543 }
27544 <?php
27545
27546
27547
27548
27549
27550
27551
27552
27553
27554
27555
27556 namespace Composer\Package\Archiver;
27557
27558 use Symfony\Component\Finder;
27559
27560
27561
27562
27563 abstract class BaseExcludeFilter
27564 {
27565
27566
27567
27568 protected $sourcePath;
27569
27570
27571
27572
27573 protected $excludePatterns;
27574
27575
27576
27577
27578 public function __construct($sourcePath)
27579 {
27580 $this->sourcePath = $sourcePath;
27581 $this->excludePatterns = array();
27582 }
27583
27584
27585
27586
27587
27588
27589
27590
27591
27592
27593
27594 public function filter($relativePath, $exclude)
27595 {
27596 foreach ($this->excludePatterns as $patternData) {
27597 list($pattern, $negate, $stripLeadingSlash) = $patternData;
27598
27599 if ($stripLeadingSlash) {
27600 $path = substr($relativePath, 1);
27601 } else {
27602 $path = $relativePath;
27603 }
27604
27605 if (@preg_match($pattern, $path)) {
27606 $exclude = !$negate;
27607 }
27608 }
27609
27610 return $exclude;
27611 }
27612
27613
27614
27615
27616
27617
27618
27619
27620
27621 protected function parseLines(array $lines, $lineParser)
27622 {
27623 return array_filter(
27624 array_map(
27625 function ($line) use ($lineParser) {
27626 $line = trim($line);
27627
27628 if (!$line || 0 === strpos($line, '#')) {
27629 return null;
27630 }
27631
27632 return call_user_func($lineParser, $line);
27633 },
27634 $lines
27635 ),
27636 function ($pattern) {
27637 return $pattern !== null;
27638 }
27639 );
27640 }
27641
27642
27643
27644
27645
27646
27647
27648
27649 protected function generatePatterns($rules)
27650 {
27651 $patterns = array();
27652 foreach ($rules as $rule) {
27653 $patterns[] = $this->generatePattern($rule);
27654 }
27655
27656 return $patterns;
27657 }
27658
27659
27660
27661
27662
27663
27664
27665
27666 protected function generatePattern($rule)
27667 {
27668 $negate = false;
27669 $pattern = '{';
27670
27671 if (strlen($rule) && $rule[0] === '!') {
27672 $negate = true;
27673 $rule = substr($rule, 1);
27674 }
27675
27676 if (strlen($rule) && $rule[0] === '/') {
27677 $pattern .= '^/';
27678 $rule = substr($rule, 1);
27679 } elseif (strlen($rule) - 1 === strpos($rule, '/')) {
27680 $pattern .= '/';
27681 $rule = substr($rule, 0, -1);
27682 } elseif (false === strpos($rule, '/')) {
27683 $pattern .= '/';
27684 }
27685
27686
27687 $pattern .= substr(Finder\Glob::toRegex($rule), 2, -2) . '(?=$|/)';
27688
27689 return array($pattern . '}', $negate, false);
27690 }
27691 }
27692 <?php
27693
27694
27695
27696
27697
27698
27699
27700
27701
27702
27703
27704 namespace Composer\Package\Archiver;
27705
27706
27707
27708
27709
27710
27711 class ComposerExcludeFilter extends BaseExcludeFilter
27712 {
27713
27714
27715
27716
27717 public function __construct($sourcePath, array $excludeRules)
27718 {
27719 parent::__construct($sourcePath);
27720 $this->excludePatterns = $this->generatePatterns($excludeRules);
27721 }
27722 }
27723 <?php
27724
27725
27726
27727
27728
27729
27730
27731
27732
27733
27734
27735 namespace Composer\Package\Archiver;
27736
27737
27738
27739
27740
27741
27742
27743
27744 class GitExcludeFilter extends BaseExcludeFilter
27745 {
27746
27747
27748
27749
27750
27751 public function __construct($sourcePath)
27752 {
27753 parent::__construct($sourcePath);
27754
27755 if (file_exists($sourcePath.'/.gitignore')) {
27756 $this->excludePatterns = $this->parseLines(
27757 file($sourcePath.'/.gitignore'),
27758 array($this, 'parseGitIgnoreLine')
27759 );
27760 }
27761 if (file_exists($sourcePath.'/.gitattributes')) {
27762 $this->excludePatterns = array_merge(
27763 $this->excludePatterns,
27764 $this->parseLines(
27765 file($sourcePath.'/.gitattributes'),
27766 array($this, 'parseGitAttributesLine')
27767 )
27768 );
27769 }
27770 }
27771
27772
27773
27774
27775
27776
27777
27778
27779 public function parseGitIgnoreLine($line)
27780 {
27781 return $this->generatePattern($line);
27782 }
27783
27784
27785
27786
27787
27788
27789
27790
27791 public function parseGitAttributesLine($line)
27792 {
27793 $parts = preg_split('#\s+#', $line);
27794
27795 if (count($parts) == 2 && $parts[1] === 'export-ignore') {
27796 return $this->generatePattern($parts[0]);
27797 }
27798
27799 return null;
27800 }
27801 }
27802 <?php
27803
27804
27805
27806
27807
27808
27809
27810
27811
27812
27813
27814 namespace Composer\Package\Archiver;
27815
27816 use Symfony\Component\Finder;
27817
27818
27819
27820
27821
27822
27823 class HgExcludeFilter extends BaseExcludeFilter
27824 {
27825 const HG_IGNORE_REGEX = 1;
27826 const HG_IGNORE_GLOB = 2;
27827
27828
27829
27830
27831
27832 protected $patternMode;
27833
27834
27835
27836
27837
27838
27839 public function __construct($sourcePath)
27840 {
27841 parent::__construct($sourcePath);
27842
27843 $this->patternMode = self::HG_IGNORE_REGEX;
27844
27845 if (file_exists($sourcePath.'/.hgignore')) {
27846 $this->excludePatterns = $this->parseLines(
27847 file($sourcePath.'/.hgignore'),
27848 array($this, 'parseHgIgnoreLine')
27849 );
27850 }
27851 }
27852
27853
27854
27855
27856
27857
27858
27859
27860 public function parseHgIgnoreLine($line)
27861 {
27862 if (preg_match('#^syntax\s*:\s*(glob|regexp)$#', $line, $matches)) {
27863 if ($matches[1] === 'glob') {
27864 $this->patternMode = self::HG_IGNORE_GLOB;
27865 } else {
27866 $this->patternMode = self::HG_IGNORE_REGEX;
27867 }
27868
27869 return null;
27870 }
27871
27872 if ($this->patternMode == self::HG_IGNORE_GLOB) {
27873 return $this->patternFromGlob($line);
27874 }
27875
27876 return $this->patternFromRegex($line);
27877 }
27878
27879
27880
27881
27882
27883
27884
27885
27886 protected function patternFromGlob($line)
27887 {
27888 $pattern = '#'.substr(Finder\Glob::toRegex($line), 2, -1).'#';
27889 $pattern = str_replace('[^/]*', '.*', $pattern);
27890
27891 return array($pattern, false, true);
27892 }
27893
27894
27895
27896
27897
27898
27899
27900
27901 public function patternFromRegex($line)
27902 {
27903
27904 $pattern = '#'.preg_replace('/((?:\\\\\\\\)*)(\\\\?)#/', '\1\2\2\\#', $line).'#';
27905
27906 return array($pattern, false, true);
27907 }
27908 }
27909 <?php
27910
27911
27912
27913
27914
27915
27916
27917
27918
27919
27920
27921 namespace Composer\Package\Archiver;
27922
27923
27924
27925
27926
27927
27928 class PharArchiver implements ArchiverInterface
27929 {
27930 protected static $formats = array(
27931 'zip' => \Phar::ZIP,
27932 'tar' => \Phar::TAR,
27933 'tar.gz' => \Phar::TAR,
27934 'tar.bz2' => \Phar::TAR,
27935 );
27936
27937 protected static $compressFormats = array(
27938 'tar.gz' => \Phar::GZ,
27939 'tar.bz2' => \Phar::BZ2,
27940 );
27941
27942
27943
27944
27945 public function archive($sources, $target, $format, array $excludes = array(), $ignoreFilters = false)
27946 {
27947 $sources = realpath($sources);
27948
27949
27950 if (file_exists($target)) {
27951 unlink($target);
27952 }
27953
27954 try {
27955 $filename = substr($target, 0, strrpos($target, $format) - 1);
27956
27957
27958 if (isset(static::$compressFormats[$format])) {
27959
27960 $target = $filename . '.tar';
27961 }
27962
27963 $phar = new \PharData($target, null, null, static::$formats[$format]);
27964 $files = new ArchivableFilesFinder($sources, $excludes, $ignoreFilters);
27965 $filesOnly = new ArchivableFilesFilter($files);
27966 $phar->buildFromIterator($filesOnly, $sources);
27967 $filesOnly->addEmptyDir($phar, $sources);
27968
27969 if (isset(static::$compressFormats[$format])) {
27970
27971 if (!$phar->canCompress(static::$compressFormats[$format])) {
27972 throw new \RuntimeException(sprintf('Can not compress to %s format', $format));
27973 }
27974
27975
27976 unlink($target);
27977
27978
27979 $phar->compress(static::$compressFormats[$format]);
27980
27981
27982 $target = $filename . '.' . $format;
27983 }
27984
27985 return $target;
27986 } catch (\UnexpectedValueException $e) {
27987 $message = sprintf(
27988 "Could not create archive '%s' from '%s': %s",
27989 $target,
27990 $sources,
27991 $e->getMessage()
27992 );
27993
27994 throw new \RuntimeException($message, $e->getCode(), $e);
27995 }
27996 }
27997
27998
27999
28000
28001 public function supports($format, $sourceType)
28002 {
28003 return isset(static::$formats[$format]);
28004 }
28005 }
28006 <?php
28007
28008
28009
28010
28011
28012
28013
28014
28015
28016
28017
28018 namespace Composer\Package\Archiver;
28019
28020 use ZipArchive;
28021 use Composer\Util\Filesystem;
28022
28023
28024
28025
28026 class ZipArchiver implements ArchiverInterface
28027 {
28028 protected static $formats = array(
28029 'zip' => 1,
28030 );
28031
28032
28033
28034
28035 public function archive($sources, $target, $format, array $excludes = array(), $ignoreFilters = false)
28036 {
28037 $fs = new Filesystem();
28038 $sources = $fs->normalizePath($sources);
28039
28040 $zip = new ZipArchive();
28041 $res = $zip->open($target, ZipArchive::CREATE);
28042 if ($res === true) {
28043 $files = new ArchivableFilesFinder($sources, $excludes, $ignoreFilters);
28044 foreach ($files as $file) {
28045
28046 $filepath = strtr($file->getPath()."/".$file->getFilename(), '\\', '/');
28047 $localname = str_replace($sources.'/', '', $filepath);
28048 if ($file->isDir()) {
28049 $zip->addEmptyDir($localname);
28050 } else {
28051 $zip->addFile($filepath, $localname);
28052 }
28053
28054
28055
28056
28057 if (PHP_VERSION_ID >= 50600) {
28058 $perms = fileperms($filepath);
28059
28060
28061
28062
28063 $zip->setExternalAttributesName($localname, ZipArchive::OPSYS_UNIX, $perms << 16);
28064 }
28065 }
28066 if ($zip->close()) {
28067 return $target;
28068 }
28069 }
28070 $message = sprintf(
28071 "Could not create archive '%s' from '%s': %s",
28072 $target,
28073 $sources,
28074 $zip->getStatusString()
28075 );
28076 throw new \RuntimeException($message);
28077 }
28078
28079
28080
28081
28082 public function supports($format, $sourceType)
28083 {
28084 return isset(static::$formats[$format]) && $this->compressionAvailable();
28085 }
28086
28087 private function compressionAvailable()
28088 {
28089 return class_exists('ZipArchive');
28090 }
28091 }
28092 <?php
28093
28094
28095
28096
28097
28098
28099
28100
28101
28102
28103
28104 namespace Composer\Package;
28105
28106 use Composer\Repository\RepositoryInterface;
28107 use Composer\Repository\PlatformRepository;
28108
28109
28110
28111
28112
28113
28114 abstract class BasePackage implements PackageInterface
28115 {
28116 public static $supportedLinkTypes = array(
28117 'require' => array('description' => 'requires', 'method' => 'requires'),
28118 'conflict' => array('description' => 'conflicts', 'method' => 'conflicts'),
28119 'provide' => array('description' => 'provides', 'method' => 'provides'),
28120 'replace' => array('description' => 'replaces', 'method' => 'replaces'),
28121 'require-dev' => array('description' => 'requires (for development)', 'method' => 'devRequires'),
28122 );
28123
28124 const STABILITY_STABLE = 0;
28125 const STABILITY_RC = 5;
28126 const STABILITY_BETA = 10;
28127 const STABILITY_ALPHA = 15;
28128 const STABILITY_DEV = 20;
28129
28130 public static $stabilities = array(
28131 'stable' => self::STABILITY_STABLE,
28132 'RC' => self::STABILITY_RC,
28133 'beta' => self::STABILITY_BETA,
28134 'alpha' => self::STABILITY_ALPHA,
28135 'dev' => self::STABILITY_DEV,
28136 );
28137
28138
28139
28140
28141
28142 public $id;
28143
28144 protected $name;
28145
28146 protected $prettyName;
28147
28148 protected $repository;
28149
28150 protected $transportOptions = array();
28151
28152
28153
28154
28155
28156
28157 public function __construct($name)
28158 {
28159 $this->prettyName = $name;
28160 $this->name = strtolower($name);
28161 $this->id = -1;
28162 }
28163
28164
28165
28166
28167 public function getName()
28168 {
28169 return $this->name;
28170 }
28171
28172
28173
28174
28175 public function getPrettyName()
28176 {
28177 return $this->prettyName;
28178 }
28179
28180
28181
28182
28183 public function getNames()
28184 {
28185 $names = array(
28186 $this->getName() => true,
28187 );
28188
28189 foreach ($this->getProvides() as $link) {
28190 $names[$link->getTarget()] = true;
28191 }
28192
28193 foreach ($this->getReplaces() as $link) {
28194 $names[$link->getTarget()] = true;
28195 }
28196
28197 return array_keys($names);
28198 }
28199
28200
28201
28202
28203 public function setId($id)
28204 {
28205 $this->id = $id;
28206 }
28207
28208
28209
28210
28211 public function getId()
28212 {
28213 return $this->id;
28214 }
28215
28216
28217
28218
28219 public function setRepository(RepositoryInterface $repository)
28220 {
28221 if ($this->repository && $repository !== $this->repository) {
28222 throw new \LogicException('A package can only be added to one repository');
28223 }
28224 $this->repository = $repository;
28225 }
28226
28227
28228
28229
28230 public function getRepository()
28231 {
28232 return $this->repository;
28233 }
28234
28235
28236
28237
28238 public function getTransportOptions()
28239 {
28240 return $this->transportOptions;
28241 }
28242
28243
28244
28245
28246
28247
28248 public function setTransportOptions(array $options)
28249 {
28250 $this->transportOptions = $options;
28251 }
28252
28253
28254
28255
28256
28257
28258 public function isPlatform()
28259 {
28260 return $this->getRepository() instanceof PlatformRepository;
28261 }
28262
28263
28264
28265
28266
28267
28268 public function getUniqueName()
28269 {
28270 return $this->getName().'-'.$this->getVersion();
28271 }
28272
28273 public function equals(PackageInterface $package)
28274 {
28275 $self = $this;
28276 if ($this instanceof AliasPackage) {
28277 $self = $this->getAliasOf();
28278 }
28279 if ($package instanceof AliasPackage) {
28280 $package = $package->getAliasOf();
28281 }
28282
28283 return $package === $self;
28284 }
28285
28286
28287
28288
28289
28290
28291 public function __toString()
28292 {
28293 return $this->getUniqueName();
28294 }
28295
28296 public function getPrettyString()
28297 {
28298 return $this->getPrettyName().' '.$this->getPrettyVersion();
28299 }
28300
28301
28302
28303
28304 public function getFullPrettyVersion($truncate = true)
28305 {
28306 if (!$this->isDev() || !in_array($this->getSourceType(), array('hg', 'git'))) {
28307 return $this->getPrettyVersion();
28308 }
28309
28310
28311 if ($truncate && strlen($this->getSourceReference()) === 40) {
28312 return $this->getPrettyVersion() . ' ' . substr($this->getSourceReference(), 0, 7);
28313 }
28314
28315 return $this->getPrettyVersion() . ' ' . $this->getSourceReference();
28316 }
28317
28318 public function getStabilityPriority()
28319 {
28320 return self::$stabilities[$this->getStability()];
28321 }
28322
28323 public function __clone()
28324 {
28325 $this->repository = null;
28326 $this->id = -1;
28327 }
28328
28329
28330
28331
28332
28333
28334
28335
28336 public static function packageNameToRegexp($allowListPattern, $wrap = '{^%s$}i')
28337 {
28338 $cleanedAllowListPattern = str_replace('\\*', '.*', preg_quote($allowListPattern));
28339
28340 return sprintf($wrap, $cleanedAllowListPattern);
28341 }
28342 }
28343 <?php
28344
28345
28346
28347
28348
28349
28350
28351
28352
28353
28354
28355 namespace Composer\Package\Comparer;
28356
28357
28358
28359
28360
28361
28362 class Comparer
28363 {
28364 private $source;
28365 private $update;
28366 private $changed;
28367
28368 public function setSource($source)
28369 {
28370 $this->source = $source;
28371 }
28372
28373 public function setUpdate($update)
28374 {
28375 $this->update = $update;
28376 }
28377
28378 public function getChanged($toString = false, $explicated = false)
28379 {
28380 $changed = $this->changed;
28381 if (!count($changed)) {
28382 return false;
28383 }
28384 if ($explicated) {
28385 foreach ($changed as $sectionKey => $itemSection) {
28386 foreach ($itemSection as $itemKey => $item) {
28387 $changed[$sectionKey][$itemKey] = $item.' ('.$sectionKey.')';
28388 }
28389 }
28390 }
28391
28392 if ($toString) {
28393 foreach ($changed as $sectionKey => $itemSection) {
28394 foreach ($itemSection as $itemKey => $item) {
28395 $changed['string'][] = $item."\r\n";
28396 }
28397 }
28398 $changed = implode("\r\n", $changed['string']);
28399 }
28400
28401 return $changed;
28402 }
28403
28404 public function doCompare()
28405 {
28406 $source = array();
28407 $destination = array();
28408 $this->changed = array();
28409 $currentDirectory = getcwd();
28410 chdir($this->source);
28411 $source = $this->doTree('.', $source);
28412 if (!is_array($source)) {
28413 return;
28414 }
28415 chdir($currentDirectory);
28416 chdir($this->update);
28417 $destination = $this->doTree('.', $destination);
28418 if (!is_array($destination)) {
28419 exit;
28420 }
28421 chdir($currentDirectory);
28422 foreach ($source as $dir => $value) {
28423 foreach ($value as $file => $hash) {
28424 if (isset($destination[$dir][$file])) {
28425 if ($hash !== $destination[$dir][$file]) {
28426 $this->changed['changed'][] = $dir.'/'.$file;
28427 }
28428 } else {
28429 $this->changed['removed'][] = $dir.'/'.$file;
28430 }
28431 }
28432 }
28433 foreach ($destination as $dir => $value) {
28434 foreach ($value as $file => $hash) {
28435 if (!isset($source[$dir][$file])) {
28436 $this->changed['added'][] = $dir.'/'.$file;
28437 }
28438 }
28439 }
28440 }
28441
28442 private function doTree($dir, &$array)
28443 {
28444 if ($dh = opendir($dir)) {
28445 while ($file = readdir($dh)) {
28446 if ($file !== '.' && $file !== '..') {
28447 if (is_link($dir.'/'.$file)) {
28448 $array[$dir][$file] = readlink($dir.'/'.$file);
28449 } elseif (is_dir($dir.'/'.$file)) {
28450 if (!count($array)) {
28451 $array[0] = 'Temp';
28452 }
28453 if (!$this->doTree($dir.'/'.$file, $array)) {
28454 return false;
28455 }
28456 } elseif (is_file($dir.'/'.$file) && filesize($dir.'/'.$file)) {
28457 set_time_limit(30);
28458 $array[$dir][$file] = md5_file($dir.'/'.$file);
28459 }
28460 }
28461 }
28462 if (count($array) > 1 && isset($array['0'])) {
28463 unset($array['0']);
28464 }
28465
28466 return $array;
28467 }
28468
28469 return false;
28470 }
28471 }
28472 <?php
28473
28474
28475
28476
28477
28478
28479
28480
28481
28482
28483
28484 namespace Composer\Package;
28485
28486
28487
28488
28489
28490
28491 class CompletePackage extends Package implements CompletePackageInterface
28492 {
28493 protected $repositories;
28494 protected $license = array();
28495 protected $keywords;
28496 protected $authors;
28497 protected $description;
28498 protected $homepage;
28499 protected $scripts = array();
28500 protected $support = array();
28501 protected $funding = array();
28502 protected $abandoned = false;
28503
28504
28505
28506
28507 public function setScripts(array $scripts)
28508 {
28509 $this->scripts = $scripts;
28510 }
28511
28512
28513
28514
28515 public function getScripts()
28516 {
28517 return $this->scripts;
28518 }
28519
28520
28521
28522
28523
28524
28525 public function setRepositories($repositories)
28526 {
28527 $this->repositories = $repositories;
28528 }
28529
28530
28531
28532
28533 public function getRepositories()
28534 {
28535 return $this->repositories;
28536 }
28537
28538
28539
28540
28541
28542
28543 public function setLicense(array $license)
28544 {
28545 $this->license = $license;
28546 }
28547
28548
28549
28550
28551 public function getLicense()
28552 {
28553 return $this->license;
28554 }
28555
28556
28557
28558
28559
28560
28561 public function setKeywords(array $keywords)
28562 {
28563 $this->keywords = $keywords;
28564 }
28565
28566
28567
28568
28569 public function getKeywords()
28570 {
28571 return $this->keywords;
28572 }
28573
28574
28575
28576
28577
28578
28579 public function setAuthors(array $authors)
28580 {
28581 $this->authors = $authors;
28582 }
28583
28584
28585
28586
28587 public function getAuthors()
28588 {
28589 return $this->authors;
28590 }
28591
28592
28593
28594
28595
28596
28597 public function setDescription($description)
28598 {
28599 $this->description = $description;
28600 }
28601
28602
28603
28604
28605 public function getDescription()
28606 {
28607 return $this->description;
28608 }
28609
28610
28611
28612
28613
28614
28615 public function setHomepage($homepage)
28616 {
28617 $this->homepage = $homepage;
28618 }
28619
28620
28621
28622
28623 public function getHomepage()
28624 {
28625 return $this->homepage;
28626 }
28627
28628
28629
28630
28631
28632
28633 public function setSupport(array $support)
28634 {
28635 $this->support = $support;
28636 }
28637
28638
28639
28640
28641 public function getSupport()
28642 {
28643 return $this->support;
28644 }
28645
28646
28647
28648
28649
28650
28651 public function setFunding(array $funding)
28652 {
28653 $this->funding = $funding;
28654 }
28655
28656
28657
28658
28659 public function getFunding()
28660 {
28661 return $this->funding;
28662 }
28663
28664
28665
28666
28667 public function isAbandoned()
28668 {
28669 return (bool) $this->abandoned;
28670 }
28671
28672
28673
28674
28675 public function setAbandoned($abandoned)
28676 {
28677 $this->abandoned = $abandoned;
28678 }
28679
28680
28681
28682
28683
28684
28685 public function getReplacementPackage()
28686 {
28687 return is_string($this->abandoned) ? $this->abandoned : null;
28688 }
28689 }
28690 <?php
28691
28692
28693
28694
28695
28696
28697
28698
28699
28700
28701
28702 namespace Composer\Package;
28703
28704
28705
28706
28707
28708
28709 interface CompletePackageInterface extends PackageInterface
28710 {
28711
28712
28713
28714
28715
28716 public function getScripts();
28717
28718
28719
28720
28721
28722
28723
28724
28725 public function getRepositories();
28726
28727
28728
28729
28730
28731
28732 public function getLicense();
28733
28734
28735
28736
28737
28738
28739 public function getKeywords();
28740
28741
28742
28743
28744
28745
28746 public function getDescription();
28747
28748
28749
28750
28751
28752
28753 public function getHomepage();
28754
28755
28756
28757
28758
28759
28760
28761
28762 public function getAuthors();
28763
28764
28765
28766
28767
28768
28769 public function getSupport();
28770
28771
28772
28773
28774
28775
28776
28777
28778 public function getFunding();
28779
28780
28781
28782
28783
28784
28785 public function isAbandoned();
28786
28787
28788
28789
28790
28791
28792 public function getReplacementPackage();
28793 }
28794 <?php
28795
28796
28797
28798
28799
28800
28801
28802
28803
28804
28805
28806 namespace Composer\Package\Dumper;
28807
28808 use Composer\Package\BasePackage;
28809 use Composer\Package\PackageInterface;
28810 use Composer\Package\CompletePackageInterface;
28811 use Composer\Package\RootPackageInterface;
28812
28813
28814
28815
28816
28817 class ArrayDumper
28818 {
28819 public function dump(PackageInterface $package)
28820 {
28821 $keys = array(
28822 'binaries' => 'bin',
28823 'type',
28824 'extra',
28825 'installationSource' => 'installation-source',
28826 'autoload',
28827 'devAutoload' => 'autoload-dev',
28828 'notificationUrl' => 'notification-url',
28829 'includePaths' => 'include-path',
28830 );
28831
28832 $data = array();
28833 $data['name'] = $package->getPrettyName();
28834 $data['version'] = $package->getPrettyVersion();
28835 $data['version_normalized'] = $package->getVersion();
28836
28837 if ($package->getTargetDir()) {
28838 $data['target-dir'] = $package->getTargetDir();
28839 }
28840
28841 if ($package->getSourceType()) {
28842 $data['source']['type'] = $package->getSourceType();
28843 $data['source']['url'] = $package->getSourceUrl();
28844 if (null !== ($value = $package->getSourceReference())) {
28845 $data['source']['reference'] = $value;
28846 }
28847 if ($mirrors = $package->getSourceMirrors()) {
28848 $data['source']['mirrors'] = $mirrors;
28849 }
28850 }
28851
28852 if ($package->getDistType()) {
28853 $data['dist']['type'] = $package->getDistType();
28854 $data['dist']['url'] = $package->getDistUrl();
28855 if (null !== ($value = $package->getDistReference())) {
28856 $data['dist']['reference'] = $value;
28857 }
28858 if (null !== ($value = $package->getDistSha1Checksum())) {
28859 $data['dist']['shasum'] = $value;
28860 }
28861 if ($mirrors = $package->getDistMirrors()) {
28862 $data['dist']['mirrors'] = $mirrors;
28863 }
28864 }
28865
28866 if ($package->getArchiveExcludes()) {
28867 $data['archive']['exclude'] = $package->getArchiveExcludes();
28868 }
28869
28870 foreach (BasePackage::$supportedLinkTypes as $type => $opts) {
28871 if ($links = $package->{'get'.ucfirst($opts['method'])}()) {
28872 foreach ($links as $link) {
28873 $data[$type][$link->getTarget()] = $link->getPrettyConstraint();
28874 }
28875 ksort($data[$type]);
28876 }
28877 }
28878
28879 if ($packages = $package->getSuggests()) {
28880 ksort($packages);
28881 $data['suggest'] = $packages;
28882 }
28883
28884 if ($package->getReleaseDate()) {
28885 $data['time'] = $package->getReleaseDate()->format(DATE_RFC3339);
28886 }
28887
28888 $data = $this->dumpValues($package, $keys, $data);
28889
28890 if ($package instanceof CompletePackageInterface) {
28891 $keys = array(
28892 'scripts',
28893 'license',
28894 'authors',
28895 'description',
28896 'homepage',
28897 'keywords',
28898 'repositories',
28899 'support',
28900 'funding',
28901 );
28902
28903 $data = $this->dumpValues($package, $keys, $data);
28904
28905 if (isset($data['keywords']) && is_array($data['keywords'])) {
28906 sort($data['keywords']);
28907 }
28908
28909 if ($package->isAbandoned()) {
28910 $data['abandoned'] = $package->getReplacementPackage() ?: true;
28911 }
28912 }
28913
28914 if ($package instanceof RootPackageInterface) {
28915 $minimumStability = $package->getMinimumStability();
28916 if ($minimumStability) {
28917 $data['minimum-stability'] = $minimumStability;
28918 }
28919 }
28920
28921 if (count($package->getTransportOptions()) > 0) {
28922 $data['transport-options'] = $package->getTransportOptions();
28923 }
28924
28925 return $data;
28926 }
28927
28928 private function dumpValues(PackageInterface $package, array $keys, array $data)
28929 {
28930 foreach ($keys as $method => $key) {
28931 if (is_numeric($method)) {
28932 $method = $key;
28933 }
28934
28935 $getter = 'get'.ucfirst($method);
28936 $value = $package->$getter();
28937
28938 if (null !== $value && !(is_array($value) && 0 === count($value))) {
28939 $data[$key] = $value;
28940 }
28941 }
28942
28943 return $data;
28944 }
28945 }
28946 <?php
28947
28948
28949
28950
28951
28952
28953
28954
28955
28956
28957
28958 namespace Composer\Package;
28959
28960 use Composer\Semver\Constraint\ConstraintInterface;
28961
28962
28963
28964
28965
28966
28967 class Link
28968 {
28969
28970
28971
28972 protected $source;
28973
28974
28975
28976
28977 protected $target;
28978
28979
28980
28981
28982 protected $constraint;
28983
28984
28985
28986
28987 protected $description;
28988
28989
28990
28991
28992 protected $prettyConstraint;
28993
28994
28995
28996
28997
28998
28999
29000
29001
29002
29003 public function __construct($source, $target, ConstraintInterface $constraint = null, $description = 'relates to', $prettyConstraint = null)
29004 {
29005 $this->source = strtolower($source);
29006 $this->target = strtolower($target);
29007 $this->constraint = $constraint;
29008 $this->description = $description;
29009 $this->prettyConstraint = $prettyConstraint;
29010 }
29011
29012
29013
29014
29015 public function getDescription()
29016 {
29017 return $this->description;
29018 }
29019
29020
29021
29022
29023 public function getSource()
29024 {
29025 return $this->source;
29026 }
29027
29028
29029
29030
29031 public function getTarget()
29032 {
29033 return $this->target;
29034 }
29035
29036
29037
29038
29039 public function getConstraint()
29040 {
29041 return $this->constraint;
29042 }
29043
29044
29045
29046
29047
29048 public function getPrettyConstraint()
29049 {
29050 if (null === $this->prettyConstraint) {
29051 throw new \UnexpectedValueException(sprintf('Link %s has been misconfigured and had no prettyConstraint given.', $this));
29052 }
29053
29054 return $this->prettyConstraint;
29055 }
29056
29057
29058
29059
29060 public function __toString()
29061 {
29062 return $this->source.' '.$this->description.' '.$this->target.' ('.$this->constraint.')';
29063 }
29064
29065
29066
29067
29068
29069 public function getPrettyString(PackageInterface $sourcePackage)
29070 {
29071 return $sourcePackage->getPrettyString().' '.$this->description.' '.$this->target.' '.$this->constraint->getPrettyString().'';
29072 }
29073 }
29074 <?php
29075
29076
29077
29078
29079
29080
29081
29082
29083
29084
29085
29086 namespace Composer\Package\LinkConstraint;
29087
29088 use Composer\Semver\Constraint\EmptyConstraint as SemverEmptyConstraint;
29089
29090 trigger_error('The ' . __NAMESPACE__ . '\EmptyConstraint class is deprecated, use Composer\Semver\Constraint\EmptyConstraint instead.', E_USER_DEPRECATED);
29091
29092
29093
29094
29095 class EmptyConstraint extends SemverEmptyConstraint implements LinkConstraintInterface
29096 {
29097 }
29098 <?php
29099
29100
29101
29102
29103
29104
29105
29106
29107
29108
29109
29110 namespace Composer\Package\LinkConstraint;
29111
29112 use Composer\Semver\Constraint\ConstraintInterface;
29113
29114 trigger_error('The ' . __NAMESPACE__ . '\LinkConstraintInterface interface is deprecated, use Composer\Semver\Constraint\ConstraintInterface instead.', E_USER_DEPRECATED);
29115
29116
29117
29118
29119 interface LinkConstraintInterface extends ConstraintInterface
29120 {
29121 }
29122 <?php
29123
29124
29125
29126
29127
29128
29129
29130
29131
29132
29133
29134 namespace Composer\Package\LinkConstraint;
29135
29136 use Composer\Semver\Constraint\MultiConstraint as SemverMultiConstraint;
29137
29138 trigger_error('The ' . __NAMESPACE__ . '\MultiConstraint class is deprecated, use Composer\Semver\Constraint\MultiConstraint instead.', E_USER_DEPRECATED);
29139
29140
29141
29142
29143 class MultiConstraint extends SemverMultiConstraint implements LinkConstraintInterface
29144 {
29145 }
29146 <?php
29147
29148
29149
29150
29151
29152
29153
29154
29155
29156
29157
29158 namespace Composer\Package\LinkConstraint;
29159
29160 use Composer\Semver\Constraint\AbstractConstraint;
29161
29162 trigger_error('The ' . __NAMESPACE__ . '\SpecificConstraint abstract class is deprecated, there is no replacement for it.', E_USER_DEPRECATED);
29163
29164
29165
29166
29167 abstract class SpecificConstraint extends AbstractConstraint implements LinkConstraintInterface
29168 {
29169 }
29170 <?php
29171
29172
29173
29174
29175
29176
29177
29178
29179
29180
29181
29182 namespace Composer\Package\LinkConstraint;
29183
29184 use Composer\Semver\Constraint\Constraint;
29185
29186 trigger_error('The ' . __NAMESPACE__ . '\VersionConstraint class is deprecated, use Composer\Semver\Constraint\Constraint instead.', E_USER_DEPRECATED);
29187
29188
29189
29190
29191 class VersionConstraint extends Constraint implements LinkConstraintInterface
29192 {
29193 }
29194 <?php
29195
29196
29197
29198
29199
29200
29201
29202
29203
29204
29205
29206 namespace Composer\Package\Loader;
29207
29208 use Composer\Package;
29209 use Composer\Package\AliasPackage;
29210 use Composer\Package\Link;
29211 use Composer\Package\RootAliasPackage;
29212 use Composer\Package\RootPackageInterface;
29213 use Composer\Package\Version\VersionParser;
29214 use Composer\Semver\VersionParser as SemverVersionParser;
29215
29216
29217
29218
29219
29220 class ArrayLoader implements LoaderInterface
29221 {
29222 protected $versionParser;
29223 protected $loadOptions;
29224
29225 public function __construct(SemverVersionParser $parser = null, $loadOptions = false)
29226 {
29227 if (!$parser) {
29228 $parser = new VersionParser;
29229 }
29230 $this->versionParser = $parser;
29231 $this->loadOptions = $loadOptions;
29232 }
29233
29234 public function load(array $config, $class = 'Composer\Package\CompletePackage')
29235 {
29236 if (!isset($config['name'])) {
29237 throw new \UnexpectedValueException('Unknown package has no name defined ('.json_encode($config).').');
29238 }
29239 if (!isset($config['version'])) {
29240 throw new \UnexpectedValueException('Package '.$config['name'].' has no version defined.');
29241 }
29242
29243
29244 if (isset($config['version_normalized'])) {
29245 $version = $config['version_normalized'];
29246 } else {
29247 $version = $this->versionParser->normalize($config['version']);
29248 }
29249 $package = new $class($config['name'], $version, $config['version']);
29250 $package->setType(isset($config['type']) ? strtolower($config['type']) : 'library');
29251
29252 if (isset($config['target-dir'])) {
29253 $package->setTargetDir($config['target-dir']);
29254 }
29255
29256 if (isset($config['extra']) && is_array($config['extra'])) {
29257 $package->setExtra($config['extra']);
29258 }
29259
29260 if (isset($config['bin'])) {
29261 if (!\is_array($config['bin'])) {
29262 $config['bin'] = array($config['bin']);
29263 }
29264 foreach ($config['bin'] as $key => $bin) {
29265 $config['bin'][$key] = ltrim($bin, '/');
29266 }
29267 $package->setBinaries($config['bin']);
29268 }
29269
29270 if (isset($config['installation-source'])) {
29271 $package->setInstallationSource($config['installation-source']);
29272 }
29273
29274 if (isset($config['source'])) {
29275 if (!isset($config['source']['type']) || !isset($config['source']['url']) || !isset($config['source']['reference'])) {
29276 throw new \UnexpectedValueException(sprintf(
29277 "Package %s's source key should be specified as {\"type\": ..., \"url\": ..., \"reference\": ...},\n%s given.",
29278 $config['name'],
29279 json_encode($config['source'])
29280 ));
29281 }
29282 $package->setSourceType($config['source']['type']);
29283 $package->setSourceUrl($config['source']['url']);
29284 $package->setSourceReference(isset($config['source']['reference']) ? $config['source']['reference'] : null);
29285 if (isset($config['source']['mirrors'])) {
29286 $package->setSourceMirrors($config['source']['mirrors']);
29287 }
29288 }
29289
29290 if (isset($config['dist'])) {
29291 if (!isset($config['dist']['type'])
29292 || !isset($config['dist']['url'])) {
29293 throw new \UnexpectedValueException(sprintf(
29294 "Package %s's dist key should be specified as ".
29295 "{\"type\": ..., \"url\": ..., \"reference\": ..., \"shasum\": ...},\n%s given.",
29296 $config['name'],
29297 json_encode($config['dist'])
29298 ));
29299 }
29300 $package->setDistType($config['dist']['type']);
29301 $package->setDistUrl($config['dist']['url']);
29302 $package->setDistReference(isset($config['dist']['reference']) ? $config['dist']['reference'] : null);
29303 $package->setDistSha1Checksum(isset($config['dist']['shasum']) ? $config['dist']['shasum'] : null);
29304 if (isset($config['dist']['mirrors'])) {
29305 $package->setDistMirrors($config['dist']['mirrors']);
29306 }
29307 }
29308
29309 foreach (Package\BasePackage::$supportedLinkTypes as $type => $opts) {
29310 if (isset($config[$type])) {
29311 $method = 'set'.ucfirst($opts['method']);
29312 $package->{$method}(
29313 $this->parseLinks(
29314 $package->getName(),
29315 $package->getPrettyVersion(),
29316 $opts['description'],
29317 $config[$type]
29318 )
29319 );
29320 }
29321 }
29322
29323 if (isset($config['suggest']) && is_array($config['suggest'])) {
29324 foreach ($config['suggest'] as $target => $reason) {
29325 if ('self.version' === trim($reason)) {
29326 $config['suggest'][$target] = $package->getPrettyVersion();
29327 }
29328 }
29329 $package->setSuggests($config['suggest']);
29330 }
29331
29332 if (isset($config['autoload'])) {
29333 $package->setAutoload($config['autoload']);
29334 }
29335
29336 if (isset($config['autoload-dev'])) {
29337 $package->setDevAutoload($config['autoload-dev']);
29338 }
29339
29340 if (isset($config['include-path'])) {
29341 $package->setIncludePaths($config['include-path']);
29342 }
29343
29344 if (!empty($config['time'])) {
29345 $time = preg_match('/^\d++$/D', $config['time']) ? '@'.$config['time'] : $config['time'];
29346
29347 try {
29348 $date = new \DateTime($time, new \DateTimeZone('UTC'));
29349 $package->setReleaseDate($date);
29350 } catch (\Exception $e) {
29351 }
29352 }
29353
29354 if (!empty($config['notification-url'])) {
29355 $package->setNotificationUrl($config['notification-url']);
29356 }
29357
29358 if (!empty($config['archive']['exclude'])) {
29359 $package->setArchiveExcludes($config['archive']['exclude']);
29360 }
29361
29362 if ($package instanceof Package\CompletePackageInterface) {
29363 if (isset($config['scripts']) && is_array($config['scripts'])) {
29364 foreach ($config['scripts'] as $event => $listeners) {
29365 $config['scripts'][$event] = (array) $listeners;
29366 }
29367 if (isset($config['scripts']['composer'])) {
29368 trigger_error('The `composer` script name is reserved for internal use, please avoid defining it', E_USER_DEPRECATED);
29369 }
29370 $package->setScripts($config['scripts']);
29371 }
29372
29373 if (!empty($config['description']) && is_string($config['description'])) {
29374 $package->setDescription($config['description']);
29375 }
29376
29377 if (!empty($config['homepage']) && is_string($config['homepage'])) {
29378 $package->setHomepage($config['homepage']);
29379 }
29380
29381 if (!empty($config['keywords']) && is_array($config['keywords'])) {
29382 $package->setKeywords($config['keywords']);
29383 }
29384
29385 if (!empty($config['license'])) {
29386 $package->setLicense(is_array($config['license']) ? $config['license'] : array($config['license']));
29387 }
29388
29389 if (!empty($config['authors']) && is_array($config['authors'])) {
29390 $package->setAuthors($config['authors']);
29391 }
29392
29393 if (isset($config['support'])) {
29394 $package->setSupport($config['support']);
29395 }
29396
29397 if (!empty($config['funding']) && is_array($config['funding'])) {
29398 $package->setFunding($config['funding']);
29399 }
29400
29401 if (isset($config['abandoned'])) {
29402 $package->setAbandoned($config['abandoned']);
29403 }
29404 }
29405
29406 if ($aliasNormalized = $this->getBranchAlias($config)) {
29407 if ($package instanceof RootPackageInterface) {
29408 $package = new RootAliasPackage($package, $aliasNormalized, preg_replace('{(\.9{7})+}', '.x', $aliasNormalized));
29409 } else {
29410 $package = new AliasPackage($package, $aliasNormalized, preg_replace('{(\.9{7})+}', '.x', $aliasNormalized));
29411 }
29412 }
29413
29414 if ($this->loadOptions && isset($config['transport-options'])) {
29415 $package->setTransportOptions($config['transport-options']);
29416 }
29417
29418 return $package;
29419 }
29420
29421
29422
29423
29424
29425
29426
29427
29428 public function parseLinks($source, $sourceVersion, $description, $links)
29429 {
29430 $res = array();
29431 foreach ($links as $target => $constraint) {
29432 if (!is_string($constraint)) {
29433 throw new \UnexpectedValueException('Link constraint in '.$source.' '.$description.' > '.$target.' should be a string, got '.gettype($constraint) . ' (' . var_export($constraint, true) . ')');
29434 }
29435 if ('self.version' === $constraint) {
29436 $parsedConstraint = $this->versionParser->parseConstraints($sourceVersion);
29437 } else {
29438 $parsedConstraint = $this->versionParser->parseConstraints($constraint);
29439 }
29440
29441 $res[strtolower($target)] = new Link($source, $target, $parsedConstraint, $description, $constraint);
29442 }
29443
29444 return $res;
29445 }
29446
29447
29448
29449
29450
29451
29452
29453 public function getBranchAlias(array $config)
29454 {
29455 if (('dev-' !== substr($config['version'], 0, 4) && '-dev' !== substr($config['version'], -4))
29456 || !isset($config['extra']['branch-alias'])
29457 || !is_array($config['extra']['branch-alias'])
29458 ) {
29459 return;
29460 }
29461
29462 foreach ($config['extra']['branch-alias'] as $sourceBranch => $targetBranch) {
29463
29464 if ('-dev' !== substr($targetBranch, -4)) {
29465 continue;
29466 }
29467
29468
29469 $validatedTargetBranch = $this->versionParser->normalizeBranch(substr($targetBranch, 0, -4));
29470 if ('-dev' !== substr($validatedTargetBranch, -4)) {
29471 continue;
29472 }
29473
29474
29475 if (strtolower($config['version']) !== strtolower($sourceBranch)) {
29476 continue;
29477 }
29478
29479
29480 if (($sourcePrefix = $this->versionParser->parseNumericAliasPrefix($sourceBranch))
29481 && ($targetPrefix = $this->versionParser->parseNumericAliasPrefix($targetBranch))
29482 && (stripos($targetPrefix, $sourcePrefix) !== 0)
29483 ) {
29484 continue;
29485 }
29486
29487 return $validatedTargetBranch;
29488 }
29489 }
29490 }
29491 <?php
29492
29493
29494
29495
29496
29497
29498
29499
29500
29501
29502
29503 namespace Composer\Package\Loader;
29504
29505
29506
29507
29508 class InvalidPackageException extends \Exception
29509 {
29510 private $errors;
29511 private $warnings;
29512 private $data;
29513
29514 public function __construct(array $errors, array $warnings, array $data)
29515 {
29516 $this->errors = $errors;
29517 $this->warnings = $warnings;
29518 $this->data = $data;
29519 parent::__construct("Invalid package information: \n".implode("\n", array_merge($errors, $warnings)));
29520 }
29521
29522 public function getData()
29523 {
29524 return $this->data;
29525 }
29526
29527 public function getErrors()
29528 {
29529 return $this->errors;
29530 }
29531
29532 public function getWarnings()
29533 {
29534 return $this->warnings;
29535 }
29536 }
29537 <?php
29538
29539
29540
29541
29542
29543
29544
29545
29546
29547
29548
29549 namespace Composer\Package\Loader;
29550
29551 use Composer\Json\JsonFile;
29552
29553
29554
29555
29556 class JsonLoader
29557 {
29558 private $loader;
29559
29560 public function __construct(LoaderInterface $loader)
29561 {
29562 $this->loader = $loader;
29563 }
29564
29565
29566
29567
29568
29569 public function load($json)
29570 {
29571 if ($json instanceof JsonFile) {
29572 $config = $json->read();
29573 } elseif (file_exists($json)) {
29574 $config = JsonFile::parseJson(file_get_contents($json), $json);
29575 } elseif (is_string($json)) {
29576 $config = JsonFile::parseJson($json);
29577 }
29578
29579 return $this->loader->load($config);
29580 }
29581 }
29582 <?php
29583
29584
29585
29586
29587
29588
29589
29590
29591
29592
29593
29594 namespace Composer\Package\Loader;
29595
29596
29597
29598
29599
29600
29601 interface LoaderInterface
29602 {
29603
29604
29605
29606
29607
29608
29609
29610 public function load(array $package, $class = 'Composer\Package\CompletePackage');
29611 }
29612 <?php
29613
29614
29615
29616
29617
29618
29619
29620
29621
29622
29623
29624 namespace Composer\Package\Loader;
29625
29626 use Composer\Package\BasePackage;
29627 use Composer\Package\AliasPackage;
29628 use Composer\Config;
29629 use Composer\IO\IOInterface;
29630 use Composer\Package\RootPackageInterface;
29631 use Composer\Repository\RepositoryFactory;
29632 use Composer\Package\Version\VersionGuesser;
29633 use Composer\Package\Version\VersionParser;
29634 use Composer\Repository\RepositoryManager;
29635 use Composer\Util\ProcessExecutor;
29636
29637
29638
29639
29640
29641
29642
29643
29644 class RootPackageLoader extends ArrayLoader
29645 {
29646
29647
29648
29649 private $manager;
29650
29651
29652
29653
29654 private $config;
29655
29656
29657
29658
29659 private $versionGuesser;
29660
29661
29662
29663
29664 private $io;
29665
29666 public function __construct(RepositoryManager $manager, Config $config, VersionParser $parser = null, VersionGuesser $versionGuesser = null, IOInterface $io = null)
29667 {
29668 parent::__construct($parser);
29669
29670 $this->manager = $manager;
29671 $this->config = $config;
29672 $this->versionGuesser = $versionGuesser ?: new VersionGuesser($config, new ProcessExecutor(), $this->versionParser);
29673 $this->io = $io;
29674 }
29675
29676
29677
29678
29679
29680
29681
29682 public function load(array $config, $class = 'Composer\Package\RootPackage', $cwd = null)
29683 {
29684 if (!isset($config['name'])) {
29685 $config['name'] = '__root__';
29686 } elseif ($this->io) {
29687 if ($err = ValidatingArrayLoader::hasPackageNamingError($config['name'])) {
29688 $this->io->writeError('<warning>Deprecation warning: Your package name '.$err.' Make sure you fix this as Composer 2.0 will error.</warning>');
29689 }
29690 }
29691 $autoVersioned = false;
29692 if (!isset($config['version'])) {
29693 $commit = null;
29694
29695
29696 if (getenv('COMPOSER_ROOT_VERSION')) {
29697 $config['version'] = getenv('COMPOSER_ROOT_VERSION');
29698 } else {
29699 $versionData = $this->versionGuesser->guessVersion($config, $cwd ?: getcwd());
29700 if ($versionData) {
29701 $config['version'] = $versionData['pretty_version'];
29702 $config['version_normalized'] = $versionData['version'];
29703 $commit = $versionData['commit'];
29704 }
29705 }
29706
29707 if (!isset($config['version'])) {
29708 $config['version'] = '1.0.0';
29709 $autoVersioned = true;
29710 }
29711
29712 if ($commit) {
29713 $config['source'] = array(
29714 'type' => '',
29715 'url' => '',
29716 'reference' => $commit,
29717 );
29718 $config['dist'] = array(
29719 'type' => '',
29720 'url' => '',
29721 'reference' => $commit,
29722 );
29723 }
29724 }
29725
29726 $realPackage = $package = parent::load($config, $class);
29727 if ($realPackage instanceof AliasPackage) {
29728 $realPackage = $package->getAliasOf();
29729 }
29730
29731 if ($autoVersioned) {
29732 $realPackage->replaceVersion($realPackage->getVersion(), 'No version set (parsed as 1.0.0)');
29733 }
29734
29735 if (isset($config['minimum-stability'])) {
29736 $realPackage->setMinimumStability(VersionParser::normalizeStability($config['minimum-stability']));
29737 }
29738
29739 $aliases = array();
29740 $stabilityFlags = array();
29741 $references = array();
29742 foreach (array('require', 'require-dev') as $linkType) {
29743 if (isset($config[$linkType])) {
29744 $linkInfo = BasePackage::$supportedLinkTypes[$linkType];
29745 $method = 'get'.ucfirst($linkInfo['method']);
29746 $links = array();
29747 foreach ($realPackage->$method() as $link) {
29748 $links[$link->getTarget()] = $link->getConstraint()->getPrettyString();
29749 }
29750 $aliases = $this->extractAliases($links, $aliases);
29751 $stabilityFlags = $this->extractStabilityFlags($links, $stabilityFlags, $realPackage->getMinimumStability());
29752 $references = $this->extractReferences($links, $references);
29753
29754 if (isset($links[$config['name']])) {
29755 throw new \RuntimeException(sprintf('Root package \'%s\' cannot require itself in its composer.json' . PHP_EOL .
29756 'Did you accidentally name your root package after an external package?', $config['name']));
29757 }
29758 }
29759 }
29760
29761 if ($this->io) {
29762 foreach (array_keys(BasePackage::$supportedLinkTypes) as $linkType) {
29763 if (isset($config[$linkType])) {
29764 foreach ($config[$linkType] as $linkName => $constraint) {
29765 if ($err = ValidatingArrayLoader::hasPackageNamingError($linkName, true)) {
29766 $this->io->writeError('<warning>Deprecation warning: '.$linkType.'.'.$err.' Make sure you fix this as Composer 2.0 will error.</warning>');
29767 }
29768 }
29769 }
29770 }
29771 }
29772
29773 $realPackage->setAliases($aliases);
29774 $realPackage->setStabilityFlags($stabilityFlags);
29775 $realPackage->setReferences($references);
29776
29777 if (isset($config['prefer-stable'])) {
29778 $realPackage->setPreferStable((bool) $config['prefer-stable']);
29779 }
29780
29781 if (isset($config['config'])) {
29782 $realPackage->setConfig($config['config']);
29783 }
29784
29785 $repos = RepositoryFactory::defaultRepos(null, $this->config, $this->manager);
29786 foreach ($repos as $repo) {
29787 $this->manager->addRepository($repo);
29788 }
29789 $realPackage->setRepositories($this->config->getRepositories());
29790
29791 return $package;
29792 }
29793
29794 private function extractAliases(array $requires, array $aliases)
29795 {
29796 foreach ($requires as $reqName => $reqVersion) {
29797 if (preg_match('{^([^,\s#]+)(?:#[^ ]+)? +as +([^,\s]+)$}', $reqVersion, $match)) {
29798 $aliases[] = array(
29799 'package' => strtolower($reqName),
29800 'version' => $this->versionParser->normalize($match[1], $reqVersion),
29801 'alias' => $match[2],
29802 'alias_normalized' => $this->versionParser->normalize($match[2], $reqVersion),
29803 );
29804 } elseif (strpos($reqVersion, ' as ') !== false) {
29805 throw new \UnexpectedValueException('Invalid alias definition in "'.$reqName.'": "'.$reqVersion.'". Aliases should be in the form "exact-version as other-exact-version".');
29806 }
29807 }
29808
29809 return $aliases;
29810 }
29811
29812 private function extractStabilityFlags(array $requires, array $stabilityFlags, $minimumStability)
29813 {
29814 $stabilities = BasePackage::$stabilities;
29815 $minimumStability = $stabilities[$minimumStability];
29816 foreach ($requires as $reqName => $reqVersion) {
29817 $constraints = array();
29818
29819
29820 $orSplit = preg_split('{\s*\|\|?\s*}', trim($reqVersion));
29821 foreach ($orSplit as $orConstraint) {
29822 $andSplit = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $orConstraint);
29823 foreach ($andSplit as $andConstraint) {
29824 $constraints[] = $andConstraint;
29825 }
29826 }
29827
29828
29829 $match = false;
29830 foreach ($constraints as $constraint) {
29831 if (preg_match('{^[^@]*?@('.implode('|', array_keys($stabilities)).')$}i', $constraint, $match)) {
29832 $name = strtolower($reqName);
29833 $stability = $stabilities[VersionParser::normalizeStability($match[1])];
29834
29835 if (isset($stabilityFlags[$name]) && $stabilityFlags[$name] > $stability) {
29836 continue;
29837 }
29838 $stabilityFlags[$name] = $stability;
29839 $match = true;
29840 }
29841 }
29842
29843 if ($match) {
29844 continue;
29845 }
29846
29847 foreach ($constraints as $constraint) {
29848
29849
29850 $reqVersion = preg_replace('{^([^,\s@]+) as .+$}', '$1', $constraint);
29851 if (preg_match('{^[^,\s@]+$}', $reqVersion) && 'stable' !== ($stabilityName = VersionParser::parseStability($reqVersion))) {
29852 $name = strtolower($reqName);
29853 $stability = $stabilities[$stabilityName];
29854 if ((isset($stabilityFlags[$name]) && $stabilityFlags[$name] > $stability) || ($minimumStability > $stability)) {
29855 continue;
29856 }
29857 $stabilityFlags[$name] = $stability;
29858 }
29859 }
29860 }
29861
29862 return $stabilityFlags;
29863 }
29864
29865 private function extractReferences(array $requires, array $references)
29866 {
29867 foreach ($requires as $reqName => $reqVersion) {
29868 $reqVersion = preg_replace('{^([^,\s@]+) as .+$}', '$1', $reqVersion);
29869 if (preg_match('{^[^,\s@]+?#([a-f0-9]+)$}', $reqVersion, $match) && 'dev' === VersionParser::parseStability($reqVersion)) {
29870 $name = strtolower($reqName);
29871 $references[$name] = $match[1];
29872 }
29873 }
29874
29875 return $references;
29876 }
29877 }
29878 <?php
29879
29880
29881
29882
29883
29884
29885
29886
29887
29888
29889
29890 namespace Composer\Package\Loader;
29891
29892 use Composer\Package\BasePackage;
29893 use Composer\Semver\Constraint\Constraint;
29894 use Composer\Package\Version\VersionParser;
29895 use Composer\Repository\PlatformRepository;
29896 use Composer\Spdx\SpdxLicenses;
29897
29898
29899
29900
29901 class ValidatingArrayLoader implements LoaderInterface
29902 {
29903 const CHECK_ALL = 3;
29904 const CHECK_UNBOUND_CONSTRAINTS = 1;
29905 const CHECK_STRICT_CONSTRAINTS = 2;
29906
29907 private $loader;
29908 private $versionParser;
29909 private $errors;
29910 private $warnings;
29911 private $config;
29912 private $strictName;
29913 private $flags;
29914
29915 public function __construct(LoaderInterface $loader, $strictName = true, VersionParser $parser = null, $flags = 0)
29916 {
29917 $this->loader = $loader;
29918 $this->versionParser = $parser ?: new VersionParser();
29919 $this->strictName = $strictName;
29920 $this->flags = $flags;
29921 }
29922
29923 public function load(array $config, $class = 'Composer\Package\CompletePackage')
29924 {
29925 $this->errors = array();
29926 $this->warnings = array();
29927 $this->config = $config;
29928
29929 if ($err = self::hasPackageNamingError($config['name'])) {
29930 $this->warnings[] = 'Deprecation warning: Your package name '.$err.' Make sure you fix this as Composer 2.0 will error.';
29931 }
29932
29933 if ($this->strictName) {
29934 $this->validateRegex('name', '[A-Za-z0-9][A-Za-z0-9_.-]*/[A-Za-z0-9][A-Za-z0-9_.-]*', true);
29935 } else {
29936 $this->validateString('name', true);
29937 }
29938
29939 if (!empty($this->config['version'])) {
29940 try {
29941 $this->versionParser->normalize($this->config['version']);
29942 } catch (\Exception $e) {
29943 $this->errors[] = 'version : invalid value ('.$this->config['version'].'): '.$e->getMessage();
29944 unset($this->config['version']);
29945 }
29946 }
29947
29948 if (!empty($this->config['config']['platform'])) {
29949 foreach ((array) $this->config['config']['platform'] as $key => $platform) {
29950 try {
29951 $this->versionParser->normalize($platform);
29952 } catch (\Exception $e) {
29953 $this->errors[] = 'config.platform.' . $key . ' : invalid value ('.$platform.'): '.$e->getMessage();
29954 }
29955 }
29956 }
29957
29958 $this->validateRegex('type', '[A-Za-z0-9-]+');
29959 $this->validateString('target-dir');
29960 $this->validateArray('extra');
29961
29962 if (isset($this->config['bin'])) {
29963 if (is_string($this->config['bin'])) {
29964 $this->validateString('bin');
29965 } else {
29966 $this->validateFlatArray('bin');
29967 }
29968 }
29969
29970 $this->validateArray('scripts'); 
29971 $this->validateString('description');
29972 $this->validateUrl('homepage');
29973 $this->validateFlatArray('keywords', '[\p{N}\p{L} ._-]+');
29974
29975 $releaseDate = null;
29976 $this->validateString('time');
29977 if (!empty($this->config['time'])) {
29978 try {
29979 $releaseDate = new \DateTime($this->config['time'], new \DateTimeZone('UTC'));
29980 } catch (\Exception $e) {
29981 $this->errors[] = 'time : invalid value ('.$this->config['time'].'): '.$e->getMessage();
29982 unset($this->config['time']);
29983 }
29984 }
29985
29986
29987 if (isset($this->config['license']) && (!$releaseDate || $releaseDate->getTimestamp() >= strtotime('-8days'))) {
29988 if (is_array($this->config['license']) || is_string($this->config['license'])) {
29989 $licenses = (array) $this->config['license'];
29990
29991 $licenseValidator = new SpdxLicenses();
29992 foreach ($licenses as $license) {
29993
29994 if ('proprietary' === $license) {
29995 continue;
29996 }
29997 $licenseToValidate = str_replace('proprietary', 'MIT', $license);
29998 if (!$licenseValidator->validate($licenseToValidate)) {
29999 if ($licenseValidator->validate(trim($licenseToValidate))) {
30000 $this->warnings[] = sprintf(
30001 'License %s must not contain extra spaces, make sure to trim it.',
30002 json_encode($license)
30003 );
30004 } else {
30005 $this->warnings[] = sprintf(
30006 'License %s is not a valid SPDX license identifier, see https://spdx.org/licenses/ if you use an open license.' . PHP_EOL .
30007 'If the software is closed-source, you may use "proprietary" as license.',
30008 json_encode($license)
30009 );
30010 }
30011 }
30012 }
30013 }
30014 }
30015
30016 if ($this->validateArray('authors') && !empty($this->config['authors'])) {
30017 foreach ($this->config['authors'] as $key => $author) {
30018 if (!is_array($author)) {
30019 $this->errors[] = 'authors.'.$key.' : should be an array, '.gettype($author).' given';
30020 unset($this->config['authors'][$key]);
30021 continue;
30022 }
30023 foreach (array('homepage', 'email', 'name', 'role') as $authorData) {
30024 if (isset($author[$authorData]) && !is_string($author[$authorData])) {
30025 $this->errors[] = 'authors.'.$key.'.'.$authorData.' : invalid value, must be a string';
30026 unset($this->config['authors'][$key][$authorData]);
30027 }
30028 }
30029 if (isset($author['homepage']) && !$this->filterUrl($author['homepage'])) {
30030 $this->warnings[] = 'authors.'.$key.'.homepage : invalid value ('.$author['homepage'].'), must be an http/https URL';
30031 unset($this->config['authors'][$key]['homepage']);
30032 }
30033 if (isset($author['email']) && !filter_var($author['email'], FILTER_VALIDATE_EMAIL)) {
30034 $this->warnings[] = 'authors.'.$key.'.email : invalid value ('.$author['email'].'), must be a valid email address';
30035 unset($this->config['authors'][$key]['email']);
30036 }
30037 if (empty($this->config['authors'][$key])) {
30038 unset($this->config['authors'][$key]);
30039 }
30040 }
30041 if (empty($this->config['authors'])) {
30042 unset($this->config['authors']);
30043 }
30044 }
30045
30046 if ($this->validateArray('support') && !empty($this->config['support'])) {
30047 foreach (array('issues', 'forum', 'wiki', 'source', 'email', 'irc', 'docs', 'rss', 'chat') as $key) {
30048 if (isset($this->config['support'][$key]) && !is_string($this->config['support'][$key])) {
30049 $this->errors[] = 'support.'.$key.' : invalid value, must be a string';
30050 unset($this->config['support'][$key]);
30051 }
30052 }
30053
30054 if (isset($this->config['support']['email']) && !filter_var($this->config['support']['email'], FILTER_VALIDATE_EMAIL)) {
30055 $this->warnings[] = 'support.email : invalid value ('.$this->config['support']['email'].'), must be a valid email address';
30056 unset($this->config['support']['email']);
30057 }
30058
30059 if (isset($this->config['support']['irc']) && !$this->filterUrl($this->config['support']['irc'], array('irc'))) {
30060 $this->warnings[] = 'support.irc : invalid value ('.$this->config['support']['irc'].'), must be a irc://<server>/<channel> URL';
30061 unset($this->config['support']['irc']);
30062 }
30063
30064 foreach (array('issues', 'forum', 'wiki', 'source', 'docs', 'chat') as $key) {
30065 if (isset($this->config['support'][$key]) && !$this->filterUrl($this->config['support'][$key])) {
30066 $this->warnings[] = 'support.'.$key.' : invalid value ('.$this->config['support'][$key].'), must be an http/https URL';
30067 unset($this->config['support'][$key]);
30068 }
30069 }
30070 if (empty($this->config['support'])) {
30071 unset($this->config['support']);
30072 }
30073 }
30074
30075 if ($this->validateArray('funding') && !empty($this->config['funding'])) {
30076 foreach ($this->config['funding'] as $key => $fundingOption) {
30077 if (!is_array($fundingOption)) {
30078 $this->errors[] = 'funding.'.$key.' : should be an array, '.gettype($fundingOption).' given';
30079 unset($this->config['funding'][$key]);
30080 continue;
30081 }
30082 foreach (array('type', 'url') as $fundingData) {
30083 if (isset($fundingOption[$fundingData]) && !is_string($fundingOption[$fundingData])) {
30084 $this->errors[] = 'funding.'.$key.'.'.$fundingData.' : invalid value, must be a string';
30085 unset($this->config['funding'][$key][$fundingData]);
30086 }
30087 }
30088 if (isset($fundingOption['url']) && !$this->filterUrl($fundingOption['url'])) {
30089 $this->warnings[] = 'funding.'.$key.'.url : invalid value ('.$fundingOption['url'].'), must be an http/https URL';
30090 unset($this->config['funding'][$key]['url']);
30091 }
30092 if (empty($this->config['funding'][$key])) {
30093 unset($this->config['funding'][$key]);
30094 }
30095 }
30096 if (empty($this->config['funding'])) {
30097 unset($this->config['funding']);
30098 }
30099 }
30100
30101 $unboundConstraint = new Constraint('=', $this->versionParser->normalize('dev-master'));
30102 $stableConstraint = new Constraint('=', '1.0.0');
30103
30104 foreach (array_keys(BasePackage::$supportedLinkTypes) as $linkType) {
30105 if ($this->validateArray($linkType) && isset($this->config[$linkType])) {
30106 foreach ($this->config[$linkType] as $package => $constraint) {
30107 if ($err = self::hasPackageNamingError($package, true)) {
30108 $this->warnings[] = 'Deprecation warning: '.$linkType.'.'.$err.' Make sure you fix this as Composer 2.0 will error.';
30109 } elseif (!preg_match('{^[A-Za-z0-9_./-]+$}', $package)) {
30110 $this->warnings[] = $linkType.'.'.$package.' : invalid key, package names must be strings containing only [A-Za-z0-9_./-]';
30111 }
30112 if (!is_string($constraint)) {
30113 $this->errors[] = $linkType.'.'.$package.' : invalid value, must be a string containing a version constraint';
30114 unset($this->config[$linkType][$package]);
30115 } elseif ('self.version' !== $constraint) {
30116 try {
30117 $linkConstraint = $this->versionParser->parseConstraints($constraint);
30118 } catch (\Exception $e) {
30119 $this->errors[] = $linkType.'.'.$package.' : invalid version constraint ('.$e->getMessage().')';
30120 unset($this->config[$linkType][$package]);
30121 continue;
30122 }
30123
30124
30125 if (
30126 ($this->flags & self::CHECK_UNBOUND_CONSTRAINTS)
30127 && 'require' === $linkType
30128 && $linkConstraint->matches($unboundConstraint)
30129 && !preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $package)
30130 ) {
30131 $this->warnings[] = $linkType.'.'.$package.' : unbound version constraints ('.$constraint.') should be avoided';
30132 } elseif (
30133
30134 ($this->flags & self::CHECK_STRICT_CONSTRAINTS)
30135 && 'require' === $linkType
30136 && substr($linkConstraint, 0, 1) === '='
30137 && $stableConstraint->versionCompare($stableConstraint, $linkConstraint, '<=')
30138 ) {
30139 $this->warnings[] = $linkType.'.'.$package.' : exact version constraints ('.$constraint.') should be avoided if the package follows semantic versioning';
30140 }
30141 }
30142 }
30143 }
30144 }
30145
30146 if ($this->validateArray('suggest') && !empty($this->config['suggest'])) {
30147 foreach ($this->config['suggest'] as $package => $description) {
30148 if (!is_string($description)) {
30149 $this->errors[] = 'suggest.'.$package.' : invalid value, must be a string describing why the package is suggested';
30150 unset($this->config['suggest'][$package]);
30151 }
30152 }
30153 }
30154
30155 if ($this->validateString('minimum-stability') && !empty($this->config['minimum-stability'])) {
30156 if (!isset(BasePackage::$stabilities[$this->config['minimum-stability']])) {
30157 $this->errors[] = 'minimum-stability : invalid value ('.$this->config['minimum-stability'].'), must be one of '.implode(', ', array_keys(BasePackage::$stabilities));
30158 unset($this->config['minimum-stability']);
30159 }
30160 }
30161
30162 if ($this->validateArray('autoload') && !empty($this->config['autoload'])) {
30163 $types = array('psr-0', 'psr-4', 'classmap', 'files', 'exclude-from-classmap');
30164 foreach ($this->config['autoload'] as $type => $typeConfig) {
30165 if (!in_array($type, $types)) {
30166 $this->errors[] = 'autoload : invalid value ('.$type.'), must be one of '.implode(', ', $types);
30167 unset($this->config['autoload'][$type]);
30168 }
30169 if ($type === 'psr-4') {
30170 foreach ($typeConfig as $namespace => $dirs) {
30171 if ($namespace !== '' && '\\' !== substr($namespace, -1)) {
30172 $this->errors[] = 'autoload.psr-4 : invalid value ('.$namespace.'), namespaces must end with a namespace separator, should be '.$namespace.'\\\\';
30173 }
30174 }
30175 }
30176 }
30177 }
30178
30179 if (!empty($this->config['autoload']['psr-4']) && !empty($this->config['target-dir'])) {
30180 $this->errors[] = 'target-dir : this can not be used together with the autoload.psr-4 setting, remove target-dir to upgrade to psr-4';
30181
30182
30183 unset($this->config['autoload']['psr-4']);
30184 }
30185
30186
30187
30188
30189
30190
30191
30192 $this->validateFlatArray('include-path');
30193 $this->validateArray('transport-options');
30194
30195
30196 if (isset($this->config['extra']['branch-alias'])) {
30197 if (!is_array($this->config['extra']['branch-alias'])) {
30198 $this->errors[] = 'extra.branch-alias : must be an array of versions => aliases';
30199 } else {
30200 foreach ($this->config['extra']['branch-alias'] as $sourceBranch => $targetBranch) {
30201
30202 if ('-dev' !== substr($targetBranch, -4)) {
30203 $this->warnings[] = 'extra.branch-alias.'.$sourceBranch.' : the target branch ('.$targetBranch.') must end in -dev';
30204 unset($this->config['extra']['branch-alias'][$sourceBranch]);
30205
30206 continue;
30207 }
30208
30209
30210 $validatedTargetBranch = $this->versionParser->normalizeBranch(substr($targetBranch, 0, -4));
30211 if ('-dev' !== substr($validatedTargetBranch, -4)) {
30212 $this->warnings[] = 'extra.branch-alias.'.$sourceBranch.' : the target branch ('.$targetBranch.') must be a parseable number like 2.0-dev';
30213 unset($this->config['extra']['branch-alias'][$sourceBranch]);
30214
30215 continue;
30216 }
30217
30218
30219 if (($sourcePrefix = $this->versionParser->parseNumericAliasPrefix($sourceBranch))
30220 && ($targetPrefix = $this->versionParser->parseNumericAliasPrefix($targetBranch))
30221 && (stripos($targetPrefix, $sourcePrefix) !== 0)
30222 ) {
30223 $this->warnings[] = 'extra.branch-alias.'.$sourceBranch.' : the target branch ('.$targetBranch.') is not a valid numeric alias for this version';
30224 unset($this->config['extra']['branch-alias'][$sourceBranch]);
30225 }
30226 }
30227 }
30228 }
30229
30230 if ($this->errors) {
30231 throw new InvalidPackageException($this->errors, $this->warnings, $config);
30232 }
30233
30234 $package = $this->loader->load($this->config, $class);
30235 $this->config = null;
30236
30237 return $package;
30238 }
30239
30240 public function getWarnings()
30241 {
30242 return $this->warnings;
30243 }
30244
30245 public function getErrors()
30246 {
30247 return $this->errors;
30248 }
30249
30250 public static function hasPackageNamingError($name, $isLink = false)
30251 {
30252 if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name)) {
30253 return;
30254 }
30255
30256 if (!preg_match('{^[a-z0-9](?:[_.-]?[a-z0-9]+)*/[a-z0-9](?:(?:[_.]?|-{0,2})[a-z0-9]+)*$}iD', $name)) {
30257 return $name.' is invalid, it should have a vendor name, a forward slash, and a package name. The vendor and package name can be words separated by -, . or _. The complete name should match "^[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9](([_.]?|-{0,2})[a-z0-9]+)*$".';
30258 }
30259
30260 $reservedNames = array('nul', 'con', 'prn', 'aux', 'com1', 'com2', 'com3', 'com4', 'com5', 'com6', 'com7', 'com8', 'com9', 'lpt1', 'lpt2', 'lpt3', 'lpt4', 'lpt5', 'lpt6', 'lpt7', 'lpt8', 'lpt9');
30261 $bits = explode('/', strtolower($name));
30262 if (in_array($bits[0], $reservedNames, true) || in_array($bits[1], $reservedNames, true)) {
30263 return $name.' is reserved, package and vendor names can not match any of: '.implode(', ', $reservedNames).'.';
30264 }
30265
30266 if (preg_match('{\.json$}', $name)) {
30267 return $name.' is invalid, package names can not end in .json, consider renaming it or perhaps using a -json suffix instead.';
30268 }
30269
30270 if (preg_match('{[A-Z]}', $name)) {
30271 if ($isLink) {
30272 return $name.' is invalid, it should not contain uppercase characters. Please use '.strtolower($name).' instead.';
30273 }
30274
30275 $suggestName = preg_replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $name);
30276 $suggestName = strtolower($suggestName);
30277
30278 return $name.' is invalid, it should not contain uppercase characters. We suggest using '.$suggestName.' instead.';
30279 }
30280 }
30281
30282 private function validateRegex($property, $regex, $mandatory = false)
30283 {
30284 if (!$this->validateString($property, $mandatory)) {
30285 return false;
30286 }
30287
30288 if (!preg_match('{^'.$regex.'$}u', $this->config[$property])) {
30289 $message = $property.' : invalid value ('.$this->config[$property].'), must match '.$regex;
30290 if ($mandatory) {
30291 $this->errors[] = $message;
30292 } else {
30293 $this->warnings[] = $message;
30294 }
30295 unset($this->config[$property]);
30296
30297 return false;
30298 }
30299
30300 return true;
30301 }
30302
30303 private function validateString($property, $mandatory = false)
30304 {
30305 if (isset($this->config[$property]) && !is_string($this->config[$property])) {
30306 $this->errors[] = $property.' : should be a string, '.gettype($this->config[$property]).' given';
30307 unset($this->config[$property]);
30308
30309 return false;
30310 }
30311
30312 if (!isset($this->config[$property]) || trim($this->config[$property]) === '') {
30313 if ($mandatory) {
30314 $this->errors[] = $property.' : must be present';
30315 }
30316 unset($this->config[$property]);
30317
30318 return false;
30319 }
30320
30321 return true;
30322 }
30323
30324 private function validateArray($property, $mandatory = false)
30325 {
30326 if (isset($this->config[$property]) && !is_array($this->config[$property])) {
30327 $this->errors[] = $property.' : should be an array, '.gettype($this->config[$property]).' given';
30328 unset($this->config[$property]);
30329
30330 return false;
30331 }
30332
30333 if (!isset($this->config[$property]) || !count($this->config[$property])) {
30334 if ($mandatory) {
30335 $this->errors[] = $property.' : must be present and contain at least one element';
30336 }
30337 unset($this->config[$property]);
30338
30339 return false;
30340 }
30341
30342 return true;
30343 }
30344
30345 private function validateFlatArray($property, $regex = null, $mandatory = false)
30346 {
30347 if (!$this->validateArray($property, $mandatory)) {
30348 return false;
30349 }
30350
30351 $pass = true;
30352 foreach ($this->config[$property] as $key => $value) {
30353 if (!is_string($value) && !is_numeric($value)) {
30354 $this->errors[] = $property.'.'.$key.' : must be a string or int, '.gettype($value).' given';
30355 unset($this->config[$property][$key]);
30356 $pass = false;
30357
30358 continue;
30359 }
30360
30361 if ($regex && !preg_match('{^'.$regex.'$}u', $value)) {
30362 $this->warnings[] = $property.'.'.$key.' : invalid value ('.$value.'), must match '.$regex;
30363 unset($this->config[$property][$key]);
30364 $pass = false;
30365 }
30366 }
30367
30368 return $pass;
30369 }
30370
30371 private function validateUrl($property, $mandatory = false)
30372 {
30373 if (!$this->validateString($property, $mandatory)) {
30374 return false;
30375 }
30376
30377 if (!$this->filterUrl($this->config[$property])) {
30378 $this->warnings[] = $property.' : invalid value ('.$this->config[$property].'), must be an http/https URL';
30379 unset($this->config[$property]);
30380
30381 return false;
30382 }
30383
30384 return true;
30385 }
30386
30387 private function filterUrl($value, array $schemes = array('http', 'https'))
30388 {
30389 if ($value === '') {
30390 return true;
30391 }
30392
30393 $bits = parse_url($value);
30394 if (empty($bits['scheme']) || empty($bits['host'])) {
30395 return false;
30396 }
30397
30398 if (!in_array($bits['scheme'], $schemes, true)) {
30399 return false;
30400 }
30401
30402 return true;
30403 }
30404 }
30405 <?php
30406
30407
30408
30409
30410
30411
30412
30413
30414
30415
30416
30417 namespace Composer\Package;
30418
30419 use Composer\Json\JsonFile;
30420 use Composer\Installer\InstallationManager;
30421 use Composer\Repository\RepositoryManager;
30422 use Composer\Util\ProcessExecutor;
30423 use Composer\Repository\ArrayRepository;
30424 use Composer\Package\Dumper\ArrayDumper;
30425 use Composer\Package\Loader\ArrayLoader;
30426 use Composer\Plugin\PluginInterface;
30427 use Composer\Util\Git as GitUtil;
30428 use Composer\IO\IOInterface;
30429 use Seld\JsonLint\ParsingException;
30430
30431
30432
30433
30434
30435
30436
30437 class Locker
30438 {
30439 private $lockFile;
30440 private $repositoryManager;
30441 private $installationManager;
30442 private $hash;
30443 private $contentHash;
30444 private $loader;
30445 private $dumper;
30446 private $process;
30447 private $lockDataCache;
30448
30449
30450
30451
30452
30453
30454
30455
30456
30457
30458 public function __construct(IOInterface $io, JsonFile $lockFile, RepositoryManager $repositoryManager, InstallationManager $installationManager, $composerFileContents)
30459 {
30460 $this->lockFile = $lockFile;
30461 $this->repositoryManager = $repositoryManager;
30462 $this->installationManager = $installationManager;
30463 $this->hash = md5($composerFileContents);
30464 $this->contentHash = self::getContentHash($composerFileContents);
30465 $this->loader = new ArrayLoader(null, true);
30466 $this->dumper = new ArrayDumper();
30467 $this->process = new ProcessExecutor($io);
30468 }
30469
30470
30471
30472
30473
30474
30475
30476
30477 public static function getContentHash($composerFileContents)
30478 {
30479 $content = json_decode($composerFileContents, true);
30480
30481 $relevantKeys = array(
30482 'name',
30483 'version',
30484 'require',
30485 'require-dev',
30486 'conflict',
30487 'replace',
30488 'provide',
30489 'minimum-stability',
30490 'prefer-stable',
30491 'repositories',
30492 'extra',
30493 );
30494
30495 $relevantContent = array();
30496
30497 foreach (array_intersect($relevantKeys, array_keys($content)) as $key) {
30498 $relevantContent[$key] = $content[$key];
30499 }
30500 if (isset($content['config']['platform'])) {
30501 $relevantContent['config']['platform'] = $content['config']['platform'];
30502 }
30503
30504 ksort($relevantContent);
30505
30506 return md5(json_encode($relevantContent));
30507 }
30508
30509
30510
30511
30512
30513
30514 public function isLocked()
30515 {
30516 if (!$this->lockFile->exists()) {
30517 return false;
30518 }
30519
30520 $data = $this->getLockData();
30521
30522 return isset($data['packages']);
30523 }
30524
30525
30526
30527
30528
30529
30530 public function isFresh()
30531 {
30532 $lock = $this->lockFile->read();
30533
30534 if (!empty($lock['content-hash'])) {
30535
30536 return $this->contentHash === $lock['content-hash'];
30537 }
30538
30539
30540 if (!empty($lock['hash'])) {
30541 return $this->hash === $lock['hash'];
30542 }
30543
30544
30545 return false;
30546 }
30547
30548
30549
30550
30551
30552
30553
30554
30555 public function getLockedRepository($withDevReqs = false)
30556 {
30557 $lockData = $this->getLockData();
30558 $packages = new ArrayRepository();
30559
30560 $lockedPackages = $lockData['packages'];
30561 if ($withDevReqs) {
30562 if (isset($lockData['packages-dev'])) {
30563 $lockedPackages = array_merge($lockedPackages, $lockData['packages-dev']);
30564 } else {
30565 throw new \RuntimeException('The lock file does not contain require-dev information, run install with the --no-dev option or run update to install those packages.');
30566 }
30567 }
30568
30569 if (empty($lockedPackages)) {
30570 return $packages;
30571 }
30572
30573 if (isset($lockedPackages[0]['name'])) {
30574 foreach ($lockedPackages as $info) {
30575 $packages->addPackage($this->loader->load($info));
30576 }
30577
30578 return $packages;
30579 }
30580
30581 throw new \RuntimeException('Your composer.lock was created before 2012-09-15, and is not supported anymore. Run "composer update" to generate a new one.');
30582 }
30583
30584
30585
30586
30587
30588
30589
30590 public function getPlatformRequirements($withDevReqs = false)
30591 {
30592 $lockData = $this->getLockData();
30593 $requirements = array();
30594
30595 if (!empty($lockData['platform'])) {
30596 $requirements = $this->loader->parseLinks(
30597 '__ROOT__',
30598 '1.0.0',
30599 'requires',
30600 isset($lockData['platform']) ? $lockData['platform'] : array()
30601 );
30602 }
30603
30604 if ($withDevReqs && !empty($lockData['platform-dev'])) {
30605 $devRequirements = $this->loader->parseLinks(
30606 '__ROOT__',
30607 '1.0.0',
30608 'requires',
30609 isset($lockData['platform-dev']) ? $lockData['platform-dev'] : array()
30610 );
30611
30612 $requirements = array_merge($requirements, $devRequirements);
30613 }
30614
30615 return $requirements;
30616 }
30617
30618 public function getMinimumStability()
30619 {
30620 $lockData = $this->getLockData();
30621
30622 return isset($lockData['minimum-stability']) ? $lockData['minimum-stability'] : 'stable';
30623 }
30624
30625 public function getStabilityFlags()
30626 {
30627 $lockData = $this->getLockData();
30628
30629 return isset($lockData['stability-flags']) ? $lockData['stability-flags'] : array();
30630 }
30631
30632 public function getPreferStable()
30633 {
30634 $lockData = $this->getLockData();
30635
30636
30637
30638 return isset($lockData['prefer-stable']) ? $lockData['prefer-stable'] : null;
30639 }
30640
30641 public function getPreferLowest()
30642 {
30643 $lockData = $this->getLockData();
30644
30645
30646
30647 return isset($lockData['prefer-lowest']) ? $lockData['prefer-lowest'] : null;
30648 }
30649
30650 public function getPlatformOverrides()
30651 {
30652 $lockData = $this->getLockData();
30653
30654 return isset($lockData['platform-overrides']) ? $lockData['platform-overrides'] : array();
30655 }
30656
30657 public function getAliases()
30658 {
30659 $lockData = $this->getLockData();
30660
30661 if (!isset($lockData['aliases'])) {
30662 return array();
30663 }
30664
30665
30666
30667 foreach ($lockData['aliases'] as $index => $alias) {
30668 if (in_array($alias['version'], array('dev-master', 'dev-default', 'dev-trunk'), true)) {
30669 $lockData['aliases'][$index]['version'] = '9999999-dev';
30670 }
30671 }
30672
30673 return $lockData['aliases'];
30674 }
30675
30676 public function getLockData()
30677 {
30678 if (null !== $this->lockDataCache) {
30679 return $this->lockDataCache;
30680 }
30681
30682 if (!$this->lockFile->exists()) {
30683 throw new \LogicException('No lockfile found. Unable to read locked packages');
30684 }
30685
30686 return $this->lockDataCache = $this->lockFile->read();
30687 }
30688
30689
30690
30691
30692
30693
30694
30695
30696
30697
30698
30699
30700
30701
30702
30703
30704
30705 public function setLockData(array $packages, $devPackages, array $platformReqs, $platformDevReqs, array $aliases, $minimumStability, array $stabilityFlags, $preferStable, $preferLowest, array $platformOverrides)
30706 {
30707 $lock = array(
30708 '_readme' => array('This file locks the dependencies of your project to a known state',
30709 'Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies',
30710 'This file is @gener'.'ated automatically', ),
30711 'content-hash' => $this->contentHash,
30712 'packages' => null,
30713 'packages-dev' => null,
30714 'aliases' => array(),
30715 'minimum-stability' => $minimumStability,
30716 'stability-flags' => $stabilityFlags,
30717 'prefer-stable' => $preferStable,
30718 'prefer-lowest' => $preferLowest,
30719 );
30720
30721 foreach ($aliases as $package => $versions) {
30722 foreach ($versions as $version => $alias) {
30723 $lock['aliases'][] = array(
30724 'alias' => $alias['alias'],
30725 'alias_normalized' => $alias['alias_normalized'],
30726 'version' => $version,
30727 'package' => $package,
30728 );
30729 }
30730 }
30731
30732 $lock['packages'] = $this->lockPackages($packages);
30733 if (null !== $devPackages) {
30734 $lock['packages-dev'] = $this->lockPackages($devPackages);
30735 }
30736
30737 $lock['platform'] = $platformReqs;
30738 $lock['platform-dev'] = $platformDevReqs;
30739 if ($platformOverrides) {
30740 $lock['platform-overrides'] = $platformOverrides;
30741 }
30742 $lock['plugin-api-version'] = PluginInterface::PLUGIN_API_VERSION;
30743
30744 if (empty($lock['packages']) && empty($lock['packages-dev']) && empty($lock['platform']) && empty($lock['platform-dev'])) {
30745 if ($this->lockFile->exists()) {
30746 unlink($this->lockFile->getPath());
30747 }
30748
30749 return false;
30750 }
30751
30752 try {
30753 $isLocked = $this->isLocked();
30754 } catch (ParsingException $e) {
30755 $isLocked = false;
30756 }
30757 if (!$isLocked || $lock !== $this->getLockData()) {
30758 $this->lockFile->write($lock);
30759 $this->lockDataCache = null;
30760
30761 return true;
30762 }
30763
30764 return false;
30765 }
30766
30767 private function lockPackages(array $packages)
30768 {
30769 $locked = array();
30770
30771 foreach ($packages as $package) {
30772 if ($package instanceof AliasPackage) {
30773 continue;
30774 }
30775
30776 $name = $package->getPrettyName();
30777 $version = $package->getPrettyVersion();
30778
30779 if (!$name || !$version) {
30780 throw new \LogicException(sprintf(
30781 'Package "%s" has no version or name and can not be locked',
30782 $package
30783 ));
30784 }
30785
30786 $spec = $this->dumper->dump($package);
30787 unset($spec['version_normalized']);
30788
30789
30790 $time = isset($spec['time']) ? $spec['time'] : null;
30791 unset($spec['time']);
30792 if ($package->isDev() && $package->getInstallationSource() === 'source') {
30793
30794 $time = $this->getPackageTime($package) ?: $time;
30795 }
30796 if (null !== $time) {
30797 $spec['time'] = $time;
30798 }
30799
30800 unset($spec['installation-source']);
30801
30802 $locked[] = $spec;
30803 }
30804
30805 usort($locked, function ($a, $b) {
30806 $comparison = strcmp($a['name'], $b['name']);
30807
30808 if (0 !== $comparison) {
30809 return $comparison;
30810 }
30811
30812
30813 return strcmp($a['version'], $b['version']);
30814 });
30815
30816 return $locked;
30817 }
30818
30819
30820
30821
30822
30823
30824
30825 private function getPackageTime(PackageInterface $package)
30826 {
30827 if (!function_exists('proc_open')) {
30828 return null;
30829 }
30830
30831 $path = realpath($this->installationManager->getInstallPath($package));
30832 $sourceType = $package->getSourceType();
30833 $datetime = null;
30834
30835 if ($path && in_array($sourceType, array('git', 'hg'))) {
30836 $sourceRef = $package->getSourceReference() ?: $package->getDistReference();
30837 switch ($sourceType) {
30838 case 'git':
30839 GitUtil::cleanEnv();
30840
30841 if (0 === $this->process->execute('git log -n1 --pretty=%ct '.ProcessExecutor::escape($sourceRef).GitUtil::getNoShowSignatureFlag($this->process), $output, $path) && preg_match('{^\s*\d+\s*$}', $output)) {
30842 $datetime = new \DateTime('@'.trim($output), new \DateTimeZone('UTC'));
30843 }
30844 break;
30845
30846 case 'hg':
30847 if (0 === $this->process->execute('hg log --template "{date|hgdate}" -r '.ProcessExecutor::escape($sourceRef), $output, $path) && preg_match('{^\s*(\d+)\s*}', $output, $match)) {
30848 $datetime = new \DateTime('@'.$match[1], new \DateTimeZone('UTC'));
30849 }
30850 break;
30851 }
30852 }
30853
30854 return $datetime ? $datetime->format(DATE_RFC3339) : null;
30855 }
30856 }
30857 <?php
30858
30859
30860
30861
30862
30863
30864
30865
30866
30867
30868
30869 namespace Composer\Package;
30870
30871 use Composer\Package\Version\VersionParser;
30872 use Composer\Util\ComposerMirror;
30873
30874
30875
30876
30877
30878
30879 class Package extends BasePackage
30880 {
30881 protected $type;
30882 protected $targetDir;
30883 protected $installationSource;
30884 protected $sourceType;
30885 protected $sourceUrl;
30886 protected $sourceReference;
30887 protected $sourceMirrors;
30888 protected $distType;
30889 protected $distUrl;
30890 protected $distReference;
30891 protected $distSha1Checksum;
30892 protected $distMirrors;
30893 protected $version;
30894 protected $prettyVersion;
30895 protected $releaseDate;
30896 protected $extra = array();
30897 protected $binaries = array();
30898 protected $dev;
30899 protected $stability;
30900 protected $notificationUrl;
30901
30902
30903 protected $requires = array();
30904
30905 protected $conflicts = array();
30906
30907 protected $provides = array();
30908
30909 protected $replaces = array();
30910
30911 protected $devRequires = array();
30912 protected $suggests = array();
30913 protected $autoload = array();
30914 protected $devAutoload = array();
30915 protected $includePaths = array();
30916 protected $archiveExcludes = array();
30917
30918
30919
30920
30921
30922
30923
30924
30925 public function __construct($name, $version, $prettyVersion)
30926 {
30927 parent::__construct($name);
30928
30929 $this->version = $version;
30930 $this->prettyVersion = $prettyVersion;
30931
30932 $this->stability = VersionParser::parseStability($version);
30933 $this->dev = $this->stability === 'dev';
30934 }
30935
30936
30937
30938
30939 public function isDev()
30940 {
30941 return $this->dev;
30942 }
30943
30944
30945
30946
30947 public function setType($type)
30948 {
30949 $this->type = $type;
30950 }
30951
30952
30953
30954
30955 public function getType()
30956 {
30957 return $this->type ?: 'library';
30958 }
30959
30960
30961
30962
30963 public function getStability()
30964 {
30965 return $this->stability;
30966 }
30967
30968
30969
30970
30971 public function setTargetDir($targetDir)
30972 {
30973 $this->targetDir = $targetDir;
30974 }
30975
30976
30977
30978
30979 public function getTargetDir()
30980 {
30981 if (null === $this->targetDir) {
30982 return;
30983 }
30984
30985 return ltrim(preg_replace('{ (?:^|[\\\\/]+) \.\.? (?:[\\\\/]+|$) (?:\.\.? (?:[\\\\/]+|$) )*}x', '/', $this->targetDir), '/');
30986 }
30987
30988
30989
30990
30991 public function setExtra(array $extra)
30992 {
30993 $this->extra = $extra;
30994 }
30995
30996
30997
30998
30999 public function getExtra()
31000 {
31001 return $this->extra;
31002 }
31003
31004
31005
31006
31007 public function setBinaries(array $binaries)
31008 {
31009 $this->binaries = $binaries;
31010 }
31011
31012
31013
31014
31015 public function getBinaries()
31016 {
31017 return $this->binaries;
31018 }
31019
31020
31021
31022
31023 public function setInstallationSource($type)
31024 {
31025 $this->installationSource = $type;
31026 }
31027
31028
31029
31030
31031 public function getInstallationSource()
31032 {
31033 return $this->installationSource;
31034 }
31035
31036
31037
31038
31039 public function setSourceType($type)
31040 {
31041 $this->sourceType = $type;
31042 }
31043
31044
31045
31046
31047 public function getSourceType()
31048 {
31049 return $this->sourceType;
31050 }
31051
31052
31053
31054
31055 public function setSourceUrl($url)
31056 {
31057 $this->sourceUrl = $url;
31058 }
31059
31060
31061
31062
31063 public function getSourceUrl()
31064 {
31065 return $this->sourceUrl;
31066 }
31067
31068
31069
31070
31071 public function setSourceReference($reference)
31072 {
31073 $this->sourceReference = $reference;
31074 }
31075
31076
31077
31078
31079 public function getSourceReference()
31080 {
31081 return $this->sourceReference;
31082 }
31083
31084
31085
31086
31087 public function setSourceMirrors($mirrors)
31088 {
31089 $this->sourceMirrors = $mirrors;
31090 }
31091
31092
31093
31094
31095 public function getSourceMirrors()
31096 {
31097 return $this->sourceMirrors;
31098 }
31099
31100
31101
31102
31103 public function getSourceUrls()
31104 {
31105 return $this->getUrls($this->sourceUrl, $this->sourceMirrors, $this->sourceReference, $this->sourceType, 'source');
31106 }
31107
31108
31109
31110
31111 public function setDistType($type)
31112 {
31113 $this->distType = $type;
31114 }
31115
31116
31117
31118
31119 public function getDistType()
31120 {
31121 return $this->distType;
31122 }
31123
31124
31125
31126
31127 public function setDistUrl($url)
31128 {
31129 $this->distUrl = $url;
31130 }
31131
31132
31133
31134
31135 public function getDistUrl()
31136 {
31137 return $this->distUrl;
31138 }
31139
31140
31141
31142
31143 public function setDistReference($reference)
31144 {
31145 $this->distReference = $reference;
31146 }
31147
31148
31149
31150
31151 public function getDistReference()
31152 {
31153 return $this->distReference;
31154 }
31155
31156
31157
31158
31159 public function setDistSha1Checksum($sha1checksum)
31160 {
31161 $this->distSha1Checksum = $sha1checksum;
31162 }
31163
31164
31165
31166
31167 public function getDistSha1Checksum()
31168 {
31169 return $this->distSha1Checksum;
31170 }
31171
31172
31173
31174
31175 public function setDistMirrors($mirrors)
31176 {
31177 $this->distMirrors = $mirrors;
31178 }
31179
31180
31181
31182
31183 public function getDistMirrors()
31184 {
31185 return $this->distMirrors;
31186 }
31187
31188
31189
31190
31191 public function getDistUrls()
31192 {
31193 return $this->getUrls($this->distUrl, $this->distMirrors, $this->distReference, $this->distType, 'dist');
31194 }
31195
31196
31197
31198
31199 public function getVersion()
31200 {
31201 return $this->version;
31202 }
31203
31204
31205
31206
31207 public function getPrettyVersion()
31208 {
31209 return $this->prettyVersion;
31210 }
31211
31212
31213
31214
31215
31216
31217 public function setReleaseDate(\DateTime $releaseDate)
31218 {
31219 $this->releaseDate = $releaseDate;
31220 }
31221
31222
31223
31224
31225 public function getReleaseDate()
31226 {
31227 return $this->releaseDate;
31228 }
31229
31230
31231
31232
31233
31234
31235 public function setRequires(array $requires)
31236 {
31237 $this->requires = $requires;
31238 }
31239
31240
31241
31242
31243 public function getRequires()
31244 {
31245 return $this->requires;
31246 }
31247
31248
31249
31250
31251
31252
31253 public function setConflicts(array $conflicts)
31254 {
31255 $this->conflicts = $conflicts;
31256 }
31257
31258
31259
31260
31261 public function getConflicts()
31262 {
31263 return $this->conflicts;
31264 }
31265
31266
31267
31268
31269
31270
31271 public function setProvides(array $provides)
31272 {
31273 $this->provides = $provides;
31274 }
31275
31276
31277
31278
31279 public function getProvides()
31280 {
31281 return $this->provides;
31282 }
31283
31284
31285
31286
31287
31288
31289 public function setReplaces(array $replaces)
31290 {
31291 $this->replaces = $replaces;
31292 }
31293
31294
31295
31296
31297 public function getReplaces()
31298 {
31299 return $this->replaces;
31300 }
31301
31302
31303
31304
31305
31306
31307 public function setDevRequires(array $devRequires)
31308 {
31309 $this->devRequires = $devRequires;
31310 }
31311
31312
31313
31314
31315 public function getDevRequires()
31316 {
31317 return $this->devRequires;
31318 }
31319
31320
31321
31322
31323
31324
31325 public function setSuggests(array $suggests)
31326 {
31327 $this->suggests = $suggests;
31328 }
31329
31330
31331
31332
31333 public function getSuggests()
31334 {
31335 return $this->suggests;
31336 }
31337
31338
31339
31340
31341
31342
31343 public function setAutoload(array $autoload)
31344 {
31345 $this->autoload = $autoload;
31346 }
31347
31348
31349
31350
31351 public function getAutoload()
31352 {
31353 return $this->autoload;
31354 }
31355
31356
31357
31358
31359
31360
31361 public function setDevAutoload(array $devAutoload)
31362 {
31363 $this->devAutoload = $devAutoload;
31364 }
31365
31366
31367
31368
31369 public function getDevAutoload()
31370 {
31371 return $this->devAutoload;
31372 }
31373
31374
31375
31376
31377
31378
31379 public function setIncludePaths(array $includePaths)
31380 {
31381 $this->includePaths = $includePaths;
31382 }
31383
31384
31385
31386
31387 public function getIncludePaths()
31388 {
31389 return $this->includePaths;
31390 }
31391
31392
31393
31394
31395
31396
31397 public function setNotificationUrl($notificationUrl)
31398 {
31399 $this->notificationUrl = $notificationUrl;
31400 }
31401
31402
31403
31404
31405 public function getNotificationUrl()
31406 {
31407 return $this->notificationUrl;
31408 }
31409
31410
31411
31412
31413
31414
31415 public function setArchiveExcludes(array $excludes)
31416 {
31417 $this->archiveExcludes = $excludes;
31418 }
31419
31420
31421
31422
31423 public function getArchiveExcludes()
31424 {
31425 return $this->archiveExcludes;
31426 }
31427
31428
31429
31430
31431
31432
31433
31434
31435 public function replaceVersion($version, $prettyVersion)
31436 {
31437 $this->version = $version;
31438 $this->prettyVersion = $prettyVersion;
31439
31440 $this->stability = VersionParser::parseStability($version);
31441 $this->dev = $this->stability === 'dev';
31442 }
31443
31444 protected function getUrls($url, $mirrors, $ref, $type, $urlType)
31445 {
31446 if (!$url) {
31447 return array();
31448 }
31449 $urls = array($url);
31450 if ($mirrors) {
31451 foreach ($mirrors as $mirror) {
31452 if ($urlType === 'dist') {
31453 $mirrorUrl = ComposerMirror::processUrl($mirror['url'], $this->name, $this->version, $ref, $type);
31454 } elseif ($urlType === 'source' && $type === 'git') {
31455 $mirrorUrl = ComposerMirror::processGitUrl($mirror['url'], $this->name, $url, $type);
31456 } elseif ($urlType === 'source' && $type === 'hg') {
31457 $mirrorUrl = ComposerMirror::processHgUrl($mirror['url'], $this->name, $url, $type);
31458 }
31459 if (!in_array($mirrorUrl, $urls)) {
31460 $func = $mirror['preferred'] ? 'array_unshift' : 'array_push';
31461 $func($urls, $mirrorUrl);
31462 }
31463 }
31464 }
31465
31466 return $urls;
31467 }
31468 }
31469 <?php
31470
31471
31472
31473
31474
31475
31476
31477
31478
31479
31480
31481 namespace Composer\Package;
31482
31483 use Composer\Repository\RepositoryInterface;
31484
31485
31486
31487
31488
31489
31490 interface PackageInterface
31491 {
31492
31493
31494
31495
31496
31497 public function getName();
31498
31499
31500
31501
31502
31503
31504 public function getPrettyName();
31505
31506
31507
31508
31509
31510
31511
31512
31513
31514 public function getNames();
31515
31516
31517
31518
31519
31520
31521 public function setId($id);
31522
31523
31524
31525
31526
31527
31528 public function getId();
31529
31530
31531
31532
31533
31534
31535 public function isDev();
31536
31537
31538
31539
31540
31541
31542 public function getType();
31543
31544
31545
31546
31547
31548
31549 public function getTargetDir();
31550
31551
31552
31553
31554
31555
31556 public function getExtra();
31557
31558
31559
31560
31561
31562
31563 public function setInstallationSource($type);
31564
31565
31566
31567
31568
31569
31570 public function getInstallationSource();
31571
31572
31573
31574
31575
31576
31577 public function getSourceType();
31578
31579
31580
31581
31582
31583
31584 public function getSourceUrl();
31585
31586
31587
31588
31589
31590
31591 public function getSourceUrls();
31592
31593
31594
31595
31596
31597
31598 public function getSourceReference();
31599
31600
31601
31602
31603
31604
31605 public function getSourceMirrors();
31606
31607
31608
31609
31610
31611
31612 public function getDistType();
31613
31614
31615
31616
31617
31618
31619 public function getDistUrl();
31620
31621
31622
31623
31624
31625
31626 public function getDistUrls();
31627
31628
31629
31630
31631
31632
31633 public function getDistReference();
31634
31635
31636
31637
31638
31639
31640 public function getDistSha1Checksum();
31641
31642
31643
31644
31645
31646
31647 public function getDistMirrors();
31648
31649
31650
31651
31652
31653
31654 public function getVersion();
31655
31656
31657
31658
31659
31660
31661 public function getPrettyVersion();
31662
31663
31664
31665
31666
31667
31668
31669
31670
31671 public function getFullPrettyVersion($truncate = true);
31672
31673
31674
31675
31676
31677
31678 public function getReleaseDate();
31679
31680
31681
31682
31683
31684
31685 public function getStability();
31686
31687
31688
31689
31690
31691
31692
31693 public function getRequires();
31694
31695
31696
31697
31698
31699
31700
31701 public function getConflicts();
31702
31703
31704
31705
31706
31707
31708
31709 public function getProvides();
31710
31711
31712
31713
31714
31715
31716
31717 public function getReplaces();
31718
31719
31720
31721
31722
31723
31724
31725 public function getDevRequires();
31726
31727
31728
31729
31730
31731
31732
31733 public function getSuggests();
31734
31735
31736
31737
31738
31739
31740
31741
31742
31743
31744
31745 public function getAutoload();
31746
31747
31748
31749
31750
31751
31752
31753
31754
31755
31756
31757 public function getDevAutoload();
31758
31759
31760
31761
31762
31763
31764
31765 public function getIncludePaths();
31766
31767
31768
31769
31770
31771
31772 public function setRepository(RepositoryInterface $repository);
31773
31774
31775
31776
31777
31778
31779 public function getRepository();
31780
31781
31782
31783
31784
31785
31786 public function getBinaries();
31787
31788
31789
31790
31791
31792
31793 public function getUniqueName();
31794
31795
31796
31797
31798
31799
31800 public function getNotificationUrl();
31801
31802
31803
31804
31805
31806
31807 public function __toString();
31808
31809
31810
31811
31812
31813
31814 public function getPrettyString();
31815
31816
31817
31818
31819
31820
31821 public function getArchiveExcludes();
31822
31823
31824
31825
31826
31827
31828 public function getTransportOptions();
31829
31830
31831
31832
31833
31834
31835 public function setSourceReference($reference);
31836
31837
31838
31839
31840
31841
31842 public function setDistUrl($url);
31843
31844
31845
31846
31847
31848
31849 public function setDistType($type);
31850
31851
31852
31853
31854
31855
31856 public function setDistReference($reference);
31857 }
31858 <?php
31859
31860
31861
31862
31863
31864
31865
31866
31867
31868
31869
31870 namespace Composer\Package;
31871
31872
31873
31874
31875 class RootAliasPackage extends AliasPackage implements RootPackageInterface
31876 {
31877 public function __construct(RootPackageInterface $aliasOf, $version, $prettyVersion)
31878 {
31879 parent::__construct($aliasOf, $version, $prettyVersion);
31880 }
31881
31882
31883
31884
31885 public function getAliases()
31886 {
31887 return $this->aliasOf->getAliases();
31888 }
31889
31890
31891
31892
31893 public function getMinimumStability()
31894 {
31895 return $this->aliasOf->getMinimumStability();
31896 }
31897
31898
31899
31900
31901 public function getStabilityFlags()
31902 {
31903 return $this->aliasOf->getStabilityFlags();
31904 }
31905
31906
31907
31908
31909 public function getReferences()
31910 {
31911 return $this->aliasOf->getReferences();
31912 }
31913
31914
31915
31916
31917 public function getPreferStable()
31918 {
31919 return $this->aliasOf->getPreferStable();
31920 }
31921
31922
31923
31924
31925 public function getConfig()
31926 {
31927 return $this->aliasOf->getConfig();
31928 }
31929
31930
31931
31932
31933 public function setRequires(array $require)
31934 {
31935 $this->requires = $this->replaceSelfVersionDependencies($require, 'requires');
31936
31937 $this->aliasOf->setRequires($require);
31938 }
31939
31940
31941
31942
31943 public function setDevRequires(array $devRequire)
31944 {
31945 $this->devRequires = $this->replaceSelfVersionDependencies($devRequire, 'devRequires');
31946
31947 $this->aliasOf->setDevRequires($devRequire);
31948 }
31949
31950
31951
31952
31953 public function setConflicts(array $conflicts)
31954 {
31955 $this->conflicts = $this->replaceSelfVersionDependencies($conflicts, 'conflicts');
31956 $this->aliasOf->setConflicts($conflicts);
31957 }
31958
31959
31960
31961
31962 public function setProvides(array $provides)
31963 {
31964 $this->provides = $this->replaceSelfVersionDependencies($provides, 'provides');
31965 $this->aliasOf->setProvides($provides);
31966 }
31967
31968
31969
31970
31971 public function setReplaces(array $replaces)
31972 {
31973 $this->replaces = $this->replaceSelfVersionDependencies($replaces, 'replaces');
31974 $this->aliasOf->setReplaces($replaces);
31975 }
31976
31977
31978
31979
31980 public function setRepositories($repositories)
31981 {
31982 $this->aliasOf->setRepositories($repositories);
31983 }
31984
31985
31986
31987
31988 public function setAutoload(array $autoload)
31989 {
31990 $this->aliasOf->setAutoload($autoload);
31991 }
31992
31993
31994
31995
31996 public function setDevAutoload(array $devAutoload)
31997 {
31998 $this->aliasOf->setDevAutoload($devAutoload);
31999 }
32000
32001
32002
32003
32004 public function setStabilityFlags(array $stabilityFlags)
32005 {
32006 $this->aliasOf->setStabilityFlags($stabilityFlags);
32007 }
32008
32009
32010
32011
32012 public function setSuggests(array $suggests)
32013 {
32014 $this->aliasOf->setSuggests($suggests);
32015 }
32016
32017
32018
32019
32020 public function setExtra(array $extra)
32021 {
32022 $this->aliasOf->setExtra($extra);
32023 }
32024
32025 public function __clone()
32026 {
32027 parent::__clone();
32028 $this->aliasOf = clone $this->aliasOf;
32029 }
32030 }
32031 <?php
32032
32033
32034
32035
32036
32037
32038
32039
32040
32041
32042
32043 namespace Composer\Package;
32044
32045
32046
32047
32048
32049
32050 class RootPackage extends CompletePackage implements RootPackageInterface
32051 {
32052 protected $minimumStability = 'stable';
32053 protected $preferStable = false;
32054 protected $stabilityFlags = array();
32055 protected $config = array();
32056 protected $references = array();
32057 protected $aliases = array();
32058
32059
32060
32061
32062
32063
32064 public function setMinimumStability($minimumStability)
32065 {
32066 $this->minimumStability = $minimumStability;
32067 }
32068
32069
32070
32071
32072 public function getMinimumStability()
32073 {
32074 return $this->minimumStability;
32075 }
32076
32077
32078
32079
32080
32081
32082 public function setStabilityFlags(array $stabilityFlags)
32083 {
32084 $this->stabilityFlags = $stabilityFlags;
32085 }
32086
32087
32088
32089
32090 public function getStabilityFlags()
32091 {
32092 return $this->stabilityFlags;
32093 }
32094
32095
32096
32097
32098
32099
32100 public function setPreferStable($preferStable)
32101 {
32102 $this->preferStable = $preferStable;
32103 }
32104
32105
32106
32107
32108 public function getPreferStable()
32109 {
32110 return $this->preferStable;
32111 }
32112
32113
32114
32115
32116
32117
32118 public function setConfig(array $config)
32119 {
32120 $this->config = $config;
32121 }
32122
32123
32124
32125
32126 public function getConfig()
32127 {
32128 return $this->config;
32129 }
32130
32131
32132
32133
32134
32135
32136 public function setReferences(array $references)
32137 {
32138 $this->references = $references;
32139 }
32140
32141
32142
32143
32144 public function getReferences()
32145 {
32146 return $this->references;
32147 }
32148
32149
32150
32151
32152
32153
32154 public function setAliases(array $aliases)
32155 {
32156 $this->aliases = $aliases;
32157 }
32158
32159
32160
32161
32162 public function getAliases()
32163 {
32164 return $this->aliases;
32165 }
32166 }
32167 <?php
32168
32169
32170
32171
32172
32173
32174
32175
32176
32177
32178
32179 namespace Composer\Package;
32180
32181
32182
32183
32184
32185
32186 interface RootPackageInterface extends CompletePackageInterface
32187 {
32188
32189
32190
32191
32192
32193 public function getAliases();
32194
32195
32196
32197
32198
32199
32200 public function getMinimumStability();
32201
32202
32203
32204
32205
32206
32207
32208
32209 public function getStabilityFlags();
32210
32211
32212
32213
32214
32215
32216
32217
32218 public function getReferences();
32219
32220
32221
32222
32223
32224
32225 public function getPreferStable();
32226
32227
32228
32229
32230
32231
32232 public function getConfig();
32233
32234
32235
32236
32237
32238
32239 public function setRequires(array $requires);
32240
32241
32242
32243
32244
32245
32246 public function setDevRequires(array $devRequires);
32247
32248
32249
32250
32251
32252
32253 public function setConflicts(array $conflicts);
32254
32255
32256
32257
32258
32259
32260 public function setProvides(array $provides);
32261
32262
32263
32264
32265
32266
32267 public function setReplaces(array $replaces);
32268
32269
32270
32271
32272
32273
32274 public function setRepositories($repositories);
32275
32276
32277
32278
32279
32280
32281 public function setAutoload(array $autoload);
32282
32283
32284
32285
32286
32287
32288 public function setDevAutoload(array $devAutoload);
32289
32290
32291
32292
32293
32294
32295 public function setStabilityFlags(array $stabilityFlags);
32296
32297
32298
32299
32300
32301
32302 public function setSuggests(array $suggests);
32303
32304
32305
32306
32307 public function setExtra(array $extra);
32308 }
32309 <?php
32310
32311
32312
32313
32314
32315
32316
32317
32318
32319
32320
32321 namespace Composer\Package\Version;
32322
32323 use Composer\Config;
32324 use Composer\Repository\Vcs\HgDriver;
32325 use Composer\IO\NullIO;
32326 use Composer\Semver\VersionParser as SemverVersionParser;
32327 use Composer\Util\Git as GitUtil;
32328 use Composer\Util\ProcessExecutor;
32329 use Composer\Util\Svn as SvnUtil;
32330
32331
32332
32333
32334
32335
32336
32337 class VersionGuesser
32338 {
32339
32340
32341
32342 private $config;
32343
32344
32345
32346
32347 private $process;
32348
32349
32350
32351
32352 private $versionParser;
32353
32354
32355
32356
32357
32358
32359 public function __construct(Config $config, ProcessExecutor $process, SemverVersionParser $versionParser)
32360 {
32361 $this->config = $config;
32362 $this->process = $process;
32363 $this->versionParser = $versionParser;
32364 }
32365
32366
32367
32368
32369
32370
32371
32372 public function guessVersion(array $packageConfig, $path)
32373 {
32374 if (!function_exists('proc_open')) {
32375 return null;
32376 }
32377
32378 $versionData = $this->guessGitVersion($packageConfig, $path);
32379 if (null !== $versionData && null !== $versionData['version']) {
32380 return $this->postprocess($versionData);
32381 }
32382
32383 $versionData = $this->guessHgVersion($packageConfig, $path);
32384 if (null !== $versionData && null !== $versionData['version']) {
32385 return $this->postprocess($versionData);
32386 }
32387
32388 $versionData = $this->guessFossilVersion($packageConfig, $path);
32389 if (null !== $versionData && null !== $versionData['version']) {
32390 return $this->postprocess($versionData);
32391 }
32392
32393 $versionData = $this->guessSvnVersion($packageConfig, $path);
32394 if (null !== $versionData && null !== $versionData['version']) {
32395 return $this->postprocess($versionData);
32396 }
32397
32398 return null;
32399 }
32400
32401 private function postprocess(array $versionData)
32402 {
32403 if (!empty($versionData['feature_version']) && $versionData['feature_version'] === $versionData['version'] && $versionData['feature_pretty_version'] === $versionData['feature_pretty_version']) {
32404 unset($versionData['feature_version'], $versionData['feature_pretty_version']);
32405 }
32406
32407 if ('-dev' === substr($versionData['version'], -4) && preg_match('{\.9{7}}', $versionData['version'])) {
32408 $versionData['pretty_version'] = preg_replace('{(\.9{7})+}', '.x', $versionData['version']);
32409 }
32410
32411 if (!empty($versionData['feature_version']) && '-dev' === substr($versionData['feature_version'], -4) && preg_match('{\.9{7}}', $versionData['feature_version'])) {
32412 $versionData['feature_pretty_version'] = preg_replace('{(\.9{7})+}', '.x', $versionData['feature_version']);
32413 }
32414
32415 return $versionData;
32416 }
32417
32418 private function guessGitVersion(array $packageConfig, $path)
32419 {
32420 GitUtil::cleanEnv();
32421 $commit = null;
32422 $version = null;
32423 $prettyVersion = null;
32424 $featureVersion = null;
32425 $featurePrettyVersion = null;
32426 $isDetached = false;
32427
32428
32429 if (0 === $this->process->execute('git branch -a --no-color --no-abbrev -v', $output, $path)) {
32430 $branches = array();
32431 $isFeatureBranch = false;
32432
32433
32434 foreach ($this->process->splitLines($output) as $branch) {
32435 if ($branch && preg_match('{^(?:\* ) *(\(no branch\)|\(detached from \S+\)|\(HEAD detached at \S+\)|\S+) *([a-f0-9]+) .*$}', $branch, $match)) {
32436 if ($match[1] === '(no branch)' || substr($match[1], 0, 10) === '(detached ' || substr($match[1], 0, 17) === '(HEAD detached at') {
32437 $version = 'dev-' . $match[2];
32438 $prettyVersion = $version;
32439 $isFeatureBranch = true;
32440 $isDetached = true;
32441 } else {
32442 $version = $this->versionParser->normalizeBranch($match[1]);
32443 $prettyVersion = 'dev-' . $match[1];
32444 $isFeatureBranch = 0 === strpos($version, 'dev-');
32445 }
32446
32447 if ($match[2]) {
32448 $commit = $match[2];
32449 }
32450 }
32451
32452 if ($branch && !preg_match('{^ *.+/HEAD }', $branch)) {
32453 if (preg_match('{^(?:\* )? *((?:remotes/(?:origin|upstream)/)?[^\s/]+) *([a-f0-9]+) .*$}', $branch, $match)) {
32454 $branches[] = $match[1];
32455 }
32456 }
32457 }
32458
32459 if ($isFeatureBranch) {
32460 $featureVersion = $version;
32461 $featurePrettyVersion = $prettyVersion;
32462
32463 $result = $this->guessFeatureVersion($packageConfig, $version, $branches, 'git rev-list %candidate%..%branch%', $path);
32464 $version = $result['version'];
32465 $prettyVersion = $result['pretty_version'];
32466 }
32467 }
32468
32469 if (!$version || $isDetached) {
32470 $result = $this->versionFromGitTags($path);
32471 if ($result) {
32472 $version = $result['version'];
32473 $prettyVersion = $result['pretty_version'];
32474 $featureVersion = null;
32475 $featurePrettyVersion = null;
32476 }
32477 }
32478
32479 if (!$commit) {
32480 $command = 'git log --pretty="%H" -n1 HEAD'.GitUtil::getNoShowSignatureFlag($this->process);
32481 if (0 === $this->process->execute($command, $output, $path)) {
32482 $commit = trim($output) ?: null;
32483 }
32484 }
32485
32486 if ($featureVersion) {
32487 return array('version' => $version, 'commit' => $commit, 'pretty_version' => $prettyVersion, 'feature_version' => $featureVersion, 'feature_pretty_version' => $featurePrettyVersion);
32488 }
32489
32490 return array('version' => $version, 'commit' => $commit, 'pretty_version' => $prettyVersion);
32491 }
32492
32493 private function versionFromGitTags($path)
32494 {
32495
32496 if (0 === $this->process->execute('git describe --exact-match --tags', $output, $path)) {
32497 try {
32498 $version = $this->versionParser->normalize(trim($output));
32499
32500 return array('version' => $version, 'pretty_version' => trim($output));
32501 } catch (\Exception $e) {
32502 }
32503 }
32504
32505 return null;
32506 }
32507
32508 private function guessHgVersion(array $packageConfig, $path)
32509 {
32510
32511 if (0 === $this->process->execute('hg branch', $output, $path)) {
32512 $branch = trim($output);
32513 $version = $this->versionParser->normalizeBranch($branch);
32514 $isFeatureBranch = 0 === strpos($version, 'dev-');
32515
32516 if ('9999999-dev' === $version) {
32517 return array('version' => $version, 'commit' => null, 'pretty_version' => 'dev-'.$branch);
32518 }
32519
32520 if (!$isFeatureBranch) {
32521 return array('version' => $version, 'commit' => null, 'pretty_version' => $version);
32522 }
32523
32524
32525 $driver = new HgDriver(array('url' => $path), new NullIO(), $this->config, $this->process);
32526 $branches = array_keys($driver->getBranches());
32527
32528
32529 $result = $this->guessFeatureVersion($packageConfig, $version, $branches, 'hg log -r "not ancestors(\'%candidate%\') and ancestors(\'%branch%\')" --template "{node}\\n"', $path);
32530 $result['commit'] = '';
32531 $result['feature_version'] = $version;
32532 $result['feature_pretty_version'] = $version;
32533
32534 return $result;
32535 }
32536 }
32537
32538 private function guessFeatureVersion(array $packageConfig, $version, array $branches, $scmCmdline, $path)
32539 {
32540 $prettyVersion = $version;
32541
32542
32543
32544 if ((isset($packageConfig['extra']['branch-alias']) && !isset($packageConfig['extra']['branch-alias'][$version]))
32545 || strpos(json_encode($packageConfig), '"self.version"')
32546 ) {
32547 $branch = preg_replace('{^dev-}', '', $version);
32548 $length = PHP_INT_MAX;
32549
32550 $nonFeatureBranches = '';
32551 if (!empty($packageConfig['non-feature-branches'])) {
32552 $nonFeatureBranches = implode('|', $packageConfig['non-feature-branches']);
32553 }
32554
32555
32556 if (preg_match('{^(' . $nonFeatureBranches . ')$}', $branch) && in_array($branch, $branches, true)) {
32557 return array('version' => $version, 'pretty_version' => $prettyVersion);
32558 }
32559
32560
32561
32562
32563 usort($branches, function ($a, $b) {
32564 $aRemote = 0 === strpos($a, 'remotes/');
32565 $bRemote = 0 === strpos($b, 'remotes/');
32566
32567 if ($aRemote !== $bRemote) {
32568 return $aRemote ? 1 : -1;
32569 }
32570
32571 return strnatcasecmp($b, $a);
32572 });
32573
32574 foreach ($branches as $candidate) {
32575 $candidateVersion = preg_replace('{^remotes/\S+/}', '', $candidate);
32576
32577
32578 if ($candidate === $branch || !preg_match('{^(' . $nonFeatureBranches . '|master|trunk|default|develop|\d+\..+)$}', $candidateVersion, $match)) {
32579 continue;
32580 }
32581
32582 $cmdLine = str_replace(array('%candidate%', '%branch%'), array($candidate, $branch), $scmCmdline);
32583 if (0 !== $this->process->execute($cmdLine, $output, $path)) {
32584 continue;
32585 }
32586
32587 if (strlen($output) < $length) {
32588 $length = strlen($output);
32589 $version = $this->versionParser->normalizeBranch($candidateVersion);
32590 $prettyVersion = 'dev-' . $candidateVersion;
32591 if ($length === 0) {
32592 break;
32593 }
32594 }
32595 }
32596 }
32597
32598 return array('version' => $version, 'pretty_version' => $prettyVersion);
32599 }
32600
32601 private function guessFossilVersion(array $packageConfig, $path)
32602 {
32603 $version = null;
32604 $prettyVersion = null;
32605
32606
32607 if (0 === $this->process->execute('fossil branch list', $output, $path)) {
32608 $branch = trim($output);
32609 $version = $this->versionParser->normalizeBranch($branch);
32610 $prettyVersion = 'dev-' . $branch;
32611 }
32612
32613
32614 if (0 === $this->process->execute('fossil tag list', $output, $path)) {
32615 try {
32616 $version = $this->versionParser->normalize(trim($output));
32617 $prettyVersion = trim($output);
32618 } catch (\Exception $e) {
32619 }
32620 }
32621
32622 return array('version' => $version, 'commit' => '', 'pretty_version' => $prettyVersion);
32623 }
32624
32625 private function guessSvnVersion(array $packageConfig, $path)
32626 {
32627 SvnUtil::cleanEnv();
32628
32629
32630 if (0 === $this->process->execute('svn info --xml', $output, $path)) {
32631 $trunkPath = isset($packageConfig['trunk-path']) ? preg_quote($packageConfig['trunk-path'], '#') : 'trunk';
32632 $branchesPath = isset($packageConfig['branches-path']) ? preg_quote($packageConfig['branches-path'], '#') : 'branches';
32633 $tagsPath = isset($packageConfig['tags-path']) ? preg_quote($packageConfig['tags-path'], '#') : 'tags';
32634
32635 $urlPattern = '#<url>.*/(' . $trunkPath . '|(' . $branchesPath . '|' . $tagsPath . ')/(.*))</url>#';
32636
32637 if (preg_match($urlPattern, $output, $matches)) {
32638 if (isset($matches[2]) && ($branchesPath === $matches[2] || $tagsPath === $matches[2])) {
32639
32640 $version = $this->versionParser->normalizeBranch($matches[3]);
32641 $prettyVersion = 'dev-' . $matches[3];
32642
32643 return array('version' => $version, 'commit' => '', 'pretty_version' => $prettyVersion);
32644 }
32645
32646 $prettyVersion = trim($matches[1]);
32647 $version = $this->versionParser->normalize($prettyVersion);
32648
32649 return array('version' => $version, 'commit' => '', 'pretty_version' => $prettyVersion);
32650 }
32651 }
32652 }
32653 }
32654 <?php
32655
32656
32657
32658
32659
32660
32661
32662
32663
32664
32665
32666 namespace Composer\Package\Version;
32667
32668 use Composer\Repository\PlatformRepository;
32669 use Composer\Semver\VersionParser as SemverVersionParser;
32670 use Composer\Semver\Semver;
32671
32672 class VersionParser extends SemverVersionParser
32673 {
32674 private static $constraints = array();
32675
32676
32677
32678
32679 public function parseConstraints($constraints)
32680 {
32681 if (!isset(self::$constraints[$constraints])) {
32682 self::$constraints[$constraints] = parent::parseConstraints($constraints);
32683 }
32684
32685 return self::$constraints[$constraints];
32686 }
32687
32688
32689
32690
32691
32692
32693
32694
32695
32696
32697
32698 public function parseNameVersionPairs(array $pairs)
32699 {
32700 $pairs = array_values($pairs);
32701 $result = array();
32702
32703 for ($i = 0, $count = count($pairs); $i < $count; $i++) {
32704 $pair = preg_replace('{^([^=: ]+)[=: ](.*)$}', '$1 $2', trim($pairs[$i]));
32705 if (false === strpos($pair, ' ') && isset($pairs[$i + 1]) && false === strpos($pairs[$i + 1], '/') && !preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $pairs[$i + 1])) {
32706 $pair .= ' '.$pairs[$i + 1];
32707 $i++;
32708 }
32709
32710 if (strpos($pair, ' ')) {
32711 list($name, $version) = explode(' ', $pair, 2);
32712 $result[] = array('name' => $name, 'version' => $version);
32713 } else {
32714 $result[] = array('name' => $pair);
32715 }
32716 }
32717
32718 return $result;
32719 }
32720
32721
32722
32723
32724 public static function isUpgrade($normalizedFrom, $normalizedTo)
32725 {
32726 if (substr($normalizedFrom, 0, 4) === 'dev-' || substr($normalizedTo, 0, 4) === 'dev-') {
32727 return true;
32728 }
32729
32730 $sorted = Semver::sort(array($normalizedTo, $normalizedFrom));
32731
32732 return $sorted[0] === $normalizedFrom;
32733 }
32734 }
32735 <?php
32736
32737
32738
32739
32740
32741
32742
32743
32744
32745
32746
32747 namespace Composer\Package\Version;
32748
32749 use Composer\DependencyResolver\Pool;
32750 use Composer\Package\BasePackage;
32751 use Composer\Package\PackageInterface;
32752 use Composer\Plugin\PluginInterface;
32753 use Composer\Composer;
32754 use Composer\Package\Loader\ArrayLoader;
32755 use Composer\Package\Dumper\ArrayDumper;
32756 use Composer\Semver\Constraint\Constraint;
32757
32758
32759
32760
32761
32762
32763
32764 class VersionSelector
32765 {
32766 private $pool;
32767
32768 private $parser;
32769
32770 public function __construct(Pool $pool)
32771 {
32772 $this->pool = $pool;
32773 }
32774
32775
32776
32777
32778
32779
32780
32781
32782
32783
32784
32785 public function findBestCandidate($packageName, $targetPackageVersion = null, $targetPhpVersion = null, $preferredStability = 'stable')
32786 {
32787 $constraint = $targetPackageVersion ? $this->getParser()->parseConstraints($targetPackageVersion) : null;
32788 $candidates = $this->pool->whatProvides(strtolower($packageName), $constraint, true);
32789
32790 if ($targetPhpVersion) {
32791 $phpConstraint = new Constraint('==', $this->getParser()->normalize($targetPhpVersion));
32792 $composerRuntimeConstraint = new Constraint('==', $this->getParser()->normalize(Composer::RUNTIME_API_VERSION));
32793 $composerPluginConstraint = new Constraint('==', $this->getParser()->normalize(PluginInterface::PLUGIN_API_VERSION));
32794 $candidates = array_filter($candidates, function ($pkg) use ($phpConstraint, $composerPluginConstraint, $composerRuntimeConstraint) {
32795 $reqs = $pkg->getRequires();
32796
32797 return (!isset($reqs['php']) || $reqs['php']->getConstraint()->matches($phpConstraint))
32798 && (!isset($reqs['composer-plugin-api']) || $reqs['composer-plugin-api']->getConstraint()->matches($composerPluginConstraint))
32799 && (!isset($reqs['composer-runtime-api']) || $reqs['composer-runtime-api']->getConstraint()->matches($composerRuntimeConstraint));
32800 });
32801 }
32802
32803 if (!$candidates) {
32804 return false;
32805 }
32806
32807
32808 $package = reset($candidates);
32809 $minPriority = BasePackage::$stabilities[$preferredStability];
32810 foreach ($candidates as $candidate) {
32811 $candidatePriority = $candidate->getStabilityPriority();
32812 $currentPriority = $package->getStabilityPriority();
32813
32814
32815
32816 if ($minPriority < $candidatePriority && $currentPriority < $candidatePriority) {
32817 continue;
32818 }
32819
32820
32821
32822 if ($minPriority < $candidatePriority && $candidatePriority < $currentPriority) {
32823 $package = $candidate;
32824 continue;
32825 }
32826
32827
32828
32829 if ($minPriority >= $candidatePriority && $minPriority < $currentPriority) {
32830 $package = $candidate;
32831 continue;
32832 }
32833
32834
32835 if (version_compare($package->getVersion(), $candidate->getVersion(), '<')) {
32836 $package = $candidate;
32837 }
32838 }
32839
32840 return $package;
32841 }
32842
32843
32844
32845
32846
32847
32848
32849
32850
32851
32852
32853
32854
32855
32856
32857
32858 public function findRecommendedRequireVersion(PackageInterface $package)
32859 {
32860 $version = $package->getVersion();
32861 if (!$package->isDev()) {
32862 return $this->transformVersion($version, $package->getPrettyVersion(), $package->getStability());
32863 }
32864
32865 $loader = new ArrayLoader($this->getParser());
32866 $dumper = new ArrayDumper();
32867 $extra = $loader->getBranchAlias($dumper->dump($package));
32868 if ($extra) {
32869 $extra = preg_replace('{^(\d+\.\d+\.\d+)(\.9999999)-dev$}', '$1.0', $extra, -1, $count);
32870 if ($count) {
32871 $extra = str_replace('.9999999', '.0', $extra);
32872
32873 return $this->transformVersion($extra, $extra, 'dev');
32874 }
32875 }
32876
32877 return $package->getPrettyVersion();
32878 }
32879
32880 private function transformVersion($version, $prettyVersion, $stability)
32881 {
32882
32883
32884 $semanticVersionParts = explode('.', $version);
32885
32886
32887 if (count($semanticVersionParts) == 4 && preg_match('{^0\D?}', $semanticVersionParts[3])) {
32888
32889 if ($semanticVersionParts[0] === '0') {
32890 unset($semanticVersionParts[3]);
32891 } else {
32892 unset($semanticVersionParts[2], $semanticVersionParts[3]);
32893 }
32894 $version = implode('.', $semanticVersionParts);
32895 } else {
32896 return $prettyVersion;
32897 }
32898
32899
32900 if ($stability != 'stable') {
32901 $version .= '@'.$stability;
32902 }
32903
32904
32905 return '^' . $version;
32906 }
32907
32908 private function getParser()
32909 {
32910 if ($this->parser === null) {
32911 $this->parser = new VersionParser();
32912 }
32913
32914 return $this->parser;
32915 }
32916 }
32917 <?php
32918
32919
32920
32921
32922
32923
32924
32925
32926
32927
32928
32929 namespace Composer\Plugin\Capability;
32930
32931
32932
32933
32934
32935
32936
32937 interface Capability
32938 {
32939 }
32940 <?php
32941
32942
32943
32944
32945
32946
32947
32948
32949
32950
32951
32952 namespace Composer\Plugin\Capability;
32953
32954
32955
32956
32957
32958
32959
32960
32961
32962
32963
32964 interface CommandProvider extends Capability
32965 {
32966
32967
32968
32969
32970
32971 public function getCommands();
32972 }
32973 <?php
32974
32975
32976
32977
32978
32979
32980
32981
32982
32983
32984
32985 namespace Composer\Plugin;
32986
32987
32988
32989
32990
32991
32992
32993
32994 interface Capable
32995 {
32996
32997
32998
32999
33000
33001
33002
33003
33004
33005
33006
33007
33008
33009
33010
33011
33012
33013
33014 public function getCapabilities();
33015 }
33016 <?php
33017
33018
33019
33020
33021
33022
33023
33024
33025
33026
33027
33028 namespace Composer\Plugin;
33029
33030 use Composer\EventDispatcher\Event;
33031 use Symfony\Component\Console\Input\InputInterface;
33032 use Symfony\Component\Console\Output\OutputInterface;
33033
33034
33035
33036
33037
33038
33039 class CommandEvent extends Event
33040 {
33041
33042
33043
33044 private $commandName;
33045
33046
33047
33048
33049 private $input;
33050
33051
33052
33053
33054 private $output;
33055
33056
33057
33058
33059
33060
33061
33062
33063
33064
33065
33066 public function __construct($name, $commandName, $input, $output, array $args = array(), array $flags = array())
33067 {
33068 parent::__construct($name, $args, $flags);
33069 $this->commandName = $commandName;
33070 $this->input = $input;
33071 $this->output = $output;
33072 }
33073
33074
33075
33076
33077
33078
33079 public function getInput()
33080 {
33081 return $this->input;
33082 }
33083
33084
33085
33086
33087
33088
33089 public function getOutput()
33090 {
33091 return $this->output;
33092 }
33093
33094
33095
33096
33097
33098
33099 public function getCommandName()
33100 {
33101 return $this->commandName;
33102 }
33103 }
33104 <?php
33105
33106
33107
33108
33109
33110
33111
33112
33113
33114
33115
33116 namespace Composer\Plugin;
33117
33118
33119
33120
33121
33122
33123 class PluginEvents
33124 {
33125
33126
33127
33128
33129
33130
33131
33132
33133 const INIT = 'init';
33134
33135
33136
33137
33138
33139
33140
33141
33142
33143 const COMMAND = 'command';
33144
33145
33146
33147
33148
33149
33150
33151
33152
33153 const PRE_FILE_DOWNLOAD = 'pre-file-download';
33154
33155
33156
33157
33158
33159
33160
33161
33162
33163 const PRE_COMMAND_RUN = 'pre-command-run';
33164 }
33165 <?php
33166
33167
33168
33169
33170
33171
33172
33173
33174
33175
33176
33177 namespace Composer\Plugin;
33178
33179 use Composer\Composer;
33180 use Composer\IO\IOInterface;
33181
33182
33183
33184
33185
33186
33187 interface PluginInterface
33188 {
33189
33190
33191
33192
33193
33194 const PLUGIN_API_VERSION = '1.1.0';
33195
33196
33197
33198
33199
33200
33201
33202 public function activate(Composer $composer, IOInterface $io);
33203 }
33204 <?php
33205
33206
33207
33208
33209
33210
33211
33212
33213
33214
33215
33216 namespace Composer\Plugin;
33217
33218 use Composer\Composer;
33219 use Composer\EventDispatcher\EventSubscriberInterface;
33220 use Composer\IO\IOInterface;
33221 use Composer\Package\CompletePackage;
33222 use Composer\Package\Package;
33223 use Composer\Package\Version\VersionParser;
33224 use Composer\Repository\RepositoryInterface;
33225 use Composer\Package\PackageInterface;
33226 use Composer\Package\Link;
33227 use Composer\Semver\Constraint\Constraint;
33228 use Composer\DependencyResolver\Pool;
33229 use Composer\Plugin\Capability\Capability;
33230 use Composer\Util\PackageSorter;
33231
33232
33233
33234
33235
33236
33237
33238 class PluginManager
33239 {
33240 protected $composer;
33241 protected $io;
33242 protected $globalComposer;
33243 protected $versionParser;
33244 protected $disablePlugins = false;
33245
33246 protected $plugins = array();
33247 protected $registeredPlugins = array();
33248
33249 private static $classCounter = 0;
33250
33251
33252
33253
33254
33255
33256
33257
33258
33259 public function __construct(IOInterface $io, Composer $composer, Composer $globalComposer = null, $disablePlugins = false)
33260 {
33261 $this->io = $io;
33262 $this->composer = $composer;
33263 $this->globalComposer = $globalComposer;
33264 $this->versionParser = new VersionParser();
33265 $this->disablePlugins = $disablePlugins;
33266 }
33267
33268
33269
33270
33271 public function loadInstalledPlugins()
33272 {
33273 if ($this->disablePlugins) {
33274 return;
33275 }
33276
33277 $repo = $this->composer->getRepositoryManager()->getLocalRepository();
33278 $globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null;
33279 if ($repo) {
33280 $this->loadRepository($repo);
33281 }
33282 if ($globalRepo) {
33283 $this->loadRepository($globalRepo);
33284 }
33285 }
33286
33287
33288
33289
33290
33291
33292 public function getPlugins()
33293 {
33294 return $this->plugins;
33295 }
33296
33297
33298
33299
33300
33301
33302 public function getGlobalComposer()
33303 {
33304 return $this->globalComposer;
33305 }
33306
33307
33308
33309
33310
33311
33312
33313
33314
33315
33316
33317
33318 public function registerPackage(PackageInterface $package, $failOnMissingClasses = false)
33319 {
33320 if ($this->disablePlugins) {
33321 return;
33322 }
33323
33324 if ($package->getType() === 'composer-plugin') {
33325 $requiresComposer = null;
33326 foreach ($package->getRequires() as $link) { 
33327 if ('composer-plugin-api' === $link->getTarget()) {
33328 $requiresComposer = $link->getConstraint();
33329 break;
33330 }
33331 }
33332
33333 if (!$requiresComposer) {
33334 throw new \RuntimeException("Plugin ".$package->getName()." is missing a require statement for a version of the composer-plugin-api package.");
33335 }
33336
33337 $currentPluginApiVersion = $this->getPluginApiVersion();
33338 $currentPluginApiConstraint = new Constraint('==', $this->versionParser->normalize($currentPluginApiVersion));
33339
33340 if ($requiresComposer->getPrettyString() === '1.0.0' && $this->getPluginApiVersion() === '1.0.0') {
33341 $this->io->writeError('<warning>The "' . $package->getName() . '" plugin requires composer-plugin-api 1.0.0, this *WILL* break in the future and it should be fixed ASAP (require ^1.0 for example).</warning>');
33342 } elseif (!$requiresComposer->matches($currentPluginApiConstraint)) {
33343 $this->io->writeError('<warning>The "' . $package->getName() . '" plugin was skipped because it requires a Plugin API version ("' . $requiresComposer->getPrettyString() . '") that does not match your Composer installation ("' . $currentPluginApiVersion . '"). You may need to run composer update with the "--no-plugins" option.</warning>');
33344
33345 return;
33346 }
33347 }
33348
33349 $oldInstallerPlugin = ($package->getType() === 'composer-installer');
33350
33351 if (in_array($package->getName(), $this->registeredPlugins)) {
33352 return;
33353 }
33354
33355 $extra = $package->getExtra();
33356 if (empty($extra['class'])) {
33357 throw new \UnexpectedValueException('Error while installing '.$package->getPrettyName().', composer-plugin packages should have a class defined in their extra key to be usable.');
33358 }
33359 $classes = is_array($extra['class']) ? $extra['class'] : array($extra['class']);
33360
33361 $localRepo = $this->composer->getRepositoryManager()->getLocalRepository();
33362 $globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null;
33363
33364 $pool = new Pool('dev');
33365 $pool->addRepository($localRepo);
33366 if ($globalRepo) {
33367 $pool->addRepository($globalRepo);
33368 }
33369
33370 $autoloadPackages = array($package->getName() => $package);
33371 $autoloadPackages = $this->collectDependencies($pool, $autoloadPackages, $package);
33372
33373 $generator = $this->composer->getAutoloadGenerator();
33374 $autoloads = array();
33375 foreach ($autoloadPackages as $autoloadPackage) {
33376 $downloadPath = $this->getInstallPath($autoloadPackage, $globalRepo && $globalRepo->hasPackage($autoloadPackage));
33377 $autoloads[] = array($autoloadPackage, $downloadPath);
33378 }
33379
33380 $map = $generator->parseAutoloads($autoloads, new Package('dummy', '1.0.0.0', '1.0.0'));
33381 $classLoader = $generator->createLoader($map);
33382 $classLoader->register();
33383
33384 foreach ($classes as $class) {
33385 if (class_exists($class, false)) {
33386 $class = trim($class, '\\');
33387 $path = $classLoader->findFile($class);
33388 $code = file_get_contents($path);
33389 $separatorPos = strrpos($class, '\\');
33390 $className = $class;
33391 if ($separatorPos) {
33392 $className = substr($class, $separatorPos + 1);
33393 }
33394 $code = preg_replace('{^((?:final\s+)?(?:\s*))class\s+('.preg_quote($className).')}mi', '$1class $2_composer_tmp'.self::$classCounter, $code, 1);
33395 $code = str_replace('__FILE__', var_export($path, true), $code);
33396 $code = str_replace('__DIR__', var_export(dirname($path), true), $code);
33397 $code = str_replace('__CLASS__', var_export($class, true), $code);
33398 $code = preg_replace('/^\s*<\?(php)?/i', '', $code, 1);
33399 eval($code);
33400 $class .= '_composer_tmp'.self::$classCounter;
33401 self::$classCounter++;
33402 }
33403
33404 if ($oldInstallerPlugin) {
33405 $installer = new $class($this->io, $this->composer);
33406 $this->composer->getInstallationManager()->addInstaller($installer);
33407 } elseif (class_exists($class)) {
33408 $plugin = new $class();
33409 $this->addPlugin($plugin);
33410 $this->registeredPlugins[] = $package->getName();
33411 } elseif ($failOnMissingClasses) {
33412 throw new \UnexpectedValueException('Plugin '.$package->getName().' could not be initialized, class not found: '.$class);
33413 }
33414 }
33415 }
33416
33417
33418
33419
33420
33421
33422 protected function getPluginApiVersion()
33423 {
33424 return PluginInterface::PLUGIN_API_VERSION;
33425 }
33426
33427
33428
33429
33430
33431
33432
33433
33434
33435
33436 public function addPlugin(PluginInterface $plugin)
33437 {
33438 $this->io->writeError('Loading plugin '.get_class($plugin), true, IOInterface::DEBUG);
33439 $this->plugins[] = $plugin;
33440 $plugin->activate($this->composer, $this->io);
33441
33442 if ($plugin instanceof EventSubscriberInterface) {
33443 $this->composer->getEventDispatcher()->addSubscriber($plugin);
33444 }
33445 }
33446
33447
33448
33449
33450
33451
33452
33453
33454
33455
33456
33457
33458 private function loadRepository(RepositoryInterface $repo)
33459 {
33460 $packages = $repo->getPackages();
33461 $sortedPackages = array_reverse(PackageSorter::sortPackages($packages));
33462 foreach ($sortedPackages as $package) {
33463 if (!($package instanceof CompletePackage)) {
33464 continue;
33465 }
33466 if ('composer-plugin' === $package->getType()) {
33467 $this->registerPackage($package);
33468
33469 } elseif ('composer-installer' === $package->getType()) {
33470 $this->registerPackage($package);
33471 }
33472 }
33473 }
33474
33475
33476
33477
33478
33479
33480
33481
33482
33483
33484 private function collectDependencies(Pool $pool, array $collected, PackageInterface $package)
33485 {
33486 $requires = array_merge(
33487 $package->getRequires(),
33488 $package->getDevRequires()
33489 );
33490
33491 foreach ($requires as $requireLink) {
33492 $requiredPackage = $this->lookupInstalledPackage($pool, $requireLink);
33493 if ($requiredPackage && !isset($collected[$requiredPackage->getName()])) {
33494 $collected[$requiredPackage->getName()] = $requiredPackage;
33495 $collected = $this->collectDependencies($pool, $collected, $requiredPackage);
33496 }
33497 }
33498
33499 return $collected;
33500 }
33501
33502
33503
33504
33505
33506
33507
33508
33509
33510
33511
33512 private function lookupInstalledPackage(Pool $pool, Link $link)
33513 {
33514 $packages = $pool->whatProvides($link->getTarget(), $link->getConstraint());
33515
33516 return !empty($packages) ? $packages[0] : null;
33517 }
33518
33519
33520
33521
33522
33523
33524
33525
33526
33527 private function getInstallPath(PackageInterface $package, $global = false)
33528 {
33529 if (!$global) {
33530 return $this->composer->getInstallationManager()->getInstallPath($package);
33531 }
33532
33533 return $this->globalComposer->getInstallationManager()->getInstallPath($package);
33534 }
33535
33536
33537
33538
33539
33540
33541
33542 protected function getCapabilityImplementationClassName(PluginInterface $plugin, $capability)
33543 {
33544 if (!($plugin instanceof Capable)) {
33545 return null;
33546 }
33547
33548 $capabilities = (array) $plugin->getCapabilities();
33549
33550 if (!empty($capabilities[$capability]) && is_string($capabilities[$capability]) && trim($capabilities[$capability])) {
33551 return trim($capabilities[$capability]);
33552 }
33553
33554 if (
33555 array_key_exists($capability, $capabilities)
33556 && (empty($capabilities[$capability]) || !is_string($capabilities[$capability]) || !trim($capabilities[$capability]))
33557 ) {
33558 throw new \UnexpectedValueException('Plugin '.get_class($plugin).' provided invalid capability class name(s), got '.var_export($capabilities[$capability], 1));
33559 }
33560 }
33561
33562
33563
33564
33565
33566
33567
33568
33569
33570 public function getPluginCapability(PluginInterface $plugin, $capabilityClassName, array $ctorArgs = array())
33571 {
33572 if ($capabilityClass = $this->getCapabilityImplementationClassName($plugin, $capabilityClassName)) {
33573 if (!class_exists($capabilityClass)) {
33574 throw new \RuntimeException("Cannot instantiate Capability, as class $capabilityClass from plugin ".get_class($plugin)." does not exist.");
33575 }
33576
33577 $ctorArgs['plugin'] = $plugin;
33578 $capabilityObj = new $capabilityClass($ctorArgs);
33579
33580
33581 if (!$capabilityObj instanceof Capability || !$capabilityObj instanceof $capabilityClassName) {
33582 throw new \RuntimeException(
33583 'Class ' . $capabilityClass . ' must implement both Composer\Plugin\Capability\Capability and '. $capabilityClassName . '.'
33584 );
33585 }
33586
33587 return $capabilityObj;
33588 }
33589 }
33590
33591
33592
33593
33594
33595
33596
33597
33598 public function getPluginCapabilities($capabilityClassName, array $ctorArgs = array())
33599 {
33600 $capabilities = array();
33601 foreach ($this->getPlugins() as $plugin) {
33602 if ($capability = $this->getPluginCapability($plugin, $capabilityClassName, $ctorArgs)) {
33603 $capabilities[] = $capability;
33604 }
33605 }
33606
33607 return $capabilities;
33608 }
33609 }
33610 <?php
33611
33612
33613
33614
33615
33616
33617
33618
33619
33620
33621
33622 namespace Composer\Plugin;
33623
33624 use Composer\EventDispatcher\Event;
33625 use Symfony\Component\Console\Input\InputInterface;
33626
33627
33628
33629
33630
33631
33632 class PreCommandRunEvent extends Event
33633 {
33634
33635
33636
33637 private $input;
33638
33639
33640
33641
33642 private $command;
33643
33644
33645
33646
33647
33648
33649
33650
33651 public function __construct($name, InputInterface $input, $command)
33652 {
33653 parent::__construct($name);
33654 $this->input = $input;
33655 $this->command = $command;
33656 }
33657
33658
33659
33660
33661
33662
33663 public function getInput()
33664 {
33665 return $this->input;
33666 }
33667
33668
33669
33670
33671
33672
33673 public function getCommand()
33674 {
33675 return $this->command;
33676 }
33677 }
33678 <?php
33679
33680
33681
33682
33683
33684
33685
33686
33687
33688
33689
33690 namespace Composer\Plugin;
33691
33692 use Composer\EventDispatcher\Event;
33693 use Composer\Util\RemoteFilesystem;
33694
33695
33696
33697
33698
33699
33700 class PreFileDownloadEvent extends Event
33701 {
33702
33703
33704
33705 private $rfs;
33706
33707
33708
33709
33710 private $processedUrl;
33711
33712
33713
33714
33715
33716
33717
33718
33719 public function __construct($name, RemoteFilesystem $rfs, $processedUrl)
33720 {
33721 parent::__construct($name);
33722 $this->rfs = $rfs;
33723 $this->processedUrl = $processedUrl;
33724 }
33725
33726
33727
33728
33729
33730
33731 public function getRemoteFilesystem()
33732 {
33733 return $this->rfs;
33734 }
33735
33736
33737
33738
33739
33740
33741 public function setRemoteFilesystem(RemoteFilesystem $rfs)
33742 {
33743 $this->rfs = $rfs;
33744 }
33745
33746
33747
33748
33749
33750
33751 public function getProcessedUrl()
33752 {
33753 return $this->processedUrl;
33754 }
33755 }
33756 <?php
33757
33758
33759
33760
33761
33762
33763
33764
33765
33766
33767
33768 namespace Composer\Question;
33769
33770 use Symfony\Component\Console\Exception\InvalidArgumentException;
33771 use Symfony\Component\Console\Question\Question;
33772
33773
33774
33775
33776
33777
33778
33779
33780 class StrictConfirmationQuestion extends Question
33781 {
33782 private $trueAnswerRegex;
33783 private $falseAnswerRegex;
33784
33785
33786
33787
33788
33789
33790
33791
33792
33793 public function __construct($question, $default = true, $trueAnswerRegex = '/^y(?:es)?$/i', $falseAnswerRegex = '/^no?$/i')
33794 {
33795 parent::__construct($question, (bool) $default);
33796
33797 $this->trueAnswerRegex = $trueAnswerRegex;
33798 $this->falseAnswerRegex = $falseAnswerRegex;
33799 $this->setNormalizer($this->getDefaultNormalizer());
33800 $this->setValidator($this->getDefaultValidator());
33801 }
33802
33803
33804
33805
33806
33807
33808 private function getDefaultNormalizer()
33809 {
33810 $default = $this->getDefault();
33811 $trueRegex = $this->trueAnswerRegex;
33812 $falseRegex = $this->falseAnswerRegex;
33813
33814 return function ($answer) use ($default, $trueRegex, $falseRegex) {
33815 if (is_bool($answer)) {
33816 return $answer;
33817 }
33818 if (empty($answer) && !empty($default)) {
33819 return $default;
33820 }
33821
33822 if (preg_match($trueRegex, $answer)) {
33823 return true;
33824 }
33825
33826 if (preg_match($falseRegex, $answer)) {
33827 return false;
33828 }
33829
33830 return null;
33831 };
33832 }
33833
33834
33835
33836
33837
33838
33839 private function getDefaultValidator()
33840 {
33841 return function ($answer) {
33842 if (!is_bool($answer)) {
33843 throw new InvalidArgumentException('Please answer yes, y, no, or n.');
33844 }
33845
33846 return $answer;
33847 };
33848 }
33849 }
33850 <?php
33851
33852
33853
33854
33855
33856
33857
33858
33859
33860
33861
33862 namespace Composer\Repository;
33863
33864 use Composer\Package\AliasPackage;
33865 use Composer\Package\PackageInterface;
33866 use Composer\Package\CompletePackageInterface;
33867 use Composer\Package\Version\VersionParser;
33868 use Composer\Semver\Constraint\ConstraintInterface;
33869 use Composer\Semver\Constraint\Constraint;
33870
33871
33872
33873
33874
33875
33876 class ArrayRepository extends BaseRepository
33877 {
33878
33879 protected $packages;
33880
33881
33882
33883
33884 protected $packageMap;
33885
33886 public function __construct(array $packages = array())
33887 {
33888 foreach ($packages as $package) {
33889 $this->addPackage($package);
33890 }
33891 }
33892
33893
33894
33895
33896 public function findPackage($name, $constraint)
33897 {
33898 $name = strtolower($name);
33899
33900 if (!$constraint instanceof ConstraintInterface) {
33901 $versionParser = new VersionParser();
33902 $constraint = $versionParser->parseConstraints($constraint);
33903 }
33904
33905 foreach ($this->getPackages() as $package) {
33906 if ($name === $package->getName()) {
33907 $pkgConstraint = new Constraint('==', $package->getVersion());
33908 if ($constraint->matches($pkgConstraint)) {
33909 return $package;
33910 }
33911 }
33912 }
33913
33914 return null;
33915 }
33916
33917
33918
33919
33920 public function findPackages($name, $constraint = null)
33921 {
33922
33923 $name = strtolower($name);
33924 $packages = array();
33925
33926 if (null !== $constraint && !$constraint instanceof ConstraintInterface) {
33927 $versionParser = new VersionParser();
33928 $constraint = $versionParser->parseConstraints($constraint);
33929 }
33930
33931 foreach ($this->getPackages() as $package) {
33932 if ($name === $package->getName()) {
33933 $pkgConstraint = new Constraint('==', $package->getVersion());
33934 if (null === $constraint || $constraint->matches($pkgConstraint)) {
33935 $packages[] = $package;
33936 }
33937 }
33938 }
33939
33940 return $packages;
33941 }
33942
33943
33944
33945
33946 public function search($query, $mode = 0, $type = null)
33947 {
33948 $regex = '{(?:'.implode('|', preg_split('{\s+}', $query)).')}i';
33949
33950 $matches = array();
33951 foreach ($this->getPackages() as $package) {
33952 $name = $package->getName();
33953 if (isset($matches[$name])) {
33954 continue;
33955 }
33956 if (preg_match($regex, $name)
33957 || ($mode === self::SEARCH_FULLTEXT && $package instanceof CompletePackageInterface && preg_match($regex, implode(' ', (array) $package->getKeywords()) . ' ' . $package->getDescription()))
33958 ) {
33959 if (null !== $type && $package->getType() !== $type) {
33960 continue;
33961 }
33962
33963 $matches[$name] = array(
33964 'name' => $package->getPrettyName(),
33965 'description' => $package instanceof CompletePackageInterface ? $package->getDescription() : null,
33966 );
33967 }
33968 }
33969
33970 return array_values($matches);
33971 }
33972
33973
33974
33975
33976 public function hasPackage(PackageInterface $package)
33977 {
33978 if ($this->packageMap === null) {
33979 $this->packageMap = array();
33980 foreach ($this->getPackages() as $repoPackage) {
33981 $this->packageMap[$repoPackage->getUniqueName()] = $repoPackage;
33982 }
33983 }
33984
33985 return isset($this->packageMap[$package->getUniqueName()]);
33986 }
33987
33988
33989
33990
33991
33992
33993 public function addPackage(PackageInterface $package)
33994 {
33995 if (null === $this->packages) {
33996 $this->initialize();
33997 }
33998 $package->setRepository($this);
33999 $this->packages[] = $package;
34000
34001 if ($package instanceof AliasPackage) {
34002 $aliasedPackage = $package->getAliasOf();
34003 if (null === $aliasedPackage->getRepository()) {
34004 $this->addPackage($aliasedPackage);
34005 }
34006 }
34007
34008
34009 $this->packageMap = null;
34010 }
34011
34012 protected function createAliasPackage(PackageInterface $package, $alias, $prettyAlias)
34013 {
34014 return new AliasPackage($package instanceof AliasPackage ? $package->getAliasOf() : $package, $alias, $prettyAlias);
34015 }
34016
34017
34018
34019
34020
34021
34022 public function removePackage(PackageInterface $package)
34023 {
34024 $packageId = $package->getUniqueName();
34025
34026 foreach ($this->getPackages() as $key => $repoPackage) {
34027 if ($packageId === $repoPackage->getUniqueName()) {
34028 array_splice($this->packages, $key, 1);
34029
34030
34031 $this->packageMap = null;
34032
34033 return;
34034 }
34035 }
34036 }
34037
34038
34039
34040
34041 public function getPackages()
34042 {
34043 if (null === $this->packages) {
34044 $this->initialize();
34045 }
34046
34047 return $this->packages;
34048 }
34049
34050
34051
34052
34053
34054
34055 public function count()
34056 {
34057 return count($this->packages);
34058 }
34059
34060
34061
34062
34063 protected function initialize()
34064 {
34065 $this->packages = array();
34066 }
34067 }
34068 <?php
34069
34070
34071
34072
34073
34074
34075
34076
34077
34078
34079
34080 namespace Composer\Repository;
34081
34082 use Composer\IO\IOInterface;
34083 use Composer\Json\JsonFile;
34084 use Composer\Package\Loader\ArrayLoader;
34085 use Composer\Package\Loader\LoaderInterface;
34086 use Composer\Util\Zip;
34087
34088
34089
34090
34091 class ArtifactRepository extends ArrayRepository implements ConfigurableRepositoryInterface
34092 {
34093
34094 protected $loader;
34095
34096 protected $lookup;
34097 protected $repoConfig;
34098 private $io;
34099
34100 public function __construct(array $repoConfig, IOInterface $io)
34101 {
34102 parent::__construct();
34103 if (!extension_loaded('zip')) {
34104 throw new \RuntimeException('The artifact repository requires PHP\'s zip extension');
34105 }
34106
34107 $this->loader = new ArrayLoader();
34108 $this->lookup = $repoConfig['url'];
34109 $this->io = $io;
34110 $this->repoConfig = $repoConfig;
34111 }
34112
34113 public function getRepoConfig()
34114 {
34115 return $this->repoConfig;
34116 }
34117
34118 protected function initialize()
34119 {
34120 parent::initialize();
34121
34122 $this->scanDirectory($this->lookup);
34123 }
34124
34125 private function scanDirectory($path)
34126 {
34127 $io = $this->io;
34128
34129 $directory = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::FOLLOW_SYMLINKS);
34130 $iterator = new \RecursiveIteratorIterator($directory);
34131 $regex = new \RegexIterator($iterator, '/^.+\.(zip|phar)$/i');
34132 foreach ($regex as $file) {
34133
34134 if (!$file->isFile()) {
34135 continue;
34136 }
34137
34138 $package = $this->getComposerInformation($file);
34139 if (!$package) {
34140 $io->writeError("File <comment>{$file->getBasename()}</comment> doesn't seem to hold a package", true, IOInterface::VERBOSE);
34141 continue;
34142 }
34143
34144 $template = 'Found package <info>%s</info> (<comment>%s</comment>) in file <info>%s</info>';
34145 $io->writeError(sprintf($template, $package->getName(), $package->getPrettyVersion(), $file->getBasename()), true, IOInterface::VERBOSE);
34146
34147 $this->addPackage($package);
34148 }
34149 }
34150
34151 private function getComposerInformation(\SplFileInfo $file)
34152 {
34153 $json = Zip::getComposerJson($file->getPathname());
34154
34155 if (null === $json) {
34156 return false;
34157 }
34158
34159 $package = JsonFile::parseJson($json, $file->getPathname().'#composer.json');
34160 $package['dist'] = array(
34161 'type' => 'zip',
34162 'url' => strtr($file->getPathname(), '\\', '/'),
34163 'shasum' => sha1_file($file->getRealPath()),
34164 );
34165
34166 try {
34167 $package = $this->loader->load($package);
34168 } catch (\UnexpectedValueException $e) {
34169 throw new \UnexpectedValueException('Failed loading package in '.$file.': '.$e->getMessage(), 0, $e);
34170 }
34171
34172 return $package;
34173 }
34174 }
34175 <?php
34176
34177
34178
34179
34180
34181
34182
34183
34184
34185
34186
34187 namespace Composer\Repository;
34188
34189 use Composer\Package\RootPackageInterface;
34190 use Composer\Semver\Constraint\ConstraintInterface;
34191 use Composer\Semver\Constraint\Constraint;
34192 use Composer\Package\Link;
34193
34194
34195
34196
34197
34198
34199 abstract class BaseRepository implements RepositoryInterface
34200 {
34201
34202
34203
34204
34205
34206
34207
34208
34209
34210
34211
34212
34213
34214 public function getDependents($needle, $constraint = null, $invert = false, $recurse = true, $packagesFound = null)
34215 {
34216 $needles = array_map('strtolower', (array) $needle);
34217 $results = array();
34218
34219
34220 if (null === $packagesFound) {
34221 $packagesFound = $needles;
34222 }
34223
34224
34225 $rootPackage = null;
34226 foreach ($this->getPackages() as $package) {
34227 if ($package instanceof RootPackageInterface) {
34228 $rootPackage = $package;
34229 break;
34230 }
34231 }
34232
34233
34234 foreach ($this->getPackages() as $package) {
34235 $links = $package->getRequires();
34236
34237
34238
34239 $packagesInTree = $packagesFound;
34240
34241
34242 if (!$invert) {
34243 $links += $package->getReplaces();
34244
34245
34246
34247
34248 foreach ($package->getReplaces() as $link) {
34249 foreach ($needles as $needle) {
34250 if ($link->getSource() === $needle) {
34251 if ($constraint === null || ($link->getConstraint()->matches($constraint) === !$invert)) {
34252
34253 if (in_array($link->getTarget(), $packagesInTree)) {
34254 $results[] = array($package, $link, false);
34255 continue;
34256 }
34257 $packagesInTree[] = $link->getTarget();
34258 $dependents = $recurse ? $this->getDependents($link->getTarget(), null, false, true, $packagesInTree) : array();
34259 $results[] = array($package, $link, $dependents);
34260 $needles[] = $link->getTarget();
34261 }
34262 }
34263 }
34264 }
34265 }
34266
34267
34268 if ($package instanceof RootPackageInterface) {
34269 $links += $package->getDevRequires();
34270 }
34271
34272
34273 foreach ($links as $link) {
34274 foreach ($needles as $needle) {
34275 if ($link->getTarget() === $needle) {
34276 if ($constraint === null || ($link->getConstraint()->matches($constraint) === !$invert)) {
34277
34278 if (in_array($link->getSource(), $packagesInTree)) {
34279 $results[] = array($package, $link, false);
34280 continue;
34281 }
34282 $packagesInTree[] = $link->getSource();
34283 $dependents = $recurse ? $this->getDependents($link->getSource(), null, false, true, $packagesInTree) : array();
34284 $results[] = array($package, $link, $dependents);
34285 }
34286 }
34287 }
34288 }
34289
34290
34291 if ($invert && in_array($package->getName(), $needles)) {
34292 foreach ($package->getConflicts() as $link) {
34293 foreach ($this->findPackages($link->getTarget()) as $pkg) {
34294 $version = new Constraint('=', $pkg->getVersion());
34295 if ($link->getConstraint()->matches($version) === $invert) {
34296 $results[] = array($package, $link, false);
34297 }
34298 }
34299 }
34300 }
34301
34302
34303 if ($invert && $constraint && in_array($package->getName(), $needles) && $constraint->matches(new Constraint('=', $package->getVersion()))) {
34304 foreach ($package->getRequires() as $link) {
34305 if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $link->getTarget())) {
34306 if ($this->findPackage($link->getTarget(), $link->getConstraint())) {
34307 continue;
34308 }
34309
34310 $platformPkg = $this->findPackage($link->getTarget(), '*');
34311 $description = $platformPkg ? 'but '.$platformPkg->getPrettyVersion().' is installed' : 'but it is missing';
34312 $results[] = array($package, new Link($package->getName(), $link->getTarget(), null, 'requires', $link->getPrettyConstraint().' '.$description), false);
34313
34314 continue;
34315 }
34316
34317 foreach ($this->getPackages() as $pkg) {
34318 if (!in_array($link->getTarget(), $pkg->getNames())) {
34319 continue;
34320 }
34321
34322 $version = new Constraint('=', $pkg->getVersion());
34323
34324 if ($link->getTarget() !== $pkg->getName()) {
34325 foreach (array_merge($pkg->getReplaces(), $pkg->getProvides()) as $prov) {
34326 if ($link->getTarget() === $prov->getTarget()) {
34327 $version = $prov->getConstraint();
34328 break;
34329 }
34330 }
34331 }
34332
34333 if (!$link->getConstraint()->matches($version)) {
34334
34335
34336 if ($rootPackage) {
34337 foreach (array_merge($rootPackage->getRequires(), $rootPackage->getDevRequires()) as $rootReq) {
34338 if (in_array($rootReq->getTarget(), $pkg->getNames()) && !$rootReq->getConstraint()->matches($link->getConstraint())) {
34339 $results[] = array($package, $link, false);
34340 $results[] = array($rootPackage, $rootReq, false);
34341 continue 3;
34342 }
34343 }
34344
34345 $results[] = array($package, $link, false);
34346 $results[] = array($rootPackage, new Link($rootPackage->getName(), $link->getTarget(), null, 'does not require', 'but ' . $pkg->getPrettyVersion() . ' is installed'), false);
34347 } else {
34348
34349 $results[] = array($package, $link, false);
34350 }
34351 }
34352
34353 continue 2;
34354 }
34355 }
34356 }
34357 }
34358
34359 ksort($results);
34360
34361 return $results;
34362 }
34363 }
34364 <?php
34365
34366
34367
34368
34369
34370
34371
34372
34373
34374
34375
34376 namespace Composer\Repository;
34377
34378 use Composer\Package\Loader\ArrayLoader;
34379 use Composer\Package\PackageInterface;
34380 use Composer\Package\AliasPackage;
34381 use Composer\Package\Version\VersionParser;
34382 use Composer\DependencyResolver\Pool;
34383 use Composer\Json\JsonFile;
34384 use Composer\Cache;
34385 use Composer\Config;
34386 use Composer\Composer;
34387 use Composer\Factory;
34388 use Composer\IO\IOInterface;
34389 use Composer\Util\RemoteFilesystem;
34390 use Composer\Plugin\PluginEvents;
34391 use Composer\Plugin\PreFileDownloadEvent;
34392 use Composer\EventDispatcher\EventDispatcher;
34393 use Composer\Downloader\TransportException;
34394 use Composer\Semver\Constraint\ConstraintInterface;
34395 use Composer\Semver\Constraint\Constraint;
34396
34397
34398
34399
34400 class ComposerRepository extends ArrayRepository implements ConfigurableRepositoryInterface
34401 {
34402 protected $config;
34403 protected $repoConfig;
34404 protected $options;
34405 protected $url;
34406 protected $baseUrl;
34407 protected $io;
34408 protected $rfs;
34409 protected $cache;
34410 protected $notifyUrl;
34411 protected $searchUrl;
34412 protected $hasProviders = false;
34413 protected $providersUrl;
34414 protected $lazyProvidersUrl;
34415 protected $providerListing;
34416 protected $providers = array();
34417 protected $providersByUid = array();
34418 protected $loader;
34419 protected $rootAliases;
34420 protected $allowSslDowngrade = false;
34421 protected $eventDispatcher;
34422 protected $sourceMirrors;
34423 protected $distMirrors;
34424 private $degradedMode = false;
34425 private $rootData;
34426 private $hasPartialPackages;
34427 private $partialPackagesByName;
34428
34429 public function __construct(array $repoConfig, IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, RemoteFilesystem $rfs = null)
34430 {
34431 parent::__construct();
34432 if (!preg_match('{^[\w.]+\??://}', $repoConfig['url'])) {
34433
34434 $repoConfig['url'] = 'http://'.$repoConfig['url'];
34435 }
34436 $repoConfig['url'] = rtrim($repoConfig['url'], '/');
34437
34438 if ('https?' === substr($repoConfig['url'], 0, 6)) {
34439 $repoConfig['url'] = (extension_loaded('openssl') ? 'https' : 'http') . substr($repoConfig['url'], 6);
34440 }
34441
34442 $urlBits = parse_url($repoConfig['url']);
34443 if ($urlBits === false || empty($urlBits['scheme'])) {
34444 throw new \UnexpectedValueException('Invalid url given for Composer repository: '.$repoConfig['url']);
34445 }
34446
34447 if (!isset($repoConfig['options'])) {
34448 $repoConfig['options'] = array();
34449 }
34450 if (isset($repoConfig['allow_ssl_downgrade']) && true === $repoConfig['allow_ssl_downgrade']) {
34451 $this->allowSslDowngrade = true;
34452 }
34453
34454 $this->config = $config;
34455 $this->options = $repoConfig['options'];
34456 $this->url = $repoConfig['url'];
34457
34458
34459 if (preg_match('{^(?P<proto>https?)://packagist\.org/?$}i', $this->url, $match)) {
34460 $this->url = $match['proto'].'://repo.packagist.org';
34461 }
34462
34463 $this->baseUrl = rtrim(preg_replace('{(?:/[^/\\\\]+\.json)?(?:[?#].*)?$}', '', $this->url), '/');
34464 $this->io = $io;
34465 $this->cache = new Cache($io, $config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $this->url), 'a-z0-9.$');
34466 $this->loader = new ArrayLoader();
34467 if ($rfs && $this->options) {
34468 $rfs = clone $rfs;
34469 $rfs->setOptions($this->options);
34470 }
34471 $this->rfs = $rfs ?: Factory::createRemoteFilesystem($this->io, $this->config, $this->options);
34472 $this->eventDispatcher = $eventDispatcher;
34473 $this->repoConfig = $repoConfig;
34474 }
34475
34476 public function getRepoConfig()
34477 {
34478 return $this->repoConfig;
34479 }
34480
34481 public function setRootAliases(array $rootAliases)
34482 {
34483 $this->rootAliases = $rootAliases;
34484 }
34485
34486
34487
34488
34489 public function findPackage($name, $constraint)
34490 {
34491 if (!$this->hasProviders()) {
34492 return parent::findPackage($name, $constraint);
34493 }
34494
34495 $name = strtolower($name);
34496 if (!$constraint instanceof ConstraintInterface) {
34497 $versionParser = new VersionParser();
34498 $constraint = $versionParser->parseConstraints($constraint);
34499 }
34500
34501 foreach ($this->getProviderNames() as $providerName) {
34502 if ($name === $providerName) {
34503 $packages = $this->whatProvides(new Pool('dev'), $providerName);
34504 foreach ($packages as $package) {
34505 if ($name === $package->getName()) {
34506 $pkgConstraint = new Constraint('==', $package->getVersion());
34507 if ($constraint->matches($pkgConstraint)) {
34508 return $package;
34509 }
34510 }
34511 }
34512 break;
34513 }
34514 }
34515 }
34516
34517
34518
34519
34520 public function findPackages($name, $constraint = null)
34521 {
34522 if (!$this->hasProviders()) {
34523 return parent::findPackages($name, $constraint);
34524 }
34525
34526 $name = strtolower($name);
34527
34528 if (null !== $constraint && !$constraint instanceof ConstraintInterface) {
34529 $versionParser = new VersionParser();
34530 $constraint = $versionParser->parseConstraints($constraint);
34531 }
34532
34533 $packages = array();
34534
34535 foreach ($this->getProviderNames() as $providerName) {
34536 if ($name === $providerName) {
34537 $candidates = $this->whatProvides(new Pool('dev'), $providerName);
34538 foreach ($candidates as $package) {
34539 if ($name === $package->getName()) {
34540 $pkgConstraint = new Constraint('==', $package->getVersion());
34541 if (null === $constraint || $constraint->matches($pkgConstraint)) {
34542 $packages[] = $package;
34543 }
34544 }
34545 }
34546 break;
34547 }
34548 }
34549
34550 return $packages;
34551 }
34552
34553 public function getPackages()
34554 {
34555 if ($this->hasProviders()) {
34556 throw new \LogicException('Composer repositories that have providers can not load the complete list of packages, use getProviderNames instead.');
34557 }
34558
34559 return parent::getPackages();
34560 }
34561
34562
34563
34564
34565 public function search($query, $mode = 0, $type = null)
34566 {
34567 $this->loadRootServerFile();
34568
34569 if ($this->searchUrl && $mode === self::SEARCH_FULLTEXT) {
34570 $url = str_replace(array('%query%', '%type%'), array($query, $type), $this->searchUrl);
34571
34572 $origin = RemoteFilesystem::getOrigin($url);
34573 $json = $this->rfs->getContents($origin, $url, false);
34574 $search = JsonFile::parseJson($json, $url);
34575
34576 if (empty($search['results'])) {
34577 return array();
34578 }
34579
34580 $results = array();
34581 foreach ($search['results'] as $result) {
34582
34583 if (empty($result['virtual'])) {
34584 $results[] = $result;
34585 }
34586 }
34587
34588 return $results;
34589 }
34590
34591 if ($this->hasProviders()) {
34592 $results = array();
34593 $regex = '{(?:'.implode('|', preg_split('{\s+}', $query)).')}i';
34594
34595 foreach ($this->getProviderNames() as $name) {
34596 if (preg_match($regex, $name)) {
34597 $results[] = array('name' => $name);
34598 }
34599 }
34600
34601 return $results;
34602 }
34603
34604 return parent::search($query, $mode);
34605 }
34606
34607 public function getProviderNames()
34608 {
34609 $this->loadRootServerFile();
34610
34611 if (null === $this->providerListing) {
34612 $this->loadProviderListings($this->loadRootServerFile());
34613 }
34614
34615 if ($this->hasPartialPackages) {
34616 if (null === $this->partialPackagesByName) {
34617 $this->initializePartialPackages();
34618 }
34619
34620 return array_keys($this->partialPackagesByName);
34621 }
34622
34623 if ($this->lazyProvidersUrl) {
34624
34625 return array();
34626 }
34627
34628 if ($this->providersUrl) {
34629 return array_keys($this->providerListing);
34630 }
34631
34632 return array();
34633 }
34634
34635 protected function configurePackageTransportOptions(PackageInterface $package)
34636 {
34637 foreach ($package->getDistUrls() as $url) {
34638 if (strpos($url, $this->baseUrl) === 0) {
34639 $package->setTransportOptions($this->options);
34640
34641 return;
34642 }
34643 }
34644 }
34645
34646 public function hasProviders()
34647 {
34648 $this->loadRootServerFile();
34649
34650 return $this->hasProviders;
34651 }
34652
34653 public function resetPackageIds()
34654 {
34655 foreach ($this->providersByUid as $package) {
34656 if ($package instanceof AliasPackage) {
34657 $package->getAliasOf()->setId(-1);
34658 }
34659 $package->setId(-1);
34660 }
34661 }
34662
34663
34664
34665
34666
34667
34668
34669 public function whatProvides(Pool $pool, $name, $bypassFilters = false)
34670 {
34671 if (isset($this->providers[$name]) && !$bypassFilters) {
34672 return $this->providers[$name];
34673 }
34674
34675 if ($this->hasPartialPackages && null === $this->partialPackagesByName) {
34676 $this->initializePartialPackages();
34677 }
34678
34679 if (!$this->hasPartialPackages || !isset($this->partialPackagesByName[$name])) {
34680
34681 if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name) || '__root__' === $name || 'composer-plugin-api' === $name) {
34682 return array();
34683 }
34684
34685 if (null === $this->providerListing) {
34686 $this->loadProviderListings($this->loadRootServerFile());
34687 }
34688
34689 $useLastModifiedCheck = false;
34690 if ($this->lazyProvidersUrl && !isset($this->providerListing[$name])) {
34691 $hash = null;
34692 $url = str_replace('%package%', $name, $this->lazyProvidersUrl);
34693 $cacheKey = 'provider-'.strtr($name, '/', '$').'.json';
34694 $useLastModifiedCheck = true;
34695 } elseif ($this->providersUrl) {
34696
34697 if (!isset($this->providerListing[$name])) {
34698 return array();
34699 }
34700
34701 $hash = $this->providerListing[$name]['sha256'];
34702 $url = str_replace(array('%package%', '%hash%'), array($name, $hash), $this->providersUrl);
34703 $cacheKey = 'provider-'.strtr($name, '/', '$').'.json';
34704 } else {
34705 return array();
34706 }
34707
34708 $packages = null;
34709 if ($cacheKey) {
34710 if (!$useLastModifiedCheck && $hash && $this->cache->sha256($cacheKey) === $hash) {
34711 $packages = json_decode($this->cache->read($cacheKey), true);
34712 } elseif ($useLastModifiedCheck) {
34713 if ($contents = $this->cache->read($cacheKey)) {
34714 $contents = json_decode($contents, true);
34715 if (isset($contents['last-modified'])) {
34716 $response = $this->fetchFileIfLastModified($url, $cacheKey, $contents['last-modified']);
34717 if (true === $response) {
34718 $packages = $contents;
34719 } elseif ($response) {
34720 $packages = $response;
34721 }
34722 }
34723 }
34724 }
34725 }
34726
34727 if (!$packages) {
34728 try {
34729 $packages = $this->fetchFile($url, $cacheKey, $hash, $useLastModifiedCheck);
34730 } catch (TransportException $e) {
34731
34732 if ($e->getStatusCode() === 404 && $this->lazyProvidersUrl) {
34733 $packages = array('packages' => array());
34734 } else {
34735 throw $e;
34736 }
34737 }
34738 }
34739
34740 $loadingPartialPackage = false;
34741 } else {
34742 $packages = array('packages' => array('versions' => $this->partialPackagesByName[$name]));
34743 $loadingPartialPackage = true;
34744 }
34745
34746 $this->providers[$name] = array();
34747 foreach ($packages['packages'] as $versions) {
34748 foreach ($versions as $version) {
34749 if (!$loadingPartialPackage && $this->hasPartialPackages && isset($this->partialPackagesByName[$version['name']])) {
34750 continue;
34751 }
34752
34753
34754 if (isset($this->providersByUid[$version['uid']])) {
34755
34756 if (!isset($this->providers[$name][$version['uid']])) {
34757
34758 if ($this->providersByUid[$version['uid']] instanceof AliasPackage) {
34759 $this->providers[$name][$version['uid']] = $this->providersByUid[$version['uid']]->getAliasOf();
34760 $this->providers[$name][$version['uid'].'-alias'] = $this->providersByUid[$version['uid']];
34761 } else {
34762 $this->providers[$name][$version['uid']] = $this->providersByUid[$version['uid']];
34763 }
34764
34765 if (isset($this->providersByUid[$version['uid'].'-root'])) {
34766 $this->providers[$name][$version['uid'].'-root'] = $this->providersByUid[$version['uid'].'-root'];
34767 }
34768 }
34769 } else {
34770 if (!$bypassFilters && !$pool->isPackageAcceptable(strtolower($version['name']), VersionParser::parseStability($version['version']))) {
34771 continue;
34772 }
34773
34774
34775 $package = $this->createPackage($version, 'Composer\Package\CompletePackage');
34776 $package->setRepository($this);
34777
34778 if ($package instanceof AliasPackage) {
34779 $aliased = $package->getAliasOf();
34780 $aliased->setRepository($this);
34781
34782 $this->providers[$name][$version['uid']] = $aliased;
34783 $this->providers[$name][$version['uid'].'-alias'] = $package;
34784
34785
34786 $this->providersByUid[$version['uid']] = $package;
34787 } else {
34788 $this->providers[$name][$version['uid']] = $package;
34789 $this->providersByUid[$version['uid']] = $package;
34790 }
34791
34792
34793 unset($rootAliasData);
34794
34795 if (isset($this->rootAliases[$package->getName()][$package->getVersion()])) {
34796 $rootAliasData = $this->rootAliases[$package->getName()][$package->getVersion()];
34797 } elseif ($package instanceof AliasPackage && isset($this->rootAliases[$package->getName()][$package->getAliasOf()->getVersion()])) {
34798 $rootAliasData = $this->rootAliases[$package->getName()][$package->getAliasOf()->getVersion()];
34799 }
34800
34801 if (isset($rootAliasData)) {
34802 $alias = $this->createAliasPackage($package, $rootAliasData['alias_normalized'], $rootAliasData['alias']);
34803 $alias->setRepository($this);
34804
34805 $this->providers[$name][$version['uid'].'-root'] = $alias;
34806 $this->providersByUid[$version['uid'].'-root'] = $alias;
34807 }
34808 }
34809 }
34810 }
34811
34812 $result = $this->providers[$name];
34813
34814
34815
34816 if ($bypassFilters) {
34817 foreach ($this->providers[$name] as $uid => $provider) {
34818 unset($this->providersByUid[$uid]);
34819 }
34820 unset($this->providers[$name]);
34821 }
34822
34823 return $result;
34824 }
34825
34826
34827
34828
34829 protected function initialize()
34830 {
34831 parent::initialize();
34832
34833 $repoData = $this->loadDataFromServer();
34834
34835 foreach ($repoData as $package) {
34836 $this->addPackage($this->createPackage($package, 'Composer\Package\CompletePackage'));
34837 }
34838 }
34839
34840
34841
34842
34843
34844
34845 public function addPackage(PackageInterface $package)
34846 {
34847 parent::addPackage($package);
34848 $this->configurePackageTransportOptions($package);
34849 }
34850
34851 protected function loadRootServerFile()
34852 {
34853 if (null !== $this->rootData) {
34854 return $this->rootData;
34855 }
34856
34857 if (!extension_loaded('openssl') && 'https' === substr($this->url, 0, 5)) {
34858 throw new \RuntimeException('You must enable the openssl extension in your php.ini to load information from '.$this->url);
34859 }
34860
34861 $jsonUrlParts = parse_url($this->url);
34862
34863 if (isset($jsonUrlParts['path']) && false !== strpos($jsonUrlParts['path'], '.json')) {
34864 $jsonUrl = $this->url;
34865 } else {
34866 $jsonUrl = $this->url . '/packages.json';
34867 }
34868
34869 $data = $this->fetchFile($jsonUrl, 'packages.json');
34870
34871 if (!empty($data['notify-batch'])) {
34872 $this->notifyUrl = $this->canonicalizeUrl($data['notify-batch']);
34873 } elseif (!empty($data['notify'])) {
34874 $this->notifyUrl = $this->canonicalizeUrl($data['notify']);
34875 }
34876
34877 if (!empty($data['search'])) {
34878 $this->searchUrl = $this->canonicalizeUrl($data['search']);
34879 }
34880
34881 if (!empty($data['mirrors'])) {
34882 foreach ($data['mirrors'] as $mirror) {
34883 if (!empty($mirror['git-url'])) {
34884 $this->sourceMirrors['git'][] = array('url' => $mirror['git-url'], 'preferred' => !empty($mirror['preferred']));
34885 }
34886 if (!empty($mirror['hg-url'])) {
34887 $this->sourceMirrors['hg'][] = array('url' => $mirror['hg-url'], 'preferred' => !empty($mirror['preferred']));
34888 }
34889 if (!empty($mirror['dist-url'])) {
34890 $this->distMirrors[] = array(
34891 'url' => $this->canonicalizeUrl($mirror['dist-url']),
34892 'preferred' => !empty($mirror['preferred']),
34893 );
34894 }
34895 }
34896 }
34897
34898 if (!empty($data['providers-lazy-url'])) {
34899 $this->lazyProvidersUrl = $this->canonicalizeUrl($data['providers-lazy-url']);
34900 $this->hasProviders = true;
34901
34902 $this->hasPartialPackages = !empty($data['packages']) && is_array($data['packages']);
34903 }
34904
34905 if ($this->allowSslDowngrade) {
34906 $this->url = str_replace('https://', 'http://', $this->url);
34907 $this->baseUrl = str_replace('https://', 'http://', $this->baseUrl);
34908 }
34909
34910 if (!empty($data['providers-url'])) {
34911 $this->providersUrl = $this->canonicalizeUrl($data['providers-url']);
34912 $this->hasProviders = true;
34913 }
34914
34915 if (!empty($data['providers']) || !empty($data['providers-includes'])) {
34916 $this->hasProviders = true;
34917 }
34918
34919
34920 if (preg_match('{^https?://repo\.packagist\.org/?$}i', $this->url) && !empty($this->repoConfig['force-lazy-providers'])) {
34921 $this->url = 'https://repo.packagist.org';
34922 $this->baseUrl = 'https://repo.packagist.org';
34923 $this->lazyProvidersUrl = $this->canonicalizeUrl('https://repo.packagist.org/p/%package%.json');
34924 $this->providersUrl = null;
34925 } elseif (!empty($this->repoConfig['force-lazy-providers'])) {
34926 $this->lazyProvidersUrl = $this->canonicalizeUrl('/p/%package%.json');
34927 $this->providersUrl = null;
34928 }
34929
34930 return $this->rootData = $data;
34931 }
34932
34933 protected function canonicalizeUrl($url)
34934 {
34935 if ('/' === $url[0]) {
34936 if (preg_match('{^[^:]++://[^/]*+}', $this->url, $matches)) {
34937 return $matches[0] . $url;
34938 }
34939
34940 return $this->url;
34941 }
34942
34943 return $url;
34944 }
34945
34946 protected function loadDataFromServer()
34947 {
34948 $data = $this->loadRootServerFile();
34949
34950 return $this->loadIncludes($data);
34951 }
34952
34953 protected function loadProviderListings($data)
34954 {
34955 if (isset($data['providers'])) {
34956 if (!is_array($this->providerListing)) {
34957 $this->providerListing = array();
34958 }
34959 $this->providerListing = array_merge($this->providerListing, $data['providers']);
34960 }
34961
34962 if ($this->providersUrl && isset($data['provider-includes'])) {
34963 $includes = $data['provider-includes'];
34964 foreach ($includes as $include => $metadata) {
34965 $url = $this->baseUrl . '/' . str_replace('%hash%', $metadata['sha256'], $include);
34966 $cacheKey = str_replace(array('%hash%','$'), '', $include);
34967 if ($this->cache->sha256($cacheKey) === $metadata['sha256']) {
34968 $includedData = json_decode($this->cache->read($cacheKey), true);
34969 } else {
34970 $includedData = $this->fetchFile($url, $cacheKey, $metadata['sha256']);
34971 }
34972
34973 $this->loadProviderListings($includedData);
34974 }
34975 }
34976 }
34977
34978 protected function loadIncludes($data)
34979 {
34980 $packages = array();
34981
34982
34983 if (!isset($data['packages']) && !isset($data['includes'])) {
34984 foreach ($data as $pkg) {
34985 foreach ($pkg['versions'] as $metadata) {
34986 $packages[] = $metadata;
34987 }
34988 }
34989
34990 return $packages;
34991 }
34992
34993 if (isset($data['packages'])) {
34994 foreach ($data['packages'] as $package => $versions) {
34995 foreach ($versions as $version => $metadata) {
34996 $packages[] = $metadata;
34997 }
34998 }
34999 }
35000
35001 if (isset($data['includes'])) {
35002 foreach ($data['includes'] as $include => $metadata) {
35003 if (isset($metadata['sha1']) && $this->cache->sha1($include) === $metadata['sha1']) {
35004 $includedData = json_decode($this->cache->read($include), true);
35005 } else {
35006 $includedData = $this->fetchFile($include);
35007 }
35008 $packages = array_merge($packages, $this->loadIncludes($includedData));
35009 }
35010 }
35011
35012 return $packages;
35013 }
35014
35015 protected function createPackage(array $data, $class = 'Composer\Package\CompletePackage')
35016 {
35017 try {
35018 if (!isset($data['notification-url'])) {
35019 $data['notification-url'] = $this->notifyUrl;
35020 }
35021
35022 $package = $this->loader->load($data, $class);
35023 if (isset($this->sourceMirrors[$package->getSourceType()])) {
35024 $package->setSourceMirrors($this->sourceMirrors[$package->getSourceType()]);
35025 }
35026 $package->setDistMirrors($this->distMirrors);
35027 $this->configurePackageTransportOptions($package);
35028
35029 return $package;
35030 } catch (\Exception $e) {
35031 throw new \RuntimeException('Could not load package '.(isset($data['name']) ? $data['name'] : json_encode($data)).' in '.$this->url.': ['.get_class($e).'] '.$e->getMessage(), 0, $e);
35032 }
35033 }
35034
35035 protected function fetchFile($filename, $cacheKey = null, $sha256 = null, $storeLastModifiedTime = false)
35036 {
35037 if (null === $cacheKey) {
35038 $cacheKey = $filename;
35039 $filename = $this->baseUrl.'/'.$filename;
35040 }
35041
35042
35043 if (($pos = strpos($filename, '$')) && preg_match('{^https?://.*}i', $filename)) {
35044 $filename = substr($filename, 0, $pos) . '%24' . substr($filename, $pos + 1);
35045 }
35046
35047 $retries = 3;
35048 while ($retries--) {
35049 try {
35050 $preFileDownloadEvent = new PreFileDownloadEvent(PluginEvents::PRE_FILE_DOWNLOAD, $this->rfs, $filename);
35051 if ($this->eventDispatcher) {
35052 $this->eventDispatcher->dispatch($preFileDownloadEvent->getName(), $preFileDownloadEvent);
35053 }
35054
35055 $origin = RemoteFilesystem::getOrigin($filename);
35056 $rfs = $preFileDownloadEvent->getRemoteFilesystem();
35057
35058 $json = $rfs->getContents($origin, $filename, false);
35059 if ($sha256 && $sha256 !== hash('sha256', $json)) {
35060
35061 if ($this->allowSslDowngrade) {
35062 $this->url = str_replace('http://', 'https://', $this->url);
35063 $this->baseUrl = str_replace('http://', 'https://', $this->baseUrl);
35064 $filename = str_replace('http://', 'https://', $filename);
35065 }
35066
35067 if ($retries) {
35068 usleep(100000);
35069
35070 continue;
35071 }
35072
35073
35074 throw new RepositorySecurityException('The contents of '.$filename.' do not match its signature. This could indicate a man-in-the-middle attack or e.g. antivirus software corrupting files. Try running composer again and report this if you think it is a mistake.');
35075 }
35076
35077 $data = JsonFile::parseJson($json, $filename);
35078 RemoteFilesystem::outputWarnings($this->io, $this->url, $data);
35079
35080 if ($cacheKey) {
35081 if ($storeLastModifiedTime) {
35082 $lastModifiedDate = $rfs->findHeaderValue($rfs->getLastHeaders(), 'last-modified');
35083 if ($lastModifiedDate) {
35084 $data['last-modified'] = $lastModifiedDate;
35085 $json = json_encode($data);
35086 }
35087 }
35088 $this->cache->write($cacheKey, $json);
35089 }
35090
35091 break;
35092 } catch (\Exception $e) {
35093 if ($e instanceof TransportException && $e->getStatusCode() === 404) {
35094 throw $e;
35095 }
35096
35097 if ($retries) {
35098 usleep(100000);
35099 continue;
35100 }
35101
35102 if ($e instanceof RepositorySecurityException) {
35103 throw $e;
35104 }
35105
35106 if ($cacheKey && ($contents = $this->cache->read($cacheKey))) {
35107 if (!$this->degradedMode) {
35108 $this->io->writeError('<warning>'.$e->getMessage().'</warning>');
35109 $this->io->writeError('<warning>'.$this->url.' could not be fully loaded, package information was loaded from the local cache and may be out of date</warning>');
35110 }
35111 $this->degradedMode = true;
35112 $data = JsonFile::parseJson($contents, $this->cache->getRoot().$cacheKey);
35113
35114 break;
35115 }
35116
35117 throw $e;
35118 }
35119 }
35120
35121 return $data;
35122 }
35123
35124 protected function fetchFileIfLastModified($filename, $cacheKey, $lastModifiedTime)
35125 {
35126 $retries = 3;
35127 while ($retries--) {
35128 try {
35129 $preFileDownloadEvent = new PreFileDownloadEvent(PluginEvents::PRE_FILE_DOWNLOAD, $this->rfs, $filename);
35130 if ($this->eventDispatcher) {
35131 $this->eventDispatcher->dispatch($preFileDownloadEvent->getName(), $preFileDownloadEvent);
35132 }
35133
35134 $origin = RemoteFilesystem::getOrigin($filename);
35135 $rfs = $preFileDownloadEvent->getRemoteFilesystem();
35136 $options = array('http' => array('header' => array('If-Modified-Since: '.$lastModifiedTime)));
35137 $json = $rfs->getContents($origin, $filename, false, $options);
35138 if ($json === '' && $rfs->findStatusCode($rfs->getLastHeaders()) === 304) {
35139 return true;
35140 }
35141
35142 $data = JsonFile::parseJson($json, $filename);
35143 RemoteFilesystem::outputWarnings($this->io, $this->url, $data);
35144
35145 $lastModifiedDate = $rfs->findHeaderValue($rfs->getLastHeaders(), 'last-modified');
35146 if ($lastModifiedDate) {
35147 $data['last-modified'] = $lastModifiedDate;
35148 $json = json_encode($data);
35149 }
35150 $this->cache->write($cacheKey, $json);
35151
35152 return $data;
35153 } catch (\Exception $e) {
35154 if ($e instanceof TransportException && $e->getStatusCode() === 404) {
35155 throw $e;
35156 }
35157
35158 if ($retries) {
35159 usleep(100000);
35160 continue;
35161 }
35162
35163 if (!$this->degradedMode) {
35164 $this->io->writeError('<warning>'.$e->getMessage().'</warning>');
35165 $this->io->writeError('<warning>'.$this->url.' could not be fully loaded, package information was loaded from the local cache and may be out of date</warning>');
35166 }
35167 $this->degradedMode = true;
35168
35169 return true;
35170 }
35171 }
35172 }
35173
35174
35175
35176
35177
35178
35179 private function initializePartialPackages()
35180 {
35181 $rootData = $this->loadRootServerFile();
35182
35183 $this->partialPackagesByName = array();
35184 foreach ($rootData['packages'] as $package => $versions) {
35185 $package = strtolower($package);
35186 foreach ($versions as $version) {
35187 $this->partialPackagesByName[$package][] = $version;
35188 if (!empty($version['provide']) && is_array($version['provide'])) {
35189 foreach ($version['provide'] as $provided => $providedVersion) {
35190 $this->partialPackagesByName[strtolower($provided)][] = $version;
35191 }
35192 }
35193 if (!empty($version['replace']) && is_array($version['replace'])) {
35194 foreach ($version['replace'] as $provided => $providedVersion) {
35195 $this->partialPackagesByName[strtolower($provided)][] = $version;
35196 }
35197 }
35198 }
35199 }
35200
35201
35202 $this->rootData = true;
35203 }
35204 }
35205 <?php
35206
35207
35208
35209
35210
35211
35212
35213
35214
35215
35216
35217 namespace Composer\Repository;
35218
35219 use Composer\Package\PackageInterface;
35220
35221
35222
35223
35224
35225
35226 class CompositeRepository extends BaseRepository
35227 {
35228
35229
35230
35231
35232 private $repositories;
35233
35234
35235
35236
35237
35238 public function __construct(array $repositories)
35239 {
35240 $this->repositories = array();
35241 foreach ($repositories as $repo) {
35242 $this->addRepository($repo);
35243 }
35244 }
35245
35246
35247
35248
35249
35250
35251 public function getRepositories()
35252 {
35253 return $this->repositories;
35254 }
35255
35256
35257
35258
35259 public function hasPackage(PackageInterface $package)
35260 {
35261 foreach ($this->repositories as $repository) {
35262
35263 if ($repository->hasPackage($package)) {
35264 return true;
35265 }
35266 }
35267
35268 return false;
35269 }
35270
35271
35272
35273
35274 public function findPackage($name, $constraint)
35275 {
35276 foreach ($this->repositories as $repository) {
35277
35278 $package = $repository->findPackage($name, $constraint);
35279 if (null !== $package) {
35280 return $package;
35281 }
35282 }
35283
35284 return null;
35285 }
35286
35287
35288
35289
35290 public function findPackages($name, $constraint = null)
35291 {
35292 $packages = array();
35293 foreach ($this->repositories as $repository) {
35294
35295 $packages[] = $repository->findPackages($name, $constraint);
35296 }
35297
35298 return $packages ? call_user_func_array('array_merge', $packages) : array();
35299 }
35300
35301
35302
35303
35304 public function search($query, $mode = 0, $type = null)
35305 {
35306 $matches = array();
35307 foreach ($this->repositories as $repository) {
35308
35309 $matches[] = $repository->search($query, $mode, $type);
35310 }
35311
35312 return $matches ? call_user_func_array('array_merge', $matches) : array();
35313 }
35314
35315
35316
35317
35318 public function getPackages()
35319 {
35320 $packages = array();
35321 foreach ($this->repositories as $repository) {
35322
35323 $packages[] = $repository->getPackages();
35324 }
35325
35326 return $packages ? call_user_func_array('array_merge', $packages) : array();
35327 }
35328
35329
35330
35331
35332 public function removePackage(PackageInterface $package)
35333 {
35334 foreach ($this->repositories as $repository) {
35335
35336 $repository->removePackage($package);
35337 }
35338 }
35339
35340
35341
35342
35343 public function count()
35344 {
35345 $total = 0;
35346 foreach ($this->repositories as $repository) {
35347
35348 $total += $repository->count();
35349 }
35350
35351 return $total;
35352 }
35353
35354
35355
35356
35357
35358 public function addRepository(RepositoryInterface $repository)
35359 {
35360 if ($repository instanceof self) {
35361 foreach ($repository->getRepositories() as $repo) {
35362 $this->addRepository($repo);
35363 }
35364 } else {
35365 $this->repositories[] = $repository;
35366 }
35367 }
35368 }
35369 <?php
35370
35371
35372
35373
35374
35375
35376
35377
35378
35379
35380
35381 namespace Composer\Repository;
35382
35383
35384
35385
35386
35387
35388 interface ConfigurableRepositoryInterface
35389 {
35390 public function getRepoConfig();
35391 }
35392 <?php
35393
35394
35395
35396
35397
35398
35399
35400
35401
35402
35403
35404 namespace Composer\Repository;
35405
35406 use Composer\Json\JsonFile;
35407 use Composer\Package\Loader\ArrayLoader;
35408 use Composer\Package\Dumper\ArrayDumper;
35409
35410
35411
35412
35413
35414
35415
35416 class FilesystemRepository extends WritableArrayRepository
35417 {
35418 private $file;
35419
35420
35421
35422
35423
35424
35425 public function __construct(JsonFile $repositoryFile)
35426 {
35427 parent::__construct();
35428 $this->file = $repositoryFile;
35429 }
35430
35431
35432
35433
35434 protected function initialize()
35435 {
35436 parent::initialize();
35437
35438 if (!$this->file->exists()) {
35439 return;
35440 }
35441
35442 try {
35443 $packages = $this->file->read();
35444
35445
35446 if (isset($packages['packages'])) {
35447 $packages = $packages['packages'];
35448 }
35449
35450 if (!is_array($packages)) {
35451 throw new \UnexpectedValueException('Could not parse package list from the repository');
35452 }
35453 } catch (\Exception $e) {
35454 throw new InvalidRepositoryException('Invalid repository data in '.$this->file->getPath().', packages could not be loaded: ['.get_class($e).'] '.$e->getMessage());
35455 }
35456
35457 $loader = new ArrayLoader(null, true);
35458 foreach ($packages as $packageData) {
35459 $package = $loader->load($packageData);
35460 $this->addPackage($package);
35461 }
35462 }
35463
35464 public function reload()
35465 {
35466 $this->packages = null;
35467 $this->initialize();
35468 }
35469
35470
35471
35472
35473 public function write()
35474 {
35475 $data = array();
35476 $dumper = new ArrayDumper();
35477
35478 foreach ($this->getCanonicalPackages() as $package) {
35479 $data[] = $dumper->dump($package);
35480 }
35481
35482 usort($data, function ($a, $b) {
35483 return strcmp($a['name'], $b['name']);
35484 });
35485
35486 $this->file->write($data);
35487 }
35488 }
35489 <?php
35490
35491
35492
35493
35494
35495
35496
35497
35498
35499
35500
35501 namespace Composer\Repository;
35502
35503
35504
35505
35506
35507
35508
35509
35510 class InstalledArrayRepository extends WritableArrayRepository implements InstalledRepositoryInterface
35511 {
35512 }
35513 <?php
35514
35515
35516
35517
35518
35519
35520
35521
35522
35523
35524
35525 namespace Composer\Repository;
35526
35527
35528
35529
35530
35531
35532 class InstalledFilesystemRepository extends FilesystemRepository implements InstalledRepositoryInterface
35533 {
35534 }
35535 <?php
35536
35537
35538
35539
35540
35541
35542
35543
35544
35545
35546
35547 namespace Composer\Repository;
35548
35549
35550
35551
35552
35553
35554
35555
35556 interface InstalledRepositoryInterface extends WritableRepositoryInterface
35557 {
35558 }
35559 <?php
35560
35561
35562
35563
35564
35565
35566
35567
35568
35569
35570
35571 namespace Composer\Repository;
35572
35573
35574
35575
35576
35577
35578 class InvalidRepositoryException extends \Exception
35579 {
35580 }
35581 <?php
35582
35583
35584
35585
35586
35587
35588
35589
35590
35591
35592
35593 namespace Composer\Repository;
35594
35595 use Composer\Package\Loader\ArrayLoader;
35596 use Composer\Package\Loader\ValidatingArrayLoader;
35597
35598
35599
35600
35601
35602
35603 class PackageRepository extends ArrayRepository
35604 {
35605 private $config;
35606
35607
35608
35609
35610
35611
35612 public function __construct(array $config)
35613 {
35614 parent::__construct();
35615 $this->config = $config['package'];
35616
35617
35618 if (!is_numeric(key($this->config))) {
35619 $this->config = array($this->config);
35620 }
35621 }
35622
35623
35624
35625
35626 protected function initialize()
35627 {
35628 parent::initialize();
35629
35630 $loader = new ValidatingArrayLoader(new ArrayLoader(null, true), false);
35631 foreach ($this->config as $package) {
35632 try {
35633 $package = $loader->load($package);
35634 } catch (\Exception $e) {
35635 throw new InvalidRepositoryException('A repository of type "package" contains an invalid package definition: '.$e->getMessage()."\n\nInvalid package definition:\n".json_encode($package));
35636 }
35637
35638 $this->addPackage($package);
35639 }
35640 }
35641 }
35642 <?php
35643
35644
35645
35646
35647
35648
35649
35650
35651
35652
35653
35654 namespace Composer\Repository;
35655
35656 use Composer\Config;
35657 use Composer\IO\IOInterface;
35658 use Composer\Json\JsonFile;
35659 use Composer\Package\Loader\ArrayLoader;
35660 use Composer\Package\Version\VersionGuesser;
35661 use Composer\Package\Version\VersionParser;
35662 use Composer\Util\Platform;
35663 use Composer\Util\ProcessExecutor;
35664 use Composer\Util\Filesystem;
35665 use Composer\Util\Git as GitUtil;
35666
35667
35668
35669
35670
35671
35672
35673
35674
35675
35676
35677
35678
35679
35680
35681
35682
35683
35684
35685
35686
35687
35688
35689
35690
35691
35692
35693
35694
35695
35696
35697
35698
35699
35700
35701
35702 class PathRepository extends ArrayRepository implements ConfigurableRepositoryInterface
35703 {
35704
35705
35706
35707 private $loader;
35708
35709
35710
35711
35712 private $versionGuesser;
35713
35714
35715
35716
35717 private $url;
35718
35719
35720
35721
35722 private $repoConfig;
35723
35724
35725
35726
35727 private $process;
35728
35729
35730
35731
35732 private $options;
35733
35734
35735
35736
35737
35738
35739
35740
35741 public function __construct(array $repoConfig, IOInterface $io, Config $config)
35742 {
35743 if (!isset($repoConfig['url'])) {
35744 throw new \RuntimeException('You must specify the `url` configuration for the path repository');
35745 }
35746
35747 $this->loader = new ArrayLoader(null, true);
35748 $this->url = Platform::expandPath($repoConfig['url']);
35749 $this->process = new ProcessExecutor($io);
35750 $this->versionGuesser = new VersionGuesser($config, $this->process, new VersionParser());
35751 $this->repoConfig = $repoConfig;
35752 $this->options = isset($repoConfig['options']) ? $repoConfig['options'] : array();
35753 if (!isset($this->options['relative'])) {
35754 $filesystem = new Filesystem();
35755 $this->options['relative'] = !$filesystem->isAbsolutePath($this->url);
35756 }
35757
35758 parent::__construct();
35759 }
35760
35761 public function getRepoConfig()
35762 {
35763 return $this->repoConfig;
35764 }
35765
35766
35767
35768
35769
35770
35771 protected function initialize()
35772 {
35773 parent::initialize();
35774
35775 $urlMatches = $this->getUrlMatches();
35776
35777 if (empty($urlMatches)) {
35778 if (preg_match('{[*{}]}', $this->url)) {
35779 $url = $this->url;
35780 while (preg_match('{[*{}]}', $url)) {
35781 $url = dirname($url);
35782 }
35783
35784 if (is_dir($url)) {
35785 return;
35786 }
35787 }
35788
35789 throw new \RuntimeException('The `url` supplied for the path (' . $this->url . ') repository does not exist');
35790 }
35791
35792 foreach ($urlMatches as $url) {
35793 $path = realpath($url) . DIRECTORY_SEPARATOR;
35794 $composerFilePath = $path.'composer.json';
35795
35796 if (!file_exists($composerFilePath)) {
35797 continue;
35798 }
35799
35800 $json = file_get_contents($composerFilePath);
35801 $package = JsonFile::parseJson($json, $composerFilePath);
35802 $package['dist'] = array(
35803 'type' => 'path',
35804 'url' => $url,
35805 'reference' => sha1($json . serialize($this->options)),
35806 );
35807 $package['transport-options'] = $this->options;
35808 unset($package['transport-options']['versions']);
35809
35810
35811 if (isset($package['name'], $this->options['versions'][$package['name']])) {
35812 $package['version'] = $this->options['versions'][$package['name']];
35813 }
35814
35815
35816 if (!isset($package['version']) && ($rootVersion = getenv('COMPOSER_ROOT_VERSION'))) {
35817 if (
35818 0 === $this->process->execute('git rev-parse HEAD', $ref1, $path)
35819 && 0 === $this->process->execute('git rev-parse HEAD', $ref2)
35820 && $ref1 === $ref2
35821 ) {
35822 $package['version'] = $rootVersion;
35823 }
35824 }
35825
35826 $output = '';
35827 if (is_dir($path . DIRECTORY_SEPARATOR . '.git') && 0 === $this->process->execute('git log -n1 --pretty=%H'.GitUtil::getNoShowSignatureFlag($this->process), $output, $path)) {
35828 $package['dist']['reference'] = trim($output);
35829 }
35830
35831 if (!isset($package['version'])) {
35832 $versionData = $this->versionGuesser->guessVersion($package, $path);
35833 if (is_array($versionData) && $versionData['pretty_version']) {
35834
35835 if (!empty($versionData['feature_pretty_version'])) {
35836 $package['version'] = $versionData['feature_pretty_version'];
35837 $this->addPackage($this->loader->load($package));
35838 }
35839
35840 $package['version'] = $versionData['pretty_version'];
35841 } else {
35842 $package['version'] = 'dev-master';
35843 }
35844 }
35845
35846 $package = $this->loader->load($package);
35847 $this->addPackage($package);
35848 }
35849 }
35850
35851
35852
35853
35854
35855
35856 private function getUrlMatches()
35857 {
35858 $flags = GLOB_MARK | GLOB_ONLYDIR;
35859
35860 if (defined('GLOB_BRACE')) {
35861 $flags |= GLOB_BRACE;
35862 } elseif (strpos($this->url, '{') !== false || strpos($this->url, '}') !== false) {
35863 throw new \RuntimeException('The operating system does not support GLOB_BRACE which is required for the url '. $this->url);
35864 }
35865
35866
35867 return array_map(function ($val) {
35868 return rtrim(str_replace(DIRECTORY_SEPARATOR, '/', $val), '/');
35869 }, glob($this->url, $flags));
35870 }
35871 }
35872 <?php
35873
35874
35875
35876
35877
35878
35879
35880
35881
35882
35883
35884 namespace Composer\Repository\Pear;
35885
35886 use Composer\Util\RemoteFilesystem;
35887
35888
35889
35890
35891
35892
35893
35894
35895 abstract class BaseChannelReader
35896 {
35897
35898
35899
35900 const CHANNEL_NS = 'http://pear.php.net/channel-1.0';
35901 const ALL_CATEGORIES_NS = 'http://pear.php.net/dtd/rest.allcategories';
35902 const CATEGORY_PACKAGES_INFO_NS = 'http://pear.php.net/dtd/rest.categorypackageinfo';
35903 const ALL_PACKAGES_NS = 'http://pear.php.net/dtd/rest.allpackages';
35904 const ALL_RELEASES_NS = 'http://pear.php.net/dtd/rest.allreleases';
35905 const PACKAGE_INFO_NS = 'http://pear.php.net/dtd/rest.package';
35906
35907
35908 private $rfs;
35909
35910 protected function __construct(RemoteFilesystem $rfs)
35911 {
35912 $this->rfs = $rfs;
35913 }
35914
35915
35916
35917
35918
35919
35920
35921
35922
35923 protected function requestContent($origin, $path)
35924 {
35925 $url = rtrim($origin, '/') . '/' . ltrim($path, '/');
35926 $content = $this->rfs->getContents($origin, $url, false);
35927 if (!$content) {
35928 throw new \UnexpectedValueException('The PEAR channel at ' . $url . ' did not respond.');
35929 }
35930
35931 return str_replace('http://pear.php.net/rest/', 'https://pear.php.net/rest/', $content);
35932 }
35933
35934
35935
35936
35937
35938
35939
35940
35941
35942 protected function requestXml($origin, $path)
35943 {
35944
35945 $xml = simplexml_load_string($this->requestContent($origin, $path), "SimpleXMLElement", LIBXML_NOERROR);
35946
35947 if (false === $xml) {
35948 throw new \UnexpectedValueException(sprintf('The PEAR channel at ' . $origin . ' is broken. (Invalid XML at file `%s`)', $path));
35949 }
35950
35951 return $xml;
35952 }
35953 }
35954 <?php
35955
35956
35957
35958
35959
35960
35961
35962
35963
35964
35965
35966 namespace Composer\Repository\Pear;
35967
35968
35969
35970
35971
35972
35973 class ChannelInfo
35974 {
35975 private $name;
35976 private $alias;
35977 private $packages;
35978
35979
35980
35981
35982
35983
35984 public function __construct($name, $alias, array $packages)
35985 {
35986 $this->name = $name;
35987 $this->alias = $alias;
35988 $this->packages = $packages;
35989 }
35990
35991
35992
35993
35994
35995
35996 public function getName()
35997 {
35998 return $this->name;
35999 }
36000
36001
36002
36003
36004
36005
36006 public function getAlias()
36007 {
36008 return $this->alias;
36009 }
36010
36011
36012
36013
36014
36015
36016 public function getPackages()
36017 {
36018 return $this->packages;
36019 }
36020 }
36021 <?php
36022
36023
36024
36025
36026
36027
36028
36029
36030
36031
36032
36033 namespace Composer\Repository\Pear;
36034
36035 use Composer\Util\RemoteFilesystem;
36036
36037
36038
36039
36040
36041
36042
36043
36044 class ChannelReader extends BaseChannelReader
36045 {
36046
36047 private $readerMap;
36048
36049 public function __construct(RemoteFilesystem $rfs)
36050 {
36051 parent::__construct($rfs);
36052
36053 $rest10reader = new ChannelRest10Reader($rfs);
36054 $rest11reader = new ChannelRest11Reader($rfs);
36055
36056 $this->readerMap = array(
36057 'REST1.3' => $rest11reader,
36058 'REST1.2' => $rest11reader,
36059 'REST1.1' => $rest11reader,
36060 'REST1.0' => $rest10reader,
36061 );
36062 }
36063
36064
36065
36066
36067
36068
36069
36070
36071 public function read($url)
36072 {
36073 $xml = $this->requestXml($url, "/channel.xml");
36074
36075 $channelName = (string) $xml->name;
36076 $channelAlias = (string) $xml->suggestedalias;
36077
36078 $supportedVersions = array_keys($this->readerMap);
36079 $selectedRestVersion = $this->selectRestVersion($xml, $supportedVersions);
36080 if (!$selectedRestVersion) {
36081 throw new \UnexpectedValueException(sprintf('PEAR repository %s does not supports any of %s protocols.', $url, implode(', ', $supportedVersions)));
36082 }
36083
36084 $reader = $this->readerMap[$selectedRestVersion['version']];
36085 $packageDefinitions = $reader->read($selectedRestVersion['baseUrl']);
36086
36087 return new ChannelInfo($channelName, $channelAlias, $packageDefinitions);
36088 }
36089
36090
36091
36092
36093
36094
36095
36096
36097 private function selectRestVersion($channelXml, $supportedVersions)
36098 {
36099 $channelXml->registerXPathNamespace('ns', self::CHANNEL_NS);
36100
36101 foreach ($supportedVersions as $version) {
36102 $xpathTest = "ns:servers/ns:*/ns:rest/ns:baseurl[@type='{$version}']";
36103 $testResult = $channelXml->xpath($xpathTest);
36104
36105 foreach ($testResult as $result) {
36106
36107 $result = (string) $result;
36108 if (preg_match('{^https://}i', $result)) {
36109 return array('version' => $version, 'baseUrl' => $result);
36110 }
36111 }
36112
36113
36114 if (count($testResult) > 0) {
36115 return array('version' => $version, 'baseUrl' => (string) $testResult[0]);
36116 }
36117 }
36118
36119 return null;
36120 }
36121 }
36122 <?php
36123
36124
36125
36126
36127
36128
36129
36130
36131
36132
36133
36134 namespace Composer\Repository\Pear;
36135
36136 use Composer\Downloader\TransportException;
36137
36138
36139
36140
36141
36142
36143
36144
36145
36146
36147
36148
36149 class ChannelRest10Reader extends BaseChannelReader
36150 {
36151 private $dependencyReader;
36152
36153 public function __construct($rfs)
36154 {
36155 parent::__construct($rfs);
36156
36157 $this->dependencyReader = new PackageDependencyParser();
36158 }
36159
36160
36161
36162
36163
36164
36165
36166
36167 public function read($baseUrl)
36168 {
36169 return $this->readPackages($baseUrl);
36170 }
36171
36172
36173
36174
36175
36176
36177
36178
36179 private function readPackages($baseUrl)
36180 {
36181 $result = array();
36182
36183 $xmlPath = '/p/packages.xml';
36184 $xml = $this->requestXml($baseUrl, $xmlPath);
36185 $xml->registerXPathNamespace('ns', self::ALL_PACKAGES_NS);
36186 foreach ($xml->xpath('ns:p') as $node) {
36187 $packageName = (string) $node;
36188 $packageInfo = $this->readPackage($baseUrl, $packageName);
36189 $result[] = $packageInfo;
36190 }
36191
36192 return $result;
36193 }
36194
36195
36196
36197
36198
36199
36200
36201
36202
36203 private function readPackage($baseUrl, $packageName)
36204 {
36205 $xmlPath = '/p/' . strtolower($packageName) . '/info.xml';
36206 $xml = $this->requestXml($baseUrl, $xmlPath);
36207 $xml->registerXPathNamespace('ns', self::PACKAGE_INFO_NS);
36208
36209 $channelName = (string) $xml->c;
36210 $packageName = (string) $xml->n;
36211 $license = (string) $xml->l;
36212 $shortDescription = (string) $xml->s;
36213 $description = (string) $xml->d;
36214
36215 return new PackageInfo(
36216 $channelName,
36217 $packageName,
36218 $license,
36219 $shortDescription,
36220 $description,
36221 $this->readPackageReleases($baseUrl, $packageName)
36222 );
36223 }
36224
36225
36226
36227
36228
36229
36230
36231
36232
36233
36234 private function readPackageReleases($baseUrl, $packageName)
36235 {
36236 $result = array();
36237
36238 try {
36239 $xmlPath = '/r/' . strtolower($packageName) . '/allreleases.xml';
36240 $xml = $this->requestXml($baseUrl, $xmlPath);
36241 $xml->registerXPathNamespace('ns', self::ALL_RELEASES_NS);
36242 foreach ($xml->xpath('ns:r') as $node) {
36243 $releaseVersion = (string) $node->v;
36244 $releaseStability = (string) $node->s;
36245
36246 try {
36247 $result[$releaseVersion] = new ReleaseInfo(
36248 $releaseStability,
36249 $this->readPackageReleaseDependencies($baseUrl, $packageName, $releaseVersion)
36250 );
36251 } catch (TransportException $exception) {
36252 if ($exception->getCode() != 404) {
36253 throw $exception;
36254 }
36255 }
36256 }
36257 } catch (TransportException $exception) {
36258 if ($exception->getCode() != 404) {
36259 throw $exception;
36260 }
36261 }
36262
36263 return $result;
36264 }
36265
36266
36267
36268
36269
36270
36271
36272
36273
36274
36275 private function readPackageReleaseDependencies($baseUrl, $packageName, $version)
36276 {
36277 $dependencyReader = new PackageDependencyParser();
36278
36279 $depthPath = '/r/' . strtolower($packageName) . '/deps.' . $version . '.txt';
36280 $content = $this->requestContent($baseUrl, $depthPath);
36281 $dependencyArray = unserialize($content);
36282
36283 return $dependencyReader->buildDependencyInfo($dependencyArray);
36284 }
36285 }
36286 <?php
36287
36288
36289
36290
36291
36292
36293
36294
36295
36296
36297
36298 namespace Composer\Repository\Pear;
36299
36300
36301
36302
36303
36304
36305
36306
36307
36308
36309 class ChannelRest11Reader extends BaseChannelReader
36310 {
36311 private $dependencyReader;
36312
36313 public function __construct($rfs)
36314 {
36315 parent::__construct($rfs);
36316
36317 $this->dependencyReader = new PackageDependencyParser();
36318 }
36319
36320
36321
36322
36323
36324
36325
36326
36327 public function read($baseUrl)
36328 {
36329 return $this->readChannelPackages($baseUrl);
36330 }
36331
36332
36333
36334
36335
36336
36337
36338
36339 private function readChannelPackages($baseUrl)
36340 {
36341 $result = array();
36342
36343 $xml = $this->requestXml($baseUrl, "/c/categories.xml");
36344 $xml->registerXPathNamespace('ns', self::ALL_CATEGORIES_NS);
36345 foreach ($xml->xpath('ns:c') as $node) {
36346 $categoryName = (string) $node;
36347 $categoryPackages = $this->readCategoryPackages($baseUrl, $categoryName);
36348 $result = array_merge($result, $categoryPackages);
36349 }
36350
36351 return $result;
36352 }
36353
36354
36355
36356
36357
36358
36359
36360
36361
36362 private function readCategoryPackages($baseUrl, $categoryName)
36363 {
36364 $result = array();
36365
36366 $categoryPath = '/c/'.urlencode($categoryName).'/packagesinfo.xml';
36367 $xml = $this->requestXml($baseUrl, $categoryPath);
36368 $xml->registerXPathNamespace('ns', self::CATEGORY_PACKAGES_INFO_NS);
36369 foreach ($xml->xpath('ns:pi') as $node) {
36370 $packageInfo = $this->parsePackage($node);
36371 $result[] = $packageInfo;
36372 }
36373
36374 return $result;
36375 }
36376
36377
36378
36379
36380
36381
36382
36383 private function parsePackage($packageInfo)
36384 {
36385 $packageInfo->registerXPathNamespace('ns', self::CATEGORY_PACKAGES_INFO_NS);
36386 $channelName = (string) $packageInfo->p->c;
36387 $packageName = (string) $packageInfo->p->n;
36388 $license = (string) $packageInfo->p->l;
36389 $shortDescription = (string) $packageInfo->p->s;
36390 $description = (string) $packageInfo->p->d;
36391
36392 $dependencies = array();
36393 foreach ($packageInfo->xpath('ns:deps') as $node) {
36394 $dependencyVersion = (string) $node->v;
36395 $dependencyArray = unserialize((string) $node->d);
36396
36397 $dependencyInfo = $this->dependencyReader->buildDependencyInfo($dependencyArray);
36398
36399 $dependencies[$dependencyVersion] = $dependencyInfo;
36400 }
36401
36402 $releases = array();
36403 $releasesInfo = $packageInfo->xpath('ns:a/ns:r');
36404 if ($releasesInfo) {
36405 foreach ($releasesInfo as $node) {
36406 $releaseVersion = (string) $node->v;
36407 $releaseStability = (string) $node->s;
36408 $releases[$releaseVersion] = new ReleaseInfo(
36409 $releaseStability,
36410 isset($dependencies[$releaseVersion]) ? $dependencies[$releaseVersion] : new DependencyInfo(array(), array())
36411 );
36412 }
36413 }
36414
36415 return new PackageInfo(
36416 $channelName,
36417 $packageName,
36418 $license,
36419 $shortDescription,
36420 $description,
36421 $releases
36422 );
36423 }
36424 }
36425 <?php
36426
36427
36428
36429
36430
36431
36432
36433
36434
36435
36436
36437 namespace Composer\Repository\Pear;
36438
36439
36440
36441
36442
36443
36444 class DependencyConstraint
36445 {
36446 private $type;
36447 private $constraint;
36448 private $channelName;
36449 private $packageName;
36450
36451
36452
36453
36454
36455
36456
36457 public function __construct($type, $constraint, $channelName, $packageName)
36458 {
36459 $this->type = $type;
36460 $this->constraint = $constraint;
36461 $this->channelName = $channelName;
36462 $this->packageName = $packageName;
36463 }
36464
36465 public function getChannelName()
36466 {
36467 return $this->channelName;
36468 }
36469
36470 public function getConstraint()
36471 {
36472 return $this->constraint;
36473 }
36474
36475 public function getPackageName()
36476 {
36477 return $this->packageName;
36478 }
36479
36480 public function getType()
36481 {
36482 return $this->type;
36483 }
36484 }
36485 <?php
36486
36487
36488
36489
36490
36491
36492
36493
36494
36495
36496
36497 namespace Composer\Repository\Pear;
36498
36499
36500
36501
36502
36503
36504 class DependencyInfo
36505 {
36506 private $requires;
36507 private $optionals;
36508
36509
36510
36511
36512
36513 public function __construct($requires, $optionals)
36514 {
36515 $this->requires = $requires;
36516 $this->optionals = $optionals;
36517 }
36518
36519
36520
36521
36522 public function getRequires()
36523 {
36524 return $this->requires;
36525 }
36526
36527
36528
36529
36530 public function getOptionals()
36531 {
36532 return $this->optionals;
36533 }
36534 }
36535 <?php
36536
36537
36538
36539
36540
36541
36542
36543
36544
36545
36546
36547 namespace Composer\Repository\Pear;
36548
36549
36550
36551
36552
36553
36554 class PackageDependencyParser
36555 {
36556
36557
36558
36559
36560
36561
36562 public function buildDependencyInfo($depArray)
36563 {
36564 if (!is_array($depArray)) {
36565 return new DependencyInfo(array(), array());
36566 }
36567 if (!$this->isHash($depArray)) {
36568 return new DependencyInfo($this->buildDependency10Info($depArray), array());
36569 }
36570
36571 return $this->buildDependency20Info($depArray);
36572 }
36573
36574
36575
36576
36577
36578
36579
36580
36581
36582
36583
36584
36585
36586 private function buildDependency10Info($depArray)
36587 {
36588 static $dep10toOperatorMap = array('has' => '==', 'eq' => '==', 'ge' => '>=', 'gt' => '>', 'le' => '<=', 'lt' => '<', 'not' => '!=');
36589
36590 $result = array();
36591
36592 foreach ($depArray as $depItem) {
36593 if (empty($depItem['rel']) || !array_key_exists($depItem['rel'], $dep10toOperatorMap)) {
36594
36595 continue;
36596 }
36597
36598 $depType = !empty($depItem['optional']) && 'yes' == $depItem['optional']
36599 ? 'optional'
36600 : 'required';
36601 $depType = 'not' == $depItem['rel']
36602 ? 'conflicts'
36603 : $depType;
36604
36605 $depVersion = !empty($depItem['version']) ? $this->parseVersion($depItem['version']) : '*';
36606
36607
36608 $depVersionConstraint = ('has' == $depItem['rel'] || 'not' == $depItem['rel']) && '*' == $depVersion
36609 ? '*'
36610 : $dep10toOperatorMap[$depItem['rel']] . $depVersion;
36611
36612 switch ($depItem['type']) {
36613 case 'php':
36614 $depChannelName = 'php';
36615 $depPackageName = '';
36616 break;
36617 case 'pkg':
36618 $depChannelName = !empty($depItem['channel']) ? $depItem['channel'] : 'pear.php.net';
36619 $depPackageName = $depItem['name'];
36620 break;
36621 case 'ext':
36622 $depChannelName = 'ext';
36623 $depPackageName = $depItem['name'];
36624 break;
36625 case 'os':
36626 case 'sapi':
36627 $depChannelName = '';
36628 $depPackageName = '';
36629 break;
36630 default:
36631 $depChannelName = '';
36632 $depPackageName = '';
36633 break;
36634 }
36635
36636 if ('' != $depChannelName) {
36637 $result[] = new DependencyConstraint(
36638 $depType,
36639 $depVersionConstraint,
36640 $depChannelName,
36641 $depPackageName
36642 );
36643 }
36644 }
36645
36646 return $result;
36647 }
36648
36649
36650
36651
36652
36653
36654
36655 private function buildDependency20Info($depArray)
36656 {
36657 $result = array();
36658 $optionals = array();
36659 $defaultOptionals = array();
36660 foreach ($depArray as $depType => $depTypeGroup) {
36661 if (!is_array($depTypeGroup)) {
36662 continue;
36663 }
36664 if ('required' == $depType || 'optional' == $depType) {
36665 foreach ($depTypeGroup as $depItemType => $depItem) {
36666 switch ($depItemType) {
36667 case 'php':
36668 $result[] = new DependencyConstraint(
36669 $depType,
36670 $this->parse20VersionConstraint($depItem),
36671 'php',
36672 ''
36673 );
36674 break;
36675 case 'package':
36676 $deps = $this->buildDepPackageConstraints($depItem, $depType);
36677 $result = array_merge($result, $deps);
36678 break;
36679 case 'extension':
36680 $deps = $this->buildDepExtensionConstraints($depItem, $depType);
36681 $result = array_merge($result, $deps);
36682 break;
36683 case 'subpackage':
36684 $deps = $this->buildDepPackageConstraints($depItem, 'replaces');
36685 $defaultOptionals += $deps;
36686 break;
36687 case 'os':
36688 case 'pearinstaller':
36689 break;
36690 default:
36691 break;
36692 }
36693 }
36694 } elseif ('group' == $depType) {
36695 if ($this->isHash($depTypeGroup)) {
36696 $depTypeGroup = array($depTypeGroup);
36697 }
36698
36699 foreach ($depTypeGroup as $depItem) {
36700 $groupName = $depItem['attribs']['name'];
36701 if (!isset($optionals[$groupName])) {
36702 $optionals[$groupName] = array();
36703 }
36704
36705 if (isset($depItem['subpackage'])) {
36706 $optionals[$groupName] += $this->buildDepPackageConstraints($depItem['subpackage'], 'replaces');
36707 } else {
36708 $result += $this->buildDepPackageConstraints($depItem['package'], 'optional');
36709 }
36710 }
36711 }
36712 }
36713
36714 if (count($defaultOptionals) > 0) {
36715 $optionals['*'] = $defaultOptionals;
36716 }
36717
36718 return new DependencyInfo($result, $optionals);
36719 }
36720
36721
36722
36723
36724
36725
36726
36727
36728 private function buildDepExtensionConstraints($depItem, $depType)
36729 {
36730 if ($this->isHash($depItem)) {
36731 $depItem = array($depItem);
36732 }
36733
36734 $result = array();
36735 foreach ($depItem as $subDepItem) {
36736 $depChannelName = 'ext';
36737 $depPackageName = $subDepItem['name'];
36738 $depVersionConstraint = $this->parse20VersionConstraint($subDepItem);
36739
36740 $result[] = new DependencyConstraint(
36741 $depType,
36742 $depVersionConstraint,
36743 $depChannelName,
36744 $depPackageName
36745 );
36746 }
36747
36748 return $result;
36749 }
36750
36751
36752
36753
36754
36755
36756
36757
36758 private function buildDepPackageConstraints($depItem, $depType)
36759 {
36760 if ($this->isHash($depItem)) {
36761 $depItem = array($depItem);
36762 }
36763
36764 $result = array();
36765 foreach ($depItem as $subDepItem) {
36766 if (!array_key_exists('channel', $subDepItem)) {
36767 $subDepItem['channel'] = $subDepItem['uri'];
36768 }
36769 $depChannelName = $subDepItem['channel'];
36770 $depPackageName = $subDepItem['name'];
36771 $depVersionConstraint = $this->parse20VersionConstraint($subDepItem);
36772 if (isset($subDepItem['conflicts'])) {
36773 $depType = 'conflicts';
36774 }
36775
36776 $result[] = new DependencyConstraint(
36777 $depType,
36778 $depVersionConstraint,
36779 $depChannelName,
36780 $depPackageName
36781 );
36782 }
36783
36784 return $result;
36785 }
36786
36787
36788
36789
36790
36791
36792
36793 private function parse20VersionConstraint(array $data)
36794 {
36795 static $dep20toOperatorMap = array('has' => '==', 'min' => '>=', 'max' => '<=', 'exclude' => '!=');
36796
36797 $versions = array();
36798 $values = array_intersect_key($data, $dep20toOperatorMap);
36799 if (0 == count($values)) {
36800 return '*';
36801 }
36802 if (isset($values['min']) && isset($values['exclude']) && $data['min'] == $data['exclude']) {
36803 $versions[] = '>' . $this->parseVersion($values['min']);
36804 } elseif (isset($values['max']) && isset($values['exclude']) && $data['max'] == $data['exclude']) {
36805 $versions[] = '<' . $this->parseVersion($values['max']);
36806 } else {
36807 foreach ($values as $op => $version) {
36808 if ('exclude' == $op && is_array($version)) {
36809 foreach ($version as $versionPart) {
36810 $versions[] = $dep20toOperatorMap[$op] . $this->parseVersion($versionPart);
36811 }
36812 } else {
36813 $versions[] = $dep20toOperatorMap[$op] . $this->parseVersion($version);
36814 }
36815 }
36816 }
36817
36818 return implode(',', $versions);
36819 }
36820
36821
36822
36823
36824
36825
36826
36827 private function parseVersion($version)
36828 {
36829 if (preg_match('{^v?(\d{1,3})(\.\d+)?(\.\d+)?(\.\d+)?}i', $version, $matches)) {
36830 $version = $matches[1]
36831 .(!empty($matches[2]) ? $matches[2] : '.0')
36832 .(!empty($matches[3]) ? $matches[3] : '.0')
36833 .(!empty($matches[4]) ? $matches[4] : '.0');
36834
36835 return $version;
36836 }
36837
36838 return null;
36839 }
36840
36841
36842
36843
36844
36845
36846
36847 private function isHash(array $array)
36848 {
36849 return !array_key_exists(1, $array) && !array_key_exists(0, $array);
36850 }
36851 }
36852 <?php
36853
36854
36855
36856
36857
36858
36859
36860
36861
36862
36863
36864 namespace Composer\Repository\Pear;
36865
36866
36867
36868
36869
36870
36871 class PackageInfo
36872 {
36873 private $channelName;
36874 private $packageName;
36875 private $license;
36876 private $shortDescription;
36877 private $description;
36878 private $releases;
36879
36880
36881
36882
36883
36884
36885
36886
36887
36888 public function __construct($channelName, $packageName, $license, $shortDescription, $description, $releases)
36889 {
36890 $this->channelName = $channelName;
36891 $this->packageName = $packageName;
36892 $this->license = $license;
36893 $this->shortDescription = $shortDescription;
36894 $this->description = $description;
36895 $this->releases = $releases;
36896 }
36897
36898
36899
36900
36901 public function getChannelName()
36902 {
36903 return $this->channelName;
36904 }
36905
36906
36907
36908
36909 public function getPackageName()
36910 {
36911 return $this->packageName;
36912 }
36913
36914
36915
36916
36917 public function getDescription()
36918 {
36919 return $this->description;
36920 }
36921
36922
36923
36924
36925 public function getShortDescription()
36926 {
36927 return $this->shortDescription;
36928 }
36929
36930
36931
36932
36933 public function getLicense()
36934 {
36935 return $this->license;
36936 }
36937
36938
36939
36940
36941 public function getReleases()
36942 {
36943 return $this->releases;
36944 }
36945 }
36946 <?php
36947
36948
36949
36950
36951
36952
36953
36954
36955
36956
36957
36958 namespace Composer\Repository\Pear;
36959
36960
36961
36962
36963
36964
36965 class ReleaseInfo
36966 {
36967 private $stability;
36968 private $dependencyInfo;
36969
36970
36971
36972
36973
36974 public function __construct($stability, $dependencyInfo)
36975 {
36976 $this->stability = $stability;
36977 $this->dependencyInfo = $dependencyInfo;
36978 }
36979
36980
36981
36982
36983 public function getDependencyInfo()
36984 {
36985 return $this->dependencyInfo;
36986 }
36987
36988
36989
36990
36991 public function getStability()
36992 {
36993 return $this->stability;
36994 }
36995 }
36996 <?php
36997
36998
36999
37000
37001
37002
37003
37004
37005
37006
37007
37008 namespace Composer\Repository;
37009
37010 use Composer\IO\IOInterface;
37011 use Composer\Semver\VersionParser as SemverVersionParser;
37012 use Composer\Package\Version\VersionParser;
37013 use Composer\Repository\Pear\ChannelReader;
37014 use Composer\Package\CompletePackage;
37015 use Composer\Repository\Pear\ChannelInfo;
37016 use Composer\EventDispatcher\EventDispatcher;
37017 use Composer\Package\Link;
37018 use Composer\Semver\Constraint\Constraint;
37019 use Composer\Util\RemoteFilesystem;
37020 use Composer\Config;
37021 use Composer\Factory;
37022
37023
37024
37025
37026
37027
37028
37029
37030
37031
37032 class PearRepository extends ArrayRepository implements ConfigurableRepositoryInterface
37033 {
37034 private $url;
37035 private $io;
37036 private $rfs;
37037 private $versionParser;
37038 private $repoConfig;
37039
37040
37041
37042
37043 private $vendorAlias;
37044
37045 public function __construct(array $repoConfig, IOInterface $io, Config $config, EventDispatcher $dispatcher = null, RemoteFilesystem $rfs = null)
37046 {
37047 parent::__construct();
37048 if (!preg_match('{^https?://}', $repoConfig['url'])) {
37049 $repoConfig['url'] = 'http://'.$repoConfig['url'];
37050 }
37051
37052 $urlBits = parse_url($repoConfig['url']);
37053 if (empty($urlBits['scheme']) || empty($urlBits['host'])) {
37054 throw new \UnexpectedValueException('Invalid url given for PEAR repository: '.$repoConfig['url']);
37055 }
37056
37057 $this->url = rtrim($repoConfig['url'], '/');
37058 $this->io = $io;
37059 $this->rfs = $rfs ?: Factory::createRemoteFilesystem($this->io, $config);
37060 $this->vendorAlias = isset($repoConfig['vendor-alias']) ? $repoConfig['vendor-alias'] : null;
37061 $this->versionParser = new VersionParser();
37062 $this->repoConfig = $repoConfig;
37063 }
37064
37065 public function getRepoConfig()
37066 {
37067 return $this->repoConfig;
37068 }
37069
37070 protected function initialize()
37071 {
37072 parent::initialize();
37073
37074 $this->io->writeError('Initializing PEAR repository '.$this->url);
37075
37076 $reader = new ChannelReader($this->rfs);
37077 try {
37078 $channelInfo = $reader->read($this->url);
37079 } catch (\Exception $e) {
37080 $this->io->writeError('<warning>PEAR repository from '.$this->url.' could not be loaded. '.$e->getMessage().'</warning>');
37081
37082 return;
37083 }
37084 $packages = $this->buildComposerPackages($channelInfo, $this->versionParser);
37085 foreach ($packages as $package) {
37086 $this->addPackage($package);
37087 }
37088 }
37089
37090
37091
37092
37093
37094
37095
37096
37097 private function buildComposerPackages(ChannelInfo $channelInfo, SemverVersionParser $versionParser)
37098 {
37099 $result = array();
37100 foreach ($channelInfo->getPackages() as $packageDefinition) {
37101 foreach ($packageDefinition->getReleases() as $version => $releaseInfo) {
37102 try {
37103 $normalizedVersion = $versionParser->normalize($version);
37104 } catch (\UnexpectedValueException $e) {
37105 $this->io->writeError('Could not load '.$packageDefinition->getPackageName().' '.$version.': '.$e->getMessage(), true, IOInterface::VERBOSE);
37106 continue;
37107 }
37108
37109 $composerPackageName = $this->buildComposerPackageName($packageDefinition->getChannelName(), $packageDefinition->getPackageName());
37110
37111
37112
37113 $urlBits = parse_url($this->url);
37114 $scheme = (isset($urlBits['scheme']) && 'https' === $urlBits['scheme'] && extension_loaded('openssl')) ? 'https' : 'http';
37115 $distUrl = "{$scheme}://{$packageDefinition->getChannelName()}/get/{$packageDefinition->getPackageName()}-{$version}.tgz";
37116
37117 $requires = array();
37118 $suggests = array();
37119 $conflicts = array();
37120 $replaces = array();
37121
37122
37123
37124 if ($channelInfo->getName() == $packageDefinition->getChannelName()) {
37125 $composerPackageAlias = $this->buildComposerPackageName($channelInfo->getAlias(), $packageDefinition->getPackageName());
37126 $aliasConstraint = new Constraint('==', $normalizedVersion);
37127 $replaces[] = new Link($composerPackageName, $composerPackageAlias, $aliasConstraint, 'replaces', (string) $aliasConstraint);
37128 }
37129
37130
37131 if (!empty($this->vendorAlias)
37132 && ($this->vendorAlias != 'pear-'.$channelInfo->getAlias() || $channelInfo->getName() != $packageDefinition->getChannelName())
37133 ) {
37134 $composerPackageAlias = "{$this->vendorAlias}/{$packageDefinition->getPackageName()}";
37135 $aliasConstraint = new Constraint('==', $normalizedVersion);
37136 $replaces[] = new Link($composerPackageName, $composerPackageAlias, $aliasConstraint, 'replaces', (string) $aliasConstraint);
37137 }
37138
37139 foreach ($releaseInfo->getDependencyInfo()->getRequires() as $dependencyConstraint) {
37140 $dependencyPackageName = $this->buildComposerPackageName($dependencyConstraint->getChannelName(), $dependencyConstraint->getPackageName());
37141 $constraint = $versionParser->parseConstraints($dependencyConstraint->getConstraint());
37142 $link = new Link($composerPackageName, $dependencyPackageName, $constraint, $dependencyConstraint->getType(), $dependencyConstraint->getConstraint());
37143 switch ($dependencyConstraint->getType()) {
37144 case 'required':
37145 $requires[] = $link;
37146 break;
37147 case 'conflicts':
37148 $conflicts[] = $link;
37149 break;
37150 case 'replaces':
37151 $replaces[] = $link;
37152 break;
37153 }
37154 }
37155
37156 foreach ($releaseInfo->getDependencyInfo()->getOptionals() as $group => $dependencyConstraints) {
37157 foreach ($dependencyConstraints as $dependencyConstraint) {
37158 $dependencyPackageName = $this->buildComposerPackageName($dependencyConstraint->getChannelName(), $dependencyConstraint->getPackageName());
37159 $suggests[$group.'-'.$dependencyPackageName] = $dependencyConstraint->getConstraint();
37160 }
37161 }
37162
37163 $package = new CompletePackage($composerPackageName, $normalizedVersion, $version);
37164 $package->setType('pear-library');
37165 $package->setDescription($packageDefinition->getDescription());
37166 $package->setLicense(array($packageDefinition->getLicense()));
37167 $package->setDistType('file');
37168 $package->setDistUrl($distUrl);
37169 $package->setAutoload(array('classmap' => array('')));
37170 $package->setIncludePaths(array('/'));
37171 $package->setRequires($requires);
37172 $package->setConflicts($conflicts);
37173 $package->setSuggests($suggests);
37174 $package->setReplaces($replaces);
37175 $result[] = $package;
37176 }
37177 }
37178
37179 return $result;
37180 }
37181
37182 private function buildComposerPackageName($channelName, $packageName)
37183 {
37184 if ('php' === $channelName) {
37185 return "php";
37186 }
37187 if ('ext' === $channelName) {
37188 return "ext-{$packageName}";
37189 }
37190
37191 return "pear-{$channelName}/{$packageName}";
37192 }
37193 }
37194 <?php
37195
37196
37197
37198
37199
37200
37201
37202
37203
37204
37205
37206 namespace Composer\Repository;
37207
37208 use Composer\Composer;
37209 use Composer\Package\CompletePackage;
37210 use Composer\Package\PackageInterface;
37211 use Composer\Package\Version\VersionParser;
37212 use Composer\Plugin\PluginInterface;
37213 use Composer\Util\ProcessExecutor;
37214 use Composer\Util\Silencer;
37215 use Composer\Util\Platform;
37216 use Composer\XdebugHandler\XdebugHandler;
37217 use Symfony\Component\Process\ExecutableFinder;
37218
37219
37220
37221
37222 class PlatformRepository extends ArrayRepository
37223 {
37224 const PLATFORM_PACKAGE_REGEX = '{^(?:php(?:-64bit|-ipv6|-zts|-debug)?|hhvm|(?:ext|lib)-[a-z0-9](?:[_.-]?[a-z0-9]+)*|composer-(?:plugin|runtime)-api)$}iD';
37225
37226 private $versionParser;
37227
37228
37229
37230
37231
37232
37233
37234
37235 private $overrides = array();
37236
37237 private $process;
37238
37239 public function __construct(array $packages = array(), array $overrides = array(), ProcessExecutor $process = null)
37240 {
37241 $this->process = $process === null ? (new ProcessExecutor()) : $process;
37242 foreach ($overrides as $name => $version) {
37243 $this->overrides[strtolower($name)] = array('name' => $name, 'version' => $version);
37244 }
37245 parent::__construct($packages);
37246 }
37247
37248 protected function initialize()
37249 {
37250 parent::initialize();
37251
37252 $this->versionParser = new VersionParser();
37253
37254
37255
37256 foreach ($this->overrides as $override) {
37257
37258 if (!preg_match(self::PLATFORM_PACKAGE_REGEX, $override['name'])) {
37259 throw new \InvalidArgumentException('Invalid platform package name in config.platform: '.$override['name']);
37260 }
37261
37262 $this->addOverriddenPackage($override);
37263 }
37264
37265 $prettyVersion = PluginInterface::PLUGIN_API_VERSION;
37266 $version = $this->versionParser->normalize($prettyVersion);
37267 $composerPluginApi = new CompletePackage('composer-plugin-api', $version, $prettyVersion);
37268 $composerPluginApi->setDescription('The Composer Plugin API');
37269 $this->addPackage($composerPluginApi);
37270
37271 $prettyVersion = Composer::RUNTIME_API_VERSION;
37272 $version = $this->versionParser->normalize($prettyVersion);
37273 $composerRuntimeApi = new CompletePackage('composer-runtime-api', $version, $prettyVersion);
37274 $composerRuntimeApi->setDescription('The Composer Runtime API');
37275 $this->addPackage($composerRuntimeApi);
37276
37277 try {
37278 $prettyVersion = PHP_VERSION;
37279 $version = $this->versionParser->normalize($prettyVersion);
37280 } catch (\UnexpectedValueException $e) {
37281 $prettyVersion = preg_replace('#^([^~+-]+).*$#', '$1', PHP_VERSION);
37282 $version = $this->versionParser->normalize($prettyVersion);
37283 }
37284
37285 $php = new CompletePackage('php', $version, $prettyVersion);
37286 $php->setDescription('The PHP interpreter');
37287 $this->addPackage($php);
37288
37289 if (PHP_DEBUG) {
37290 $phpdebug = new CompletePackage('php-debug', $version, $prettyVersion);
37291 $phpdebug->setDescription('The PHP interpreter, with debugging symbols');
37292 $this->addPackage($phpdebug);
37293 }
37294
37295 if (defined('PHP_ZTS') && PHP_ZTS) {
37296 $phpzts = new CompletePackage('php-zts', $version, $prettyVersion);
37297 $phpzts->setDescription('The PHP interpreter, with Zend Thread Safety');
37298 $this->addPackage($phpzts);
37299 }
37300
37301 if (PHP_INT_SIZE === 8) {
37302 $php64 = new CompletePackage('php-64bit', $version, $prettyVersion);
37303 $php64->setDescription('The PHP interpreter, 64bit');
37304 $this->addPackage($php64);
37305 }
37306
37307
37308
37309 if (defined('AF_INET6') || Silencer::call('inet_pton', '::') !== false) {
37310 $phpIpv6 = new CompletePackage('php-ipv6', $version, $prettyVersion);
37311 $phpIpv6->setDescription('The PHP interpreter, with IPv6 support');
37312 $this->addPackage($phpIpv6);
37313 }
37314
37315 $loadedExtensions = get_loaded_extensions();
37316
37317
37318 foreach ($loadedExtensions as $name) {
37319 if (in_array($name, array('standard', 'Core'))) {
37320 continue;
37321 }
37322
37323 $reflExt = new \ReflectionExtension($name);
37324 $prettyVersion = $reflExt->getVersion();
37325 $this->addExtension($name, $prettyVersion);
37326 }
37327
37328
37329 if (!in_array('xdebug', $loadedExtensions, true) && ($prettyVersion = XdebugHandler::getSkippedVersion())) {
37330 $this->addExtension('xdebug', $prettyVersion);
37331 }
37332
37333
37334
37335
37336 foreach ($loadedExtensions as $name) {
37337 $prettyVersion = null;
37338 $description = 'The '.$name.' PHP library';
37339 switch ($name) {
37340 case 'curl':
37341 $curlVersion = curl_version();
37342 $prettyVersion = $curlVersion['version'];
37343 break;
37344
37345 case 'iconv':
37346 $prettyVersion = ICONV_VERSION;
37347 break;
37348
37349 case 'intl':
37350 $name = 'ICU';
37351 if (defined('INTL_ICU_VERSION')) {
37352 $prettyVersion = INTL_ICU_VERSION;
37353 } else {
37354 $reflector = new \ReflectionExtension('intl');
37355
37356 ob_start();
37357 $reflector->info();
37358 $output = ob_get_clean();
37359
37360 preg_match('/^ICU version => (.*)$/m', $output, $matches);
37361 $prettyVersion = $matches[1];
37362 }
37363
37364 break;
37365
37366 case 'imagick':
37367 $imagick = new \Imagick();
37368 $imageMagickVersion = $imagick->getVersion();
37369
37370
37371 preg_match('/^ImageMagick ([\d.]+)(?:-(\d+))?/', $imageMagickVersion['versionString'], $matches);
37372 if (isset($matches[2])) {
37373 $prettyVersion = "{$matches[1]}.{$matches[2]}";
37374 } else {
37375 $prettyVersion = $matches[1];
37376 }
37377 break;
37378
37379 case 'libxml':
37380 $prettyVersion = LIBXML_DOTTED_VERSION;
37381 break;
37382
37383 case 'openssl':
37384 $prettyVersion = preg_replace_callback('{^(?:OpenSSL|LibreSSL)?\s*([0-9.]+)([a-z]*).*}i', function ($match) {
37385 if (empty($match[2])) {
37386 return $match[1];
37387 }
37388
37389
37390
37391
37392 if (!preg_match('{^z*[a-z]$}', $match[2])) {
37393
37394 return 0;
37395 }
37396
37397 $len = strlen($match[2]);
37398 $patchVersion = ($len - 1) * 26; 
37399 $patchVersion += ord($match[2][$len - 1]) - 96;
37400
37401 return $match[1].'.'.$patchVersion;
37402 }, OPENSSL_VERSION_TEXT);
37403
37404 $description = OPENSSL_VERSION_TEXT;
37405 break;
37406
37407 case 'pcre':
37408 $prettyVersion = preg_replace('{^(\S+).*}', '$1', PCRE_VERSION);
37409 break;
37410
37411 case 'uuid':
37412 $prettyVersion = phpversion('uuid');
37413 break;
37414
37415 case 'xsl':
37416 $prettyVersion = LIBXSLT_DOTTED_VERSION;
37417 break;
37418
37419 default:
37420
37421 continue 2;
37422 }
37423
37424 try {
37425 $version = $this->versionParser->normalize($prettyVersion);
37426 } catch (\UnexpectedValueException $e) {
37427 continue;
37428 }
37429
37430 $lib = new CompletePackage('lib-'.$name, $version, $prettyVersion);
37431 $lib->setDescription($description);
37432 $this->addPackage($lib);
37433 }
37434
37435 $hhvmVersion = defined('HHVM_VERSION') ? HHVM_VERSION : null;
37436 if ($hhvmVersion === null && !Platform::isWindows()) {
37437 $finder = new ExecutableFinder();
37438 $hhvm = $finder->find('hhvm');
37439 if ($hhvm !== null) {
37440 $exitCode = $this->process->execute(
37441 ProcessExecutor::escape($hhvm).
37442 ' --php -d hhvm.jit=0 -r "echo HHVM_VERSION;" 2>/dev/null',
37443 $hhvmVersion
37444 );
37445 if ($exitCode !== 0) {
37446 $hhvmVersion = null;
37447 }
37448 }
37449 }
37450 if ($hhvmVersion) {
37451 try {
37452 $prettyVersion = $hhvmVersion;
37453 $version = $this->versionParser->normalize($prettyVersion);
37454 } catch (\UnexpectedValueException $e) {
37455 $prettyVersion = preg_replace('#^([^~+-]+).*$#', '$1', $hhvmVersion);
37456 $version = $this->versionParser->normalize($prettyVersion);
37457 }
37458
37459 $hhvm = new CompletePackage('hhvm', $version, $prettyVersion);
37460 $hhvm->setDescription('The HHVM Runtime (64bit)');
37461 $this->addPackage($hhvm);
37462 }
37463 }
37464
37465
37466
37467
37468 public function addPackage(PackageInterface $package)
37469 {
37470
37471 if (isset($this->overrides[$package->getName()])) {
37472 $overrider = $this->findPackage($package->getName(), '*');
37473 if ($package->getVersion() === $overrider->getVersion()) {
37474 $actualText = 'same as actual';
37475 } else {
37476 $actualText = 'actual: '.$package->getPrettyVersion();
37477 }
37478 $overrider->setDescription($overrider->getDescription().' ('.$actualText.')');
37479
37480 return;
37481 }
37482
37483
37484 if (isset($this->overrides['php']) && 0 === strpos($package->getName(), 'php-')) {
37485 $overrider = $this->addOverriddenPackage($this->overrides['php'], $package->getPrettyName());
37486 if ($package->getVersion() === $overrider->getVersion()) {
37487 $actualText = 'same as actual';
37488 } else {
37489 $actualText = 'actual: '.$package->getPrettyVersion();
37490 }
37491 $overrider->setDescription($overrider->getDescription().' ('.$actualText.')');
37492
37493 return;
37494 }
37495
37496 parent::addPackage($package);
37497 }
37498
37499 private function addOverriddenPackage(array $override, $name = null)
37500 {
37501 $version = $this->versionParser->normalize($override['version']);
37502 $package = new CompletePackage($name ?: $override['name'], $version, $override['version']);
37503 $package->setDescription('Package overridden via config.platform');
37504 $package->setExtra(array('config.platform' => true));
37505 parent::addPackage($package);
37506
37507 return $package;
37508 }
37509
37510
37511
37512
37513
37514
37515
37516 private function addExtension($name, $prettyVersion)
37517 {
37518 $extraDescription = null;
37519
37520 try {
37521 $version = $this->versionParser->normalize($prettyVersion);
37522 } catch (\UnexpectedValueException $e) {
37523 $extraDescription = ' (actual version: '.$prettyVersion.')';
37524 if (preg_match('{^(\d+\.\d+\.\d+(?:\.\d+)?)}', $prettyVersion, $match)) {
37525 $prettyVersion = $match[1];
37526 } else {
37527 $prettyVersion = '0';
37528 }
37529 $version = $this->versionParser->normalize($prettyVersion);
37530 }
37531
37532 $packageName = $this->buildPackageName($name);
37533 $ext = new CompletePackage($packageName, $version, $prettyVersion);
37534 $ext->setDescription('The '.$name.' PHP extension'.$extraDescription);
37535 $this->addPackage($ext);
37536 }
37537
37538 private function buildPackageName($name)
37539 {
37540 return 'ext-' . str_replace(' ', '-', $name);
37541 }
37542 }
37543 <?php
37544
37545
37546
37547
37548
37549
37550
37551
37552
37553
37554
37555 namespace Composer\Repository;
37556
37557 use Composer\Factory;
37558 use Composer\IO\IOInterface;
37559 use Composer\Config;
37560 use Composer\EventDispatcher\EventDispatcher;
37561 use Composer\Util\RemoteFilesystem;
37562 use Composer\Json\JsonFile;
37563
37564
37565
37566
37567 class RepositoryFactory
37568 {
37569
37570
37571
37572
37573
37574
37575
37576 public static function configFromString(IOInterface $io, Config $config, $repository, $allowFilesystem = false)
37577 {
37578 if (0 === strpos($repository, 'http')) {
37579 $repoConfig = array('type' => 'composer', 'url' => $repository);
37580 } elseif ("json" === pathinfo($repository, PATHINFO_EXTENSION)) {
37581 $json = new JsonFile($repository, Factory::createRemoteFilesystem($io, $config));
37582 $data = $json->read();
37583 if (!empty($data['packages']) || !empty($data['includes']) || !empty($data['provider-includes'])) {
37584 $repoConfig = array('type' => 'composer', 'url' => 'file://' . strtr(realpath($repository), '\\', '/'));
37585 } elseif ($allowFilesystem) {
37586 $repoConfig = array('type' => 'filesystem', 'json' => $json);
37587 } else {
37588 throw new \InvalidArgumentException("Invalid repository URL ($repository) given. This file does not contain a valid composer repository.");
37589 }
37590 } elseif ('{' === substr($repository, 0, 1)) {
37591
37592 $repoConfig = JsonFile::parseJson($repository);
37593 } else {
37594 throw new \InvalidArgumentException("Invalid repository url ($repository) given. Has to be a .json file, an http url or a JSON object.");
37595 }
37596
37597 return $repoConfig;
37598 }
37599
37600
37601
37602
37603
37604
37605
37606
37607 public static function fromString(IOInterface $io, Config $config, $repository, $allowFilesystem = false, RepositoryManager $rm = null)
37608 {
37609 $repoConfig = static::configFromString($io, $config, $repository, $allowFilesystem);
37610
37611 return static::createRepo($io, $config, $repoConfig, $rm);
37612 }
37613
37614
37615
37616
37617
37618
37619
37620 public static function createRepo(IOInterface $io, Config $config, array $repoConfig, RepositoryManager $rm = null)
37621 {
37622 if (!$rm) {
37623 $rm = static::manager($io, $config, null, Factory::createRemoteFilesystem($io, $config));
37624 }
37625 $repos = static::createRepos($rm, array($repoConfig));
37626
37627 return reset($repos);
37628 }
37629
37630
37631
37632
37633
37634
37635
37636 public static function defaultRepos(IOInterface $io = null, Config $config = null, RepositoryManager $rm = null)
37637 {
37638 if (!$config) {
37639 $config = Factory::createConfig($io);
37640 }
37641 if ($io) {
37642 $io->loadConfiguration($config);
37643 }
37644 if (!$rm) {
37645 if (!$io) {
37646 throw new \InvalidArgumentException('This function requires either an IOInterface or a RepositoryManager');
37647 }
37648 $rm = static::manager($io, $config, null, Factory::createRemoteFilesystem($io, $config));
37649 }
37650
37651 return static::createRepos($rm, $config->getRepositories());
37652 }
37653
37654
37655
37656
37657
37658
37659
37660
37661 public static function manager(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, RemoteFilesystem $rfs = null)
37662 {
37663 $rm = new RepositoryManager($io, $config, $eventDispatcher, $rfs);
37664 $rm->setRepositoryClass('composer', 'Composer\Repository\ComposerRepository');
37665 $rm->setRepositoryClass('vcs', 'Composer\Repository\VcsRepository');
37666 $rm->setRepositoryClass('package', 'Composer\Repository\PackageRepository');
37667 $rm->setRepositoryClass('pear', 'Composer\Repository\PearRepository');
37668 $rm->setRepositoryClass('git', 'Composer\Repository\VcsRepository');
37669 $rm->setRepositoryClass('git-bitbucket', 'Composer\Repository\VcsRepository');
37670 $rm->setRepositoryClass('github', 'Composer\Repository\VcsRepository');
37671 $rm->setRepositoryClass('gitlab', 'Composer\Repository\VcsRepository');
37672 $rm->setRepositoryClass('svn', 'Composer\Repository\VcsRepository');
37673 $rm->setRepositoryClass('fossil', 'Composer\Repository\VcsRepository');
37674 $rm->setRepositoryClass('perforce', 'Composer\Repository\VcsRepository');
37675 $rm->setRepositoryClass('hg', 'Composer\Repository\VcsRepository');
37676 $rm->setRepositoryClass('hg-bitbucket', 'Composer\Repository\VcsRepository');
37677 $rm->setRepositoryClass('artifact', 'Composer\Repository\ArtifactRepository');
37678 $rm->setRepositoryClass('path', 'Composer\Repository\PathRepository');
37679
37680 return $rm;
37681 }
37682
37683
37684
37685
37686 private static function createRepos(RepositoryManager $rm, array $repoConfigs)
37687 {
37688 $repos = array();
37689
37690 foreach ($repoConfigs as $index => $repo) {
37691 if (is_string($repo)) {
37692 throw new \UnexpectedValueException('"repositories" should be an array of repository definitions, only a single repository was given');
37693 }
37694 if (!is_array($repo)) {
37695 throw new \UnexpectedValueException('Repository "'.$index.'" ('.json_encode($repo).') should be an array, '.gettype($repo).' given');
37696 }
37697 if (!isset($repo['type'])) {
37698 throw new \UnexpectedValueException('Repository "'.$index.'" ('.json_encode($repo).') must have a type defined');
37699 }
37700
37701 $name = self::generateRepositoryName($index, $repo, $repos);
37702 if ($repo['type'] === 'filesystem') {
37703 $repos[$name] = new FilesystemRepository($repo['json']);
37704 } else {
37705 $repos[$name] = $rm->createRepository($repo['type'], $repo, $index);
37706 }
37707 }
37708
37709 return $repos;
37710 }
37711
37712 public static function generateRepositoryName($index, array $repo, array $existingRepos)
37713 {
37714 $name = is_int($index) && isset($repo['url']) ? preg_replace('{^https?://}i', '', $repo['url']) : $index;
37715 while (isset($existingRepos[$name])) {
37716 $name .= '2';
37717 }
37718
37719 return $name;
37720 }
37721 }
37722 <?php
37723
37724
37725
37726
37727
37728
37729
37730
37731
37732
37733
37734 namespace Composer\Repository;
37735
37736 use Composer\Package\PackageInterface;
37737
37738
37739
37740
37741
37742
37743
37744
37745 interface RepositoryInterface extends \Countable
37746 {
37747 const SEARCH_FULLTEXT = 0;
37748 const SEARCH_NAME = 1;
37749
37750
37751
37752
37753
37754
37755
37756
37757 public function hasPackage(PackageInterface $package);
37758
37759
37760
37761
37762
37763
37764
37765
37766
37767 public function findPackage($name, $constraint);
37768
37769
37770
37771
37772
37773
37774
37775
37776
37777 public function findPackages($name, $constraint = null);
37778
37779
37780
37781
37782
37783
37784 public function getPackages();
37785
37786
37787
37788
37789
37790
37791
37792
37793
37794 public function search($query, $mode = 0);
37795 }
37796 <?php
37797
37798
37799
37800
37801
37802
37803
37804
37805
37806
37807
37808 namespace Composer\Repository;
37809
37810 use Composer\IO\IOInterface;
37811 use Composer\Config;
37812 use Composer\EventDispatcher\EventDispatcher;
37813 use Composer\Package\PackageInterface;
37814 use Composer\Util\RemoteFilesystem;
37815
37816
37817
37818
37819
37820
37821
37822
37823 class RepositoryManager
37824 {
37825 private $localRepository;
37826 private $repositories = array();
37827 private $repositoryClasses = array();
37828 private $io;
37829 private $config;
37830 private $eventDispatcher;
37831 private $rfs;
37832
37833 public function __construct(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, RemoteFilesystem $rfs = null)
37834 {
37835 $this->io = $io;
37836 $this->config = $config;
37837 $this->eventDispatcher = $eventDispatcher;
37838 $this->rfs = $rfs;
37839 }
37840
37841
37842
37843
37844
37845
37846
37847
37848
37849 public function findPackage($name, $constraint)
37850 {
37851 foreach ($this->repositories as $repository) {
37852
37853 if ($package = $repository->findPackage($name, $constraint)) {
37854 return $package;
37855 }
37856 }
37857
37858 return null;
37859 }
37860
37861
37862
37863
37864
37865
37866
37867
37868
37869 public function findPackages($name, $constraint)
37870 {
37871 $packages = array();
37872
37873 foreach ($this->getRepositories() as $repository) {
37874 $packages = array_merge($packages, $repository->findPackages($name, $constraint));
37875 }
37876
37877 return $packages;
37878 }
37879
37880
37881
37882
37883
37884
37885 public function addRepository(RepositoryInterface $repository)
37886 {
37887 $this->repositories[] = $repository;
37888 }
37889
37890
37891
37892
37893
37894
37895
37896
37897 public function prependRepository(RepositoryInterface $repository)
37898 {
37899 array_unshift($this->repositories, $repository);
37900 }
37901
37902
37903
37904
37905
37906
37907
37908
37909
37910
37911 public function createRepository($type, $config, $name = null)
37912 {
37913 if (!isset($this->repositoryClasses[$type])) {
37914 throw new \InvalidArgumentException('Repository type is not registered: '.$type);
37915 }
37916
37917 if (isset($config['packagist']) && false === $config['packagist']) {
37918 $this->io->writeError('<warning>Repository "'.$name.'" ('.json_encode($config).') has a packagist key which should be in its own repository definition</warning>');
37919 }
37920
37921 $class = $this->repositoryClasses[$type];
37922
37923 $reflMethod = new \ReflectionMethod($class, '__construct');
37924 $params = $reflMethod->getParameters();
37925 if (isset($params[4])) {
37926 $paramType = null;
37927 if (\PHP_VERSION_ID >= 70000) {
37928 $reflectionType = $params[4]->getType();
37929 if ($reflectionType) {
37930 $paramType = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : (string)$reflectionType;
37931 }
37932 } else {
37933 $paramType = $params[4]->getClass() ? $params[4]->getClass()->getName() : null;
37934 }
37935
37936 if ($paramType === 'Composer\Util\RemoteFilesystem') {
37937 return new $class($config, $this->io, $this->config, $this->eventDispatcher, $this->rfs);
37938 }
37939 }
37940
37941 return new $class($config, $this->io, $this->config, $this->eventDispatcher);
37942 }
37943
37944
37945
37946
37947
37948
37949
37950 public function setRepositoryClass($type, $class)
37951 {
37952 $this->repositoryClasses[$type] = $class;
37953 }
37954
37955
37956
37957
37958
37959
37960 public function getRepositories()
37961 {
37962 return $this->repositories;
37963 }
37964
37965
37966
37967
37968
37969
37970 public function setLocalRepository(WritableRepositoryInterface $repository)
37971 {
37972 $this->localRepository = $repository;
37973 }
37974
37975
37976
37977
37978
37979
37980 public function getLocalRepository()
37981 {
37982 return $this->localRepository;
37983 }
37984 }
37985 <?php
37986
37987
37988
37989
37990
37991
37992
37993
37994
37995
37996
37997 namespace Composer\Repository;
37998
37999
38000
38001
38002
38003
38004 class RepositorySecurityException extends \Exception
38005 {
38006 }
38007 <?php
38008
38009
38010
38011
38012
38013
38014
38015
38016
38017
38018
38019 namespace Composer\Repository\Vcs;
38020
38021 use Composer\Cache;
38022 use Composer\Downloader\TransportException;
38023 use Composer\Json\JsonFile;
38024 use Composer\Util\Bitbucket;
38025
38026 abstract class BitbucketDriver extends VcsDriver
38027 {
38028
38029 protected $cache;
38030 protected $owner;
38031 protected $repository;
38032 protected $hasIssues;
38033 protected $rootIdentifier;
38034 protected $tags;
38035 protected $branches;
38036 protected $infoCache = array();
38037 protected $branchesUrl = '';
38038 protected $tagsUrl = '';
38039 protected $homeUrl = '';
38040 protected $website = '';
38041 protected $cloneHttpsUrl = '';
38042
38043
38044
38045
38046 protected $fallbackDriver;
38047
38048 protected $vcsType;
38049
38050
38051
38052
38053 public function initialize()
38054 {
38055 preg_match('#^https?://bitbucket\.org/([^/]+)/([^/]+?)(\.git|/?)$#i', $this->url, $match);
38056 $this->owner = $match[1];
38057 $this->repository = $match[2];
38058 $this->originUrl = 'bitbucket.org';
38059 $this->cache = new Cache(
38060 $this->io,
38061 implode('/', array(
38062 $this->config->get('cache-repo-dir'),
38063 $this->originUrl,
38064 $this->owner,
38065 $this->repository,
38066 ))
38067 );
38068 }
38069
38070
38071
38072
38073 public function getUrl()
38074 {
38075 if ($this->fallbackDriver) {
38076 return $this->fallbackDriver->getUrl();
38077 }
38078
38079 return $this->cloneHttpsUrl;
38080 }
38081
38082
38083
38084
38085
38086
38087
38088 protected function getRepoData()
38089 {
38090 $resource = sprintf(
38091 'https://api.bitbucket.org/2.0/repositories/%s/%s?%s',
38092 $this->owner,
38093 $this->repository,
38094 http_build_query(
38095 array('fields' => '-project,-owner'),
38096 null,
38097 '&'
38098 )
38099 );
38100
38101 $repoData = JsonFile::parseJson($this->getContentsWithOAuthCredentials($resource, true), $resource);
38102 if ($this->fallbackDriver) {
38103 return false;
38104 }
38105 $this->parseCloneUrls($repoData['links']['clone']);
38106
38107 $this->hasIssues = !empty($repoData['has_issues']);
38108 $this->branchesUrl = $repoData['links']['branches']['href'];
38109 $this->tagsUrl = $repoData['links']['tags']['href'];
38110 $this->homeUrl = $repoData['links']['html']['href'];
38111 $this->website = $repoData['website'];
38112 $this->vcsType = $repoData['scm'];
38113
38114 return true;
38115 }
38116
38117
38118
38119
38120 public function getComposerInformation($identifier)
38121 {
38122 if ($this->fallbackDriver) {
38123 return $this->fallbackDriver->getComposerInformation($identifier);
38124 }
38125
38126 if (!isset($this->infoCache[$identifier])) {
38127 if ($this->shouldCache($identifier) && $res = $this->cache->read($identifier)) {
38128 $composer = JsonFile::parseJson($res);
38129 } else {
38130 $composer = $this->getBaseComposerInformation($identifier);
38131
38132 if ($this->shouldCache($identifier)) {
38133 $this->cache->write($identifier, json_encode($composer));
38134 }
38135 }
38136
38137 if ($composer) {
38138
38139 if (!isset($composer['support']['source'])) {
38140 $label = array_search(
38141 $identifier,
38142 $this->getTags()
38143 ) ?: array_search(
38144 $identifier,
38145 $this->getBranches()
38146 ) ?: $identifier;
38147
38148 if (array_key_exists($label, $tags = $this->getTags())) {
38149 $hash = $tags[$label];
38150 } elseif (array_key_exists($label, $branches = $this->getBranches())) {
38151 $hash = $branches[$label];
38152 }
38153
38154 if (! isset($hash)) {
38155 $composer['support']['source'] = sprintf(
38156 'https://%s/%s/%s/src',
38157 $this->originUrl,
38158 $this->owner,
38159 $this->repository
38160 );
38161 } else {
38162 $composer['support']['source'] = sprintf(
38163 'https://%s/%s/%s/src/%s/?at=%s',
38164 $this->originUrl,
38165 $this->owner,
38166 $this->repository,
38167 $hash,
38168 $label
38169 );
38170 }
38171 }
38172 if (!isset($composer['support']['issues']) && $this->hasIssues) {
38173 $composer['support']['issues'] = sprintf(
38174 'https://%s/%s/%s/issues',
38175 $this->originUrl,
38176 $this->owner,
38177 $this->repository
38178 );
38179 }
38180 if (!isset($composer['homepage'])) {
38181 $composer['homepage'] = empty($this->website) ? $this->homeUrl : $this->website;
38182 }
38183 }
38184
38185 $this->infoCache[$identifier] = $composer;
38186 }
38187
38188 return $this->infoCache[$identifier];
38189 }
38190
38191
38192
38193
38194 public function getFileContent($file, $identifier)
38195 {
38196 if ($this->fallbackDriver) {
38197 return $this->fallbackDriver->getFileContent($file, $identifier);
38198 }
38199
38200 if (strpos($identifier, '/') !== false) {
38201 $branches = $this->getBranches();
38202 if (isset($branches[$identifier])) {
38203 $identifier = $branches[$identifier];
38204 }
38205 }
38206
38207 $resource = sprintf(
38208 'https://api.bitbucket.org/2.0/repositories/%s/%s/src/%s/%s',
38209 $this->owner,
38210 $this->repository,
38211 $identifier,
38212 $file
38213 );
38214
38215 return $this->getContentsWithOAuthCredentials($resource);
38216 }
38217
38218
38219
38220
38221 public function getChangeDate($identifier)
38222 {
38223 if ($this->fallbackDriver) {
38224 return $this->fallbackDriver->getChangeDate($identifier);
38225 }
38226
38227 if (strpos($identifier, '/') !== false) {
38228 $branches = $this->getBranches();
38229 if (isset($branches[$identifier])) {
38230 $identifier = $branches[$identifier];
38231 }
38232 }
38233
38234 $resource = sprintf(
38235 'https://api.bitbucket.org/2.0/repositories/%s/%s/commit/%s?fields=date',
38236 $this->owner,
38237 $this->repository,
38238 $identifier
38239 );
38240 $commit = JsonFile::parseJson($this->getContentsWithOAuthCredentials($resource), $resource);
38241
38242 return new \DateTime($commit['date']);
38243 }
38244
38245
38246
38247
38248 public function getSource($identifier)
38249 {
38250 if ($this->fallbackDriver) {
38251 return $this->fallbackDriver->getSource($identifier);
38252 }
38253
38254 return array('type' => $this->vcsType, 'url' => $this->getUrl(), 'reference' => $identifier);
38255 }
38256
38257
38258
38259
38260 public function getDist($identifier)
38261 {
38262 if ($this->fallbackDriver) {
38263 return $this->fallbackDriver->getDist($identifier);
38264 }
38265
38266 $url = sprintf(
38267 'https://bitbucket.org/%s/%s/get/%s.zip',
38268 $this->owner,
38269 $this->repository,
38270 $identifier
38271 );
38272
38273 return array('type' => 'zip', 'url' => $url, 'reference' => $identifier, 'shasum' => '');
38274 }
38275
38276
38277
38278
38279 public function getTags()
38280 {
38281 if ($this->fallbackDriver) {
38282 return $this->fallbackDriver->getTags();
38283 }
38284
38285 if (null === $this->tags) {
38286 $this->tags = array();
38287 $resource = sprintf(
38288 '%s?%s',
38289 $this->tagsUrl,
38290 http_build_query(
38291 array(
38292 'pagelen' => 100,
38293 'fields' => 'values.name,values.target.hash,next',
38294 'sort' => '-target.date',
38295 ),
38296 null,
38297 '&'
38298 )
38299 );
38300 $hasNext = true;
38301 while ($hasNext) {
38302 $tagsData = JsonFile::parseJson($this->getContentsWithOAuthCredentials($resource), $resource);
38303 foreach ($tagsData['values'] as $data) {
38304 $this->tags[$data['name']] = $data['target']['hash'];
38305 }
38306 if (empty($tagsData['next'])) {
38307 $hasNext = false;
38308 } else {
38309 $resource = $tagsData['next'];
38310 }
38311 }
38312 if ($this->vcsType === 'hg') {
38313 unset($this->tags['tip']);
38314 }
38315 }
38316
38317 return $this->tags;
38318 }
38319
38320
38321
38322
38323 public function getBranches()
38324 {
38325 if ($this->fallbackDriver) {
38326 return $this->fallbackDriver->getBranches();
38327 }
38328
38329 if (null === $this->branches) {
38330 $this->branches = array();
38331 $resource = sprintf(
38332 '%s?%s',
38333 $this->branchesUrl,
38334 http_build_query(
38335 array(
38336 'pagelen' => 100,
38337 'fields' => 'values.name,values.target.hash,values.heads,next',
38338 'sort' => '-target.date',
38339 ),
38340 null,
38341 '&'
38342 )
38343 );
38344 $hasNext = true;
38345 while ($hasNext) {
38346 $branchData = JsonFile::parseJson($this->getContentsWithOAuthCredentials($resource), $resource);
38347 foreach ($branchData['values'] as $data) {
38348
38349 if ($this->vcsType === 'hg' && empty($data['heads'])) {
38350 continue;
38351 }
38352
38353 $this->branches[$data['name']] = $data['target']['hash'];
38354 }
38355 if (empty($branchData['next'])) {
38356 $hasNext = false;
38357 } else {
38358 $resource = $branchData['next'];
38359 }
38360 }
38361 }
38362
38363 return $this->branches;
38364 }
38365
38366
38367
38368
38369
38370
38371
38372
38373
38374 protected function getContentsWithOAuthCredentials($url, $fetchingRepoData = false)
38375 {
38376 try {
38377 return parent::getContents($url);
38378 } catch (TransportException $e) {
38379 $bitbucketUtil = new Bitbucket($this->io, $this->config, $this->process, $this->remoteFilesystem);
38380
38381 if (403 === $e->getCode() || (401 === $e->getCode() && strpos($e->getMessage(), 'Could not authenticate against') === 0)) {
38382 if (!$this->io->hasAuthentication($this->originUrl)
38383 && $bitbucketUtil->authorizeOAuth($this->originUrl)
38384 ) {
38385 return parent::getContents($url);
38386 }
38387
38388 if (!$this->io->isInteractive() && $fetchingRepoData) {
38389 return $this->attemptCloneFallback();
38390 }
38391 }
38392
38393 throw $e;
38394 }
38395 }
38396
38397
38398
38399
38400
38401
38402 abstract protected function generateSshUrl();
38403
38404 protected function attemptCloneFallback()
38405 {
38406 try {
38407 $this->setupFallbackDriver($this->generateSshUrl());
38408 } catch (\RuntimeException $e) {
38409 $this->fallbackDriver = null;
38410
38411 $this->io->writeError(
38412 '<error>Failed to clone the ' . $this->generateSshUrl() . ' repository, try running in interactive mode'
38413 . ' so that you can enter your Bitbucket OAuth consumer credentials</error>'
38414 );
38415 throw $e;
38416 }
38417 }
38418
38419
38420
38421
38422
38423 abstract protected function setupFallbackDriver($url);
38424
38425
38426
38427
38428
38429 protected function parseCloneUrls(array $cloneLinks)
38430 {
38431 foreach ($cloneLinks as $cloneLink) {
38432 if ($cloneLink['name'] === 'https') {
38433
38434
38435 $this->cloneHttpsUrl = preg_replace('/https:\/\/([^@]+@)?/', 'https://', $cloneLink['href']);
38436 }
38437 }
38438 }
38439
38440
38441
38442
38443 protected function getMainBranchData()
38444 {
38445 $resource = sprintf(
38446 'https://api.bitbucket.org/2.0/repositories/%s/%s?fields=mainbranch',
38447 $this->owner,
38448 $this->repository
38449 );
38450
38451 $data = JsonFile::parseJson($this->getContentsWithOAuthCredentials($resource), $resource);
38452 if (isset($data['mainbranch'])) {
38453 return $data['mainbranch'];
38454 }
38455
38456 return null;
38457 }
38458 }
38459 <?php
38460
38461
38462
38463
38464
38465
38466
38467
38468
38469
38470
38471 namespace Composer\Repository\Vcs;
38472
38473 use Composer\Cache;
38474 use Composer\Config;
38475 use Composer\Util\ProcessExecutor;
38476 use Composer\Util\Filesystem;
38477 use Composer\IO\IOInterface;
38478
38479
38480
38481
38482 class FossilDriver extends VcsDriver
38483 {
38484 protected $tags;
38485 protected $branches;
38486 protected $rootIdentifier;
38487 protected $repoFile;
38488 protected $checkoutDir;
38489 protected $infoCache = array();
38490
38491
38492
38493
38494 public function initialize()
38495 {
38496
38497 $this->checkFossil();
38498
38499
38500 $this->config->prohibitUrlByConfig($this->url, $this->io);
38501
38502
38503
38504 if (Filesystem::isLocalPath($this->url) && is_dir($this->url)) {
38505 $this->checkoutDir = $this->url;
38506 } else {
38507 if (!Cache::isUsable($this->config->get('cache-repo-dir')) || !Cache::isUsable($this->config->get('cache-vcs-dir'))) {
38508 throw new \RuntimeException('FossilDriver requires a usable cache directory, and it looks like you set it to be disabled');
38509 }
38510
38511 $localName = preg_replace('{[^a-z0-9]}i', '-', $this->url);
38512 $this->repoFile = $this->config->get('cache-repo-dir') . '/' . $localName . '.fossil';
38513 $this->checkoutDir = $this->config->get('cache-vcs-dir') . '/' . $localName . '/';
38514
38515 $this->updateLocalRepo();
38516 }
38517
38518 $this->getTags();
38519 $this->getBranches();
38520 }
38521
38522
38523
38524
38525 protected function checkFossil()
38526 {
38527 if (0 !== $this->process->execute('fossil version', $ignoredOutput)) {
38528 throw new \RuntimeException("fossil was not found, check that it is installed and in your PATH env.\n\n" . $this->process->getErrorOutput());
38529 }
38530 }
38531
38532
38533
38534
38535 protected function updateLocalRepo()
38536 {
38537 $fs = new Filesystem();
38538 $fs->ensureDirectoryExists($this->checkoutDir);
38539
38540 if (!is_writable(dirname($this->checkoutDir))) {
38541 throw new \RuntimeException('Can not clone '.$this->url.' to access package information. The "'.$this->checkoutDir.'" directory is not writable by the current user.');
38542 }
38543
38544
38545 if (is_file($this->repoFile) && is_dir($this->checkoutDir) && 0 === $this->process->execute('fossil info', $output, $this->checkoutDir)) {
38546 if (0 !== $this->process->execute('fossil pull', $output, $this->checkoutDir)) {
38547 $this->io->writeError('<error>Failed to update '.$this->url.', package information from this repository may be outdated ('.$this->process->getErrorOutput().')</error>');
38548 }
38549 } else {
38550
38551 $fs->removeDirectory($this->checkoutDir);
38552 $fs->remove($this->repoFile);
38553
38554 $fs->ensureDirectoryExists($this->checkoutDir);
38555
38556 if (0 !== $this->process->execute(sprintf('fossil clone %s %s', ProcessExecutor::escape($this->url), ProcessExecutor::escape($this->repoFile)), $output)) {
38557 $output = $this->process->getErrorOutput();
38558
38559 throw new \RuntimeException('Failed to clone '.$this->url.' to repository ' . $this->repoFile . "\n\n" .$output);
38560 }
38561
38562 if (0 !== $this->process->execute(sprintf('fossil open %s --nested', ProcessExecutor::escape($this->repoFile)), $output, $this->checkoutDir)) {
38563 $output = $this->process->getErrorOutput();
38564
38565 throw new \RuntimeException('Failed to open repository '.$this->repoFile.' in ' . $this->checkoutDir . "\n\n" .$output);
38566 }
38567 }
38568 }
38569
38570
38571
38572
38573 public function getRootIdentifier()
38574 {
38575 if (null === $this->rootIdentifier) {
38576 $this->rootIdentifier = 'trunk';
38577 }
38578
38579 return $this->rootIdentifier;
38580 }
38581
38582
38583
38584
38585 public function getUrl()
38586 {
38587 return $this->url;
38588 }
38589
38590
38591
38592
38593 public function getSource($identifier)
38594 {
38595 return array('type' => 'fossil', 'url' => $this->getUrl(), 'reference' => $identifier);
38596 }
38597
38598
38599
38600
38601 public function getDist($identifier)
38602 {
38603 return null;
38604 }
38605
38606
38607
38608
38609 public function getFileContent($file, $identifier)
38610 {
38611 $command = sprintf('fossil cat -r %s %s', ProcessExecutor::escape($identifier), ProcessExecutor::escape($file));
38612 $this->process->execute($command, $content, $this->checkoutDir);
38613
38614 if (!trim($content)) {
38615 return null;
38616 }
38617
38618 return $content;
38619 }
38620
38621
38622
38623
38624 public function getChangeDate($identifier)
38625 {
38626 $this->process->execute('fossil finfo -b -n 1 composer.json', $output, $this->checkoutDir);
38627 list($ckout, $date, $message) = explode(' ', trim($output), 3);
38628
38629 return new \DateTime($date, new \DateTimeZone('UTC'));
38630 }
38631
38632
38633
38634
38635 public function getTags()
38636 {
38637 if (null === $this->tags) {
38638 $tags = array();
38639
38640 $this->process->execute('fossil tag list', $output, $this->checkoutDir);
38641 foreach ($this->process->splitLines($output) as $tag) {
38642 $tags[$tag] = $tag;
38643 }
38644
38645 $this->tags = $tags;
38646 }
38647
38648 return $this->tags;
38649 }
38650
38651
38652
38653
38654 public function getBranches()
38655 {
38656 if (null === $this->branches) {
38657 $branches = array();
38658 $bookmarks = array();
38659
38660 $this->process->execute('fossil branch list', $output, $this->checkoutDir);
38661 foreach ($this->process->splitLines($output) as $branch) {
38662 $branch = trim(preg_replace('/^\*/', '', trim($branch)));
38663 $branches[$branch] = $branch;
38664 }
38665
38666 $this->branches = $branches;
38667 }
38668
38669 return $this->branches;
38670 }
38671
38672
38673
38674
38675 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
38676 {
38677 if (preg_match('#(^(?:https?|ssh)://(?:[^@]@)?(?:chiselapp\.com|fossil\.))#i', $url)) {
38678 return true;
38679 }
38680
38681 if (preg_match('!/fossil/|\.fossil!', $url)) {
38682 return true;
38683 }
38684
38685
38686 if (Filesystem::isLocalPath($url)) {
38687 $url = Filesystem::getPlatformPath($url);
38688 if (!is_dir($url)) {
38689 return false;
38690 }
38691
38692 $process = new ProcessExecutor($io);
38693
38694 if ($process->execute('fossil info', $output, $url) === 0) {
38695 return true;
38696 }
38697 }
38698
38699 return false;
38700 }
38701 }
38702 <?php
38703
38704
38705
38706
38707
38708
38709
38710
38711
38712
38713
38714 namespace Composer\Repository\Vcs;
38715
38716 use Composer\Config;
38717 use Composer\IO\IOInterface;
38718
38719
38720
38721
38722 class GitBitbucketDriver extends BitbucketDriver
38723 {
38724
38725
38726
38727 public function getRootIdentifier()
38728 {
38729 if ($this->fallbackDriver) {
38730 return $this->fallbackDriver->getRootIdentifier();
38731 }
38732
38733 if (null === $this->rootIdentifier) {
38734 if (! $this->getRepoData()) {
38735 return $this->fallbackDriver->getRootIdentifier();
38736 }
38737
38738 if ($this->vcsType !== 'git') {
38739 throw new \RuntimeException(
38740 $this->url.' does not appear to be a git repository, use '.
38741 $this->cloneHttpsUrl.' if this is a mercurial bitbucket repository'
38742 );
38743 }
38744
38745 $mainBranchData = $this->getMainBranchData();
38746 $this->rootIdentifier = !empty($mainBranchData['name']) ? $mainBranchData['name'] : 'master';
38747 }
38748
38749 return $this->rootIdentifier;
38750 }
38751
38752
38753
38754
38755 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
38756 {
38757 if (!preg_match('#^https?://bitbucket\.org/([^/]+)/(.+?)\.git$#i', $url)) {
38758 return false;
38759 }
38760
38761 if (!extension_loaded('openssl')) {
38762 $io->writeError('Skipping Bitbucket git driver for '.$url.' because the OpenSSL PHP extension is missing.', true, IOInterface::VERBOSE);
38763
38764 return false;
38765 }
38766
38767 return true;
38768 }
38769
38770
38771
38772
38773 protected function setupFallbackDriver($url)
38774 {
38775 $this->fallbackDriver = new GitDriver(
38776 array('url' => $url),
38777 $this->io,
38778 $this->config,
38779 $this->process,
38780 $this->remoteFilesystem
38781 );
38782 $this->fallbackDriver->initialize();
38783 }
38784
38785
38786
38787
38788 protected function generateSshUrl()
38789 {
38790 return 'git@' . $this->originUrl . ':' . $this->owner.'/'.$this->repository.'.git';
38791 }
38792 }
38793 <?php
38794
38795
38796
38797
38798
38799
38800
38801
38802
38803
38804
38805 namespace Composer\Repository\Vcs;
38806
38807 use Composer\Util\ProcessExecutor;
38808 use Composer\Util\Filesystem;
38809 use Composer\Util\Git as GitUtil;
38810 use Composer\IO\IOInterface;
38811 use Composer\Cache;
38812 use Composer\Config;
38813
38814
38815
38816
38817 class GitDriver extends VcsDriver
38818 {
38819 protected $cache;
38820 protected $tags;
38821 protected $branches;
38822 protected $rootIdentifier;
38823 protected $repoDir;
38824 protected $infoCache = array();
38825
38826
38827
38828
38829 public function initialize()
38830 {
38831 if (Filesystem::isLocalPath($this->url)) {
38832 $this->url = preg_replace('{[\\/]\.git/?$}', '', $this->url);
38833 $this->repoDir = $this->url;
38834 $cacheUrl = realpath($this->url);
38835 } else {
38836 if (!Cache::isUsable($this->config->get('cache-vcs-dir'))) {
38837 throw new \RuntimeException('GitDriver requires a usable cache directory, and it looks like you set it to be disabled');
38838 }
38839
38840 $this->repoDir = $this->config->get('cache-vcs-dir') . '/' . preg_replace('{[^a-z0-9.]}i', '-', $this->url) . '/';
38841
38842 GitUtil::cleanEnv();
38843
38844 $fs = new Filesystem();
38845 $fs->ensureDirectoryExists(dirname($this->repoDir));
38846
38847 if (!is_writable(dirname($this->repoDir))) {
38848 throw new \RuntimeException('Can not clone '.$this->url.' to access package information. The "'.dirname($this->repoDir).'" directory is not writable by the current user.');
38849 }
38850
38851 if (preg_match('{^ssh://[^@]+@[^:]+:[^0-9]+}', $this->url)) {
38852 throw new \InvalidArgumentException('The source URL '.$this->url.' is invalid, ssh URLs should have a port number after ":".'."\n".'Use ssh://git@example.com:22/path or just git@example.com:path if you do not want to provide a password or custom port.');
38853 }
38854
38855 $gitUtil = new GitUtil($this->io, $this->config, $this->process, $fs);
38856 if (!$gitUtil->syncMirror($this->url, $this->repoDir)) {
38857 $this->io->writeError('<error>Failed to update '.$this->url.', package information from this repository may be outdated</error>');
38858 }
38859
38860 $cacheUrl = $this->url;
38861 }
38862
38863 $this->getTags();
38864 $this->getBranches();
38865
38866 $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $cacheUrl));
38867 }
38868
38869
38870
38871
38872 public function getRootIdentifier()
38873 {
38874 if (null === $this->rootIdentifier) {
38875 $this->rootIdentifier = 'master';
38876
38877
38878 $this->process->execute('git branch --no-color', $output, $this->repoDir);
38879 $branches = $this->process->splitLines($output);
38880 if (!in_array('* master', $branches)) {
38881 foreach ($branches as $branch) {
38882 if ($branch && preg_match('{^\* +(\S+)}', $branch, $match)) {
38883 $this->rootIdentifier = $match[1];
38884 break;
38885 }
38886 }
38887 }
38888 }
38889
38890 return $this->rootIdentifier;
38891 }
38892
38893
38894
38895
38896 public function getUrl()
38897 {
38898 return $this->url;
38899 }
38900
38901
38902
38903
38904 public function getSource($identifier)
38905 {
38906 return array('type' => 'git', 'url' => $this->getUrl(), 'reference' => $identifier);
38907 }
38908
38909
38910
38911
38912 public function getDist($identifier)
38913 {
38914 return null;
38915 }
38916
38917
38918
38919
38920 public function getFileContent($file, $identifier)
38921 {
38922 $resource = sprintf('%s:%s', ProcessExecutor::escape($identifier), ProcessExecutor::escape($file));
38923 $this->process->execute(sprintf('git show %s', $resource), $content, $this->repoDir);
38924
38925 if (!trim($content)) {
38926 return null;
38927 }
38928
38929 return $content;
38930 }
38931
38932
38933
38934
38935 public function getChangeDate($identifier)
38936 {
38937 $this->process->execute(sprintf(
38938 'git -c log.showSignature=false log -1 --format=%%at %s',
38939 ProcessExecutor::escape($identifier)
38940 ), $output, $this->repoDir);
38941
38942 return new \DateTime('@'.trim($output), new \DateTimeZone('UTC'));
38943 }
38944
38945
38946
38947
38948 public function getTags()
38949 {
38950 if (null === $this->tags) {
38951 $this->tags = array();
38952
38953 $this->process->execute('git show-ref --tags --dereference', $output, $this->repoDir);
38954 foreach ($output = $this->process->splitLines($output) as $tag) {
38955 if ($tag && preg_match('{^([a-f0-9]{40}) refs/tags/(\S+?)(\^\{\})?$}', $tag, $match)) {
38956 $this->tags[$match[2]] = $match[1];
38957 }
38958 }
38959 }
38960
38961 return $this->tags;
38962 }
38963
38964
38965
38966
38967 public function getBranches()
38968 {
38969 if (null === $this->branches) {
38970 $branches = array();
38971
38972 $this->process->execute('git branch --no-color --no-abbrev -v', $output, $this->repoDir);
38973 foreach ($this->process->splitLines($output) as $branch) {
38974 if ($branch && !preg_match('{^ *[^/]+/HEAD }', $branch)) {
38975 if (preg_match('{^(?:\* )? *(\S+) *([a-f0-9]+)(?: .*)?$}', $branch, $match)) {
38976 $branches[$match[1]] = $match[2];
38977 }
38978 }
38979 }
38980
38981 $this->branches = $branches;
38982 }
38983
38984 return $this->branches;
38985 }
38986
38987
38988
38989
38990 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
38991 {
38992 if (preg_match('#(^git://|\.git/?$|git(?:olite)?@|//git\.|//github.com/)#i', $url)) {
38993 return true;
38994 }
38995
38996
38997 if (Filesystem::isLocalPath($url)) {
38998 $url = Filesystem::getPlatformPath($url);
38999 if (!is_dir($url)) {
39000 return false;
39001 }
39002
39003 $process = new ProcessExecutor($io);
39004
39005 if ($process->execute('git tag', $output, $url) === 0) {
39006 return true;
39007 }
39008 }
39009
39010 if (!$deep) {
39011 return false;
39012 }
39013
39014 $gitUtil = new GitUtil($io, $config, new ProcessExecutor($io), new Filesystem());
39015 GitUtil::cleanEnv();
39016
39017 try {
39018 $gitUtil->runCommand(function ($url) {
39019 return 'git ls-remote --heads ' . ProcessExecutor::escape($url);
39020 }, $url, sys_get_temp_dir());
39021 } catch (\RuntimeException $e) {
39022 return false;
39023 }
39024
39025 return true;
39026 }
39027 }
39028 <?php
39029
39030
39031
39032
39033
39034
39035
39036
39037
39038
39039
39040 namespace Composer\Repository\Vcs;
39041
39042 use Composer\Config;
39043 use Composer\Downloader\TransportException;
39044 use Composer\Json\JsonFile;
39045 use Composer\Cache;
39046 use Composer\IO\IOInterface;
39047 use Composer\Util\GitHub;
39048
39049
39050
39051
39052 class GitHubDriver extends VcsDriver
39053 {
39054 protected $cache;
39055 protected $owner;
39056 protected $repository;
39057 protected $tags;
39058 protected $branches;
39059 protected $rootIdentifier;
39060 protected $repoData;
39061 protected $hasIssues;
39062 protected $infoCache = array();
39063 protected $isPrivate = false;
39064 private $isArchived = false;
39065 private $fundingInfo;
39066
39067
39068
39069
39070
39071
39072 protected $gitDriver;
39073
39074
39075
39076
39077 public function initialize()
39078 {
39079 preg_match('#^(?:(?:https?|git)://([^/]+)/|git@([^:]+):/?)([^/]+)/(.+?)(?:\.git|/)?$#', $this->url, $match);
39080 $this->owner = $match[3];
39081 $this->repository = $match[4];
39082 $this->originUrl = strtolower(!empty($match[1]) ? $match[1] : $match[2]);
39083 if ($this->originUrl === 'www.github.com') {
39084 $this->originUrl = 'github.com';
39085 }
39086 $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.$this->originUrl.'/'.$this->owner.'/'.$this->repository);
39087
39088 if ( $this->config->get('use-github-api') === false || (isset($this->repoConfig['no-api']) && $this->repoConfig['no-api'] ) ){
39089 $this->setupGitDriver($this->url);
39090
39091 return;
39092 }
39093
39094 $this->fetchRootIdentifier();
39095 }
39096
39097 public function getRepositoryUrl()
39098 {
39099 return 'https://'.$this->originUrl.'/'.$this->owner.'/'.$this->repository;
39100 }
39101
39102
39103
39104
39105 public function getRootIdentifier()
39106 {
39107 if ($this->gitDriver) {
39108 return $this->gitDriver->getRootIdentifier();
39109 }
39110
39111 return $this->rootIdentifier;
39112 }
39113
39114
39115
39116
39117 public function getUrl()
39118 {
39119 if ($this->gitDriver) {
39120 return $this->gitDriver->getUrl();
39121 }
39122
39123 return 'https://' . $this->originUrl . '/'.$this->owner.'/'.$this->repository.'.git';
39124 }
39125
39126
39127
39128
39129 protected function getApiUrl()
39130 {
39131 if ('github.com' === $this->originUrl) {
39132 $apiUrl = 'api.github.com';
39133 } else {
39134 $apiUrl = $this->originUrl . '/api/v3';
39135 }
39136
39137 return 'https://' . $apiUrl;
39138 }
39139
39140
39141
39142
39143 public function getSource($identifier)
39144 {
39145 if ($this->gitDriver) {
39146 return $this->gitDriver->getSource($identifier);
39147 }
39148 if ($this->isPrivate) {
39149
39150
39151 $url = $this->generateSshUrl();
39152 } else {
39153 $url = $this->getUrl();
39154 }
39155
39156 return array('type' => 'git', 'url' => $url, 'reference' => $identifier);
39157 }
39158
39159
39160
39161
39162 public function getDist($identifier)
39163 {
39164 $url = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/zipball/'.$identifier;
39165
39166 return array('type' => 'zip', 'url' => $url, 'reference' => $identifier, 'shasum' => '');
39167 }
39168
39169
39170
39171
39172 public function getComposerInformation($identifier)
39173 {
39174 if ($this->gitDriver) {
39175 return $this->gitDriver->getComposerInformation($identifier);
39176 }
39177
39178 if (!isset($this->infoCache[$identifier])) {
39179 if ($this->shouldCache($identifier) && $res = $this->cache->read($identifier)) {
39180 $composer = JsonFile::parseJson($res);
39181 } else {
39182 $composer = $this->getBaseComposerInformation($identifier);
39183
39184 if ($this->shouldCache($identifier)) {
39185 $this->cache->write($identifier, json_encode($composer));
39186 }
39187 }
39188
39189 if ($composer) {
39190
39191 if (!isset($composer['support']['source'])) {
39192 $label = array_search($identifier, $this->getTags()) ?: array_search($identifier, $this->getBranches()) ?: $identifier;
39193 $composer['support']['source'] = sprintf('https://%s/%s/%s/tree/%s', $this->originUrl, $this->owner, $this->repository, $label);
39194 }
39195 if (!isset($composer['support']['issues']) && $this->hasIssues) {
39196 $composer['support']['issues'] = sprintf('https://%s/%s/%s/issues', $this->originUrl, $this->owner, $this->repository);
39197 }
39198 if (!isset($composer['abandoned']) && $this->isArchived) {
39199 $composer['abandoned'] = true;
39200 }
39201 if (!isset($composer['funding']) && $funding = $this->getFundingInfo()) {
39202 $composer['funding'] = $funding;
39203 }
39204 }
39205
39206 $this->infoCache[$identifier] = $composer;
39207 }
39208
39209 return $this->infoCache[$identifier];
39210 }
39211
39212 private function getFundingInfo()
39213 {
39214 if (null !== $this->fundingInfo) {
39215 return $this->fundingInfo;
39216 }
39217
39218 if ($this->originUrl !== 'github.com') {
39219 return $this->fundingInfo = false;
39220 }
39221
39222 foreach (array($this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/contents/.github/FUNDING.yml', $this->getApiUrl() . '/repos/'.$this->owner.'/.github/contents/FUNDING.yml') as $file) {
39223
39224 try {
39225 $result = $this->remoteFilesystem->getContents($this->originUrl, $file, false, array(
39226 'retry-auth-failure' => false,
39227 ));
39228 $response = json_decode($result, true);
39229 } catch (TransportException $e) {
39230 continue;
39231 }
39232 if (empty($response['content']) || $response['encoding'] !== 'base64' || !($funding = base64_decode($response['content']))) {
39233 continue;
39234 }
39235 break;
39236 }
39237 if (empty($funding)) {
39238 return $this->fundingInfo = false;
39239 }
39240
39241 $result = array();
39242 $key = null;
39243 foreach (preg_split('{\r?\n}', $funding) as $line) {
39244 $line = trim($line);
39245 if (preg_match('{^(\w+)\s*:\s*(.+)$}', $line, $match)) {
39246 if (preg_match('{^\[(.*)\](?:\s*#.*)?$}', $match[2], $match2)) {
39247 foreach (array_map('trim', preg_split('{[\'"]?\s*,\s*[\'"]?}', $match2[1])) as $item) {
39248 $result[] = array('type' => $match[1], 'url' => trim($item, '"\' '));
39249 }
39250 } elseif (preg_match('{^([^#].*?)(\s+#.*)?$}', $match[2], $match2)) {
39251 $result[] = array('type' => $match[1], 'url' => trim($match2[1], '"\' '));
39252 }
39253 $key = null;
39254 } elseif (preg_match('{^(\w+)\s*:\s*#\s*$}', $line, $match)) {
39255 $key = $match[1];
39256 } elseif ($key && preg_match('{^-\s*(.+)(\s+#.*)?$}', $line, $match)) {
39257 $result[] = array('type' => $key, 'url' => trim($match[1], '"\' '));
39258 }
39259 }
39260
39261 foreach ($result as $key => $item) {
39262 switch ($item['type']) {
39263 case 'tidelift':
39264 $result[$key]['url'] = 'https://tidelift.com/funding/github/' . $item['url'];
39265 break;
39266 case 'github':
39267 $result[$key]['url'] = 'https://github.com/' . basename($item['url']);
39268 break;
39269 case 'patreon':
39270 $result[$key]['url'] = 'https://www.patreon.com/' . basename($item['url']);
39271 break;
39272 case 'otechie':
39273 $result[$key]['url'] = 'https://otechie.com/' . basename($item['url']);
39274 break;
39275 case 'open_collective':
39276 $result[$key]['url'] = 'https://opencollective.com/' . basename($item['url']);
39277 break;
39278 case 'liberapay':
39279 $result[$key]['url'] = 'https://liberapay.com/' . basename($item['url']);
39280 break;
39281 case 'ko_fi':
39282 $result[$key]['url'] = 'https://ko-fi.com/' . basename($item['url']);
39283 break;
39284 case 'issuehunt':
39285 $result[$key]['url'] = 'https://issuehunt.io/r/' . $item['url'];
39286 break;
39287 case 'community_bridge':
39288 $result[$key]['url'] = 'https://funding.communitybridge.org/projects/' . basename($item['url']);
39289 break;
39290 }
39291 }
39292
39293 return $this->fundingInfo = $result;
39294 }
39295
39296
39297
39298
39299 public function getFileContent($file, $identifier)
39300 {
39301 if ($this->gitDriver) {
39302 return $this->gitDriver->getFileContent($file, $identifier);
39303 }
39304
39305 $resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/contents/' . $file . '?ref='.urlencode($identifier);
39306 $resource = JsonFile::parseJson($this->getContents($resource));
39307 if (empty($resource['content']) || $resource['encoding'] !== 'base64' || !($content = base64_decode($resource['content']))) {
39308 throw new \RuntimeException('Could not retrieve ' . $file . ' for '.$identifier);
39309 }
39310
39311 return $content;
39312 }
39313
39314
39315
39316
39317 public function getChangeDate($identifier)
39318 {
39319 if ($this->gitDriver) {
39320 return $this->gitDriver->getChangeDate($identifier);
39321 }
39322
39323 $resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/commits/'.urlencode($identifier);
39324 $commit = JsonFile::parseJson($this->getContents($resource), $resource);
39325
39326 return new \DateTime($commit['commit']['committer']['date']);
39327 }
39328
39329
39330
39331
39332 public function getTags()
39333 {
39334 if ($this->gitDriver) {
39335 return $this->gitDriver->getTags();
39336 }
39337 if (null === $this->tags) {
39338 $this->tags = array();
39339 $resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/tags?per_page=100';
39340
39341 do {
39342 $tagsData = JsonFile::parseJson($this->getContents($resource), $resource);
39343 foreach ($tagsData as $tag) {
39344 $this->tags[$tag['name']] = $tag['commit']['sha'];
39345 }
39346
39347 $resource = $this->getNextPage();
39348 } while ($resource);
39349 }
39350
39351 return $this->tags;
39352 }
39353
39354
39355
39356
39357 public function getBranches()
39358 {
39359 if ($this->gitDriver) {
39360 return $this->gitDriver->getBranches();
39361 }
39362 if (null === $this->branches) {
39363 $this->branches = array();
39364 $resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/git/refs/heads?per_page=100';
39365
39366 do {
39367 $branchData = JsonFile::parseJson($this->getContents($resource), $resource);
39368 foreach ($branchData as $branch) {
39369 $name = substr($branch['ref'], 11);
39370 if ($name !== 'gh-pages') {
39371 $this->branches[$name] = $branch['object']['sha'];
39372 }
39373 }
39374
39375 $resource = $this->getNextPage();
39376 } while ($resource);
39377 }
39378
39379 return $this->branches;
39380 }
39381
39382
39383
39384
39385 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
39386 {
39387 if (!preg_match('#^((?:https?|git)://([^/]+)/|git@([^:]+):/?)([^/]+)/(.+?)(?:\.git|/)?$#', $url, $matches)) {
39388 return false;
39389 }
39390
39391 $originUrl = !empty($matches[2]) ? $matches[2] : $matches[3];
39392 if (!in_array(strtolower(preg_replace('{^www\.}i', '', $originUrl)), $config->get('github-domains'))) {
39393 return false;
39394 }
39395
39396 if (!extension_loaded('openssl')) {
39397 $io->writeError('Skipping GitHub driver for '.$url.' because the OpenSSL PHP extension is missing.', true, IOInterface::VERBOSE);
39398
39399 return false;
39400 }
39401
39402 return true;
39403 }
39404
39405
39406
39407
39408
39409
39410 public function getRepoData()
39411 {
39412 $this->fetchRootIdentifier();
39413
39414 return $this->repoData;
39415 }
39416
39417
39418
39419
39420
39421
39422 protected function generateSshUrl()
39423 {
39424 if (false !== strpos($this->originUrl, ':')) {
39425 return 'ssh://git@' . $this->originUrl . '/'.$this->owner.'/'.$this->repository.'.git';
39426 }
39427
39428 return 'git@' . $this->originUrl . ':'.$this->owner.'/'.$this->repository.'.git';
39429 }
39430
39431
39432
39433
39434 protected function getContents($url, $fetchingRepoData = false)
39435 {
39436 try {
39437 return parent::getContents($url);
39438 } catch (TransportException $e) {
39439 $gitHubUtil = new GitHub($this->io, $this->config, $this->process, $this->remoteFilesystem);
39440
39441 switch ($e->getCode()) {
39442 case 401:
39443 case 404:
39444
39445 if (!$fetchingRepoData) {
39446 throw $e;
39447 }
39448
39449 if ($gitHubUtil->authorizeOAuth($this->originUrl)) {
39450 return parent::getContents($url);
39451 }
39452
39453 if (!$this->io->isInteractive()) {
39454 return $this->attemptCloneFallback();
39455 }
39456
39457 $scopesIssued = array();
39458 $scopesNeeded = array();
39459 if ($headers = $e->getHeaders()) {
39460 if ($scopes = $this->remoteFilesystem->findHeaderValue($headers, 'X-OAuth-Scopes')) {
39461 $scopesIssued = explode(' ', $scopes);
39462 }
39463 if ($scopes = $this->remoteFilesystem->findHeaderValue($headers, 'X-Accepted-OAuth-Scopes')) {
39464 $scopesNeeded = explode(' ', $scopes);
39465 }
39466 }
39467 $scopesFailed = array_diff($scopesNeeded, $scopesIssued);
39468
39469
39470 if (!$headers || !count($scopesNeeded) || count($scopesFailed)) {
39471 $gitHubUtil->authorizeOAuthInteractively($this->originUrl, 'Your GitHub credentials are required to fetch private repository metadata (<info>'.$this->url.'</info>)');
39472 }
39473
39474 return parent::getContents($url);
39475
39476 case 403:
39477 if (!$this->io->hasAuthentication($this->originUrl) && $gitHubUtil->authorizeOAuth($this->originUrl)) {
39478 return parent::getContents($url);
39479 }
39480
39481 if (!$this->io->isInteractive() && $fetchingRepoData) {
39482 return $this->attemptCloneFallback();
39483 }
39484
39485 $rateLimited = $gitHubUtil->isRateLimited($e->getHeaders());
39486
39487 if (!$this->io->hasAuthentication($this->originUrl)) {
39488 if (!$this->io->isInteractive()) {
39489 $this->io->writeError('<error>GitHub API limit exhausted. Failed to get metadata for the '.$this->url.' repository, try running in interactive mode so that you can enter your GitHub credentials to increase the API limit</error>');
39490 throw $e;
39491 }
39492
39493 $gitHubUtil->authorizeOAuthInteractively($this->originUrl, 'API limit exhausted. Enter your GitHub credentials to get a larger API limit (<info>'.$this->url.'</info>)');
39494
39495 return parent::getContents($url);
39496 }
39497
39498 if ($rateLimited) {
39499 $rateLimit = $gitHubUtil->getRateLimit($e->getHeaders());
39500 $this->io->writeError(sprintf(
39501 '<error>GitHub API limit (%d calls/hr) is exhausted. You are already authorized so you have to wait until %s before doing more requests</error>',
39502 $rateLimit['limit'],
39503 $rateLimit['reset']
39504 ));
39505 }
39506
39507 throw $e;
39508
39509 default:
39510 throw $e;
39511 }
39512 }
39513 }
39514
39515
39516
39517
39518
39519
39520 protected function fetchRootIdentifier()
39521 {
39522 if ($this->repoData) {
39523 return;
39524 }
39525
39526 $repoDataUrl = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository;
39527
39528 $this->repoData = JsonFile::parseJson($this->getContents($repoDataUrl, true), $repoDataUrl);
39529 if (null === $this->repoData && null !== $this->gitDriver) {
39530 return;
39531 }
39532
39533 $this->owner = $this->repoData['owner']['login'];
39534 $this->repository = $this->repoData['name'];
39535
39536 $this->isPrivate = !empty($this->repoData['private']);
39537 if (isset($this->repoData['default_branch'])) {
39538 $this->rootIdentifier = $this->repoData['default_branch'];
39539 } elseif (isset($this->repoData['master_branch'])) {
39540 $this->rootIdentifier = $this->repoData['master_branch'];
39541 } else {
39542 $this->rootIdentifier = 'master';
39543 }
39544 $this->hasIssues = !empty($this->repoData['has_issues']);
39545 $this->isArchived = !empty($this->repoData['archived']);
39546 }
39547
39548 protected function attemptCloneFallback()
39549 {
39550 $this->isPrivate = true;
39551
39552 try {
39553
39554
39555
39556
39557 $this->setupGitDriver($this->generateSshUrl());
39558
39559 return;
39560 } catch (\RuntimeException $e) {
39561 $this->gitDriver = null;
39562
39563 $this->io->writeError('<error>Failed to clone the '.$this->generateSshUrl().' repository, try running in interactive mode so that you can enter your GitHub credentials</error>');
39564 throw $e;
39565 }
39566 }
39567
39568 protected function setupGitDriver($url)
39569 {
39570 $this->gitDriver = new GitDriver(
39571 array('url' => $url),
39572 $this->io,
39573 $this->config,
39574 $this->process,
39575 $this->remoteFilesystem
39576 );
39577 $this->gitDriver->initialize();
39578 }
39579
39580 protected function getNextPage()
39581 {
39582 $headers = $this->remoteFilesystem->getLastHeaders();
39583 foreach ($headers as $header) {
39584 if (preg_match('{^link:\s*(.+?)\s*$}i', $header, $match)) {
39585 $links = explode(',', $match[1]);
39586 foreach ($links as $link) {
39587 if (preg_match('{<(.+?)>; *rel="next"}', $link, $match)) {
39588 return $match[1];
39589 }
39590 }
39591 }
39592 }
39593 }
39594 }
39595 <?php
39596
39597
39598
39599
39600
39601
39602
39603
39604
39605
39606
39607 namespace Composer\Repository\Vcs;
39608
39609 use Composer\Config;
39610 use Composer\Cache;
39611 use Composer\IO\IOInterface;
39612 use Composer\Json\JsonFile;
39613 use Composer\Downloader\TransportException;
39614 use Composer\Util\RemoteFilesystem;
39615 use Composer\Util\GitLab;
39616
39617
39618
39619
39620
39621
39622
39623 class GitLabDriver extends VcsDriver
39624 {
39625 private $scheme;
39626 private $namespace;
39627 private $repository;
39628
39629
39630
39631
39632 private $project;
39633
39634
39635
39636
39637 private $commits = array();
39638
39639
39640
39641
39642 private $tags;
39643
39644
39645
39646
39647 private $branches;
39648
39649
39650
39651
39652
39653
39654 protected $gitDriver;
39655
39656
39657
39658
39659
39660
39661 private $isPrivate = true;
39662
39663
39664
39665
39666 private $hasNonstandardOrigin = false;
39667
39668 const URL_REGEX = '#^(?:(?P<scheme>https?)://(?P<domain>.+?)(?::(?P<port>[0-9]+))?/|git@(?P<domain2>[^:]+):)(?P<parts>.+)/(?P<repo>[^/]+?)(?:\.git|/)?$#';
39669
39670
39671
39672
39673
39674
39675
39676
39677 public function initialize()
39678 {
39679 if (!preg_match(self::URL_REGEX, $this->url, $match)) {
39680 throw new \InvalidArgumentException('The URL provided is invalid. It must be the HTTP URL of a GitLab project.');
39681 }
39682
39683 $guessedDomain = !empty($match['domain']) ? $match['domain'] : $match['domain2'];
39684 $configuredDomains = $this->config->get('gitlab-domains');
39685 $urlParts = explode('/', $match['parts']);
39686
39687 $this->scheme = !empty($match['scheme'])
39688 ? $match['scheme']
39689 : (isset($this->repoConfig['secure-http']) && $this->repoConfig['secure-http'] === false ? 'http' : 'https')
39690 ;
39691 $this->originUrl = $this->determineOrigin($configuredDomains, $guessedDomain, $urlParts, $match['port']);
39692
39693 if (false !== strpos($this->originUrl, ':') || false !== strpos($this->originUrl, '/')) {
39694 $this->hasNonstandardOrigin = true;
39695 }
39696
39697 $this->namespace = implode('/', $urlParts);
39698 $this->repository = preg_replace('#(\.git)$#', '', $match['repo']);
39699
39700 $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.$this->originUrl.'/'.$this->namespace.'/'.$this->repository);
39701
39702 $this->fetchProject();
39703 }
39704
39705
39706
39707
39708
39709
39710
39711 public function setRemoteFilesystem(RemoteFilesystem $remoteFilesystem)
39712 {
39713 $this->remoteFilesystem = $remoteFilesystem;
39714 }
39715
39716
39717
39718
39719 public function getComposerInformation($identifier)
39720 {
39721 if ($this->gitDriver) {
39722 return $this->gitDriver->getComposerInformation($identifier);
39723 }
39724
39725 if (!isset($this->infoCache[$identifier])) {
39726 if ($this->shouldCache($identifier) && $res = $this->cache->read($identifier)) {
39727 $composer = JsonFile::parseJson($res);
39728 } else {
39729 $composer = $this->getBaseComposerInformation($identifier);
39730
39731 if ($this->shouldCache($identifier)) {
39732 $this->cache->write($identifier, json_encode($composer));
39733 }
39734 }
39735
39736 if ($composer) {
39737
39738 if (!isset($composer['support']['issues']) && isset($this->project['_links']['issues'])) {
39739 $composer['support']['issues'] = $this->project['_links']['issues'];
39740 }
39741 if (!isset($composer['abandoned']) && !empty($this->project['archived'])) {
39742 $composer['abandoned'] = true;
39743 }
39744 }
39745
39746 $this->infoCache[$identifier] = $composer;
39747 }
39748
39749 return $this->infoCache[$identifier];
39750 }
39751
39752
39753
39754
39755 public function getFileContent($file, $identifier)
39756 {
39757 if ($this->gitDriver) {
39758 return $this->gitDriver->getFileContent($file, $identifier);
39759 }
39760
39761
39762 if (!preg_match('{[a-f0-9]{40}}i', $identifier)) {
39763 $branches = $this->getBranches();
39764 if (isset($branches[$identifier])) {
39765 $identifier = $branches[$identifier];
39766 }
39767 }
39768
39769 $resource = $this->getApiUrl().'/repository/files/'.$this->urlEncodeAll($file).'/raw?ref='.$identifier;
39770
39771 try {
39772 $content = $this->getContents($resource);
39773 } catch (TransportException $e) {
39774 if ($e->getCode() !== 404) {
39775 throw $e;
39776 }
39777
39778 return null;
39779 }
39780
39781 return $content;
39782 }
39783
39784
39785
39786
39787 public function getChangeDate($identifier)
39788 {
39789 if ($this->gitDriver) {
39790 return $this->gitDriver->getChangeDate($identifier);
39791 }
39792
39793 if (isset($this->commits[$identifier])) {
39794 return new \DateTime($this->commits[$identifier]['committed_date']);
39795 }
39796
39797 return new \DateTime();
39798 }
39799
39800
39801
39802
39803 public function getRepositoryUrl()
39804 {
39805 return $this->isPrivate ? $this->project['ssh_url_to_repo'] : $this->project['http_url_to_repo'];
39806 }
39807
39808
39809
39810
39811 public function getUrl()
39812 {
39813 if ($this->gitDriver) {
39814 return $this->gitDriver->getUrl();
39815 }
39816
39817 return $this->project['web_url'];
39818 }
39819
39820
39821
39822
39823 public function getDist($identifier)
39824 {
39825 $url = $this->getApiUrl().'/repository/archive.zip?sha='.$identifier;
39826
39827 return array('type' => 'zip', 'url' => $url, 'reference' => $identifier, 'shasum' => '');
39828 }
39829
39830
39831
39832
39833 public function getSource($identifier)
39834 {
39835 if ($this->gitDriver) {
39836 return $this->gitDriver->getSource($identifier);
39837 }
39838
39839 return array('type' => 'git', 'url' => $this->getRepositoryUrl(), 'reference' => $identifier);
39840 }
39841
39842
39843
39844
39845 public function getRootIdentifier()
39846 {
39847 if ($this->gitDriver) {
39848 return $this->gitDriver->getRootIdentifier();
39849 }
39850
39851 return $this->project['default_branch'];
39852 }
39853
39854
39855
39856
39857 public function getBranches()
39858 {
39859 if ($this->gitDriver) {
39860 return $this->gitDriver->getBranches();
39861 }
39862
39863 if (!$this->branches) {
39864 $this->branches = $this->getReferences('branches');
39865 }
39866
39867 return $this->branches;
39868 }
39869
39870
39871
39872
39873 public function getTags()
39874 {
39875 if ($this->gitDriver) {
39876 return $this->gitDriver->getTags();
39877 }
39878
39879 if (!$this->tags) {
39880 $this->tags = $this->getReferences('tags');
39881 }
39882
39883 return $this->tags;
39884 }
39885
39886
39887
39888
39889 public function getApiUrl()
39890 {
39891 return $this->scheme.'://'.$this->originUrl.'/api/v4/projects/'.$this->urlEncodeAll($this->namespace).'%2F'.$this->urlEncodeAll($this->repository);
39892 }
39893
39894
39895
39896
39897
39898
39899
39900 private function urlEncodeAll($string)
39901 {
39902 $encoded = '';
39903 for ($i = 0; isset($string[$i]); $i++) {
39904 $character = $string[$i];
39905 if (!ctype_alnum($character) && !in_array($character, array('-', '_'), true)) {
39906 $character = '%' . sprintf('%02X', ord($character));
39907 }
39908 $encoded .= $character;
39909 }
39910
39911 return $encoded;
39912 }
39913
39914
39915
39916
39917
39918
39919 protected function getReferences($type)
39920 {
39921 $perPage = 100;
39922 $resource = $this->getApiUrl().'/repository/'.$type.'?per_page='.$perPage;
39923
39924 $references = array();
39925 do {
39926 $data = JsonFile::parseJson($this->getContents($resource), $resource);
39927
39928 foreach ($data as $datum) {
39929 $references[$datum['name']] = $datum['commit']['id'];
39930
39931
39932
39933 $this->commits[$datum['commit']['id']] = $datum['commit'];
39934 }
39935
39936 if (count($data) >= $perPage) {
39937 $resource = $this->getNextPage();
39938 } else {
39939 $resource = false;
39940 }
39941 } while ($resource);
39942
39943 return $references;
39944 }
39945
39946 protected function fetchProject()
39947 {
39948
39949 $resource = $this->getApiUrl();
39950 $this->project = JsonFile::parseJson($this->getContents($resource, true), $resource);
39951 if (isset($this->project['visibility'])) {
39952 $this->isPrivate = $this->project['visibility'] !== 'public';
39953 } else {
39954
39955 $this->isPrivate = false;
39956 }
39957 }
39958
39959 protected function attemptCloneFallback()
39960 {
39961 try {
39962 if ($this->isPrivate === false) {
39963 $url = $this->generatePublicUrl();
39964 } else {
39965 $url = $this->generateSshUrl();
39966 }
39967
39968
39969
39970
39971 $this->setupGitDriver($url);
39972
39973 return;
39974 } catch (\RuntimeException $e) {
39975 $this->gitDriver = null;
39976
39977 $this->io->writeError('<error>Failed to clone the '.$url.' repository, try running in interactive mode so that you can enter your credentials</error>');
39978 throw $e;
39979 }
39980 }
39981
39982
39983
39984
39985
39986
39987 protected function generateSshUrl()
39988 {
39989 if ($this->hasNonstandardOrigin) {
39990 return 'ssh://git@'.$this->originUrl.'/'.$this->namespace.'/'.$this->repository.'.git';
39991 }
39992
39993 return 'git@' . $this->originUrl . ':'.$this->namespace.'/'.$this->repository.'.git';
39994 }
39995
39996 protected function generatePublicUrl()
39997 {
39998 return $this->scheme . '://' . $this->originUrl . '/'.$this->namespace.'/'.$this->repository.'.git';
39999 }
40000
40001 protected function setupGitDriver($url)
40002 {
40003 $this->gitDriver = new GitDriver(
40004 array('url' => $url),
40005 $this->io,
40006 $this->config,
40007 $this->process,
40008 $this->remoteFilesystem
40009 );
40010 $this->gitDriver->initialize();
40011 }
40012
40013
40014
40015
40016 protected function getContents($url, $fetchingRepoData = false)
40017 {
40018 try {
40019 $res = parent::getContents($url);
40020
40021 if ($fetchingRepoData) {
40022 $json = JsonFile::parseJson($res, $url);
40023
40024
40025
40026
40027 if (!isset($json['default_branch']) && isset($json['permissions'])) {
40028 $this->isPrivate = $json['visibility'] !== 'public';
40029
40030 $moreThanGuestAccess = false;
40031
40032
40033
40034 foreach ($json['permissions'] as $permission) {
40035 if ($permission && $permission['access_level'] > 10) {
40036 $moreThanGuestAccess = true;
40037 }
40038 }
40039
40040 if (!$moreThanGuestAccess) {
40041 $this->io->writeError('<warning>GitLab token with Guest only access detected</warning>');
40042
40043 return $this->attemptCloneFallback();
40044 }
40045 }
40046
40047
40048 if (!isset($json['default_branch'])) {
40049 if (!empty($json['id'])) {
40050 $this->isPrivate = false;
40051 }
40052
40053 throw new TransportException('GitLab API seems to not be authenticated as it did not return a default_branch', 401);
40054 }
40055 }
40056
40057 return $res;
40058 } catch (TransportException $e) {
40059 $gitLabUtil = new GitLab($this->io, $this->config, $this->process, $this->remoteFilesystem);
40060
40061 switch ($e->getCode()) {
40062 case 401:
40063 case 404:
40064
40065 if (!$fetchingRepoData) {
40066 throw $e;
40067 }
40068
40069 if ($gitLabUtil->authorizeOAuth($this->originUrl)) {
40070 return parent::getContents($url);
40071 }
40072
40073 if (!$this->io->isInteractive()) {
40074 return $this->attemptCloneFallback();
40075 }
40076 $this->io->writeError('<warning>Failed to download ' . $this->namespace . '/' . $this->repository . ':' . $e->getMessage() . '</warning>');
40077 $gitLabUtil->authorizeOAuthInteractively($this->scheme, $this->originUrl, 'Your credentials are required to fetch private repository metadata (<info>'.$this->url.'</info>)');
40078
40079 return parent::getContents($url);
40080
40081 case 403:
40082 if (!$this->io->hasAuthentication($this->originUrl) && $gitLabUtil->authorizeOAuth($this->originUrl)) {
40083 return parent::getContents($url);
40084 }
40085
40086 if (!$this->io->isInteractive() && $fetchingRepoData) {
40087 return $this->attemptCloneFallback();
40088 }
40089
40090 throw $e;
40091
40092 default:
40093 throw $e;
40094 }
40095 }
40096 }
40097
40098
40099
40100
40101
40102
40103
40104 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
40105 {
40106 if (!preg_match(self::URL_REGEX, $url, $match)) {
40107 return false;
40108 }
40109
40110 $scheme = !empty($match['scheme']) ? $match['scheme'] : null;
40111 $guessedDomain = !empty($match['domain']) ? $match['domain'] : $match['domain2'];
40112 $urlParts = explode('/', $match['parts']);
40113
40114 if (false === self::determineOrigin((array) $config->get('gitlab-domains'), $guessedDomain, $urlParts, $match['port'])) {
40115 return false;
40116 }
40117
40118 if ('https' === $scheme && !extension_loaded('openssl')) {
40119 $io->writeError('Skipping GitLab driver for '.$url.' because the OpenSSL PHP extension is missing.', true, IOInterface::VERBOSE);
40120
40121 return false;
40122 }
40123
40124 return true;
40125 }
40126
40127 private function getNextPage()
40128 {
40129 $headers = $this->remoteFilesystem->getLastHeaders();
40130 foreach ($headers as $header) {
40131 if (preg_match('{^link:\s*(.+?)\s*$}i', $header, $match)) {
40132 $links = explode(',', $match[1]);
40133 foreach ($links as $link) {
40134 if (preg_match('{<(.+?)>; *rel="next"}', $link, $match)) {
40135 return $match[1];
40136 }
40137 }
40138 }
40139 }
40140 }
40141
40142
40143
40144
40145
40146
40147
40148 private static function determineOrigin(array $configuredDomains, $guessedDomain, array &$urlParts, $portNumber)
40149 {
40150 $guessedDomain = strtolower($guessedDomain);
40151
40152 if (in_array($guessedDomain, $configuredDomains) || ($portNumber && in_array($guessedDomain.':'.$portNumber, $configuredDomains))) {
40153 if ($portNumber) {
40154 return $guessedDomain.':'.$portNumber;
40155 }
40156 return $guessedDomain;
40157 }
40158
40159 if ($portNumber) {
40160 $guessedDomain .= ':'.$portNumber;
40161 }
40162
40163 while (null !== ($part = array_shift($urlParts))) {
40164 $guessedDomain .= '/' . $part;
40165
40166 if (in_array($guessedDomain, $configuredDomains) || ($portNumber && in_array(preg_replace('{:\d+}', '', $guessedDomain), $configuredDomains))) {
40167 return $guessedDomain;
40168 }
40169 }
40170
40171 return false;
40172 }
40173 }
40174 <?php
40175
40176
40177
40178
40179
40180
40181
40182
40183
40184
40185
40186 namespace Composer\Repository\Vcs;
40187
40188 use Composer\Config;
40189 use Composer\IO\IOInterface;
40190
40191
40192
40193
40194 class HgBitbucketDriver extends BitbucketDriver
40195 {
40196
40197
40198
40199 public function getRootIdentifier()
40200 {
40201 if ($this->fallbackDriver) {
40202 return $this->fallbackDriver->getRootIdentifier();
40203 }
40204
40205 if (null === $this->rootIdentifier) {
40206 if (! $this->getRepoData()) {
40207 return $this->fallbackDriver->getRootIdentifier();
40208 }
40209
40210 if ($this->vcsType !== 'hg') {
40211 throw new \RuntimeException(
40212 $this->url.' does not appear to be a mercurial repository, use '.
40213 $this->cloneHttpsUrl.' if this is a git bitbucket repository'
40214 );
40215 }
40216
40217 $mainBranchData = $this->getMainBranchData();
40218 $this->rootIdentifier = !empty($mainBranchData['name']) ? $mainBranchData['name'] : 'default';
40219 }
40220
40221 return $this->rootIdentifier;
40222 }
40223
40224
40225
40226
40227 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
40228 {
40229 if (!preg_match('#^https?://bitbucket\.org/([^/]+)/([^/]+)/?$#i', $url)) {
40230 return false;
40231 }
40232
40233 if (!extension_loaded('openssl')) {
40234 $io->writeError('Skipping Bitbucket hg driver for '.$url.' because the OpenSSL PHP extension is missing.', true, IOInterface::VERBOSE);
40235
40236 return false;
40237 }
40238
40239 return true;
40240 }
40241
40242
40243
40244
40245 protected function setupFallbackDriver($url)
40246 {
40247 $this->fallbackDriver = new HgDriver(
40248 array('url' => $url),
40249 $this->io,
40250 $this->config,
40251 $this->process,
40252 $this->remoteFilesystem
40253 );
40254 $this->fallbackDriver->initialize();
40255 }
40256
40257
40258
40259
40260 protected function generateSshUrl()
40261 {
40262 return 'ssh://hg@' . $this->originUrl . '/' . $this->owner.'/'.$this->repository;
40263 }
40264 }
40265 <?php
40266
40267
40268
40269
40270
40271
40272
40273
40274
40275
40276
40277 namespace Composer\Repository\Vcs;
40278
40279 use Composer\Config;
40280 use Composer\Cache;
40281 use Composer\Util\Hg as HgUtils;
40282 use Composer\Util\ProcessExecutor;
40283 use Composer\Util\Filesystem;
40284 use Composer\IO\IOInterface;
40285
40286
40287
40288
40289 class HgDriver extends VcsDriver
40290 {
40291 protected $tags;
40292 protected $branches;
40293 protected $rootIdentifier;
40294 protected $repoDir;
40295 protected $infoCache = array();
40296
40297
40298
40299
40300 public function initialize()
40301 {
40302 if (Filesystem::isLocalPath($this->url)) {
40303 $this->repoDir = $this->url;
40304 } else {
40305 if (!Cache::isUsable($this->config->get('cache-vcs-dir'))) {
40306 throw new \RuntimeException('HgDriver requires a usable cache directory, and it looks like you set it to be disabled');
40307 }
40308
40309 $cacheDir = $this->config->get('cache-vcs-dir');
40310 $this->repoDir = $cacheDir . '/' . preg_replace('{[^a-z0-9]}i', '-', $this->url) . '/';
40311
40312 $fs = new Filesystem();
40313 $fs->ensureDirectoryExists($cacheDir);
40314
40315 if (!is_writable(dirname($this->repoDir))) {
40316 throw new \RuntimeException('Can not clone '.$this->url.' to access package information. The "'.$cacheDir.'" directory is not writable by the current user.');
40317 }
40318
40319
40320 $this->config->prohibitUrlByConfig($this->url, $this->io);
40321
40322 $hgUtils = new HgUtils($this->io, $this->config, $this->process);
40323
40324
40325 if (is_dir($this->repoDir) && 0 === $this->process->execute('hg summary', $output, $this->repoDir)) {
40326 if (0 !== $this->process->execute('hg pull', $output, $this->repoDir)) {
40327 $this->io->writeError('<error>Failed to update '.$this->url.', package information from this repository may be outdated ('.$this->process->getErrorOutput().')</error>');
40328 }
40329 } else {
40330
40331 $fs->removeDirectory($this->repoDir);
40332
40333 $repoDir = $this->repoDir;
40334 $command = function ($url) use ($repoDir) {
40335 return sprintf('hg clone --noupdate %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($repoDir));
40336 };
40337
40338 $hgUtils->runCommand($command, $this->url, null);
40339 }
40340 }
40341
40342 $this->getTags();
40343 $this->getBranches();
40344 }
40345
40346
40347
40348
40349 public function getRootIdentifier()
40350 {
40351 if (null === $this->rootIdentifier) {
40352 $this->process->execute(sprintf('hg tip --template "{node}"'), $output, $this->repoDir);
40353 $output = $this->process->splitLines($output);
40354 $this->rootIdentifier = $output[0];
40355 }
40356
40357 return $this->rootIdentifier;
40358 }
40359
40360
40361
40362
40363 public function getUrl()
40364 {
40365 return $this->url;
40366 }
40367
40368
40369
40370
40371 public function getSource($identifier)
40372 {
40373 return array('type' => 'hg', 'url' => $this->getUrl(), 'reference' => $identifier);
40374 }
40375
40376
40377
40378
40379 public function getDist($identifier)
40380 {
40381 return null;
40382 }
40383
40384
40385
40386
40387 public function getFileContent($file, $identifier)
40388 {
40389 $resource = sprintf('hg cat -r %s %s', ProcessExecutor::escape($identifier), ProcessExecutor::escape($file));
40390 $this->process->execute($resource, $content, $this->repoDir);
40391
40392 if (!trim($content)) {
40393 return;
40394 }
40395
40396 return $content;
40397 }
40398
40399
40400
40401
40402 public function getChangeDate($identifier)
40403 {
40404 $this->process->execute(
40405 sprintf(
40406 'hg log --template "{date|rfc3339date}" -r %s',
40407 ProcessExecutor::escape($identifier)
40408 ),
40409 $output,
40410 $this->repoDir
40411 );
40412
40413 return new \DateTime(trim($output), new \DateTimeZone('UTC'));
40414 }
40415
40416
40417
40418
40419 public function getTags()
40420 {
40421 if (null === $this->tags) {
40422 $tags = array();
40423
40424 $this->process->execute('hg tags', $output, $this->repoDir);
40425 foreach ($this->process->splitLines($output) as $tag) {
40426 if ($tag && preg_match('(^([^\s]+)\s+\d+:(.*)$)', $tag, $match)) {
40427 $tags[$match[1]] = $match[2];
40428 }
40429 }
40430 unset($tags['tip']);
40431
40432 $this->tags = $tags;
40433 }
40434
40435 return $this->tags;
40436 }
40437
40438
40439
40440
40441 public function getBranches()
40442 {
40443 if (null === $this->branches) {
40444 $branches = array();
40445 $bookmarks = array();
40446
40447 $this->process->execute('hg branches', $output, $this->repoDir);
40448 foreach ($this->process->splitLines($output) as $branch) {
40449 if ($branch && preg_match('(^([^\s]+)\s+\d+:([a-f0-9]+))', $branch, $match)) {
40450 $branches[$match[1]] = $match[2];
40451 }
40452 }
40453
40454 $this->process->execute('hg bookmarks', $output, $this->repoDir);
40455 foreach ($this->process->splitLines($output) as $branch) {
40456 if ($branch && preg_match('(^(?:[\s*]*)([^\s]+)\s+\d+:(.*)$)', $branch, $match)) {
40457 $bookmarks[$match[1]] = $match[2];
40458 }
40459 }
40460
40461
40462 $this->branches = array_merge($bookmarks, $branches);
40463 }
40464
40465 return $this->branches;
40466 }
40467
40468
40469
40470
40471 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
40472 {
40473 if (preg_match('#(^(?:https?|ssh)://(?:[^@]+@)?bitbucket.org|https://(?:.*?)\.kilnhg.com)#i', $url)) {
40474 return true;
40475 }
40476
40477
40478 if (Filesystem::isLocalPath($url)) {
40479 $url = Filesystem::getPlatformPath($url);
40480 if (!is_dir($url)) {
40481 return false;
40482 }
40483
40484 $process = new ProcessExecutor($io);
40485
40486 if ($process->execute('hg summary', $output, $url) === 0) {
40487 return true;
40488 }
40489 }
40490
40491 if (!$deep) {
40492 return false;
40493 }
40494
40495 $processExecutor = new ProcessExecutor($io);
40496 $exit = $processExecutor->execute(sprintf('hg identify %s', ProcessExecutor::escape($url)), $ignored);
40497
40498 return $exit === 0;
40499 }
40500 }
40501 <?php
40502
40503
40504
40505
40506
40507
40508
40509
40510
40511
40512
40513 namespace Composer\Repository\Vcs;
40514
40515 use Composer\Config;
40516 use Composer\Cache;
40517 use Composer\IO\IOInterface;
40518 use Composer\Util\ProcessExecutor;
40519 use Composer\Util\Perforce;
40520
40521
40522
40523
40524 class PerforceDriver extends VcsDriver
40525 {
40526 protected $depot;
40527 protected $branch;
40528
40529 protected $perforce;
40530
40531
40532
40533
40534 public function initialize()
40535 {
40536 $this->depot = $this->repoConfig['depot'];
40537 $this->branch = '';
40538 if (!empty($this->repoConfig['branch'])) {
40539 $this->branch = $this->repoConfig['branch'];
40540 }
40541
40542 $this->initPerforce($this->repoConfig);
40543 $this->perforce->p4Login();
40544 $this->perforce->checkStream();
40545
40546 $this->perforce->writeP4ClientSpec();
40547 $this->perforce->connectClient();
40548
40549 return true;
40550 }
40551
40552 private function initPerforce($repoConfig)
40553 {
40554 if (!empty($this->perforce)) {
40555 return;
40556 }
40557
40558 if (!Cache::isUsable($this->config->get('cache-vcs-dir'))) {
40559 throw new \RuntimeException('PerforceDriver requires a usable cache directory, and it looks like you set it to be disabled');
40560 }
40561
40562 $repoDir = $this->config->get('cache-vcs-dir') . '/' . $this->depot;
40563 $this->perforce = Perforce::create($repoConfig, $this->getUrl(), $repoDir, $this->process, $this->io);
40564 }
40565
40566
40567
40568
40569 public function getFileContent($file, $identifier)
40570 {
40571 return $this->perforce->getFileContent($file, $identifier);
40572 }
40573
40574
40575
40576
40577 public function getChangeDate($identifier)
40578 {
40579 return null;
40580 }
40581
40582
40583
40584
40585 public function getRootIdentifier()
40586 {
40587 return $this->branch;
40588 }
40589
40590
40591
40592
40593 public function getBranches()
40594 {
40595 return $this->perforce->getBranches();
40596 }
40597
40598
40599
40600
40601 public function getTags()
40602 {
40603 return $this->perforce->getTags();
40604 }
40605
40606
40607
40608
40609 public function getDist($identifier)
40610 {
40611 return null;
40612 }
40613
40614
40615
40616
40617 public function getSource($identifier)
40618 {
40619 $source = array(
40620 'type' => 'perforce',
40621 'url' => $this->repoConfig['url'],
40622 'reference' => $identifier,
40623 'p4user' => $this->perforce->getUser(),
40624 );
40625
40626 return $source;
40627 }
40628
40629
40630
40631
40632 public function getUrl()
40633 {
40634 return $this->url;
40635 }
40636
40637
40638
40639
40640 public function hasComposerFile($identifier)
40641 {
40642 $composerInfo = $this->perforce->getComposerInformation('//' . $this->depot . '/' . $identifier);
40643 $composerInfoIdentifier = $identifier;
40644
40645 return !empty($composerInfo);
40646 }
40647
40648
40649
40650
40651 public function getContents($url)
40652 {
40653 return false;
40654 }
40655
40656
40657
40658
40659 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
40660 {
40661 if ($deep || preg_match('#\b(perforce|p4)\b#i', $url)) {
40662 return Perforce::checkServerExists($url, new ProcessExecutor($io));
40663 }
40664
40665 return false;
40666 }
40667
40668
40669
40670
40671 public function cleanup()
40672 {
40673 $this->perforce->cleanupClientSpec();
40674 $this->perforce = null;
40675 }
40676
40677 public function getDepot()
40678 {
40679 return $this->depot;
40680 }
40681
40682 public function getBranch()
40683 {
40684 return $this->branch;
40685 }
40686 }
40687 <?php
40688
40689
40690
40691
40692
40693
40694
40695
40696
40697
40698
40699 namespace Composer\Repository\Vcs;
40700
40701 use Composer\Cache;
40702 use Composer\Config;
40703 use Composer\Json\JsonFile;
40704 use Composer\Util\ProcessExecutor;
40705 use Composer\Util\Filesystem;
40706 use Composer\Util\Svn as SvnUtil;
40707 use Composer\IO\IOInterface;
40708 use Composer\Downloader\TransportException;
40709
40710
40711
40712
40713
40714 class SvnDriver extends VcsDriver
40715 {
40716
40717
40718
40719 protected $cache;
40720 protected $baseUrl;
40721 protected $tags;
40722 protected $branches;
40723 protected $rootIdentifier;
40724 protected $infoCache = array();
40725
40726 protected $trunkPath = 'trunk';
40727 protected $branchesPath = 'branches';
40728 protected $tagsPath = 'tags';
40729 protected $packagePath = '';
40730 protected $cacheCredentials = true;
40731
40732
40733
40734
40735 private $util;
40736
40737
40738
40739
40740 public function initialize()
40741 {
40742 $this->url = $this->baseUrl = rtrim(self::normalizeUrl($this->url), '/');
40743
40744 SvnUtil::cleanEnv();
40745
40746 if (isset($this->repoConfig['trunk-path'])) {
40747 $this->trunkPath = $this->repoConfig['trunk-path'];
40748 }
40749 if (isset($this->repoConfig['branches-path'])) {
40750 $this->branchesPath = $this->repoConfig['branches-path'];
40751 }
40752 if (isset($this->repoConfig['tags-path'])) {
40753 $this->tagsPath = $this->repoConfig['tags-path'];
40754 }
40755 if (array_key_exists('svn-cache-credentials', $this->repoConfig)) {
40756 $this->cacheCredentials = (bool) $this->repoConfig['svn-cache-credentials'];
40757 }
40758 if (isset($this->repoConfig['package-path'])) {
40759 $this->packagePath = '/' . trim($this->repoConfig['package-path'], '/');
40760 }
40761
40762 if (false !== ($pos = strrpos($this->url, '/' . $this->trunkPath))) {
40763 $this->baseUrl = substr($this->url, 0, $pos);
40764 }
40765
40766 $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $this->baseUrl));
40767
40768 $this->getBranches();
40769 $this->getTags();
40770 }
40771
40772
40773
40774
40775 public function getRootIdentifier()
40776 {
40777 return $this->rootIdentifier ?: $this->trunkPath;
40778 }
40779
40780
40781
40782
40783 public function getUrl()
40784 {
40785 return $this->url;
40786 }
40787
40788
40789
40790
40791 public function getSource($identifier)
40792 {
40793 return array('type' => 'svn', 'url' => $this->baseUrl, 'reference' => $identifier);
40794 }
40795
40796
40797
40798
40799 public function getDist($identifier)
40800 {
40801 return null;
40802 }
40803
40804
40805
40806
40807 protected function shouldCache($identifier)
40808 {
40809 return $this->cache && preg_match('{@\d+$}', $identifier);
40810 }
40811
40812
40813
40814
40815 public function getComposerInformation($identifier)
40816 {
40817 if (!isset($this->infoCache[$identifier])) {
40818 if ($this->shouldCache($identifier) && $res = $this->cache->read($identifier.'.json')) {
40819 return $this->infoCache[$identifier] = JsonFile::parseJson($res);
40820 }
40821
40822 try {
40823 $composer = $this->getBaseComposerInformation($identifier);
40824 } catch (TransportException $e) {
40825 $message = $e->getMessage();
40826 if (stripos($message, 'path not found') === false && stripos($message, 'svn: warning: W160013') === false) {
40827 throw $e;
40828 }
40829
40830 $composer = '';
40831 }
40832
40833 if ($this->shouldCache($identifier)) {
40834 $this->cache->write($identifier.'.json', json_encode($composer));
40835 }
40836
40837 $this->infoCache[$identifier] = $composer;
40838 }
40839
40840 return $this->infoCache[$identifier];
40841 }
40842
40843
40844
40845
40846
40847 public function getFileContent($file, $identifier)
40848 {
40849 $identifier = '/' . trim($identifier, '/') . '/';
40850
40851 preg_match('{^(.+?)(@\d+)?/$}', $identifier, $match);
40852 if (!empty($match[2])) {
40853 $path = $match[1];
40854 $rev = $match[2];
40855 } else {
40856 $path = $identifier;
40857 $rev = '';
40858 }
40859
40860 try {
40861 $resource = $path.$file;
40862 $output = $this->execute('svn cat', $this->baseUrl . $resource . $rev);
40863 if (!trim($output)) {
40864 return null;
40865 }
40866 } catch (\RuntimeException $e) {
40867 throw new TransportException($e->getMessage());
40868 }
40869
40870 return $output;
40871 }
40872
40873
40874
40875
40876 public function getChangeDate($identifier)
40877 {
40878 $identifier = '/' . trim($identifier, '/') . '/';
40879
40880 preg_match('{^(.+?)(@\d+)?/$}', $identifier, $match);
40881 if (!empty($match[2])) {
40882 $path = $match[1];
40883 $rev = $match[2];
40884 } else {
40885 $path = $identifier;
40886 $rev = '';
40887 }
40888
40889 $output = $this->execute('svn info', $this->baseUrl . $path . $rev);
40890 foreach ($this->process->splitLines($output) as $line) {
40891 if ($line && preg_match('{^Last Changed Date: ([^(]+)}', $line, $match)) {
40892 return new \DateTime($match[1], new \DateTimeZone('UTC'));
40893 }
40894 }
40895
40896 return null;
40897 }
40898
40899
40900
40901
40902 public function getTags()
40903 {
40904 if (null === $this->tags) {
40905 $this->tags = array();
40906
40907 if ($this->tagsPath !== false) {
40908 $output = $this->execute('svn ls --verbose', $this->baseUrl . '/' . $this->tagsPath);
40909 if ($output) {
40910 foreach ($this->process->splitLines($output) as $line) {
40911 $line = trim($line);
40912 if ($line && preg_match('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) {
40913 if (isset($match[1]) && isset($match[2]) && $match[2] !== './') {
40914 $this->tags[rtrim($match[2], '/')] = $this->buildIdentifier(
40915 '/' . $this->tagsPath . '/' . $match[2],
40916 $match[1]
40917 );
40918 }
40919 }
40920 }
40921 }
40922 }
40923 }
40924
40925 return $this->tags;
40926 }
40927
40928
40929
40930
40931 public function getBranches()
40932 {
40933 if (null === $this->branches) {
40934 $this->branches = array();
40935
40936 if (false === $this->trunkPath) {
40937 $trunkParent = $this->baseUrl . '/';
40938 } else {
40939 $trunkParent = $this->baseUrl . '/' . $this->trunkPath;
40940 }
40941
40942 $output = $this->execute('svn ls --verbose', $trunkParent);
40943 if ($output) {
40944 foreach ($this->process->splitLines($output) as $line) {
40945 $line = trim($line);
40946 if ($line && preg_match('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) {
40947 if (isset($match[1]) && isset($match[2]) && $match[2] === './') {
40948 $this->branches['trunk'] = $this->buildIdentifier(
40949 '/' . $this->trunkPath,
40950 $match[1]
40951 );
40952 $this->rootIdentifier = $this->branches['trunk'];
40953 break;
40954 }
40955 }
40956 }
40957 }
40958 unset($output);
40959
40960 if ($this->branchesPath !== false) {
40961 $output = $this->execute('svn ls --verbose', $this->baseUrl . '/' . $this->branchesPath);
40962 if ($output) {
40963 foreach ($this->process->splitLines(trim($output)) as $line) {
40964 $line = trim($line);
40965 if ($line && preg_match('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) {
40966 if (isset($match[1]) && isset($match[2]) && $match[2] !== './') {
40967 $this->branches[rtrim($match[2], '/')] = $this->buildIdentifier(
40968 '/' . $this->branchesPath . '/' . $match[2],
40969 $match[1]
40970 );
40971 }
40972 }
40973 }
40974 }
40975 }
40976 }
40977
40978 return $this->branches;
40979 }
40980
40981
40982
40983
40984 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
40985 {
40986 $url = self::normalizeUrl($url);
40987 if (preg_match('#(^svn://|^svn\+ssh://|svn\.)#i', $url)) {
40988 return true;
40989 }
40990
40991
40992 if (!$deep && !Filesystem::isLocalPath($url)) {
40993 return false;
40994 }
40995
40996 $processExecutor = new ProcessExecutor($io);
40997
40998 $exit = $processExecutor->execute(
40999 "svn info --non-interactive ".ProcessExecutor::escape($url),
41000 $ignoredOutput
41001 );
41002
41003 if ($exit === 0) {
41004
41005 return true;
41006 }
41007
41008
41009 if (false !== stripos($processExecutor->getErrorOutput(), 'authorization failed:')) {
41010
41011
41012 return true;
41013 }
41014
41015
41016 if (false !== stripos($processExecutor->getErrorOutput(), 'Authentication failed')) {
41017
41018
41019 return true;
41020 }
41021
41022 return false;
41023 }
41024
41025
41026
41027
41028
41029
41030
41031
41032 protected static function normalizeUrl($url)
41033 {
41034 $fs = new Filesystem();
41035 if ($fs->isAbsolutePath($url)) {
41036 return 'file://' . strtr($url, '\\', '/');
41037 }
41038
41039 return $url;
41040 }
41041
41042
41043
41044
41045
41046
41047
41048
41049
41050
41051 protected function execute($command, $url)
41052 {
41053 if (null === $this->util) {
41054 $this->util = new SvnUtil($this->baseUrl, $this->io, $this->config, $this->process);
41055 $this->util->setCacheCredentials($this->cacheCredentials);
41056 }
41057
41058 try {
41059 return $this->util->execute($command, $url);
41060 } catch (\RuntimeException $e) {
41061 if (null === $this->util->binaryVersion()) {
41062 throw new \RuntimeException('Failed to load '.$this->url.', svn was not found, check that it is installed and in your PATH env.' . "\n\n" . $this->process->getErrorOutput());
41063 }
41064
41065 throw new \RuntimeException(
41066 'Repository '.$this->url.' could not be processed, '.$e->getMessage()
41067 );
41068 }
41069 }
41070
41071
41072
41073
41074
41075
41076
41077
41078
41079 protected function buildIdentifier($baseDir, $revision)
41080 {
41081 return rtrim($baseDir, '/') . $this->packagePath . '/@' . $revision;
41082 }
41083 }
41084 <?php
41085
41086
41087
41088
41089
41090
41091
41092
41093
41094
41095
41096 namespace Composer\Repository\Vcs;
41097
41098 use Composer\Cache;
41099 use Composer\Downloader\TransportException;
41100 use Composer\Config;
41101 use Composer\Factory;
41102 use Composer\IO\IOInterface;
41103 use Composer\Json\JsonFile;
41104 use Composer\Util\ProcessExecutor;
41105 use Composer\Util\RemoteFilesystem;
41106 use Composer\Util\Filesystem;
41107
41108
41109
41110
41111
41112
41113 abstract class VcsDriver implements VcsDriverInterface
41114 {
41115
41116 protected $url;
41117
41118 protected $originUrl;
41119
41120 protected $repoConfig;
41121
41122 protected $io;
41123
41124 protected $config;
41125
41126 protected $process;
41127
41128 protected $remoteFilesystem;
41129
41130 protected $infoCache = array();
41131
41132 protected $cache;
41133
41134
41135
41136
41137
41138
41139
41140
41141
41142
41143 final public function __construct(array $repoConfig, IOInterface $io, Config $config, ProcessExecutor $process = null, RemoteFilesystem $remoteFilesystem = null)
41144 {
41145 if (Filesystem::isLocalPath($repoConfig['url'])) {
41146 $repoConfig['url'] = Filesystem::getPlatformPath($repoConfig['url']);
41147 }
41148
41149 $this->url = $repoConfig['url'];
41150 $this->originUrl = $repoConfig['url'];
41151 $this->repoConfig = $repoConfig;
41152 $this->io = $io;
41153 $this->config = $config;
41154 $this->process = $process ?: new ProcessExecutor($io);
41155 $this->remoteFilesystem = $remoteFilesystem ?: Factory::createRemoteFilesystem($this->io, $config);
41156 }
41157
41158
41159
41160
41161
41162
41163
41164 protected function shouldCache($identifier)
41165 {
41166 return $this->cache && preg_match('{[a-f0-9]{40}}i', $identifier);
41167 }
41168
41169
41170
41171
41172 public function getComposerInformation($identifier)
41173 {
41174 if (!isset($this->infoCache[$identifier])) {
41175 if ($this->shouldCache($identifier) && $res = $this->cache->read($identifier)) {
41176 return $this->infoCache[$identifier] = JsonFile::parseJson($res);
41177 }
41178
41179 $composer = $this->getBaseComposerInformation($identifier);
41180
41181 if ($this->shouldCache($identifier)) {
41182 $this->cache->write($identifier, json_encode($composer));
41183 }
41184
41185 $this->infoCache[$identifier] = $composer;
41186 }
41187
41188 return $this->infoCache[$identifier];
41189 }
41190
41191 protected function getBaseComposerInformation($identifier)
41192 {
41193 $composerFileContent = $this->getFileContent('composer.json', $identifier);
41194
41195 if (!$composerFileContent) {
41196 return null;
41197 }
41198
41199 $composer = JsonFile::parseJson($composerFileContent, $identifier . ':composer.json');
41200
41201 if (empty($composer['time']) && $changeDate = $this->getChangeDate($identifier)) {
41202 $composer['time'] = $changeDate->format(DATE_RFC3339);
41203 }
41204
41205 return $composer;
41206 }
41207
41208
41209
41210
41211 public function hasComposerFile($identifier)
41212 {
41213 try {
41214 return (bool) $this->getComposerInformation($identifier);
41215 } catch (TransportException $e) {
41216 }
41217
41218 return false;
41219 }
41220
41221
41222
41223
41224
41225
41226
41227
41228 protected function getScheme()
41229 {
41230 if (extension_loaded('openssl')) {
41231 return 'https';
41232 }
41233
41234 return 'http';
41235 }
41236
41237
41238
41239
41240
41241
41242
41243
41244 protected function getContents($url)
41245 {
41246 $options = isset($this->repoConfig['options']) ? $this->repoConfig['options'] : array();
41247
41248 return $this->remoteFilesystem->getContents($this->originUrl, $url, false, $options);
41249 }
41250
41251
41252
41253
41254 public function cleanup()
41255 {
41256 return;
41257 }
41258 }
41259 <?php
41260
41261
41262
41263
41264
41265
41266
41267
41268
41269
41270
41271 namespace Composer\Repository\Vcs;
41272
41273 use Composer\Config;
41274 use Composer\IO\IOInterface;
41275
41276
41277
41278
41279 interface VcsDriverInterface
41280 {
41281
41282
41283
41284 public function initialize();
41285
41286
41287
41288
41289
41290
41291
41292 public function getComposerInformation($identifier);
41293
41294
41295
41296
41297
41298
41299
41300
41301 public function getFileContent($file, $identifier);
41302
41303
41304
41305
41306
41307
41308
41309 public function getChangeDate($identifier);
41310
41311
41312
41313
41314
41315
41316 public function getRootIdentifier();
41317
41318
41319
41320
41321
41322
41323 public function getBranches();
41324
41325
41326
41327
41328
41329
41330 public function getTags();
41331
41332
41333
41334
41335
41336 public function getDist($identifier);
41337
41338
41339
41340
41341
41342 public function getSource($identifier);
41343
41344
41345
41346
41347
41348
41349 public function getUrl();
41350
41351
41352
41353
41354
41355
41356
41357
41358 public function hasComposerFile($identifier);
41359
41360
41361
41362
41363 public function cleanup();
41364
41365
41366
41367
41368
41369
41370
41371
41372
41373
41374 public static function supports(IOInterface $io, Config $config, $url, $deep = false);
41375 }
41376 <?php
41377
41378
41379
41380
41381
41382
41383
41384
41385
41386
41387
41388 namespace Composer\Repository;
41389
41390 use Composer\Downloader\TransportException;
41391 use Composer\Repository\Vcs\VcsDriverInterface;
41392 use Composer\Package\Version\VersionParser;
41393 use Composer\Package\Loader\ArrayLoader;
41394 use Composer\Package\Loader\ValidatingArrayLoader;
41395 use Composer\Package\Loader\InvalidPackageException;
41396 use Composer\Package\Loader\LoaderInterface;
41397 use Composer\EventDispatcher\EventDispatcher;
41398 use Composer\Semver\Constraint\Constraint;
41399 use Composer\IO\IOInterface;
41400 use Composer\Config;
41401
41402
41403
41404
41405 class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInterface
41406 {
41407 protected $url;
41408 protected $packageName;
41409 protected $isVerbose;
41410 protected $isVeryVerbose;
41411 protected $io;
41412 protected $config;
41413 protected $versionParser;
41414 protected $type;
41415 protected $loader;
41416 protected $repoConfig;
41417 protected $branchErrorOccurred = false;
41418 private $drivers;
41419
41420 private $driver;
41421
41422 private $versionCache;
41423 private $emptyReferences = array();
41424 private $versionTransportExceptions = array();
41425
41426 public function __construct(array $repoConfig, IOInterface $io, Config $config, EventDispatcher $dispatcher = null, array $drivers = null, VersionCacheInterface $versionCache = null)
41427 {
41428 parent::__construct();
41429 $this->drivers = $drivers ?: array(
41430 'github' => 'Composer\Repository\Vcs\GitHubDriver',
41431 'gitlab' => 'Composer\Repository\Vcs\GitLabDriver',
41432 'git-bitbucket' => 'Composer\Repository\Vcs\GitBitbucketDriver',
41433 'git' => 'Composer\Repository\Vcs\GitDriver',
41434 'hg-bitbucket' => 'Composer\Repository\Vcs\HgBitbucketDriver',
41435 'hg' => 'Composer\Repository\Vcs\HgDriver',
41436 'perforce' => 'Composer\Repository\Vcs\PerforceDriver',
41437 'fossil' => 'Composer\Repository\Vcs\FossilDriver',
41438
41439 'svn' => 'Composer\Repository\Vcs\SvnDriver',
41440 );
41441
41442 $this->url = $repoConfig['url'];
41443 $this->io = $io;
41444 $this->type = isset($repoConfig['type']) ? $repoConfig['type'] : 'vcs';
41445 $this->isVerbose = $io->isVerbose();
41446 $this->isVeryVerbose = $io->isVeryVerbose();
41447 $this->config = $config;
41448 $this->repoConfig = $repoConfig;
41449 $this->versionCache = $versionCache;
41450 }
41451
41452 public function getRepoConfig()
41453 {
41454 return $this->repoConfig;
41455 }
41456
41457 public function setLoader(LoaderInterface $loader)
41458 {
41459 $this->loader = $loader;
41460 }
41461
41462 public function getDriver()
41463 {
41464 if ($this->driver) {
41465 return $this->driver;
41466 }
41467
41468 if (isset($this->drivers[$this->type])) {
41469 $class = $this->drivers[$this->type];
41470 $this->driver = new $class($this->repoConfig, $this->io, $this->config);
41471 $this->driver->initialize();
41472
41473 return $this->driver;
41474 }
41475
41476 foreach ($this->drivers as $driver) {
41477 if ($driver::supports($this->io, $this->config, $this->url)) {
41478 $this->driver = new $driver($this->repoConfig, $this->io, $this->config);
41479 $this->driver->initialize();
41480
41481 return $this->driver;
41482 }
41483 }
41484
41485 foreach ($this->drivers as $driver) {
41486 if ($driver::supports($this->io, $this->config, $this->url, true)) {
41487 $this->driver = new $driver($this->repoConfig, $this->io, $this->config);
41488 $this->driver->initialize();
41489
41490 return $this->driver;
41491 }
41492 }
41493 }
41494
41495 public function hadInvalidBranches()
41496 {
41497 return $this->branchErrorOccurred;
41498 }
41499
41500 public function getEmptyReferences()
41501 {
41502 return $this->emptyReferences;
41503 }
41504
41505 public function getVersionTransportExceptions()
41506 {
41507 return $this->versionTransportExceptions;
41508 }
41509
41510 protected function initialize()
41511 {
41512 parent::initialize();
41513
41514 $isVerbose = $this->isVerbose;
41515 $isVeryVerbose = $this->isVeryVerbose;
41516
41517 $driver = $this->getDriver();
41518 if (!$driver) {
41519 throw new \InvalidArgumentException('No driver found to handle VCS repository '.$this->url);
41520 }
41521
41522 $this->versionParser = new VersionParser;
41523 if (!$this->loader) {
41524 $this->loader = new ArrayLoader($this->versionParser);
41525 }
41526
41527 try {
41528 if ($driver->hasComposerFile($driver->getRootIdentifier())) {
41529 $data = $driver->getComposerInformation($driver->getRootIdentifier());
41530 $this->packageName = !empty($data['name']) ? $data['name'] : null;
41531 }
41532 } catch (\Exception $e) {
41533 if ($isVeryVerbose) {
41534 $this->io->writeError('<error>Skipped parsing '.$driver->getRootIdentifier().', '.$e->getMessage().'</error>');
41535 }
41536 }
41537
41538 foreach ($driver->getTags() as $tag => $identifier) {
41539 $msg = 'Reading composer.json of <info>' . ($this->packageName ?: $this->url) . '</info> (<comment>' . $tag . '</comment>)';
41540 if ($isVeryVerbose) {
41541 $this->io->writeError($msg);
41542 } elseif ($isVerbose) {
41543 $this->io->overwriteError($msg, false);
41544 }
41545
41546
41547 $tag = str_replace('release-', '', $tag);
41548
41549 $cachedPackage = $this->getCachedPackageVersion($tag, $identifier, $isVerbose, $isVeryVerbose);
41550 if ($cachedPackage) {
41551 $this->addPackage($cachedPackage);
41552
41553 continue;
41554 } elseif ($cachedPackage === false) {
41555 $this->emptyReferences[] = $identifier;
41556
41557 continue;
41558 }
41559
41560 if (!$parsedTag = $this->validateTag($tag)) {
41561 if ($isVeryVerbose) {
41562 $this->io->writeError('<warning>Skipped tag '.$tag.', invalid tag name</warning>');
41563 }
41564 continue;
41565 }
41566
41567 try {
41568 if (!$data = $driver->getComposerInformation($identifier)) {
41569 if ($isVeryVerbose) {
41570 $this->io->writeError('<warning>Skipped tag '.$tag.', no composer file</warning>');
41571 }
41572 $this->emptyReferences[] = $identifier;
41573 continue;
41574 }
41575
41576
41577 if (isset($data['version'])) {
41578 $data['version_normalized'] = $this->versionParser->normalize($data['version']);
41579 } else {
41580
41581 $data['version'] = $tag;
41582 $data['version_normalized'] = $parsedTag;
41583 }
41584
41585
41586 $data['version'] = preg_replace('{[.-]?dev$}i', '', $data['version']);
41587 $data['version_normalized'] = preg_replace('{(^dev-|[.-]?dev$)}i', '', $data['version_normalized']);
41588
41589
41590 if ($data['version_normalized'] !== $parsedTag) {
41591 if ($isVeryVerbose) {
41592 if (preg_match('{(^dev-|[.-]?dev$)}i', $parsedTag)) {
41593 $this->io->writeError('<warning>Skipped tag '.$tag.', invalid tag name, tags can not use dev prefixes or suffixes</warning>');
41594 } else {
41595 $this->io->writeError('<warning>Skipped tag '.$tag.', tag ('.$parsedTag.') does not match version ('.$data['version_normalized'].') in composer.json</warning>');
41596 }
41597 }
41598 continue;
41599 }
41600
41601 $tagPackageName = isset($data['name']) ? $data['name'] : $this->packageName;
41602 if ($existingPackage = $this->findPackage($tagPackageName, $data['version_normalized'])) {
41603 if ($isVeryVerbose) {
41604 $this->io->writeError('<warning>Skipped tag '.$tag.', it conflicts with an another tag ('.$existingPackage->getPrettyVersion().') as both resolve to '.$data['version_normalized'].' internally</warning>');
41605 }
41606 continue;
41607 }
41608
41609 if ($isVeryVerbose) {
41610 $this->io->writeError('Importing tag '.$tag.' ('.$data['version_normalized'].')');
41611 }
41612
41613 $this->addPackage($this->loader->load($this->preProcess($driver, $data, $identifier)));
41614 } catch (\Exception $e) {
41615 if ($e instanceof TransportException) {
41616 $this->versionTransportExceptions['tags'][$tag] = $e;
41617 if ($e->getCode() === 404) {
41618 $this->emptyReferences[] = $identifier;
41619 }
41620 }
41621 if ($isVeryVerbose) {
41622 $this->io->writeError('<warning>Skipped tag '.$tag.', '.($e instanceof TransportException ? 'no composer file was found (' . $e->getCode() . ' HTTP status code)' : $e->getMessage()).'</warning>');
41623 }
41624 continue;
41625 }
41626 }
41627
41628 if (!$isVeryVerbose) {
41629 $this->io->overwriteError('', false);
41630 }
41631
41632 $branches = $driver->getBranches();
41633 foreach ($branches as $branch => $identifier) {
41634 $msg = 'Reading composer.json of <info>' . ($this->packageName ?: $this->url) . '</info> (<comment>' . $branch . '</comment>)';
41635 if ($isVeryVerbose) {
41636 $this->io->writeError($msg);
41637 } elseif ($isVerbose) {
41638 $this->io->overwriteError($msg, false);
41639 }
41640
41641 if ($branch === 'trunk' && isset($branches['master'])) {
41642 if ($isVeryVerbose) {
41643 $this->io->writeError('<warning>Skipped branch '.$branch.', can not parse both master and trunk branches as they both resolve to 9999999-dev internally</warning>');
41644 }
41645 continue;
41646 }
41647
41648 if (!$parsedBranch = $this->validateBranch($branch)) {
41649 if ($isVeryVerbose) {
41650 $this->io->writeError('<warning>Skipped branch '.$branch.', invalid name</warning>');
41651 }
41652 continue;
41653 }
41654
41655
41656 if ('dev-' === substr($parsedBranch, 0, 4) || '9999999-dev' === $parsedBranch) {
41657 $version = 'dev-' . $branch;
41658 } else {
41659 $prefix = substr($branch, 0, 1) === 'v' ? 'v' : '';
41660 $version = $prefix . preg_replace('{(\.9{7})+}', '.x', $parsedBranch);
41661 }
41662
41663 $cachedPackage = $this->getCachedPackageVersion($version, $identifier, $isVerbose, $isVeryVerbose);
41664 if ($cachedPackage) {
41665 $this->addPackage($cachedPackage);
41666
41667 continue;
41668 } elseif ($cachedPackage === false) {
41669 $this->emptyReferences[] = $identifier;
41670
41671 continue;
41672 }
41673
41674 try {
41675 if (!$data = $driver->getComposerInformation($identifier)) {
41676 if ($isVeryVerbose) {
41677 $this->io->writeError('<warning>Skipped branch '.$branch.', no composer file</warning>');
41678 }
41679 $this->emptyReferences[] = $identifier;
41680 continue;
41681 }
41682
41683
41684 $data['version'] = $version;
41685 $data['version_normalized'] = $parsedBranch;
41686
41687 if ($isVeryVerbose) {
41688 $this->io->writeError('Importing branch '.$branch.' ('.$data['version'].')');
41689 }
41690
41691 $packageData = $this->preProcess($driver, $data, $identifier);
41692 $package = $this->loader->load($packageData);
41693 if ($this->loader instanceof ValidatingArrayLoader && $this->loader->getWarnings()) {
41694 throw new InvalidPackageException($this->loader->getErrors(), $this->loader->getWarnings(), $packageData);
41695 }
41696 $this->addPackage($package);
41697 } catch (TransportException $e) {
41698 $this->versionTransportExceptions['branches'][$branch] = $e;
41699 if ($e->getCode() === 404) {
41700 $this->emptyReferences[] = $identifier;
41701 }
41702 if ($isVeryVerbose) {
41703 $this->io->writeError('<warning>Skipped branch '.$branch.', no composer file was found (' . $e->getCode() . ' HTTP status code)</warning>');
41704 }
41705 continue;
41706 } catch (\Exception $e) {
41707 if (!$isVeryVerbose) {
41708 $this->io->writeError('');
41709 }
41710 $this->branchErrorOccurred = true;
41711 $this->io->writeError('<error>Skipped branch '.$branch.', '.$e->getMessage().'</error>');
41712 $this->io->writeError('');
41713 continue;
41714 }
41715 }
41716 $driver->cleanup();
41717
41718 if (!$isVeryVerbose) {
41719 $this->io->overwriteError('', false);
41720 }
41721
41722 if (!$this->getPackages()) {
41723 throw new InvalidRepositoryException('No valid composer.json was found in any branch or tag of '.$this->url.', could not load a package from it.');
41724 }
41725 }
41726
41727 protected function preProcess(VcsDriverInterface $driver, array $data, $identifier)
41728 {
41729
41730 $dataPackageName = isset($data['name']) ? $data['name'] : null;
41731 $data['name'] = $this->packageName ?: $dataPackageName;
41732
41733 if (!isset($data['dist'])) {
41734 $data['dist'] = $driver->getDist($identifier);
41735 }
41736 if (!isset($data['source'])) {
41737 $data['source'] = $driver->getSource($identifier);
41738 }
41739
41740 return $data;
41741 }
41742
41743 private function validateBranch($branch)
41744 {
41745 try {
41746 $normalizedBranch = $this->versionParser->normalizeBranch($branch);
41747
41748
41749 $this->versionParser->parseConstraints($normalizedBranch);
41750
41751 return $normalizedBranch;
41752 } catch (\Exception $e) {
41753 }
41754
41755 return false;
41756 }
41757
41758 private function validateTag($version)
41759 {
41760 try {
41761 return $this->versionParser->normalize($version);
41762 } catch (\Exception $e) {
41763 }
41764
41765 return false;
41766 }
41767
41768 private function getCachedPackageVersion($version, $identifier, $isVerbose, $isVeryVerbose)
41769 {
41770 if (!$this->versionCache) {
41771 return;
41772 }
41773
41774 $cachedPackage = $this->versionCache->getVersionPackage($version, $identifier);
41775 if ($cachedPackage === false) {
41776 if ($isVeryVerbose) {
41777 $this->io->writeError('<warning>Skipped '.$version.', no composer file (cached from ref '.$identifier.')</warning>');
41778 }
41779
41780 return false;
41781 }
41782
41783 if ($cachedPackage) {
41784 $msg = 'Found cached composer.json of <info>' . ($this->packageName ?: $this->url) . '</info> (<comment>' . $version . '</comment>)';
41785 if ($isVeryVerbose) {
41786 $this->io->writeError($msg);
41787 } elseif ($isVerbose) {
41788 $this->io->overwriteError($msg, false);
41789 }
41790
41791 if ($existingPackage = $this->findPackage($cachedPackage['name'], new Constraint('=', $cachedPackage['version_normalized']))) {
41792 if ($isVeryVerbose) {
41793 $this->io->writeError('<warning>Skipped cached version '.$version.', it conflicts with an another tag ('.$existingPackage->getPrettyVersion().') as both resolve to '.$cachedPackage['version_normalized'].' internally</warning>');
41794 }
41795 $cachedPackage = null;
41796 }
41797 }
41798
41799 if ($cachedPackage) {
41800 return $this->loader->load($cachedPackage);
41801 }
41802
41803 return null;
41804 }
41805 }
41806 <?php
41807
41808
41809
41810
41811
41812
41813
41814
41815
41816
41817
41818 namespace Composer\Repository;
41819
41820 interface VersionCacheInterface
41821 {
41822
41823
41824
41825
41826
41827 public function getVersionPackage($version, $identifier);
41828 }
41829 <?php
41830
41831
41832
41833
41834
41835
41836
41837
41838
41839
41840
41841 namespace Composer\Repository;
41842
41843 use Composer\Package\AliasPackage;
41844
41845
41846
41847
41848
41849
41850 class WritableArrayRepository extends ArrayRepository implements WritableRepositoryInterface
41851 {
41852
41853
41854
41855 public function write()
41856 {
41857 }
41858
41859
41860
41861
41862 public function reload()
41863 {
41864 }
41865
41866
41867
41868
41869 public function getCanonicalPackages()
41870 {
41871 $packages = $this->getPackages();
41872
41873
41874 $packagesByName = array();
41875 foreach ($packages as $package) {
41876 if (!isset($packagesByName[$package->getName()]) || $packagesByName[$package->getName()] instanceof AliasPackage) {
41877 $packagesByName[$package->getName()] = $package;
41878 }
41879 }
41880
41881 $canonicalPackages = array();
41882
41883
41884 foreach ($packagesByName as $package) {
41885 while ($package instanceof AliasPackage) {
41886 $package = $package->getAliasOf();
41887 }
41888
41889 $canonicalPackages[] = $package;
41890 }
41891
41892 return $canonicalPackages;
41893 }
41894 }
41895 <?php
41896
41897
41898
41899
41900
41901
41902
41903
41904
41905
41906
41907 namespace Composer\Repository;
41908
41909 use Composer\Package\PackageInterface;
41910
41911
41912
41913
41914
41915
41916 interface WritableRepositoryInterface extends RepositoryInterface
41917 {
41918
41919
41920
41921 public function write();
41922
41923
41924
41925
41926
41927
41928 public function addPackage(PackageInterface $package);
41929
41930
41931
41932
41933
41934
41935 public function removePackage(PackageInterface $package);
41936
41937
41938
41939
41940
41941
41942 public function getCanonicalPackages();
41943
41944
41945
41946
41947 public function reload();
41948 }
41949 <?php
41950
41951
41952
41953
41954
41955
41956
41957
41958
41959
41960
41961 namespace Composer\Script;
41962
41963
41964
41965
41966
41967
41968 class CommandEvent extends Event
41969 {
41970 }
41971 <?php
41972
41973
41974
41975
41976
41977
41978
41979
41980
41981
41982
41983 namespace Composer\Script;
41984
41985 use Composer\Composer;
41986 use Composer\IO\IOInterface;
41987 use Composer\EventDispatcher\Event as BaseEvent;
41988
41989
41990
41991
41992
41993
41994
41995 class Event extends BaseEvent
41996 {
41997
41998
41999
42000 private $composer;
42001
42002
42003
42004
42005 private $io;
42006
42007
42008
42009
42010 private $devMode;
42011
42012
42013
42014
42015 private $originatingEvent;
42016
42017
42018
42019
42020
42021
42022
42023
42024
42025
42026
42027 public function __construct($name, Composer $composer, IOInterface $io, $devMode = false, array $args = array(), array $flags = array())
42028 {
42029 parent::__construct($name, $args, $flags);
42030 $this->composer = $composer;
42031 $this->io = $io;
42032 $this->devMode = $devMode;
42033 $this->originatingEvent = null;
42034 }
42035
42036
42037
42038
42039
42040
42041 public function getComposer()
42042 {
42043 return $this->composer;
42044 }
42045
42046
42047
42048
42049
42050
42051 public function getIO()
42052 {
42053 return $this->io;
42054 }
42055
42056
42057
42058
42059
42060
42061 public function isDevMode()
42062 {
42063 return $this->devMode;
42064 }
42065
42066
42067
42068
42069
42070
42071 public function getOriginatingEvent()
42072 {
42073 return $this->originatingEvent;
42074 }
42075
42076
42077
42078
42079
42080
42081
42082 public function setOriginatingEvent(BaseEvent $event)
42083 {
42084 $this->originatingEvent = $this->calculateOriginatingEvent($event);
42085
42086 return $this;
42087 }
42088
42089
42090
42091
42092
42093
42094
42095 private function calculateOriginatingEvent(BaseEvent $event)
42096 {
42097 if ($event instanceof Event && $event->getOriginatingEvent()) {
42098 return $this->calculateOriginatingEvent($event->getOriginatingEvent());
42099 }
42100
42101 return $event;
42102 }
42103 }
42104 <?php
42105
42106
42107
42108
42109
42110
42111
42112
42113
42114
42115
42116 namespace Composer\Script;
42117
42118 use Composer\Installer\PackageEvent as BasePackageEvent;
42119
42120
42121
42122
42123
42124
42125 class PackageEvent extends BasePackageEvent
42126 {
42127 }
42128 <?php
42129
42130
42131
42132
42133
42134
42135
42136
42137
42138
42139
42140 namespace Composer\Script;
42141
42142
42143
42144
42145
42146
42147
42148 class ScriptEvents
42149 {
42150
42151
42152
42153
42154
42155
42156
42157 const PRE_INSTALL_CMD = 'pre-install-cmd';
42158
42159
42160
42161
42162
42163
42164
42165
42166 const POST_INSTALL_CMD = 'post-install-cmd';
42167
42168
42169
42170
42171
42172
42173
42174
42175 const PRE_UPDATE_CMD = 'pre-update-cmd';
42176
42177
42178
42179
42180
42181
42182
42183
42184 const POST_UPDATE_CMD = 'post-update-cmd';
42185
42186
42187
42188
42189
42190
42191
42192
42193 const PRE_STATUS_CMD = 'pre-status-cmd';
42194
42195
42196
42197
42198
42199
42200
42201
42202 const POST_STATUS_CMD = 'post-status-cmd';
42203
42204
42205
42206
42207
42208
42209
42210
42211 const PRE_AUTOLOAD_DUMP = 'pre-autoload-dump';
42212
42213
42214
42215
42216
42217
42218
42219
42220 const POST_AUTOLOAD_DUMP = 'post-autoload-dump';
42221
42222
42223
42224
42225
42226
42227
42228
42229 const POST_ROOT_PACKAGE_INSTALL = 'post-root-package-install';
42230
42231
42232
42233
42234
42235
42236
42237
42238
42239 const POST_CREATE_PROJECT_CMD = 'post-create-project-cmd';
42240
42241
42242
42243
42244
42245
42246
42247
42248 const PRE_ARCHIVE_CMD = 'pre-archive-cmd';
42249
42250
42251
42252
42253
42254
42255
42256
42257 const POST_ARCHIVE_CMD = 'post-archive-cmd';
42258
42259
42260
42261
42262
42263
42264
42265
42266
42267
42268
42269 const PRE_PACKAGE_INSTALL = 'pre-package-install';
42270
42271
42272
42273
42274
42275
42276
42277
42278
42279 const POST_PACKAGE_INSTALL = 'post-package-install';
42280
42281
42282
42283
42284
42285
42286
42287
42288
42289 const PRE_PACKAGE_UPDATE = 'pre-package-update';
42290
42291
42292
42293
42294
42295
42296
42297
42298
42299 const POST_PACKAGE_UPDATE = 'post-package-update';
42300
42301
42302
42303
42304
42305
42306
42307
42308
42309 const PRE_PACKAGE_UNINSTALL = 'pre-package-uninstall';
42310
42311
42312
42313
42314
42315
42316
42317
42318
42319 const POST_PACKAGE_UNINSTALL = 'post-package-uninstall';
42320 }
42321 <?php
42322
42323
42324
42325
42326
42327
42328
42329
42330
42331
42332
42333 namespace Composer\SelfUpdate;
42334
42335
42336
42337
42338 class Keys
42339 {
42340 public static function fingerprint($path)
42341 {
42342 $hash = strtoupper(hash('sha256', preg_replace('{\s}', '', file_get_contents($path))));
42343
42344 return implode(' ', array(
42345 substr($hash, 0, 8),
42346 substr($hash, 8, 8),
42347 substr($hash, 16, 8),
42348 substr($hash, 24, 8),
42349 '', 
42350 substr($hash, 32, 8),
42351 substr($hash, 40, 8),
42352 substr($hash, 48, 8),
42353 substr($hash, 56, 8),
42354 ));
42355 }
42356 }
42357 <?php
42358
42359
42360
42361
42362
42363
42364
42365
42366
42367
42368
42369 namespace Composer\SelfUpdate;
42370
42371 use Composer\Util\RemoteFilesystem;
42372 use Composer\Config;
42373 use Composer\Json\JsonFile;
42374
42375
42376
42377
42378 class Versions
42379 {
42380 public static $channels = array('stable', 'preview', 'snapshot', '1', '2');
42381
42382 private $rfs;
42383 private $config;
42384 private $channel;
42385 private $versionsData;
42386
42387 public function __construct(Config $config, RemoteFilesystem $rfs)
42388 {
42389 $this->rfs = $rfs;
42390 $this->config = $config;
42391 }
42392
42393 public function getChannel()
42394 {
42395 if ($this->channel) {
42396 return $this->channel;
42397 }
42398
42399 $channelFile = $this->config->get('home').'/update-channel';
42400 if (file_exists($channelFile)) {
42401 $channel = trim(file_get_contents($channelFile));
42402 if (in_array($channel, array('stable', 'preview', 'snapshot'), true)) {
42403 return $this->channel = $channel;
42404 }
42405 }
42406
42407 return $this->channel = 'stable';
42408 }
42409
42410 public function setChannel($channel)
42411 {
42412 if (!in_array($channel, self::$channels, true)) {
42413 throw new \InvalidArgumentException('Invalid channel '.$channel.', must be one of: ' . implode(', ', self::$channels));
42414 }
42415
42416 $channelFile = $this->config->get('home').'/update-channel';
42417 $this->channel = $channel;
42418 file_put_contents($channelFile, (is_numeric($channel) ? 'stable' : $channel).PHP_EOL);
42419 }
42420
42421 public function getLatest($channel = null)
42422 {
42423 $versions = $this->getVersionsData();
42424
42425 foreach ($versions[$channel ?: $this->getChannel()] as $version) {
42426 if ($version['min-php'] <= PHP_VERSION_ID) {
42427 return $version;
42428 }
42429 }
42430
42431 throw new \UnexpectedValueException('There is no version of Composer available for your PHP version ('.PHP_VERSION.')');
42432 }
42433
42434 private function getVersionsData()
42435 {
42436 if (!$this->versionsData) {
42437 if ($this->config->get('disable-tls') === true) {
42438 $protocol = 'http';
42439 } else {
42440 $protocol = 'https';
42441 }
42442
42443 $this->versionsData = JsonFile::parseJson($this->rfs->getContents('getcomposer.org', $protocol . '://getcomposer.org/versions', false));
42444 }
42445
42446 return $this->versionsData;
42447 }
42448 }
42449 <?php
42450
42451
42452
42453
42454
42455
42456
42457
42458
42459
42460
42461 namespace Composer\Util;
42462
42463 use Composer\Config;
42464 use Composer\IO\IOInterface;
42465
42466
42467
42468
42469 class AuthHelper
42470 {
42471 protected $io;
42472 protected $config;
42473
42474 public function __construct(IOInterface $io, Config $config)
42475 {
42476 $this->io = $io;
42477 $this->config = $config;
42478 }
42479
42480 public function storeAuth($originUrl, $storeAuth)
42481 {
42482 $store = false;
42483 $configSource = $this->config->getAuthConfigSource();
42484 if ($storeAuth === true) {
42485 $store = $configSource;
42486 } elseif ($storeAuth === 'prompt') {
42487 $answer = $this->io->askAndValidate(
42488 'Do you want to store credentials for '.$originUrl.' in '.$configSource->getName().' ? [Yn] ',
42489 function ($value) {
42490 $input = strtolower(substr(trim($value), 0, 1));
42491 if (in_array($input, array('y','n'))) {
42492 return $input;
42493 }
42494 throw new \RuntimeException('Please answer (y)es or (n)o');
42495 },
42496 null,
42497 'y'
42498 );
42499
42500 if ($answer === 'y') {
42501 $store = $configSource;
42502 }
42503 }
42504 if ($store) {
42505 $store->addConfigSetting(
42506 'http-basic.'.$originUrl,
42507 $this->io->getAuthentication($originUrl)
42508 );
42509 }
42510 }
42511 }
42512 <?php
42513
42514
42515
42516
42517
42518
42519
42520
42521
42522
42523
42524 namespace Composer\Util;
42525
42526 use Composer\Factory;
42527 use Composer\IO\IOInterface;
42528 use Composer\Config;
42529 use Composer\Downloader\TransportException;
42530
42531
42532
42533
42534 class Bitbucket
42535 {
42536 private $io;
42537 private $config;
42538 private $process;
42539 private $remoteFilesystem;
42540 private $token = array();
42541 private $time;
42542
42543 const OAUTH2_ACCESS_TOKEN_URL = 'https://bitbucket.org/site/oauth2/access_token';
42544
42545
42546
42547
42548
42549
42550
42551
42552
42553
42554 public function __construct(IOInterface $io, Config $config, ProcessExecutor $process = null, RemoteFilesystem $remoteFilesystem = null, $time = null)
42555 {
42556 $this->io = $io;
42557 $this->config = $config;
42558 $this->process = $process ?: new ProcessExecutor($io);
42559 $this->remoteFilesystem = $remoteFilesystem ?: Factory::createRemoteFilesystem($this->io, $config);
42560 $this->time = $time;
42561 }
42562
42563
42564
42565
42566 public function getToken()
42567 {
42568 if (!isset($this->token['access_token'])) {
42569 return '';
42570 }
42571
42572 return $this->token['access_token'];
42573 }
42574
42575
42576
42577
42578
42579
42580
42581 public function authorizeOAuth($originUrl)
42582 {
42583 if ($originUrl !== 'bitbucket.org') {
42584 return false;
42585 }
42586
42587
42588 if (0 === $this->process->execute('git config bitbucket.accesstoken', $output)) {
42589 $this->io->setAuthentication($originUrl, 'x-token-auth', trim($output));
42590
42591 return true;
42592 }
42593
42594 return false;
42595 }
42596
42597
42598
42599
42600
42601 private function requestAccessToken($originUrl)
42602 {
42603 try {
42604 $json = $this->remoteFilesystem->getContents($originUrl, self::OAUTH2_ACCESS_TOKEN_URL, false, array(
42605 'retry-auth-failure' => false,
42606 'http' => array(
42607 'method' => 'POST',
42608 'content' => 'grant_type=client_credentials',
42609 ),
42610 ));
42611
42612 $this->token = json_decode($json, true);
42613 } catch (TransportException $e) {
42614 if ($e->getCode() === 400) {
42615 $this->io->writeError('<error>Invalid OAuth consumer provided.</error>');
42616 $this->io->writeError('This can have two reasons:');
42617 $this->io->writeError('1. You are authenticating with a bitbucket username/password combination');
42618 $this->io->writeError('2. You are using an OAuth consumer, but didn\'t configure a (dummy) callback url');
42619
42620 return false;
42621 } elseif (in_array($e->getCode(), array(403, 401))) {
42622 $this->io->writeError('<error>Invalid OAuth consumer provided.</error>');
42623 $this->io->writeError('You can also add it manually later by using "composer config --global --auth bitbucket-oauth.bitbucket.org <consumer-key> <consumer-secret>"');
42624
42625 return false;
42626 }
42627
42628 throw $e;
42629 }
42630
42631 return true;
42632 }
42633
42634
42635
42636
42637
42638
42639
42640
42641
42642
42643 public function authorizeOAuthInteractively($originUrl, $message = null)
42644 {
42645 if ($message) {
42646 $this->io->writeError($message);
42647 }
42648
42649 $url = 'https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/';
42650 $this->io->writeError(sprintf('Follow the instructions on %s', $url));
42651 $this->io->writeError(sprintf('to create a consumer. It will be stored in "%s" for future use by Composer.', $this->config->getAuthConfigSource()->getName()));
42652 $this->io->writeError('Ensure you enter a "Callback URL" (http://example.com is fine) or it will not be possible to create an Access Token (this callback url will not be used by composer)');
42653
42654 $consumerKey = trim($this->io->askAndHideAnswer('Consumer Key (hidden): '));
42655
42656 if (!$consumerKey) {
42657 $this->io->writeError('<warning>No consumer key given, aborting.</warning>');
42658 $this->io->writeError('You can also add it manually later by using "composer config --global --auth bitbucket-oauth.bitbucket.org <consumer-key> <consumer-secret>"');
42659
42660 return false;
42661 }
42662
42663 $consumerSecret = trim($this->io->askAndHideAnswer('Consumer Secret (hidden): '));
42664
42665 if (!$consumerSecret) {
42666 $this->io->writeError('<warning>No consumer secret given, aborting.</warning>');
42667 $this->io->writeError('You can also add it manually later by using "composer config --global --auth bitbucket-oauth.bitbucket.org <consumer-key> <consumer-secret>"');
42668
42669 return false;
42670 }
42671
42672 $this->io->setAuthentication($originUrl, $consumerKey, $consumerSecret);
42673
42674 if (!$this->requestAccessToken($originUrl)) {
42675 return false;
42676 }
42677
42678
42679 $this->storeInAuthConfig($originUrl, $consumerKey, $consumerSecret);
42680
42681
42682 $this->config->getAuthConfigSource()->removeConfigSetting('http-basic.' . $originUrl);
42683
42684 $this->io->writeError('<info>Consumer stored successfully.</info>');
42685
42686 return true;
42687 }
42688
42689
42690
42691
42692
42693
42694
42695
42696
42697 public function requestToken($originUrl, $consumerKey, $consumerSecret)
42698 {
42699 if (!empty($this->token) || $this->getTokenFromConfig($originUrl)) {
42700 return $this->token['access_token'];
42701 }
42702
42703 $this->io->setAuthentication($originUrl, $consumerKey, $consumerSecret);
42704 if (!$this->requestAccessToken($originUrl)) {
42705 return '';
42706 }
42707
42708 $this->storeInAuthConfig($originUrl, $consumerKey, $consumerSecret);
42709
42710 return $this->token['access_token'];
42711 }
42712
42713
42714
42715
42716
42717
42718
42719 private function storeInAuthConfig($originUrl, $consumerKey, $consumerSecret)
42720 {
42721 $this->config->getConfigSource()->removeConfigSetting('bitbucket-oauth.'.$originUrl);
42722
42723 $time = null === $this->time ? time() : $this->time;
42724 $consumer = array(
42725 "consumer-key" => $consumerKey,
42726 "consumer-secret" => $consumerSecret,
42727 "access-token" => $this->token['access_token'],
42728 "access-token-expiration" => $time + $this->token['expires_in'],
42729 );
42730
42731 $this->config->getAuthConfigSource()->addConfigSetting('bitbucket-oauth.'.$originUrl, $consumer);
42732 }
42733
42734
42735
42736
42737
42738 private function getTokenFromConfig($originUrl)
42739 {
42740 $authConfig = $this->config->get('bitbucket-oauth');
42741
42742 if (
42743 !isset($authConfig[$originUrl]['access-token'])
42744 || !isset($authConfig[$originUrl]['access-token-expiration'])
42745 || time() > $authConfig[$originUrl]['access-token-expiration']
42746 ) {
42747 return false;
42748 }
42749
42750 $this->token = array(
42751 'access_token' => $authConfig[$originUrl]['access-token'],
42752 );
42753
42754 return true;
42755 }
42756 }
42757 <?php
42758
42759
42760
42761
42762
42763
42764
42765
42766
42767
42768
42769 namespace Composer\Util;
42770
42771
42772
42773
42774
42775
42776 class ComposerMirror
42777 {
42778 public static function processUrl($mirrorUrl, $packageName, $version, $reference, $type)
42779 {
42780 if ($reference) {
42781 $reference = preg_match('{^([a-f0-9]*|%reference%)$}', $reference) ? $reference : md5($reference);
42782 }
42783 $version = strpos($version, '/') === false ? $version : md5($version);
42784
42785 return str_replace(
42786 array('%package%', '%version%', '%reference%', '%type%'),
42787 array($packageName, $version, $reference, $type),
42788 $mirrorUrl
42789 );
42790 }
42791
42792 public static function processGitUrl($mirrorUrl, $packageName, $url, $type)
42793 {
42794 if (preg_match('#^(?:(?:https?|git)://github\.com/|git@github\.com:)([^/]+)/(.+?)(?:\.git)?$#', $url, $match)) {
42795 $url = 'gh-'.$match[1].'/'.$match[2];
42796 } elseif (preg_match('#^https://bitbucket\.org/([^/]+)/(.+?)(?:\.git)?/?$#', $url, $match)) {
42797 $url = 'bb-'.$match[1].'/'.$match[2];
42798 } else {
42799 $url = preg_replace('{[^a-z0-9_.-]}i', '-', trim($url, '/'));
42800 }
42801
42802 return str_replace(
42803 array('%package%', '%normalizedUrl%', '%type%'),
42804 array($packageName, $url, $type),
42805 $mirrorUrl
42806 );
42807 }
42808
42809 public static function processHgUrl($mirrorUrl, $packageName, $url, $type)
42810 {
42811 return self::processGitUrl($mirrorUrl, $packageName, $url, $type);
42812 }
42813 }
42814 <?php
42815
42816
42817
42818
42819
42820
42821
42822
42823
42824
42825
42826 namespace Composer\Util;
42827
42828 use Composer\Package\Loader\ArrayLoader;
42829 use Composer\Package\Loader\ValidatingArrayLoader;
42830 use Composer\Package\Loader\InvalidPackageException;
42831 use Composer\Json\JsonValidationException;
42832 use Composer\IO\IOInterface;
42833 use Composer\Json\JsonFile;
42834 use Composer\Spdx\SpdxLicenses;
42835
42836
42837
42838
42839
42840
42841
42842 class ConfigValidator
42843 {
42844 private $io;
42845
42846 public function __construct(IOInterface $io)
42847 {
42848 $this->io = $io;
42849 }
42850
42851
42852
42853
42854
42855
42856
42857
42858
42859 public function validate($file, $arrayLoaderValidationFlags = ValidatingArrayLoader::CHECK_ALL)
42860 {
42861 $errors = array();
42862 $publishErrors = array();
42863 $warnings = array();
42864
42865
42866 $laxValid = false;
42867 try {
42868 $json = new JsonFile($file, null, $this->io);
42869 $manifest = $json->read();
42870
42871 $json->validateSchema(JsonFile::LAX_SCHEMA);
42872 $laxValid = true;
42873 $json->validateSchema();
42874 } catch (JsonValidationException $e) {
42875 foreach ($e->getErrors() as $message) {
42876 if ($laxValid) {
42877 $publishErrors[] = $message;
42878 } else {
42879 $errors[] = $message;
42880 }
42881 }
42882 } catch (\Exception $e) {
42883 $errors[] = $e->getMessage();
42884
42885 return array($errors, $publishErrors, $warnings);
42886 }
42887
42888
42889 if (empty($manifest['license'])) {
42890 $warnings[] = 'No license specified, it is recommended to do so. For closed-source software you may use "proprietary" as license.';
42891 } else {
42892 $licenses = (array) $manifest['license'];
42893
42894
42895 foreach ($licenses as $key => $license) {
42896 if ('proprietary' === $license) {
42897 unset($licenses[$key]);
42898 }
42899 }
42900
42901 $licenseValidator = new SpdxLicenses();
42902 foreach ($licenses as $license) {
42903 $spdxLicense = $licenseValidator->getLicenseByIdentifier($license);
42904 if ($spdxLicense && $spdxLicense[3]) {
42905 if (preg_match('{^[AL]?GPL-[123](\.[01])?\+$}i', $license)) {
42906 $warnings[] = sprintf(
42907 'License "%s" is a deprecated SPDX license identifier, use "'.str_replace('+', '', $license).'-or-later" instead',
42908 $license
42909 );
42910 } elseif (preg_match('{^[AL]?GPL-[123](\.[01])?$}i', $license)) {
42911 $warnings[] = sprintf(
42912 'License "%s" is a deprecated SPDX license identifier, use "'.$license.'-only" or "'.$license.'-or-later" instead',
42913 $license
42914 );
42915 } else {
42916 $warnings[] = sprintf(
42917 'License "%s" is a deprecated SPDX license identifier, see https://spdx.org/licenses/',
42918 $license
42919 );
42920 }
42921 }
42922 }
42923 }
42924
42925 if (isset($manifest['version'])) {
42926 $warnings[] = 'The version field is present, it is recommended to leave it out if the package is published on Packagist.';
42927 }
42928
42929 if (!empty($manifest['name']) && preg_match('{[A-Z]}', $manifest['name'])) {
42930 $suggestName = preg_replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $manifest['name']);
42931 $suggestName = strtolower($suggestName);
42932
42933 $publishErrors[] = sprintf(
42934 'Name "%s" does not match the best practice (e.g. lower-cased/with-dashes). We suggest using "%s" instead. As such you will not be able to submit it to Packagist.',
42935 $manifest['name'],
42936 $suggestName
42937 );
42938 }
42939
42940 if (!empty($manifest['type']) && $manifest['type'] == 'composer-installer') {
42941 $warnings[] = "The package type 'composer-installer' is deprecated. Please distribute your custom installers as plugins from now on. See https://getcomposer.org/doc/articles/plugins.md for plugin documentation.";
42942 }
42943
42944
42945 if (isset($manifest['require']) && isset($manifest['require-dev'])) {
42946 $requireOverrides = array_intersect_key($manifest['require'], $manifest['require-dev']);
42947
42948 if (!empty($requireOverrides)) {
42949 $plural = (count($requireOverrides) > 1) ? 'are' : 'is';
42950 $warnings[] = implode(', ', array_keys($requireOverrides)). " {$plural} required both in require and require-dev, this can lead to unexpected behavior";
42951 }
42952 }
42953
42954
42955
42956 foreach (array('provide', 'replace') as $linkType) {
42957 if (isset($manifest[$linkType])) {
42958 foreach (array('require', 'require-dev') as $requireType) {
42959 if (isset($manifest[$requireType])) {
42960 foreach ($manifest[$linkType] as $provide => $constraint) {
42961 if (isset($manifest[$requireType][$provide])) {
42962 $warnings[] = 'The package ' . $provide . ' in '.$requireType.' is also listed in '.$linkType.' which satisfies the requirement. Remove it from '.$linkType.' if you wish to install it.';
42963 }
42964 }
42965 }
42966 }
42967 }
42968 }
42969
42970
42971 $require = isset($manifest['require']) ? $manifest['require'] : array();
42972 $requireDev = isset($manifest['require-dev']) ? $manifest['require-dev'] : array();
42973 $packages = array_merge($require, $requireDev);
42974 foreach ($packages as $package => $version) {
42975 if (preg_match('/#/', $version) === 1) {
42976 $warnings[] = sprintf(
42977 'The package "%s" is pointing to a commit-ref, this is bad practice and can cause unforeseen issues.',
42978 $package
42979 );
42980 }
42981 }
42982
42983
42984 $scriptsDescriptions = isset($manifest['scripts-descriptions']) ? $manifest['scripts-descriptions'] : array();
42985 $scripts = isset($manifest['scripts']) ? $manifest['scripts'] : array();
42986 foreach ($scriptsDescriptions as $scriptName => $scriptDescription) {
42987 if (!array_key_exists($scriptName, $scripts)) {
42988 $warnings[] = sprintf(
42989 'Description for non-existent script "%s" found in "scripts-descriptions"',
42990 $scriptName
42991 );
42992 }
42993 }
42994
42995
42996 if (isset($manifest['autoload']['psr-0'][''])) {
42997 $warnings[] = "Defining autoload.psr-0 with an empty namespace prefix is a bad idea for performance";
42998 }
42999 if (isset($manifest['autoload']['psr-4'][''])) {
43000 $warnings[] = "Defining autoload.psr-4 with an empty namespace prefix is a bad idea for performance";
43001 }
43002
43003 try {
43004 $loader = new ValidatingArrayLoader(new ArrayLoader(), true, null, $arrayLoaderValidationFlags);
43005 if (!isset($manifest['version'])) {
43006 $manifest['version'] = '1.0.0';
43007 }
43008 if (!isset($manifest['name'])) {
43009 $manifest['name'] = 'dummy/dummy';
43010 }
43011 $loader->load($manifest);
43012 } catch (InvalidPackageException $e) {
43013 $errors = array_merge($errors, $e->getErrors());
43014 }
43015
43016 $warnings = array_merge($warnings, $loader->getWarnings());
43017
43018 return array($errors, $publishErrors, $warnings);
43019 }
43020 }
43021 <?php
43022
43023
43024
43025
43026
43027
43028
43029
43030
43031
43032
43033 namespace Composer\Util;
43034
43035 use Composer\IO\IOInterface;
43036
43037
43038
43039
43040
43041
43042 class ErrorHandler
43043 {
43044 private static $io;
43045
43046
43047
43048
43049
43050
43051
43052
43053
43054
43055
43056
43057
43058 public static function handle($level, $message, $file, $line)
43059 {
43060
43061 if (!(error_reporting() & $level)) {
43062 return;
43063 }
43064
43065 if (filter_var(ini_get('xdebug.scream'), FILTER_VALIDATE_BOOLEAN)) {
43066 $message .= "\n\nWarning: You have xdebug.scream enabled, the warning above may be".
43067 "\na legitimately suppressed error that you were not supposed to see.";
43068 }
43069
43070 if ($level !== E_DEPRECATED && $level !== E_USER_DEPRECATED) {
43071 throw new \ErrorException($message, 0, $level, $file, $line);
43072 }
43073
43074 if (self::$io) {
43075 self::$io->writeError('<warning>Deprecation Notice: '.$message.' in '.$file.':'.$line.'</warning>');
43076 if (self::$io->isVerbose()) {
43077 self::$io->writeError('<warning>Stack trace:</warning>');
43078 self::$io->writeError(array_filter(array_map(function ($a) {
43079 if (isset($a['line'], $a['file'])) {
43080 return '<warning> '.$a['file'].':'.$a['line'].'</warning>';
43081 }
43082
43083 return null;
43084 }, array_slice(debug_backtrace(), 2))));
43085 }
43086 }
43087
43088 return true;
43089 }
43090
43091
43092
43093
43094
43095
43096 public static function register(IOInterface $io = null)
43097 {
43098 set_error_handler(array(__CLASS__, 'handle'));
43099 error_reporting(E_ALL | E_STRICT);
43100 self::$io = $io;
43101 }
43102 }
43103 <?php
43104
43105
43106
43107
43108
43109
43110
43111
43112
43113
43114
43115 namespace Composer\Util;
43116
43117 use RecursiveDirectoryIterator;
43118 use RecursiveIteratorIterator;
43119 use Symfony\Component\Filesystem\Exception\IOException;
43120 use Symfony\Component\Finder\Finder;
43121
43122
43123
43124
43125
43126 class Filesystem
43127 {
43128 private $processExecutor;
43129
43130 public function __construct(ProcessExecutor $executor = null)
43131 {
43132 $this->processExecutor = $executor ?: new ProcessExecutor();
43133 }
43134
43135 public function remove($file)
43136 {
43137 if (is_dir($file)) {
43138 return $this->removeDirectory($file);
43139 }
43140
43141 if (file_exists($file)) {
43142 return $this->unlink($file);
43143 }
43144
43145 return false;
43146 }
43147
43148
43149
43150
43151
43152
43153
43154 public function isDirEmpty($dir)
43155 {
43156 $finder = Finder::create()
43157 ->ignoreVCS(false)
43158 ->ignoreDotFiles(false)
43159 ->depth(0)
43160 ->in($dir);
43161
43162 return count($finder) === 0;
43163 }
43164
43165 public function emptyDirectory($dir, $ensureDirectoryExists = true)
43166 {
43167 if (file_exists($dir) && is_link($dir)) {
43168 $this->unlink($dir);
43169 }
43170
43171 if ($ensureDirectoryExists) {
43172 $this->ensureDirectoryExists($dir);
43173 }
43174
43175 if (is_dir($dir)) {
43176 $finder = Finder::create()
43177 ->ignoreVCS(false)
43178 ->ignoreDotFiles(false)
43179 ->depth(0)
43180 ->in($dir);
43181
43182 foreach ($finder as $path) {
43183 $this->remove((string) $path);
43184 }
43185 }
43186 }
43187
43188
43189
43190
43191
43192
43193
43194
43195
43196
43197
43198 public function removeDirectory($directory)
43199 {
43200 if ($this->isSymlinkedDirectory($directory)) {
43201 return $this->unlinkSymlinkedDirectory($directory);
43202 }
43203
43204 if ($this->isJunction($directory)) {
43205 return $this->removeJunction($directory);
43206 }
43207
43208 if (is_link($directory)) {
43209 return unlink($directory);
43210 }
43211
43212 if (!file_exists($directory) || !is_dir($directory)) {
43213 return true;
43214 }
43215
43216 if (preg_match('{^(?:[a-z]:)?[/\\\\]+$}i', $directory)) {
43217 throw new \RuntimeException('Aborting an attempted deletion of '.$directory.', this was probably not intended, if it is a real use case please report it.');
43218 }
43219
43220 if (!function_exists('proc_open')) {
43221 return $this->removeDirectoryPhp($directory);
43222 }
43223
43224 if (Platform::isWindows()) {
43225 $cmd = sprintf('rmdir /S /Q %s', ProcessExecutor::escape(realpath($directory)));
43226 } else {
43227 $cmd = sprintf('rm -rf %s', ProcessExecutor::escape($directory));
43228 }
43229
43230 $result = $this->getProcess()->execute($cmd, $output) === 0;
43231
43232
43233 clearstatcache();
43234
43235 if ($result && !file_exists($directory)) {
43236 return true;
43237 }
43238
43239 return $this->removeDirectoryPhp($directory);
43240 }
43241
43242
43243
43244
43245
43246
43247
43248
43249
43250
43251
43252 public function removeDirectoryPhp($directory)
43253 {
43254 try {
43255 $it = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS);
43256 } catch (\UnexpectedValueException $e) {
43257
43258
43259 clearstatcache();
43260 usleep(100000);
43261 if (!is_dir($directory)) {
43262 return true;
43263 }
43264 $it = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS);
43265 }
43266 $ri = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
43267
43268 foreach ($ri as $file) {
43269 if ($file->isDir()) {
43270 $this->rmdir($file->getPathname());
43271 } else {
43272 $this->unlink($file->getPathname());
43273 }
43274 }
43275
43276 return $this->rmdir($directory);
43277 }
43278
43279 public function ensureDirectoryExists($directory)
43280 {
43281 if (!is_dir($directory)) {
43282 if (file_exists($directory)) {
43283 throw new \RuntimeException(
43284 $directory.' exists and is not a directory.'
43285 );
43286 }
43287 if (!@mkdir($directory, 0777, true)) {
43288 throw new \RuntimeException(
43289 $directory.' does not exist and could not be created.'
43290 );
43291 }
43292 }
43293 }
43294
43295
43296
43297
43298
43299
43300
43301
43302 public function unlink($path)
43303 {
43304 $unlinked = @$this->unlinkImplementation($path);
43305 if (!$unlinked) {
43306
43307 if (Platform::isWindows()) {
43308 usleep(350000);
43309 $unlinked = @$this->unlinkImplementation($path);
43310 }
43311
43312 if (!$unlinked) {
43313 $error = error_get_last();
43314 $message = 'Could not delete '.$path.': ' . @$error['message'];
43315 if (Platform::isWindows()) {
43316 $message .= "\nThis can be due to an antivirus or the Windows Search Indexer locking the file while they are analyzed";
43317 }
43318
43319 throw new \RuntimeException($message);
43320 }
43321 }
43322
43323 return true;
43324 }
43325
43326
43327
43328
43329
43330
43331
43332
43333 public function rmdir($path)
43334 {
43335 $deleted = @rmdir($path);
43336 if (!$deleted) {
43337
43338 if (Platform::isWindows()) {
43339 usleep(350000);
43340 $deleted = @rmdir($path);
43341 }
43342
43343 if (!$deleted) {
43344 $error = error_get_last();
43345 $message = 'Could not delete '.$path.': ' . @$error['message'];
43346 if (Platform::isWindows()) {
43347 $message .= "\nThis can be due to an antivirus or the Windows Search Indexer locking the file while they are analyzed";
43348 }
43349
43350 throw new \RuntimeException($message);
43351 }
43352 }
43353
43354 return true;
43355 }
43356
43357
43358
43359
43360
43361
43362
43363
43364
43365
43366 public function copyThenRemove($source, $target)
43367 {
43368 $this->copy($source, $target);
43369 if (!is_dir($source)) {
43370 $this->unlink($source);
43371
43372 return;
43373 }
43374
43375 $this->removeDirectoryPhp($source);
43376 }
43377
43378
43379
43380
43381
43382
43383
43384
43385 public function copy($source, $target)
43386 {
43387 if (!is_dir($source)) {
43388 return copy($source, $target);
43389 }
43390
43391 $it = new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS);
43392 $ri = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::SELF_FIRST);
43393 $this->ensureDirectoryExists($target);
43394
43395 $result = true;
43396 foreach ($ri as $file) {
43397 $targetPath = $target . DIRECTORY_SEPARATOR . $ri->getSubPathName();
43398 if ($file->isDir()) {
43399 $this->ensureDirectoryExists($targetPath);
43400 } else {
43401 $result = $result && copy($file->getPathname(), $targetPath);
43402 }
43403 }
43404
43405 return $result;
43406 }
43407
43408 public function rename($source, $target)
43409 {
43410 if (true === @rename($source, $target)) {
43411 return;
43412 }
43413
43414 if (!function_exists('proc_open')) {
43415 $this->copyThenRemove($source, $target);
43416
43417 return;
43418 }
43419
43420 if (Platform::isWindows()) {
43421
43422 $command = sprintf('xcopy %s %s /E /I /Q /Y', ProcessExecutor::escape($source), ProcessExecutor::escape($target));
43423 $result = $this->processExecutor->execute($command, $output);
43424
43425
43426 clearstatcache();
43427
43428 if (0 === $result) {
43429 $this->remove($source);
43430
43431 return;
43432 }
43433 } else {
43434
43435
43436 $command = sprintf('mv %s %s', ProcessExecutor::escape($source), ProcessExecutor::escape($target));
43437 $result = $this->processExecutor->execute($command, $output);
43438
43439
43440 clearstatcache();
43441
43442 if (0 === $result) {
43443 return;
43444 }
43445 }
43446
43447 $this->copyThenRemove($source, $target);
43448 }
43449
43450
43451
43452
43453
43454
43455
43456
43457
43458
43459 public function findShortestPath($from, $to, $directories = false)
43460 {
43461 if (!$this->isAbsolutePath($from) || !$this->isAbsolutePath($to)) {
43462 throw new \InvalidArgumentException(sprintf('$from (%s) and $to (%s) must be absolute paths.', $from, $to));
43463 }
43464
43465 $from = lcfirst($this->normalizePath($from));
43466 $to = lcfirst($this->normalizePath($to));
43467
43468 if ($directories) {
43469 $from = rtrim($from, '/') . '/dummy_file';
43470 }
43471
43472 if (dirname($from) === dirname($to)) {
43473 return './'.basename($to);
43474 }
43475
43476 $commonPath = $to;
43477 while (strpos($from.'/', $commonPath.'/') !== 0 && '/' !== $commonPath && !preg_match('{^[a-z]:/?$}i', $commonPath)) {
43478 $commonPath = strtr(dirname($commonPath), '\\', '/');
43479 }
43480
43481 if (0 !== strpos($from, $commonPath) || '/' === $commonPath) {
43482 return $to;
43483 }
43484
43485 $commonPath = rtrim($commonPath, '/') . '/';
43486 $sourcePathDepth = substr_count(substr($from, strlen($commonPath)), '/');
43487 $commonPathCode = str_repeat('../', $sourcePathDepth);
43488
43489 return ($commonPathCode . substr($to, strlen($commonPath))) ?: './';
43490 }
43491
43492
43493
43494
43495
43496
43497
43498
43499
43500
43501
43502 public function findShortestPathCode($from, $to, $directories = false, $staticCode = false)
43503 {
43504 if (!$this->isAbsolutePath($from) || !$this->isAbsolutePath($to)) {
43505 throw new \InvalidArgumentException(sprintf('$from (%s) and $to (%s) must be absolute paths.', $from, $to));
43506 }
43507
43508 $from = lcfirst($this->normalizePath($from));
43509 $to = lcfirst($this->normalizePath($to));
43510
43511 if ($from === $to) {
43512 return $directories ? '__DIR__' : '__FILE__';
43513 }
43514
43515 $commonPath = $to;
43516 while (strpos($from.'/', $commonPath.'/') !== 0 && '/' !== $commonPath && !preg_match('{^[a-z]:/?$}i', $commonPath) && '.' !== $commonPath) {
43517 $commonPath = strtr(dirname($commonPath), '\\', '/');
43518 }
43519
43520 if (0 !== strpos($from, $commonPath) || '/' === $commonPath || '.' === $commonPath) {
43521 return var_export($to, true);
43522 }
43523
43524 $commonPath = rtrim($commonPath, '/') . '/';
43525 if (strpos($to, $from.'/') === 0) {
43526 return '__DIR__ . '.var_export(substr($to, strlen($from)), true);
43527 }
43528 $sourcePathDepth = substr_count(substr($from, strlen($commonPath)), '/') + $directories;
43529 if ($staticCode) {
43530 $commonPathCode = "__DIR__ . '".str_repeat('/..', $sourcePathDepth)."'";
43531 } else {
43532 $commonPathCode = str_repeat('dirname(', $sourcePathDepth).'__DIR__'.str_repeat(')', $sourcePathDepth);
43533 }
43534 $relTarget = substr($to, strlen($commonPath));
43535
43536 return $commonPathCode . (strlen($relTarget) ? '.' . var_export('/' . $relTarget, true) : '');
43537 }
43538
43539
43540
43541
43542
43543
43544
43545 public function isAbsolutePath($path)
43546 {
43547 return substr($path, 0, 1) === '/' || substr($path, 1, 1) === ':' || substr($path, 0, 2) === '\\\\';
43548 }
43549
43550
43551
43552
43553
43554
43555
43556
43557
43558 public function size($path)
43559 {
43560 if (!file_exists($path)) {
43561 throw new \RuntimeException("$path does not exist.");
43562 }
43563 if (is_dir($path)) {
43564 return $this->directorySize($path);
43565 }
43566
43567 return filesize($path);
43568 }
43569
43570
43571
43572
43573
43574
43575
43576
43577 public function normalizePath($path)
43578 {
43579 $parts = array();
43580 $path = strtr($path, '\\', '/');
43581 $prefix = '';
43582 $absolute = false;
43583
43584
43585 if (preg_match('{^( [0-9a-z]{2,}+: (?: // (?: [a-z]: )? )? | [a-z]: )}ix', $path, $match)) {
43586 $prefix = $match[1];
43587 $path = substr($path, strlen($prefix));
43588 }
43589
43590 if (substr($path, 0, 1) === '/') {
43591 $absolute = true;
43592 $path = substr($path, 1);
43593 }
43594
43595 $up = false;
43596 foreach (explode('/', $path) as $chunk) {
43597 if ('..' === $chunk && ($absolute || $up)) {
43598 array_pop($parts);
43599 $up = !(empty($parts) || '..' === end($parts));
43600 } elseif ('.' !== $chunk && '' !== $chunk) {
43601 $parts[] = $chunk;
43602 $up = '..' !== $chunk;
43603 }
43604 }
43605
43606 return $prefix.($absolute ? '/' : '').implode('/', $parts);
43607 }
43608
43609
43610
43611
43612
43613
43614
43615 public static function isLocalPath($path)
43616 {
43617 return (bool) preg_match('{^(file://(?!//)|/(?!/)|/?[a-z]:[\\\\/]|\.\.[\\\\/]|[a-z0-9_.-]+[\\\\/])}i', $path);
43618 }
43619
43620 public static function getPlatformPath($path)
43621 {
43622 if (Platform::isWindows()) {
43623 $path = preg_replace('{^(?:file:///([a-z]):?/)}i', 'file://$1:/', $path);
43624 }
43625
43626 return preg_replace('{^file://}i', '', $path);
43627 }
43628
43629 protected function directorySize($directory)
43630 {
43631 $it = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS);
43632 $ri = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
43633
43634 $size = 0;
43635 foreach ($ri as $file) {
43636 if ($file->isFile()) {
43637 $size += $file->getSize();
43638 }
43639 }
43640
43641 return $size;
43642 }
43643
43644 protected function getProcess()
43645 {
43646 return $this->processExecutor;
43647 }
43648
43649
43650
43651
43652
43653
43654
43655
43656
43657
43658 private function unlinkImplementation($path)
43659 {
43660 if (Platform::isWindows() && is_dir($path) && is_link($path)) {
43661 return rmdir($path);
43662 }
43663
43664 return unlink($path);
43665 }
43666
43667
43668
43669
43670
43671
43672
43673
43674 public function relativeSymlink($target, $link)
43675 {
43676 $cwd = getcwd();
43677
43678 $relativePath = $this->findShortestPath($link, $target);
43679 chdir(dirname($link));
43680 $result = @symlink($relativePath, $link);
43681
43682 chdir($cwd);
43683
43684 return $result;
43685 }
43686
43687
43688
43689
43690
43691
43692
43693
43694 public function isSymlinkedDirectory($directory)
43695 {
43696 if (!is_dir($directory)) {
43697 return false;
43698 }
43699
43700 $resolved = $this->resolveSymlinkedDirectorySymlink($directory);
43701
43702 return is_link($resolved);
43703 }
43704
43705
43706
43707
43708
43709
43710 private function unlinkSymlinkedDirectory($directory)
43711 {
43712 $resolved = $this->resolveSymlinkedDirectorySymlink($directory);
43713
43714 return $this->unlink($resolved);
43715 }
43716
43717
43718
43719
43720
43721
43722
43723
43724 private function resolveSymlinkedDirectorySymlink($pathname)
43725 {
43726 if (!is_dir($pathname)) {
43727 return $pathname;
43728 }
43729
43730 $resolved = rtrim($pathname, '/');
43731
43732 if (!strlen($resolved)) {
43733 return $pathname;
43734 }
43735
43736 return $resolved;
43737 }
43738
43739
43740
43741
43742
43743
43744
43745 public function junction($target, $junction)
43746 {
43747 if (!Platform::isWindows()) {
43748 throw new \LogicException(sprintf('Function %s is not available on non-Windows platform', __CLASS__));
43749 }
43750 if (!is_dir($target)) {
43751 throw new IOException(sprintf('Cannot junction to "%s" as it is not a directory.', $target), 0, null, $target);
43752 }
43753 $cmd = sprintf(
43754 'mklink /J %s %s',
43755 ProcessExecutor::escape(str_replace('/', DIRECTORY_SEPARATOR, $junction)),
43756 ProcessExecutor::escape(realpath($target))
43757 );
43758 if ($this->getProcess()->execute($cmd, $output) !== 0) {
43759 throw new IOException(sprintf('Failed to create junction to "%s" at "%s".', $target, $junction), 0, null, $target);
43760 }
43761 clearstatcache(true, $junction);
43762 }
43763
43764
43765
43766
43767
43768
43769
43770
43771
43772
43773
43774
43775
43776
43777
43778
43779
43780
43781
43782
43783
43784 public function isJunction($junction)
43785 {
43786 if (!Platform::isWindows()) {
43787 return false;
43788 }
43789
43790
43791 clearstatcache(true, $junction);
43792
43793 if (!is_dir($junction) || is_link($junction)) {
43794 return false;
43795 }
43796
43797 $stat = lstat($junction);
43798
43799
43800 return $stat ? 0x4000 !== ($stat['mode'] & 0xF000) : false;
43801 }
43802
43803
43804
43805
43806
43807
43808
43809 public function removeJunction($junction)
43810 {
43811 if (!Platform::isWindows()) {
43812 return false;
43813 }
43814 $junction = rtrim(str_replace('/', DIRECTORY_SEPARATOR, $junction), DIRECTORY_SEPARATOR);
43815 if (!$this->isJunction($junction)) {
43816 throw new IOException(sprintf('%s is not a junction and thus cannot be removed as one', $junction));
43817 }
43818
43819 return $this->rmdir($junction);
43820 }
43821 }
43822 <?php
43823
43824
43825
43826
43827
43828
43829
43830
43831
43832
43833
43834 namespace Composer\Util;
43835
43836 use Composer\Config;
43837 use Composer\IO\IOInterface;
43838
43839
43840
43841
43842 class Git
43843 {
43844 private static $version = false;
43845
43846
43847 protected $io;
43848
43849 protected $config;
43850
43851 protected $process;
43852
43853 protected $filesystem;
43854
43855 public function __construct(IOInterface $io, Config $config, ProcessExecutor $process, Filesystem $fs)
43856 {
43857 $this->io = $io;
43858 $this->config = $config;
43859 $this->process = $process;
43860 $this->filesystem = $fs;
43861 }
43862
43863 public function runCommand($commandCallable, $url, $cwd, $initialClone = false)
43864 {
43865
43866 $this->config->prohibitUrlByConfig($url, $this->io);
43867
43868 if ($initialClone) {
43869 $origCwd = $cwd;
43870 $cwd = null;
43871 }
43872
43873 if (preg_match('{^ssh://[^@]+@[^:]+:[^0-9]+}', $url)) {
43874 throw new \InvalidArgumentException('The source URL ' . $url . ' is invalid, ssh URLs should have a port number after ":".' . "\n" . 'Use ssh://git@example.com:22/path or just git@example.com:path if you do not want to provide a password or custom port.');
43875 }
43876
43877 if (!$initialClone) {
43878
43879 $this->process->execute('git remote -v', $output, $cwd);
43880 if (preg_match('{^(?:composer|origin)\s+https?://(.+):(.+)@([^/]+)}im', $output, $match) && !$this->io->hasAuthentication($match[3])) {
43881 $this->io->setAuthentication($match[3], rawurldecode($match[1]), rawurldecode($match[2]));
43882 }
43883 }
43884
43885 $protocols = $this->config->get('github-protocols');
43886 if (!is_array($protocols)) {
43887 throw new \RuntimeException('Config value "github-protocols" must be an array, got ' . gettype($protocols));
43888 }
43889
43890 if (preg_match('{^(?:https?|git)://' . self::getGitHubDomainsRegex($this->config) . '/(.*)}', $url, $match)) {
43891 $messages = array();
43892 foreach ($protocols as $protocol) {
43893 if ('ssh' === $protocol) {
43894 $protoUrl = "git@" . $match[1] . ":" . $match[2];
43895 } else {
43896 $protoUrl = $protocol . "://" . $match[1] . "/" . $match[2];
43897 }
43898
43899 if (0 === $this->process->execute(call_user_func($commandCallable, $protoUrl), $ignoredOutput, $cwd)) {
43900 return;
43901 }
43902 $messages[] = '- ' . $protoUrl . "\n" . preg_replace('#^#m', '  ', $this->process->getErrorOutput());
43903 if ($initialClone) {
43904 $this->filesystem->removeDirectory($origCwd);
43905 }
43906 }
43907
43908
43909 if (!$this->io->hasAuthentication($match[1]) && !$this->io->isInteractive()) {
43910 $this->throwException('Failed to clone ' . $url . ' via ' . implode(', ', $protocols) . ' protocols, aborting.' . "\n\n" . implode("\n", $messages), $url);
43911 }
43912 }
43913
43914
43915 $bypassSshForGitHub = preg_match('{^git@' . self::getGitHubDomainsRegex($this->config) . ':(.+?)\.git$}i', $url) && !in_array('ssh', $protocols, true);
43916
43917 $command = call_user_func($commandCallable, $url);
43918
43919 $auth = null;
43920 if ($bypassSshForGitHub || 0 !== $this->process->execute($command, $ignoredOutput, $cwd)) {
43921 $errorMsg = $this->process->getErrorOutput();
43922
43923 if (preg_match('{^git@' . self::getGitHubDomainsRegex($this->config) . ':(.+?)\.git$}i', $url, $match)
43924 || preg_match('{^https?://' . self::getGitHubDomainsRegex($this->config) . '/(.*)}', $url, $match)
43925 ) {
43926 if (!$this->io->hasAuthentication($match[1])) {
43927 $gitHubUtil = new GitHub($this->io, $this->config, $this->process);
43928 $message = 'Cloning failed using an ssh key for authentication, enter your GitHub credentials to access private repos';
43929
43930 if (!$gitHubUtil->authorizeOAuth($match[1]) && $this->io->isInteractive()) {
43931 $gitHubUtil->authorizeOAuthInteractively($match[1], $message);
43932 }
43933 }
43934
43935 if ($this->io->hasAuthentication($match[1])) {
43936 $auth = $this->io->getAuthentication($match[1]);
43937 $authUrl = 'https://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[1] . '/' . $match[2] . '.git';
43938 $command = call_user_func($commandCallable, $authUrl);
43939 if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
43940 return;
43941 }
43942
43943 $errorMsg = $this->process->getErrorOutput();
43944 }
43945 } elseif (preg_match('{^https://(bitbucket\.org)/(.*)(\.git)?$}U', $url, $match)) { 
43946 $bitbucketUtil = new Bitbucket($this->io, $this->config, $this->process);
43947
43948 if (!$this->io->hasAuthentication($match[1])) {
43949 $message = 'Enter your Bitbucket credentials to access private repos';
43950
43951 if (!$bitbucketUtil->authorizeOAuth($match[1]) && $this->io->isInteractive()) {
43952 $bitbucketUtil->authorizeOAuthInteractively($match[1], $message);
43953 $accessToken = $bitbucketUtil->getToken();
43954 $this->io->setAuthentication($match[1], 'x-token-auth', $accessToken);
43955 }
43956 } else { 
43957 $auth = $this->io->getAuthentication($match[1]);
43958
43959
43960 if ($auth['username'] !== 'x-token-auth') {
43961 $accessToken = $bitbucketUtil->requestToken($match[1], $auth['username'], $auth['password']);
43962 if (! empty($accessToken)) {
43963 $this->io->setAuthentication($match[1], 'x-token-auth', $accessToken);
43964 }
43965 }
43966 }
43967
43968 if ($this->io->hasAuthentication($match[1])) {
43969 $auth = $this->io->getAuthentication($match[1]);
43970 $authUrl = 'https://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[1] . '/' . $match[2] . '.git';
43971
43972 $command = call_user_func($commandCallable, $authUrl);
43973 if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
43974 return;
43975 }
43976
43977 $errorMsg = $this->process->getErrorOutput();
43978 } else { 
43979 $sshUrl = 'git@bitbucket.org:' . $match[2] . '.git';
43980 $this->io->writeError('    No bitbucket authentication configured. Falling back to ssh.');
43981 $command = call_user_func($commandCallable, $sshUrl);
43982 if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
43983 return;
43984 }
43985
43986 $errorMsg = $this->process->getErrorOutput();
43987 }
43988 } elseif (
43989 preg_match('{^(git)@' . self::getGitLabDomainsRegex($this->config) . ':(.+?\.git)$}i', $url, $match)
43990 || preg_match('{^(https?)://' . self::getGitLabDomainsRegex($this->config) . '/(.*)}', $url, $match)
43991 ) {
43992 if ($match[1] === 'git') {
43993 $match[1] = 'https';
43994 }
43995
43996 if (!$this->io->hasAuthentication($match[2])) {
43997 $gitLabUtil = new GitLab($this->io, $this->config, $this->process);
43998 $message = 'Cloning failed, enter your GitLab credentials to access private repos';
43999
44000 if (!$gitLabUtil->authorizeOAuth($match[2]) && $this->io->isInteractive()) {
44001 $gitLabUtil->authorizeOAuthInteractively($match[1], $match[2], $message);
44002 }
44003 }
44004
44005 if ($this->io->hasAuthentication($match[2])) {
44006 $auth = $this->io->getAuthentication($match[2]);
44007 if ($auth['password'] === 'private-token' || $auth['password'] === 'oauth2' || $auth['password'] === 'gitlab-ci-token') {
44008 $authUrl = $match[1] . '://' . rawurlencode($auth['password']) . ':' . rawurlencode($auth['username']) . '@' . $match[2] . '/' . $match[3]; 
44009 } else {
44010 $authUrl = $match[1] . '://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[2] . '/' . $match[3];
44011 }
44012
44013 $command = call_user_func($commandCallable, $authUrl);
44014 if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
44015 return;
44016 }
44017
44018 $errorMsg = $this->process->getErrorOutput();
44019 }
44020 } elseif ($this->isAuthenticationFailure($url, $match)) { 
44021 if (strpos($match[2], '@')) {
44022 list($authParts, $match[2]) = explode('@', $match[2], 2);
44023 }
44024
44025 $storeAuth = false;
44026 if ($this->io->hasAuthentication($match[2])) {
44027 $auth = $this->io->getAuthentication($match[2]);
44028 } elseif ($this->io->isInteractive()) {
44029 $defaultUsername = null;
44030 if (isset($authParts) && $authParts) {
44031 if (false !== strpos($authParts, ':')) {
44032 list($defaultUsername, ) = explode(':', $authParts, 2);
44033 } else {
44034 $defaultUsername = $authParts;
44035 }
44036 }
44037
44038 $this->io->writeError('    Authentication required (<info>' . $match[2] . '</info>):');
44039 $auth = array(
44040 'username' => $this->io->ask('      Username: ', $defaultUsername),
44041 'password' => $this->io->askAndHideAnswer('      Password: '),
44042 );
44043 $storeAuth = $this->config->get('store-auths');
44044 }
44045
44046 if ($auth) {
44047 $authUrl = $match[1] . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[2] . $match[3];
44048
44049 $command = call_user_func($commandCallable, $authUrl);
44050 if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
44051 $this->io->setAuthentication($match[2], $auth['username'], $auth['password']);
44052 $authHelper = new AuthHelper($this->io, $this->config);
44053 $authHelper->storeAuth($match[2], $storeAuth);
44054
44055 return;
44056 }
44057
44058 $errorMsg = $this->process->getErrorOutput();
44059 }
44060 }
44061
44062 if ($initialClone) {
44063 $this->filesystem->removeDirectory($origCwd);
44064 }
44065
44066 $this->throwException('Failed to execute ' . $command . "\n\n" . $errorMsg, $url);
44067 }
44068 }
44069
44070 public function syncMirror($url, $dir)
44071 {
44072
44073 if (is_dir($dir) && 0 === $this->process->execute('git rev-parse --git-dir', $output, $dir) && trim($output) === '.') {
44074 try {
44075 $commandCallable = function ($url) {
44076 $sanitizedUrl = preg_replace('{://([^@]+?):(.+?)@}', '://', $url);
44077
44078 return sprintf('git remote set-url origin %s && git remote update --prune origin && git remote set-url origin %s', ProcessExecutor::escape($url), ProcessExecutor::escape($sanitizedUrl));
44079 };
44080 $this->runCommand($commandCallable, $url, $dir);
44081 } catch (\Exception $e) {
44082 $this->io->writeError('<error>Sync mirror failed: ' . $e->getMessage() . '</error>', true, IOInterface::DEBUG);
44083
44084 return false;
44085 }
44086
44087 return true;
44088 }
44089
44090
44091 $this->filesystem->removeDirectory($dir);
44092
44093 $commandCallable = function ($url) use ($dir) {
44094 return sprintf('git clone --mirror %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($dir));
44095 };
44096
44097 $this->runCommand($commandCallable, $url, $dir, true);
44098
44099 return true;
44100 }
44101
44102 public function fetchRefOrSyncMirror($url, $dir, $ref)
44103 {
44104 if ($this->checkRefIsInMirror($url, $dir, $ref)) {
44105 return true;
44106 }
44107
44108 if ($this->syncMirror($url, $dir)) {
44109 return $this->checkRefIsInMirror($url, $dir, $ref);
44110 }
44111
44112 return false;
44113 }
44114
44115 public static function getNoShowSignatureFlag(ProcessExecutor $process)
44116 {
44117 $gitVersion = self::getVersion($process);
44118 if ($gitVersion && version_compare($gitVersion, '2.10.0-rc0', '>=')) {
44119 return ' --no-show-signature';
44120 }
44121
44122 return '';
44123 }
44124
44125 private function checkRefIsInMirror($url, $dir, $ref)
44126 {
44127 if (is_dir($dir) && 0 === $this->process->execute('git rev-parse --git-dir', $output, $dir) && trim($output) === '.') {
44128 $escapedRef = ProcessExecutor::escape($ref.'^{commit}');
44129 $exitCode = $this->process->execute(sprintf('git rev-parse --quiet --verify %s', $escapedRef), $ignoredOutput, $dir);
44130 if ($exitCode === 0) {
44131 return true;
44132 }
44133 }
44134
44135 return false;
44136 }
44137
44138 private function isAuthenticationFailure($url, &$match)
44139 {
44140 if (!preg_match('{^(https?://)([^/]+)(.*)$}i', $url, $match)) {
44141 return false;
44142 }
44143
44144 $authFailures = array(
44145 'fatal: Authentication failed',
44146 'remote error: Invalid username or password.',
44147 'error: 401 Unauthorized',
44148 'fatal: unable to access',
44149 'fatal: could not read Username',
44150 );
44151
44152 $errorOutput = $this->process->getErrorOutput();
44153 foreach ($authFailures as $authFailure) {
44154 if (strpos($errorOutput, $authFailure) !== false) {
44155 return true;
44156 }
44157 }
44158
44159 return false;
44160 }
44161
44162 public static function cleanEnv()
44163 {
44164 if (PHP_VERSION_ID < 50400 && ini_get('safe_mode') && false === strpos(ini_get('safe_mode_allowed_env_vars'), 'GIT_ASKPASS')) {
44165 throw new \RuntimeException('safe_mode is enabled and safe_mode_allowed_env_vars does not contain GIT_ASKPASS, can not set env var. You can disable safe_mode with "-dsafe_mode=0" when running composer');
44166 }
44167
44168
44169 if (getenv('GIT_ASKPASS') !== 'echo') {
44170 putenv('GIT_ASKPASS=echo');
44171 $_SERVER['GIT_ASKPASS'] = 'echo';
44172 }
44173
44174
44175 if (getenv('GIT_DIR')) {
44176 putenv('GIT_DIR');
44177 unset($_SERVER['GIT_DIR']);
44178 }
44179 if (getenv('GIT_WORK_TREE')) {
44180 putenv('GIT_WORK_TREE');
44181 unset($_SERVER['GIT_WORK_TREE']);
44182 }
44183
44184
44185 if (getenv('LANGUAGE') !== 'C') {
44186 putenv('LANGUAGE=C');
44187 $_SERVER['LANGUAGE'] = 'C';
44188 }
44189
44190
44191 putenv("DYLD_LIBRARY_PATH");
44192 unset($_SERVER['DYLD_LIBRARY_PATH']);
44193 }
44194
44195 public static function getGitHubDomainsRegex(Config $config)
44196 {
44197 return '(' . implode('|', array_map('preg_quote', $config->get('github-domains'))) . ')';
44198 }
44199
44200 public static function getGitLabDomainsRegex(Config $config)
44201 {
44202 return '(' . implode('|', array_map('preg_quote', $config->get('gitlab-domains'))) . ')';
44203 }
44204
44205 public static function sanitizeUrl($message)
44206 {
44207 return preg_replace_callback('{://(?P<user>[^@]+?):(?P<password>.+?)@}', function ($m) {
44208 if (preg_match('{^[a-f0-9]{12,}$}', $m[1])) {
44209 return '://***:***@';
44210 }
44211
44212 return '://' . $m[1] . ':***@';
44213 }, $message);
44214 }
44215
44216 private function throwException($message, $url)
44217 {
44218
44219 clearstatcache();
44220
44221 if (0 !== $this->process->execute('git --version', $ignoredOutput)) {
44222 throw new \RuntimeException(self::sanitizeUrl('Failed to clone ' . $url . ', git was not found, check that it is installed and in your PATH env.' . "\n\n" . $this->process->getErrorOutput()));
44223 }
44224
44225 throw new \RuntimeException(self::sanitizeUrl($message));
44226 }
44227
44228
44229
44230
44231
44232
44233 public static function getVersion(ProcessExecutor $process = null)
44234 {
44235 if (false === self::$version) {
44236 self::$version = null;
44237 if (!$process) {
44238 $process = new ProcessExecutor;
44239 }
44240 if (0 === $process->execute('git --version', $output) && preg_match('/^git version (\d+(?:\.\d+)+)/m', $output, $matches)) {
44241 self::$version = $matches[1];
44242 }
44243 }
44244
44245 return self::$version;
44246 }
44247 }
44248 <?php
44249
44250
44251
44252
44253
44254
44255
44256
44257
44258
44259
44260 namespace Composer\Util;
44261
44262 use Composer\Factory;
44263 use Composer\IO\IOInterface;
44264 use Composer\Config;
44265 use Composer\Downloader\TransportException;
44266
44267
44268
44269
44270 class GitHub
44271 {
44272 protected $io;
44273 protected $config;
44274 protected $process;
44275 protected $remoteFilesystem;
44276
44277
44278
44279
44280
44281
44282
44283
44284
44285 public function __construct(IOInterface $io, Config $config, ProcessExecutor $process = null, RemoteFilesystem $remoteFilesystem = null)
44286 {
44287 $this->io = $io;
44288 $this->config = $config;
44289 $this->process = $process ?: new ProcessExecutor($io);
44290 $this->remoteFilesystem = $remoteFilesystem ?: Factory::createRemoteFilesystem($this->io, $config);
44291 }
44292
44293
44294
44295
44296
44297
44298
44299 public function authorizeOAuth($originUrl)
44300 {
44301 if (!in_array($originUrl, $this->config->get('github-domains'))) {
44302 return false;
44303 }
44304
44305
44306 if (0 === $this->process->execute('git config github.accesstoken', $output)) {
44307 $this->io->setAuthentication($originUrl, trim($output), 'x-oauth-basic');
44308
44309 return true;
44310 }
44311
44312 return false;
44313 }
44314
44315
44316
44317
44318
44319
44320
44321
44322
44323
44324 public function authorizeOAuthInteractively($originUrl, $message = null)
44325 {
44326 if ($message) {
44327 $this->io->writeError($message);
44328 }
44329
44330 $note = 'Composer';
44331 if ($this->config->get('github-expose-hostname') === true && 0 === $this->process->execute('hostname', $output)) {
44332 $note .= ' on ' . trim($output);
44333 }
44334 $note .= ' ' . date('Y-m-d Hi');
44335
44336 $url = 'https://'.$originUrl.'/settings/tokens/new?scopes=repo&description=' . str_replace('%20', '+', rawurlencode($note));
44337 $this->io->writeError(sprintf('Head to %s', $url));
44338 $this->io->writeError(sprintf('to retrieve a token. It will be stored in "%s" for future use by Composer.', $this->config->getAuthConfigSource()->getName()));
44339
44340 $token = trim($this->io->askAndHideAnswer('Token (hidden): '));
44341
44342 if (!$token) {
44343 $this->io->writeError('<warning>No token given, aborting.</warning>');
44344 $this->io->writeError('You can also add it manually later by using "composer config --global --auth github-oauth.github.com <token>"');
44345
44346 return false;
44347 }
44348
44349 $this->io->setAuthentication($originUrl, $token, 'x-oauth-basic');
44350
44351 try {
44352 $apiUrl = ('github.com' === $originUrl) ? 'api.github.com/' : $originUrl . '/api/v3/';
44353
44354 $this->remoteFilesystem->getContents($originUrl, 'https://'. $apiUrl, false, array(
44355 'retry-auth-failure' => false,
44356 ));
44357 } catch (TransportException $e) {
44358 if (in_array($e->getCode(), array(403, 401))) {
44359 $this->io->writeError('<error>Invalid token provided.</error>');
44360 $this->io->writeError('You can also add it manually later by using "composer config --global --auth github-oauth.github.com <token>"');
44361
44362 return false;
44363 }
44364
44365 throw $e;
44366 }
44367
44368
44369 $this->config->getConfigSource()->removeConfigSetting('github-oauth.'.$originUrl);
44370 $this->config->getAuthConfigSource()->addConfigSetting('github-oauth.'.$originUrl, $token);
44371
44372 $this->io->writeError('<info>Token stored successfully.</info>');
44373
44374 return true;
44375 }
44376
44377
44378
44379
44380
44381
44382
44383
44384 public function getRateLimit(array $headers)
44385 {
44386 $rateLimit = array(
44387 'limit' => '?',
44388 'reset' => '?',
44389 );
44390
44391 foreach ($headers as $header) {
44392 $header = trim($header);
44393 if (false === strpos($header, 'X-RateLimit-')) {
44394 continue;
44395 }
44396 list($type, $value) = explode(':', $header, 2);
44397 switch ($type) {
44398 case 'X-RateLimit-Limit':
44399 $rateLimit['limit'] = (int) trim($value);
44400 break;
44401 case 'X-RateLimit-Reset':
44402 $rateLimit['reset'] = date('Y-m-d H:i:s', (int) trim($value));
44403 break;
44404 }
44405 }
44406
44407 return $rateLimit;
44408 }
44409
44410
44411
44412
44413
44414
44415
44416
44417 public function isRateLimited(array $headers)
44418 {
44419 foreach ($headers as $header) {
44420 if (preg_match('{^X-RateLimit-Remaining: *0$}i', trim($header))) {
44421 return true;
44422 }
44423 }
44424
44425 return false;
44426 }
44427 }
44428 <?php
44429
44430
44431
44432
44433
44434
44435
44436
44437
44438
44439
44440 namespace Composer\Util;
44441
44442 use Composer\IO\IOInterface;
44443 use Composer\Config;
44444 use Composer\Factory;
44445 use Composer\Downloader\TransportException;
44446 use Composer\Json\JsonFile;
44447
44448
44449
44450
44451 class GitLab
44452 {
44453 protected $io;
44454 protected $config;
44455 protected $process;
44456 protected $remoteFilesystem;
44457
44458
44459
44460
44461
44462
44463
44464
44465
44466 public function __construct(IOInterface $io, Config $config, ProcessExecutor $process = null, RemoteFilesystem $remoteFilesystem = null)
44467 {
44468 $this->io = $io;
44469 $this->config = $config;
44470 $this->process = $process ?: new ProcessExecutor($io);
44471 $this->remoteFilesystem = $remoteFilesystem ?: Factory::createRemoteFilesystem($this->io, $config);
44472 }
44473
44474
44475
44476
44477
44478
44479
44480
44481 public function authorizeOAuth($originUrl)
44482 {
44483
44484 $bcOriginUrl = preg_replace('{:\d+}', '', $originUrl);
44485
44486 if (!in_array($originUrl, $this->config->get('gitlab-domains'), true) && !in_array($bcOriginUrl, $this->config->get('gitlab-domains'), true)) {
44487 return false;
44488 }
44489
44490
44491 if (0 === $this->process->execute('git config gitlab.accesstoken', $output)) {
44492 $this->io->setAuthentication($originUrl, trim($output), 'oauth2');
44493
44494 return true;
44495 }
44496
44497
44498 $authTokens = $this->config->get('gitlab-token');
44499
44500 if (isset($authTokens[$originUrl])) {
44501 $this->io->setAuthentication($originUrl, $authTokens[$originUrl], 'private-token');
44502
44503 return true;
44504 }
44505
44506 if (isset($authTokens[$bcOriginUrl])) {
44507 $this->io->setAuthentication($originUrl, $authTokens[$bcOriginUrl], 'private-token');
44508
44509 return true;
44510 }
44511
44512 return false;
44513 }
44514
44515
44516
44517
44518
44519
44520
44521
44522
44523
44524
44525
44526
44527 public function authorizeOAuthInteractively($scheme, $originUrl, $message = null)
44528 {
44529 if ($message) {
44530 $this->io->writeError($message);
44531 }
44532
44533 $this->io->writeError(sprintf('A token will be created and stored in "%s", your password will never be stored', $this->config->getAuthConfigSource()->getName()));
44534 $this->io->writeError('To revoke access to this token you can visit '.$scheme.'://'.$originUrl.'/profile/applications');
44535
44536 $attemptCounter = 0;
44537
44538 while ($attemptCounter++ < 5) {
44539 try {
44540 $response = $this->createToken($scheme, $originUrl);
44541 } catch (TransportException $e) {
44542
44543
44544 if (in_array($e->getCode(), array(403, 401))) {
44545 if (401 === $e->getCode()) {
44546 $response = json_decode($e->getResponse(), true);
44547 if (isset($response['error']) && $response['error'] === 'invalid_grant') {
44548 $this->io->writeError('Bad credentials. If you have two factor authentication enabled you will have to manually create a personal access token');
44549 } else {
44550 $this->io->writeError('Bad credentials.');
44551 }
44552 } else {
44553 $this->io->writeError('Maximum number of login attempts exceeded. Please try again later.');
44554 }
44555
44556 $this->io->writeError('You can also manually create a personal access token enabling the "read_api" scope at '.$scheme.'://'.$originUrl.'/profile/personal_access_tokens');
44557 $this->io->writeError('Add it using "composer config --global --auth gitlab-token.'.$originUrl.' <token>"');
44558
44559 continue;
44560 }
44561
44562 throw $e;
44563 }
44564
44565 $this->io->setAuthentication($originUrl, $response['access_token'], 'oauth2');
44566
44567
44568 $this->config->getAuthConfigSource()->addConfigSetting('gitlab-oauth.'.$originUrl, $response['access_token']);
44569
44570 return true;
44571 }
44572
44573 throw new \RuntimeException('Invalid GitLab credentials 5 times in a row, aborting.');
44574 }
44575
44576 private function createToken($scheme, $originUrl)
44577 {
44578 $username = $this->io->ask('Username: ');
44579 $password = $this->io->askAndHideAnswer('Password: ');
44580
44581 $headers = array('Content-Type: application/x-www-form-urlencoded');
44582
44583 $apiUrl = $originUrl;
44584 $data = http_build_query(array(
44585 'username' => $username,
44586 'password' => $password,
44587 'grant_type' => 'password',
44588 ), null, '&');
44589 $options = array(
44590 'retry-auth-failure' => false,
44591 'http' => array(
44592 'method' => 'POST',
44593 'header' => $headers,
44594 'content' => $data,
44595 ),
44596 );
44597
44598 $json = $this->remoteFilesystem->getContents($originUrl, $scheme.'://'.$apiUrl.'/oauth/token', false, $options);
44599
44600 $this->io->writeError('Token successfully created');
44601
44602 return JsonFile::parseJson($json);
44603 }
44604 }
44605 <?php
44606
44607
44608
44609
44610
44611
44612
44613
44614
44615
44616
44617 namespace Composer\Util;
44618
44619 use Composer\Config;
44620 use Composer\IO\IOInterface;
44621
44622
44623
44624
44625 class Hg
44626 {
44627
44628
44629
44630 private $io;
44631
44632
44633
44634
44635 private $config;
44636
44637
44638
44639
44640 private $process;
44641
44642 public function __construct(IOInterface $io, Config $config, ProcessExecutor $process)
44643 {
44644 $this->io = $io;
44645 $this->config = $config;
44646 $this->process = $process;
44647 }
44648
44649 public function runCommand($commandCallable, $url, $cwd)
44650 {
44651 $this->config->prohibitUrlByConfig($url, $this->io);
44652
44653
44654 $command = call_user_func($commandCallable, $url);
44655
44656 if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
44657 return;
44658 }
44659
44660
44661 if (preg_match('{^(https?)://((.+)(?:\:(.+))?@)?([^/]+)(/.*)?}mi', $url, $match) && $this->io->hasAuthentication($match[5])) {
44662 $auth = $this->io->getAuthentication($match[5]);
44663 $authenticatedUrl = $match[1] . '://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[5] . (!empty($match[6]) ? $match[6] : null);
44664
44665 $command = call_user_func($commandCallable, $authenticatedUrl);
44666
44667 if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
44668 return;
44669 }
44670
44671 $error = $this->process->getErrorOutput();
44672 } else {
44673 $error = 'The given URL (' . $url . ') does not match the required format (http(s)://(username:password@)example.com/path-to-repository)';
44674 }
44675
44676 $this->throwException('Failed to clone ' . $url . ', ' . "\n\n" . $error, $url);
44677 }
44678
44679 public static function sanitizeUrl($message)
44680 {
44681 return preg_replace_callback('{://(?P<user>[^@]+?):(?P<password>.+?)@}', function ($m) {
44682 if (preg_match('{^[a-f0-9]{12,}$}', $m[1])) {
44683 return '://***:***@';
44684 }
44685
44686 return '://' . $m[1] . ':***@';
44687 }, $message);
44688 }
44689
44690 private function throwException($message, $url)
44691 {
44692 if (0 !== $this->process->execute('hg --version', $ignoredOutput)) {
44693 throw new \RuntimeException(self::sanitizeUrl('Failed to clone ' . $url . ', hg was not found, check that it is installed and in your PATH env.' . "\n\n" . $this->process->getErrorOutput()));
44694 }
44695
44696 throw new \RuntimeException(self::sanitizeUrl($message));
44697 }
44698 }
44699 <?php
44700
44701
44702
44703
44704
44705
44706
44707
44708
44709
44710
44711 namespace Composer\Util;
44712
44713 use Composer\XdebugHandler\XdebugHandler;
44714
44715
44716
44717
44718
44719
44720
44721
44722 class IniHelper
44723 {
44724
44725
44726
44727
44728
44729
44730
44731
44732 public static function getAll()
44733 {
44734 return XdebugHandler::getAllIniFiles();
44735 }
44736
44737
44738
44739
44740
44741
44742 public static function getMessage()
44743 {
44744 $paths = self::getAll();
44745
44746 if (empty($paths[0])) {
44747 array_shift($paths);
44748 }
44749
44750 $ini = array_shift($paths);
44751
44752 if (empty($ini)) {
44753 return 'A php.ini file does not exist. You will have to create one.';
44754 }
44755
44756 if (!empty($paths)) {
44757 return 'Your command-line PHP is using multiple ini files. Run `php --ini` to show them.';
44758 }
44759
44760 return 'The php.ini used by your command-line PHP is: '.$ini;
44761 }
44762 }
44763 <?php
44764
44765
44766
44767
44768
44769
44770
44771
44772
44773
44774
44775 namespace Composer\Util;
44776
44777 use stdClass;
44778
44779
44780
44781
44782 class NoProxyPattern
44783 {
44784
44785
44786
44787 protected $hostNames = array();
44788
44789
44790
44791
44792 protected $rules = array();
44793
44794
44795
44796
44797 protected $noproxy;
44798
44799
44800
44801
44802 public function __construct($pattern)
44803 {
44804 $this->hostNames = preg_split('{[\s,]+}', $pattern, null, PREG_SPLIT_NO_EMPTY);
44805 $this->noproxy = empty($this->hostNames) || '*' === $this->hostNames[0];
44806 }
44807
44808
44809
44810
44811
44812
44813
44814
44815 public function test($url)
44816 {
44817 if ($this->noproxy) {
44818 return true;
44819 }
44820
44821 if (!$urlData = $this->getUrlData($url)) {
44822 return false;
44823 }
44824
44825 foreach ($this->hostNames as $index => $hostName) {
44826 if ($this->match($index, $hostName, $urlData)) {
44827 return true;
44828 }
44829 }
44830
44831 return false;
44832 }
44833
44834
44835
44836
44837
44838
44839
44840
44841 protected function getUrlData($url)
44842 {
44843 if (!$host = parse_url($url, PHP_URL_HOST)) {
44844 return false;
44845 }
44846
44847 $port = parse_url($url, PHP_URL_PORT);
44848
44849 if (empty($port)) {
44850 switch (parse_url($url, PHP_URL_SCHEME)) {
44851 case 'http':
44852 $port = 80;
44853 break;
44854 case 'https':
44855 $port = 443;
44856 break;
44857 }
44858 }
44859
44860 $hostName = $host . ($port ? ':' . $port : '');
44861 list($host, $port, $err) = $this->splitHostPort($hostName);
44862
44863 if ($err || !$this->ipCheckData($host, $ipdata)) {
44864 return false;
44865 }
44866
44867 return $this->makeData($host, $port, $ipdata);
44868 }
44869
44870
44871
44872
44873
44874
44875
44876
44877
44878
44879 protected function match($index, $hostName, $url)
44880 {
44881 if (!$rule = $this->getRule($index, $hostName)) {
44882
44883 return false;
44884 }
44885
44886 if ($rule->ipdata) {
44887
44888 if (!$url->ipdata) {
44889 return false;
44890 }
44891
44892 if ($rule->ipdata->netmask) {
44893 return $this->matchRange($rule->ipdata, $url->ipdata);
44894 }
44895
44896 $match = $rule->ipdata->ip === $url->ipdata->ip;
44897 } else {
44898
44899 $haystack = substr($url->name, - strlen($rule->name));
44900 $match = stripos($haystack, $rule->name) === 0;
44901 }
44902
44903 if ($match && $rule->port) {
44904 $match = $rule->port === $url->port;
44905 }
44906
44907 return $match;
44908 }
44909
44910
44911
44912
44913
44914
44915
44916
44917
44918 protected function matchRange(stdClass $network, stdClass $target)
44919 {
44920 $net = unpack('C*', $network->ip);
44921 $mask = unpack('C*', $network->netmask);
44922 $ip = unpack('C*', $target->ip);
44923
44924 for ($i = 1; $i < 17; ++$i) {
44925 if (($net[$i] & $mask[$i]) !== ($ip[$i] & $mask[$i])) {
44926 return false;
44927 }
44928 }
44929
44930 return true;
44931 }
44932
44933
44934
44935
44936
44937
44938
44939
44940
44941 private function getRule($index, $hostName)
44942 {
44943 if (array_key_exists($index, $this->rules)) {
44944 return $this->rules[$index];
44945 }
44946
44947 $this->rules[$index] = null;
44948 list($host, $port, $err) = $this->splitHostPort($hostName);
44949
44950 if ($err || !$this->ipCheckData($host, $ipdata, true)) {
44951 return null;
44952 }
44953
44954 $this->rules[$index] = $this->makeData($host, $port, $ipdata);
44955
44956 return $this->rules[$index];
44957 }
44958
44959
44960
44961
44962
44963
44964
44965
44966
44967
44968 private function ipCheckData($host, &$ipdata, $allowPrefix = false)
44969 {
44970 $ipdata = null;
44971 $netmask = null;
44972 $prefix = null;
44973 $modified = false;
44974
44975
44976 if (strpos($host, '/') !== false) {
44977 list($host, $prefix) = explode('/', $host);
44978
44979 if (!$allowPrefix || !$this->validateInt($prefix, 0, 128)) {
44980 return false;
44981 }
44982 $prefix = (int) $prefix;
44983 $modified = true;
44984 }
44985
44986
44987 if (!filter_var($host, FILTER_VALIDATE_IP)) {
44988 return !$modified;
44989 }
44990
44991 list($ip, $size) = $this->ipGetAddr($host);
44992
44993 if ($prefix !== null) {
44994
44995 if ($prefix > $size * 8) {
44996 return false;
44997 }
44998
44999 list($ip, $netmask) = $this->ipGetNetwork($ip, $size, $prefix);
45000 }
45001
45002 $ipdata = $this->makeIpData($ip, $size, $netmask);
45003
45004 return true;
45005 }
45006
45007
45008
45009
45010
45011
45012
45013
45014
45015
45016
45017 private function ipGetAddr($host)
45018 {
45019 $ip = inet_pton($host);
45020 $size = strlen($ip);
45021 $mapped = $this->ipMapTo6($ip, $size);
45022
45023 return array($mapped, $size);
45024 }
45025
45026
45027
45028
45029
45030
45031
45032
45033
45034 private function ipGetMask($prefix, $size)
45035 {
45036 $mask = '';
45037
45038 if ($ones = floor($prefix / 8)) {
45039 $mask = str_repeat(chr(255), $ones);
45040 }
45041
45042 if ($remainder = $prefix % 8) {
45043 $mask .= chr(0xff ^ (0xff >> $remainder));
45044 }
45045
45046 $mask = str_pad($mask, $size, chr(0));
45047
45048 return $this->ipMapTo6($mask, $size);
45049 }
45050
45051
45052
45053
45054
45055
45056
45057
45058
45059
45060 private function ipGetNetwork($rangeIp, $size, $prefix)
45061 {
45062 $netmask = $this->ipGetMask($prefix, $size);
45063
45064
45065 $mask = unpack('C*', $netmask);
45066 $ip = unpack('C*', $rangeIp);
45067 $net = '';
45068
45069 for ($i = 1; $i < 17; ++$i) {
45070 $net .= chr($ip[$i] & $mask[$i]);
45071 }
45072
45073 return array($net, $netmask);
45074 }
45075
45076
45077
45078
45079
45080
45081
45082
45083
45084 private function ipMapTo6($binary, $size)
45085 {
45086 if ($size === 4) {
45087 $prefix = str_repeat(chr(0), 10) . str_repeat(chr(255), 2);
45088 $binary = $prefix . $binary;
45089 }
45090
45091 return $binary;
45092 }
45093
45094
45095
45096
45097
45098
45099
45100
45101
45102
45103 private function makeData($host, $port, $ipdata)
45104 {
45105 return (object) array(
45106 'host' => $host,
45107 'name' => '.' . ltrim($host, '.'),
45108 'port' => $port,
45109 'ipdata' => $ipdata,
45110 );
45111 }
45112
45113
45114
45115
45116
45117
45118
45119
45120
45121
45122 private function makeIpData($ip, $size, $netmask)
45123 {
45124 return (object) array(
45125 'ip' => $ip,
45126 'size' => $size,
45127 'netmask' => $netmask,
45128 );
45129 }
45130
45131
45132
45133
45134
45135
45136
45137
45138 private function splitHostPort($hostName)
45139 {
45140
45141 $error = array('', '', true);
45142 $port = 0;
45143 $ip6 = '';
45144
45145
45146 if ($hostName[0] === '[') {
45147 $index = strpos($hostName, ']');
45148
45149
45150 if (false === $index || $index < 3) {
45151 return $error;
45152 }
45153
45154 $ip6 = substr($hostName, 1, $index - 1);
45155 $hostName = substr($hostName, $index + 1);
45156
45157 if (strpbrk($hostName, '[]') !== false
45158 || substr_count($hostName, ':') > 1) {
45159 return $error;
45160 }
45161 }
45162
45163 if (substr_count($hostName, ':') === 1) {
45164 $index = strpos($hostName, ':');
45165 $port = substr($hostName, $index + 1);
45166 $hostName = substr($hostName, 0, $index);
45167
45168 if (!$this->validateInt($port, 1, 65535)) {
45169 return $error;
45170 }
45171
45172 $port = (int) $port;
45173 }
45174
45175 $host = $ip6 . $hostName;
45176
45177 return array($host, $port, false);
45178 }
45179
45180
45181
45182
45183
45184
45185
45186
45187 private function validateInt($int, $min, $max)
45188 {
45189 $options = array(
45190 'options' => array(
45191 'min_range' => $min,
45192 'max_range' => $max)
45193 );
45194
45195 return false !== filter_var($int, FILTER_VALIDATE_INT, $options);
45196 }
45197 }
45198 <?php
45199
45200
45201 namespace Composer\Util;
45202
45203 use Composer\Package\Link;
45204 use Composer\Package\PackageInterface;
45205
45206 class PackageSorter
45207 {
45208
45209
45210
45211
45212
45213
45214
45215
45216 public static function sortPackages(array $packages) {
45217 $usageList = array();
45218
45219 foreach ($packages as $package) { 
45220 foreach (array_merge($package->getRequires(), $package->getDevRequires()) as $link) { 
45221 $target = $link->getTarget();
45222 $usageList[$target][] = $package->getName();
45223 }
45224 }
45225 $computing = array();
45226 $computed = array();
45227 $computeImportance = function ($name) use (&$computeImportance, &$computing, &$computed, $usageList) {
45228
45229 if (isset($computed[$name])) {
45230 return $computed[$name];
45231 }
45232
45233
45234 if (isset($computing[$name])) {
45235 return 0;
45236 }
45237
45238 $computing[$name] = true;
45239 $weight = 0;
45240
45241 if (isset($usageList[$name])) {
45242 foreach ($usageList[$name] as $user) {
45243 $weight -= 1 - $computeImportance($user);
45244 }
45245 }
45246
45247 unset($computing[$name]);
45248 $computed[$name] = $weight;
45249
45250 return $weight;
45251 };
45252
45253 $weightList = array();
45254
45255 foreach ($packages as $name => $package) {
45256 $weight = $computeImportance($name);
45257 $weightList[$name] = $weight;
45258 }
45259
45260 $stable_sort = function (&$array) {
45261 static $transform, $restore;
45262
45263 $i = 0;
45264
45265 if (!$transform) {
45266 $transform = function (&$v, $k) use (&$i) {
45267 $v = array($v, ++$i, $k, $v);
45268 };
45269
45270 $restore = function (&$v) {
45271 $v = $v[3];
45272 };
45273 }
45274
45275 array_walk($array, $transform);
45276 asort($array);
45277 array_walk($array, $restore);
45278 };
45279
45280 $stable_sort($weightList);
45281
45282 $sortedPackages = array();
45283
45284 foreach (array_keys($weightList) as $name) {
45285 $sortedPackages[] = $packages[$name];
45286 }
45287 return $sortedPackages;
45288 }
45289 }
45290 <?php
45291
45292
45293
45294
45295
45296
45297
45298
45299
45300
45301
45302 namespace Composer\Util;
45303
45304 use Composer\IO\IOInterface;
45305 use Symfony\Component\Process\Process;
45306
45307
45308
45309
45310 class Perforce
45311 {
45312 protected $path;
45313 protected $p4Depot;
45314 protected $p4Client;
45315 protected $p4User;
45316 protected $p4Password;
45317 protected $p4Port;
45318 protected $p4Stream;
45319 protected $p4ClientSpec;
45320 protected $p4DepotType;
45321 protected $p4Branch;
45322 protected $process;
45323 protected $uniquePerforceClientName;
45324 protected $windowsFlag;
45325 protected $commandResult;
45326
45327 protected $io;
45328
45329 protected $filesystem;
45330
45331 public function __construct($repoConfig, $port, $path, ProcessExecutor $process, $isWindows, IOInterface $io)
45332 {
45333 $this->windowsFlag = $isWindows;
45334 $this->p4Port = $port;
45335 $this->initializePath($path);
45336 $this->process = $process;
45337 $this->initialize($repoConfig);
45338 $this->io = $io;
45339 }
45340
45341 public static function create($repoConfig, $port, $path, ProcessExecutor $process, IOInterface $io)
45342 {
45343 return new Perforce($repoConfig, $port, $path, $process, Platform::isWindows(), $io);
45344 }
45345
45346 public static function checkServerExists($url, ProcessExecutor $processExecutor)
45347 {
45348 $output = null;
45349
45350 return 0 === $processExecutor->execute('p4 -p ' . ProcessExecutor::escape($url) . ' info -s', $output);
45351 }
45352
45353 public function initialize($repoConfig)
45354 {
45355 $this->uniquePerforceClientName = $this->generateUniquePerforceClientName();
45356 if (!$repoConfig) {
45357 return;
45358 }
45359 if (isset($repoConfig['unique_perforce_client_name'])) {
45360 $this->uniquePerforceClientName = $repoConfig['unique_perforce_client_name'];
45361 }
45362
45363 if (isset($repoConfig['depot'])) {
45364 $this->p4Depot = $repoConfig['depot'];
45365 }
45366 if (isset($repoConfig['branch'])) {
45367 $this->p4Branch = $repoConfig['branch'];
45368 }
45369 if (isset($repoConfig['p4user'])) {
45370 $this->p4User = $repoConfig['p4user'];
45371 } else {
45372 $this->p4User = $this->getP4variable('P4USER');
45373 }
45374 if (isset($repoConfig['p4password'])) {
45375 $this->p4Password = $repoConfig['p4password'];
45376 }
45377 }
45378
45379 public function initializeDepotAndBranch($depot, $branch)
45380 {
45381 if (isset($depot)) {
45382 $this->p4Depot = $depot;
45383 }
45384 if (isset($branch)) {
45385 $this->p4Branch = $branch;
45386 }
45387 }
45388
45389 public function generateUniquePerforceClientName()
45390 {
45391 return gethostname() . "_" . time();
45392 }
45393
45394 public function cleanupClientSpec()
45395 {
45396 $client = $this->getClient();
45397 $task = 'client -d ' . ProcessExecutor::escape($client);
45398 $useP4Client = false;
45399 $command = $this->generateP4Command($task, $useP4Client);
45400 $this->executeCommand($command);
45401 $clientSpec = $this->getP4ClientSpec();
45402 $fileSystem = $this->getFilesystem();
45403 $fileSystem->remove($clientSpec);
45404 }
45405
45406 protected function executeCommand($command)
45407 {
45408 $this->commandResult = '';
45409
45410 return $this->process->execute($command, $this->commandResult);
45411 }
45412
45413 public function getClient()
45414 {
45415 if (!isset($this->p4Client)) {
45416 $cleanStreamName = str_replace(array('//', '/', '@'), array('', '_', ''), $this->getStream());
45417 $this->p4Client = 'composer_perforce_' . $this->uniquePerforceClientName . '_' . $cleanStreamName;
45418 }
45419
45420 return $this->p4Client;
45421 }
45422
45423 protected function getPath()
45424 {
45425 return $this->path;
45426 }
45427
45428 public function initializePath($path)
45429 {
45430 $this->path = $path;
45431 $fs = $this->getFilesystem();
45432 $fs->ensureDirectoryExists($path);
45433 }
45434
45435 protected function getPort()
45436 {
45437 return $this->p4Port;
45438 }
45439
45440 public function setStream($stream)
45441 {
45442 $this->p4Stream = $stream;
45443 $index = strrpos($stream, '/');
45444
45445 if ($index > 2) {
45446 $this->p4DepotType = 'stream';
45447 }
45448 }
45449
45450 public function isStream()
45451 {
45452 return (strcmp($this->p4DepotType, 'stream') === 0);
45453 }
45454
45455 public function getStream()
45456 {
45457 if (!isset($this->p4Stream)) {
45458 if ($this->isStream()) {
45459 $this->p4Stream = '//' . $this->p4Depot . '/' . $this->p4Branch;
45460 } else {
45461 $this->p4Stream = '//' . $this->p4Depot;
45462 }
45463 }
45464
45465 return $this->p4Stream;
45466 }
45467
45468 public function getStreamWithoutLabel($stream)
45469 {
45470 $index = strpos($stream, '@');
45471 if ($index === false) {
45472 return $stream;
45473 }
45474
45475 return substr($stream, 0, $index);
45476 }
45477
45478 public function getP4ClientSpec()
45479 {
45480 return $this->path . '/' . $this->getClient() . '.p4.spec';
45481 }
45482
45483 public function getUser()
45484 {
45485 return $this->p4User;
45486 }
45487
45488 public function setUser($user)
45489 {
45490 $this->p4User = $user;
45491 }
45492
45493 public function queryP4User()
45494 {
45495 $this->getUser();
45496 if (strlen($this->p4User) > 0) {
45497 return;
45498 }
45499 $this->p4User = $this->getP4variable('P4USER');
45500 if (strlen($this->p4User) > 0) {
45501 return;
45502 }
45503 $this->p4User = $this->io->ask('Enter P4 User:');
45504 if ($this->windowsFlag) {
45505 $command = 'p4 set P4USER=' . $this->p4User;
45506 } else {
45507 $command = 'export P4USER=' . $this->p4User;
45508 }
45509 $this->executeCommand($command);
45510 }
45511
45512 protected function getP4variable($name)
45513 {
45514 if ($this->windowsFlag) {
45515 $command = 'p4 set';
45516 $this->executeCommand($command);
45517 $result = trim($this->commandResult);
45518 $resArray = explode(PHP_EOL, $result);
45519 foreach ($resArray as $line) {
45520 $fields = explode('=', $line);
45521 if (strcmp($name, $fields[0]) == 0) {
45522 $index = strpos($fields[1], ' ');
45523 if ($index === false) {
45524 $value = $fields[1];
45525 } else {
45526 $value = substr($fields[1], 0, $index);
45527 }
45528 $value = trim($value);
45529
45530 return $value;
45531 }
45532 }
45533
45534 return null;
45535 }
45536
45537 $command = 'echo $' . $name;
45538 $this->executeCommand($command);
45539 $result = trim($this->commandResult);
45540
45541 return $result;
45542 }
45543
45544 public function queryP4Password()
45545 {
45546 if (isset($this->p4Password)) {
45547 return $this->p4Password;
45548 }
45549 $password = $this->getP4variable('P4PASSWD');
45550 if (strlen($password) <= 0) {
45551 $password = $this->io->askAndHideAnswer('Enter password for Perforce user ' . $this->getUser() . ': ');
45552 }
45553 $this->p4Password = $password;
45554
45555 return $password;
45556 }
45557
45558 public function generateP4Command($command, $useClient = true)
45559 {
45560 $p4Command = 'p4 ';
45561 $p4Command .= '-u ' . $this->getUser() . ' ';
45562 if ($useClient) {
45563 $p4Command .= '-c ' . $this->getClient() . ' ';
45564 }
45565 $p4Command = $p4Command . '-p ' . $this->getPort() . ' ' . $command;
45566
45567 return $p4Command;
45568 }
45569
45570 public function isLoggedIn()
45571 {
45572 $command = $this->generateP4Command('login -s', false);
45573 $exitCode = $this->executeCommand($command);
45574 if ($exitCode) {
45575 $errorOutput = $this->process->getErrorOutput();
45576 $index = strpos($errorOutput, $this->getUser());
45577 if ($index === false) {
45578 $index = strpos($errorOutput, 'p4');
45579 if ($index === false) {
45580 return false;
45581 }
45582 throw new \Exception('p4 command not found in path: ' . $errorOutput);
45583 }
45584 throw new \Exception('Invalid user name: ' . $this->getUser());
45585 }
45586
45587 return true;
45588 }
45589
45590 public function connectClient()
45591 {
45592 $p4CreateClientCommand = $this->generateP4Command(
45593 'client -i < ' . str_replace(" ", "\\ ", $this->getP4ClientSpec())
45594 );
45595 $this->executeCommand($p4CreateClientCommand);
45596 }
45597
45598 public function syncCodeBase($sourceReference)
45599 {
45600 $prevDir = getcwd();
45601 chdir($this->path);
45602 $p4SyncCommand = $this->generateP4Command('sync -f ');
45603 if (null !== $sourceReference) {
45604 $p4SyncCommand .= '@' . $sourceReference;
45605 }
45606 $this->executeCommand($p4SyncCommand);
45607 chdir($prevDir);
45608 }
45609
45610 public function writeClientSpecToFile($spec)
45611 {
45612 fwrite($spec, 'Client: ' . $this->getClient() . PHP_EOL . PHP_EOL);
45613 fwrite($spec, 'Update: ' . date('Y/m/d H:i:s') . PHP_EOL . PHP_EOL);
45614 fwrite($spec, 'Access: ' . date('Y/m/d H:i:s') . PHP_EOL);
45615 fwrite($spec, 'Owner:  ' . $this->getUser() . PHP_EOL . PHP_EOL);
45616 fwrite($spec, 'Description:' . PHP_EOL);
45617 fwrite($spec, '  Created by ' . $this->getUser() . ' from composer.' . PHP_EOL . PHP_EOL);
45618 fwrite($spec, 'Root: ' . $this->getPath() . PHP_EOL . PHP_EOL);
45619 fwrite($spec, 'Options:  noallwrite noclobber nocompress unlocked modtime rmdir' . PHP_EOL . PHP_EOL);
45620 fwrite($spec, 'SubmitOptions:  revertunchanged' . PHP_EOL . PHP_EOL);
45621 fwrite($spec, 'LineEnd:  local' . PHP_EOL . PHP_EOL);
45622 if ($this->isStream()) {
45623 fwrite($spec, 'Stream:' . PHP_EOL);
45624 fwrite($spec, '  ' . $this->getStreamWithoutLabel($this->p4Stream) . PHP_EOL);
45625 } else {
45626 fwrite(
45627 $spec,
45628 'View:  ' . $this->getStream() . '/...  //' . $this->getClient() . '/... ' . PHP_EOL
45629 );
45630 }
45631 }
45632
45633 public function writeP4ClientSpec()
45634 {
45635 $clientSpec = $this->getP4ClientSpec();
45636 $spec = fopen($clientSpec, 'w');
45637 try {
45638 $this->writeClientSpecToFile($spec);
45639 } catch (\Exception $e) {
45640 fclose($spec);
45641 throw $e;
45642 }
45643 fclose($spec);
45644 }
45645
45646 protected function read($pipe, $name)
45647 {
45648 if (feof($pipe)) {
45649 return;
45650 }
45651 $line = fgets($pipe);
45652 while ($line !== false) {
45653 $line = fgets($pipe);
45654 }
45655 }
45656
45657 public function windowsLogin($password)
45658 {
45659 $command = $this->generateP4Command(' login -a');
45660
45661
45662 if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
45663 $process = Process::fromShellCommandline($command, null, null, $password);
45664 } else {
45665 $process = new Process($command, null, null, $password);
45666 }
45667
45668 return $process->run();
45669 }
45670
45671 public function p4Login()
45672 {
45673 $this->queryP4User();
45674 if (!$this->isLoggedIn()) {
45675 $password = $this->queryP4Password();
45676 if ($this->windowsFlag) {
45677 $this->windowsLogin($password);
45678 } else {
45679 $command = 'echo ' . ProcessExecutor::escape($password) . ' | ' . $this->generateP4Command(' login -a', false);
45680 $exitCode = $this->executeCommand($command);
45681 $result = trim($this->commandResult);
45682 if ($exitCode) {
45683 throw new \Exception("Error logging in:" . $this->process->getErrorOutput());
45684 }
45685 }
45686 }
45687 }
45688
45689 public function getComposerInformation($identifier)
45690 {
45691 $composerFileContent = $this->getFileContent('composer.json', $identifier);
45692
45693 if (!$composerFileContent) {
45694 return;
45695 }
45696
45697 return json_decode($composerFileContent, true);
45698 }
45699
45700 public function getFileContent($file, $identifier)
45701 {
45702 $path = $this->getFilePath($file, $identifier);
45703
45704 $command = $this->generateP4Command(' print ' . ProcessExecutor::escape($path));
45705 $this->executeCommand($command);
45706 $result = $this->commandResult;
45707
45708 if (!trim($result)) {
45709 return null;
45710 }
45711
45712 return $result;
45713 }
45714
45715 public function getFilePath($file, $identifier)
45716 {
45717 $index = strpos($identifier, '@');
45718 if ($index === false) {
45719 $path = $identifier. '/' . $file;
45720
45721 return $path;
45722 }
45723
45724 $path = substr($identifier, 0, $index) . '/' . $file . substr($identifier, $index);
45725 $command = $this->generateP4Command(' files ' . ProcessExecutor::escape($path), false);
45726 $this->executeCommand($command);
45727 $result = $this->commandResult;
45728 $index2 = strpos($result, 'no such file(s).');
45729 if ($index2 === false) {
45730 $index3 = strpos($result, 'change');
45731 if ($index3 !== false) {
45732 $phrase = trim(substr($result, $index3));
45733 $fields = explode(' ', $phrase);
45734
45735 return substr($identifier, 0, $index) . '/' . $file . '@' . $fields[1];
45736 }
45737 }
45738
45739 return null;
45740 }
45741
45742 public function getBranches()
45743 {
45744 $possibleBranches = array();
45745 if (!$this->isStream()) {
45746 $possibleBranches[$this->p4Branch] = $this->getStream();
45747 } else {
45748 $command = $this->generateP4Command('streams '.ProcessExecutor::escape('//' . $this->p4Depot . '/...'));
45749 $this->executeCommand($command);
45750 $result = $this->commandResult;
45751 $resArray = explode(PHP_EOL, $result);
45752 foreach ($resArray as $line) {
45753 $resBits = explode(' ', $line);
45754 if (count($resBits) > 4) {
45755 $branch = preg_replace('/[^A-Za-z0-9 ]/', '', $resBits[4]);
45756 $possibleBranches[$branch] = $resBits[1];
45757 }
45758 }
45759 }
45760 $command = $this->generateP4Command('changes '. ProcessExecutor::escape($this->getStream() . '/...'), false);
45761 $this->executeCommand($command);
45762 $result = $this->commandResult;
45763 $resArray = explode(PHP_EOL, $result);
45764 $lastCommit = $resArray[0];
45765 $lastCommitArr = explode(' ', $lastCommit);
45766 $lastCommitNum = $lastCommitArr[1];
45767
45768 $branches = array('master' => $possibleBranches[$this->p4Branch] . '@'. $lastCommitNum);
45769
45770 return $branches;
45771 }
45772
45773 public function getTags()
45774 {
45775 $command = $this->generateP4Command('labels');
45776 $this->executeCommand($command);
45777 $result = $this->commandResult;
45778 $resArray = explode(PHP_EOL, $result);
45779 $tags = array();
45780 foreach ($resArray as $line) {
45781 if (strpos($line, 'Label') !== false) {
45782 $fields = explode(' ', $line);
45783 $tags[$fields[1]] = $this->getStream() . '@' . $fields[1];
45784 }
45785 }
45786
45787 return $tags;
45788 }
45789
45790 public function checkStream()
45791 {
45792 $command = $this->generateP4Command('depots', false);
45793 $this->executeCommand($command);
45794 $result = $this->commandResult;
45795 $resArray = explode(PHP_EOL, $result);
45796 foreach ($resArray as $line) {
45797 if (strpos($line, 'Depot') !== false) {
45798 $fields = explode(' ', $line);
45799 if (strcmp($this->p4Depot, $fields[1]) === 0) {
45800 $this->p4DepotType = $fields[3];
45801
45802 return $this->isStream();
45803 }
45804 }
45805 }
45806
45807 return false;
45808 }
45809
45810
45811
45812
45813
45814 protected function getChangeList($reference)
45815 {
45816 $index = strpos($reference, '@');
45817 if ($index === false) {
45818 return null;
45819 }
45820 $label = substr($reference, $index);
45821 $command = $this->generateP4Command(' changes -m1 ' . ProcessExecutor::escape($label));
45822 $this->executeCommand($command);
45823 $changes = $this->commandResult;
45824 if (strpos($changes, 'Change') !== 0) {
45825 return null;
45826 }
45827 $fields = explode(' ', $changes);
45828
45829 return $fields[1];
45830 }
45831
45832
45833
45834
45835
45836
45837 public function getCommitLogs($fromReference, $toReference)
45838 {
45839 $fromChangeList = $this->getChangeList($fromReference);
45840 if ($fromChangeList === null) {
45841 return null;
45842 }
45843 $toChangeList = $this->getChangeList($toReference);
45844 if ($toChangeList === null) {
45845 return null;
45846 }
45847 $index = strpos($fromReference, '@');
45848 $main = substr($fromReference, 0, $index) . '/...';
45849 $command = $this->generateP4Command('filelog ' . ProcessExecutor::escape($main . '@' . $fromChangeList. ',' . $toChangeList));
45850 $this->executeCommand($command);
45851
45852 return $this->commandResult;
45853 }
45854
45855 public function getFilesystem()
45856 {
45857 if (empty($this->filesystem)) {
45858 $this->filesystem = new Filesystem($this->process);
45859 }
45860
45861 return $this->filesystem;
45862 }
45863
45864 public function setFilesystem(Filesystem $fs)
45865 {
45866 $this->filesystem = $fs;
45867 }
45868 }
45869 <?php
45870
45871
45872
45873
45874
45875
45876
45877
45878
45879
45880
45881 namespace Composer\Util;
45882
45883
45884
45885
45886
45887
45888 class Platform
45889 {
45890
45891
45892
45893
45894
45895
45896 public static function expandPath($path)
45897 {
45898 if (preg_match('#^~[\\/]#', $path)) {
45899 return self::getUserDirectory() . substr($path, 1);
45900 }
45901
45902 return preg_replace_callback('#^(\$|(?P<percent>%))(?P<var>\w++)(?(percent)%)(?P<path>.*)#', function ($matches) {
45903
45904 if (Platform::isWindows() && $matches['var'] == 'HOME') {
45905 return (getenv('HOME') ?: getenv('USERPROFILE')) . $matches['path'];
45906 }
45907
45908 return getenv($matches['var']) . $matches['path'];
45909 }, $path);
45910 }
45911
45912
45913
45914
45915
45916 public static function getUserDirectory()
45917 {
45918 if (false !== ($home = getenv('HOME'))) {
45919 return $home;
45920 }
45921
45922 if (self::isWindows() && false !== ($home = getenv('USERPROFILE'))) {
45923 return $home;
45924 }
45925
45926 if (function_exists('posix_getuid') && function_exists('posix_getpwuid')) {
45927 $info = posix_getpwuid(posix_getuid());
45928
45929 return $info['dir'];
45930 }
45931
45932 throw new \RuntimeException('Could not determine user directory');
45933 }
45934
45935
45936
45937
45938 public static function isWindows()
45939 {
45940 return defined('PHP_WINDOWS_VERSION_BUILD');
45941 }
45942
45943
45944
45945
45946
45947 public static function strlen($str)
45948 {
45949 static $useMbString = null;
45950 if (null === $useMbString) {
45951 $useMbString = function_exists('mb_strlen') && ini_get('mbstring.func_overload');
45952 }
45953
45954 if ($useMbString) {
45955 return mb_strlen($str, '8bit');
45956 }
45957
45958 return strlen($str);
45959 }
45960 }
45961 <?php
45962
45963
45964
45965
45966
45967
45968
45969
45970
45971
45972
45973 namespace Composer\Util;
45974
45975 use Composer\IO\IOInterface;
45976 use Symfony\Component\Process\Process;
45977 use Symfony\Component\Process\ProcessUtils;
45978
45979
45980
45981
45982 class ProcessExecutor
45983 {
45984 protected static $timeout = 300;
45985
45986 protected $captureOutput;
45987 protected $errorOutput;
45988 protected $io;
45989
45990 public function __construct(IOInterface $io = null)
45991 {
45992 $this->io = $io;
45993 }
45994
45995
45996
45997
45998
45999
46000
46001
46002
46003
46004 public function execute($command, &$output = null, $cwd = null)
46005 {
46006 if ($this->io && $this->io->isDebug()) {
46007 $safeCommand = preg_replace_callback('{://(?P<user>[^:/\s]+):(?P<password>[^@\s/]+)@}i', function ($m) {
46008 if (preg_match('{^[a-f0-9]{12,}$}', $m['user'])) {
46009 return '://***:***@';
46010 }
46011
46012 return '://'.$m['user'].':***@';
46013 }, $command);
46014 $safeCommand = preg_replace("{--password (.*[^\\\\]\') }", '--password \'***\' ', $safeCommand);
46015 $this->io->writeError('Executing command ('.($cwd ?: 'CWD').'): '.$safeCommand);
46016 }
46017
46018
46019
46020 if (null === $cwd && Platform::isWindows() && false !== strpos($command, 'git') && getcwd()) {
46021 $cwd = realpath(getcwd());
46022 }
46023
46024 $this->captureOutput = func_num_args() > 1;
46025 $this->errorOutput = null;
46026
46027
46028 if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
46029 $process = Process::fromShellCommandline($command, $cwd, null, null, static::getTimeout());
46030 } else {
46031 $process = new Process($command, $cwd, null, null, static::getTimeout());
46032 }
46033
46034 $callback = is_callable($output) ? $output : array($this, 'outputHandler');
46035 $process->run($callback);
46036
46037 if ($this->captureOutput && !is_callable($output)) {
46038 $output = $process->getOutput();
46039 }
46040
46041 $this->errorOutput = $process->getErrorOutput();
46042
46043 return $process->getExitCode();
46044 }
46045
46046 public function splitLines($output)
46047 {
46048 $output = trim($output);
46049
46050 return ((string) $output === '') ? array() : preg_split('{\r?\n}', $output);
46051 }
46052
46053
46054
46055
46056
46057
46058 public function getErrorOutput()
46059 {
46060 return $this->errorOutput;
46061 }
46062
46063 public function outputHandler($type, $buffer)
46064 {
46065 if ($this->captureOutput) {
46066 return;
46067 }
46068
46069 if (null === $this->io) {
46070 echo $buffer;
46071
46072 return;
46073 }
46074
46075 if (method_exists($this->io, 'writeRaw')) {
46076 if (Process::ERR === $type) {
46077 $this->io->writeErrorRaw($buffer, false);
46078 } else {
46079 $this->io->writeRaw($buffer, false);
46080 }
46081 } else {
46082 if (Process::ERR === $type) {
46083 $this->io->writeError($buffer, false);
46084 } else {
46085 $this->io->write($buffer, false);
46086 }
46087 }
46088 }
46089
46090 public static function getTimeout()
46091 {
46092 return static::$timeout;
46093 }
46094
46095 public static function setTimeout($timeout)
46096 {
46097 static::$timeout = $timeout;
46098 }
46099
46100
46101
46102
46103
46104
46105
46106
46107 public static function escape($argument)
46108 {
46109 return self::escapeArgument($argument);
46110 }
46111
46112
46113
46114
46115
46116
46117
46118
46119 private static function escapeArgument($argument)
46120 {
46121
46122
46123
46124
46125 if ('\\' === DIRECTORY_SEPARATOR) {
46126 if ((string) $argument === '') {
46127 return escapeshellarg($argument);
46128 }
46129
46130 $escapedArgument = '';
46131 $quote = false;
46132 foreach (preg_split('/(")/', $argument, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $part) {
46133 if ('"' === $part) {
46134 $escapedArgument .= '\\"';
46135 } elseif (self::isSurroundedBy($part, '%')) {
46136
46137 $escapedArgument .= '^%"'.substr($part, 1, -1).'"^%';
46138 } else {
46139
46140 if ('\\' === substr($part, -1)) {
46141 $part .= '\\';
46142 }
46143 $quote = true;
46144 $escapedArgument .= $part;
46145 }
46146 }
46147 if ($quote) {
46148 $escapedArgument = '"'.$escapedArgument.'"';
46149 }
46150
46151 return $escapedArgument;
46152 }
46153
46154 return "'".str_replace("'", "'\\''", $argument)."'";
46155 }
46156
46157 private static function isSurroundedBy($arg, $char)
46158 {
46159 return 2 < strlen($arg) && $char === $arg[0] && $char === $arg[strlen($arg) - 1];
46160 }
46161 }
46162 <?php
46163
46164
46165
46166
46167
46168
46169
46170
46171
46172
46173
46174 namespace Composer\Util;
46175
46176 use Composer\Config;
46177 use Composer\Composer;
46178 use Composer\Semver\Constraint\Constraint;
46179 use Composer\Package\Version\VersionParser;
46180 use Composer\IO\IOInterface;
46181 use Composer\Downloader\TransportException;
46182 use Composer\CaBundle\CaBundle;
46183 use Psr\Log\LoggerInterface;
46184
46185
46186
46187
46188
46189
46190 class RemoteFilesystem
46191 {
46192 private $io;
46193 private $config;
46194 private $scheme;
46195 private $bytesMax;
46196 private $originUrl;
46197 private $fileUrl;
46198 private $fileName;
46199 private $retry;
46200 private $progress;
46201 private $lastProgress;
46202 private $options = array();
46203 private $peerCertificateMap = array();
46204 private $disableTls = false;
46205 private $retryAuthFailure;
46206 private $lastHeaders;
46207 private $storeAuth;
46208 private $degradedMode = false;
46209 private $redirects;
46210 private $maxRedirects = 20;
46211 private $displayedOriginAuthentications = array();
46212
46213
46214
46215
46216
46217
46218
46219
46220
46221 public function __construct(IOInterface $io, Config $config = null, array $options = array(), $disableTls = false)
46222 {
46223 $this->io = $io;
46224
46225
46226
46227 if ($disableTls === false) {
46228 $this->options = $this->getTlsDefaults($options);
46229 } else {
46230 $this->disableTls = true;
46231 }
46232
46233
46234 $this->options = array_replace_recursive($this->options, $options);
46235 $this->config = $config;
46236 }
46237
46238
46239
46240
46241
46242
46243
46244
46245
46246
46247
46248
46249 public function copy($originUrl, $fileUrl, $fileName, $progress = true, $options = array())
46250 {
46251 return $this->get($originUrl, $fileUrl, $options, $fileName, $progress);
46252 }
46253
46254
46255
46256
46257
46258
46259
46260
46261
46262
46263
46264 public function getContents($originUrl, $fileUrl, $progress = true, $options = array())
46265 {
46266 return $this->get($originUrl, $fileUrl, $options, null, $progress);
46267 }
46268
46269
46270
46271
46272
46273
46274 public function getOptions()
46275 {
46276 return $this->options;
46277 }
46278
46279
46280
46281
46282
46283
46284 public function setOptions(array $options)
46285 {
46286 $this->options = array_replace_recursive($this->options, $options);
46287 }
46288
46289
46290
46291
46292
46293
46294 public function isTlsDisabled()
46295 {
46296 return $this->disableTls === true;
46297 }
46298
46299
46300
46301
46302
46303
46304 public function getLastHeaders()
46305 {
46306 return $this->lastHeaders;
46307 }
46308
46309
46310
46311
46312
46313
46314 public function findHeaderValue(array $headers, $name)
46315 {
46316 $value = null;
46317 foreach ($headers as $header) {
46318 if (preg_match('{^'.$name.':\s*(.+?)\s*$}i', $header, $match)) {
46319 $value = $match[1];
46320 } elseif (preg_match('{^HTTP/}i', $header)) {
46321
46322
46323 $value = null;
46324 }
46325 }
46326
46327 return $value;
46328 }
46329
46330
46331
46332
46333
46334 public function findStatusCode(array $headers)
46335 {
46336 $value = null;
46337 foreach ($headers as $header) {
46338 if (preg_match('{^HTTP/\S+ (\d+)}i', $header, $match)) {
46339
46340
46341 $value = (int) $match[1];
46342 }
46343 }
46344
46345 return $value;
46346 }
46347
46348
46349
46350
46351
46352 public function findStatusMessage(array $headers)
46353 {
46354 $value = null;
46355 foreach ($headers as $header) {
46356 if (preg_match('{^HTTP/\S+ \d+}i', $header)) {
46357
46358
46359 $value = $header;
46360 }
46361 }
46362
46363 return $value;
46364 }
46365
46366
46367
46368
46369
46370
46371
46372
46373
46374
46375
46376
46377
46378
46379
46380 protected function get($originUrl, $fileUrl, $additionalOptions = array(), $fileName = null, $progress = true)
46381 {
46382 if (strpos($originUrl, '.github.com') === (strlen($originUrl) - 11)) {
46383 $originUrl = 'github.com';
46384 }
46385
46386
46387
46388 if (
46389 $this->config
46390 && is_array($this->config->get('gitlab-domains'))
46391 && false === strpos($originUrl, '/')
46392 && !in_array($originUrl, $this->config->get('gitlab-domains'))
46393 ) {
46394 foreach ($this->config->get('gitlab-domains') as $gitlabDomain) {
46395 if (0 === strpos($gitlabDomain, $originUrl)) {
46396 $originUrl = $gitlabDomain;
46397 break;
46398 }
46399 }
46400 unset($gitlabDomain);
46401 }
46402
46403 $this->scheme = parse_url($fileUrl, PHP_URL_SCHEME);
46404 $this->bytesMax = 0;
46405 $this->originUrl = $originUrl;
46406 $this->fileUrl = $fileUrl;
46407 $this->fileName = $fileName;
46408 $this->progress = $progress;
46409 $this->lastProgress = null;
46410 $this->retryAuthFailure = true;
46411 $this->lastHeaders = array();
46412 $this->redirects = 1; 
46413
46414
46415 if (preg_match('{^https?://([^:/]+):([^@/]+)@([^/]+)}i', $fileUrl, $match)) {
46416 $this->io->setAuthentication($originUrl, rawurldecode($match[1]), rawurldecode($match[2]));
46417 }
46418
46419 $tempAdditionalOptions = $additionalOptions;
46420 if (isset($tempAdditionalOptions['retry-auth-failure'])) {
46421 $this->retryAuthFailure = (bool) $tempAdditionalOptions['retry-auth-failure'];
46422
46423 unset($tempAdditionalOptions['retry-auth-failure']);
46424 }
46425
46426 $isRedirect = false;
46427 if (isset($tempAdditionalOptions['redirects'])) {
46428 $this->redirects = $tempAdditionalOptions['redirects'];
46429 $isRedirect = true;
46430
46431 unset($tempAdditionalOptions['redirects']);
46432 }
46433
46434 $options = $this->getOptionsForUrl($originUrl, $tempAdditionalOptions);
46435 unset($tempAdditionalOptions);
46436
46437 $origFileUrl = $fileUrl;
46438
46439 if (isset($options['github-token'])) {
46440
46441 if (preg_match('{^https?://api\.github\.com/}', $fileUrl)) {
46442 $options['http']['header'][] = 'Authorization: token '.$options['github-token'];
46443 }
46444 unset($options['github-token']);
46445 }
46446
46447 if (isset($options['gitlab-token'])) {
46448 $fileUrl .= (false === strpos($fileUrl, '?') ? '?' : '&') . 'access_token='.$options['gitlab-token'];
46449 unset($options['gitlab-token']);
46450 }
46451
46452 if (isset($options['http'])) {
46453 $options['http']['ignore_errors'] = true;
46454 }
46455
46456 if ($this->degradedMode && substr($fileUrl, 0, 26) === 'http://repo.packagist.org/') {
46457
46458 $fileUrl = 'http://' . gethostbyname('repo.packagist.org') . substr($fileUrl, 20);
46459 $degradedPackagist = true;
46460 }
46461
46462 $ctx = StreamContextFactory::getContext($fileUrl, $options, array('notification' => array($this, 'callbackGet')));
46463
46464 $actualContextOptions = stream_context_get_options($ctx);
46465 $usingProxy = !empty($actualContextOptions['http']['proxy']) ? ' using proxy ' . $actualContextOptions['http']['proxy'] : '';
46466 $this->io->writeError((substr($origFileUrl, 0, 4) === 'http' ? 'Downloading ' : 'Reading ') . $this->stripCredentialsFromUrl($origFileUrl) . $usingProxy, true, IOInterface::DEBUG);
46467 unset($origFileUrl, $actualContextOptions);
46468
46469
46470 if ((!preg_match('{^http://(repo\.)?packagist\.org/p/}', $fileUrl) || (false === strpos($fileUrl, '$') && false === strpos($fileUrl, '%24'))) && empty($degradedPackagist) && $this->config) {
46471 $this->config->prohibitUrlByConfig($fileUrl, $this->io);
46472 }
46473
46474 if ($this->progress && !$isRedirect) {
46475 $this->io->writeError("Downloading (<comment>connecting...</comment>)", false);
46476 }
46477
46478 $errorMessage = '';
46479 $errorCode = 0;
46480 $result = false;
46481 set_error_handler(function ($code, $msg) use (&$errorMessage) {
46482 if ($errorMessage) {
46483 $errorMessage .= "\n";
46484 }
46485 $errorMessage .= preg_replace('{^file_get_contents\(.*?\): }', '', $msg);
46486
46487 return true;
46488 });
46489 try {
46490 $result = $this->getRemoteContents($originUrl, $fileUrl, $ctx, $http_response_header);
46491
46492 if (!empty($http_response_header[0])) {
46493 $statusCode = $this->findStatusCode($http_response_header);
46494 if ($statusCode >= 400 && $this->findHeaderValue($http_response_header, 'content-type') === 'application/json') {
46495 self::outputWarnings($this->io, $originUrl, json_decode($result, true));
46496 }
46497
46498 if (in_array($statusCode, array(401, 403)) && $this->retryAuthFailure) {
46499 $this->promptAuthAndRetry($statusCode, $this->findStatusMessage($http_response_header), null, $http_response_header);
46500 }
46501 }
46502
46503 $contentLength = !empty($http_response_header[0]) ? $this->findHeaderValue($http_response_header, 'content-length') : null;
46504 if ($contentLength && Platform::strlen($result) < $contentLength) {
46505
46506 $e = new TransportException('Content-Length mismatch, received '.Platform::strlen($result).' bytes out of the expected '.$contentLength);
46507 $e->setHeaders($http_response_header);
46508 $e->setStatusCode($this->findStatusCode($http_response_header));
46509 $e->setResponse($result);
46510 $this->io->writeError('Content-Length mismatch, received '.Platform::strlen($result).' out of '.$contentLength.' bytes: (' . base64_encode($result).')', true, IOInterface::DEBUG);
46511
46512 throw $e;
46513 }
46514
46515 if (PHP_VERSION_ID < 50600 && !empty($options['ssl']['peer_fingerprint'])) {
46516
46517 $params = stream_context_get_params($ctx);
46518 $expectedPeerFingerprint = $options['ssl']['peer_fingerprint'];
46519 $peerFingerprint = TlsHelper::getCertificateFingerprint($params['options']['ssl']['peer_certificate']);
46520
46521
46522 if ($expectedPeerFingerprint !== $peerFingerprint) {
46523 throw new TransportException('Peer fingerprint did not match');
46524 }
46525 }
46526 } catch (\Exception $e) {
46527 if ($e instanceof TransportException && !empty($http_response_header[0])) {
46528 $e->setHeaders($http_response_header);
46529 $e->setStatusCode($this->findStatusCode($http_response_header));
46530 }
46531 if ($e instanceof TransportException && $result !== false) {
46532 $e->setResponse($result);
46533 }
46534 $result = false;
46535 }
46536 if ($errorMessage && !filter_var(ini_get('allow_url_fopen'), FILTER_VALIDATE_BOOLEAN)) {
46537 $errorMessage = 'allow_url_fopen must be enabled in php.ini ('.$errorMessage.')';
46538 }
46539 restore_error_handler();
46540 if (isset($e) && !$this->retry) {
46541 if (!$this->degradedMode && false !== strpos($e->getMessage(), 'Operation timed out')) {
46542 $this->degradedMode = true;
46543 $this->io->writeError('');
46544 $this->io->writeError(array(
46545 '<error>'.$e->getMessage().'</error>',
46546 '<error>Retrying with degraded mode, check https://getcomposer.org/doc/articles/troubleshooting.md#degraded-mode for more info</error>',
46547 ));
46548
46549 return $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress);
46550 }
46551
46552 throw $e;
46553 }
46554
46555 $statusCode = null;
46556 $contentType = null;
46557 $locationHeader = null;
46558 if (!empty($http_response_header[0])) {
46559 $statusCode = $this->findStatusCode($http_response_header);
46560 $contentType = $this->findHeaderValue($http_response_header, 'content-type');
46561 $locationHeader = $this->findHeaderValue($http_response_header, 'location');
46562 }
46563
46564
46565 if ($originUrl === 'bitbucket.org'
46566 && !$this->isPublicBitBucketDownload($fileUrl)
46567 && substr($fileUrl, -4) === '.zip'
46568 && (!$locationHeader || substr(parse_url($locationHeader, PHP_URL_PATH), -4) !== '.zip')
46569 && $contentType && preg_match('{^text/html\b}i', $contentType)
46570 ) {
46571 $result = false;
46572 if ($this->retryAuthFailure) {
46573 $this->promptAuthAndRetry(401);
46574 }
46575 }
46576
46577
46578 if ($statusCode === 404
46579 && $this->config && in_array($originUrl, $this->config->get('gitlab-domains'), true)
46580 && false !== strpos($fileUrl, 'archive.zip')
46581 ) {
46582 $result = false;
46583 if ($this->retryAuthFailure) {
46584 $this->promptAuthAndRetry(401);
46585 }
46586 }
46587
46588
46589 $hasFollowedRedirect = false;
46590 if ($statusCode >= 300 && $statusCode <= 399 && $statusCode !== 304 && $this->redirects < $this->maxRedirects) {
46591 $hasFollowedRedirect = true;
46592 $result = $this->handleRedirect($http_response_header, $additionalOptions, $result);
46593 }
46594
46595
46596 if ($statusCode && $statusCode >= 400 && $statusCode <= 599) {
46597 if (!$this->retry) {
46598 if ($this->progress && !$this->retry && !$isRedirect) {
46599 $this->io->overwriteError("Downloading (<error>failed</error>)", false);
46600 }
46601
46602 $e = new TransportException('The "'.$this->fileUrl.'" file could not be downloaded ('.$http_response_header[0].')', $statusCode);
46603 $e->setHeaders($http_response_header);
46604 $e->setResponse($result);
46605 $e->setStatusCode($statusCode);
46606 throw $e;
46607 }
46608 $result = false;
46609 }
46610
46611 if ($this->progress && !$this->retry && !$isRedirect) {
46612 $this->io->overwriteError("Downloading (".($result === false ? '<error>failed</error>' : '<comment>100%</comment>').")", false);
46613 }
46614
46615
46616 if ($result && extension_loaded('zlib') && substr($fileUrl, 0, 4) === 'http' && !$hasFollowedRedirect) {
46617 $contentEncoding = $this->findHeaderValue($http_response_header, 'content-encoding');
46618 $decode = $contentEncoding && 'gzip' === strtolower($contentEncoding);
46619
46620 if ($decode) {
46621 try {
46622 if (PHP_VERSION_ID >= 50400) {
46623 $result = zlib_decode($result);
46624 } else {
46625
46626 $result = file_get_contents('compress.zlib://data:application/octet-stream;base64,'.base64_encode($result));
46627 }
46628
46629 if (!$result) {
46630 throw new TransportException('Failed to decode zlib stream');
46631 }
46632 } catch (\Exception $e) {
46633 if ($this->degradedMode) {
46634 throw $e;
46635 }
46636
46637 $this->degradedMode = true;
46638 $this->io->writeError(array(
46639 '',
46640 '<error>Failed to decode response: '.$e->getMessage().'</error>',
46641 '<error>Retrying with degraded mode, check https://getcomposer.org/doc/articles/troubleshooting.md#degraded-mode for more info</error>',
46642 ));
46643
46644 return $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress);
46645 }
46646 }
46647 }
46648
46649
46650 if (false !== $result && null !== $fileName && !$isRedirect) {
46651 if ('' === $result) {
46652 throw new TransportException('"'.$this->fileUrl.'" appears broken, and returned an empty 200 response');
46653 }
46654
46655 $errorMessage = '';
46656 set_error_handler(function ($code, $msg) use (&$errorMessage) {
46657 if ($errorMessage) {
46658 $errorMessage .= "\n";
46659 }
46660 $errorMessage .= preg_replace('{^file_put_contents\(.*?\): }', '', $msg);
46661
46662 return true;
46663 });
46664 $result = (bool) file_put_contents($fileName, $result);
46665 restore_error_handler();
46666 if (false === $result) {
46667 throw new TransportException('The "'.$this->fileUrl.'" file could not be written to '.$fileName.': '.$errorMessage);
46668 }
46669 }
46670
46671
46672 if (false === $result && false !== strpos($errorMessage, 'Peer certificate') && PHP_VERSION_ID < 50600) {
46673
46674
46675
46676
46677
46678
46679
46680
46681
46682
46683
46684
46685
46686
46687
46688
46689 if (CaBundle::isOpensslParseSafe()) {
46690 $certDetails = $this->getCertificateCnAndFp($this->fileUrl, $options);
46691
46692 if ($certDetails) {
46693 $this->peerCertificateMap[$this->getUrlAuthority($this->fileUrl)] = $certDetails;
46694
46695 $this->retry = true;
46696 }
46697 } else {
46698 $this->io->writeError('');
46699 $this->io->writeError(sprintf(
46700 '<error>Your version of PHP, %s, is affected by CVE-2013-6420 and cannot safely perform certificate validation, we strongly suggest you upgrade.</error>',
46701 PHP_VERSION
46702 ));
46703 }
46704 }
46705
46706 if ($this->retry) {
46707 $this->retry = false;
46708
46709 $result = $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress);
46710
46711 if ($this->storeAuth && $this->config) {
46712 $authHelper = new AuthHelper($this->io, $this->config);
46713 $authHelper->storeAuth($this->originUrl, $this->storeAuth);
46714 $this->storeAuth = false;
46715 }
46716
46717 return $result;
46718 }
46719
46720 if (false === $result) {
46721 $e = new TransportException('The "'.$this->fileUrl.'" file could not be downloaded: '.$errorMessage, $errorCode);
46722 if (!empty($http_response_header[0])) {
46723 $e->setHeaders($http_response_header);
46724 }
46725
46726 if (!$this->degradedMode && false !== strpos($e->getMessage(), 'Operation timed out')) {
46727 $this->degradedMode = true;
46728 $this->io->writeError('');
46729 $this->io->writeError(array(
46730 '<error>'.$e->getMessage().'</error>',
46731 '<error>Retrying with degraded mode, check https://getcomposer.org/doc/articles/troubleshooting.md#degraded-mode for more info</error>',
46732 ));
46733
46734 return $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress);
46735 }
46736
46737 throw $e;
46738 }
46739
46740 if (!empty($http_response_header[0])) {
46741 $this->lastHeaders = $http_response_header;
46742 }
46743
46744 return $result;
46745 }
46746
46747
46748
46749
46750
46751
46752
46753
46754
46755
46756 protected function getRemoteContents($originUrl, $fileUrl, $context, array &$responseHeaders = null)
46757 {
46758 try {
46759 $e = null;
46760 $result = file_get_contents($fileUrl, false, $context);
46761 } catch (\Throwable $e) {
46762 } catch (\Exception $e) {
46763 }
46764
46765 $responseHeaders = isset($http_response_header) ? $http_response_header : array();
46766
46767 if (null !== $e) {
46768 throw $e;
46769 }
46770
46771 return $result;
46772 }
46773
46774
46775
46776
46777
46778
46779
46780
46781
46782
46783
46784
46785 protected function callbackGet($notificationCode, $severity, $message, $messageCode, $bytesTransferred, $bytesMax)
46786 {
46787 switch ($notificationCode) {
46788 case STREAM_NOTIFY_FAILURE:
46789 if (400 === $messageCode) {
46790
46791
46792 throw new TransportException("The '" . $this->fileUrl . "' URL could not be accessed: " . $message, $messageCode);
46793 }
46794 break;
46795
46796 case STREAM_NOTIFY_FILE_SIZE_IS:
46797 $this->bytesMax = $bytesMax;
46798 break;
46799
46800 case STREAM_NOTIFY_PROGRESS:
46801 if ($this->bytesMax > 0 && $this->progress) {
46802 $progression = min(100, round($bytesTransferred / $this->bytesMax * 100));
46803
46804 if ((0 === $progression % 5) && 100 !== $progression && $progression !== $this->lastProgress) {
46805 $this->lastProgress = $progression;
46806 $this->io->overwriteError("Downloading (<comment>$progression%</comment>)", false);
46807 }
46808 }
46809 break;
46810
46811 default:
46812 break;
46813 }
46814 }
46815
46816 protected function promptAuthAndRetry($httpStatus, $reason = null, $warning = null, $headers = array())
46817 {
46818 if ($this->config && in_array($this->originUrl, $this->config->get('github-domains'), true)) {
46819 $gitHubUtil = new GitHub($this->io, $this->config, null);
46820 $message = "\n";
46821
46822 $rateLimited = $gitHubUtil->isRateLimited($headers);
46823 if ($rateLimited) {
46824 $rateLimit = $gitHubUtil->getRateLimit($headers);
46825 if ($this->io->hasAuthentication($this->originUrl)) {
46826 $message = 'Review your configured GitHub OAuth token or enter a new one to go over the API rate limit.';
46827 } else {
46828 $message = 'Create a GitHub OAuth token to go over the API rate limit.';
46829 }
46830
46831 $message = sprintf(
46832 'GitHub API limit (%d calls/hr) is exhausted, could not fetch '.$this->fileUrl.'. '.$message.' You can also wait until %s for the rate limit to reset.',
46833 $rateLimit['limit'],
46834 $rateLimit['reset']
46835 )."\n";
46836 } else {
46837 $message .= 'Could not fetch '.$this->fileUrl.', please ';
46838 if ($this->io->hasAuthentication($this->originUrl)) {
46839 $message .= 'review your configured GitHub OAuth token or enter a new one to access private repos';
46840 } else {
46841 $message .= 'create a GitHub OAuth token to access private repos';
46842 }
46843 }
46844
46845 if (!$gitHubUtil->authorizeOAuth($this->originUrl)
46846 && (!$this->io->isInteractive() || !$gitHubUtil->authorizeOAuthInteractively($this->originUrl, $message))
46847 ) {
46848 throw new TransportException('Could not authenticate against '.$this->originUrl, 401);
46849 }
46850 } elseif ($this->config && in_array($this->originUrl, $this->config->get('gitlab-domains'), true)) {
46851 $message = "\n".'Could not fetch '.$this->fileUrl.', enter your ' . $this->originUrl . ' credentials ' .($httpStatus === 401 ? 'to access private repos' : 'to go over the API rate limit');
46852 $gitLabUtil = new GitLab($this->io, $this->config, null);
46853
46854 if ($this->io->hasAuthentication($this->originUrl) && ($auth = $this->io->getAuthentication($this->originUrl)) && in_array($auth['password'], array('gitlab-ci-token', 'private-token', 'oauth2'), true)) {
46855 throw new TransportException("Invalid credentials for '" . $this->fileUrl . "', aborting.", $httpStatus);
46856 }
46857
46858 if (!$gitLabUtil->authorizeOAuth($this->originUrl)
46859 && (!$this->io->isInteractive() || !$gitLabUtil->authorizeOAuthInteractively($this->scheme, $this->originUrl, $message))
46860 ) {
46861 throw new TransportException('Could not authenticate against '.$this->originUrl, 401);
46862 }
46863 } elseif ($this->config && ($this->originUrl === 'bitbucket.org' || $this->originUrl === 'api.bitbucket.org')) {
46864 $askForOAuthToken = true;
46865 $this->originUrl = 'bitbucket.org';
46866
46867 if ($this->io->hasAuthentication($this->originUrl)) {
46868 $auth = $this->io->getAuthentication($this->originUrl);
46869 if ($auth['username'] !== 'x-token-auth') {
46870 $bitbucketUtil = new Bitbucket($this->io, $this->config);
46871 $accessToken = $bitbucketUtil->requestToken($this->originUrl, $auth['username'], $auth['password']);
46872 if (!empty($accessToken)) {
46873 $this->io->setAuthentication($this->originUrl, 'x-token-auth', $accessToken);
46874 $askForOAuthToken = false;
46875 }
46876 } else {
46877 throw new TransportException('Could not authenticate against ' . $this->originUrl, 401);
46878 }
46879 }
46880
46881 if ($askForOAuthToken) {
46882 $message = "\n".'Could not fetch ' . $this->fileUrl . ', please create a bitbucket OAuth token to ' . (($httpStatus === 401 || $httpStatus === 403) ? 'access private repos' : 'go over the API rate limit');
46883 $bitBucketUtil = new Bitbucket($this->io, $this->config);
46884 if (! $bitBucketUtil->authorizeOAuth($this->originUrl)
46885 && (! $this->io->isInteractive() || !$bitBucketUtil->authorizeOAuthInteractively($this->originUrl, $message))
46886 ) {
46887 throw new TransportException('Could not authenticate against ' . $this->originUrl, 401);
46888 }
46889 }
46890 } else {
46891
46892 if ($httpStatus === 404) {
46893 return;
46894 }
46895
46896
46897 if (!$this->io->isInteractive()) {
46898 if ($httpStatus === 401) {
46899 $message = "The '" . $this->fileUrl . "' URL required authentication.\nYou must be using the interactive console to authenticate";
46900 }
46901 if ($httpStatus === 403) {
46902 $message = "The '" . $this->fileUrl . "' URL could not be accessed: " . $reason;
46903 }
46904
46905 throw new TransportException($message, $httpStatus);
46906 }
46907
46908 if ($this->io->hasAuthentication($this->originUrl)) {
46909 throw new TransportException("Invalid credentials for '" . $this->fileUrl . "', aborting.", $httpStatus);
46910 }
46911
46912 $this->io->writeError('    Authentication required (<info>'.$this->originUrl.'</info>):');
46913 $username = $this->io->ask('      Username: ');
46914 $password = $this->io->askAndHideAnswer('      Password: ');
46915 $this->io->setAuthentication($this->originUrl, $username, $password);
46916 $this->storeAuth = $this->config->get('store-auths');
46917 }
46918
46919 $this->retry = true;
46920 throw new TransportException('RETRY');
46921 }
46922
46923 protected function getOptionsForUrl($originUrl, $additionalOptions)
46924 {
46925 $tlsOptions = array();
46926
46927
46928 if ($this->disableTls === false && PHP_VERSION_ID < 50600 && !stream_is_local($this->fileUrl)) {
46929 $host = parse_url($this->fileUrl, PHP_URL_HOST);
46930
46931 if (PHP_VERSION_ID < 50304) {
46932
46933
46934
46935
46936
46937 if ($host === 'github.com' || $host === 'api.github.com') {
46938 $host = '*.github.com';
46939 }
46940 }
46941
46942 $tlsOptions['ssl']['CN_match'] = $host;
46943 $tlsOptions['ssl']['SNI_server_name'] = $host;
46944
46945 $urlAuthority = $this->getUrlAuthority($this->fileUrl);
46946
46947 if (isset($this->peerCertificateMap[$urlAuthority])) {
46948
46949 $certMap = $this->peerCertificateMap[$urlAuthority];
46950
46951 $this->io->writeError('', true, IOInterface::DEBUG);
46952 $this->io->writeError(sprintf(
46953 'Using <info>%s</info> as CN for subjectAltName enabled host <info>%s</info>',
46954 $certMap['cn'],
46955 $urlAuthority
46956 ), true, IOInterface::DEBUG);
46957
46958 $tlsOptions['ssl']['CN_match'] = $certMap['cn'];
46959 $tlsOptions['ssl']['peer_fingerprint'] = $certMap['fp'];
46960 } elseif (!CaBundle::isOpensslParseSafe() && $host === 'repo.packagist.org') {
46961
46962 $tlsOptions['ssl']['CN_match'] = 'packagist.org';
46963 }
46964 }
46965
46966 $headers = array();
46967
46968 if (extension_loaded('zlib')) {
46969 $headers[] = 'Accept-Encoding: gzip';
46970 }
46971
46972 $options = array_replace_recursive($this->options, $tlsOptions, $additionalOptions);
46973 if (!$this->degradedMode) {
46974
46975
46976 $options['http']['protocol_version'] = 1.1;
46977 $headers[] = 'Connection: close';
46978 }
46979
46980 if ($this->io->hasAuthentication($originUrl)) {
46981 $authenticationDisplayMessage = null;
46982 $auth = $this->io->getAuthentication($originUrl);
46983 if ($auth['password'] === 'bearer') {
46984 $headers[] = 'Authorization: Bearer '.$auth['username'];
46985 } elseif ('github.com' === $originUrl && 'x-oauth-basic' === $auth['password']) {
46986 $options['github-token'] = $auth['username'];
46987 $authenticationDisplayMessage = 'Using GitHub token authentication';
46988 } elseif ($this->config && in_array($originUrl, $this->config->get('gitlab-domains'), true)) {
46989 if ($auth['password'] === 'oauth2') {
46990 $headers[] = 'Authorization: Bearer '.$auth['username'];
46991 $authenticationDisplayMessage = 'Using GitLab OAuth token authentication';
46992 } elseif ($auth['password'] === 'private-token' || $auth['password'] === 'gitlab-ci-token') {
46993 $headers[] = 'PRIVATE-TOKEN: '.$auth['username'];
46994 $authenticationDisplayMessage = 'Using GitLab private token authentication';
46995 }
46996 } elseif ('bitbucket.org' === $originUrl
46997 && $this->fileUrl !== Bitbucket::OAUTH2_ACCESS_TOKEN_URL && 'x-token-auth' === $auth['username']
46998 ) {
46999 if (!$this->isPublicBitBucketDownload($this->fileUrl)) {
47000 $headers[] = 'Authorization: Bearer ' . $auth['password'];
47001 $authenticationDisplayMessage = 'Using Bitbucket OAuth token authentication';
47002 }
47003 } else {
47004 $authStr = base64_encode($auth['username'] . ':' . $auth['password']);
47005 $headers[] = 'Authorization: Basic '.$authStr;
47006 $authenticationDisplayMessage = 'Using HTTP basic authentication with username "' . $auth['username'] . '"';
47007 }
47008
47009 if ($authenticationDisplayMessage && !in_array($originUrl, $this->displayedOriginAuthentications, true)) {
47010 $this->io->writeError($authenticationDisplayMessage, true, IOInterface::DEBUG);
47011 $this->displayedOriginAuthentications[] = $originUrl;
47012 }
47013 }
47014
47015 $options['http']['follow_location'] = 0;
47016
47017 if (isset($options['http']['header']) && !is_array($options['http']['header'])) {
47018 $options['http']['header'] = explode("\r\n", trim($options['http']['header'], "\r\n"));
47019 }
47020 foreach ($headers as $header) {
47021 $options['http']['header'][] = $header;
47022 }
47023
47024 return $options;
47025 }
47026
47027 private function handleRedirect(array $http_response_header, array $additionalOptions, $result)
47028 {
47029 if ($locationHeader = $this->findHeaderValue($http_response_header, 'location')) {
47030 if (parse_url($locationHeader, PHP_URL_SCHEME)) {
47031
47032 $targetUrl = $locationHeader;
47033 } elseif (parse_url($locationHeader, PHP_URL_HOST)) {
47034
47035 $targetUrl = $this->scheme.':'.$locationHeader;
47036 } elseif ('/' === $locationHeader[0]) {
47037
47038 $urlHost = parse_url($this->fileUrl, PHP_URL_HOST);
47039
47040
47041 $targetUrl = preg_replace('{^(.+(?://|@)'.preg_quote($urlHost).'(?::\d+)?)(?:[/\?].*)?$}', '\1'.$locationHeader, $this->fileUrl);
47042 } else {
47043
47044
47045 $targetUrl = preg_replace('{^(.+/)[^/?]*(?:\?.*)?$}', '\1'.$locationHeader, $this->fileUrl);
47046 }
47047 }
47048
47049 if (!empty($targetUrl)) {
47050 $this->redirects++;
47051
47052 $this->io->writeError('', true, IOInterface::DEBUG);
47053 $this->io->writeError(sprintf('Following redirect (%u) %s', $this->redirects, $this->stripCredentialsFromUrl($targetUrl)), true, IOInterface::DEBUG);
47054
47055 $additionalOptions['redirects'] = $this->redirects;
47056
47057 return $this->get(parse_url($targetUrl, PHP_URL_HOST), $targetUrl, $additionalOptions, $this->fileName, $this->progress);
47058 }
47059
47060 if (!$this->retry) {
47061 $e = new TransportException('The "'.$this->fileUrl.'" file could not be downloaded, got redirect without Location ('.$http_response_header[0].')');
47062 $e->setHeaders($http_response_header);
47063 $e->setResponse($result);
47064
47065 throw $e;
47066 }
47067
47068 return false;
47069 }
47070
47071
47072
47073
47074
47075
47076 private function getTlsDefaults(array $options)
47077 {
47078 $ciphers = implode(':', array(
47079 'ECDHE-RSA-AES128-GCM-SHA256',
47080 'ECDHE-ECDSA-AES128-GCM-SHA256',
47081 'ECDHE-RSA-AES256-GCM-SHA384',
47082 'ECDHE-ECDSA-AES256-GCM-SHA384',
47083 'DHE-RSA-AES128-GCM-SHA256',
47084 'DHE-DSS-AES128-GCM-SHA256',
47085 'kEDH+AESGCM',
47086 'ECDHE-RSA-AES128-SHA256',
47087 'ECDHE-ECDSA-AES128-SHA256',
47088 'ECDHE-RSA-AES128-SHA',
47089 'ECDHE-ECDSA-AES128-SHA',
47090 'ECDHE-RSA-AES256-SHA384',
47091 'ECDHE-ECDSA-AES256-SHA384',
47092 'ECDHE-RSA-AES256-SHA',
47093 'ECDHE-ECDSA-AES256-SHA',
47094 'DHE-RSA-AES128-SHA256',
47095 'DHE-RSA-AES128-SHA',
47096 'DHE-DSS-AES128-SHA256',
47097 'DHE-RSA-AES256-SHA256',
47098 'DHE-DSS-AES256-SHA',
47099 'DHE-RSA-AES256-SHA',
47100 'AES128-GCM-SHA256',
47101 'AES256-GCM-SHA384',
47102 'AES128-SHA256',
47103 'AES256-SHA256',
47104 'AES128-SHA',
47105 'AES256-SHA',
47106 'AES',
47107 'CAMELLIA',
47108 'DES-CBC3-SHA',
47109 '!aNULL',
47110 '!eNULL',
47111 '!EXPORT',
47112 '!DES',
47113 '!RC4',
47114 '!MD5',
47115 '!PSK',
47116 '!aECDH',
47117 '!EDH-DSS-DES-CBC3-SHA',
47118 '!EDH-RSA-DES-CBC3-SHA',
47119 '!KRB5-DES-CBC3-SHA',
47120 ));
47121
47122
47123
47124
47125
47126
47127
47128 $defaults = array(
47129 'ssl' => array(
47130 'ciphers' => $ciphers,
47131 'verify_peer' => true,
47132 'verify_depth' => 7,
47133 'SNI_enabled' => true,
47134 'capture_peer_cert' => true,
47135 ),
47136 );
47137
47138 if (isset($options['ssl'])) {
47139 $defaults['ssl'] = array_replace_recursive($defaults['ssl'], $options['ssl']);
47140 }
47141
47142 $caBundleLogger = $this->io instanceof LoggerInterface ? $this->io : null;
47143
47144
47145
47146
47147
47148 if (!isset($defaults['ssl']['cafile']) && !isset($defaults['ssl']['capath'])) {
47149 $result = CaBundle::getSystemCaRootBundlePath($caBundleLogger);
47150
47151 if (is_dir($result)) {
47152 $defaults['ssl']['capath'] = $result;
47153 } else {
47154 $defaults['ssl']['cafile'] = $result;
47155 }
47156 }
47157
47158 if (isset($defaults['ssl']['cafile']) && (!is_readable($defaults['ssl']['cafile']) || !CaBundle::validateCaFile($defaults['ssl']['cafile'], $caBundleLogger))) {
47159 throw new TransportException('The configured cafile was not valid or could not be read.');
47160 }
47161
47162 if (isset($defaults['ssl']['capath']) && (!is_dir($defaults['ssl']['capath']) || !is_readable($defaults['ssl']['capath']))) {
47163 throw new TransportException('The configured capath was not valid or could not be read.');
47164 }
47165
47166
47167
47168
47169 if (PHP_VERSION_ID >= 50413) {
47170 $defaults['ssl']['disable_compression'] = true;
47171 }
47172
47173 return $defaults;
47174 }
47175
47176
47177
47178
47179
47180
47181 private function getCertificateCnAndFp($url, $options)
47182 {
47183 if (PHP_VERSION_ID >= 50600) {
47184 throw new \BadMethodCallException(sprintf(
47185 '%s must not be used on PHP >= 5.6',
47186 __METHOD__
47187 ));
47188 }
47189
47190 $context = StreamContextFactory::getContext($url, $options, array('options' => array(
47191 'ssl' => array(
47192 'capture_peer_cert' => true,
47193 'verify_peer' => false, 
47194 ), ),
47195 ));
47196
47197
47198
47199 if (false === $handle = @fopen($url, 'rb', false, $context)) {
47200 return;
47201 }
47202
47203
47204 fclose($handle);
47205 $handle = null;
47206
47207 $params = stream_context_get_params($context);
47208
47209 if (!empty($params['options']['ssl']['peer_certificate'])) {
47210 $peerCertificate = $params['options']['ssl']['peer_certificate'];
47211
47212 if (TlsHelper::checkCertificateHost($peerCertificate, parse_url($url, PHP_URL_HOST), $commonName)) {
47213 return array(
47214 'cn' => $commonName,
47215 'fp' => TlsHelper::getCertificateFingerprint($peerCertificate),
47216 );
47217 }
47218 }
47219 }
47220
47221 private function getUrlAuthority($url)
47222 {
47223 $defaultPorts = array(
47224 'ftp' => 21,
47225 'http' => 80,
47226 'https' => 443,
47227 'ssh2.sftp' => 22,
47228 'ssh2.scp' => 22,
47229 );
47230
47231 $scheme = parse_url($url, PHP_URL_SCHEME);
47232
47233 if (!isset($defaultPorts[$scheme])) {
47234 throw new \InvalidArgumentException(sprintf(
47235 'Could not get default port for unknown scheme: %s',
47236 $scheme
47237 ));
47238 }
47239
47240 $defaultPort = $defaultPorts[$scheme];
47241 $port = parse_url($url, PHP_URL_PORT) ?: $defaultPort;
47242
47243 return parse_url($url, PHP_URL_HOST).':'.$port;
47244 }
47245
47246
47247
47248
47249
47250
47251
47252
47253 private function isPublicBitBucketDownload($urlToBitBucketFile)
47254 {
47255 $domain = parse_url($urlToBitBucketFile, PHP_URL_HOST);
47256 if (strpos($domain, 'bitbucket.org') === false) {
47257
47258
47259 return true;
47260 }
47261
47262 $path = parse_url($urlToBitBucketFile, PHP_URL_PATH);
47263
47264
47265
47266 $pathParts = explode('/', $path);
47267
47268 return count($pathParts) >= 4 && $pathParts[3] == 'downloads';
47269 }
47270
47271 public static function outputWarnings(IOInterface $io, $url, $data)
47272 {
47273 foreach (array('warning', 'info') as $type) {
47274 if (empty($data[$type])) {
47275 continue;
47276 }
47277
47278 if (!empty($data[$type . '-versions'])) {
47279 $versionParser = new VersionParser();
47280 $constraint = $versionParser->parseConstraints($data[$type . '-versions']);
47281 $composer = new Constraint('==', $versionParser->normalize(Composer::getVersion()));
47282 if (!$constraint->matches($composer)) {
47283 continue;
47284 }
47285 }
47286
47287 $io->writeError('<'.$type.'>'.ucfirst($type).' from '.$url.': '.$data[$type].'</'.$type.'>');
47288 }
47289 }
47290
47291 public static function getOrigin($urlOrPath)
47292 {
47293 $hostPort = parse_url($urlOrPath, PHP_URL_HOST);
47294 if (!$hostPort) {
47295 return $urlOrPath;
47296 }
47297 if (parse_url($urlOrPath, PHP_URL_PORT)) {
47298 $hostPort .= ':'.parse_url($urlOrPath, PHP_URL_PORT);
47299 }
47300
47301 return $hostPort;
47302 }
47303
47304 private function stripCredentialsFromUrl($url)
47305 {
47306
47307
47308 return preg_replace('{([&?]access_token=)[^&]+}', '$1***', $url);
47309 }
47310 }
47311 <?php
47312
47313
47314
47315
47316
47317
47318
47319
47320
47321
47322
47323 namespace Composer\Util;
47324
47325
47326
47327
47328
47329
47330 class Silencer
47331 {
47332
47333
47334
47335 private static $stack = array();
47336
47337
47338
47339
47340
47341
47342
47343 public static function suppress($mask = null)
47344 {
47345 if (!isset($mask)) {
47346 $mask = E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE | E_DEPRECATED | E_USER_DEPRECATED | E_STRICT;
47347 }
47348 $old = error_reporting();
47349 self::$stack[] = $old;
47350 error_reporting($old & ~$mask);
47351
47352 return $old;
47353 }
47354
47355
47356
47357
47358 public static function restore()
47359 {
47360 if (!empty(self::$stack)) {
47361 error_reporting(array_pop(self::$stack));
47362 }
47363 }
47364
47365
47366
47367
47368
47369
47370
47371
47372
47373
47374 public static function call($callable )
47375 {
47376 try {
47377 self::suppress();
47378 $result = call_user_func_array($callable, array_slice(func_get_args(), 1));
47379 self::restore();
47380
47381 return $result;
47382 } catch (\Exception $e) {
47383
47384 self::restore();
47385 throw $e;
47386 }
47387 }
47388 }
47389 <?php
47390
47391
47392
47393
47394
47395
47396
47397
47398
47399
47400
47401 namespace Composer\Util;
47402
47403 use Composer\Spdx\SpdxLicenses;
47404
47405 trigger_error('The ' . __NAMESPACE__ . '\SpdxLicense class is deprecated, use Composer\Spdx\SpdxLicenses instead.', E_USER_DEPRECATED);
47406
47407
47408
47409
47410 class SpdxLicense extends SpdxLicenses
47411 {
47412 }
47413 <?php
47414
47415
47416
47417
47418
47419
47420
47421
47422
47423
47424
47425 namespace Composer\Util;
47426
47427 use Composer\Composer;
47428
47429
47430
47431
47432
47433
47434
47435 final class StreamContextFactory
47436 {
47437
47438
47439
47440
47441
47442
47443
47444
47445
47446 public static function getContext($url, array $defaultOptions = array(), array $defaultParams = array())
47447 {
47448 $options = array('http' => array(
47449
47450 'follow_location' => 1,
47451 'max_redirects' => 20,
47452 ));
47453
47454
47455 if ((PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') && (!empty($_SERVER['HTTP_PROXY']) || !empty($_SERVER['http_proxy']))) {
47456 $proxy = parse_url(!empty($_SERVER['http_proxy']) ? $_SERVER['http_proxy'] : $_SERVER['HTTP_PROXY']);
47457 }
47458
47459
47460 if (!empty($_SERVER['CGI_HTTP_PROXY'])) {
47461 $proxy = parse_url($_SERVER['CGI_HTTP_PROXY']);
47462 }
47463
47464
47465 if (preg_match('{^https://}i', $url) && (!empty($_SERVER['HTTPS_PROXY']) || !empty($_SERVER['https_proxy']))) {
47466 $proxy = parse_url(!empty($_SERVER['https_proxy']) ? $_SERVER['https_proxy'] : $_SERVER['HTTPS_PROXY']);
47467 }
47468
47469
47470 if (!empty($_SERVER['NO_PROXY']) || !empty($_SERVER['no_proxy']) && parse_url($url, PHP_URL_HOST)) {
47471 $pattern = new NoProxyPattern(!empty($_SERVER['no_proxy']) ? $_SERVER['no_proxy'] : $_SERVER['NO_PROXY']);
47472 if ($pattern->test($url)) {
47473 unset($proxy);
47474 }
47475 }
47476
47477 if (!empty($proxy)) {
47478 $proxyURL = isset($proxy['scheme']) ? $proxy['scheme'] . '://' : '';
47479 $proxyURL .= isset($proxy['host']) ? $proxy['host'] : '';
47480
47481 if (isset($proxy['port'])) {
47482 $proxyURL .= ":" . $proxy['port'];
47483 } elseif ('http://' == substr($proxyURL, 0, 7)) {
47484 $proxyURL .= ":80";
47485 } elseif ('https://' == substr($proxyURL, 0, 8)) {
47486 $proxyURL .= ":443";
47487 }
47488
47489
47490 $proxyURL = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $proxyURL);
47491
47492 if (0 === strpos($proxyURL, 'ssl:') && !extension_loaded('openssl')) {
47493 throw new \RuntimeException('You must enable the openssl extension to use a proxy over https');
47494 }
47495
47496 $options['http']['proxy'] = $proxyURL;
47497
47498
47499 switch (parse_url($url, PHP_URL_SCHEME)) {
47500 case 'http': 
47501 $reqFullUriEnv = getenv('HTTP_PROXY_REQUEST_FULLURI');
47502 if ($reqFullUriEnv === false || $reqFullUriEnv === '' || (strtolower($reqFullUriEnv) !== 'false' && (bool) $reqFullUriEnv)) {
47503 $options['http']['request_fulluri'] = true;
47504 }
47505 break;
47506 case 'https': 
47507 $reqFullUriEnv = getenv('HTTPS_PROXY_REQUEST_FULLURI');
47508 if ($reqFullUriEnv === false || $reqFullUriEnv === '' || (strtolower($reqFullUriEnv) !== 'false' && (bool) $reqFullUriEnv)) {
47509 $options['http']['request_fulluri'] = true;
47510 }
47511 break;
47512 }
47513
47514
47515 if ('https' === parse_url($url, PHP_URL_SCHEME)) {
47516 $options['ssl']['SNI_enabled'] = true;
47517 if (PHP_VERSION_ID < 50600) {
47518 $options['ssl']['SNI_server_name'] = parse_url($url, PHP_URL_HOST);
47519 }
47520 }
47521
47522
47523 if (isset($proxy['user'])) {
47524 $auth = rawurldecode($proxy['user']);
47525 if (isset($proxy['pass'])) {
47526 $auth .= ':' . rawurldecode($proxy['pass']);
47527 }
47528 $auth = base64_encode($auth);
47529
47530
47531 if (isset($defaultOptions['http']['header'])) {
47532 if (is_string($defaultOptions['http']['header'])) {
47533 $defaultOptions['http']['header'] = array($defaultOptions['http']['header']);
47534 }
47535 $defaultOptions['http']['header'][] = "Proxy-Authorization: Basic {$auth}";
47536 } else {
47537 $options['http']['header'] = array("Proxy-Authorization: Basic {$auth}");
47538 }
47539 }
47540 }
47541
47542 $options = array_replace_recursive($options, $defaultOptions);
47543
47544 if (isset($options['http']['header'])) {
47545 $options['http']['header'] = self::fixHttpHeaderField($options['http']['header']);
47546 }
47547
47548 if (defined('HHVM_VERSION')) {
47549 $phpVersion = 'HHVM ' . HHVM_VERSION;
47550 } else {
47551 $phpVersion = 'PHP ' . PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION;
47552 }
47553
47554 if (!isset($options['http']['header']) || false === stripos(implode('', $options['http']['header']), 'user-agent')) {
47555 $options['http']['header'][] = sprintf(
47556 'User-Agent: Composer/%s (%s; %s; %s%s)',
47557 Composer::getVersion(),
47558 function_exists('php_uname') ? php_uname('s') : 'Unknown',
47559 function_exists('php_uname') ? php_uname('r') : 'Unknown',
47560 $phpVersion,
47561 getenv('CI') ? '; CI' : ''
47562 );
47563 }
47564
47565 return stream_context_create($options, $defaultParams);
47566 }
47567
47568
47569
47570
47571
47572
47573
47574
47575
47576
47577
47578 private static function fixHttpHeaderField($header)
47579 {
47580 if (!is_array($header)) {
47581 $header = explode("\r\n", $header);
47582 }
47583 uasort($header, function ($el) {
47584 return stripos($el, 'content-type') === 0 ? 1 : -1;
47585 });
47586
47587 return $header;
47588 }
47589 }
47590 <?php
47591
47592
47593
47594
47595
47596
47597
47598
47599
47600
47601
47602 namespace Composer\Util;
47603
47604 use Composer\Config;
47605 use Composer\IO\IOInterface;
47606
47607
47608
47609
47610
47611 class Svn
47612 {
47613 const MAX_QTY_AUTH_TRIES = 5;
47614
47615
47616
47617
47618 protected $credentials;
47619
47620
47621
47622
47623 protected $hasAuth;
47624
47625
47626
47627
47628 protected $io;
47629
47630
47631
47632
47633 protected $url;
47634
47635
47636
47637
47638 protected $cacheCredentials = true;
47639
47640
47641
47642
47643 protected $process;
47644
47645
47646
47647
47648 protected $qtyAuthTries = 0;
47649
47650
47651
47652
47653 protected $config;
47654
47655
47656
47657
47658 private static $version;
47659
47660
47661
47662
47663
47664
47665
47666 public function __construct($url, IOInterface $io, Config $config, ProcessExecutor $process = null)
47667 {
47668 $this->url = $url;
47669 $this->io = $io;
47670 $this->config = $config;
47671 $this->process = $process ?: new ProcessExecutor($io);
47672 }
47673
47674 public static function cleanEnv()
47675 {
47676
47677 putenv("DYLD_LIBRARY_PATH");
47678 unset($_SERVER['DYLD_LIBRARY_PATH']);
47679 }
47680
47681
47682
47683
47684
47685
47686
47687
47688
47689
47690
47691
47692
47693
47694 public function execute($command, $url, $cwd = null, $path = null, $verbose = false)
47695 {
47696
47697 $this->config->prohibitUrlByConfig($url, $this->io);
47698
47699 return $this->executeWithAuthRetry($command, $cwd, $url, $path, $verbose);
47700 }
47701
47702
47703
47704
47705
47706
47707
47708
47709
47710
47711
47712
47713
47714 public function executeLocal($command, $path, $cwd = null, $verbose = false)
47715 {
47716
47717 return $this->executeWithAuthRetry($command, $cwd, '', $path, $verbose);
47718 }
47719
47720 private function executeWithAuthRetry($svnCommand, $cwd, $url, $path, $verbose)
47721 {
47722
47723 $command = $this->getCommand($svnCommand, $url, $path);
47724
47725 $output = null;
47726 $io = $this->io;
47727 $handler = function ($type, $buffer) use (&$output, $io, $verbose) {
47728 if ($type !== 'out') {
47729 return;
47730 }
47731 if ('Redirecting to URL ' === substr($buffer, 0, 19)) {
47732 return;
47733 }
47734 $output .= $buffer;
47735 if ($verbose) {
47736 $io->writeError($buffer, false);
47737 }
47738 };
47739 $status = $this->process->execute($command, $handler, $cwd);
47740 if (0 === $status) {
47741 return $output;
47742 }
47743
47744 $errorOutput = $this->process->getErrorOutput();
47745 $fullOutput = implode("\n", array($output, $errorOutput));
47746
47747
47748 if (false === stripos($fullOutput, 'Could not authenticate to server:')
47749 && false === stripos($fullOutput, 'authorization failed')
47750 && false === stripos($fullOutput, 'svn: E170001:')
47751 && false === stripos($fullOutput, 'svn: E215004:')) {
47752 throw new \RuntimeException($fullOutput);
47753 }
47754
47755 if (!$this->hasAuth()) {
47756 $this->doAuthDance();
47757 }
47758
47759
47760 if ($this->qtyAuthTries++ < self::MAX_QTY_AUTH_TRIES) {
47761
47762 return $this->executeWithAuthRetry($svnCommand, $cwd, $url, $path, $verbose);
47763 }
47764
47765 throw new \RuntimeException(
47766 'wrong credentials provided ('.$fullOutput.')'
47767 );
47768 }
47769
47770
47771
47772
47773 public function setCacheCredentials($cacheCredentials)
47774 {
47775 $this->cacheCredentials = $cacheCredentials;
47776 }
47777
47778
47779
47780
47781
47782
47783
47784 protected function doAuthDance()
47785 {
47786
47787 if (!$this->io->isInteractive()) {
47788 throw new \RuntimeException(
47789 'can not ask for authentication in non interactive mode'
47790 );
47791 }
47792
47793 $this->io->writeError("The Subversion server ({$this->url}) requested credentials:");
47794
47795 $this->hasAuth = true;
47796 $this->credentials['username'] = $this->io->ask("Username: ");
47797 $this->credentials['password'] = $this->io->askAndHideAnswer("Password: ");
47798
47799 $this->cacheCredentials = $this->io->askConfirmation("Should Subversion cache these credentials? (yes/no) ", true);
47800
47801 return $this;
47802 }
47803
47804
47805
47806
47807
47808
47809
47810
47811
47812
47813 protected function getCommand($cmd, $url, $path = null)
47814 {
47815 $cmd = sprintf(
47816 '%s %s%s %s',
47817 $cmd,
47818 '--non-interactive ',
47819 $this->getCredentialString(),
47820 ProcessExecutor::escape($url)
47821 );
47822
47823 if ($path) {
47824 $cmd .= ' ' . ProcessExecutor::escape($path);
47825 }
47826
47827 return $cmd;
47828 }
47829
47830
47831
47832
47833
47834
47835
47836
47837 protected function getCredentialString()
47838 {
47839 if (!$this->hasAuth()) {
47840 return '';
47841 }
47842
47843 return sprintf(
47844 ' %s--username %s --password %s ',
47845 $this->getAuthCache(),
47846 ProcessExecutor::escape($this->getUsername()),
47847 ProcessExecutor::escape($this->getPassword())
47848 );
47849 }
47850
47851
47852
47853
47854
47855
47856
47857 protected function getPassword()
47858 {
47859 if ($this->credentials === null) {
47860 throw new \LogicException("No svn auth detected.");
47861 }
47862
47863 return isset($this->credentials['password']) ? $this->credentials['password'] : '';
47864 }
47865
47866
47867
47868
47869
47870
47871
47872 protected function getUsername()
47873 {
47874 if ($this->credentials === null) {
47875 throw new \LogicException("No svn auth detected.");
47876 }
47877
47878 return $this->credentials['username'];
47879 }
47880
47881
47882
47883
47884
47885
47886 protected function hasAuth()
47887 {
47888 if (null !== $this->hasAuth) {
47889 return $this->hasAuth;
47890 }
47891
47892 if (false === $this->createAuthFromConfig()) {
47893 $this->createAuthFromUrl();
47894 }
47895
47896 return $this->hasAuth;
47897 }
47898
47899
47900
47901
47902
47903
47904 protected function getAuthCache()
47905 {
47906 return $this->cacheCredentials ? '' : '--no-auth-cache ';
47907 }
47908
47909
47910
47911
47912
47913
47914 private function createAuthFromConfig()
47915 {
47916 if (!$this->config->has('http-basic')) {
47917 return $this->hasAuth = false;
47918 }
47919
47920 $authConfig = $this->config->get('http-basic');
47921
47922 $host = parse_url($this->url, PHP_URL_HOST);
47923 if (isset($authConfig[$host])) {
47924 $this->credentials['username'] = $authConfig[$host]['username'];
47925 $this->credentials['password'] = $authConfig[$host]['password'];
47926
47927 return $this->hasAuth = true;
47928 }
47929
47930 return $this->hasAuth = false;
47931 }
47932
47933
47934
47935
47936
47937
47938 private function createAuthFromUrl()
47939 {
47940 $uri = parse_url($this->url);
47941 if (empty($uri['user'])) {
47942 return $this->hasAuth = false;
47943 }
47944
47945 $this->credentials['username'] = $uri['user'];
47946 if (!empty($uri['pass'])) {
47947 $this->credentials['password'] = $uri['pass'];
47948 }
47949
47950 return $this->hasAuth = true;
47951 }
47952
47953
47954
47955
47956
47957
47958 public function binaryVersion()
47959 {
47960 if (!self::$version) {
47961 if (0 === $this->process->execute('svn --version', $output)) {
47962 if (preg_match('{(\d+(?:\.\d+)+)}', $output, $match)) {
47963 self::$version = $match[1];
47964 }
47965 }
47966 }
47967
47968 return self::$version;
47969 }
47970 }
47971 <?php
47972
47973
47974
47975
47976
47977
47978
47979
47980
47981
47982
47983 namespace Composer\Util;
47984
47985 use Composer\CaBundle\CaBundle;
47986
47987
47988
47989
47990 final class TlsHelper
47991 {
47992
47993
47994
47995
47996
47997
47998
47999
48000
48001 public static function checkCertificateHost($certificate, $hostname, &$cn = null)
48002 {
48003 $names = self::getCertificateNames($certificate);
48004
48005 if (empty($names)) {
48006 return false;
48007 }
48008
48009 $combinedNames = array_merge($names['san'], array($names['cn']));
48010 $hostname = strtolower($hostname);
48011
48012 foreach ($combinedNames as $certName) {
48013 $matcher = self::certNameMatcher($certName);
48014
48015 if ($matcher && $matcher($hostname)) {
48016 $cn = $names['cn'];
48017
48018 return true;
48019 }
48020 }
48021
48022 return false;
48023 }
48024
48025
48026
48027
48028
48029
48030
48031
48032 public static function getCertificateNames($certificate)
48033 {
48034 if (is_array($certificate)) {
48035 $info = $certificate;
48036 } elseif (CaBundle::isOpensslParseSafe()) {
48037 $info = openssl_x509_parse($certificate, false);
48038 }
48039
48040 if (!isset($info['subject']['commonName'])) {
48041 return null;
48042 }
48043
48044 $commonName = strtolower($info['subject']['commonName']);
48045 $subjectAltNames = array();
48046
48047 if (isset($info['extensions']['subjectAltName'])) {
48048 $subjectAltNames = preg_split('{\s*,\s*}', $info['extensions']['subjectAltName']);
48049 $subjectAltNames = array_filter(array_map(function ($name) {
48050 if (0 === strpos($name, 'DNS:')) {
48051 return strtolower(ltrim(substr($name, 4)));
48052 }
48053
48054 return null;
48055 }, $subjectAltNames));
48056 $subjectAltNames = array_values($subjectAltNames);
48057 }
48058
48059 return array(
48060 'cn' => $commonName,
48061 'san' => $subjectAltNames,
48062 );
48063 }
48064
48065
48066
48067
48068
48069
48070
48071
48072
48073
48074
48075
48076
48077
48078
48079
48080
48081
48082
48083
48084
48085
48086
48087
48088
48089
48090
48091
48092
48093
48094
48095
48096
48097
48098
48099
48100
48101
48102
48103
48104 public static function getCertificateFingerprint($certificate)
48105 {
48106 $pubkeydetails = openssl_pkey_get_details(openssl_get_publickey($certificate));
48107 $pubkeypem = $pubkeydetails['key'];
48108
48109 $start = '-----BEGIN PUBLIC KEY-----';
48110 $end = '-----END PUBLIC KEY-----';
48111 $pemtrim = substr($pubkeypem, strpos($pubkeypem, $start) + strlen($start), (strlen($pubkeypem) - strpos($pubkeypem, $end)) * (-1));
48112 $der = base64_decode($pemtrim);
48113
48114 return sha1($der);
48115 }
48116
48117
48118
48119
48120
48121
48122
48123
48124
48125 public static function isOpensslParseSafe()
48126 {
48127 return CaBundle::isOpensslParseSafe();
48128 }
48129
48130
48131
48132
48133
48134
48135
48136
48137 private static function certNameMatcher($certName)
48138 {
48139 $wildcards = substr_count($certName, '*');
48140
48141 if (0 === $wildcards) {
48142
48143 return function ($hostname) use ($certName) {
48144 return $hostname === $certName;
48145 };
48146 }
48147
48148 if (1 === $wildcards) {
48149 $components = explode('.', $certName);
48150
48151 if (3 > count($components)) {
48152
48153 return;
48154 }
48155
48156 $firstComponent = $components[0];
48157
48158
48159 if ('*' !== $firstComponent[strlen($firstComponent) - 1]) {
48160 return;
48161 }
48162
48163 $wildcardRegex = preg_quote($certName);
48164 $wildcardRegex = str_replace('\\*', '[a-z0-9-]+', $wildcardRegex);
48165 $wildcardRegex = "{^{$wildcardRegex}$}";
48166
48167 return function ($hostname) use ($wildcardRegex) {
48168 return 1 === preg_match($wildcardRegex, $hostname);
48169 };
48170 }
48171 }
48172 }
48173 <?php
48174
48175
48176
48177
48178
48179
48180
48181
48182
48183
48184
48185 namespace Composer\Util;
48186
48187 use Composer\Config;
48188
48189
48190
48191
48192 class Url
48193 {
48194 public static function updateDistReference(Config $config, $url, $ref)
48195 {
48196 $host = parse_url($url, PHP_URL_HOST);
48197
48198 if ($host === 'api.github.com' || $host === 'github.com' || $host === 'www.github.com') {
48199 if (preg_match('{^https?://(?:www\.)?github\.com/([^/]+)/([^/]+)/(zip|tar)ball/(.+)$}i', $url, $match)) {
48200
48201 $url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $ref;
48202 } elseif (preg_match('{^https?://(?:www\.)?github\.com/([^/]+)/([^/]+)/archive/.+\.(zip|tar)(?:\.gz)?$}i', $url, $match)) {
48203
48204 $url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $ref;
48205 } elseif (preg_match('{^https?://api\.github\.com/repos/([^/]+)/([^/]+)/(zip|tar)ball(?:/.+)?$}i', $url, $match)) {
48206
48207 $url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $ref;
48208 }
48209 } elseif ($host === 'bitbucket.org' || $host === 'www.bitbucket.org') {
48210 if (preg_match('{^https?://(?:www\.)?bitbucket\.org/([^/]+)/([^/]+)/get/(.+)\.(zip|tar\.gz|tar\.bz2)$}i', $url, $match)) {
48211
48212 $url = 'https://bitbucket.org/' . $match[1] . '/'. $match[2] . '/get/' . $ref . '.' . $match[4];
48213 }
48214 } elseif ($host === 'gitlab.com' || $host === 'www.gitlab.com') {
48215 if (preg_match('{^https?://(?:www\.)?gitlab\.com/api/v[34]/projects/([^/]+)/repository/archive\.(zip|tar\.gz|tar\.bz2|tar)\?sha=.+$}i', $url, $match)) {
48216
48217 $url = 'https://gitlab.com/api/v4/projects/' . $match[1] . '/repository/archive.' . $match[2] . '?sha=' . $ref;
48218 }
48219 } elseif (in_array($host, $config->get('github-domains'), true)) {
48220 $url = preg_replace('{(/repos/[^/]+/[^/]+/(zip|tar)ball)(?:/.+)?$}i', '$1/'.$ref, $url);
48221 } elseif (in_array($host, $config->get('gitlab-domains'), true)) {
48222 $url = preg_replace('{(/api/v[34]/projects/[^/]+/repository/archive\.(?:zip|tar\.gz|tar\.bz2|tar)\?sha=).+$}i', '${1}'.$ref, $url);
48223 }
48224
48225 return $url;
48226 }
48227 }
48228 <?php
48229
48230
48231
48232
48233
48234
48235
48236
48237
48238
48239
48240 namespace Composer\Util;
48241
48242
48243
48244
48245 class Zip
48246 {
48247
48248
48249
48250
48251
48252
48253
48254 public static function getComposerJson($pathToZip)
48255 {
48256 if (!extension_loaded('zip')) {
48257 throw new \RuntimeException('The Zip Util requires PHP\'s zip extension');
48258 }
48259
48260 $zip = new \ZipArchive();
48261 if ($zip->open($pathToZip) !== true) {
48262 return null;
48263 }
48264
48265 if (0 == $zip->numFiles) {
48266 $zip->close();
48267
48268 return null;
48269 }
48270
48271 $foundFileIndex = self::locateFile($zip, 'composer.json');
48272 if (false === $foundFileIndex) {
48273 $zip->close();
48274
48275 return null;
48276 }
48277
48278 $content = null;
48279 $configurationFileName = $zip->getNameIndex($foundFileIndex);
48280 $stream = $zip->getStream($configurationFileName);
48281
48282 if (false !== $stream) {
48283 $content = stream_get_contents($stream);
48284 }
48285
48286 $zip->close();
48287
48288 return $content;
48289 }
48290
48291
48292
48293
48294
48295
48296
48297
48298
48299 private static function locateFile(\ZipArchive $zip, $filename)
48300 {
48301 $indexOfShortestMatch = false;
48302 $lengthOfShortestMatch = -1;
48303
48304 for ($i = 0; $i < $zip->numFiles; $i++) {
48305 $stat = $zip->statIndex($i);
48306 if (strcmp(basename($stat['name']), $filename) === 0) {
48307 $directoryName = dirname($stat['name']);
48308 if ($directoryName === '.') {
48309
48310
48311 return $i;
48312 }
48313
48314 if (strpos($directoryName, '\\') !== false ||
48315 strpos($directoryName, '/') !== false) {
48316
48317 continue;
48318 }
48319
48320 $length = strlen($stat['name']);
48321 if ($indexOfShortestMatch === false || $length < $lengthOfShortestMatch) {
48322
48323 $contents = $zip->getFromIndex($i);
48324 if ($contents !== false) {
48325 $indexOfShortestMatch = $i;
48326 $lengthOfShortestMatch = $length;
48327 }
48328 }
48329 }
48330 }
48331
48332 return $indexOfShortestMatch;
48333 }
48334 }
48335 <?php
48336
48337
48338
48339
48340
48341
48342
48343
48344
48345
48346
48347 namespace Composer;
48348
48349 use Symfony\Component\Console\Output\OutputInterface;
48350
48351 trigger_error('The ' . __NAMESPACE__ . '\XdebugHandler class is deprecated, use Composer\XdebugHandler\XdebugHandler instead,', E_USER_DEPRECATED);
48352
48353
48354
48355
48356 class XdebugHandler extends XdebugHandler\XdebugHandler
48357 {
48358 const ENV_ALLOW = 'COMPOSER_ALLOW_XDEBUG';
48359 const ENV_VERSION = 'COMPOSER_XDEBUG_VERSION';
48360
48361 public function __construct(OutputInterface $output)
48362 {
48363 parent::__construct('composer', '--ansi');
48364 }
48365 }
48366 <?php
48367
48368
48369
48370
48371
48372
48373
48374
48375
48376
48377
48378 function includeIfExists($file)
48379 {
48380 return file_exists($file) ? include $file : false;
48381 }
48382
48383 if ((!$loader = includeIfExists(__DIR__.'/../vendor/autoload.php')) && (!$loader = includeIfExists(__DIR__.'/../../../autoload.php'))) {
48384 echo 'You must set up the project dependencies using `composer install`'.PHP_EOL.
48385 'See https://getcomposer.org/download/ for instructions on installing Composer'.PHP_EOL;
48386 exit(1);
48387 }
48388
48389 return $loader;
48390 <?php
48391
48392 /*
48393  * This file is part of Composer.
48394  *
48395  * (c) Nils Adermann <naderman@naderman.de>
48396  *     Jordi Boggiano <j.boggiano@seld.be>
48397  *
48398  * For the full copyright and license information, please view the LICENSE
48399  * file that was distributed with this source code.
48400  */
48401
48402 namespace Composer\Autoload;
48403
48404 /**
48405  * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
48406  *
48407  *     $loader = new \Composer\Autoload\ClassLoader();
48408  *
48409  *     // register classes with namespaces
48410  *     $loader->add('Symfony\Component', __DIR__.'/component');
48411  *     $loader->add('Symfony',           __DIR__.'/framework');
48412  *
48413  *     // activate the autoloader
48414  *     $loader->register();
48415  *
48416  *     // to enable searching the include path (eg. for PEAR packages)
48417  *     $loader->setUseIncludePath(true);
48418  *
48419  * In this example, if you try to use a class in the Symfony\Component
48420  * namespace or one of its children (Symfony\Component\Console for instance),
48421  * the autoloader will first look for the class under the component/
48422  * directory, and it will then fallback to the framework/ directory if not
48423  * found before giving up.
48424  *
48425  * This class is loosely based on the Symfony UniversalClassLoader.
48426  *
48427  * @author Fabien Potencier <fabien@symfony.com>
48428  * @author Jordi Boggiano <j.boggiano@seld.be>
48429  * @see    http://www.php-fig.org/psr/psr-0/
48430  * @see    http://www.php-fig.org/psr/psr-4/
48431  */
48432 class ClassLoader
48433 {
48434     // PSR-4
48435     private $prefixLengthsPsr4 = array();
48436     private $prefixDirsPsr4 = array();
48437     private $fallbackDirsPsr4 = array();
48438
48439     // PSR-0
48440     private $prefixesPsr0 = array();
48441     private $fallbackDirsPsr0 = array();
48442
48443     private $useIncludePath = false;
48444     private $classMap = array();
48445     private $classMapAuthoritative = false;
48446     private $missingClasses = array();
48447     private $apcuPrefix;
48448
48449     public function getPrefixes()
48450     {
48451         if (!empty($this->prefixesPsr0)) {
48452             return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
48453         }
48454
48455         return array();
48456     }
48457
48458     public function getPrefixesPsr4()
48459     {
48460         return $this->prefixDirsPsr4;
48461     }
48462
48463     public function getFallbackDirs()
48464     {
48465         return $this->fallbackDirsPsr0;
48466     }
48467
48468     public function getFallbackDirsPsr4()
48469     {
48470         return $this->fallbackDirsPsr4;
48471     }
48472
48473     public function getClassMap()
48474     {
48475         return $this->classMap;
48476     }
48477
48478     /**
48479      * @param array $classMap Class to filename map
48480      */
48481     public function addClassMap(array $classMap)
48482     {
48483         if ($this->classMap) {
48484             $this->classMap = array_merge($this->classMap, $classMap);
48485         } else {
48486             $this->classMap = $classMap;
48487         }
48488     }
48489
48490     /**
48491      * Registers a set of PSR-0 directories for a given prefix, either
48492      * appending or prepending to the ones previously set for this prefix.
48493      *
48494      * @param string       $prefix  The prefix
48495      * @param array|string $paths   The PSR-0 root directories
48496      * @param bool         $prepend Whether to prepend the directories
48497      */
48498     public function add($prefix, $paths, $prepend = false)
48499     {
48500         if (!$prefix) {
48501             if ($prepend) {
48502                 $this->fallbackDirsPsr0 = array_merge(
48503                     (array) $paths,
48504                     $this->fallbackDirsPsr0
48505                 );
48506             } else {
48507                 $this->fallbackDirsPsr0 = array_merge(
48508                     $this->fallbackDirsPsr0,
48509                     (array) $paths
48510                 );
48511             }
48512
48513             return;
48514         }
48515
48516         $first = $prefix[0];
48517         if (!isset($this->prefixesPsr0[$first][$prefix])) {
48518             $this->prefixesPsr0[$first][$prefix] = (array) $paths;
48519
48520             return;
48521         }
48522         if ($prepend) {
48523             $this->prefixesPsr0[$first][$prefix] = array_merge(
48524                 (array) $paths,
48525                 $this->prefixesPsr0[$first][$prefix]
48526             );
48527         } else {
48528             $this->prefixesPsr0[$first][$prefix] = array_merge(
48529                 $this->prefixesPsr0[$first][$prefix],
48530                 (array) $paths
48531             );
48532         }
48533     }
48534
48535     /**
48536      * Registers a set of PSR-4 directories for a given namespace, either
48537      * appending or prepending to the ones previously set for this namespace.
48538      *
48539      * @param string       $prefix  The prefix/namespace, with trailing '\\'
48540      * @param array|string $paths   The PSR-4 base directories
48541      * @param bool         $prepend Whether to prepend the directories
48542      *
48543      * @throws \InvalidArgumentException
48544      */
48545     public function addPsr4($prefix, $paths, $prepend = false)
48546     {
48547         if (!$prefix) {
48548             // Register directories for the root namespace.
48549             if ($prepend) {
48550                 $this->fallbackDirsPsr4 = array_merge(
48551                     (array) $paths,
48552                     $this->fallbackDirsPsr4
48553                 );
48554             } else {
48555                 $this->fallbackDirsPsr4 = array_merge(
48556                     $this->fallbackDirsPsr4,
48557                     (array) $paths
48558                 );
48559             }
48560         } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
48561             // Register directories for a new namespace.
48562             $length = strlen($prefix);
48563             if ('\\' !== $prefix[$length - 1]) {
48564                 throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
48565             }
48566             $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
48567             $this->prefixDirsPsr4[$prefix] = (array) $paths;
48568         } elseif ($prepend) {
48569             // Prepend directories for an already registered namespace.
48570             $this->prefixDirsPsr4[$prefix] = array_merge(
48571                 (array) $paths,
48572                 $this->prefixDirsPsr4[$prefix]
48573             );
48574         } else {
48575             // Append directories for an already registered namespace.
48576             $this->prefixDirsPsr4[$prefix] = array_merge(
48577                 $this->prefixDirsPsr4[$prefix],
48578                 (array) $paths
48579             );
48580         }
48581     }
48582
48583     /**
48584      * Registers a set of PSR-0 directories for a given prefix,
48585      * replacing any others previously set for this prefix.
48586      *
48587      * @param string       $prefix The prefix
48588      * @param array|string $paths  The PSR-0 base directories
48589      */
48590     public function set($prefix, $paths)
48591     {
48592         if (!$prefix) {
48593             $this->fallbackDirsPsr0 = (array) $paths;
48594         } else {
48595             $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
48596         }
48597     }
48598
48599     /**
48600      * Registers a set of PSR-4 directories for a given namespace,
48601      * replacing any others previously set for this namespace.
48602      *
48603      * @param string       $prefix The prefix/namespace, with trailing '\\'
48604      * @param array|string $paths  The PSR-4 base directories
48605      *
48606      * @throws \InvalidArgumentException
48607      */
48608     public function setPsr4($prefix, $paths)
48609     {
48610         if (!$prefix) {
48611             $this->fallbackDirsPsr4 = (array) $paths;
48612         } else {
48613             $length = strlen($prefix);
48614             if ('\\' !== $prefix[$length - 1]) {
48615                 throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
48616             }
48617             $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
48618             $this->prefixDirsPsr4[$prefix] = (array) $paths;
48619         }
48620     }
48621
48622     /**
48623      * Turns on searching the include path for class files.
48624      *
48625      * @param bool $useIncludePath
48626      */
48627     public function setUseIncludePath($useIncludePath)
48628     {
48629         $this->useIncludePath = $useIncludePath;
48630     }
48631
48632     /**
48633      * Can be used to check if the autoloader uses the include path to check
48634      * for classes.
48635      *
48636      * @return bool
48637      */
48638     public function getUseIncludePath()
48639     {
48640         return $this->useIncludePath;
48641     }
48642
48643     /**
48644      * Turns off searching the prefix and fallback directories for classes
48645      * that have not been registered with the class map.
48646      *
48647      * @param bool $classMapAuthoritative
48648      */
48649     public function setClassMapAuthoritative($classMapAuthoritative)
48650     {
48651         $this->classMapAuthoritative = $classMapAuthoritative;
48652     }
48653
48654     /**
48655      * Should class lookup fail if not found in the current class map?
48656      *
48657      * @return bool
48658      */
48659     public function isClassMapAuthoritative()
48660     {
48661         return $this->classMapAuthoritative;
48662     }
48663
48664     /**
48665      * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
48666      *
48667      * @param string|null $apcuPrefix
48668      */
48669     public function setApcuPrefix($apcuPrefix)
48670     {
48671         $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
48672     }
48673
48674     /**
48675      * The APCu prefix in use, or null if APCu caching is not enabled.
48676      *
48677      * @return string|null
48678      */
48679     public function getApcuPrefix()
48680     {
48681         return $this->apcuPrefix;
48682     }
48683
48684     /**
48685      * Registers this instance as an autoloader.
48686      *
48687      * @param bool $prepend Whether to prepend the autoloader or not
48688      */
48689     public function register($prepend = false)
48690     {
48691         spl_autoload_register(array($this, 'loadClass'), true, $prepend);
48692     }
48693
48694     /**
48695      * Unregisters this instance as an autoloader.
48696      */
48697     public function unregister()
48698     {
48699         spl_autoload_unregister(array($this, 'loadClass'));
48700     }
48701
48702     /**
48703      * Loads the given class or interface.
48704      *
48705      * @param  string    $class The name of the class
48706      * @return bool|null True if loaded, null otherwise
48707      */
48708     public function loadClass($class)
48709     {
48710         if ($file = $this->findFile($class)) {
48711             includeFile($file);
48712
48713             return true;
48714         }
48715     }
48716
48717     /**
48718      * Finds the path to the file where the class is defined.
48719      *
48720      * @param string $class The name of the class
48721      *
48722      * @return string|false The path if found, false otherwise
48723      */
48724     public function findFile($class)
48725     {
48726         // class map lookup
48727         if (isset($this->classMap[$class])) {
48728             return $this->classMap[$class];
48729         }
48730         if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
48731             return false;
48732         }
48733         if (null !== $this->apcuPrefix) {
48734             $file = apcu_fetch($this->apcuPrefix.$class, $hit);
48735             if ($hit) {
48736                 return $file;
48737             }
48738         }
48739
48740         $file = $this->findFileWithExtension($class, '.php');
48741
48742         // Search for Hack files if we are running on HHVM
48743         if (false === $file && defined('HHVM_VERSION')) {
48744             $file = $this->findFileWithExtension($class, '.hh');
48745         }
48746
48747         if (null !== $this->apcuPrefix) {
48748             apcu_add($this->apcuPrefix.$class, $file);
48749         }
48750
48751         if (false === $file) {
48752             // Remember that this class does not exist.
48753             $this->missingClasses[$class] = true;
48754         }
48755
48756         return $file;
48757     }
48758
48759     private function findFileWithExtension($class, $ext)
48760     {
48761         // PSR-4 lookup
48762         $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
48763
48764         $first = $class[0];
48765         if (isset($this->prefixLengthsPsr4[$first])) {
48766             $subPath = $class;
48767             while (false !== $lastPos = strrpos($subPath, '\\')) {
48768                 $subPath = substr($subPath, 0, $lastPos);
48769                 $search = $subPath . '\\';
48770                 if (isset($this->prefixDirsPsr4[$search])) {
48771                     $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
48772                     foreach ($this->prefixDirsPsr4[$search] as $dir) {
48773                         if (file_exists($file = $dir . $pathEnd)) {
48774                             return $file;
48775                         }
48776                     }
48777                 }
48778             }
48779         }
48780
48781         // PSR-4 fallback dirs
48782         foreach ($this->fallbackDirsPsr4 as $dir) {
48783             if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
48784                 return $file;
48785             }
48786         }
48787
48788         // PSR-0 lookup
48789         if (false !== $pos = strrpos($class, '\\')) {
48790             // namespaced class name
48791             $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
48792                 . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
48793         } else {
48794             // PEAR-like class name
48795             $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
48796         }
48797
48798         if (isset($this->prefixesPsr0[$first])) {
48799             foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
48800                 if (0 === strpos($class, $prefix)) {
48801                     foreach ($dirs as $dir) {
48802                         if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
48803                             return $file;
48804                         }
48805                     }
48806                 }
48807             }
48808         }
48809
48810         // PSR-0 fallback dirs
48811         foreach ($this->fallbackDirsPsr0 as $dir) {
48812             if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
48813                 return $file;
48814             }
48815         }
48816
48817         // PSR-0 include paths.
48818         if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
48819             return $file;
48820         }
48821
48822         return false;
48823     }
48824 }
48825
48826 /**
48827  * Scope isolated include.
48828  *
48829  * Prevents access to $this/self from included files.
48830  */
48831 function includeFile($file)
48832 {
48833     include $file;
48834 }
48835 {
48836     "$schema": "http://json-schema.org/draft-04/schema#",
48837     "description": "A representation of packages metadata.",
48838     "type": "object",
48839     "oneOf": [
48840         { "required": [ "packages" ] },
48841         { "required": [ "providers" ] },
48842         { "required": [ "provider-includes", "providers-url" ] }
48843     ],
48844     "properties": {
48845         "packages": {
48846             "type": ["object", "array"],
48847             "description": "A hashmap of package names in the form of <vendor>/<name>.",
48848             "additionalProperties": { "$ref": "#/definitions/versions" }
48849         },
48850         "providers-url": {
48851             "type": "string",
48852             "description": "Endpoint to retrieve provider data from, e.g. '/p/%package%$%hash%.json'."
48853         },
48854         "provider-includes": {
48855             "type": "object",
48856             "description": "A hashmap of provider listings.",
48857             "additionalProperties": { "$ref": "#/definitions/provider" }
48858         },
48859         "providers": {
48860             "type": "object",
48861             "description": "A hashmap of package names in the form of <vendor>/<name>.",
48862             "additionalProperties": { "$ref": "#/definitions/provider" }
48863         },
48864         "notify-batch": {
48865             "type": "string",
48866             "description": "Endpoint to call after multiple packages have been installed, e.g. '/downloads/'."
48867         },
48868         "search": {
48869             "type": "string",
48870             "description": "Endpoint that provides search capabilities, e.g. '/search.json?q=%query%&type=%type%'."
48871         },
48872         "warning": {
48873             "type": "string",
48874             "description": "A message that will be output by Composer as a warning when this source is consulted."
48875         }
48876     },
48877     "definitions": {
48878         "versions": {
48879             "type": "object",
48880             "description": "A hashmap of versions and their metadata.",
48881             "additionalProperties": { "$ref": "#/definitions/version" }
48882         },
48883         "version": {
48884             "type": "object",
48885             "oneOf": [
48886                 { "$ref": "#/definitions/package" },
48887                 { "$ref": "#/definitions/metapackage" }
48888             ]
48889         },
48890         "package-base": {
48891             "properties": {
48892                 "name": { "type": "string" },
48893                 "type": { "type": "string" },
48894                 "version": { "type": "string" },
48895                 "version_normalized": {
48896                     "type": "string",
48897                     "description": "Normalized version, optional but can save computational time on client side."
48898                 },
48899                 "autoload": { "type": "object" },
48900                 "require": { "type": "object" },
48901                 "replace": { "type": "object" },
48902                 "conflict": { "type": "object" },
48903                 "provide": { "type": "object" },
48904                 "time": { "type": "string" }
48905             },
48906             "additionalProperties": true
48907         },
48908         "package": {
48909             "allOf": [
48910                 { "$ref": "#/definitions/package-base" },
48911                 {
48912                     "properties": {
48913                         "dist": { "type": "object" },
48914                         "source": { "type": "object" }
48915                     }
48916                 },
48917                 { "oneOf": [
48918                     { "required": [ "name", "version", "source" ] },
48919                     { "required": [ "name", "version", "dist" ] }
48920                 ] }
48921             ]
48922         },
48923         "metapackage": {
48924             "allOf": [
48925                 { "$ref": "#/definitions/package-base" },
48926                 {
48927                     "properties": {
48928                         "type": { "type": "string", "enum": [ "metapackage" ] }
48929                     },
48930                     "required": [ "name", "version", "type" ]
48931                 }
48932             ]
48933         },
48934         "provider": {
48935             "type": "object",
48936             "properties": {
48937                 "sha256": {
48938                     "type": "string",
48939                     "description": "Hash value that can be used to validate the resource."
48940                 }
48941             }
48942         }
48943     }
48944 }
48945 {
48946     "$schema": "http://json-schema.org/draft-04/schema#",
48947     "name": "Package",
48948     "type": "object",
48949     "additionalProperties": false,
48950     "required": [ "name", "description" ],
48951     "properties": {
48952         "name": {
48953             "type": "string",
48954             "description": "Package name, including 'vendor-name/' prefix."
48955         },
48956         "type": {
48957             "description": "Package type, either 'library' for common packages, 'composer-plugin' for plugins, 'metapackage' for empty packages, or a custom type ([a-z0-9-]+) defined by whatever project this package applies to.",
48958             "type": "string",
48959             "pattern": "^[a-z0-9-]+$"
48960         },
48961         "target-dir": {
48962             "description": "DEPRECATED: Forces the package to be installed into the given subdirectory path. This is used for autoloading PSR-0 packages that do not contain their full path. Use forward slashes for cross-platform compatibility.",
48963             "type": "string"
48964         },
48965         "description": {
48966             "type": "string",
48967             "description": "Short package description."
48968         },
48969         "keywords": {
48970             "type": "array",
48971             "items": {
48972                 "type": "string",
48973                 "description": "A tag/keyword that this package relates to."
48974             }
48975         },
48976         "homepage": {
48977             "type": "string",
48978             "description": "Homepage URL for the project.",
48979             "format": "uri"
48980         },
48981         "readme": {
48982             "type": "string",
48983             "description": "Relative path to the readme document."
48984         },
48985         "version": {
48986             "type": "string",
48987             "description": "Package version, see https://getcomposer.org/doc/04-schema.md#version for more info on valid schemes.",
48988             "pattern": "^v?\\d+(((\\.\\d+)?\\.\\d+)?\\.\\d+)?|^dev-"
48989         },
48990         "time": {
48991             "type": "string",
48992             "description": "Package release date, in 'YYYY-MM-DD', 'YYYY-MM-DD HH:MM:SS' or 'YYYY-MM-DDTHH:MM:SSZ' format."
48993         },
48994         "license": {
48995             "type": ["string", "array"],
48996             "description": "License name. Or an array of license names."
48997         },
48998         "authors": {
48999             "$ref": "#/definitions/authors"
49000         },
49001         "require": {
49002             "type": "object",
49003             "description": "This is a hash of package name (keys) and version constraints (values) that are required to run this package.",
49004             "additionalProperties": {
49005                 "type": "string"
49006             }
49007         },
49008         "replace": {
49009             "type": "object",
49010             "description": "This is a hash of package name (keys) and version constraints (values) that can be replaced by this package.",
49011             "additionalProperties": {
49012                 "type": "string"
49013             }
49014         },
49015         "conflict": {
49016             "type": "object",
49017             "description": "This is a hash of package name (keys) and version constraints (values) that conflict with this package.",
49018             "additionalProperties": {
49019                 "type": "string"
49020             }
49021         },
49022         "provide": {
49023             "type": "object",
49024             "description": "This is a hash of package name (keys) and version constraints (values) that this package provides in addition to this package's name.",
49025             "additionalProperties": {
49026                 "type": "string"
49027             }
49028         },
49029         "require-dev": {
49030             "type": "object",
49031             "description": "This is a hash of package name (keys) and version constraints (values) that this package requires for developing it (testing tools and such).",
49032             "additionalProperties": {
49033                 "type": "string"
49034             }
49035         },
49036         "suggest": {
49037             "type": "object",
49038             "description": "This is a hash of package name (keys) and descriptions (values) that this package suggests work well with it (this will be suggested to the user during installation).",
49039             "additionalProperties": {
49040                 "type": "string"
49041             }
49042         },
49043         "config": {
49044             "type": "object",
49045             "description": "Composer options.",
49046             "properties": {
49047                 "process-timeout": {
49048                     "type": "integer",
49049                     "description": "The timeout in seconds for process executions, defaults to 300 (5mins)."
49050                 },
49051                 "use-include-path": {
49052                     "type": "boolean",
49053                     "description": "If true, the Composer autoloader will also look for classes in the PHP include path."
49054                 },
49055                 "preferred-install": {
49056                     "type": ["string", "object"],
49057                     "description": "The install method Composer will prefer to use, defaults to auto and can be any of source, dist, auto, or a hash of {\"pattern\": \"preference\"}."
49058                 },
49059                 "notify-on-install": {
49060                     "type": "boolean",
49061                     "description": "Composer allows repositories to define a notification URL, so that they get notified whenever a package from that repository is installed. This option allows you to disable that behaviour, defaults to true."
49062                 },
49063                 "github-protocols": {
49064                     "type": "array",
49065                     "description": "A list of protocols to use for github.com clones, in priority order, defaults to [\"git\", \"https\", \"http\"].",
49066                     "items": {
49067                         "type": "string"
49068                     }
49069                 },
49070                 "github-oauth": {
49071                     "type": "object",
49072                     "description": "A hash of domain name => github API oauth tokens, typically {\"github.com\":\"<token>\"}.",
49073                     "additionalProperties": {
49074                         "type": "string"
49075                     }
49076                 },
49077                 "gitlab-oauth": {
49078                     "type": "object",
49079                     "description": "A hash of domain name => gitlab API oauth tokens, typically {\"gitlab.com\":\"<token>\"}.",
49080                     "additionalProperties": {
49081                         "type": "string"
49082                     }
49083                 },
49084                 "gitlab-token": {
49085                     "type": "object",
49086                     "description": "A hash of domain name => gitlab private tokens, typically {\"gitlab.com\":\"<token>\"}.",
49087                     "additionalProperties": {
49088                         "type": "string"
49089                     }
49090                 },
49091                 "bearer": {
49092                     "type": "object",
49093                     "description": "A hash of domain name => bearer authentication token, for example {\"example.com\":\"<token>\"}.",
49094                     "additionalProperties": {
49095                         "type": "string"
49096                     }
49097                 },
49098                 "disable-tls": {
49099                     "type": "boolean",
49100                     "description": "Defaults to `false`. If set to true all HTTPS URLs will be tried with HTTP instead and no network level encryption is performed. Enabling this is a security risk and is NOT recommended. The better way is to enable the php_openssl extension in php.ini."
49101                 },
49102                 "secure-http": {
49103                     "type": "boolean",
49104                     "description": "Defaults to `true`. If set to true only HTTPS URLs are allowed to be downloaded via Composer. If you really absolutely need HTTP access to something then you can disable it, but using \"Let's Encrypt\" to get a free SSL certificate is generally a better alternative."
49105                 },
49106                 "cafile": {
49107                     "type": "string",
49108                     "description": "A way to set the path to the openssl CA file. In PHP 5.6+ you should rather set this via openssl.cafile in php.ini, although PHP 5.6+ should be able to detect your system CA file automatically."
49109                 },
49110                 "capath": {
49111                     "type": "string",
49112                     "description": "If cafile is not specified or if the certificate is not found there, the directory pointed to by capath is searched for a suitable certificate. capath must be a correctly hashed certificate directory."
49113                 },
49114                 "http-basic": {
49115                     "type": "object",
49116                     "description": "A hash of domain name => {\"username\": \"...\", \"password\": \"...\"}.",
49117                     "additionalProperties": {
49118                         "type": "object",
49119                         "required": ["username", "password"],
49120                         "properties": {
49121                             "username": {
49122                                 "type": "string",
49123                                 "description": "The username used for HTTP Basic authentication"
49124                             },
49125                             "password": {
49126                                 "type": "string",
49127                                 "description": "The password used for HTTP Basic authentication"
49128                             }
49129                         }
49130                     }
49131                 },
49132                 "store-auths": {
49133                     "type": ["string", "boolean"],
49134                     "description": "What to do after prompting for authentication, one of: true (store), false (do not store) or \"prompt\" (ask every time), defaults to prompt."
49135                 },
49136                 "platform": {
49137                     "type": "object",
49138                     "description": "This is a hash of package name (keys) and version (values) that will be used to mock the platform packages on this machine.",
49139                     "additionalProperties": {
49140                         "type": "string"
49141                     }
49142                 },
49143                 "vendor-dir": {
49144                     "type": "string",
49145                     "description": "The location where all packages are installed, defaults to \"vendor\"."
49146                 },
49147                 "bin-dir": {
49148                     "type": "string",
49149                     "description": "The location where all binaries are linked, defaults to \"vendor/bin\"."
49150                 },
49151                 "data-dir": {
49152                     "type": "string",
49153                     "description": "The location where old phar files are stored, defaults to \"$home\" except on XDG Base Directory compliant unixes."
49154                 },
49155                 "cache-dir": {
49156                     "type": "string",
49157                     "description": "The location where all caches are located, defaults to \"~/.composer/cache\" on *nix and \"%LOCALAPPDATA%\\Composer\" on windows."
49158                 },
49159                 "cache-files-dir": {
49160                     "type": "string",
49161                     "description": "The location where files (zip downloads) are cached, defaults to \"{$cache-dir}/files\"."
49162                 },
49163                 "cache-repo-dir": {
49164                     "type": "string",
49165                     "description": "The location where repo (git/hg repo clones) are cached, defaults to \"{$cache-dir}/repo\"."
49166                 },
49167                 "cache-vcs-dir": {
49168                     "type": "string",
49169                     "description": "The location where vcs infos (git clones, github api calls, etc. when reading vcs repos) are cached, defaults to \"{$cache-dir}/vcs\"."
49170                 },
49171                 "cache-ttl": {
49172                     "type": "integer",
49173                     "description": "The default cache time-to-live, defaults to 15552000 (6 months)."
49174                 },
49175                 "cache-files-ttl": {
49176                     "type": "integer",
49177                     "description": "The cache time-to-live for files, defaults to the value of cache-ttl."
49178                 },
49179                 "cache-files-maxsize": {
49180                     "type": ["string", "integer"],
49181                     "description": "The cache max size for the files cache, defaults to \"300MiB\"."
49182                 },
49183                 "bin-compat": {
49184                     "enum": ["auto", "full"],
49185                     "description": "The compatibility of the binaries, defaults to \"auto\" (automatically guessed) and can be \"full\" (compatible with both Windows and Unix-based systems)."
49186                 },
49187                 "discard-changes": {
49188                     "type": ["string", "boolean"],
49189                     "description": "The default style of handling dirty updates, defaults to false and can be any of true, false or \"stash\"."
49190                 },
49191                 "autoloader-suffix": {
49192                     "type": "string",
49193                     "description": "Optional string to be used as a suffix for the generated Composer autoloader. When null a random one will be generated."
49194                 },
49195                 "optimize-autoloader": {
49196                     "type": "boolean",
49197                     "description": "Always optimize when dumping the autoloader."
49198                 },
49199                 "prepend-autoloader": {
49200                     "type": "boolean",
49201                     "description": "If false, the composer autoloader will not be prepended to existing autoloaders, defaults to true."
49202                 },
49203                 "classmap-authoritative": {
49204                     "type": "boolean",
49205                     "description": "If true, the composer autoloader will not scan the filesystem for classes that are not found in the class map, defaults to false."
49206                 },
49207                 "apcu-autoloader": {
49208                     "type": "boolean",
49209                     "description": "If true, the Composer autoloader will check for APCu and use it to cache found/not-found classes when the extension is enabled, defaults to false."
49210                 },
49211                 "github-domains": {
49212                     "type": "array",
49213                     "description": "A list of domains to use in github mode. This is used for GitHub Enterprise setups, defaults to [\"github.com\"].",
49214                     "items": {
49215                         "type": "string"
49216                     }
49217                 },
49218                 "github-expose-hostname": {
49219                     "type": "boolean",
49220                     "description": "Defaults to true. If set to false, the OAuth tokens created to access the github API will have a date instead of the machine hostname."
49221                 },
49222                 "gitlab-domains": {
49223                     "type": "array",
49224                     "description": "A list of domains to use in gitlab mode. This is used for custom GitLab setups, defaults to [\"gitlab.com\"].",
49225                     "items": {
49226                         "type": "string"
49227                     }
49228                 },
49229                 "use-github-api": {
49230                     "type": "boolean",
49231                     "description": "Defaults to true.  If set to false, globally disables the use of the GitHub API for all GitHub repositories and clones the repository as it would for any other repository."
49232                 },
49233                 "archive-format": {
49234                     "type": "string",
49235                     "description": "The default archiving format when not provided on cli, defaults to \"tar\"."
49236                 },
49237                 "archive-dir": {
49238                     "type": "string",
49239                     "description": "The default archive path when not provided on cli, defaults to \".\"."
49240                 },
49241                 "htaccess-protect": {
49242                     "type": "boolean",
49243                     "description": "Defaults to true. If set to false, Composer will not create .htaccess files in the composer home, cache, and data directories."
49244                 },
49245                 "sort-packages": {
49246                     "type": "boolean",
49247                     "description": "Defaults to false. If set to true, Composer will sort packages when adding/updating a new dependency."
49248                 },
49249                 "lock": {
49250                     "type": "boolean",
49251                     "description": "Defaults to true. If set to false, Composer will not create a composer.lock file."
49252                 }
49253             }
49254         },
49255         "extra": {
49256             "type": ["object", "array"],
49257             "description": "Arbitrary extra data that can be used by plugins, for example, package of type composer-plugin may have a 'class' key defining an installer class name.",
49258             "additionalProperties": true
49259         },
49260         "autoload": {
49261             "$ref": "#/definitions/autoload"
49262         },
49263         "autoload-dev": {
49264             "type": "object",
49265             "description": "Description of additional autoload rules for development purpose (eg. a test suite).",
49266             "properties": {
49267                 "psr-0": {
49268                     "type": "object",
49269                     "description": "This is a hash of namespaces (keys) and the directories they can be found into (values, can be arrays of paths) by the autoloader.",
49270                     "additionalProperties": {
49271                         "type": ["string", "array"],
49272                         "items": {
49273                             "type": "string"
49274                         }
49275                     }
49276                 },
49277                 "psr-4": {
49278                     "type": "object",
49279                     "description": "This is a hash of namespaces (keys) and the PSR-4 directories they can map to (values, can be arrays of paths) by the autoloader.",
49280                     "additionalProperties": {
49281                         "type": ["string", "array"],
49282                         "items": {
49283                             "type": "string"
49284                         }
49285                     }
49286                 },
49287                 "classmap": {
49288                     "type": "array",
49289                     "description": "This is an array of directories that contain classes to be included in the class-map generation process."
49290                 },
49291                 "files": {
49292                     "type": "array",
49293                     "description": "This is an array of files that are always required on every request."
49294                 }
49295             }
49296         },
49297         "archive": {
49298             "type": ["object"],
49299             "description": "Options for creating package archives for distribution.",
49300             "properties": {
49301                 "exclude": {
49302                     "type": "array",
49303                     "description": "A list of patterns for paths to exclude or include if prefixed with an exclamation mark."
49304                 }
49305             }
49306         },
49307         "repositories": {
49308             "type": ["object", "array"],
49309             "description": "A set of additional repositories where packages can be found.",
49310             "additionalProperties": {
49311                 "anyOf": [
49312                     { "$ref": "#/definitions/repository" },
49313                     { "type": "boolean", "enum": [false] }
49314                 ]
49315             },
49316             "items": {
49317                 "anyOf": [
49318                     { "$ref": "#/definitions/repository" },
49319                     {
49320                         "type": "object",
49321                         "additionalProperties": { "type": "boolean", "enum": [false] },
49322                         "minProperties": 1,
49323                         "maxProperties": 1
49324                     }
49325                 ]
49326             }
49327         },
49328         "minimum-stability": {
49329             "type": ["string"],
49330             "description": "The minimum stability the packages must have to be install-able. Possible values are: dev, alpha, beta, RC, stable.",
49331             "pattern": "^dev|alpha|beta|rc|RC|stable$"
49332         },
49333         "prefer-stable": {
49334             "type": ["boolean"],
49335             "description": "If set to true, stable packages will be preferred to dev packages when possible, even if the minimum-stability allows unstable packages."
49336         },
49337         "bin": {
49338             "type": ["string", "array"],
49339             "description": "A set of files, or a single file, that should be treated as binaries and symlinked into bin-dir (from config).",
49340             "items": {
49341                 "type": "string"
49342             }
49343         },
49344         "include-path": {
49345             "type": ["array"],
49346             "description": "DEPRECATED: A list of directories which should get added to PHP's include path. This is only present to support legacy projects, and all new code should preferably use autoloading.",
49347             "items": {
49348                 "type": "string"
49349             }
49350         },
49351         "scripts": {
49352             "type": ["object"],
49353             "description": "Script listeners that will be executed before/after some events.",
49354             "properties": {
49355                 "pre-install-cmd": {
49356                     "type": ["array", "string"],
49357                     "description": "Occurs before the install command is executed, contains one or more Class::method callables or shell commands."
49358                 },
49359                 "post-install-cmd": {
49360                     "type": ["array", "string"],
49361                     "description": "Occurs after the install command is executed, contains one or more Class::method callables or shell commands."
49362                 },
49363                 "pre-update-cmd": {
49364                     "type": ["array", "string"],
49365                     "description": "Occurs before the update command is executed, contains one or more Class::method callables or shell commands."
49366                 },
49367                 "post-update-cmd": {
49368                     "type": ["array", "string"],
49369                     "description": "Occurs after the update command is executed, contains one or more Class::method callables or shell commands."
49370                 },
49371                 "pre-status-cmd": {
49372                     "type": ["array", "string"],
49373                     "description": "Occurs before the status command is executed, contains one or more Class::method callables or shell commands."
49374                 },
49375                 "post-status-cmd": {
49376                     "type": ["array", "string"],
49377                     "description": "Occurs after the status command is executed, contains one or more Class::method callables or shell commands."
49378                 },
49379                 "pre-package-install": {
49380                     "type": ["array", "string"],
49381                     "description": "Occurs before a package is installed, contains one or more Class::method callables or shell commands."
49382                 },
49383                 "post-package-install": {
49384                     "type": ["array", "string"],
49385                     "description": "Occurs after a package is installed, contains one or more Class::method callables or shell commands."
49386                 },
49387                 "pre-package-update": {
49388                     "type": ["array", "string"],
49389                     "description": "Occurs before a package is updated, contains one or more Class::method callables or shell commands."
49390                 },
49391                 "post-package-update": {
49392                     "type": ["array", "string"],
49393                     "description": "Occurs after a package is updated, contains one or more Class::method callables or shell commands."
49394                 },
49395                 "pre-package-uninstall": {
49396                     "type": ["array", "string"],
49397                     "description": "Occurs before a package has been uninstalled, contains one or more Class::method callables or shell commands."
49398                 },
49399                 "post-package-uninstall": {
49400                     "type": ["array", "string"],
49401                     "description": "Occurs after a package has been uninstalled, contains one or more Class::method callables or shell commands."
49402                 },
49403                 "pre-autoload-dump": {
49404                     "type": ["array", "string"],
49405                     "description": "Occurs before the autoloader is dumped, contains one or more Class::method callables or shell commands."
49406                 },
49407                 "post-autoload-dump": {
49408                     "type": ["array", "string"],
49409                     "description": "Occurs after the autoloader is dumped, contains one or more Class::method callables or shell commands."
49410                 },
49411                 "post-root-package-install": {
49412                     "type": ["array", "string"],
49413                     "description": "Occurs after the root-package is installed, contains one or more Class::method callables or shell commands."
49414                 },
49415                 "post-create-project-cmd": {
49416                     "type": ["array", "string"],
49417                     "description": "Occurs after the create-project command is executed, contains one or more Class::method callables or shell commands."
49418                 }
49419             }
49420         },
49421         "scripts-descriptions": {
49422             "type": ["object"],
49423             "description": "Descriptions for custom commands, shown in console help.",
49424             "additionalProperties": {
49425                 "type": "string"
49426             }
49427         },
49428         "support": {
49429             "type": "object",
49430             "properties": {
49431                 "email": {
49432                     "type": "string",
49433                     "description": "Email address for support.",
49434                     "format": "email"
49435                 },
49436                 "issues": {
49437                     "type": "string",
49438                     "description": "URL to the issue tracker.",
49439                     "format": "uri"
49440                 },
49441                 "forum": {
49442                     "type": "string",
49443                     "description": "URL to the forum.",
49444                     "format": "uri"
49445                 },
49446                 "wiki": {
49447                     "type": "string",
49448                     "description": "URL to the wiki.",
49449                     "format": "uri"
49450                 },
49451                 "irc": {
49452                     "type": "string",
49453                     "description": "IRC channel for support, as irc://server/channel.",
49454                     "format": "uri"
49455                 },
49456                 "chat": {
49457                     "type": "string",
49458                     "description": "URL to the support chat.",
49459                     "format": "uri"
49460                 },
49461                 "source": {
49462                     "type": "string",
49463                     "description": "URL to browse or download the sources.",
49464                     "format": "uri"
49465                 },
49466                 "docs": {
49467                     "type": "string",
49468                     "description": "URL to the documentation.",
49469                     "format": "uri"
49470                 },
49471                 "rss": {
49472                     "type": "string",
49473                     "description": "URL to the RSS feed.",
49474                     "format": "uri"
49475                 }
49476             }
49477         },
49478         "funding": {
49479             "type": "array",
49480             "description": "A list of options to fund the development and maintenance of the package.",
49481             "items": {
49482                 "type": "object",
49483                 "properties": {
49484                     "type": {
49485                         "type": "string",
49486                         "description": "Type of funding or platform through which funding is possible."
49487                     },
49488                     "url": {
49489                         "type": "string",
49490                         "description": "URL to a website with details on funding and a way to fund the package.",
49491                         "format": "uri"
49492                     }
49493                 }
49494             }
49495         },
49496         "non-feature-branches": {
49497             "type": ["array"],
49498             "description": "A set of string or regex patterns for non-numeric branch names that will not be handled as feature branches.",
49499             "items": {
49500                 "type": "string"
49501             }
49502         },
49503         "abandoned": {
49504             "type": ["boolean", "string"],
49505             "description": "Indicates whether this package has been abandoned, it can be boolean or a package name/URL pointing to a recommended alternative. Defaults to false."
49506         },
49507         "_comment": {
49508             "type": ["array", "string"],
49509             "description": "A key to store comments in"
49510         }
49511     },
49512     "definitions": {
49513         "authors": {
49514             "type": "array",
49515             "description": "List of authors that contributed to the package. This is typically the main maintainers, not the full list.",
49516             "items": {
49517                 "type": "object",
49518                 "additionalProperties": false,
49519                 "required": [ "name"],
49520                 "properties": {
49521                     "name": {
49522                         "type": "string",
49523                         "description": "Full name of the author."
49524                     },
49525                     "email": {
49526                         "type": "string",
49527                         "description": "Email address of the author.",
49528                         "format": "email"
49529                     },
49530                     "homepage": {
49531                         "type": "string",
49532                         "description": "Homepage URL for the author.",
49533                         "format": "uri"
49534                     },
49535                     "role": {
49536                         "type": "string",
49537                         "description": "Author's role in the project."
49538                     }
49539                 }
49540             }
49541         },
49542         "autoload": {
49543             "type": "object",
49544             "description": "Description of how the package can be autoloaded.",
49545             "properties": {
49546                 "psr-0": {
49547                     "type": "object",
49548                     "description": "This is a hash of namespaces (keys) and the directories they can be found in (values, can be arrays of paths) by the autoloader.",
49549                     "additionalProperties": {
49550                         "type": ["string", "array"],
49551                         "items": {
49552                             "type": "string"
49553                         }
49554                     }
49555                 },
49556                 "psr-4": {
49557                     "type": "object",
49558                     "description": "This is a hash of namespaces (keys) and the PSR-4 directories they can map to (values, can be arrays of paths) by the autoloader.",
49559                     "additionalProperties": {
49560                         "type": ["string", "array"],
49561                         "items": {
49562                             "type": "string"
49563                         }
49564                     }
49565                 },
49566                 "classmap": {
49567                     "type": "array",
49568                     "description": "This is an array of directories that contain classes to be included in the class-map generation process."
49569                 },
49570                 "files": {
49571                     "type": "array",
49572                     "description": "This is an array of files that are always required on every request."
49573                 },
49574                 "exclude-from-classmap": {
49575                     "type": "array",
49576                     "description": "This is an array of patterns to exclude from autoload classmap generation. (e.g. \"exclude-from-classmap\": [\"/test/\", \"/tests/\", \"/Tests/\"]"
49577                 }
49578             }
49579         },
49580         "repository": {
49581             "type": "object",
49582             "anyOf": [
49583                 { "$ref": "#/definitions/composer-repository" },
49584                 { "$ref": "#/definitions/vcs-repository" },
49585                 { "$ref": "#/definitions/path-repository" },
49586                 { "$ref": "#/definitions/artifact-repository" },
49587                 { "$ref": "#/definitions/pear-repository" },
49588                 { "$ref": "#/definitions/package-repository" }
49589             ]
49590         },
49591         "composer-repository": {
49592             "type": "object",
49593             "required": ["type", "url"],
49594             "properties": {
49595                 "type": { "type": "string", "enum": ["composer"] },
49596                 "url": { "type": "string" },
49597                 "options": {
49598                     "type": "object",
49599                     "additionalProperties": true
49600                 },
49601                 "allow_ssl_downgrade": { "type": "boolean" },
49602                 "force-lazy-providers": { "type": "boolean" }
49603             }
49604         },
49605         "vcs-repository": {
49606             "type": "object",
49607             "required": ["type", "url"],
49608             "properties": {
49609                 "type": { "type": "string", "enum": ["vcs", "github", "git", "gitlab", "git-bitbucket", "hg", "hg-bitbucket", "fossil", "perforce", "svn"] },
49610                 "url": { "type": "string" },
49611                 "no-api": { "type": "boolean" },
49612                 "secure-http": { "type": "boolean" },
49613                 "svn-cache-credentials": { "type": "boolean" },
49614                 "trunk-path": { "type": ["string", "boolean"] },
49615                 "branches-path": { "type": ["string", "boolean"] },
49616                 "tags-path": { "type": ["string", "boolean"] },
49617                 "package-path": { "type": "string" },
49618                 "depot": { "type": "string" },
49619                 "branch": { "type": "string" },
49620                 "unique_perforce_client_name": { "type": "string" },
49621                 "p4user": { "type": "string" },
49622                 "p4password": { "type": "string" }
49623             }
49624         },
49625         "path-repository": {
49626             "type": "object",
49627             "required": ["type", "url"],
49628             "properties": {
49629                 "type": { "type": "string", "enum": ["path"] },
49630                 "url": { "type": "string" },
49631                 "options": {
49632                     "type": "object",
49633                     "properties": {
49634                         "symlink": { "type": ["boolean", "null"] }
49635                     },
49636                     "additionalProperties": true
49637                 }
49638             }
49639         },
49640         "artifact-repository": {
49641             "type": "object",
49642             "required": ["type", "url"],
49643             "properties": {
49644                 "type": { "type": "string", "enum": ["artifact"] },
49645                 "url": { "type": "string" }
49646             }
49647         },
49648         "pear-repository": {
49649             "type": "object",
49650             "required": ["type", "url"],
49651             "properties": {
49652                 "type": { "type": "string", "enum": ["pear"] },
49653                 "url": { "type": "string" },
49654                 "vendor-alias": { "type": "string" }
49655             }
49656         },
49657         "package-repository": {
49658             "type": "object",
49659             "required": ["type", "package"],
49660             "properties": {
49661                 "type": { "type": "string", "enum": ["package"] },
49662                 "package": {
49663                     "oneOf": [
49664                         { "$ref": "#/definitions/inline-package" },
49665                         {
49666                             "type": "array",
49667                             "items": { "$ref": "#/definitions/inline-package" }
49668                         }
49669                     ]
49670                 }
49671             }
49672         },
49673         "inline-package": {
49674             "type": "object",
49675             "required": ["name", "version"],
49676             "properties": {
49677                 "name": {
49678                     "type": "string",
49679                     "description": "Package name, including 'vendor-name/' prefix."
49680                 },
49681                 "type": {
49682                     "type": "string"
49683                 },
49684                 "target-dir": {
49685                     "description": "DEPRECATED: Forces the package to be installed into the given subdirectory path. This is used for autoloading PSR-0 packages that do not contain their full path. Use forward slashes for cross-platform compatibility.",
49686                     "type": "string"
49687                 },
49688                 "description": {
49689                     "type": "string"
49690                 },
49691                 "keywords": {
49692                     "type": "array",
49693                     "items": {
49694                         "type": "string"
49695                     }
49696                 },
49697                 "homepage": {
49698                     "type": "string",
49699                     "format": "uri"
49700                 },
49701                 "version": {
49702                     "type": "string"
49703                 },
49704                 "time": {
49705                     "type": "string"
49706                 },
49707                 "license": {
49708                     "type": [
49709                         "string",
49710                         "array"
49711                     ]
49712                 },
49713                 "authors": {
49714                     "$ref": "#/definitions/authors"
49715                 },
49716                 "require": {
49717                     "type": "object",
49718                     "additionalProperties": {
49719                         "type": "string"
49720                     }
49721                 },
49722                 "replace": {
49723                     "type": "object",
49724                     "additionalProperties": {
49725                         "type": "string"
49726                     }
49727                 },
49728                 "conflict": {
49729                     "type": "object",
49730                     "additionalProperties": {
49731                         "type": "string"
49732                     }
49733                 },
49734                 "provide": {
49735                     "type": "object",
49736                     "additionalProperties": {
49737                         "type": "string"
49738                     }
49739                 },
49740                 "require-dev": {
49741                     "type": "object",
49742                     "additionalProperties": {
49743                         "type": "string"
49744                     }
49745                 },
49746                 "suggest": {
49747                     "type": "object",
49748                     "additionalProperties": {
49749                         "type": "string"
49750                     }
49751                 },
49752                 "extra": {
49753                     "type": ["object", "array"],
49754                     "additionalProperties": true
49755                 },
49756                 "autoload": {
49757                     "$ref": "#/definitions/autoload"
49758                 },
49759                 "archive": {
49760                     "type": ["object"],
49761                     "properties": {
49762                         "exclude": {
49763                             "type": "array"
49764                         }
49765                     }
49766                 },
49767                 "bin": {
49768                     "type": ["string", "array"],
49769                     "description": "A set of files, or a single file, that should be treated as binaries and symlinked into bin-dir (from config).",
49770                     "items": {
49771                         "type": "string"
49772                     }
49773                 },
49774                 "include-path": {
49775                     "type": ["array"],
49776                     "description": "DEPRECATED: A list of directories which should get added to PHP's include path. This is only present to support legacy projects, and all new code should preferably use autoloading.",
49777                     "items": {
49778                         "type": "string"
49779                     }
49780                 },
49781                 "source": {
49782                     "type": "object",
49783                     "required": ["type", "url", "reference"],
49784                     "properties": {
49785                         "type": {
49786                             "type": "string"
49787                         },
49788                         "url": {
49789                             "type": "string"
49790                         },
49791                         "reference": {
49792                             "type": "string"
49793                         },
49794                         "mirrors": {
49795                             "type": "array"
49796                         }
49797                     }
49798                 },
49799                 "dist": {
49800                     "type": "object",
49801                     "required": ["type", "url"],
49802                     "properties": {
49803                         "type": {
49804                             "type": "string"
49805                         },
49806                         "url": {
49807                             "type": "string"
49808                         },
49809                         "reference": {
49810                             "type": "string"
49811                         },
49812                         "shasum": {
49813                             "type": "string"
49814                         },
49815                         "mirrors": {
49816                             "type": "array"
49817                         }
49818                     }
49819                 }
49820             },
49821             "additionalProperties": true
49822         }
49823     }
49824 }
49825 {
49826     "389-exception": [
49827         "389 Directory Server Exception"
49828     ],
49829     "Autoconf-exception-2.0": [
49830         "Autoconf exception 2.0"
49831     ],
49832     "Autoconf-exception-3.0": [
49833         "Autoconf exception 3.0"
49834     ],
49835     "Bison-exception-2.2": [
49836         "Bison exception 2.2"
49837     ],
49838     "Bootloader-exception": [
49839         "Bootloader Distribution Exception"
49840     ],
49841     "Classpath-exception-2.0": [
49842         "Classpath exception 2.0"
49843     ],
49844     "CLISP-exception-2.0": [
49845         "CLISP exception 2.0"
49846     ],
49847     "DigiRule-FOSS-exception": [
49848         "DigiRule FOSS License Exception"
49849     ],
49850     "eCos-exception-2.0": [
49851         "eCos exception 2.0"
49852     ],
49853     "Fawkes-Runtime-exception": [
49854         "Fawkes Runtime Exception"
49855     ],
49856     "FLTK-exception": [
49857         "FLTK exception"
49858     ],
49859     "Font-exception-2.0": [
49860         "Font exception 2.0"
49861     ],
49862     "freertos-exception-2.0": [
49863         "FreeRTOS Exception 2.0"
49864     ],
49865     "GCC-exception-2.0": [
49866         "GCC Runtime Library exception 2.0"
49867     ],
49868     "GCC-exception-3.1": [
49869         "GCC Runtime Library exception 3.1"
49870     ],
49871     "gnu-javamail-exception": [
49872         "GNU JavaMail exception"
49873     ],
49874     "GPL-3.0-linking-exception": [
49875         "GPL-3.0 Linking Exception"
49876     ],
49877     "GPL-3.0-linking-source-exception": [
49878         "GPL-3.0 Linking Exception (with Corresponding Source)"
49879     ],
49880     "GPL-CC-1.0": [
49881         "GPL Cooperation Commitment 1.0"
49882     ],
49883     "i2p-gpl-java-exception": [
49884         "i2p GPL+Java Exception"
49885     ],
49886     "LGPL-3.0-linking-exception": [
49887         "LGPL-3.0 Linking Exception"
49888     ],
49889     "Libtool-exception": [
49890         "Libtool Exception"
49891     ],
49892     "Linux-syscall-note": [
49893         "Linux Syscall Note"
49894     ],
49895     "LLVM-exception": [
49896         "LLVM Exception"
49897     ],
49898     "LZMA-exception": [
49899         "LZMA exception"
49900     ],
49901     "mif-exception": [
49902         "Macros and Inline Functions Exception"
49903     ],
49904     "Nokia-Qt-exception-1.1": [
49905         "Nokia Qt LGPL exception 1.1"
49906     ],
49907     "OCaml-LGPL-linking-exception": [
49908         "OCaml LGPL Linking Exception"
49909     ],
49910     "OCCT-exception-1.0": [
49911         "Open CASCADE Exception 1.0"
49912     ],
49913     "OpenJDK-assembly-exception-1.0": [
49914         "OpenJDK Assembly exception 1.0"
49915     ],
49916     "openvpn-openssl-exception": [
49917         "OpenVPN OpenSSL Exception"
49918     ],
49919     "PS-or-PDF-font-exception-20170817": [
49920         "PS/PDF font exception (2017-08-17)"
49921     ],
49922     "Qt-GPL-exception-1.0": [
49923         "Qt GPL exception 1.0"
49924     ],
49925     "Qt-LGPL-exception-1.1": [
49926         "Qt LGPL exception 1.1"
49927     ],
49928     "Qwt-exception-1.0": [
49929         "Qwt exception 1.0"
49930     ],
49931     "SHL-2.0": [
49932         "Solderpad Hardware License v2.0"
49933     ],
49934     "SHL-2.1": [
49935         "Solderpad Hardware License v2.1"
49936     ],
49937     "Swift-exception": [
49938         "Swift Exception"
49939     ],
49940     "u-boot-exception-2.0": [
49941         "U-Boot exception 2.0"
49942     ],
49943     "Universal-FOSS-exception-1.0": [
49944         "Universal FOSS Exception, Version 1.0"
49945     ],
49946     "WxWindows-exception-3.1": [
49947         "WxWindows Library Exception 3.1"
49948     ]
49949 }{
49950     "0BSD": [
49951         "BSD Zero Clause License",
49952         true,
49953         false
49954     ],
49955     "AAL": [
49956         "Attribution Assurance License",
49957         true,
49958         false
49959     ],
49960     "Abstyles": [
49961         "Abstyles License",
49962         false,
49963         false
49964     ],
49965     "Adobe-2006": [
49966         "Adobe Systems Incorporated Source Code License Agreement",
49967         false,
49968         false
49969     ],
49970     "Adobe-Glyph": [
49971         "Adobe Glyph List License",
49972         false,
49973         false
49974     ],
49975     "ADSL": [
49976         "Amazon Digital Services License",
49977         false,
49978         false
49979     ],
49980     "AFL-1.1": [
49981         "Academic Free License v1.1",
49982         true,
49983         false
49984     ],
49985     "AFL-1.2": [
49986         "Academic Free License v1.2",
49987         true,
49988         false
49989     ],
49990     "AFL-2.0": [
49991         "Academic Free License v2.0",
49992         true,
49993         false
49994     ],
49995     "AFL-2.1": [
49996         "Academic Free License v2.1",
49997         true,
49998         false
49999     ],
50000     "AFL-3.0": [
50001         "Academic Free License v3.0",
50002         true,
50003         false
50004     ],
50005     "Afmparse": [
50006         "Afmparse License",
50007         false,
50008         false
50009     ],
50010     "AGPL-1.0": [
50011         "Affero General Public License v1.0",
50012         false,
50013         true
50014     ],
50015     "AGPL-1.0-only": [
50016         "Affero General Public License v1.0 only",
50017         false,
50018         false
50019     ],
50020     "AGPL-1.0-or-later": [
50021         "Affero General Public License v1.0 or later",
50022         false,
50023         false
50024     ],
50025     "AGPL-3.0": [
50026         "GNU Affero General Public License v3.0",
50027         true,
50028         true
50029     ],
50030     "AGPL-3.0-only": [
50031         "GNU Affero General Public License v3.0 only",
50032         true,
50033         false
50034     ],
50035     "AGPL-3.0-or-later": [
50036         "GNU Affero General Public License v3.0 or later",
50037         true,
50038         false
50039     ],
50040     "Aladdin": [
50041         "Aladdin Free Public License",
50042         false,
50043         false
50044     ],
50045     "AMDPLPA": [
50046         "AMD's plpa_map.c License",
50047         false,
50048         false
50049     ],
50050     "AML": [
50051         "Apple MIT License",
50052         false,
50053         false
50054     ],
50055     "AMPAS": [
50056         "Academy of Motion Picture Arts and Sciences BSD",
50057         false,
50058         false
50059     ],
50060     "ANTLR-PD": [
50061         "ANTLR Software Rights Notice",
50062         false,
50063         false
50064     ],
50065     "ANTLR-PD-fallback": [
50066         "ANTLR Software Rights Notice with license fallback",
50067         false,
50068         false
50069     ],
50070     "Apache-1.0": [
50071         "Apache License 1.0",
50072         false,
50073         false
50074     ],
50075     "Apache-1.1": [
50076         "Apache License 1.1",
50077         true,
50078         false
50079     ],
50080     "Apache-2.0": [
50081         "Apache License 2.0",
50082         true,
50083         false
50084     ],
50085     "APAFML": [
50086         "Adobe Postscript AFM License",
50087         false,
50088         false
50089     ],
50090     "APL-1.0": [
50091         "Adaptive Public License 1.0",
50092         true,
50093         false
50094     ],
50095     "APSL-1.0": [
50096         "Apple Public Source License 1.0",
50097         true,
50098         false
50099     ],
50100     "APSL-1.1": [
50101         "Apple Public Source License 1.1",
50102         true,
50103         false
50104     ],
50105     "APSL-1.2": [
50106         "Apple Public Source License 1.2",
50107         true,
50108         false
50109     ],
50110     "APSL-2.0": [
50111         "Apple Public Source License 2.0",
50112         true,
50113         false
50114     ],
50115     "Artistic-1.0": [
50116         "Artistic License 1.0",
50117         true,
50118         false
50119     ],
50120     "Artistic-1.0-cl8": [
50121         "Artistic License 1.0 w/clause 8",
50122         true,
50123         false
50124     ],
50125     "Artistic-1.0-Perl": [
50126         "Artistic License 1.0 (Perl)",
50127         true,
50128         false
50129     ],
50130     "Artistic-2.0": [
50131         "Artistic License 2.0",
50132         true,
50133         false
50134     ],
50135     "Bahyph": [
50136         "Bahyph License",
50137         false,
50138         false
50139     ],
50140     "Barr": [
50141         "Barr License",
50142         false,
50143         false
50144     ],
50145     "Beerware": [
50146         "Beerware License",
50147         false,
50148         false
50149     ],
50150     "BitTorrent-1.0": [
50151         "BitTorrent Open Source License v1.0",
50152         false,
50153         false
50154     ],
50155     "BitTorrent-1.1": [
50156         "BitTorrent Open Source License v1.1",
50157         false,
50158         false
50159     ],
50160     "blessing": [
50161         "SQLite Blessing",
50162         false,
50163         false
50164     ],
50165     "BlueOak-1.0.0": [
50166         "Blue Oak Model License 1.0.0",
50167         false,
50168         false
50169     ],
50170     "Borceux": [
50171         "Borceux license",
50172         false,
50173         false
50174     ],
50175     "BSD-1-Clause": [
50176         "BSD 1-Clause License",
50177         true,
50178         false
50179     ],
50180     "BSD-2-Clause": [
50181         "BSD 2-Clause \"Simplified\" License",
50182         true,
50183         false
50184     ],
50185     "BSD-2-Clause-FreeBSD": [
50186         "BSD 2-Clause FreeBSD License",
50187         false,
50188         true
50189     ],
50190     "BSD-2-Clause-NetBSD": [
50191         "BSD 2-Clause NetBSD License",
50192         false,
50193         true
50194     ],
50195     "BSD-2-Clause-Patent": [
50196         "BSD-2-Clause Plus Patent License",
50197         true,
50198         false
50199     ],
50200     "BSD-2-Clause-Views": [
50201         "BSD 2-Clause with views sentence",
50202         false,
50203         false
50204     ],
50205     "BSD-3-Clause": [
50206         "BSD 3-Clause \"New\" or \"Revised\" License",
50207         true,
50208         false
50209     ],
50210     "BSD-3-Clause-Attribution": [
50211         "BSD with attribution",
50212         false,
50213         false
50214     ],
50215     "BSD-3-Clause-Clear": [
50216         "BSD 3-Clause Clear License",
50217         false,
50218         false
50219     ],
50220     "BSD-3-Clause-LBNL": [
50221         "Lawrence Berkeley National Labs BSD variant license",
50222         true,
50223         false
50224     ],
50225     "BSD-3-Clause-No-Nuclear-License": [
50226         "BSD 3-Clause No Nuclear License",
50227         false,
50228         false
50229     ],
50230     "BSD-3-Clause-No-Nuclear-License-2014": [
50231         "BSD 3-Clause No Nuclear License 2014",
50232         false,
50233         false
50234     ],
50235     "BSD-3-Clause-No-Nuclear-Warranty": [
50236         "BSD 3-Clause No Nuclear Warranty",
50237         false,
50238         false
50239     ],
50240     "BSD-3-Clause-Open-MPI": [
50241         "BSD 3-Clause Open MPI variant",
50242         false,
50243         false
50244     ],
50245     "BSD-4-Clause": [
50246         "BSD 4-Clause \"Original\" or \"Old\" License",
50247         false,
50248         false
50249     ],
50250     "BSD-4-Clause-UC": [
50251         "BSD-4-Clause (University of California-Specific)",
50252         false,
50253         false
50254     ],
50255     "BSD-Protection": [
50256         "BSD Protection License",
50257         false,
50258         false
50259     ],
50260     "BSD-Source-Code": [
50261         "BSD Source Code Attribution",
50262         false,
50263         false
50264     ],
50265     "BSL-1.0": [
50266         "Boost Software License 1.0",
50267         true,
50268         false
50269     ],
50270     "BUSL-1.1": [
50271         "Business Source License 1.1",
50272         false,
50273         false
50274     ],
50275     "bzip2-1.0.5": [
50276         "bzip2 and libbzip2 License v1.0.5",
50277         false,
50278         false
50279     ],
50280     "bzip2-1.0.6": [
50281         "bzip2 and libbzip2 License v1.0.6",
50282         false,
50283         false
50284     ],
50285     "CAL-1.0": [
50286         "Cryptographic Autonomy License 1.0",
50287         true,
50288         false
50289     ],
50290     "CAL-1.0-Combined-Work-Exception": [
50291         "Cryptographic Autonomy License 1.0 (Combined Work Exception)",
50292         true,
50293         false
50294     ],
50295     "Caldera": [
50296         "Caldera License",
50297         false,
50298         false
50299     ],
50300     "CATOSL-1.1": [
50301         "Computer Associates Trusted Open Source License 1.1",
50302         true,
50303         false
50304     ],
50305     "CC-BY-1.0": [
50306         "Creative Commons Attribution 1.0 Generic",
50307         false,
50308         false
50309     ],
50310     "CC-BY-2.0": [
50311         "Creative Commons Attribution 2.0 Generic",
50312         false,
50313         false
50314     ],
50315     "CC-BY-2.5": [
50316         "Creative Commons Attribution 2.5 Generic",
50317         false,
50318         false
50319     ],
50320     "CC-BY-3.0": [
50321         "Creative Commons Attribution 3.0 Unported",
50322         false,
50323         false
50324     ],
50325     "CC-BY-3.0-AT": [
50326         "Creative Commons Attribution 3.0 Austria",
50327         false,
50328         false
50329     ],
50330     "CC-BY-3.0-US": [
50331         "Creative Commons Attribution 3.0 United States",
50332         false,
50333         false
50334     ],
50335     "CC-BY-4.0": [
50336         "Creative Commons Attribution 4.0 International",
50337         false,
50338         false
50339     ],
50340     "CC-BY-NC-1.0": [
50341         "Creative Commons Attribution Non Commercial 1.0 Generic",
50342         false,
50343         false
50344     ],
50345     "CC-BY-NC-2.0": [
50346         "Creative Commons Attribution Non Commercial 2.0 Generic",
50347         false,
50348         false
50349     ],
50350     "CC-BY-NC-2.5": [
50351         "Creative Commons Attribution Non Commercial 2.5 Generic",
50352         false,
50353         false
50354     ],
50355     "CC-BY-NC-3.0": [
50356         "Creative Commons Attribution Non Commercial 3.0 Unported",
50357         false,
50358         false
50359     ],
50360     "CC-BY-NC-4.0": [
50361         "Creative Commons Attribution Non Commercial 4.0 International",
50362         false,
50363         false
50364     ],
50365     "CC-BY-NC-ND-1.0": [
50366         "Creative Commons Attribution Non Commercial No Derivatives 1.0 Generic",
50367         false,
50368         false
50369     ],
50370     "CC-BY-NC-ND-2.0": [
50371         "Creative Commons Attribution Non Commercial No Derivatives 2.0 Generic",
50372         false,
50373         false
50374     ],
50375     "CC-BY-NC-ND-2.5": [
50376         "Creative Commons Attribution Non Commercial No Derivatives 2.5 Generic",
50377         false,
50378         false
50379     ],
50380     "CC-BY-NC-ND-3.0": [
50381         "Creative Commons Attribution Non Commercial No Derivatives 3.0 Unported",
50382         false,
50383         false
50384     ],
50385     "CC-BY-NC-ND-3.0-IGO": [
50386         "Creative Commons Attribution Non Commercial No Derivatives 3.0 IGO",
50387         false,
50388         false
50389     ],
50390     "CC-BY-NC-ND-4.0": [
50391         "Creative Commons Attribution Non Commercial No Derivatives 4.0 International",
50392         false,
50393         false
50394     ],
50395     "CC-BY-NC-SA-1.0": [
50396         "Creative Commons Attribution Non Commercial Share Alike 1.0 Generic",
50397         false,
50398         false
50399     ],
50400     "CC-BY-NC-SA-2.0": [
50401         "Creative Commons Attribution Non Commercial Share Alike 2.0 Generic",
50402         false,
50403         false
50404     ],
50405     "CC-BY-NC-SA-2.5": [
50406         "Creative Commons Attribution Non Commercial Share Alike 2.5 Generic",
50407         false,
50408         false
50409     ],
50410     "CC-BY-NC-SA-3.0": [
50411         "Creative Commons Attribution Non Commercial Share Alike 3.0 Unported",
50412         false,
50413         false
50414     ],
50415     "CC-BY-NC-SA-4.0": [
50416         "Creative Commons Attribution Non Commercial Share Alike 4.0 International",
50417         false,
50418         false
50419     ],
50420     "CC-BY-ND-1.0": [
50421         "Creative Commons Attribution No Derivatives 1.0 Generic",
50422         false,
50423         false
50424     ],
50425     "CC-BY-ND-2.0": [
50426         "Creative Commons Attribution No Derivatives 2.0 Generic",
50427         false,
50428         false
50429     ],
50430     "CC-BY-ND-2.5": [
50431         "Creative Commons Attribution No Derivatives 2.5 Generic",
50432         false,
50433         false
50434     ],
50435     "CC-BY-ND-3.0": [
50436         "Creative Commons Attribution No Derivatives 3.0 Unported",
50437         false,
50438         false
50439     ],
50440     "CC-BY-ND-4.0": [
50441         "Creative Commons Attribution No Derivatives 4.0 International",
50442         false,
50443         false
50444     ],
50445     "CC-BY-SA-1.0": [
50446         "Creative Commons Attribution Share Alike 1.0 Generic",
50447         false,
50448         false
50449     ],
50450     "CC-BY-SA-2.0": [
50451         "Creative Commons Attribution Share Alike 2.0 Generic",
50452         false,
50453         false
50454     ],
50455     "CC-BY-SA-2.0-UK": [
50456         "Creative Commons Attribution Share Alike 2.0 England and Wales",
50457         false,
50458         false
50459     ],
50460     "CC-BY-SA-2.5": [
50461         "Creative Commons Attribution Share Alike 2.5 Generic",
50462         false,
50463         false
50464     ],
50465     "CC-BY-SA-3.0": [
50466         "Creative Commons Attribution Share Alike 3.0 Unported",
50467         false,
50468         false
50469     ],
50470     "CC-BY-SA-3.0-AT": [
50471         "Creative Commons Attribution-Share Alike 3.0 Austria",
50472         false,
50473         false
50474     ],
50475     "CC-BY-SA-4.0": [
50476         "Creative Commons Attribution Share Alike 4.0 International",
50477         false,
50478         false
50479     ],
50480     "CC-PDDC": [
50481         "Creative Commons Public Domain Dedication and Certification",
50482         false,
50483         false
50484     ],
50485     "CC0-1.0": [
50486         "Creative Commons Zero v1.0 Universal",
50487         false,
50488         false
50489     ],
50490     "CDDL-1.0": [
50491         "Common Development and Distribution License 1.0",
50492         true,
50493         false
50494     ],
50495     "CDDL-1.1": [
50496         "Common Development and Distribution License 1.1",
50497         false,
50498         false
50499     ],
50500     "CDLA-Permissive-1.0": [
50501         "Community Data License Agreement Permissive 1.0",
50502         false,
50503         false
50504     ],
50505     "CDLA-Sharing-1.0": [
50506         "Community Data License Agreement Sharing 1.0",
50507         false,
50508         false
50509     ],
50510     "CECILL-1.0": [
50511         "CeCILL Free Software License Agreement v1.0",
50512         false,
50513         false
50514     ],
50515     "CECILL-1.1": [
50516         "CeCILL Free Software License Agreement v1.1",
50517         false,
50518         false
50519     ],
50520     "CECILL-2.0": [
50521         "CeCILL Free Software License Agreement v2.0",
50522         false,
50523         false
50524     ],
50525     "CECILL-2.1": [
50526         "CeCILL Free Software License Agreement v2.1",
50527         true,
50528         false
50529     ],
50530     "CECILL-B": [
50531         "CeCILL-B Free Software License Agreement",
50532         false,
50533         false
50534     ],
50535     "CECILL-C": [
50536         "CeCILL-C Free Software License Agreement",
50537         false,
50538         false
50539     ],
50540     "CERN-OHL-1.1": [
50541         "CERN Open Hardware Licence v1.1",
50542         false,
50543         false
50544     ],
50545     "CERN-OHL-1.2": [
50546         "CERN Open Hardware Licence v1.2",
50547         false,
50548         false
50549     ],
50550     "CERN-OHL-P-2.0": [
50551         "CERN Open Hardware Licence Version 2 - Permissive",
50552         false,
50553         false
50554     ],
50555     "CERN-OHL-S-2.0": [
50556         "CERN Open Hardware Licence Version 2 - Strongly Reciprocal",
50557         false,
50558         false
50559     ],
50560     "CERN-OHL-W-2.0": [
50561         "CERN Open Hardware Licence Version 2 - Weakly Reciprocal",
50562         false,
50563         false
50564     ],
50565     "ClArtistic": [
50566         "Clarified Artistic License",
50567         false,
50568         false
50569     ],
50570     "CNRI-Jython": [
50571         "CNRI Jython License",
50572         false,
50573         false
50574     ],
50575     "CNRI-Python": [
50576         "CNRI Python License",
50577         true,
50578         false
50579     ],
50580     "CNRI-Python-GPL-Compatible": [
50581         "CNRI Python Open Source GPL Compatible License Agreement",
50582         false,
50583         false
50584     ],
50585     "Condor-1.1": [
50586         "Condor Public License v1.1",
50587         false,
50588         false
50589     ],
50590     "copyleft-next-0.3.0": [
50591         "copyleft-next 0.3.0",
50592         false,
50593         false
50594     ],
50595     "copyleft-next-0.3.1": [
50596         "copyleft-next 0.3.1",
50597         false,
50598         false
50599     ],
50600     "CPAL-1.0": [
50601         "Common Public Attribution License 1.0",
50602         true,
50603         false
50604     ],
50605     "CPL-1.0": [
50606         "Common Public License 1.0",
50607         true,
50608         false
50609     ],
50610     "CPOL-1.02": [
50611         "Code Project Open License 1.02",
50612         false,
50613         false
50614     ],
50615     "Crossword": [
50616         "Crossword License",
50617         false,
50618         false
50619     ],
50620     "CrystalStacker": [
50621         "CrystalStacker License",
50622         false,
50623         false
50624     ],
50625     "CUA-OPL-1.0": [
50626         "CUA Office Public License v1.0",
50627         true,
50628         false
50629     ],
50630     "Cube": [
50631         "Cube License",
50632         false,
50633         false
50634     ],
50635     "curl": [
50636         "curl License",
50637         false,
50638         false
50639     ],
50640     "D-FSL-1.0": [
50641         "Deutsche Freie Software Lizenz",
50642         false,
50643         false
50644     ],
50645     "diffmark": [
50646         "diffmark license",
50647         false,
50648         false
50649     ],
50650     "DOC": [
50651         "DOC License",
50652         false,
50653         false
50654     ],
50655     "Dotseqn": [
50656         "Dotseqn License",
50657         false,
50658         false
50659     ],
50660     "DSDP": [
50661         "DSDP License",
50662         false,
50663         false
50664     ],
50665     "dvipdfm": [
50666         "dvipdfm License",
50667         false,
50668         false
50669     ],
50670     "ECL-1.0": [
50671         "Educational Community License v1.0",
50672         true,
50673         false
50674     ],
50675     "ECL-2.0": [
50676         "Educational Community License v2.0",
50677         true,
50678         false
50679     ],
50680     "eCos-2.0": [
50681         "eCos license version 2.0",
50682         false,
50683         true
50684     ],
50685     "EFL-1.0": [
50686         "Eiffel Forum License v1.0",
50687         true,
50688         false
50689     ],
50690     "EFL-2.0": [
50691         "Eiffel Forum License v2.0",
50692         true,
50693         false
50694     ],
50695     "eGenix": [
50696         "eGenix.com Public License 1.1.0",
50697         false,
50698         false
50699     ],
50700     "Entessa": [
50701         "Entessa Public License v1.0",
50702         true,
50703         false
50704     ],
50705     "EPICS": [
50706         "EPICS Open License",
50707         false,
50708         false
50709     ],
50710     "EPL-1.0": [
50711         "Eclipse Public License 1.0",
50712         true,
50713         false
50714     ],
50715     "EPL-2.0": [
50716         "Eclipse Public License 2.0",
50717         true,
50718         false
50719     ],
50720     "ErlPL-1.1": [
50721         "Erlang Public License v1.1",
50722         false,
50723         false
50724     ],
50725     "etalab-2.0": [
50726         "Etalab Open License 2.0",
50727         false,
50728         false
50729     ],
50730     "EUDatagrid": [
50731         "EU DataGrid Software License",
50732         true,
50733         false
50734     ],
50735     "EUPL-1.0": [
50736         "European Union Public License 1.0",
50737         false,
50738         false
50739     ],
50740     "EUPL-1.1": [
50741         "European Union Public License 1.1",
50742         true,
50743         false
50744     ],
50745     "EUPL-1.2": [
50746         "European Union Public License 1.2",
50747         true,
50748         false
50749     ],
50750     "Eurosym": [
50751         "Eurosym License",
50752         false,
50753         false
50754     ],
50755     "Fair": [
50756         "Fair License",
50757         true,
50758         false
50759     ],
50760     "Frameworx-1.0": [
50761         "Frameworx Open License 1.0",
50762         true,
50763         false
50764     ],
50765     "FreeImage": [
50766         "FreeImage Public License v1.0",
50767         false,
50768         false
50769     ],
50770     "FSFAP": [
50771         "FSF All Permissive License",
50772         false,
50773         false
50774     ],
50775     "FSFUL": [
50776         "FSF Unlimited License",
50777         false,
50778         false
50779     ],
50780     "FSFULLR": [
50781         "FSF Unlimited License (with License Retention)",
50782         false,
50783         false
50784     ],
50785     "FTL": [
50786         "Freetype Project License",
50787         false,
50788         false
50789     ],
50790     "GFDL-1.1": [
50791         "GNU Free Documentation License v1.1",
50792         false,
50793         true
50794     ],
50795     "GFDL-1.1-invariants-only": [
50796         "GNU Free Documentation License v1.1 only - invariants",
50797         false,
50798         false
50799     ],
50800     "GFDL-1.1-invariants-or-later": [
50801         "GNU Free Documentation License v1.1 or later - invariants",
50802         false,
50803         false
50804     ],
50805     "GFDL-1.1-no-invariants-only": [
50806         "GNU Free Documentation License v1.1 only - no invariants",
50807         false,
50808         false
50809     ],
50810     "GFDL-1.1-no-invariants-or-later": [
50811         "GNU Free Documentation License v1.1 or later - no invariants",
50812         false,
50813         false
50814     ],
50815     "GFDL-1.1-only": [
50816         "GNU Free Documentation License v1.1 only",
50817         false,
50818         false
50819     ],
50820     "GFDL-1.1-or-later": [
50821         "GNU Free Documentation License v1.1 or later",
50822         false,
50823         false
50824     ],
50825     "GFDL-1.2": [
50826         "GNU Free Documentation License v1.2",
50827         false,
50828         true
50829     ],
50830     "GFDL-1.2-invariants-only": [
50831         "GNU Free Documentation License v1.2 only - invariants",
50832         false,
50833         false
50834     ],
50835     "GFDL-1.2-invariants-or-later": [
50836         "GNU Free Documentation License v1.2 or later - invariants",
50837         false,
50838         false
50839     ],
50840     "GFDL-1.2-no-invariants-only": [
50841         "GNU Free Documentation License v1.2 only - no invariants",
50842         false,
50843         false
50844     ],
50845     "GFDL-1.2-no-invariants-or-later": [
50846         "GNU Free Documentation License v1.2 or later - no invariants",
50847         false,
50848         false
50849     ],
50850     "GFDL-1.2-only": [
50851         "GNU Free Documentation License v1.2 only",
50852         false,
50853         false
50854     ],
50855     "GFDL-1.2-or-later": [
50856         "GNU Free Documentation License v1.2 or later",
50857         false,
50858         false
50859     ],
50860     "GFDL-1.3": [
50861         "GNU Free Documentation License v1.3",
50862         false,
50863         true
50864     ],
50865     "GFDL-1.3-invariants-only": [
50866         "GNU Free Documentation License v1.3 only - invariants",
50867         false,
50868         false
50869     ],
50870     "GFDL-1.3-invariants-or-later": [
50871         "GNU Free Documentation License v1.3 or later - invariants",
50872         false,
50873         false
50874     ],
50875     "GFDL-1.3-no-invariants-only": [
50876         "GNU Free Documentation License v1.3 only - no invariants",
50877         false,
50878         false
50879     ],
50880     "GFDL-1.3-no-invariants-or-later": [
50881         "GNU Free Documentation License v1.3 or later - no invariants",
50882         false,
50883         false
50884     ],
50885     "GFDL-1.3-only": [
50886         "GNU Free Documentation License v1.3 only",
50887         false,
50888         false
50889     ],
50890     "GFDL-1.3-or-later": [
50891         "GNU Free Documentation License v1.3 or later",
50892         false,
50893         false
50894     ],
50895     "Giftware": [
50896         "Giftware License",
50897         false,
50898         false
50899     ],
50900     "GL2PS": [
50901         "GL2PS License",
50902         false,
50903         false
50904     ],
50905     "Glide": [
50906         "3dfx Glide License",
50907         false,
50908         false
50909     ],
50910     "Glulxe": [
50911         "Glulxe License",
50912         false,
50913         false
50914     ],
50915     "GLWTPL": [
50916         "Good Luck With That Public License",
50917         false,
50918         false
50919     ],
50920     "gnuplot": [
50921         "gnuplot License",
50922         false,
50923         false
50924     ],
50925     "GPL-1.0": [
50926         "GNU General Public License v1.0 only",
50927         false,
50928         true
50929     ],
50930     "GPL-1.0+": [
50931         "GNU General Public License v1.0 or later",
50932         false,
50933         true
50934     ],
50935     "GPL-1.0-only": [
50936         "GNU General Public License v1.0 only",
50937         false,
50938         false
50939     ],
50940     "GPL-1.0-or-later": [
50941         "GNU General Public License v1.0 or later",
50942         false,
50943         false
50944     ],
50945     "GPL-2.0": [
50946         "GNU General Public License v2.0 only",
50947         true,
50948         true
50949     ],
50950     "GPL-2.0+": [
50951         "GNU General Public License v2.0 or later",
50952         true,
50953         true
50954     ],
50955     "GPL-2.0-only": [
50956         "GNU General Public License v2.0 only",
50957         true,
50958         false
50959     ],
50960     "GPL-2.0-or-later": [
50961         "GNU General Public License v2.0 or later",
50962         true,
50963         false
50964     ],
50965     "GPL-2.0-with-autoconf-exception": [
50966         "GNU General Public License v2.0 w/Autoconf exception",
50967         false,
50968         true
50969     ],
50970     "GPL-2.0-with-bison-exception": [
50971         "GNU General Public License v2.0 w/Bison exception",
50972         false,
50973         true
50974     ],
50975     "GPL-2.0-with-classpath-exception": [
50976         "GNU General Public License v2.0 w/Classpath exception",
50977         false,
50978         true
50979     ],
50980     "GPL-2.0-with-font-exception": [
50981         "GNU General Public License v2.0 w/Font exception",
50982         false,
50983         true
50984     ],
50985     "GPL-2.0-with-GCC-exception": [
50986         "GNU General Public License v2.0 w/GCC Runtime Library exception",
50987         false,
50988         true
50989     ],
50990     "GPL-3.0": [
50991         "GNU General Public License v3.0 only",
50992         true,
50993         true
50994     ],
50995     "GPL-3.0+": [
50996         "GNU General Public License v3.0 or later",
50997         true,
50998         true
50999     ],
51000     "GPL-3.0-only": [
51001         "GNU General Public License v3.0 only",
51002         true,
51003         false
51004     ],
51005     "GPL-3.0-or-later": [
51006         "GNU General Public License v3.0 or later",
51007         true,
51008         false
51009     ],
51010     "GPL-3.0-with-autoconf-exception": [
51011         "GNU General Public License v3.0 w/Autoconf exception",
51012         false,
51013         true
51014     ],
51015     "GPL-3.0-with-GCC-exception": [
51016         "GNU General Public License v3.0 w/GCC Runtime Library exception",
51017         true,
51018         true
51019     ],
51020     "gSOAP-1.3b": [
51021         "gSOAP Public License v1.3b",
51022         false,
51023         false
51024     ],
51025     "HaskellReport": [
51026         "Haskell Language Report License",
51027         false,
51028         false
51029     ],
51030     "Hippocratic-2.1": [
51031         "Hippocratic License 2.1",
51032         false,
51033         false
51034     ],
51035     "HPND": [
51036         "Historical Permission Notice and Disclaimer",
51037         true,
51038         false
51039     ],
51040     "HPND-sell-variant": [
51041         "Historical Permission Notice and Disclaimer - sell variant",
51042         false,
51043         false
51044     ],
51045     "HTMLTIDY": [
51046         "HTML Tidy License",
51047         false,
51048         false
51049     ],
51050     "IBM-pibs": [
51051         "IBM PowerPC Initialization and Boot Software",
51052         false,
51053         false
51054     ],
51055     "ICU": [
51056         "ICU License",
51057         false,
51058         false
51059     ],
51060     "IJG": [
51061         "Independent JPEG Group License",
51062         false,
51063         false
51064     ],
51065     "ImageMagick": [
51066         "ImageMagick License",
51067         false,
51068         false
51069     ],
51070     "iMatix": [
51071         "iMatix Standard Function Library Agreement",
51072         false,
51073         false
51074     ],
51075     "Imlib2": [
51076         "Imlib2 License",
51077         false,
51078         false
51079     ],
51080     "Info-ZIP": [
51081         "Info-ZIP License",
51082         false,
51083         false
51084     ],
51085     "Intel": [
51086         "Intel Open Source License",
51087         true,
51088         false
51089     ],
51090     "Intel-ACPI": [
51091         "Intel ACPI Software License Agreement",
51092         false,
51093         false
51094     ],
51095     "Interbase-1.0": [
51096         "Interbase Public License v1.0",
51097         false,
51098         false
51099     ],
51100     "IPA": [
51101         "IPA Font License",
51102         true,
51103         false
51104     ],
51105     "IPL-1.0": [
51106         "IBM Public License v1.0",
51107         true,
51108         false
51109     ],
51110     "ISC": [
51111         "ISC License",
51112         true,
51113         false
51114     ],
51115     "JasPer-2.0": [
51116         "JasPer License",
51117         false,
51118         false
51119     ],
51120     "JPNIC": [
51121         "Japan Network Information Center License",
51122         false,
51123         false
51124     ],
51125     "JSON": [
51126         "JSON License",
51127         false,
51128         false
51129     ],
51130     "LAL-1.2": [
51131         "Licence Art Libre 1.2",
51132         false,
51133         false
51134     ],
51135     "LAL-1.3": [
51136         "Licence Art Libre 1.3",
51137         false,
51138         false
51139     ],
51140     "Latex2e": [
51141         "Latex2e License",
51142         false,
51143         false
51144     ],
51145     "Leptonica": [
51146         "Leptonica License",
51147         false,
51148         false
51149     ],
51150     "LGPL-2.0": [
51151         "GNU Library General Public License v2 only",
51152         true,
51153         true
51154     ],
51155     "LGPL-2.0+": [
51156         "GNU Library General Public License v2 or later",
51157         true,
51158         true
51159     ],
51160     "LGPL-2.0-only": [
51161         "GNU Library General Public License v2 only",
51162         true,
51163         false
51164     ],
51165     "LGPL-2.0-or-later": [
51166         "GNU Library General Public License v2 or later",
51167         true,
51168         false
51169     ],
51170     "LGPL-2.1": [
51171         "GNU Lesser General Public License v2.1 only",
51172         true,
51173         true
51174     ],
51175     "LGPL-2.1+": [
51176         "GNU Library General Public License v2.1 or later",
51177         true,
51178         true
51179     ],
51180     "LGPL-2.1-only": [
51181         "GNU Lesser General Public License v2.1 only",
51182         true,
51183         false
51184     ],
51185     "LGPL-2.1-or-later": [
51186         "GNU Lesser General Public License v2.1 or later",
51187         true,
51188         false
51189     ],
51190     "LGPL-3.0": [
51191         "GNU Lesser General Public License v3.0 only",
51192         true,
51193         true
51194     ],
51195     "LGPL-3.0+": [
51196         "GNU Lesser General Public License v3.0 or later",
51197         true,
51198         true
51199     ],
51200     "LGPL-3.0-only": [
51201         "GNU Lesser General Public License v3.0 only",
51202         true,
51203         false
51204     ],
51205     "LGPL-3.0-or-later": [
51206         "GNU Lesser General Public License v3.0 or later",
51207         true,
51208         false
51209     ],
51210     "LGPLLR": [
51211         "Lesser General Public License For Linguistic Resources",
51212         false,
51213         false
51214     ],
51215     "Libpng": [
51216         "libpng License",
51217         false,
51218         false
51219     ],
51220     "libpng-2.0": [
51221         "PNG Reference Library version 2",
51222         false,
51223         false
51224     ],
51225     "libselinux-1.0": [
51226         "libselinux public domain notice",
51227         false,
51228         false
51229     ],
51230     "libtiff": [
51231         "libtiff License",
51232         false,
51233         false
51234     ],
51235     "LiLiQ-P-1.1": [
51236         "Licence Libre du Qu\u00e9bec \u2013 Permissive version 1.1",
51237         true,
51238         false
51239     ],
51240     "LiLiQ-R-1.1": [
51241         "Licence Libre du Qu\u00e9bec \u2013 R\u00e9ciprocit\u00e9 version 1.1",
51242         true,
51243         false
51244     ],
51245     "LiLiQ-Rplus-1.1": [
51246         "Licence Libre du Qu\u00e9bec \u2013 R\u00e9ciprocit\u00e9 forte version 1.1",
51247         true,
51248         false
51249     ],
51250     "Linux-OpenIB": [
51251         "Linux Kernel Variant of OpenIB.org license",
51252         false,
51253         false
51254     ],
51255     "LPL-1.0": [
51256         "Lucent Public License Version 1.0",
51257         true,
51258         false
51259     ],
51260     "LPL-1.02": [
51261         "Lucent Public License v1.02",
51262         true,
51263         false
51264     ],
51265     "LPPL-1.0": [
51266         "LaTeX Project Public License v1.0",
51267         false,
51268         false
51269     ],
51270     "LPPL-1.1": [
51271         "LaTeX Project Public License v1.1",
51272         false,
51273         false
51274     ],
51275     "LPPL-1.2": [
51276         "LaTeX Project Public License v1.2",
51277         false,
51278         false
51279     ],
51280     "LPPL-1.3a": [
51281         "LaTeX Project Public License v1.3a",
51282         false,
51283         false
51284     ],
51285     "LPPL-1.3c": [
51286         "LaTeX Project Public License v1.3c",
51287         true,
51288         false
51289     ],
51290     "MakeIndex": [
51291         "MakeIndex License",
51292         false,
51293         false
51294     ],
51295     "MirOS": [
51296         "The MirOS Licence",
51297         true,
51298         false
51299     ],
51300     "MIT": [
51301         "MIT License",
51302         true,
51303         false
51304     ],
51305     "MIT-0": [
51306         "MIT No Attribution",
51307         true,
51308         false
51309     ],
51310     "MIT-advertising": [
51311         "Enlightenment License (e16)",
51312         false,
51313         false
51314     ],
51315     "MIT-CMU": [
51316         "CMU License",
51317         false,
51318         false
51319     ],
51320     "MIT-enna": [
51321         "enna License",
51322         false,
51323         false
51324     ],
51325     "MIT-feh": [
51326         "feh License",
51327         false,
51328         false
51329     ],
51330     "MIT-open-group": [
51331         "MIT Open Group variant",
51332         false,
51333         false
51334     ],
51335     "MITNFA": [
51336         "MIT +no-false-attribs license",
51337         false,
51338         false
51339     ],
51340     "Motosoto": [
51341         "Motosoto License",
51342         true,
51343         false
51344     ],
51345     "mpich2": [
51346         "mpich2 License",
51347         false,
51348         false
51349     ],
51350     "MPL-1.0": [
51351         "Mozilla Public License 1.0",
51352         true,
51353         false
51354     ],
51355     "MPL-1.1": [
51356         "Mozilla Public License 1.1",
51357         true,
51358         false
51359     ],
51360     "MPL-2.0": [
51361         "Mozilla Public License 2.0",
51362         true,
51363         false
51364     ],
51365     "MPL-2.0-no-copyleft-exception": [
51366         "Mozilla Public License 2.0 (no copyleft exception)",
51367         true,
51368         false
51369     ],
51370     "MS-PL": [
51371         "Microsoft Public License",
51372         true,
51373         false
51374     ],
51375     "MS-RL": [
51376         "Microsoft Reciprocal License",
51377         true,
51378         false
51379     ],
51380     "MTLL": [
51381         "Matrix Template Library License",
51382         false,
51383         false
51384     ],
51385     "MulanPSL-1.0": [
51386         "Mulan Permissive Software License, Version 1",
51387         false,
51388         false
51389     ],
51390     "MulanPSL-2.0": [
51391         "Mulan Permissive Software License, Version 2",
51392         true,
51393         false
51394     ],
51395     "Multics": [
51396         "Multics License",
51397         true,
51398         false
51399     ],
51400     "Mup": [
51401         "Mup License",
51402         false,
51403         false
51404     ],
51405     "NASA-1.3": [
51406         "NASA Open Source Agreement 1.3",
51407         true,
51408         false
51409     ],
51410     "Naumen": [
51411         "Naumen Public License",
51412         true,
51413         false
51414     ],
51415     "NBPL-1.0": [
51416         "Net Boolean Public License v1",
51417         false,
51418         false
51419     ],
51420     "NCGL-UK-2.0": [
51421         "Non-Commercial Government Licence",
51422         false,
51423         false
51424     ],
51425     "NCSA": [
51426         "University of Illinois/NCSA Open Source License",
51427         true,
51428         false
51429     ],
51430     "Net-SNMP": [
51431         "Net-SNMP License",
51432         false,
51433         false
51434     ],
51435     "NetCDF": [
51436         "NetCDF license",
51437         false,
51438         false
51439     ],
51440     "Newsletr": [
51441         "Newsletr License",
51442         false,
51443         false
51444     ],
51445     "NGPL": [
51446         "Nethack General Public License",
51447         true,
51448         false
51449     ],
51450     "NIST-PD": [
51451         "NIST Public Domain Notice",
51452         false,
51453         false
51454     ],
51455     "NIST-PD-fallback": [
51456         "NIST Public Domain Notice with license fallback",
51457         false,
51458         false
51459     ],
51460     "NLOD-1.0": [
51461         "Norwegian Licence for Open Government Data",
51462         false,
51463         false
51464     ],
51465     "NLPL": [
51466         "No Limit Public License",
51467         false,
51468         false
51469     ],
51470     "Nokia": [
51471         "Nokia Open Source License",
51472         true,
51473         false
51474     ],
51475     "NOSL": [
51476         "Netizen Open Source License",
51477         false,
51478         false
51479     ],
51480     "Noweb": [
51481         "Noweb License",
51482         false,
51483         false
51484     ],
51485     "NPL-1.0": [
51486         "Netscape Public License v1.0",
51487         false,
51488         false
51489     ],
51490     "NPL-1.1": [
51491         "Netscape Public License v1.1",
51492         false,
51493         false
51494     ],
51495     "NPOSL-3.0": [
51496         "Non-Profit Open Software License 3.0",
51497         true,
51498         false
51499     ],
51500     "NRL": [
51501         "NRL License",
51502         false,
51503         false
51504     ],
51505     "NTP": [
51506         "NTP License",
51507         true,
51508         false
51509     ],
51510     "NTP-0": [
51511         "NTP No Attribution",
51512         false,
51513         false
51514     ],
51515     "Nunit": [
51516         "Nunit License",
51517         false,
51518         true
51519     ],
51520     "O-UDA-1.0": [
51521         "Open Use of Data Agreement v1.0",
51522         false,
51523         false
51524     ],
51525     "OCCT-PL": [
51526         "Open CASCADE Technology Public License",
51527         false,
51528         false
51529     ],
51530     "OCLC-2.0": [
51531         "OCLC Research Public License 2.0",
51532         true,
51533         false
51534     ],
51535     "ODbL-1.0": [
51536         "ODC Open Database License v1.0",
51537         false,
51538         false
51539     ],
51540     "ODC-By-1.0": [
51541         "Open Data Commons Attribution License v1.0",
51542         false,
51543         false
51544     ],
51545     "OFL-1.0": [
51546         "SIL Open Font License 1.0",
51547         false,
51548         false
51549     ],
51550     "OFL-1.0-no-RFN": [
51551         "SIL Open Font License 1.0 with no Reserved Font Name",
51552         false,
51553         false
51554     ],
51555     "OFL-1.0-RFN": [
51556         "SIL Open Font License 1.0 with Reserved Font Name",
51557         false,
51558         false
51559     ],
51560     "OFL-1.1": [
51561         "SIL Open Font License 1.1",
51562         true,
51563         false
51564     ],
51565     "OFL-1.1-no-RFN": [
51566         "SIL Open Font License 1.1 with no Reserved Font Name",
51567         true,
51568         false
51569     ],
51570     "OFL-1.1-RFN": [
51571         "SIL Open Font License 1.1 with Reserved Font Name",
51572         true,
51573         false
51574     ],
51575     "OGC-1.0": [
51576         "OGC Software License, Version 1.0",
51577         false,
51578         false
51579     ],
51580     "OGL-Canada-2.0": [
51581         "Open Government Licence - Canada",
51582         false,
51583         false
51584     ],
51585     "OGL-UK-1.0": [
51586         "Open Government Licence v1.0",
51587         false,
51588         false
51589     ],
51590     "OGL-UK-2.0": [
51591         "Open Government Licence v2.0",
51592         false,
51593         false
51594     ],
51595     "OGL-UK-3.0": [
51596         "Open Government Licence v3.0",
51597         false,
51598         false
51599     ],
51600     "OGTSL": [
51601         "Open Group Test Suite License",
51602         true,
51603         false
51604     ],
51605     "OLDAP-1.1": [
51606         "Open LDAP Public License v1.1",
51607         false,
51608         false
51609     ],
51610     "OLDAP-1.2": [
51611         "Open LDAP Public License v1.2",
51612         false,
51613         false
51614     ],
51615     "OLDAP-1.3": [
51616         "Open LDAP Public License v1.3",
51617         false,
51618         false
51619     ],
51620     "OLDAP-1.4": [
51621         "Open LDAP Public License v1.4",
51622         false,
51623         false
51624     ],
51625     "OLDAP-2.0": [
51626         "Open LDAP Public License v2.0 (or possibly 2.0A and 2.0B)",
51627         false,
51628         false
51629     ],
51630     "OLDAP-2.0.1": [
51631         "Open LDAP Public License v2.0.1",
51632         false,
51633         false
51634     ],
51635     "OLDAP-2.1": [
51636         "Open LDAP Public License v2.1",
51637         false,
51638         false
51639     ],
51640     "OLDAP-2.2": [
51641         "Open LDAP Public License v2.2",
51642         false,
51643         false
51644     ],
51645     "OLDAP-2.2.1": [
51646         "Open LDAP Public License v2.2.1",
51647         false,
51648         false
51649     ],
51650     "OLDAP-2.2.2": [
51651         "Open LDAP Public License 2.2.2",
51652         false,
51653         false
51654     ],
51655     "OLDAP-2.3": [
51656         "Open LDAP Public License v2.3",
51657         false,
51658         false
51659     ],
51660     "OLDAP-2.4": [
51661         "Open LDAP Public License v2.4",
51662         false,
51663         false
51664     ],
51665     "OLDAP-2.5": [
51666         "Open LDAP Public License v2.5",
51667         false,
51668         false
51669     ],
51670     "OLDAP-2.6": [
51671         "Open LDAP Public License v2.6",
51672         false,
51673         false
51674     ],
51675     "OLDAP-2.7": [
51676         "Open LDAP Public License v2.7",
51677         false,
51678         false
51679     ],
51680     "OLDAP-2.8": [
51681         "Open LDAP Public License v2.8",
51682         true,
51683         false
51684     ],
51685     "OML": [
51686         "Open Market License",
51687         false,
51688         false
51689     ],
51690     "OpenSSL": [
51691         "OpenSSL License",
51692         false,
51693         false
51694     ],
51695     "OPL-1.0": [
51696         "Open Public License v1.0",
51697         false,
51698         false
51699     ],
51700     "OSET-PL-2.1": [
51701         "OSET Public License version 2.1",
51702         true,
51703         false
51704     ],
51705     "OSL-1.0": [
51706         "Open Software License 1.0",
51707         true,
51708         false
51709     ],
51710     "OSL-1.1": [
51711         "Open Software License 1.1",
51712         false,
51713         false
51714     ],
51715     "OSL-2.0": [
51716         "Open Software License 2.0",
51717         true,
51718         false
51719     ],
51720     "OSL-2.1": [
51721         "Open Software License 2.1",
51722         true,
51723         false
51724     ],
51725     "OSL-3.0": [
51726         "Open Software License 3.0",
51727         true,
51728         false
51729     ],
51730     "Parity-6.0.0": [
51731         "The Parity Public License 6.0.0",
51732         false,
51733         false
51734     ],
51735     "Parity-7.0.0": [
51736         "The Parity Public License 7.0.0",
51737         false,
51738         false
51739     ],
51740     "PDDL-1.0": [
51741         "ODC Public Domain Dedication & License 1.0",
51742         false,
51743         false
51744     ],
51745     "PHP-3.0": [
51746         "PHP License v3.0",
51747         true,
51748         false
51749     ],
51750     "PHP-3.01": [
51751         "PHP License v3.01",
51752         true,
51753         false
51754     ],
51755     "Plexus": [
51756         "Plexus Classworlds License",
51757         false,
51758         false
51759     ],
51760     "PolyForm-Noncommercial-1.0.0": [
51761         "PolyForm Noncommercial License 1.0.0",
51762         false,
51763         false
51764     ],
51765     "PolyForm-Small-Business-1.0.0": [
51766         "PolyForm Small Business License 1.0.0",
51767         false,
51768         false
51769     ],
51770     "PostgreSQL": [
51771         "PostgreSQL License",
51772         true,
51773         false
51774     ],
51775     "PSF-2.0": [
51776         "Python Software Foundation License 2.0",
51777         false,
51778         false
51779     ],
51780     "psfrag": [
51781         "psfrag License",
51782         false,
51783         false
51784     ],
51785     "psutils": [
51786         "psutils License",
51787         false,
51788         false
51789     ],
51790     "Python-2.0": [
51791         "Python License 2.0",
51792         true,
51793         false
51794     ],
51795     "Qhull": [
51796         "Qhull License",
51797         false,
51798         false
51799     ],
51800     "QPL-1.0": [
51801         "Q Public License 1.0",
51802         true,
51803         false
51804     ],
51805     "Rdisc": [
51806         "Rdisc License",
51807         false,
51808         false
51809     ],
51810     "RHeCos-1.1": [
51811         "Red Hat eCos Public License v1.1",
51812         false,
51813         false
51814     ],
51815     "RPL-1.1": [
51816         "Reciprocal Public License 1.1",
51817         true,
51818         false
51819     ],
51820     "RPL-1.5": [
51821         "Reciprocal Public License 1.5",
51822         true,
51823         false
51824     ],
51825     "RPSL-1.0": [
51826         "RealNetworks Public Source License v1.0",
51827         true,
51828         false
51829     ],
51830     "RSA-MD": [
51831         "RSA Message-Digest License",
51832         false,
51833         false
51834     ],
51835     "RSCPL": [
51836         "Ricoh Source Code Public License",
51837         true,
51838         false
51839     ],
51840     "Ruby": [
51841         "Ruby License",
51842         false,
51843         false
51844     ],
51845     "SAX-PD": [
51846         "Sax Public Domain Notice",
51847         false,
51848         false
51849     ],
51850     "Saxpath": [
51851         "Saxpath License",
51852         false,
51853         false
51854     ],
51855     "SCEA": [
51856         "SCEA Shared Source License",
51857         false,
51858         false
51859     ],
51860     "Sendmail": [
51861         "Sendmail License",
51862         false,
51863         false
51864     ],
51865     "Sendmail-8.23": [
51866         "Sendmail License 8.23",
51867         false,
51868         false
51869     ],
51870     "SGI-B-1.0": [
51871         "SGI Free Software License B v1.0",
51872         false,
51873         false
51874     ],
51875     "SGI-B-1.1": [
51876         "SGI Free Software License B v1.1",
51877         false,
51878         false
51879     ],
51880     "SGI-B-2.0": [
51881         "SGI Free Software License B v2.0",
51882         false,
51883         false
51884     ],
51885     "SHL-0.5": [
51886         "Solderpad Hardware License v0.5",
51887         false,
51888         false
51889     ],
51890     "SHL-0.51": [
51891         "Solderpad Hardware License, Version 0.51",
51892         false,
51893         false
51894     ],
51895     "SimPL-2.0": [
51896         "Simple Public License 2.0",
51897         true,
51898         false
51899     ],
51900     "SISSL": [
51901         "Sun Industry Standards Source License v1.1",
51902         true,
51903         false
51904     ],
51905     "SISSL-1.2": [
51906         "Sun Industry Standards Source License v1.2",
51907         false,
51908         false
51909     ],
51910     "Sleepycat": [
51911         "Sleepycat License",
51912         true,
51913         false
51914     ],
51915     "SMLNJ": [
51916         "Standard ML of New Jersey License",
51917         false,
51918         false
51919     ],
51920     "SMPPL": [
51921         "Secure Messaging Protocol Public License",
51922         false,
51923         false
51924     ],
51925     "SNIA": [
51926         "SNIA Public License 1.1",
51927         false,
51928         false
51929     ],
51930     "Spencer-86": [
51931         "Spencer License 86",
51932         false,
51933         false
51934     ],
51935     "Spencer-94": [
51936         "Spencer License 94",
51937         false,
51938         false
51939     ],
51940     "Spencer-99": [
51941         "Spencer License 99",
51942         false,
51943         false
51944     ],
51945     "SPL-1.0": [
51946         "Sun Public License v1.0",
51947         true,
51948         false
51949     ],
51950     "SSH-OpenSSH": [
51951         "SSH OpenSSH license",
51952         false,
51953         false
51954     ],
51955     "SSH-short": [
51956         "SSH short notice",
51957         false,
51958         false
51959     ],
51960     "SSPL-1.0": [
51961         "Server Side Public License, v 1",
51962         false,
51963         false
51964     ],
51965     "StandardML-NJ": [
51966         "Standard ML of New Jersey License",
51967         false,
51968         true
51969     ],
51970     "SugarCRM-1.1.3": [
51971         "SugarCRM Public License v1.1.3",
51972         false,
51973         false
51974     ],
51975     "SWL": [
51976         "Scheme Widget Library (SWL) Software License Agreement",
51977         false,
51978         false
51979     ],
51980     "TAPR-OHL-1.0": [
51981         "TAPR Open Hardware License v1.0",
51982         false,
51983         false
51984     ],
51985     "TCL": [
51986         "TCL/TK License",
51987         false,
51988         false
51989     ],
51990     "TCP-wrappers": [
51991         "TCP Wrappers License",
51992         false,
51993         false
51994     ],
51995     "TMate": [
51996         "TMate Open Source License",
51997         false,
51998         false
51999     ],
52000     "TORQUE-1.1": [
52001         "TORQUE v2.5+ Software License v1.1",
52002         false,
52003         false
52004     ],
52005     "TOSL": [
52006         "Trusster Open Source License",
52007         false,
52008         false
52009     ],
52010     "TU-Berlin-1.0": [
52011         "Technische Universitaet Berlin License 1.0",
52012         false,
52013         false
52014     ],
52015     "TU-Berlin-2.0": [
52016         "Technische Universitaet Berlin License 2.0",
52017         false,
52018         false
52019     ],
52020     "UCL-1.0": [
52021         "Upstream Compatibility License v1.0",
52022         true,
52023         false
52024     ],
52025     "Unicode-DFS-2015": [
52026         "Unicode License Agreement - Data Files and Software (2015)",
52027         false,
52028         false
52029     ],
52030     "Unicode-DFS-2016": [
52031         "Unicode License Agreement - Data Files and Software (2016)",
52032         true,
52033         false
52034     ],
52035     "Unicode-TOU": [
52036         "Unicode Terms of Use",
52037         false,
52038         false
52039     ],
52040     "Unlicense": [
52041         "The Unlicense",
52042         true,
52043         false
52044     ],
52045     "UPL-1.0": [
52046         "Universal Permissive License v1.0",
52047         true,
52048         false
52049     ],
52050     "Vim": [
52051         "Vim License",
52052         false,
52053         false
52054     ],
52055     "VOSTROM": [
52056         "VOSTROM Public License for Open Source",
52057         false,
52058         false
52059     ],
52060     "VSL-1.0": [
52061         "Vovida Software License v1.0",
52062         true,
52063         false
52064     ],
52065     "W3C": [
52066         "W3C Software Notice and License (2002-12-31)",
52067         true,
52068         false
52069     ],
52070     "W3C-19980720": [
52071         "W3C Software Notice and License (1998-07-20)",
52072         false,
52073         false
52074     ],
52075     "W3C-20150513": [
52076         "W3C Software Notice and Document License (2015-05-13)",
52077         false,
52078         false
52079     ],
52080     "Watcom-1.0": [
52081         "Sybase Open Watcom Public License 1.0",
52082         true,
52083         false
52084     ],
52085     "Wsuipa": [
52086         "Wsuipa License",
52087         false,
52088         false
52089     ],
52090     "WTFPL": [
52091         "Do What The F*ck You Want To Public License",
52092         false,
52093         false
52094     ],
52095     "wxWindows": [
52096         "wxWindows Library License",
52097         false,
52098         true
52099     ],
52100     "X11": [
52101         "X11 License",
52102         false,
52103         false
52104     ],
52105     "Xerox": [
52106         "Xerox License",
52107         false,
52108         false
52109     ],
52110     "XFree86-1.1": [
52111         "XFree86 License 1.1",
52112         false,
52113         false
52114     ],
52115     "xinetd": [
52116         "xinetd License",
52117         false,
52118         false
52119     ],
52120     "Xnet": [
52121         "X.Net License",
52122         true,
52123         false
52124     ],
52125     "xpp": [
52126         "XPP License",
52127         false,
52128         false
52129     ],
52130     "XSkat": [
52131         "XSkat License",
52132         false,
52133         false
52134     ],
52135     "YPL-1.0": [
52136         "Yahoo! Public License v1.0",
52137         false,
52138         false
52139     ],
52140     "YPL-1.1": [
52141         "Yahoo! Public License v1.1",
52142         false,
52143         false
52144     ],
52145     "Zed": [
52146         "Zed License",
52147         false,
52148         false
52149     ],
52150     "Zend-2.0": [
52151         "Zend License v2.0",
52152         false,
52153         false
52154     ],
52155     "Zimbra-1.3": [
52156         "Zimbra Public License v1.3",
52157         false,
52158         false
52159     ],
52160     "Zimbra-1.4": [
52161         "Zimbra Public License v1.4",
52162         false,
52163         false
52164     ],
52165     "Zlib": [
52166         "zlib License",
52167         true,
52168         false
52169     ],
52170     "zlib-acknowledgement": [
52171         "zlib/libpng License with Acknowledgement",
52172         false,
52173         false
52174     ],
52175     "ZPL-1.1": [
52176         "Zope Public License 1.1",
52177         false,
52178         false
52179     ],
52180     "ZPL-2.0": [
52181         "Zope Public License 2.0",
52182         true,
52183         false
52184     ],
52185     "ZPL-2.1": [
52186         "Zope Public License 2.1",
52187         false,
52188         false
52189     ]
52190 }MZ\90\0\ 3\0\0\0\ 4\0\0\0ÿÿ\0\0¸\0\0\0\0\0\0\0@\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0è\0\0\0\ e\1fº\ e\0´ Í!¸\ 1LÍ!This program cannot be run in DOS mode.\r\r
52191 $\0\0\0\0\0\0\0\7fÆ,Í;§B\9e;§B\9e;§B\9e2ß×\9e:§B\9e2ßÁ\9e-§B\9e2ßÆ\9e9§B\9e2ßÑ\9e?§B\9e\1ca9\9e8§B\9e;§C\9e\b§B\9e2ßÈ\9e:§B\9e2ßÖ\9e:§B\9e2ßÓ\9e:§B\9eRich;§B\9e\0\0\0\0\0\0\0\0PE\0\0L\ 1\ 5\0¬MoO\0\0\0\0\0\0\0\0à\0\ 2\ 1\v\ 1      \0\0
52192 \0\0\0\16\0\0\0\0\0\08\13\0\0\0\10\0\0\0 \0\0\0\0@\0\0\10\0\0\0\ 2\0\0\ 5\0\0\0\0\0\0\0\ 5\0\0\0\0\0\0\0\0`\0\0\0\ 4\0\0?\9c\0\0\ 3\0@\81\0\0\10\0\0\10\0\0\0\0\10\0\0\10\0\0\0\0\0\0\10\0\0\0\0\0\0\0\0\0\0\0\90"\0\0P\0\0\0\0@\0\0 \ 6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0P\0\0p\ 1\0\0\0!\0\0\1c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\08!\0\0@\0\0\0\0\0\0\0\0\0\0\0\0 \0\0Ø\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0.text\0\0\0\v     \0\0\0\10\0\0\0
52193 \0\0\0\ 4\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0`.rdata\0\0Π\0\0\0 \0\0\0
52194 \0\0\0\ e\0\0\0\0\0\0\0\0\0\0\0\0\0\0@\0\0@.data\0\0\0\90\ 3\0\0\00\0\0\0\ 2\0\0\0\18\0\0\0\0\0\0\0\0\0\0\0\0\0\0@\0\0À.rsrc\0\0\0 \ 6\0\0\0@\0\0\0\b\0\0\0\1a\0\0\0\0\0\0\0\0\0\0\0\0\0\0@\0\0@.reloc\0\0Ì\ 1\0\0\0P\0\0\0\ 2\0\0\0"\0\0\0\0\0\0\0\0\0\0\0\0\0\0@\0\0B\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0j$¸æ\18@\0èx\b\0\0jöÿ\15\b @\0\83\0\8bð\8dEÐPVÿ\15\0 @\0\8b\83àûPVÿ\15\ 4 @\0\8dMÔÿ\15X @\0\83\0\8dEÔPÿ5H @\0ÿ\15L @\0YYÿ5\ @\0\8dEÔPÿ5` @\0ÿ\15D @\0YY\8bÈÿ\15P @\0\83Müÿ\8dMÔÿ\15T @\03ÀèH\b\0\0Ã;\r\00@\0u\ 2óÃé¬\ 2\0\0h\80\15@\0è£\ 4\0\0¡l3@\0Ç\ 4$40@\0ÿ5h3@\0£40@\0h$0@\0h(0@\0h 0@\0ÿ\15  @\0\83Ä\14£00@\0\85À}\bj\bè¹\ 3\0\0YÃj\10h\b"@\0è\1f\ 6\0\0\89]üd¡\18\0\0\0\8bp\ 4\89]ä¿\803@\0SVWÿ\150 @\0;Ãt\19;Æu\b3öF\89uäë\10\ 3\0\0ÿ\154 @\0ëÚ3öF¡|3@\0;Æu
52195 j\1fè\\ 3\0\0Yë;¡|3@\0\85Àu,\895|3@\0hð @\0hä @\0è§\ 5\0\0YY\85Àt\17ÇEüþÿÿÿ¸ÿ\0\0\0éÝ\0\0\0\895<0@\0¡|3@\0;Æu\ehà @\0hØ @\0èl\ 5\0\0YYÇ\ 5|3@\0\ 2\0\0\09]äu\bSWÿ\158 @\09\1d\8c3@\0t\19h\8c3@\0è\83\ 4\0\0Y\85Àt
52196 Sj\ 2Sÿ\15\8c3@\0¡$0@\0\8b\r¼ @\0\89\ 1ÿ5$0@\0ÿ5(0@\0ÿ5 0@\0è\10þÿÿ\83Ä\f£80@\09\1d,0@\0u7Pÿ\15À @\0\8b\8b\b\8b     \89MàPQè\8e\ 3\0\0YYÃ\8b\8bEà£80@\03Û9\1d,0@\0u\aPÿ\15h @\09\1d<0@\0u\ 6ÿ\15\9c @\0ÇEüþÿÿÿ¡80@\0èû\ 4\0\0øMZ\0\0f9\ 5\0\0@\0t\ 43ÀëM¡<\0@\0\8d\80\0\0@\0\818PE\0\0\ f·H\18\81ù\v\ 1\0\0t\e\81ù\v\ 2\0\0\83¸\84\0\0\0\ evÌ3É9\88ø\0\0\0ë\ e\83xt\ ev¼3É9\88è\0\0\0\ f\95Á\8bÁj\ 1£,0@\0ÿ\15p @\0jÿÿ\15l @\0YY£\843@\0£\883@\0ÿ\15Ì @\0\8b\rt3@\0\89\bÿ\15\88 @\0\8b\rp3@\0\89\b¡¨ @\0\8b\0£x3@\0èV\ 2\0\0è¬\ 4\0\0\83=\140@\0\0u\f\17@\0ÿ\15¬ @\0Yèg\ 4\0\0\83=\100@\0ÿu   jÿÿ\15° @\0Y3ÀÃè{\ 4\0\0é\9fýÿÿ\8bÿU\8bì\81ì(\ 3\0\0£H1@\0\89\rD1@\0\89\15@1@\0\89\1d<1@\0\89581@\0\89=41@\0f\8c\15`1@\0f\8c\rT1@\0f\8c\1d01@\0f\8c\ 5,1@\0f\8c%(1@\0f\8c-$1@\0\9c\8f\ 5X1@\0\8bE\0£L1@\0\8bE\ 4£P1@\0\8dE\b£\1@\0\8b\85àüÿÿÇ\ 5\980@\0\ 1\0\ 1\0¡P1@\0£L0@\0Ç\ 5@0@\0   \ 4\0ÀÇ\ 5D0@\0\ 1\0\0\0¡\00@\0\89\85Øüÿÿ¡\ 40@\0\89\85Üüÿÿÿ\15\1c @\0£\900@\0j\ 1è?\ 4\0\0Yj\0ÿ\15  @\0h\1c!@\0ÿ\15$ @\0\83=\900@\0\0u\bj\ 1è\e\ 4\0\0Yh     \ 4\0Àÿ\15( @\0Pÿ\15, @\0ÉÃ\8bÿU\8bì\8bE\b\8b\0\818csmàu*\83x\10\ 3u$\8b@\14\ 5\93\19t\15=!\ 5\93\19t\ e="\ 5\93\19t\a=\0@\99\ 1u\ 5èÐ\ 3\0\03À]Â\ 4\0hH\14@\0ÿ\15  @\03ÀÃÿ%¤ @\0j\14h("@\0èb\ 2\0\0ÿ5\883@\0\8b5\8c @\0ÿÖY\89\83øÿu\fÿu\bÿ\15Ä @\0Yëgj\bè\92\ 3\0\0Y\83\0ÿ5\883@\0ÿÖ\89Eäÿ5\843@\0ÿÖYY\89\8dEàP\8dEäPÿu\b\8b5l @\0ÿÖYPèU\ 3\0\0\89EÜÿuäÿÖ£\883@\0ÿuàÿÖ\83Ä\14£\843@\0ÇEüþÿÿÿè \0\0\0\8bEÜè\18\ 2\0\0Ãj\bè\19\ 3\0\0\8bÿU\8bìÿu\bèNÿÿÿ÷Ø\eÀ÷ØYH]Ã\8bÿV¸ü!@\0¾ü!@\0W\8bø;Æs\ f\8b\a\85Àt\ 2ÿÐ\83Ç\ 4;þrñ_^Ã\8bÿV¸\ 4"@\0¾\ 4"@\0W\8bø;Æs\ f\8b\a\85Àt\ 2ÿÐ\83Ç\ 4;þrñ_^Ãÿ%È @\0ÌÌÌÌ\8bÿU\8bì\8bM\b¸MZ\0\0f9\ 1t\ 43À]Ã\8bA<\ 3Á\818PE\0\0uï3Ò¹\v\ 1\0\0f9H\18\ f\94Â\8bÂ]ÃÌÌÌÌÌÌÌÌÌÌÌ\8bÿU\8bì\8bE\b\8bH<\ 3È\ f·A\14SV\ f·q\ 63ÒW\8dD\b\18\85öv\e\8b}\f\8bH\f;ùr   \8bX\b\ 3Ù;ûr
52197 B\83À(;Örè3À_^[]ÃÌÌÌÌÌÌÌÌÌÌÌÌ\8bÿU\8bìjþhH"@\0he\17@\0\0\0\0\0P\83ì\bSVW¡\00@\01Eø3ÅP\8dEðd£\0\0\0\0\89eèÇEü\0\0\0\0h\0\0@\0è*ÿÿÿ\83Ä\ 4\85ÀtU\8bE\b-\0\0@\0Ph\0\0@\0èPÿÿÿ\83Ä\b\85Àt;\8b@$Áè\1f÷Ð\83à\ 1ÇEüþÿÿÿ\8bMðd\89\r\0\0\0\0Y_^[\8bå]Ã\8b\8b\b\8b\ 13Ò=\ 5\0\0À\ f\94Â\8bÂÃ\8beèÇEüþÿÿÿ3À\8bMðd\89\r\0\0\0\0Y_^[\8bå]ÃÌÿ%¸ @\0ÿ%´ @\0ÌÌhe\17@\0dÿ5\0\0\0\0\8bD$\10\89l$\10\8dl$\10+àSVW¡\00@\01Eü3ÅP\89eèÿuø\8bEüÇEüþÿÿÿ\89\8dEðd£\0\0\0\0Ã\8bMðd\89\r\0\0\0\0Y__^[\8bå]QÃ\8bÿU\8bìÿu\14ÿu\10ÿu\fÿu\bh\87\10@\0h\00@\0èç\0\0\0\83Ä\18\8bÿVh\0\0\ 3\0h\0\0\ 1\03öVèÙ\0\0\0\83Ä\f\85Àt\rVVVVVèÂ\0\0\0\83Ä\14^Ã3ÀÃ\8bÿU\8bì\83ì\10¡\00@\0\83\0\83\0SW¿Næ@»»\0\0ÿÿ;Çt\r\85Ãt     ÷У\ 40@\0ë`V\8dEøPÿ\15< @\0\8buü3uøÿ\15\f @\03ðÿ\15\10 @\03ðÿ\15\14 @\0\8dEðPÿ\15\18 @\0\8bEô3Eð3ð;÷u\a¾Oæ@»ë\v\85óu\a\8bÆÁà\10\vð\895\00@\0÷Ö\895\ 40@\0^_[ÉÃÿ%t @\0ÿ%x @\0ÿ%| @\0ÿ%\80 @\0ÿ%\84 @\0ÿ%\90 @\0ÿ%\94 @\0ÿ%\98 @\0ÿ%Р@\0Pdÿ5\0\0\0\0\8dD$\f+d$\fSVW\89(\8bè¡\00@\03ÅP\89EðÿuüÇEüÿÿÿÿ\8dEôd£\0\0\0\0Ã\8bMôd\89\r\0\0\0\0Y__^[\8bå]QÃ\8bMð3Íè¯÷ÿÿéÝÿÿÿ\8dMÔÿ%T @\0\8bT$\b\8dB\f\8bJÌ3Èè\90÷ÿÿ\8bJü3Èè\86÷ÿÿ¸l"@\0ésÿÿÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0¸#\0\0Ê#\0\0Ü#\0\0\88)\0\0r)\0\0b)\0\0H)\0\04)\0\0\16)\0\0ú(\0\0æ(\0\0Ò(\0\0´(\0\0¬(\0\0\96(\0\0\9e)\0\0\0\0\0\0ú#\0\0à$\0\0\1a%\0\0Ê%\0\0\1a&\0\0d&\0\0®&\0\0¤$\0\0\0\0\0\0('\0\0Ä'\0\0Ö'\0\0è'\0\0þ'\0\0\1e(\0\0((\0\06(\0\0¦'\0\0H(\0\0Z(\0\0t(\0\0\86(\0\0\1e'\0\0\ e'\0\0\0'\0\0\96'\0\0\82'\0\0l'\0\0^'\0\0R'\0\0F'\0\0>'\0\0>(\0\00'\0\0¶'\0\0¸)\0\0\0\0\0\0\0\0\0\0\96\10@\0\0\0\0\0\0\0\0\0W\12@\0\8a\14@\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0¬MoO\0\0\0\0\ 2\0\0\0l\0\0\0\80!\0\0\80\ f\0\0@0@\0\980@\0bad allocation\0\0\0\0\0\0H\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00@\0ð!@\0\ 2\0\0\0RSDSÑ\8c³\10´\8f\ 1J¨!öÌëLZ\0\ 1\0\0\0c:\users\seld\documents\visual studio 2010\Projects\hiddeninp\Release\hiddeninp.pdb\0\0\0\0\0e\17\0\0æ\18\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0þÿÿÿ\0\0\0\0Ðÿÿÿ\0\0\0\0þÿÿÿ\a\12@\0\e\12@\0\0\0\0\0þÿÿÿ\0\0\0\0Ìÿÿÿ\0\0\0\0þÿÿÿ\0\0\0\0:\15@\0\0\0\0\0þÿÿÿ\0\0\0\0Øÿÿÿ\0\0\0\0þÿÿÿË\16@\0ß\16@\0ÿÿÿÿÝ\18@\0"\ 5\93\19\ 1\0\0\0d"@\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ 1\0\0\0à"\0\0\0\0\0\0\0\0\0\0ì#\0\0\0 \0\0$#\0\0\0\0\0\0\0\0\0\0ô&\0\0\0\0H#\0\0\0\0\0\0\0\0\0\0\12(\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0¸#\0\0Ê#\0\0Ü#\0\0\88)\0\0r)\0\0b)\0\0H)\0\04)\0\0\16)\0\0ú(\0\0æ(\0\0Ò(\0\0´(\0\0¬(\0\0\96(\0\0\9e)\0\0\0\0\0\0ú#\0\0à$\0\0\1a%\0\0Ê%\0\0\1a&\0\0d&\0\0®&\0\0¤$\0\0\0\0\0\0('\0\0Ä'\0\0Ö'\0\0è'\0\0þ'\0\0\1e(\0\0((\0\06(\0\0¦'\0\0H(\0\0Z(\0\0t(\0\0\86(\0\0\1e'\0\0\ e'\0\0\0'\0\0\96'\0\0\82'\0\0l'\0\0^'\0\0R'\0\0F'\0\0>'\0\0>(\0\00'\0\0¶'\0\0¸)\0\0\0\0\0\0\95\ 1GetConsoleMode\0\0·\ 3SetConsoleMode\0\0;\ 2GetStdHandle\0\0KERNEL32.dll\0\0\16\0??$?6DU?$char_traits@D@std@@V?$allocator@D@1@@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@0@@Z\0\91\ 6?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A\0\0J\ 6?cin@std@@3V?$basic_istream@DU?$char_traits@D@std@@@1@A\0Â\0??$getline@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@YAAAV?$basic_istream@DU?$char_traits@D@std@@@0@AAV10@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@0@@Z\0\1d\ 3??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01@@Z@Z\0\0_\ 2??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ\0\0{\ 1??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ\0\0³\a?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@Z\0\0MSVCP90.dll\0\15\ 1_amsg_exit\0\0\9f\0__getmainargs\0,\ 1_cexit\0\0|\ 1_exit\0f\0_XcptFilter\0Ì\ 4exit\0\0 \0__initenv\0\ 4\ 2_initterm\0\ 5\ 2_initterm_e\0<\ 1_configthreadlocale\0ã\0__setusermatherr\0\0\v\ 1_adjust_fdiv\0\0Ë\0__p__commode\0\0Ï\0__p__fmode\0\0j\ 1_encode_pointer\0à\0__set_app_type\0\0K\ 1_crt_debugger_hook\0\0C\0?terminate@@YAXXZ\0MSVCR90.dll\0æ\ 3_unlock\0\96\0__dllonexit\0v\ 2_lock\0\1c\ 3_onexit\0`\ 1_decode_pointer\0s\ 1_except_handler4_common\0\v\ 2_invoke_watson\0\0?\ 1_controlfp_s\0\0½\ 2InterlockedExchange\0!\ 4Sleep\0º\ 2InterlockedCompareExchange\0\0-\ 4TerminateProcess\0\0©\ 1GetCurrentProcess\0>\ 4UnhandledExceptionFilter\0\0\15\ 4SetUnhandledExceptionFilter\0Ñ\ 2IsDebuggerPresent\0T\ 3QueryPerformanceCounter\0f\ 2GetTickCount\0\0­\ 1GetCurrentThreadId\0\0ª\ 1GetCurrentProcessId\0O\ 2GetSystemTimeAsFileTime\0s\0__CxxFrameHandler3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0Næ@»±\19¿Dÿÿÿÿÿÿÿÿþÿÿÿ\ 1\0\0\0$!@\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ 4\0\0\0\0\0\ 2\0\10\0\0\0 \0\0\80\18\0\0\08\0\0\80\0\0\0\0\0\0\0\0\ 4\0\0\0\0\0\ 1\0\ 1\0\0\0P\0\0\80\0\0\0\0\0\0\0\0\ 4\0\0\0\0\0\ 1\0\ 1\0\0\0h\0\0\80\0\0\0\0\0\0\0\0\ 4\0\0\0\0\0\ 1\0 \ 4\0\0\80\0\0\0\0\0\0\0\0\0\0\0\ 4\0\0\0\0\0\ 1\0 \ 4\0\0\90\0\0\0 @\0\0(\ 3\0\0ä\ 4\0\0\0\0\0\0ÈC\0\0V\ 2\0\0ä\ 4\0\0\0\0\0\0(\ 34\0\0\0V\0S\0_\0V\0E\0R\0S\0I\0O\0N\0_\0I\0N\0F\0O\0\0\0\0\0½\ 4ïþ\0\0\ 1\0\0\0\ 1\0\0\0\0\0\0\0\ 1\0\0\0\0\0\17\0\0\0\0\0\0\0\ 4\0\0\0\ 1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\86\ 2\0\0\ 1\0S\0t\0r\0i\0n\0g\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0b\ 2\0\0\ 1\00\04\00\09\00\04\0b\00\0\0\0Ê\0Q\0\ 1\0F\0i\0l\0e\0D\0e\0s\0c\0r\0i\0p\0t\0i\0o\0n\0\0\0\0\0R\0e\0a\0d\0s\0 \0f\0r\0o\0m\0 \0s\0t\0d\0i\0n\0 \0w\0i\0t\0h\0o\0u\0t\0 \0l\0e\0a\0k\0i\0n\0g\0 \0i\0n\0f\0o\0 \0t\0o\0 \0t\0h\0e\0 \0t\0e\0r\0m\0i\0n\0a\0l\0 \0a\0n\0d\0 \0o\0u\0t\0p\0u\0t\0s\0 \0b\0a\0c\0k\0 \0t\0o\0 \0s\0t\0d\0o\0u\0t\0\0\0\0\06\0\v\0\ 1\0F\0i\0l\0e\0V\0e\0r\0s\0i\0o\0n\0\0\0\0\01\0,\0 \00\0,\0 \00\0,\0 \00\0\0\0\0\08\0\f\0\ 1\0I\0n\0t\0e\0r\0n\0a\0l\0N\0a\0m\0e\0\0\0h\0i\0d\0d\0e\0n\0i\0n\0p\0u\0t\0\0\0P\0\16\0\ 1\0L\0e\0g\0a\0l\0C\0o\0p\0y\0r\0i\0g\0h\0t\0\0\0J\0o\0r\0d\0i\0 \0B\0o\0g\0g\0i\0a\0n\0o\0 \0-\0 \02\00\01\02\0\0\0H\0\10\0\ 1\0O\0r\0i\0g\0i\0n\0a\0l\0F\0i\0l\0e\0n\0a\0m\0e\0\0\0h\0i\0d\0d\0e\0n\0i\0n\0p\0u\0t\0.\0e\0x\0e\0\0\0:\0\r\0\ 1\0P\0r\0o\0d\0u\0c\0t\0N\0a\0m\0e\0\0\0\0\0H\0i\0d\0d\0e\0n\0 \0I\0n\0p\0u\0t\0\0\0\0\0:\0\v\0\ 1\0P\0r\0o\0d\0u\0c\0t\0V\0e\0r\0s\0i\0o\0n\0\0\01\0,\0 \00\0,\0 \00\0,\0 \00\0\0\0\0\0D\0\0\0\ 1\0V\0a\0r\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0\0\0$\0\ 4\0\0\0T\0r\0a\0n\0s\0l\0a\0t\0i\0o\0n\0\0\0\0\0     \ 4°\ 4<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\r
52198   <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">\r
52199     <security>\r
52200       <requestedPrivileges>\r
52201         <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>\r
52202       </requestedPrivileges>\r
52203     </security>\r
52204   </trustInfo>\r
52205   <dependency>\r
52206     <dependentAssembly>\r
52207       <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.21022.8" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>\r
52208     </dependentAssembly>\r
52209   </dependency>\r
52210 </assembly>PAPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDING\0\10\0\0@\ 1\0\0\ 30\100!0/080F0L0T0^0d0n0{0\890\970¡0¨0®0³0¸0½0Â0È0Ð0ä0ÿ0\b1#1-1@1J1O1T1v1{1\841\891\961§1­1´1È1Í1Ó1Û1á1ç1ô1ú1\ 32"2*23292A2M2_2j2p2¹2¿2Ç2Î2Ó2Ù2ß2ç2í2ô2û2\v3\133\193%303N3T3Z3`3f3l3s3z3\813\883\8f3\963\9d3¥3­3µ3Á3Ê3Ï3Õ3ß3è3ó3ÿ3\ 44\144\194\1f4%4;4B4\8b4\914\9a4¡4¬4²4Æ4Û4æ4þ4\145!5^5c5\845\895¨5H6M6_6}6\916\976\07\ 67\r7*7w7|7Á7ä7ñ7ý7\ 58\r8\198=8E8P8V8\8b8h8n8t8z8\808\9c8â8\ 29\0\0\0 \0\0$\0\0\0Ü0è0ì0\1c1 1t1x1\1c2 2@2\2`2h2t2\00\0\0\f\0\0\0\180\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0<?php
52211
52212 /*
52213  * This file is part of the Symfony package.
52214  *
52215  * (c) Fabien Potencier <fabien@symfony.com>
52216  *
52217  * For the full copyright and license information, please view the LICENSE
52218  * file that was distributed with this source code.
52219  */
52220
52221 use Symfony\Polyfill\Mbstring as p;
52222
52223 if (!function_exists('mb_convert_variables')) {
52224     /**
52225      * Convert character code in variable(s)
52226      */
52227     function mb_convert_variables($to_encoding, $from_encoding, &$var, &...$vars)
52228     {
52229         $vars = [&$var, ...$vars];
52230
52231         $ok = true;
52232         array_walk_recursive($vars, function (&$v) use (&$ok, $to_encoding, $from_encoding) {
52233             if (false === $v = p\Mbstring::mb_convert_encoding($v, $to_encoding, $from_encoding)) {
52234                 $ok = false;
52235             }
52236         });
52237
52238         return $ok ? $from_encoding : false;
52239     }
52240 }
52241 <?php
52242
52243
52244
52245
52246
52247
52248
52249
52250
52251
52252 namespace Symfony\Component\Console;
52253
52254 use Symfony\Component\Console\Command\Command;
52255 use Symfony\Component\Console\Command\HelpCommand;
52256 use Symfony\Component\Console\Command\ListCommand;
52257 use Symfony\Component\Console\Descriptor\TextDescriptor;
52258 use Symfony\Component\Console\Descriptor\XmlDescriptor;
52259 use Symfony\Component\Console\Event\ConsoleCommandEvent;
52260 use Symfony\Component\Console\Event\ConsoleExceptionEvent;
52261 use Symfony\Component\Console\Event\ConsoleTerminateEvent;
52262 use Symfony\Component\Console\Exception\CommandNotFoundException;
52263 use Symfony\Component\Console\Exception\ExceptionInterface;
52264 use Symfony\Component\Console\Exception\LogicException;
52265 use Symfony\Component\Console\Formatter\OutputFormatter;
52266 use Symfony\Component\Console\Helper\DebugFormatterHelper;
52267 use Symfony\Component\Console\Helper\DialogHelper;
52268 use Symfony\Component\Console\Helper\FormatterHelper;
52269 use Symfony\Component\Console\Helper\Helper;
52270 use Symfony\Component\Console\Helper\HelperSet;
52271 use Symfony\Component\Console\Helper\ProcessHelper;
52272 use Symfony\Component\Console\Helper\ProgressHelper;
52273 use Symfony\Component\Console\Helper\QuestionHelper;
52274 use Symfony\Component\Console\Helper\TableHelper;
52275 use Symfony\Component\Console\Input\ArgvInput;
52276 use Symfony\Component\Console\Input\ArrayInput;
52277 use Symfony\Component\Console\Input\InputArgument;
52278 use Symfony\Component\Console\Input\InputAwareInterface;
52279 use Symfony\Component\Console\Input\InputDefinition;
52280 use Symfony\Component\Console\Input\InputInterface;
52281 use Symfony\Component\Console\Input\InputOption;
52282 use Symfony\Component\Console\Output\BufferedOutput;
52283 use Symfony\Component\Console\Output\ConsoleOutput;
52284 use Symfony\Component\Console\Output\ConsoleOutputInterface;
52285 use Symfony\Component\Console\Output\OutputInterface;
52286 use Symfony\Component\Debug\Exception\FatalThrowableError;
52287 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
52288
52289
52290
52291
52292
52293
52294
52295
52296
52297
52298
52299
52300
52301
52302
52303
52304 class Application
52305 {
52306 private $commands = array();
52307 private $wantHelps = false;
52308 private $runningCommand;
52309 private $name;
52310 private $version;
52311 private $catchExceptions = true;
52312 private $autoExit = true;
52313 private $definition;
52314 private $helperSet;
52315 private $dispatcher;
52316 private $terminalDimensions;
52317 private $defaultCommand;
52318 private $initialized;
52319
52320
52321
52322
52323
52324 public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
52325 {
52326 $this->name = $name;
52327 $this->version = $version;
52328 $this->defaultCommand = 'list';
52329 }
52330
52331 public function setDispatcher(EventDispatcherInterface $dispatcher)
52332 {
52333 $this->dispatcher = $dispatcher;
52334 }
52335
52336
52337
52338
52339
52340
52341
52342
52343 public function run(InputInterface $input = null, OutputInterface $output = null)
52344 {
52345 if (null === $input) {
52346 $input = new ArgvInput();
52347 }
52348
52349 if (null === $output) {
52350 $output = new ConsoleOutput();
52351 }
52352
52353 $this->configureIO($input, $output);
52354
52355 try {
52356 $e = null;
52357 $exitCode = $this->doRun($input, $output);
52358 } catch (\Exception $e) {
52359 }
52360
52361 if (null !== $e) {
52362 if (!$this->catchExceptions) {
52363 throw $e;
52364 }
52365
52366 if ($output instanceof ConsoleOutputInterface) {
52367 $this->renderException($e, $output->getErrorOutput());
52368 } else {
52369 $this->renderException($e, $output);
52370 }
52371
52372 $exitCode = $this->getExitCodeForThrowable($e);
52373 }
52374
52375 if ($this->autoExit) {
52376 if ($exitCode > 255) {
52377 $exitCode = 255;
52378 }
52379
52380 exit($exitCode);
52381 }
52382
52383 return $exitCode;
52384 }
52385
52386
52387
52388
52389
52390
52391 public function doRun(InputInterface $input, OutputInterface $output)
52392 {
52393 if (true === $input->hasParameterOption(array('--version', '-V'))) {
52394 $output->writeln($this->getLongVersion());
52395
52396 return 0;
52397 }
52398
52399 $name = $this->getCommandName($input);
52400 if (true === $input->hasParameterOption(array('--help', '-h'))) {
52401 if (!$name) {
52402 $name = 'help';
52403 $input = new ArrayInput(array('command' => 'help'));
52404 } else {
52405 $this->wantHelps = true;
52406 }
52407 }
52408
52409 if (!$name) {
52410 $name = $this->defaultCommand;
52411 $definition = $this->getDefinition();
52412 $definition->setArguments(array_merge(
52413 $definition->getArguments(),
52414 array(
52415 'command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name),
52416 )
52417 ));
52418 }
52419
52420 $this->runningCommand = null;
52421
52422 $command = $this->find($name);
52423
52424 $this->runningCommand = $command;
52425 $exitCode = $this->doRunCommand($command, $input, $output);
52426 $this->runningCommand = null;
52427
52428 return $exitCode;
52429 }
52430
52431 public function setHelperSet(HelperSet $helperSet)
52432 {
52433 $this->helperSet = $helperSet;
52434 }
52435
52436
52437
52438
52439
52440
52441 public function getHelperSet()
52442 {
52443 if (!$this->helperSet) {
52444 $this->helperSet = $this->getDefaultHelperSet();
52445 }
52446
52447 return $this->helperSet;
52448 }
52449
52450 public function setDefinition(InputDefinition $definition)
52451 {
52452 $this->definition = $definition;
52453 }
52454
52455
52456
52457
52458
52459
52460 public function getDefinition()
52461 {
52462 if (!$this->definition) {
52463 $this->definition = $this->getDefaultInputDefinition();
52464 }
52465
52466 return $this->definition;
52467 }
52468
52469
52470
52471
52472
52473
52474 public function getHelp()
52475 {
52476 return $this->getLongVersion();
52477 }
52478
52479
52480
52481
52482
52483
52484 public function setCatchExceptions($boolean)
52485 {
52486 $this->catchExceptions = (bool) $boolean;
52487 }
52488
52489
52490
52491
52492
52493
52494 public function setAutoExit($boolean)
52495 {
52496 $this->autoExit = (bool) $boolean;
52497 }
52498
52499
52500
52501
52502
52503
52504 public function getName()
52505 {
52506 return $this->name;
52507 }
52508
52509
52510
52511
52512
52513
52514 public function setName($name)
52515 {
52516 $this->name = $name;
52517 }
52518
52519
52520
52521
52522
52523
52524 public function getVersion()
52525 {
52526 return $this->version;
52527 }
52528
52529
52530
52531
52532
52533
52534 public function setVersion($version)
52535 {
52536 $this->version = $version;
52537 }
52538
52539
52540
52541
52542
52543
52544 public function getLongVersion()
52545 {
52546 if ('UNKNOWN' !== $this->getName()) {
52547 if ('UNKNOWN' !== $this->getVersion()) {
52548 return sprintf('<info>%s</info> version <comment>%s</comment>', $this->getName(), $this->getVersion());
52549 }
52550
52551 return sprintf('<info>%s</info>', $this->getName());
52552 }
52553
52554 return '<info>Console Tool</info>';
52555 }
52556
52557
52558
52559
52560
52561
52562
52563
52564 public function register($name)
52565 {
52566 return $this->add(new Command($name));
52567 }
52568
52569
52570
52571
52572
52573
52574
52575
52576 public function addCommands(array $commands)
52577 {
52578 foreach ($commands as $command) {
52579 $this->add($command);
52580 }
52581 }
52582
52583
52584
52585
52586
52587
52588
52589
52590
52591 public function add(Command $command)
52592 {
52593 $this->init();
52594
52595 $command->setApplication($this);
52596
52597 if (!$command->isEnabled()) {
52598 $command->setApplication(null);
52599
52600 return;
52601 }
52602
52603 if (null === $command->getDefinition()) {
52604 throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', \get_class($command)));
52605 }
52606
52607 $this->commands[$command->getName()] = $command;
52608
52609 foreach ($command->getAliases() as $alias) {
52610 $this->commands[$alias] = $command;
52611 }
52612
52613 return $command;
52614 }
52615
52616
52617
52618
52619
52620
52621
52622
52623
52624
52625 public function get($name)
52626 {
52627 $this->init();
52628
52629 if (!isset($this->commands[$name])) {
52630 throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name));
52631 }
52632
52633 $command = $this->commands[$name];
52634
52635 if ($this->wantHelps) {
52636 $this->wantHelps = false;
52637
52638 $helpCommand = $this->get('help');
52639 $helpCommand->setCommand($command);
52640
52641 return $helpCommand;
52642 }
52643
52644 return $command;
52645 }
52646
52647
52648
52649
52650
52651
52652
52653
52654 public function has($name)
52655 {
52656 $this->init();
52657
52658 return isset($this->commands[$name]);
52659 }
52660
52661
52662
52663
52664
52665
52666
52667
52668 public function getNamespaces()
52669 {
52670 $namespaces = array();
52671 foreach ($this->all() as $command) {
52672 $namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
52673
52674 foreach ($command->getAliases() as $alias) {
52675 $namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias));
52676 }
52677 }
52678
52679 return array_values(array_unique(array_filter($namespaces)));
52680 }
52681
52682
52683
52684
52685
52686
52687
52688
52689
52690
52691 public function findNamespace($namespace)
52692 {
52693 $allNamespaces = $this->getNamespaces();
52694 $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $namespace);
52695 $namespaces = preg_grep('{^'.$expr.'}', $allNamespaces);
52696
52697 if (empty($namespaces)) {
52698 $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace);
52699
52700 if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) {
52701 if (1 == \count($alternatives)) {
52702 $message .= "\n\nDid you mean this?\n    ";
52703 } else {
52704 $message .= "\n\nDid you mean one of these?\n    ";
52705 }
52706
52707 $message .= implode("\n    ", $alternatives);
52708 }
52709
52710 throw new CommandNotFoundException($message, $alternatives);
52711 }
52712
52713 $exact = \in_array($namespace, $namespaces, true);
52714 if (\count($namespaces) > 1 && !$exact) {
52715 throw new CommandNotFoundException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces));
52716 }
52717
52718 return $exact ? $namespace : reset($namespaces);
52719 }
52720
52721
52722
52723
52724
52725
52726
52727
52728
52729
52730
52731
52732
52733 public function find($name)
52734 {
52735 $this->init();
52736 $aliases = array();
52737 $allCommands = array_keys($this->commands);
52738 $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $name);
52739 $commands = preg_grep('{^'.$expr.'}', $allCommands);
52740
52741 if (empty($commands) || \count(preg_grep('{^'.$expr.'$}', $commands)) < 1) {
52742 if (false !== $pos = strrpos($name, ':')) {
52743
52744 $this->findNamespace(substr($name, 0, $pos));
52745 }
52746
52747 $message = sprintf('Command "%s" is not defined.', $name);
52748
52749 if ($alternatives = $this->findAlternatives($name, $allCommands)) {
52750 if (1 == \count($alternatives)) {
52751 $message .= "\n\nDid you mean this?\n    ";
52752 } else {
52753 $message .= "\n\nDid you mean one of these?\n    ";
52754 }
52755 $message .= implode("\n    ", $alternatives);
52756 }
52757
52758 throw new CommandNotFoundException($message, $alternatives);
52759 }
52760
52761
52762 if (\count($commands) > 1) {
52763 $commandList = $this->commands;
52764 $commands = array_filter($commands, function ($nameOrAlias) use ($commandList, $commands, &$aliases) {
52765 $commandName = $commandList[$nameOrAlias]->getName();
52766 $aliases[$nameOrAlias] = $commandName;
52767
52768 return $commandName === $nameOrAlias || !\in_array($commandName, $commands);
52769 });
52770 }
52771
52772 $exact = \in_array($name, $commands, true) || isset($aliases[$name]);
52773 if (!$exact && \count($commands) > 1) {
52774 $suggestions = $this->getAbbreviationSuggestions(array_values($commands));
52775
52776 throw new CommandNotFoundException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions), array_values($commands));
52777 }
52778
52779 return $this->get($exact ? $name : reset($commands));
52780 }
52781
52782
52783
52784
52785
52786
52787
52788
52789
52790
52791 public function all($namespace = null)
52792 {
52793 $this->init();
52794
52795 if (null === $namespace) {
52796 return $this->commands;
52797 }
52798
52799 $commands = array();
52800 foreach ($this->commands as $name => $command) {
52801 if ($namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1)) {
52802 $commands[$name] = $command;
52803 }
52804 }
52805
52806 return $commands;
52807 }
52808
52809
52810
52811
52812
52813
52814
52815
52816 public static function getAbbreviations($names)
52817 {
52818 $abbrevs = array();
52819 foreach ($names as $name) {
52820 for ($len = \strlen($name); $len > 0; --$len) {
52821 $abbrev = substr($name, 0, $len);
52822 $abbrevs[$abbrev][] = $name;
52823 }
52824 }
52825
52826 return $abbrevs;
52827 }
52828
52829
52830
52831
52832
52833
52834
52835
52836
52837
52838
52839 public function asText($namespace = null, $raw = false)
52840 {
52841 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);
52842
52843 $descriptor = new TextDescriptor();
52844 $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, !$raw);
52845 $descriptor->describe($output, $this, array('namespace' => $namespace, 'raw_output' => true));
52846
52847 return $output->fetch();
52848 }
52849
52850
52851
52852
52853
52854
52855
52856
52857
52858
52859
52860 public function asXml($namespace = null, $asDom = false)
52861 {
52862 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);
52863
52864 $descriptor = new XmlDescriptor();
52865
52866 if ($asDom) {
52867 return $descriptor->getApplicationDocument($this, $namespace);
52868 }
52869
52870 $output = new BufferedOutput();
52871 $descriptor->describe($output, $this, array('namespace' => $namespace));
52872
52873 return $output->fetch();
52874 }
52875
52876
52877
52878
52879 public function renderException($e, $output)
52880 {
52881 $output->writeln('', OutputInterface::VERBOSITY_QUIET);
52882
52883 do {
52884 $title = sprintf('  [%s]  ', \get_class($e));
52885
52886 $len = Helper::strlen($title);
52887
52888 $width = $this->getTerminalWidth() ? $this->getTerminalWidth() - 1 : PHP_INT_MAX;
52889
52890 if (\defined('HHVM_VERSION') && $width > 1 << 31) {
52891 $width = 1 << 31;
52892 }
52893 $lines = array();
52894 foreach (preg_split('/\r?\n/', trim($e->getMessage())) as $line) {
52895 foreach ($this->splitStringByWidth($line, $width - 4) as $line) {
52896
52897 $lineLength = Helper::strlen($line) + 4;
52898 $lines[] = array($line, $lineLength);
52899
52900 $len = max($lineLength, $len);
52901 }
52902 }
52903
52904 $messages = array();
52905 $messages[] = $emptyLine = sprintf('<error>%s</error>', str_repeat(' ', $len));
52906 $messages[] = sprintf('<error>%s%s</error>', $title, str_repeat(' ', max(0, $len - Helper::strlen($title))));
52907 foreach ($lines as $line) {
52908 $messages[] = sprintf('<error>  %s  %s</error>', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1]));
52909 }
52910 $messages[] = $emptyLine;
52911 $messages[] = '';
52912
52913 $output->writeln($messages, OutputInterface::VERBOSITY_QUIET);
52914
52915 if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
52916 $output->writeln('<comment>Exception trace:</comment>', OutputInterface::VERBOSITY_QUIET);
52917
52918
52919 $trace = $e->getTrace();
52920 array_unshift($trace, array(
52921 'function' => '',
52922 'file' => null !== $e->getFile() ? $e->getFile() : 'n/a',
52923 'line' => null !== $e->getLine() ? $e->getLine() : 'n/a',
52924 'args' => array(),
52925 ));
52926
52927 for ($i = 0, $count = \count($trace); $i < $count; ++$i) {
52928 $class = isset($trace[$i]['class']) ? $trace[$i]['class'] : '';
52929 $type = isset($trace[$i]['type']) ? $trace[$i]['type'] : '';
52930 $function = $trace[$i]['function'];
52931 $file = isset($trace[$i]['file']) ? $trace[$i]['file'] : 'n/a';
52932 $line = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a';
52933
52934 $output->writeln(sprintf(' %s%s%s() at <info>%s:%s</info>', $class, $type, $function, $file, $line), OutputInterface::VERBOSITY_QUIET);
52935 }
52936
52937 $output->writeln('', OutputInterface::VERBOSITY_QUIET);
52938 }
52939 } while ($e = $e->getPrevious());
52940
52941 if (null !== $this->runningCommand) {
52942 $output->writeln(sprintf('<info>%s</info>', sprintf($this->runningCommand->getSynopsis(), $this->getName())), OutputInterface::VERBOSITY_QUIET);
52943 $output->writeln('', OutputInterface::VERBOSITY_QUIET);
52944 }
52945 }
52946
52947
52948
52949
52950
52951
52952 protected function getTerminalWidth()
52953 {
52954 $dimensions = $this->getTerminalDimensions();
52955
52956 return $dimensions[0];
52957 }
52958
52959
52960
52961
52962
52963
52964 protected function getTerminalHeight()
52965 {
52966 $dimensions = $this->getTerminalDimensions();
52967
52968 return $dimensions[1];
52969 }
52970
52971
52972
52973
52974
52975
52976 public function getTerminalDimensions()
52977 {
52978 if ($this->terminalDimensions) {
52979 return $this->terminalDimensions;
52980 }
52981
52982 if ('\\' === \DIRECTORY_SEPARATOR) {
52983
52984 if (preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim(getenv('ANSICON')), $matches)) {
52985 return array((int) $matches[1], (int) $matches[2]);
52986 }
52987
52988 if (preg_match('/^(\d+)x(\d+)$/', $this->getConsoleMode(), $matches)) {
52989 return array((int) $matches[1], (int) $matches[2]);
52990 }
52991 }
52992
52993 if ($sttyString = $this->getSttyColumns()) {
52994
52995 if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) {
52996 return array((int) $matches[2], (int) $matches[1]);
52997 }
52998
52999 if (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) {
53000 return array((int) $matches[2], (int) $matches[1]);
53001 }
53002 }
53003
53004 return array(null, null);
53005 }
53006
53007
53008
53009
53010
53011
53012
53013
53014
53015
53016
53017 public function setTerminalDimensions($width, $height)
53018 {
53019 $this->terminalDimensions = array($width, $height);
53020
53021 return $this;
53022 }
53023
53024
53025
53026
53027 protected function configureIO(InputInterface $input, OutputInterface $output)
53028 {
53029 if (true === $input->hasParameterOption(array('--ansi'))) {
53030 $output->setDecorated(true);
53031 } elseif (true === $input->hasParameterOption(array('--no-ansi'))) {
53032 $output->setDecorated(false);
53033 }
53034
53035 if (true === $input->hasParameterOption(array('--no-interaction', '-n'))) {
53036 $input->setInteractive(false);
53037 } elseif (\function_exists('posix_isatty') && $this->getHelperSet()->has('question')) {
53038 $inputStream = $this->getHelperSet()->get('question')->getInputStream();
53039 if (!@posix_isatty($inputStream) && false === getenv('SHELL_INTERACTIVE')) {
53040 $input->setInteractive(false);
53041 }
53042 }
53043
53044 if (true === $input->hasParameterOption(array('--quiet', '-q'))) {
53045 $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
53046 $input->setInteractive(false);
53047 } else {
53048 if ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || 3 === $input->getParameterOption('--verbose')) {
53049 $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
53050 } elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2') || 2 === $input->getParameterOption('--verbose')) {
53051 $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
53052 } elseif ($input->hasParameterOption('-v') || $input->hasParameterOption('--verbose=1') || $input->hasParameterOption('--verbose') || $input->getParameterOption('--verbose')) {
53053 $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
53054 }
53055 }
53056 }
53057
53058
53059
53060
53061
53062
53063
53064
53065
53066 protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output)
53067 {
53068 foreach ($command->getHelperSet() as $helper) {
53069 if ($helper instanceof InputAwareInterface) {
53070 $helper->setInput($input);
53071 }
53072 }
53073
53074 if (null === $this->dispatcher) {
53075 return $command->run($input, $output);
53076 }
53077
53078
53079 try {
53080 $command->mergeApplicationDefinition();
53081 $input->bind($command->getDefinition());
53082 } catch (ExceptionInterface $e) {
53083
53084 }
53085
53086 $event = new ConsoleCommandEvent($command, $input, $output);
53087 $e = null;
53088
53089 try {
53090 $this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event);
53091
53092 if ($event->commandShouldRun()) {
53093 $exitCode = $command->run($input, $output);
53094 } else {
53095 $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED;
53096 }
53097 } catch (\Exception $e) {
53098 } catch (\Throwable $e) {
53099 }
53100 if (null !== $e) {
53101 $x = $e instanceof \Exception ? $e : new FatalThrowableError($e);
53102 $event = new ConsoleExceptionEvent($command, $input, $output, $x, $x->getCode());
53103 $this->dispatcher->dispatch(ConsoleEvents::EXCEPTION, $event);
53104
53105 if ($x !== $event->getException()) {
53106 $e = $event->getException();
53107 }
53108
53109 $exitCode = $this->getExitCodeForThrowable($e);
53110 }
53111
53112 $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode);
53113 $this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);
53114
53115 if (null !== $e) {
53116 throw $e;
53117 }
53118
53119 return $event->getExitCode();
53120 }
53121
53122
53123
53124
53125
53126
53127 protected function getCommandName(InputInterface $input)
53128 {
53129 return $input->getFirstArgument();
53130 }
53131
53132
53133
53134
53135
53136
53137 protected function getDefaultInputDefinition()
53138 {
53139 return new InputDefinition(array(
53140 new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
53141
53142 new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message'),
53143 new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'),
53144 new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'),
53145 new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'),
53146 new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output'),
53147 new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output'),
53148 new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'),
53149 ));
53150 }
53151
53152
53153
53154
53155
53156
53157 protected function getDefaultCommands()
53158 {
53159 return array(new HelpCommand(), new ListCommand());
53160 }
53161
53162
53163
53164
53165
53166
53167 protected function getDefaultHelperSet()
53168 {
53169 return new HelperSet(array(
53170 new FormatterHelper(),
53171 new DialogHelper(false),
53172 new ProgressHelper(false),
53173 new TableHelper(false),
53174 new DebugFormatterHelper(),
53175 new ProcessHelper(),
53176 new QuestionHelper(),
53177 ));
53178 }
53179
53180
53181
53182
53183
53184
53185 private function getSttyColumns()
53186 {
53187 if (!\function_exists('proc_open')) {
53188 return;
53189 }
53190
53191 $descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
53192 $process = proc_open('stty -a | grep columns', $descriptorspec, $pipes, null, null, array('suppress_errors' => true));
53193 if (\is_resource($process)) {
53194 $info = stream_get_contents($pipes[1]);
53195 fclose($pipes[1]);
53196 fclose($pipes[2]);
53197 proc_close($process);
53198
53199 return $info;
53200 }
53201 }
53202
53203
53204
53205
53206
53207
53208 private function getConsoleMode()
53209 {
53210 if (!\function_exists('proc_open')) {
53211 return;
53212 }
53213
53214 $descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
53215 $process = proc_open('mode CON', $descriptorspec, $pipes, null, null, array('suppress_errors' => true));
53216 if (\is_resource($process)) {
53217 $info = stream_get_contents($pipes[1]);
53218 fclose($pipes[1]);
53219 fclose($pipes[2]);
53220 proc_close($process);
53221
53222 if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
53223 return $matches[2].'x'.$matches[1];
53224 }
53225 }
53226 }
53227
53228
53229
53230
53231
53232
53233
53234
53235 private function getAbbreviationSuggestions($abbrevs)
53236 {
53237 return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], \count($abbrevs) > 2 ? sprintf(' and %d more', \count($abbrevs) - 2) : '');
53238 }
53239
53240
53241
53242
53243
53244
53245
53246
53247
53248
53249
53250 public function extractNamespace($name, $limit = null)
53251 {
53252 $parts = explode(':', $name);
53253 array_pop($parts);
53254
53255 return implode(':', null === $limit ? $parts : \array_slice($parts, 0, $limit));
53256 }
53257
53258
53259
53260
53261
53262
53263
53264
53265
53266
53267 private function findAlternatives($name, $collection)
53268 {
53269 $threshold = 1e3;
53270 $alternatives = array();
53271
53272 $collectionParts = array();
53273 foreach ($collection as $item) {
53274 $collectionParts[$item] = explode(':', $item);
53275 }
53276
53277 foreach (explode(':', $name) as $i => $subname) {
53278 foreach ($collectionParts as $collectionName => $parts) {
53279 $exists = isset($alternatives[$collectionName]);
53280 if (!isset($parts[$i]) && $exists) {
53281 $alternatives[$collectionName] += $threshold;
53282 continue;
53283 } elseif (!isset($parts[$i])) {
53284 continue;
53285 }
53286
53287 $lev = levenshtein($subname, $parts[$i]);
53288 if ($lev <= \strlen($subname) / 3 || '' !== $subname && false !== strpos($parts[$i], $subname)) {
53289 $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;
53290 } elseif ($exists) {
53291 $alternatives[$collectionName] += $threshold;
53292 }
53293 }
53294 }
53295
53296 foreach ($collection as $item) {
53297 $lev = levenshtein($name, $item);
53298 if ($lev <= \strlen($name) / 3 || false !== strpos($item, $name)) {
53299 $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
53300 }
53301 }
53302
53303 $alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; });
53304 asort($alternatives);
53305
53306 return array_keys($alternatives);
53307 }
53308
53309
53310
53311
53312
53313
53314 public function setDefaultCommand($commandName)
53315 {
53316 $this->defaultCommand = $commandName;
53317 }
53318
53319 private function splitStringByWidth($string, $width)
53320 {
53321
53322
53323
53324 if (false === $encoding = mb_detect_encoding($string, null, true)) {
53325 return str_split($string, $width);
53326 }
53327
53328 $utf8String = mb_convert_encoding($string, 'utf8', $encoding);
53329 $lines = array();
53330 $line = '';
53331 foreach (preg_split('//u', $utf8String) as $char) {
53332
53333 if (mb_strwidth($line.$char, 'utf8') <= $width) {
53334 $line .= $char;
53335 continue;
53336 }
53337
53338 $lines[] = str_pad($line, $width);
53339 $line = $char;
53340 }
53341
53342 $lines[] = \count($lines) ? str_pad($line, $width) : $line;
53343
53344 mb_convert_variables($encoding, 'utf8', $lines);
53345
53346 return $lines;
53347 }
53348
53349
53350
53351
53352
53353
53354
53355
53356 private function extractAllNamespaces($name)
53357 {
53358
53359 $parts = explode(':', $name, -1);
53360 $namespaces = array();
53361
53362 foreach ($parts as $part) {
53363 if (\count($namespaces)) {
53364 $namespaces[] = end($namespaces).':'.$part;
53365 } else {
53366 $namespaces[] = $part;
53367 }
53368 }
53369
53370 return $namespaces;
53371 }
53372
53373 private function init()
53374 {
53375 if ($this->initialized) {
53376 return;
53377 }
53378 $this->initialized = true;
53379
53380 foreach ($this->getDefaultCommands() as $command) {
53381 $this->add($command);
53382 }
53383 }
53384
53385
53386
53387
53388
53389
53390 private function getExitCodeForThrowable($throwable)
53391 {
53392 $exitCode = $throwable->getCode();
53393 if (is_numeric($exitCode)) {
53394 $exitCode = (int) $exitCode;
53395 if (0 === $exitCode) {
53396 $exitCode = 1;
53397 }
53398 } else {
53399 $exitCode = 1;
53400 }
53401
53402 return $exitCode;
53403 }
53404 }
53405 <?php
53406
53407
53408
53409
53410
53411
53412
53413
53414
53415
53416 namespace Symfony\Component\Console\Command;
53417
53418 use Symfony\Component\Console\Application;
53419 use Symfony\Component\Console\Descriptor\TextDescriptor;
53420 use Symfony\Component\Console\Descriptor\XmlDescriptor;
53421 use Symfony\Component\Console\Exception\ExceptionInterface;
53422 use Symfony\Component\Console\Exception\InvalidArgumentException;
53423 use Symfony\Component\Console\Exception\LogicException;
53424 use Symfony\Component\Console\Helper\HelperSet;
53425 use Symfony\Component\Console\Input\InputArgument;
53426 use Symfony\Component\Console\Input\InputDefinition;
53427 use Symfony\Component\Console\Input\InputInterface;
53428 use Symfony\Component\Console\Input\InputOption;
53429 use Symfony\Component\Console\Output\BufferedOutput;
53430 use Symfony\Component\Console\Output\OutputInterface;
53431
53432
53433
53434
53435
53436
53437 class Command
53438 {
53439 private $application;
53440 private $name;
53441 private $processTitle;
53442 private $aliases = array();
53443 private $definition;
53444 private $help;
53445 private $description;
53446 private $ignoreValidationErrors = false;
53447 private $applicationDefinitionMerged = false;
53448 private $applicationDefinitionMergedWithArgs = false;
53449 private $code;
53450 private $synopsis = array();
53451 private $usages = array();
53452 private $helperSet;
53453
53454
53455
53456
53457
53458
53459 public function __construct($name = null)
53460 {
53461 $this->definition = new InputDefinition();
53462
53463 if (null !== $name) {
53464 $this->setName($name);
53465 }
53466
53467 $this->configure();
53468
53469 if (!$this->name) {
53470 throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', \get_class($this)));
53471 }
53472 }
53473
53474
53475
53476
53477
53478
53479 public function ignoreValidationErrors()
53480 {
53481 $this->ignoreValidationErrors = true;
53482 }
53483
53484 public function setApplication(Application $application = null)
53485 {
53486 $this->application = $application;
53487 if ($application) {
53488 $this->setHelperSet($application->getHelperSet());
53489 } else {
53490 $this->helperSet = null;
53491 }
53492 }
53493
53494 public function setHelperSet(HelperSet $helperSet)
53495 {
53496 $this->helperSet = $helperSet;
53497 }
53498
53499
53500
53501
53502
53503
53504 public function getHelperSet()
53505 {
53506 return $this->helperSet;
53507 }
53508
53509
53510
53511
53512
53513
53514 public function getApplication()
53515 {
53516 return $this->application;
53517 }
53518
53519
53520
53521
53522
53523
53524
53525
53526
53527 public function isEnabled()
53528 {
53529 return true;
53530 }
53531
53532
53533
53534
53535 protected function configure()
53536 {
53537 }
53538
53539
53540
53541
53542
53543
53544
53545
53546
53547
53548
53549
53550
53551
53552
53553 protected function execute(InputInterface $input, OutputInterface $output)
53554 {
53555 throw new LogicException('You must override the execute() method in the concrete command class.');
53556 }
53557
53558
53559
53560
53561
53562
53563
53564
53565 protected function interact(InputInterface $input, OutputInterface $output)
53566 {
53567 }
53568
53569
53570
53571
53572
53573
53574
53575
53576
53577
53578
53579 protected function initialize(InputInterface $input, OutputInterface $output)
53580 {
53581 }
53582
53583
53584
53585
53586
53587
53588
53589
53590
53591
53592
53593
53594
53595
53596
53597 public function run(InputInterface $input, OutputInterface $output)
53598 {
53599
53600 $this->getSynopsis(true);
53601 $this->getSynopsis(false);
53602
53603
53604 $this->mergeApplicationDefinition();
53605
53606
53607 try {
53608 $input->bind($this->definition);
53609 } catch (ExceptionInterface $e) {
53610 if (!$this->ignoreValidationErrors) {
53611 throw $e;
53612 }
53613 }
53614
53615 $this->initialize($input, $output);
53616
53617 if (null !== $this->processTitle) {
53618 if (\function_exists('cli_set_process_title')) {
53619 if (!@cli_set_process_title($this->processTitle)) {
53620 if ('Darwin' === PHP_OS) {
53621 $output->writeln('<comment>Running "cli_set_process_title" as an unprivileged user is not supported on MacOS.</comment>', OutputInterface::VERBOSITY_VERY_VERBOSE);
53622 } else {
53623 cli_set_process_title($this->processTitle);
53624 }
53625 }
53626 } elseif (\function_exists('setproctitle')) {
53627 setproctitle($this->processTitle);
53628 } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) {
53629 $output->writeln('<comment>Install the proctitle PECL to be able to change the process title.</comment>');
53630 }
53631 }
53632
53633 if ($input->isInteractive()) {
53634 $this->interact($input, $output);
53635 }
53636
53637
53638
53639
53640 if ($input->hasArgument('command') && null === $input->getArgument('command')) {
53641 $input->setArgument('command', $this->getName());
53642 }
53643
53644 $input->validate();
53645
53646 if ($this->code) {
53647 $statusCode = \call_user_func($this->code, $input, $output);
53648 } else {
53649 $statusCode = $this->execute($input, $output);
53650 }
53651
53652 return is_numeric($statusCode) ? (int) $statusCode : 0;
53653 }
53654
53655
53656
53657
53658
53659
53660
53661
53662
53663
53664
53665
53666
53667
53668
53669 public function setCode($code)
53670 {
53671 if (!\is_callable($code)) {
53672 throw new InvalidArgumentException('Invalid callable provided to Command::setCode.');
53673 }
53674
53675 if (\PHP_VERSION_ID >= 50400 && $code instanceof \Closure) {
53676 $r = new \ReflectionFunction($code);
53677 if (null === $r->getClosureThis()) {
53678 if (\PHP_VERSION_ID < 70000) {
53679
53680
53681
53682
53683 $code = @\Closure::bind($code, $this);
53684 } else {
53685 $code = \Closure::bind($code, $this);
53686 }
53687 }
53688 }
53689
53690 $this->code = $code;
53691
53692 return $this;
53693 }
53694
53695
53696
53697
53698
53699
53700
53701
53702 public function mergeApplicationDefinition($mergeArgs = true)
53703 {
53704 if (null === $this->application || (true === $this->applicationDefinitionMerged && ($this->applicationDefinitionMergedWithArgs || !$mergeArgs))) {
53705 return;
53706 }
53707
53708 $this->definition->addOptions($this->application->getDefinition()->getOptions());
53709
53710 $this->applicationDefinitionMerged = true;
53711
53712 if ($mergeArgs) {
53713 $currentArguments = $this->definition->getArguments();
53714 $this->definition->setArguments($this->application->getDefinition()->getArguments());
53715 $this->definition->addArguments($currentArguments);
53716
53717 $this->applicationDefinitionMergedWithArgs = true;
53718 }
53719 }
53720
53721
53722
53723
53724
53725
53726
53727
53728 public function setDefinition($definition)
53729 {
53730 if ($definition instanceof InputDefinition) {
53731 $this->definition = $definition;
53732 } else {
53733 $this->definition->setDefinition($definition);
53734 }
53735
53736 $this->applicationDefinitionMerged = false;
53737
53738 return $this;
53739 }
53740
53741
53742
53743
53744
53745
53746 public function getDefinition()
53747 {
53748 return $this->definition;
53749 }
53750
53751
53752
53753
53754
53755
53756
53757
53758
53759
53760
53761 public function getNativeDefinition()
53762 {
53763 return $this->getDefinition();
53764 }
53765
53766
53767
53768
53769
53770
53771
53772
53773
53774
53775
53776
53777
53778 public function addArgument($name, $mode = null, $description = '', $default = null)
53779 {
53780 $this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
53781
53782 return $this;
53783 }
53784
53785
53786
53787
53788
53789
53790
53791
53792
53793
53794
53795
53796
53797
53798 public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
53799 {
53800 $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
53801
53802 return $this;
53803 }
53804
53805
53806
53807
53808
53809
53810
53811
53812
53813
53814
53815
53816
53817
53818
53819 public function setName($name)
53820 {
53821 $this->validateName($name);
53822
53823 $this->name = $name;
53824
53825 return $this;
53826 }
53827
53828
53829
53830
53831
53832
53833
53834
53835
53836
53837
53838
53839
53840 public function setProcessTitle($title)
53841 {
53842 $this->processTitle = $title;
53843
53844 return $this;
53845 }
53846
53847
53848
53849
53850
53851
53852 public function getName()
53853 {
53854 return $this->name;
53855 }
53856
53857
53858
53859
53860
53861
53862
53863
53864 public function setDescription($description)
53865 {
53866 $this->description = $description;
53867
53868 return $this;
53869 }
53870
53871
53872
53873
53874
53875
53876 public function getDescription()
53877 {
53878 return $this->description;
53879 }
53880
53881
53882
53883
53884
53885
53886
53887
53888 public function setHelp($help)
53889 {
53890 $this->help = $help;
53891
53892 return $this;
53893 }
53894
53895
53896
53897
53898
53899
53900 public function getHelp()
53901 {
53902 return $this->help;
53903 }
53904
53905
53906
53907
53908
53909
53910
53911 public function getProcessedHelp()
53912 {
53913 $name = $this->name;
53914
53915 $placeholders = array(
53916 '%command.name%',
53917 '%command.full_name%',
53918 );
53919 $replacements = array(
53920 $name,
53921 $_SERVER['PHP_SELF'].' '.$name,
53922 );
53923
53924 return str_replace($placeholders, $replacements, $this->getHelp() ?: $this->getDescription());
53925 }
53926
53927
53928
53929
53930
53931
53932
53933
53934
53935
53936 public function setAliases($aliases)
53937 {
53938 if (!\is_array($aliases) && !$aliases instanceof \Traversable) {
53939 throw new InvalidArgumentException('$aliases must be an array or an instance of \Traversable');
53940 }
53941
53942 foreach ($aliases as $alias) {
53943 $this->validateName($alias);
53944 }
53945
53946 $this->aliases = $aliases;
53947
53948 return $this;
53949 }
53950
53951
53952
53953
53954
53955
53956 public function getAliases()
53957 {
53958 return $this->aliases;
53959 }
53960
53961
53962
53963
53964
53965
53966
53967
53968 public function getSynopsis($short = false)
53969 {
53970 $key = $short ? 'short' : 'long';
53971
53972 if (!isset($this->synopsis[$key])) {
53973 $this->synopsis[$key] = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis($short)));
53974 }
53975
53976 return $this->synopsis[$key];
53977 }
53978
53979
53980
53981
53982
53983
53984
53985
53986 public function addUsage($usage)
53987 {
53988 if (0 !== strpos($usage, $this->name)) {
53989 $usage = sprintf('%s %s', $this->name, $usage);
53990 }
53991
53992 $this->usages[] = $usage;
53993
53994 return $this;
53995 }
53996
53997
53998
53999
54000
54001
54002 public function getUsages()
54003 {
54004 return $this->usages;
54005 }
54006
54007
54008
54009
54010
54011
54012
54013
54014
54015
54016
54017 public function getHelper($name)
54018 {
54019 if (null === $this->helperSet) {
54020 throw new LogicException(sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name));
54021 }
54022
54023 return $this->helperSet->get($name);
54024 }
54025
54026
54027
54028
54029
54030
54031
54032
54033 public function asText()
54034 {
54035 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);
54036
54037 $descriptor = new TextDescriptor();
54038 $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true);
54039 $descriptor->describe($output, $this, array('raw_output' => true));
54040
54041 return $output->fetch();
54042 }
54043
54044
54045
54046
54047
54048
54049
54050
54051
54052
54053 public function asXml($asDom = false)
54054 {
54055 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);
54056
54057 $descriptor = new XmlDescriptor();
54058
54059 if ($asDom) {
54060 return $descriptor->getCommandDocument($this);
54061 }
54062
54063 $output = new BufferedOutput();
54064 $descriptor->describe($output, $this);
54065
54066 return $output->fetch();
54067 }
54068
54069
54070
54071
54072
54073
54074
54075
54076
54077
54078 private function validateName($name)
54079 {
54080 if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) {
54081 throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
54082 }
54083 }
54084 }
54085 <?php
54086
54087
54088
54089
54090
54091
54092
54093
54094
54095
54096 namespace Symfony\Component\Console\Command;
54097
54098 use Symfony\Component\Console\Helper\DescriptorHelper;
54099 use Symfony\Component\Console\Input\InputArgument;
54100 use Symfony\Component\Console\Input\InputInterface;
54101 use Symfony\Component\Console\Input\InputOption;
54102 use Symfony\Component\Console\Output\OutputInterface;
54103
54104
54105
54106
54107
54108
54109 class HelpCommand extends Command
54110 {
54111 private $command;
54112
54113
54114
54115
54116 protected function configure()
54117 {
54118 $this->ignoreValidationErrors();
54119
54120 $this
54121 ->setName('help')
54122 ->setDefinition(array(
54123 new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),
54124 new InputOption('xml', null, InputOption::VALUE_NONE, 'To output help as XML'),
54125 new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
54126 new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'),
54127 ))
54128 ->setDescription('Displays help for a command')
54129 ->setHelp(<<<'EOF'
54130 The <info>%command.name%</info> command displays help for a given command:
54131
54132   <info>php %command.full_name% list</info>
54133
54134 You can also output the help in other formats by using the <comment>--format</comment> option:
54135
54136   <info>php %command.full_name% --format=xml list</info>
54137
54138 To display the list of available commands, please use the <info>list</info> command.
54139 EOF
54140 )
54141 ;
54142 }
54143
54144 public function setCommand(Command $command)
54145 {
54146 $this->command = $command;
54147 }
54148
54149
54150
54151
54152 protected function execute(InputInterface $input, OutputInterface $output)
54153 {
54154 if (null === $this->command) {
54155 $this->command = $this->getApplication()->find($input->getArgument('command_name'));
54156 }
54157
54158 if ($input->getOption('xml')) {
54159 @trigger_error('The --xml option was deprecated in version 2.7 and will be removed in version 3.0. Use the --format option instead.', E_USER_DEPRECATED);
54160
54161 $input->setOption('format', 'xml');
54162 }
54163
54164 $helper = new DescriptorHelper();
54165 $helper->describe($output, $this->command, array(
54166 'format' => $input->getOption('format'),
54167 'raw_text' => $input->getOption('raw'),
54168 ));
54169
54170 $this->command = null;
54171 }
54172 }
54173 <?php
54174
54175
54176
54177
54178
54179
54180
54181
54182
54183
54184 namespace Symfony\Component\Console\Command;
54185
54186 use Symfony\Component\Console\Helper\DescriptorHelper;
54187 use Symfony\Component\Console\Input\InputArgument;
54188 use Symfony\Component\Console\Input\InputDefinition;
54189 use Symfony\Component\Console\Input\InputInterface;
54190 use Symfony\Component\Console\Input\InputOption;
54191 use Symfony\Component\Console\Output\OutputInterface;
54192
54193
54194
54195
54196
54197
54198 class ListCommand extends Command
54199 {
54200
54201
54202
54203 protected function configure()
54204 {
54205 $this
54206 ->setName('list')
54207 ->setDefinition($this->createDefinition())
54208 ->setDescription('Lists commands')
54209 ->setHelp(<<<'EOF'
54210 The <info>%command.name%</info> command lists all commands:
54211
54212   <info>php %command.full_name%</info>
54213
54214 You can also display the commands for a specific namespace:
54215
54216   <info>php %command.full_name% test</info>
54217
54218 You can also output the information in other formats by using the <comment>--format</comment> option:
54219
54220   <info>php %command.full_name% --format=xml</info>
54221
54222 It's also possible to get raw list of commands (useful for embedding command runner):
54223
54224   <info>php %command.full_name% --raw</info>
54225 EOF
54226 )
54227 ;
54228 }
54229
54230
54231
54232
54233 public function getNativeDefinition()
54234 {
54235 return $this->createDefinition();
54236 }
54237
54238
54239
54240
54241 protected function execute(InputInterface $input, OutputInterface $output)
54242 {
54243 if ($input->getOption('xml')) {
54244 @trigger_error('The --xml option was deprecated in version 2.7 and will be removed in version 3.0. Use the --format option instead.', E_USER_DEPRECATED);
54245
54246 $input->setOption('format', 'xml');
54247 }
54248
54249 $helper = new DescriptorHelper();
54250 $helper->describe($output, $this->getApplication(), array(
54251 'format' => $input->getOption('format'),
54252 'raw_text' => $input->getOption('raw'),
54253 'namespace' => $input->getArgument('namespace'),
54254 ));
54255 }
54256
54257
54258
54259
54260 private function createDefinition()
54261 {
54262 return new InputDefinition(array(
54263 new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
54264 new InputOption('xml', null, InputOption::VALUE_NONE, 'To output list as XML'),
54265 new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'),
54266 new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
54267 ));
54268 }
54269 }
54270 <?php
54271
54272
54273
54274
54275
54276
54277
54278
54279
54280
54281 namespace Symfony\Component\Console;
54282
54283
54284
54285
54286
54287
54288 final class ConsoleEvents
54289 {
54290
54291
54292
54293
54294
54295
54296
54297
54298
54299
54300 const COMMAND = 'console.command';
54301
54302
54303
54304
54305
54306
54307
54308
54309
54310
54311 const TERMINATE = 'console.terminate';
54312
54313
54314
54315
54316
54317
54318
54319
54320
54321
54322
54323 const EXCEPTION = 'console.exception';
54324 }
54325 <?php
54326
54327
54328
54329
54330
54331
54332
54333
54334
54335
54336 namespace Symfony\Component\Console\Descriptor;
54337
54338 use Symfony\Component\Console\Application;
54339 use Symfony\Component\Console\Command\Command;
54340 use Symfony\Component\Console\Exception\CommandNotFoundException;
54341
54342
54343
54344
54345
54346
54347 class ApplicationDescription
54348 {
54349 const GLOBAL_NAMESPACE = '_global';
54350
54351 private $application;
54352 private $namespace;
54353
54354
54355
54356
54357 private $namespaces;
54358
54359
54360
54361
54362 private $commands;
54363
54364
54365
54366
54367 private $aliases;
54368
54369 public function __construct(Application $application, $namespace = null)
54370 {
54371 $this->application = $application;
54372 $this->namespace = $namespace;
54373 }
54374
54375
54376
54377
54378 public function getNamespaces()
54379 {
54380 if (null === $this->namespaces) {
54381 $this->inspectApplication();
54382 }
54383
54384 return $this->namespaces;
54385 }
54386
54387
54388
54389
54390 public function getCommands()
54391 {
54392 if (null === $this->commands) {
54393 $this->inspectApplication();
54394 }
54395
54396 return $this->commands;
54397 }
54398
54399
54400
54401
54402
54403
54404
54405
54406 public function getCommand($name)
54407 {
54408 if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) {
54409 throw new CommandNotFoundException(sprintf('Command %s does not exist.', $name));
54410 }
54411
54412 return isset($this->commands[$name]) ? $this->commands[$name] : $this->aliases[$name];
54413 }
54414
54415 private function inspectApplication()
54416 {
54417 $this->commands = array();
54418 $this->namespaces = array();
54419
54420 $all = $this->application->all($this->namespace ? $this->application->findNamespace($this->namespace) : null);
54421 foreach ($this->sortCommands($all) as $namespace => $commands) {
54422 $names = array();
54423
54424
54425 foreach ($commands as $name => $command) {
54426 if (!$command->getName()) {
54427 continue;
54428 }
54429
54430 if ($command->getName() === $name) {
54431 $this->commands[$name] = $command;
54432 } else {
54433 $this->aliases[$name] = $command;
54434 }
54435
54436 $names[] = $name;
54437 }
54438
54439 $this->namespaces[$namespace] = array('id' => $namespace, 'commands' => $names);
54440 }
54441 }
54442
54443
54444
54445
54446 private function sortCommands(array $commands)
54447 {
54448 $namespacedCommands = array();
54449 $globalCommands = array();
54450 foreach ($commands as $name => $command) {
54451 $key = $this->application->extractNamespace($name, 1);
54452 if (!$key) {
54453 $globalCommands['_global'][$name] = $command;
54454 } else {
54455 $namespacedCommands[$key][$name] = $command;
54456 }
54457 }
54458 ksort($namespacedCommands);
54459 $namespacedCommands = array_merge($globalCommands, $namespacedCommands);
54460
54461 foreach ($namespacedCommands as &$commandsSet) {
54462 ksort($commandsSet);
54463 }
54464
54465 unset($commandsSet);
54466
54467 return $namespacedCommands;
54468 }
54469 }
54470 <?php
54471
54472
54473
54474
54475
54476
54477
54478
54479
54480
54481 namespace Symfony\Component\Console\Descriptor;
54482
54483 use Symfony\Component\Console\Application;
54484 use Symfony\Component\Console\Command\Command;
54485 use Symfony\Component\Console\Exception\InvalidArgumentException;
54486 use Symfony\Component\Console\Input\InputArgument;
54487 use Symfony\Component\Console\Input\InputDefinition;
54488 use Symfony\Component\Console\Input\InputOption;
54489 use Symfony\Component\Console\Output\OutputInterface;
54490
54491
54492
54493
54494
54495
54496 abstract class Descriptor implements DescriptorInterface
54497 {
54498
54499
54500
54501 private $output;
54502
54503
54504
54505
54506 public function describe(OutputInterface $output, $object, array $options = array())
54507 {
54508 $this->output = $output;
54509
54510 switch (true) {
54511 case $object instanceof InputArgument:
54512 $this->describeInputArgument($object, $options);
54513 break;
54514 case $object instanceof InputOption:
54515 $this->describeInputOption($object, $options);
54516 break;
54517 case $object instanceof InputDefinition:
54518 $this->describeInputDefinition($object, $options);
54519 break;
54520 case $object instanceof Command:
54521 $this->describeCommand($object, $options);
54522 break;
54523 case $object instanceof Application:
54524 $this->describeApplication($object, $options);
54525 break;
54526 default:
54527 throw new InvalidArgumentException(sprintf('Object of type "%s" is not describable.', \get_class($object)));
54528 }
54529 }
54530
54531
54532
54533
54534
54535
54536
54537 protected function write($content, $decorated = false)
54538 {
54539 $this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW);
54540 }
54541
54542
54543
54544
54545
54546
54547 abstract protected function describeInputArgument(InputArgument $argument, array $options = array());
54548
54549
54550
54551
54552
54553
54554 abstract protected function describeInputOption(InputOption $option, array $options = array());
54555
54556
54557
54558
54559
54560
54561 abstract protected function describeInputDefinition(InputDefinition $definition, array $options = array());
54562
54563
54564
54565
54566
54567
54568 abstract protected function describeCommand(Command $command, array $options = array());
54569
54570
54571
54572
54573
54574
54575 abstract protected function describeApplication(Application $application, array $options = array());
54576 }
54577 <?php
54578
54579
54580
54581
54582
54583
54584
54585
54586
54587
54588 namespace Symfony\Component\Console\Descriptor;
54589
54590 use Symfony\Component\Console\Output\OutputInterface;
54591
54592
54593
54594
54595
54596
54597 interface DescriptorInterface
54598 {
54599
54600
54601
54602
54603
54604
54605
54606 public function describe(OutputInterface $output, $object, array $options = array());
54607 }
54608 <?php
54609
54610
54611
54612
54613
54614
54615
54616
54617
54618
54619 namespace Symfony\Component\Console\Descriptor;
54620
54621 use Symfony\Component\Console\Application;
54622 use Symfony\Component\Console\Command\Command;
54623 use Symfony\Component\Console\Input\InputArgument;
54624 use Symfony\Component\Console\Input\InputDefinition;
54625 use Symfony\Component\Console\Input\InputOption;
54626
54627
54628
54629
54630
54631
54632
54633
54634 class JsonDescriptor extends Descriptor
54635 {
54636
54637
54638
54639 protected function describeInputArgument(InputArgument $argument, array $options = array())
54640 {
54641 $this->writeData($this->getInputArgumentData($argument), $options);
54642 }
54643
54644
54645
54646
54647 protected function describeInputOption(InputOption $option, array $options = array())
54648 {
54649 $this->writeData($this->getInputOptionData($option), $options);
54650 }
54651
54652
54653
54654
54655 protected function describeInputDefinition(InputDefinition $definition, array $options = array())
54656 {
54657 $this->writeData($this->getInputDefinitionData($definition), $options);
54658 }
54659
54660
54661
54662
54663 protected function describeCommand(Command $command, array $options = array())
54664 {
54665 $this->writeData($this->getCommandData($command), $options);
54666 }
54667
54668
54669
54670
54671 protected function describeApplication(Application $application, array $options = array())
54672 {
54673 $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;
54674 $description = new ApplicationDescription($application, $describedNamespace);
54675 $commands = array();
54676
54677 foreach ($description->getCommands() as $command) {
54678 $commands[] = $this->getCommandData($command);
54679 }
54680
54681 $data = $describedNamespace
54682 ? array('commands' => $commands, 'namespace' => $describedNamespace)
54683 : array('commands' => $commands, 'namespaces' => array_values($description->getNamespaces()));
54684
54685 $this->writeData($data, $options);
54686 }
54687
54688
54689
54690
54691
54692
54693 private function writeData(array $data, array $options)
54694 {
54695 $this->write(json_encode($data, isset($options['json_encoding']) ? $options['json_encoding'] : 0));
54696 }
54697
54698
54699
54700
54701 private function getInputArgumentData(InputArgument $argument)
54702 {
54703 return array(
54704 'name' => $argument->getName(),
54705 'is_required' => $argument->isRequired(),
54706 'is_array' => $argument->isArray(),
54707 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $argument->getDescription()),
54708 'default' => INF === $argument->getDefault() ? 'INF' : $argument->getDefault(),
54709 );
54710 }
54711
54712
54713
54714
54715 private function getInputOptionData(InputOption $option)
54716 {
54717 return array(
54718 'name' => '--'.$option->getName(),
54719 'shortcut' => $option->getShortcut() ? '-'.str_replace('|', '|-', $option->getShortcut()) : '',
54720 'accept_value' => $option->acceptValue(),
54721 'is_value_required' => $option->isValueRequired(),
54722 'is_multiple' => $option->isArray(),
54723 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $option->getDescription()),
54724 'default' => INF === $option->getDefault() ? 'INF' : $option->getDefault(),
54725 );
54726 }
54727
54728
54729
54730
54731 private function getInputDefinitionData(InputDefinition $definition)
54732 {
54733 $inputArguments = array();
54734 foreach ($definition->getArguments() as $name => $argument) {
54735 $inputArguments[$name] = $this->getInputArgumentData($argument);
54736 }
54737
54738 $inputOptions = array();
54739 foreach ($definition->getOptions() as $name => $option) {
54740 $inputOptions[$name] = $this->getInputOptionData($option);
54741 }
54742
54743 return array('arguments' => $inputArguments, 'options' => $inputOptions);
54744 }
54745
54746
54747
54748
54749 private function getCommandData(Command $command)
54750 {
54751 $command->getSynopsis();
54752 $command->mergeApplicationDefinition(false);
54753
54754 return array(
54755 'name' => $command->getName(),
54756 'usage' => array_merge(array($command->getSynopsis()), $command->getUsages(), $command->getAliases()),
54757 'description' => $command->getDescription(),
54758 'help' => $command->getProcessedHelp(),
54759 'definition' => $this->getInputDefinitionData($command->getNativeDefinition()),
54760 );
54761 }
54762 }
54763 <?php
54764
54765
54766
54767
54768
54769
54770
54771
54772
54773
54774 namespace Symfony\Component\Console\Descriptor;
54775
54776 use Symfony\Component\Console\Application;
54777 use Symfony\Component\Console\Command\Command;
54778 use Symfony\Component\Console\Helper\Helper;
54779 use Symfony\Component\Console\Input\InputArgument;
54780 use Symfony\Component\Console\Input\InputDefinition;
54781 use Symfony\Component\Console\Input\InputOption;
54782
54783
54784
54785
54786
54787
54788
54789
54790 class MarkdownDescriptor extends Descriptor
54791 {
54792
54793
54794
54795 protected function describeInputArgument(InputArgument $argument, array $options = array())
54796 {
54797 $this->write(
54798 '**'.$argument->getName().':**'."\n\n"
54799 .'* Name: '.($argument->getName() ?: '<none>')."\n"
54800 .'* Is required: '.($argument->isRequired() ? 'yes' : 'no')."\n"
54801 .'* Is array: '.($argument->isArray() ? 'yes' : 'no')."\n"
54802 .'* Description: '.preg_replace('/\s*[\r\n]\s*/', "\n  ", $argument->getDescription() ?: '<none>')."\n"
54803 .'* Default: `'.str_replace("\n", '', var_export($argument->getDefault(), true)).'`'
54804 );
54805 }
54806
54807
54808
54809
54810 protected function describeInputOption(InputOption $option, array $options = array())
54811 {
54812 $this->write(
54813 '**'.$option->getName().':**'."\n\n"
54814 .'* Name: `--'.$option->getName().'`'."\n"
54815 .'* Shortcut: '.($option->getShortcut() ? '`-'.str_replace('|', '|-', $option->getShortcut()).'`' : '<none>')."\n"
54816 .'* Accept value: '.($option->acceptValue() ? 'yes' : 'no')."\n"
54817 .'* Is value required: '.($option->isValueRequired() ? 'yes' : 'no')."\n"
54818 .'* Is multiple: '.($option->isArray() ? 'yes' : 'no')."\n"
54819 .'* Description: '.preg_replace('/\s*[\r\n]\s*/', "\n  ", $option->getDescription() ?: '<none>')."\n"
54820 .'* Default: `'.str_replace("\n", '', var_export($option->getDefault(), true)).'`'
54821 );
54822 }
54823
54824
54825
54826
54827 protected function describeInputDefinition(InputDefinition $definition, array $options = array())
54828 {
54829 if ($showArguments = \count($definition->getArguments()) > 0) {
54830 $this->write('### Arguments:');
54831 foreach ($definition->getArguments() as $argument) {
54832 $this->write("\n\n");
54833 $this->write($this->describeInputArgument($argument));
54834 }
54835 }
54836
54837 if (\count($definition->getOptions()) > 0) {
54838 if ($showArguments) {
54839 $this->write("\n\n");
54840 }
54841
54842 $this->write('### Options:');
54843 foreach ($definition->getOptions() as $option) {
54844 $this->write("\n\n");
54845 $this->write($this->describeInputOption($option));
54846 }
54847 }
54848 }
54849
54850
54851
54852
54853 protected function describeCommand(Command $command, array $options = array())
54854 {
54855 $command->getSynopsis();
54856 $command->mergeApplicationDefinition(false);
54857
54858 $this->write(
54859 $command->getName()."\n"
54860 .str_repeat('-', Helper::strlen($command->getName()))."\n\n"
54861 .'* Description: '.($command->getDescription() ?: '<none>')."\n"
54862 .'* Usage:'."\n\n"
54863 .array_reduce(array_merge(array($command->getSynopsis()), $command->getAliases(), $command->getUsages()), function ($carry, $usage) {
54864 return $carry.'  * `'.$usage.'`'."\n";
54865 })
54866 );
54867
54868 if ($help = $command->getProcessedHelp()) {
54869 $this->write("\n");
54870 $this->write($help);
54871 }
54872
54873 if ($command->getNativeDefinition()) {
54874 $this->write("\n\n");
54875 $this->describeInputDefinition($command->getNativeDefinition());
54876 }
54877 }
54878
54879
54880
54881
54882 protected function describeApplication(Application $application, array $options = array())
54883 {
54884 $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;
54885 $description = new ApplicationDescription($application, $describedNamespace);
54886
54887 $this->write($application->getName()."\n".str_repeat('=', Helper::strlen($application->getName())));
54888
54889 foreach ($description->getNamespaces() as $namespace) {
54890 if (ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
54891 $this->write("\n\n");
54892 $this->write('**'.$namespace['id'].':**');
54893 }
54894
54895 $this->write("\n\n");
54896 $this->write(implode("\n", array_map(function ($commandName) {
54897 return '* '.$commandName;
54898 }, $namespace['commands'])));
54899 }
54900
54901 foreach ($description->getCommands() as $command) {
54902 $this->write("\n\n");
54903 $this->write($this->describeCommand($command));
54904 }
54905 }
54906 }
54907 <?php
54908
54909
54910
54911
54912
54913
54914
54915
54916
54917
54918 namespace Symfony\Component\Console\Descriptor;
54919
54920 use Symfony\Component\Console\Application;
54921 use Symfony\Component\Console\Command\Command;
54922 use Symfony\Component\Console\Formatter\OutputFormatter;
54923 use Symfony\Component\Console\Helper\Helper;
54924 use Symfony\Component\Console\Input\InputArgument;
54925 use Symfony\Component\Console\Input\InputDefinition;
54926 use Symfony\Component\Console\Input\InputOption;
54927
54928
54929
54930
54931
54932
54933
54934
54935 class TextDescriptor extends Descriptor
54936 {
54937
54938
54939
54940 protected function describeInputArgument(InputArgument $argument, array $options = array())
54941 {
54942 if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) {
54943 $default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($argument->getDefault()));
54944 } else {
54945 $default = '';
54946 }
54947
54948 $totalWidth = isset($options['total_width']) ? $options['total_width'] : Helper::strlen($argument->getName());
54949 $spacingWidth = $totalWidth - \strlen($argument->getName());
54950
54951 $this->writeText(sprintf('  <info>%s</info>  %s%s%s',
54952 $argument->getName(),
54953 str_repeat(' ', $spacingWidth),
54954
54955 preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $argument->getDescription()),
54956 $default
54957 ), $options);
54958 }
54959
54960
54961
54962
54963 protected function describeInputOption(InputOption $option, array $options = array())
54964 {
54965 if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) {
54966 $default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($option->getDefault()));
54967 } else {
54968 $default = '';
54969 }
54970
54971 $value = '';
54972 if ($option->acceptValue()) {
54973 $value = '='.strtoupper($option->getName());
54974
54975 if ($option->isValueOptional()) {
54976 $value = '['.$value.']';
54977 }
54978 }
54979
54980 $totalWidth = isset($options['total_width']) ? $options['total_width'] : $this->calculateTotalWidthForOptions(array($option));
54981 $synopsis = sprintf('%s%s',
54982 $option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : '    ',
54983 sprintf('--%s%s', $option->getName(), $value)
54984 );
54985
54986 $spacingWidth = $totalWidth - Helper::strlen($synopsis);
54987
54988 $this->writeText(sprintf('  <info>%s</info>  %s%s%s%s',
54989 $synopsis,
54990 str_repeat(' ', $spacingWidth),
54991
54992 preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $option->getDescription()),
54993 $default,
54994 $option->isArray() ? '<comment> (multiple values allowed)</comment>' : ''
54995 ), $options);
54996 }
54997
54998
54999
55000
55001 protected function describeInputDefinition(InputDefinition $definition, array $options = array())
55002 {
55003 $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions());
55004 foreach ($definition->getArguments() as $argument) {
55005 $totalWidth = max($totalWidth, Helper::strlen($argument->getName()));
55006 }
55007
55008 if ($definition->getArguments()) {
55009 $this->writeText('<comment>Arguments:</comment>', $options);
55010 $this->writeText("\n");
55011 foreach ($definition->getArguments() as $argument) {
55012 $this->describeInputArgument($argument, array_merge($options, array('total_width' => $totalWidth)));
55013 $this->writeText("\n");
55014 }
55015 }
55016
55017 if ($definition->getArguments() && $definition->getOptions()) {
55018 $this->writeText("\n");
55019 }
55020
55021 if ($definition->getOptions()) {
55022 $laterOptions = array();
55023
55024 $this->writeText('<comment>Options:</comment>', $options);
55025 foreach ($definition->getOptions() as $option) {
55026 if (\strlen($option->getShortcut()) > 1) {
55027 $laterOptions[] = $option;
55028 continue;
55029 }
55030 $this->writeText("\n");
55031 $this->describeInputOption($option, array_merge($options, array('total_width' => $totalWidth)));
55032 }
55033 foreach ($laterOptions as $option) {
55034 $this->writeText("\n");
55035 $this->describeInputOption($option, array_merge($options, array('total_width' => $totalWidth)));
55036 }
55037 }
55038 }
55039
55040
55041
55042
55043 protected function describeCommand(Command $command, array $options = array())
55044 {
55045 $command->getSynopsis(true);
55046 $command->getSynopsis(false);
55047 $command->mergeApplicationDefinition(false);
55048
55049 $this->writeText('<comment>Usage:</comment>', $options);
55050 foreach (array_merge(array($command->getSynopsis(true)), $command->getAliases(), $command->getUsages()) as $usage) {
55051 $this->writeText("\n");
55052 $this->writeText('  '.OutputFormatter::escape($usage), $options);
55053 }
55054 $this->writeText("\n");
55055
55056 $definition = $command->getNativeDefinition();
55057 if ($definition->getOptions() || $definition->getArguments()) {
55058 $this->writeText("\n");
55059 $this->describeInputDefinition($definition, $options);
55060 $this->writeText("\n");
55061 }
55062
55063 if ($help = $command->getProcessedHelp()) {
55064 $this->writeText("\n");
55065 $this->writeText('<comment>Help:</comment>', $options);
55066 $this->writeText("\n");
55067 $this->writeText('  '.str_replace("\n", "\n  ", $help), $options);
55068 $this->writeText("\n");
55069 }
55070 }
55071
55072
55073
55074
55075 protected function describeApplication(Application $application, array $options = array())
55076 {
55077 $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;
55078 $description = new ApplicationDescription($application, $describedNamespace);
55079
55080 if (isset($options['raw_text']) && $options['raw_text']) {
55081 $width = $this->getColumnWidth($description->getCommands());
55082
55083 foreach ($description->getCommands() as $command) {
55084 $this->writeText(sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options);
55085 $this->writeText("\n");
55086 }
55087 } else {
55088 if ('' != $help = $application->getHelp()) {
55089 $this->writeText("$help\n\n", $options);
55090 }
55091
55092 $this->writeText("<comment>Usage:</comment>\n", $options);
55093 $this->writeText("  command [options] [arguments]\n\n", $options);
55094
55095 $this->describeInputDefinition(new InputDefinition($application->getDefinition()->getOptions()), $options);
55096
55097 $this->writeText("\n");
55098 $this->writeText("\n");
55099
55100 $width = $this->getColumnWidth($description->getCommands());
55101
55102 if ($describedNamespace) {
55103 $this->writeText(sprintf('<comment>Available commands for the "%s" namespace:</comment>', $describedNamespace), $options);
55104 } else {
55105 $this->writeText('<comment>Available commands:</comment>', $options);
55106 }
55107
55108
55109 foreach ($description->getNamespaces() as $namespace) {
55110 if (!$describedNamespace && ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
55111 $this->writeText("\n");
55112 $this->writeText(' <comment>'.$namespace['id'].'</comment>', $options);
55113 }
55114
55115 foreach ($namespace['commands'] as $name) {
55116 $this->writeText("\n");
55117 $spacingWidth = $width - Helper::strlen($name);
55118 $this->writeText(sprintf('  <info>%s</info>%s%s', $name, str_repeat(' ', $spacingWidth), $description->getCommand($name)->getDescription()), $options);
55119 }
55120 }
55121
55122 $this->writeText("\n");
55123 }
55124 }
55125
55126
55127
55128
55129 private function writeText($content, array $options = array())
55130 {
55131 $this->write(
55132 isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content,
55133 isset($options['raw_output']) ? !$options['raw_output'] : true
55134 );
55135 }
55136
55137
55138
55139
55140
55141
55142
55143
55144 private function formatDefaultValue($default)
55145 {
55146 if (INF === $default) {
55147 return 'INF';
55148 }
55149
55150 if (\is_string($default)) {
55151 $default = OutputFormatter::escape($default);
55152 } elseif (\is_array($default)) {
55153 foreach ($default as $key => $value) {
55154 if (\is_string($value)) {
55155 $default[$key] = OutputFormatter::escape($value);
55156 }
55157 }
55158 }
55159
55160 if (\PHP_VERSION_ID < 50400) {
55161 return str_replace(array('\/', '\\\\'), array('/', '\\'), json_encode($default));
55162 }
55163
55164 return str_replace('\\\\', '\\', json_encode($default, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
55165 }
55166
55167
55168
55169
55170
55171
55172 private function getColumnWidth(array $commands)
55173 {
55174 $widths = array();
55175
55176 foreach ($commands as $command) {
55177 $widths[] = Helper::strlen($command->getName());
55178 foreach ($command->getAliases() as $alias) {
55179 $widths[] = Helper::strlen($alias);
55180 }
55181 }
55182
55183 return max($widths) + 2;
55184 }
55185
55186
55187
55188
55189
55190
55191 private function calculateTotalWidthForOptions(array $options)
55192 {
55193 $totalWidth = 0;
55194 foreach ($options as $option) {
55195
55196 $nameLength = 1 + max(\strlen($option->getShortcut()), 1) + 4 + Helper::strlen($option->getName());
55197
55198 if ($option->acceptValue()) {
55199 $valueLength = 1 + Helper::strlen($option->getName()); 
55200 $valueLength += $option->isValueOptional() ? 2 : 0; 
55201
55202 $nameLength += $valueLength;
55203 }
55204 $totalWidth = max($totalWidth, $nameLength);
55205 }
55206
55207 return $totalWidth;
55208 }
55209 }
55210 <?php
55211
55212
55213
55214
55215
55216
55217
55218
55219
55220
55221 namespace Symfony\Component\Console\Descriptor;
55222
55223 use Symfony\Component\Console\Application;
55224 use Symfony\Component\Console\Command\Command;
55225 use Symfony\Component\Console\Input\InputArgument;
55226 use Symfony\Component\Console\Input\InputDefinition;
55227 use Symfony\Component\Console\Input\InputOption;
55228
55229
55230
55231
55232
55233
55234
55235
55236 class XmlDescriptor extends Descriptor
55237 {
55238
55239
55240
55241 public function getInputDefinitionDocument(InputDefinition $definition)
55242 {
55243 $dom = new \DOMDocument('1.0', 'UTF-8');
55244 $dom->appendChild($definitionXML = $dom->createElement('definition'));
55245
55246 $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments'));
55247 foreach ($definition->getArguments() as $argument) {
55248 $this->appendDocument($argumentsXML, $this->getInputArgumentDocument($argument));
55249 }
55250
55251 $definitionXML->appendChild($optionsXML = $dom->createElement('options'));
55252 foreach ($definition->getOptions() as $option) {
55253 $this->appendDocument($optionsXML, $this->getInputOptionDocument($option));
55254 }
55255
55256 return $dom;
55257 }
55258
55259
55260
55261
55262 public function getCommandDocument(Command $command)
55263 {
55264 $dom = new \DOMDocument('1.0', 'UTF-8');
55265 $dom->appendChild($commandXML = $dom->createElement('command'));
55266
55267 $command->getSynopsis();
55268 $command->mergeApplicationDefinition(false);
55269
55270 $commandXML->setAttribute('id', $command->getName());
55271 $commandXML->setAttribute('name', $command->getName());
55272
55273 $commandXML->appendChild($usagesXML = $dom->createElement('usages'));
55274
55275 foreach (array_merge(array($command->getSynopsis()), $command->getAliases(), $command->getUsages()) as $usage) {
55276 $usagesXML->appendChild($dom->createElement('usage', $usage));
55277 }
55278
55279 $commandXML->appendChild($descriptionXML = $dom->createElement('description'));
55280 $descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getDescription())));
55281
55282 $commandXML->appendChild($helpXML = $dom->createElement('help'));
55283 $helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getProcessedHelp())));
55284
55285 $definitionXML = $this->getInputDefinitionDocument($command->getNativeDefinition());
55286 $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0));
55287
55288 return $dom;
55289 }
55290
55291
55292
55293
55294
55295
55296
55297 public function getApplicationDocument(Application $application, $namespace = null)
55298 {
55299 $dom = new \DOMDocument('1.0', 'UTF-8');
55300 $dom->appendChild($rootXml = $dom->createElement('symfony'));
55301
55302 if ('UNKNOWN' !== $application->getName()) {
55303 $rootXml->setAttribute('name', $application->getName());
55304 if ('UNKNOWN' !== $application->getVersion()) {
55305 $rootXml->setAttribute('version', $application->getVersion());
55306 }
55307 }
55308
55309 $rootXml->appendChild($commandsXML = $dom->createElement('commands'));
55310
55311 $description = new ApplicationDescription($application, $namespace);
55312
55313 if ($namespace) {
55314 $commandsXML->setAttribute('namespace', $namespace);
55315 }
55316
55317 foreach ($description->getCommands() as $command) {
55318 $this->appendDocument($commandsXML, $this->getCommandDocument($command));
55319 }
55320
55321 if (!$namespace) {
55322 $rootXml->appendChild($namespacesXML = $dom->createElement('namespaces'));
55323
55324 foreach ($description->getNamespaces() as $namespaceDescription) {
55325 $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace'));
55326 $namespaceArrayXML->setAttribute('id', $namespaceDescription['id']);
55327
55328 foreach ($namespaceDescription['commands'] as $name) {
55329 $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command'));
55330 $commandXML->appendChild($dom->createTextNode($name));
55331 }
55332 }
55333 }
55334
55335 return $dom;
55336 }
55337
55338
55339
55340
55341 protected function describeInputArgument(InputArgument $argument, array $options = array())
55342 {
55343 $this->writeDocument($this->getInputArgumentDocument($argument));
55344 }
55345
55346
55347
55348
55349 protected function describeInputOption(InputOption $option, array $options = array())
55350 {
55351 $this->writeDocument($this->getInputOptionDocument($option));
55352 }
55353
55354
55355
55356
55357 protected function describeInputDefinition(InputDefinition $definition, array $options = array())
55358 {
55359 $this->writeDocument($this->getInputDefinitionDocument($definition));
55360 }
55361
55362
55363
55364
55365 protected function describeCommand(Command $command, array $options = array())
55366 {
55367 $this->writeDocument($this->getCommandDocument($command));
55368 }
55369
55370
55371
55372
55373 protected function describeApplication(Application $application, array $options = array())
55374 {
55375 $this->writeDocument($this->getApplicationDocument($application, isset($options['namespace']) ? $options['namespace'] : null));
55376 }
55377
55378
55379
55380
55381 private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent)
55382 {
55383 foreach ($importedParent->childNodes as $childNode) {
55384 $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, true));
55385 }
55386 }
55387
55388
55389
55390
55391
55392
55393 private function writeDocument(\DOMDocument $dom)
55394 {
55395 $dom->formatOutput = true;
55396 $this->write($dom->saveXML());
55397 }
55398
55399
55400
55401
55402 private function getInputArgumentDocument(InputArgument $argument)
55403 {
55404 $dom = new \DOMDocument('1.0', 'UTF-8');
55405
55406 $dom->appendChild($objectXML = $dom->createElement('argument'));
55407 $objectXML->setAttribute('name', $argument->getName());
55408 $objectXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0);
55409 $objectXML->setAttribute('is_array', $argument->isArray() ? 1 : 0);
55410 $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
55411 $descriptionXML->appendChild($dom->createTextNode($argument->getDescription()));
55412
55413 $objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));
55414 $defaults = \is_array($argument->getDefault()) ? $argument->getDefault() : (\is_bool($argument->getDefault()) ? array(var_export($argument->getDefault(), true)) : ($argument->getDefault() ? array($argument->getDefault()) : array()));
55415 foreach ($defaults as $default) {
55416 $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
55417 $defaultXML->appendChild($dom->createTextNode($default));
55418 }
55419
55420 return $dom;
55421 }
55422
55423
55424
55425
55426 private function getInputOptionDocument(InputOption $option)
55427 {
55428 $dom = new \DOMDocument('1.0', 'UTF-8');
55429
55430 $dom->appendChild($objectXML = $dom->createElement('option'));
55431 $objectXML->setAttribute('name', '--'.$option->getName());
55432 $pos = strpos($option->getShortcut(), '|');
55433 if (false !== $pos) {
55434 $objectXML->setAttribute('shortcut', '-'.substr($option->getShortcut(), 0, $pos));
55435 $objectXML->setAttribute('shortcuts', '-'.str_replace('|', '|-', $option->getShortcut()));
55436 } else {
55437 $objectXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : '');
55438 }
55439 $objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0);
55440 $objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0);
55441 $objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0);
55442 $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
55443 $descriptionXML->appendChild($dom->createTextNode($option->getDescription()));
55444
55445 if ($option->acceptValue()) {
55446 $defaults = \is_array($option->getDefault()) ? $option->getDefault() : (\is_bool($option->getDefault()) ? array(var_export($option->getDefault(), true)) : ($option->getDefault() ? array($option->getDefault()) : array()));
55447 $objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));
55448
55449 if (!empty($defaults)) {
55450 foreach ($defaults as $default) {
55451 $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
55452 $defaultXML->appendChild($dom->createTextNode($default));
55453 }
55454 }
55455 }
55456
55457 return $dom;
55458 }
55459 }
55460 <?php
55461
55462
55463
55464
55465
55466
55467
55468
55469
55470
55471 namespace Symfony\Component\Console\Event;
55472
55473
55474
55475
55476
55477
55478 class ConsoleCommandEvent extends ConsoleEvent
55479 {
55480
55481
55482
55483 const RETURN_CODE_DISABLED = 113;
55484
55485
55486
55487
55488 private $commandShouldRun = true;
55489
55490
55491
55492
55493
55494
55495 public function disableCommand()
55496 {
55497 return $this->commandShouldRun = false;
55498 }
55499
55500
55501
55502
55503
55504
55505 public function enableCommand()
55506 {
55507 return $this->commandShouldRun = true;
55508 }
55509
55510
55511
55512
55513
55514
55515 public function commandShouldRun()
55516 {
55517 return $this->commandShouldRun;
55518 }
55519 }
55520 <?php
55521
55522
55523
55524
55525
55526
55527
55528
55529
55530
55531 namespace Symfony\Component\Console\Event;
55532
55533 use Symfony\Component\Console\Command\Command;
55534 use Symfony\Component\Console\Input\InputInterface;
55535 use Symfony\Component\Console\Output\OutputInterface;
55536 use Symfony\Component\EventDispatcher\Event;
55537
55538
55539
55540
55541
55542
55543 class ConsoleEvent extends Event
55544 {
55545 protected $command;
55546
55547 private $input;
55548 private $output;
55549
55550 public function __construct(Command $command, InputInterface $input, OutputInterface $output)
55551 {
55552 $this->command = $command;
55553 $this->input = $input;
55554 $this->output = $output;
55555 }
55556
55557
55558
55559
55560
55561
55562 public function getCommand()
55563 {
55564 return $this->command;
55565 }
55566
55567
55568
55569
55570
55571
55572 public function getInput()
55573 {
55574 return $this->input;
55575 }
55576
55577
55578
55579
55580
55581
55582 public function getOutput()
55583 {
55584 return $this->output;
55585 }
55586 }
55587 <?php
55588
55589
55590
55591
55592
55593
55594
55595
55596
55597
55598 namespace Symfony\Component\Console\Event;
55599
55600 use Symfony\Component\Console\Command\Command;
55601 use Symfony\Component\Console\Input\InputInterface;
55602 use Symfony\Component\Console\Output\OutputInterface;
55603
55604
55605
55606
55607
55608
55609 class ConsoleExceptionEvent extends ConsoleEvent
55610 {
55611 private $exception;
55612 private $exitCode;
55613
55614 public function __construct(Command $command, InputInterface $input, OutputInterface $output, \Exception $exception, $exitCode)
55615 {
55616 parent::__construct($command, $input, $output);
55617
55618 $this->setException($exception);
55619 $this->exitCode = (int) $exitCode;
55620 }
55621
55622
55623
55624
55625
55626
55627 public function getException()
55628 {
55629 return $this->exception;
55630 }
55631
55632
55633
55634
55635
55636
55637
55638
55639 public function setException(\Exception $exception)
55640 {
55641 $this->exception = $exception;
55642 }
55643
55644
55645
55646
55647
55648
55649 public function getExitCode()
55650 {
55651 return $this->exitCode;
55652 }
55653 }
55654 <?php
55655
55656
55657
55658
55659
55660
55661
55662
55663
55664
55665 namespace Symfony\Component\Console\Event;
55666
55667 use Symfony\Component\Console\Command\Command;
55668 use Symfony\Component\Console\Input\InputInterface;
55669 use Symfony\Component\Console\Output\OutputInterface;
55670
55671
55672
55673
55674
55675
55676 class ConsoleTerminateEvent extends ConsoleEvent
55677 {
55678
55679
55680
55681
55682
55683 private $exitCode;
55684
55685 public function __construct(Command $command, InputInterface $input, OutputInterface $output, $exitCode)
55686 {
55687 parent::__construct($command, $input, $output);
55688
55689 $this->setExitCode($exitCode);
55690 }
55691
55692
55693
55694
55695
55696
55697 public function setExitCode($exitCode)
55698 {
55699 $this->exitCode = (int) $exitCode;
55700 }
55701
55702
55703
55704
55705
55706
55707 public function getExitCode()
55708 {
55709 return $this->exitCode;
55710 }
55711 }
55712 <?php
55713
55714
55715
55716
55717
55718
55719
55720
55721
55722
55723 namespace Symfony\Component\Console\Exception;
55724
55725
55726
55727
55728
55729
55730 class CommandNotFoundException extends \InvalidArgumentException implements ExceptionInterface
55731 {
55732 private $alternatives;
55733
55734
55735
55736
55737
55738
55739
55740 public function __construct($message, array $alternatives = array(), $code = 0, \Exception $previous = null)
55741 {
55742 parent::__construct($message, $code, $previous);
55743
55744 $this->alternatives = $alternatives;
55745 }
55746
55747
55748
55749
55750 public function getAlternatives()
55751 {
55752 return $this->alternatives;
55753 }
55754 }
55755 <?php
55756
55757
55758
55759
55760
55761
55762
55763
55764
55765
55766 namespace Symfony\Component\Console\Exception;
55767
55768
55769
55770
55771
55772
55773 interface ExceptionInterface
55774 {
55775 }
55776 <?php
55777
55778
55779
55780
55781
55782
55783
55784
55785
55786
55787 namespace Symfony\Component\Console\Exception;
55788
55789
55790
55791
55792 class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
55793 {
55794 }
55795 <?php
55796
55797
55798
55799
55800
55801
55802
55803
55804
55805
55806 namespace Symfony\Component\Console\Exception;
55807
55808
55809
55810
55811
55812
55813 class InvalidOptionException extends \InvalidArgumentException implements ExceptionInterface
55814 {
55815 }
55816 <?php
55817
55818
55819
55820
55821
55822
55823
55824
55825
55826
55827 namespace Symfony\Component\Console\Exception;
55828
55829
55830
55831
55832 class LogicException extends \LogicException implements ExceptionInterface
55833 {
55834 }
55835 <?php
55836
55837
55838
55839
55840
55841
55842
55843
55844
55845
55846 namespace Symfony\Component\Console\Exception;
55847
55848
55849
55850
55851 class RuntimeException extends \RuntimeException implements ExceptionInterface
55852 {
55853 }
55854 <?php
55855
55856
55857
55858
55859
55860
55861
55862
55863
55864
55865 namespace Symfony\Component\Console\Formatter;
55866
55867 use Symfony\Component\Console\Exception\InvalidArgumentException;
55868
55869
55870
55871
55872
55873
55874 class OutputFormatter implements OutputFormatterInterface
55875 {
55876 private $decorated;
55877 private $styles = array();
55878 private $styleStack;
55879
55880
55881
55882
55883
55884
55885
55886
55887 public static function escape($text)
55888 {
55889 $text = preg_replace('/([^\\\\]?)</', '$1\\<', $text);
55890
55891 return self::escapeTrailingBackslash($text);
55892 }
55893
55894
55895
55896
55897
55898
55899
55900
55901
55902
55903 public static function escapeTrailingBackslash($text)
55904 {
55905 if ('\\' === substr($text, -1)) {
55906 $len = \strlen($text);
55907 $text = rtrim($text, '\\');
55908 $text = str_replace("\0", '', $text);
55909 $text .= str_repeat("\0", $len - \strlen($text));
55910 }
55911
55912 return $text;
55913 }
55914
55915
55916
55917
55918
55919
55920
55921 public function __construct($decorated = false, array $styles = array())
55922 {
55923 $this->decorated = (bool) $decorated;
55924
55925 $this->setStyle('error', new OutputFormatterStyle('white', 'red'));
55926 $this->setStyle('info', new OutputFormatterStyle('green'));
55927 $this->setStyle('comment', new OutputFormatterStyle('yellow'));
55928 $this->setStyle('question', new OutputFormatterStyle('black', 'cyan'));
55929
55930 foreach ($styles as $name => $style) {
55931 $this->setStyle($name, $style);
55932 }
55933
55934 $this->styleStack = new OutputFormatterStyleStack();
55935 }
55936
55937
55938
55939
55940 public function setDecorated($decorated)
55941 {
55942 $this->decorated = (bool) $decorated;
55943 }
55944
55945
55946
55947
55948 public function isDecorated()
55949 {
55950 return $this->decorated;
55951 }
55952
55953
55954
55955
55956 public function setStyle($name, OutputFormatterStyleInterface $style)
55957 {
55958 $this->styles[strtolower($name)] = $style;
55959 }
55960
55961
55962
55963
55964 public function hasStyle($name)
55965 {
55966 return isset($this->styles[strtolower($name)]);
55967 }
55968
55969
55970
55971
55972 public function getStyle($name)
55973 {
55974 if (!$this->hasStyle($name)) {
55975 throw new InvalidArgumentException(sprintf('Undefined style: %s', $name));
55976 }
55977
55978 return $this->styles[strtolower($name)];
55979 }
55980
55981
55982
55983
55984 public function format($message)
55985 {
55986 $message = (string) $message;
55987 $offset = 0;
55988 $output = '';
55989 $tagRegex = '[a-z][a-z0-9_=;-]*+';
55990 preg_match_all("#<(($tagRegex) | /($tagRegex)?)>#ix", $message, $matches, PREG_OFFSET_CAPTURE);
55991 foreach ($matches[0] as $i => $match) {
55992 $pos = $match[1];
55993 $text = $match[0];
55994
55995 if (0 != $pos && '\\' == $message[$pos - 1]) {
55996 continue;
55997 }
55998
55999
56000 $output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset));
56001 $offset = $pos + \strlen($text);
56002
56003
56004 if ($open = '/' != $text[1]) {
56005 $tag = $matches[1][$i][0];
56006 } else {
56007 $tag = isset($matches[3][$i][0]) ? $matches[3][$i][0] : '';
56008 }
56009
56010 if (!$open && !$tag) {
56011
56012 $this->styleStack->pop();
56013 } elseif (false === $style = $this->createStyleFromString(strtolower($tag))) {
56014 $output .= $this->applyCurrentStyle($text);
56015 } elseif ($open) {
56016 $this->styleStack->push($style);
56017 } else {
56018 $this->styleStack->pop($style);
56019 }
56020 }
56021
56022 $output .= $this->applyCurrentStyle(substr($message, $offset));
56023
56024 if (false !== strpos($output, "\0")) {
56025 return strtr($output, array("\0" => '\\', '\\<' => '<'));
56026 }
56027
56028 return str_replace('\\<', '<', $output);
56029 }
56030
56031
56032
56033
56034 public function getStyleStack()
56035 {
56036 return $this->styleStack;
56037 }
56038
56039
56040
56041
56042
56043
56044
56045
56046 private function createStyleFromString($string)
56047 {
56048 if (isset($this->styles[$string])) {
56049 return $this->styles[$string];
56050 }
56051
56052 if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', strtolower($string), $matches, PREG_SET_ORDER)) {
56053 return false;
56054 }
56055
56056 $style = new OutputFormatterStyle();
56057 foreach ($matches as $match) {
56058 array_shift($match);
56059
56060 if ('fg' == $match[0]) {
56061 $style->setForeground($match[1]);
56062 } elseif ('bg' == $match[0]) {
56063 $style->setBackground($match[1]);
56064 } else {
56065 try {
56066 $style->setOption($match[1]);
56067 } catch (\InvalidArgumentException $e) {
56068 return false;
56069 }
56070 }
56071 }
56072
56073 return $style;
56074 }
56075
56076
56077
56078
56079
56080
56081
56082
56083 private function applyCurrentStyle($text)
56084 {
56085 return $this->isDecorated() && \strlen($text) > 0 ? $this->styleStack->getCurrent()->apply($text) : $text;
56086 }
56087 }
56088 <?php
56089
56090
56091
56092
56093
56094
56095
56096
56097
56098
56099 namespace Symfony\Component\Console\Formatter;
56100
56101
56102
56103
56104
56105
56106 interface OutputFormatterInterface
56107 {
56108
56109
56110
56111
56112
56113 public function setDecorated($decorated);
56114
56115
56116
56117
56118
56119
56120 public function isDecorated();
56121
56122
56123
56124
56125
56126
56127
56128 public function setStyle($name, OutputFormatterStyleInterface $style);
56129
56130
56131
56132
56133
56134
56135
56136
56137 public function hasStyle($name);
56138
56139
56140
56141
56142
56143
56144
56145
56146
56147
56148 public function getStyle($name);
56149
56150
56151
56152
56153
56154
56155
56156
56157 public function format($message);
56158 }
56159 <?php
56160
56161
56162
56163
56164
56165
56166
56167
56168
56169
56170 namespace Symfony\Component\Console\Formatter;
56171
56172 use Symfony\Component\Console\Exception\InvalidArgumentException;
56173
56174
56175
56176
56177
56178
56179 class OutputFormatterStyle implements OutputFormatterStyleInterface
56180 {
56181 private static $availableForegroundColors = array(
56182 'black' => array('set' => 30, 'unset' => 39),
56183 'red' => array('set' => 31, 'unset' => 39),
56184 'green' => array('set' => 32, 'unset' => 39),
56185 'yellow' => array('set' => 33, 'unset' => 39),
56186 'blue' => array('set' => 34, 'unset' => 39),
56187 'magenta' => array('set' => 35, 'unset' => 39),
56188 'cyan' => array('set' => 36, 'unset' => 39),
56189 'white' => array('set' => 37, 'unset' => 39),
56190 'default' => array('set' => 39, 'unset' => 39),
56191 );
56192 private static $availableBackgroundColors = array(
56193 'black' => array('set' => 40, 'unset' => 49),
56194 'red' => array('set' => 41, 'unset' => 49),
56195 'green' => array('set' => 42, 'unset' => 49),
56196 'yellow' => array('set' => 43, 'unset' => 49),
56197 'blue' => array('set' => 44, 'unset' => 49),
56198 'magenta' => array('set' => 45, 'unset' => 49),
56199 'cyan' => array('set' => 46, 'unset' => 49),
56200 'white' => array('set' => 47, 'unset' => 49),
56201 'default' => array('set' => 49, 'unset' => 49),
56202 );
56203 private static $availableOptions = array(
56204 'bold' => array('set' => 1, 'unset' => 22),
56205 'underscore' => array('set' => 4, 'unset' => 24),
56206 'blink' => array('set' => 5, 'unset' => 25),
56207 'reverse' => array('set' => 7, 'unset' => 27),
56208 'conceal' => array('set' => 8, 'unset' => 28),
56209 );
56210
56211 private $foreground;
56212 private $background;
56213 private $options = array();
56214
56215
56216
56217
56218
56219
56220
56221
56222 public function __construct($foreground = null, $background = null, array $options = array())
56223 {
56224 if (null !== $foreground) {
56225 $this->setForeground($foreground);
56226 }
56227 if (null !== $background) {
56228 $this->setBackground($background);
56229 }
56230 if (\count($options)) {
56231 $this->setOptions($options);
56232 }
56233 }
56234
56235
56236
56237
56238
56239
56240
56241
56242 public function setForeground($color = null)
56243 {
56244 if (null === $color) {
56245 $this->foreground = null;
56246
56247 return;
56248 }
56249
56250 if (!isset(static::$availableForegroundColors[$color])) {
56251 throw new InvalidArgumentException(sprintf('Invalid foreground color specified: "%s". Expected one of (%s)', $color, implode(', ', array_keys(static::$availableForegroundColors))));
56252 }
56253
56254 $this->foreground = static::$availableForegroundColors[$color];
56255 }
56256
56257
56258
56259
56260
56261
56262
56263
56264 public function setBackground($color = null)
56265 {
56266 if (null === $color) {
56267 $this->background = null;
56268
56269 return;
56270 }
56271
56272 if (!isset(static::$availableBackgroundColors[$color])) {
56273 throw new InvalidArgumentException(sprintf('Invalid background color specified: "%s". Expected one of (%s)', $color, implode(', ', array_keys(static::$availableBackgroundColors))));
56274 }
56275
56276 $this->background = static::$availableBackgroundColors[$color];
56277 }
56278
56279
56280
56281
56282
56283
56284
56285
56286 public function setOption($option)
56287 {
56288 if (!isset(static::$availableOptions[$option])) {
56289 throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s)', $option, implode(', ', array_keys(static::$availableOptions))));
56290 }
56291
56292 if (!\in_array(static::$availableOptions[$option], $this->options)) {
56293 $this->options[] = static::$availableOptions[$option];
56294 }
56295 }
56296
56297
56298
56299
56300
56301
56302
56303
56304 public function unsetOption($option)
56305 {
56306 if (!isset(static::$availableOptions[$option])) {
56307 throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s)', $option, implode(', ', array_keys(static::$availableOptions))));
56308 }
56309
56310 $pos = array_search(static::$availableOptions[$option], $this->options);
56311 if (false !== $pos) {
56312 unset($this->options[$pos]);
56313 }
56314 }
56315
56316
56317
56318
56319 public function setOptions(array $options)
56320 {
56321 $this->options = array();
56322
56323 foreach ($options as $option) {
56324 $this->setOption($option);
56325 }
56326 }
56327
56328
56329
56330
56331
56332
56333
56334
56335 public function apply($text)
56336 {
56337 $setCodes = array();
56338 $unsetCodes = array();
56339
56340 if (null !== $this->foreground) {
56341 $setCodes[] = $this->foreground['set'];
56342 $unsetCodes[] = $this->foreground['unset'];
56343 }
56344 if (null !== $this->background) {
56345 $setCodes[] = $this->background['set'];
56346 $unsetCodes[] = $this->background['unset'];
56347 }
56348 if (\count($this->options)) {
56349 foreach ($this->options as $option) {
56350 $setCodes[] = $option['set'];
56351 $unsetCodes[] = $option['unset'];
56352 }
56353 }
56354
56355 if (0 === \count($setCodes)) {
56356 return $text;
56357 }
56358
56359 return sprintf("\033[%sm%s\033[%sm", implode(';', $setCodes), $text, implode(';', $unsetCodes));
56360 }
56361 }
56362 <?php
56363
56364
56365
56366
56367
56368
56369
56370
56371
56372
56373 namespace Symfony\Component\Console\Formatter;
56374
56375
56376
56377
56378
56379
56380 interface OutputFormatterStyleInterface
56381 {
56382
56383
56384
56385
56386
56387 public function setForeground($color = null);
56388
56389
56390
56391
56392
56393
56394 public function setBackground($color = null);
56395
56396
56397
56398
56399
56400
56401 public function setOption($option);
56402
56403
56404
56405
56406
56407
56408 public function unsetOption($option);
56409
56410
56411
56412
56413 public function setOptions(array $options);
56414
56415
56416
56417
56418
56419
56420
56421
56422 public function apply($text);
56423 }
56424 <?php
56425
56426
56427
56428
56429
56430
56431
56432
56433
56434
56435 namespace Symfony\Component\Console\Formatter;
56436
56437 use Symfony\Component\Console\Exception\InvalidArgumentException;
56438
56439
56440
56441
56442 class OutputFormatterStyleStack
56443 {
56444
56445
56446
56447 private $styles;
56448
56449 private $emptyStyle;
56450
56451 public function __construct(OutputFormatterStyleInterface $emptyStyle = null)
56452 {
56453 $this->emptyStyle = $emptyStyle ?: new OutputFormatterStyle();
56454 $this->reset();
56455 }
56456
56457
56458
56459
56460 public function reset()
56461 {
56462 $this->styles = array();
56463 }
56464
56465
56466
56467
56468 public function push(OutputFormatterStyleInterface $style)
56469 {
56470 $this->styles[] = $style;
56471 }
56472
56473
56474
56475
56476
56477
56478
56479
56480 public function pop(OutputFormatterStyleInterface $style = null)
56481 {
56482 if (empty($this->styles)) {
56483 return $this->emptyStyle;
56484 }
56485
56486 if (null === $style) {
56487 return array_pop($this->styles);
56488 }
56489
56490 foreach (array_reverse($this->styles, true) as $index => $stackedStyle) {
56491 if ($style->apply('') === $stackedStyle->apply('')) {
56492 $this->styles = \array_slice($this->styles, 0, $index);
56493
56494 return $stackedStyle;
56495 }
56496 }
56497
56498 throw new InvalidArgumentException('Incorrectly nested style tag found.');
56499 }
56500
56501
56502
56503
56504
56505
56506 public function getCurrent()
56507 {
56508 if (empty($this->styles)) {
56509 return $this->emptyStyle;
56510 }
56511
56512 return $this->styles[\count($this->styles) - 1];
56513 }
56514
56515
56516
56517
56518 public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle)
56519 {
56520 $this->emptyStyle = $emptyStyle;
56521
56522 return $this;
56523 }
56524
56525
56526
56527
56528 public function getEmptyStyle()
56529 {
56530 return $this->emptyStyle;
56531 }
56532 }
56533 <?php
56534
56535
56536
56537
56538
56539
56540
56541
56542
56543
56544 namespace Symfony\Component\Console\Helper;
56545
56546
56547
56548
56549
56550
56551
56552
56553 class DebugFormatterHelper extends Helper
56554 {
56555 private $colors = array('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default');
56556 private $started = array();
56557 private $count = -1;
56558
56559
56560
56561
56562
56563
56564
56565
56566
56567
56568 public function start($id, $message, $prefix = 'RUN')
56569 {
56570 $this->started[$id] = array('border' => ++$this->count % \count($this->colors));
56571
56572 return sprintf("%s<bg=blue;fg=white> %s </> <fg=blue>%s</>\n", $this->getBorder($id), $prefix, $message);
56573 }
56574
56575
56576
56577
56578
56579
56580
56581
56582
56583
56584
56585
56586 public function progress($id, $buffer, $error = false, $prefix = 'OUT', $errorPrefix = 'ERR')
56587 {
56588 $message = '';
56589
56590 if ($error) {
56591 if (isset($this->started[$id]['out'])) {
56592 $message .= "\n";
56593 unset($this->started[$id]['out']);
56594 }
56595 if (!isset($this->started[$id]['err'])) {
56596 $message .= sprintf('%s<bg=red;fg=white> %s </> ', $this->getBorder($id), $errorPrefix);
56597 $this->started[$id]['err'] = true;
56598 }
56599
56600 $message .= str_replace("\n", sprintf("\n%s<bg=red;fg=white> %s </> ", $this->getBorder($id), $errorPrefix), $buffer);
56601 } else {
56602 if (isset($this->started[$id]['err'])) {
56603 $message .= "\n";
56604 unset($this->started[$id]['err']);
56605 }
56606 if (!isset($this->started[$id]['out'])) {
56607 $message .= sprintf('%s<bg=green;fg=white> %s </> ', $this->getBorder($id), $prefix);
56608 $this->started[$id]['out'] = true;
56609 }
56610
56611 $message .= str_replace("\n", sprintf("\n%s<bg=green;fg=white> %s </> ", $this->getBorder($id), $prefix), $buffer);
56612 }
56613
56614 return $message;
56615 }
56616
56617
56618
56619
56620
56621
56622
56623
56624
56625
56626
56627 public function stop($id, $message, $successful, $prefix = 'RES')
56628 {
56629 $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : '';
56630
56631 if ($successful) {
56632 return sprintf("%s%s<bg=green;fg=white> %s </> <fg=green>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
56633 }
56634
56635 $message = sprintf("%s%s<bg=red;fg=white> %s </> <fg=red>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
56636
56637 unset($this->started[$id]['out'], $this->started[$id]['err']);
56638
56639 return $message;
56640 }
56641
56642
56643
56644
56645
56646
56647 private function getBorder($id)
56648 {
56649 return sprintf('<bg=%s> </>', $this->colors[$this->started[$id]['border']]);
56650 }
56651
56652
56653
56654
56655 public function getName()
56656 {
56657 return 'debug_formatter';
56658 }
56659 }
56660 <?php
56661
56662
56663
56664
56665
56666
56667
56668
56669
56670
56671 namespace Symfony\Component\Console\Helper;
56672
56673 use Symfony\Component\Console\Descriptor\DescriptorInterface;
56674 use Symfony\Component\Console\Descriptor\JsonDescriptor;
56675 use Symfony\Component\Console\Descriptor\MarkdownDescriptor;
56676 use Symfony\Component\Console\Descriptor\TextDescriptor;
56677 use Symfony\Component\Console\Descriptor\XmlDescriptor;
56678 use Symfony\Component\Console\Exception\InvalidArgumentException;
56679 use Symfony\Component\Console\Output\OutputInterface;
56680
56681
56682
56683
56684
56685
56686 class DescriptorHelper extends Helper
56687 {
56688
56689
56690
56691 private $descriptors = array();
56692
56693 public function __construct()
56694 {
56695 $this
56696 ->register('txt', new TextDescriptor())
56697 ->register('xml', new XmlDescriptor())
56698 ->register('json', new JsonDescriptor())
56699 ->register('md', new MarkdownDescriptor())
56700 ;
56701 }
56702
56703
56704
56705
56706
56707
56708
56709
56710
56711
56712
56713
56714
56715
56716 public function describe(OutputInterface $output, $object, array $options = array())
56717 {
56718 $options = array_merge(array(
56719 'raw_text' => false,
56720 'format' => 'txt',
56721 ), $options);
56722
56723 if (!isset($this->descriptors[$options['format']])) {
56724 throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $options['format']));
56725 }
56726
56727 $descriptor = $this->descriptors[$options['format']];
56728 $descriptor->describe($output, $object, $options);
56729 }
56730
56731
56732
56733
56734
56735
56736
56737
56738
56739 public function register($format, DescriptorInterface $descriptor)
56740 {
56741 $this->descriptors[$format] = $descriptor;
56742
56743 return $this;
56744 }
56745
56746
56747
56748
56749 public function getName()
56750 {
56751 return 'descriptor';
56752 }
56753 }
56754 <?php
56755
56756
56757
56758
56759
56760
56761
56762
56763
56764
56765 namespace Symfony\Component\Console\Helper;
56766
56767 use Symfony\Component\Console\Exception\InvalidArgumentException;
56768 use Symfony\Component\Console\Exception\RuntimeException;
56769 use Symfony\Component\Console\Formatter\OutputFormatterStyle;
56770 use Symfony\Component\Console\Output\ConsoleOutputInterface;
56771 use Symfony\Component\Console\Output\OutputInterface;
56772
56773
56774
56775
56776
56777
56778
56779
56780
56781 class DialogHelper extends InputAwareHelper
56782 {
56783 private $inputStream;
56784 private static $shell;
56785 private static $stty;
56786
56787 public function __construct($triggerDeprecationError = true)
56788 {
56789 if ($triggerDeprecationError) {
56790 @trigger_error('"Symfony\Component\Console\Helper\DialogHelper" is deprecated since Symfony 2.5 and will be removed in 3.0. Use "Symfony\Component\Console\Helper\QuestionHelper" instead.', E_USER_DEPRECATED);
56791 }
56792 }
56793
56794
56795
56796
56797
56798
56799
56800
56801
56802
56803
56804
56805
56806
56807
56808
56809 public function select(OutputInterface $output, $question, $choices, $default = null, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false)
56810 {
56811 if ($output instanceof ConsoleOutputInterface) {
56812 $output = $output->getErrorOutput();
56813 }
56814
56815 $width = max(array_map('strlen', array_keys($choices)));
56816
56817 $messages = (array) $question;
56818 foreach ($choices as $key => $value) {
56819 $messages[] = sprintf("  [<info>%-{$width}s</info>] %s", $key, $value);
56820 }
56821
56822 $output->writeln($messages);
56823
56824 $result = $this->askAndValidate($output, '> ', function ($picked) use ($choices, $errorMessage, $multiselect) {
56825
56826 $selectedChoices = str_replace(' ', '', $picked);
56827
56828 if ($multiselect) {
56829
56830 if (!preg_match('/^[a-zA-Z0-9_-]+(?:,[a-zA-Z0-9_-]+)*$/', $selectedChoices, $matches)) {
56831 throw new InvalidArgumentException(sprintf($errorMessage, $picked));
56832 }
56833 $selectedChoices = explode(',', $selectedChoices);
56834 } else {
56835 $selectedChoices = array($picked);
56836 }
56837
56838 $multiselectChoices = array();
56839
56840 foreach ($selectedChoices as $value) {
56841 if (empty($choices[$value])) {
56842 throw new InvalidArgumentException(sprintf($errorMessage, $value));
56843 }
56844 $multiselectChoices[] = $value;
56845 }
56846
56847 if ($multiselect) {
56848 return $multiselectChoices;
56849 }
56850
56851 return $picked;
56852 }, $attempts, $default);
56853
56854 return $result;
56855 }
56856
56857
56858
56859
56860
56861
56862
56863
56864
56865
56866
56867
56868
56869 public function ask(OutputInterface $output, $question, $default = null, array $autocomplete = null)
56870 {
56871 if ($this->input && !$this->input->isInteractive()) {
56872 return $default;
56873 }
56874
56875 if ($output instanceof ConsoleOutputInterface) {
56876 $output = $output->getErrorOutput();
56877 }
56878
56879 $output->write($question);
56880
56881 $inputStream = $this->inputStream ?: STDIN;
56882
56883 if (null === $autocomplete || !$this->hasSttyAvailable()) {
56884 $ret = fgets($inputStream, 4096);
56885 if (false === $ret) {
56886 throw new RuntimeException('Aborted');
56887 }
56888 $ret = trim($ret);
56889 } else {
56890 $ret = '';
56891
56892 $i = 0;
56893 $ofs = -1;
56894 $matches = $autocomplete;
56895 $numMatches = \count($matches);
56896
56897 $sttyMode = shell_exec('stty -g');
56898
56899
56900 shell_exec('stty -icanon -echo');
56901
56902
56903 $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white'));
56904
56905
56906 while (!feof($inputStream)) {
56907 $c = fread($inputStream, 1);
56908
56909
56910 if ("\177" === $c) {
56911 if (0 === $numMatches && 0 !== $i) {
56912 --$i;
56913
56914 $output->write("\033[1D");
56915 }
56916
56917 if (0 === $i) {
56918 $ofs = -1;
56919 $matches = $autocomplete;
56920 $numMatches = \count($matches);
56921 } else {
56922 $numMatches = 0;
56923 }
56924
56925
56926 $ret = substr($ret, 0, $i);
56927 } elseif ("\033" === $c) {
56928
56929 $c .= fread($inputStream, 2);
56930
56931
56932 if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) {
56933 if ('A' === $c[2] && -1 === $ofs) {
56934 $ofs = 0;
56935 }
56936
56937 if (0 === $numMatches) {
56938 continue;
56939 }
56940
56941 $ofs += ('A' === $c[2]) ? -1 : 1;
56942 $ofs = ($numMatches + $ofs) % $numMatches;
56943 }
56944 } elseif (\ord($c) < 32) {
56945 if ("\t" === $c || "\n" === $c) {
56946 if ($numMatches > 0 && -1 !== $ofs) {
56947 $ret = $matches[$ofs];
56948
56949 $output->write(substr($ret, $i));
56950 $i = \strlen($ret);
56951 }
56952
56953 if ("\n" === $c) {
56954 $output->write($c);
56955 break;
56956 }
56957
56958 $numMatches = 0;
56959 }
56960
56961 continue;
56962 } else {
56963 $output->write($c);
56964 $ret .= $c;
56965 ++$i;
56966
56967 $numMatches = 0;
56968 $ofs = 0;
56969
56970 foreach ($autocomplete as $value) {
56971
56972 if (0 === strpos($value, $ret) && $i !== \strlen($value)) {
56973 $matches[$numMatches++] = $value;
56974 }
56975 }
56976 }
56977
56978
56979 $output->write("\033[K");
56980
56981 if ($numMatches > 0 && -1 !== $ofs) {
56982
56983 $output->write("\0337");
56984
56985 $output->write('<hl>'.substr($matches[$ofs], $i).'</hl>');
56986
56987 $output->write("\0338");
56988 }
56989 }
56990
56991
56992 shell_exec(sprintf('stty %s', $sttyMode));
56993 }
56994
56995 return \strlen($ret) > 0 ? $ret : $default;
56996 }
56997
56998
56999
57000
57001
57002
57003
57004
57005
57006
57007
57008
57009 public function askConfirmation(OutputInterface $output, $question, $default = true)
57010 {
57011 $answer = 'z';
57012 while ($answer && !\in_array(strtolower($answer[0]), array('y', 'n'))) {
57013 $answer = $this->ask($output, $question);
57014 }
57015
57016 if (false === $default) {
57017 return $answer && 'y' == strtolower($answer[0]);
57018 }
57019
57020 return !$answer || 'y' == strtolower($answer[0]);
57021 }
57022
57023
57024
57025
57026
57027
57028
57029
57030
57031
57032
57033
57034 public function askHiddenResponse(OutputInterface $output, $question, $fallback = true)
57035 {
57036 if ($output instanceof ConsoleOutputInterface) {
57037 $output = $output->getErrorOutput();
57038 }
57039
57040 if ('\\' === \DIRECTORY_SEPARATOR) {
57041 $exe = __DIR__.'/../Resources/bin/hiddeninput.exe';
57042
57043
57044 if ('phar:' === substr(__FILE__, 0, 5)) {
57045 $tmpExe = sys_get_temp_dir().'/hiddeninput.exe';
57046 copy($exe, $tmpExe);
57047 $exe = $tmpExe;
57048 }
57049
57050 $output->write($question);
57051 $value = rtrim(shell_exec($exe));
57052 $output->writeln('');
57053
57054 if (isset($tmpExe)) {
57055 unlink($tmpExe);
57056 }
57057
57058 return $value;
57059 }
57060
57061 if ($this->hasSttyAvailable()) {
57062 $output->write($question);
57063
57064 $sttyMode = shell_exec('stty -g');
57065
57066 shell_exec('stty -echo');
57067 $value = fgets($this->inputStream ?: STDIN, 4096);
57068 shell_exec(sprintf('stty %s', $sttyMode));
57069
57070 if (false === $value) {
57071 throw new RuntimeException('Aborted');
57072 }
57073
57074 $value = trim($value);
57075 $output->writeln('');
57076
57077 return $value;
57078 }
57079
57080 if (false !== $shell = $this->getShell()) {
57081 $output->write($question);
57082 $readCmd = 'csh' === $shell ? 'set mypassword = $<' : 'read -r mypassword';
57083 $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd);
57084 $value = rtrim(shell_exec($command));
57085 $output->writeln('');
57086
57087 return $value;
57088 }
57089
57090 if ($fallback) {
57091 return $this->ask($output, $question);
57092 }
57093
57094 throw new RuntimeException('Unable to hide the response');
57095 }
57096
57097
57098
57099
57100
57101
57102
57103
57104
57105
57106
57107
57108
57109
57110
57111
57112
57113
57114
57115 public function askAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $default = null, array $autocomplete = null)
57116 {
57117 $that = $this;
57118
57119 $interviewer = function () use ($output, $question, $default, $autocomplete, $that) {
57120 return $that->ask($output, $question, $default, $autocomplete);
57121 };
57122
57123 return $this->validateAttempts($interviewer, $output, $validator, $attempts);
57124 }
57125
57126
57127
57128
57129
57130
57131
57132
57133
57134
57135
57136
57137
57138
57139
57140
57141
57142
57143
57144 public function askHiddenResponseAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $fallback = true)
57145 {
57146 $that = $this;
57147
57148 $interviewer = function () use ($output, $question, $fallback, $that) {
57149 return $that->askHiddenResponse($output, $question, $fallback);
57150 };
57151
57152 return $this->validateAttempts($interviewer, $output, $validator, $attempts);
57153 }
57154
57155
57156
57157
57158
57159
57160
57161
57162 public function setInputStream($stream)
57163 {
57164 $this->inputStream = $stream;
57165 }
57166
57167
57168
57169
57170
57171
57172 public function getInputStream()
57173 {
57174 return $this->inputStream;
57175 }
57176
57177
57178
57179
57180 public function getName()
57181 {
57182 return 'dialog';
57183 }
57184
57185
57186
57187
57188
57189
57190 private function getShell()
57191 {
57192 if (null !== self::$shell) {
57193 return self::$shell;
57194 }
57195
57196 self::$shell = false;
57197
57198 if (file_exists('/usr/bin/env')) {
57199
57200 $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null";
57201 foreach (array('bash', 'zsh', 'ksh', 'csh') as $sh) {
57202 if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) {
57203 self::$shell = $sh;
57204 break;
57205 }
57206 }
57207 }
57208
57209 return self::$shell;
57210 }
57211
57212 private function hasSttyAvailable()
57213 {
57214 if (null !== self::$stty) {
57215 return self::$stty;
57216 }
57217
57218 exec('stty 2>&1', $output, $exitcode);
57219
57220 return self::$stty = 0 === $exitcode;
57221 }
57222
57223
57224
57225
57226
57227
57228
57229
57230
57231
57232
57233
57234
57235 private function validateAttempts($interviewer, OutputInterface $output, $validator, $attempts)
57236 {
57237 if ($output instanceof ConsoleOutputInterface) {
57238 $output = $output->getErrorOutput();
57239 }
57240
57241 $e = null;
57242 while (false === $attempts || $attempts--) {
57243 if (null !== $e) {
57244 $output->writeln($this->getHelperSet()->get('formatter')->formatBlock($e->getMessage(), 'error'));
57245 }
57246
57247 try {
57248 return \call_user_func($validator, $interviewer());
57249 } catch (\Exception $e) {
57250 }
57251 }
57252
57253 throw $e;
57254 }
57255 }
57256 <?php
57257
57258
57259
57260
57261
57262
57263
57264
57265
57266
57267 namespace Symfony\Component\Console\Helper;
57268
57269 use Symfony\Component\Console\Formatter\OutputFormatter;
57270
57271
57272
57273
57274
57275
57276 class FormatterHelper extends Helper
57277 {
57278
57279
57280
57281
57282
57283
57284
57285
57286
57287 public function formatSection($section, $message, $style = 'info')
57288 {
57289 return sprintf('<%s>[%s]</%s> %s', $style, $section, $style, $message);
57290 }
57291
57292
57293
57294
57295
57296
57297
57298
57299
57300
57301 public function formatBlock($messages, $style, $large = false)
57302 {
57303 if (!\is_array($messages)) {
57304 $messages = array($messages);
57305 }
57306
57307 $len = 0;
57308 $lines = array();
57309 foreach ($messages as $message) {
57310 $message = OutputFormatter::escape($message);
57311 $lines[] = sprintf($large ? '  %s  ' : ' %s ', $message);
57312 $len = max($this->strlen($message) + ($large ? 4 : 2), $len);
57313 }
57314
57315 $messages = $large ? array(str_repeat(' ', $len)) : array();
57316 for ($i = 0; isset($lines[$i]); ++$i) {
57317 $messages[] = $lines[$i].str_repeat(' ', $len - $this->strlen($lines[$i]));
57318 }
57319 if ($large) {
57320 $messages[] = str_repeat(' ', $len);
57321 }
57322
57323 for ($i = 0; isset($messages[$i]); ++$i) {
57324 $messages[$i] = sprintf('<%s>%s</%s>', $style, $messages[$i], $style);
57325 }
57326
57327 return implode("\n", $messages);
57328 }
57329
57330
57331
57332
57333 public function getName()
57334 {
57335 return 'formatter';
57336 }
57337 }
57338 <?php
57339
57340
57341
57342
57343
57344
57345
57346
57347
57348
57349 namespace Symfony\Component\Console\Helper;
57350
57351 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
57352
57353
57354
57355
57356
57357
57358 abstract class Helper implements HelperInterface
57359 {
57360 protected $helperSet = null;
57361
57362
57363
57364
57365 public function setHelperSet(HelperSet $helperSet = null)
57366 {
57367 $this->helperSet = $helperSet;
57368 }
57369
57370
57371
57372
57373 public function getHelperSet()
57374 {
57375 return $this->helperSet;
57376 }
57377
57378
57379
57380
57381
57382
57383
57384
57385 public static function strlen($string)
57386 {
57387 if (false === $encoding = mb_detect_encoding($string, null, true)) {
57388 return \strlen($string);
57389 }
57390
57391 return mb_strwidth($string, $encoding);
57392 }
57393
57394 public static function formatTime($secs)
57395 {
57396 static $timeFormats = array(
57397 array(0, '< 1 sec'),
57398 array(1, '1 sec'),
57399 array(2, 'secs', 1),
57400 array(60, '1 min'),
57401 array(120, 'mins', 60),
57402 array(3600, '1 hr'),
57403 array(7200, 'hrs', 3600),
57404 array(86400, '1 day'),
57405 array(172800, 'days', 86400),
57406 );
57407
57408 foreach ($timeFormats as $index => $format) {
57409 if ($secs >= $format[0]) {
57410 if ((isset($timeFormats[$index + 1]) && $secs < $timeFormats[$index + 1][0])
57411 || $index == \count($timeFormats) - 1
57412 ) {
57413 if (2 == \count($format)) {
57414 return $format[1];
57415 }
57416
57417 return floor($secs / $format[2]).' '.$format[1];
57418 }
57419 }
57420 }
57421 }
57422
57423 public static function formatMemory($memory)
57424 {
57425 if ($memory >= 1024 * 1024 * 1024) {
57426 return sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024);
57427 }
57428
57429 if ($memory >= 1024 * 1024) {
57430 return sprintf('%.1f MiB', $memory / 1024 / 1024);
57431 }
57432
57433 if ($memory >= 1024) {
57434 return sprintf('%d KiB', $memory / 1024);
57435 }
57436
57437 return sprintf('%d B', $memory);
57438 }
57439
57440 public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, $string)
57441 {
57442 return self::strlen(self::removeDecoration($formatter, $string));
57443 }
57444
57445 public static function removeDecoration(OutputFormatterInterface $formatter, $string)
57446 {
57447 $isDecorated = $formatter->isDecorated();
57448 $formatter->setDecorated(false);
57449
57450 $string = $formatter->format($string);
57451
57452 $string = preg_replace("/\033\[[^m]*m/", '', $string);
57453 $formatter->setDecorated($isDecorated);
57454
57455 return $string;
57456 }
57457 }
57458 <?php
57459
57460
57461
57462
57463
57464
57465
57466
57467
57468
57469 namespace Symfony\Component\Console\Helper;
57470
57471
57472
57473
57474
57475
57476 interface HelperInterface
57477 {
57478
57479
57480
57481 public function setHelperSet(HelperSet $helperSet = null);
57482
57483
57484
57485
57486
57487
57488 public function getHelperSet();
57489
57490
57491
57492
57493
57494
57495 public function getName();
57496 }
57497 <?php
57498
57499
57500
57501
57502
57503
57504
57505
57506
57507
57508 namespace Symfony\Component\Console\Helper;
57509
57510 use Symfony\Component\Console\Command\Command;
57511 use Symfony\Component\Console\Exception\InvalidArgumentException;
57512
57513
57514
57515
57516
57517
57518 class HelperSet implements \IteratorAggregate
57519 {
57520
57521
57522
57523 private $helpers = array();
57524 private $command;
57525
57526
57527
57528
57529 public function __construct(array $helpers = array())
57530 {
57531 foreach ($helpers as $alias => $helper) {
57532 $this->set($helper, \is_int($alias) ? null : $alias);
57533 }
57534 }
57535
57536
57537
57538
57539
57540
57541
57542 public function set(HelperInterface $helper, $alias = null)
57543 {
57544 $this->helpers[$helper->getName()] = $helper;
57545 if (null !== $alias) {
57546 $this->helpers[$alias] = $helper;
57547 }
57548
57549 $helper->setHelperSet($this);
57550 }
57551
57552
57553
57554
57555
57556
57557
57558
57559 public function has($name)
57560 {
57561 return isset($this->helpers[$name]);
57562 }
57563
57564
57565
57566
57567
57568
57569
57570
57571
57572
57573 public function get($name)
57574 {
57575 if (!$this->has($name)) {
57576 throw new InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name));
57577 }
57578
57579 if ('dialog' === $name && $this->helpers[$name] instanceof DialogHelper) {
57580 @trigger_error('"Symfony\Component\Console\Helper\DialogHelper" is deprecated since Symfony 2.5 and will be removed in 3.0. Use "Symfony\Component\Console\Helper\QuestionHelper" instead.', E_USER_DEPRECATED);
57581 } elseif ('progress' === $name && $this->helpers[$name] instanceof ProgressHelper) {
57582 @trigger_error('"Symfony\Component\Console\Helper\ProgressHelper" is deprecated since Symfony 2.5 and will be removed in 3.0. Use "Symfony\Component\Console\Helper\ProgressBar" instead.', E_USER_DEPRECATED);
57583 } elseif ('table' === $name && $this->helpers[$name] instanceof TableHelper) {
57584 @trigger_error('"Symfony\Component\Console\Helper\TableHelper" is deprecated since Symfony 2.5 and will be removed in 3.0. Use "Symfony\Component\Console\Helper\Table" instead.', E_USER_DEPRECATED);
57585 }
57586
57587 return $this->helpers[$name];
57588 }
57589
57590 public function setCommand(Command $command = null)
57591 {
57592 $this->command = $command;
57593 }
57594
57595
57596
57597
57598
57599
57600 public function getCommand()
57601 {
57602 return $this->command;
57603 }
57604
57605
57606
57607
57608 public function getIterator()
57609 {
57610 return new \ArrayIterator($this->helpers);
57611 }
57612 }
57613 <?php
57614
57615
57616
57617
57618
57619
57620
57621
57622
57623
57624 namespace Symfony\Component\Console\Helper;
57625
57626 use Symfony\Component\Console\Input\InputAwareInterface;
57627 use Symfony\Component\Console\Input\InputInterface;
57628
57629
57630
57631
57632
57633
57634 abstract class InputAwareHelper extends Helper implements InputAwareInterface
57635 {
57636 protected $input;
57637
57638
57639
57640
57641 public function setInput(InputInterface $input)
57642 {
57643 $this->input = $input;
57644 }
57645 }
57646 <?php
57647
57648
57649
57650
57651
57652
57653
57654
57655
57656
57657 namespace Symfony\Component\Console\Helper;
57658
57659 use Symfony\Component\Console\Output\ConsoleOutputInterface;
57660 use Symfony\Component\Console\Output\OutputInterface;
57661 use Symfony\Component\Process\Exception\ProcessFailedException;
57662 use Symfony\Component\Process\Process;
57663 use Symfony\Component\Process\ProcessBuilder;
57664
57665
57666
57667
57668
57669
57670 class ProcessHelper extends Helper
57671 {
57672
57673
57674
57675
57676
57677
57678
57679
57680
57681
57682
57683
57684 public function run(OutputInterface $output, $cmd, $error = null, $callback = null, $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE)
57685 {
57686 if ($output instanceof ConsoleOutputInterface) {
57687 $output = $output->getErrorOutput();
57688 }
57689
57690 $formatter = $this->getHelperSet()->get('debug_formatter');
57691
57692 if (\is_array($cmd)) {
57693 $process = ProcessBuilder::create($cmd)->getProcess();
57694 } elseif ($cmd instanceof Process) {
57695 $process = $cmd;
57696 } else {
57697 $process = new Process($cmd);
57698 }
57699
57700 if ($verbosity <= $output->getVerbosity()) {
57701 $output->write($formatter->start(spl_object_hash($process), $this->escapeString($process->getCommandLine())));
57702 }
57703
57704 if ($output->isDebug()) {
57705 $callback = $this->wrapCallback($output, $process, $callback);
57706 }
57707
57708 $process->run($callback);
57709
57710 if ($verbosity <= $output->getVerbosity()) {
57711 $message = $process->isSuccessful() ? 'Command ran successfully' : sprintf('%s Command did not run successfully', $process->getExitCode());
57712 $output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful()));
57713 }
57714
57715 if (!$process->isSuccessful() && null !== $error) {
57716 $output->writeln(sprintf('<error>%s</error>', $this->escapeString($error)));
57717 }
57718
57719 return $process;
57720 }
57721
57722
57723
57724
57725
57726
57727
57728
57729
57730
57731
57732
57733
57734
57735
57736
57737
57738
57739
57740 public function mustRun(OutputInterface $output, $cmd, $error = null, $callback = null)
57741 {
57742 $process = $this->run($output, $cmd, $error, $callback);
57743
57744 if (!$process->isSuccessful()) {
57745 throw new ProcessFailedException($process);
57746 }
57747
57748 return $process;
57749 }
57750
57751
57752
57753
57754
57755
57756
57757
57758
57759
57760 public function wrapCallback(OutputInterface $output, Process $process, $callback = null)
57761 {
57762 if ($output instanceof ConsoleOutputInterface) {
57763 $output = $output->getErrorOutput();
57764 }
57765
57766 $formatter = $this->getHelperSet()->get('debug_formatter');
57767
57768 $that = $this;
57769
57770 return function ($type, $buffer) use ($output, $process, $callback, $formatter, $that) {
57771 $output->write($formatter->progress(spl_object_hash($process), $that->escapeString($buffer), Process::ERR === $type));
57772
57773 if (null !== $callback) {
57774 \call_user_func($callback, $type, $buffer);
57775 }
57776 };
57777 }
57778
57779
57780
57781
57782
57783
57784 public function escapeString($str)
57785 {
57786 return str_replace('<', '\\<', $str);
57787 }
57788
57789
57790
57791
57792 public function getName()
57793 {
57794 return 'process';
57795 }
57796 }
57797 <?php
57798
57799
57800
57801
57802
57803
57804
57805
57806
57807
57808 namespace Symfony\Component\Console\Helper;
57809
57810 use Symfony\Component\Console\Exception\LogicException;
57811 use Symfony\Component\Console\Output\ConsoleOutputInterface;
57812 use Symfony\Component\Console\Output\OutputInterface;
57813
57814
57815
57816
57817
57818
57819
57820 class ProgressBar
57821 {
57822 private $barWidth = 28;
57823 private $barChar;
57824 private $emptyBarChar = '-';
57825 private $progressChar = '>';
57826 private $format;
57827 private $internalFormat;
57828 private $redrawFreq = 1;
57829 private $output;
57830 private $step = 0;
57831 private $max;
57832 private $startTime;
57833 private $stepWidth;
57834 private $percent = 0.0;
57835 private $formatLineCount;
57836 private $messages = array();
57837 private $overwrite = true;
57838 private $firstRun = true;
57839
57840 private static $formatters;
57841 private static $formats;
57842
57843
57844
57845
57846
57847 public function __construct(OutputInterface $output, $max = 0)
57848 {
57849 if ($output instanceof ConsoleOutputInterface) {
57850 $output = $output->getErrorOutput();
57851 }
57852
57853 $this->output = $output;
57854 $this->setMaxSteps($max);
57855
57856 if (!$this->output->isDecorated()) {
57857
57858 $this->overwrite = false;
57859
57860
57861 $this->setRedrawFrequency($max / 10);
57862 }
57863
57864 $this->startTime = time();
57865 }
57866
57867
57868
57869
57870
57871
57872
57873
57874
57875 public static function setPlaceholderFormatterDefinition($name, $callable)
57876 {
57877 if (!self::$formatters) {
57878 self::$formatters = self::initPlaceholderFormatters();
57879 }
57880
57881 self::$formatters[$name] = $callable;
57882 }
57883
57884
57885
57886
57887
57888
57889
57890
57891 public static function getPlaceholderFormatterDefinition($name)
57892 {
57893 if (!self::$formatters) {
57894 self::$formatters = self::initPlaceholderFormatters();
57895 }
57896
57897 return isset(self::$formatters[$name]) ? self::$formatters[$name] : null;
57898 }
57899
57900
57901
57902
57903
57904
57905
57906
57907
57908 public static function setFormatDefinition($name, $format)
57909 {
57910 if (!self::$formats) {
57911 self::$formats = self::initFormats();
57912 }
57913
57914 self::$formats[$name] = $format;
57915 }
57916
57917
57918
57919
57920
57921
57922
57923
57924 public static function getFormatDefinition($name)
57925 {
57926 if (!self::$formats) {
57927 self::$formats = self::initFormats();
57928 }
57929
57930 return isset(self::$formats[$name]) ? self::$formats[$name] : null;
57931 }
57932
57933
57934
57935
57936
57937
57938
57939
57940
57941
57942
57943 public function setMessage($message, $name = 'message')
57944 {
57945 $this->messages[$name] = $message;
57946 }
57947
57948 public function getMessage($name = 'message')
57949 {
57950 return $this->messages[$name];
57951 }
57952
57953
57954
57955
57956
57957
57958 public function getStartTime()
57959 {
57960 return $this->startTime;
57961 }
57962
57963
57964
57965
57966
57967
57968 public function getMaxSteps()
57969 {
57970 return $this->max;
57971 }
57972
57973
57974
57975
57976
57977
57978
57979
57980 public function getStep()
57981 {
57982 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.6 and will be removed in 3.0. Use the getProgress() method instead.', E_USER_DEPRECATED);
57983
57984 return $this->getProgress();
57985 }
57986
57987
57988
57989
57990
57991
57992 public function getProgress()
57993 {
57994 return $this->step;
57995 }
57996
57997
57998
57999
58000
58001
58002
58003
58004 public function getStepWidth()
58005 {
58006 return $this->stepWidth;
58007 }
58008
58009
58010
58011
58012
58013
58014 public function getProgressPercent()
58015 {
58016 return $this->percent;
58017 }
58018
58019
58020
58021
58022
58023
58024 public function setBarWidth($size)
58025 {
58026 $this->barWidth = (int) $size;
58027 }
58028
58029
58030
58031
58032
58033
58034 public function getBarWidth()
58035 {
58036 return $this->barWidth;
58037 }
58038
58039
58040
58041
58042
58043
58044 public function setBarCharacter($char)
58045 {
58046 $this->barChar = $char;
58047 }
58048
58049
58050
58051
58052
58053
58054 public function getBarCharacter()
58055 {
58056 if (null === $this->barChar) {
58057 return $this->max ? '=' : $this->emptyBarChar;
58058 }
58059
58060 return $this->barChar;
58061 }
58062
58063
58064
58065
58066
58067
58068 public function setEmptyBarCharacter($char)
58069 {
58070 $this->emptyBarChar = $char;
58071 }
58072
58073
58074
58075
58076
58077
58078 public function getEmptyBarCharacter()
58079 {
58080 return $this->emptyBarChar;
58081 }
58082
58083
58084
58085
58086
58087
58088 public function setProgressCharacter($char)
58089 {
58090 $this->progressChar = $char;
58091 }
58092
58093
58094
58095
58096
58097
58098 public function getProgressCharacter()
58099 {
58100 return $this->progressChar;
58101 }
58102
58103
58104
58105
58106
58107
58108 public function setFormat($format)
58109 {
58110 $this->format = null;
58111 $this->internalFormat = $format;
58112 }
58113
58114
58115
58116
58117
58118
58119 public function setRedrawFrequency($freq)
58120 {
58121 $this->redrawFreq = max((int) $freq, 1);
58122 }
58123
58124
58125
58126
58127
58128
58129 public function start($max = null)
58130 {
58131 $this->startTime = time();
58132 $this->step = 0;
58133 $this->percent = 0.0;
58134
58135 if (null !== $max) {
58136 $this->setMaxSteps($max);
58137 }
58138
58139 $this->display();
58140 }
58141
58142
58143
58144
58145
58146
58147
58148
58149 public function advance($step = 1)
58150 {
58151 $this->setProgress($this->step + $step);
58152 }
58153
58154
58155
58156
58157
58158
58159
58160
58161
58162
58163 public function setCurrent($step)
58164 {
58165 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.6 and will be removed in 3.0. Use the setProgress() method instead.', E_USER_DEPRECATED);
58166
58167 $this->setProgress($step);
58168 }
58169
58170
58171
58172
58173
58174
58175 public function setOverwrite($overwrite)
58176 {
58177 $this->overwrite = (bool) $overwrite;
58178 }
58179
58180
58181
58182
58183
58184
58185
58186
58187 public function setProgress($step)
58188 {
58189 $step = (int) $step;
58190 if ($step < $this->step) {
58191 throw new LogicException('You can\'t regress the progress bar.');
58192 }
58193
58194 if ($this->max && $step > $this->max) {
58195 $this->max = $step;
58196 }
58197
58198 $prevPeriod = (int) ($this->step / $this->redrawFreq);
58199 $currPeriod = (int) ($step / $this->redrawFreq);
58200 $this->step = $step;
58201 $this->percent = $this->max ? (float) $this->step / $this->max : 0;
58202 if ($prevPeriod !== $currPeriod || $this->max === $step) {
58203 $this->display();
58204 }
58205 }
58206
58207
58208
58209
58210 public function finish()
58211 {
58212 if (!$this->max) {
58213 $this->max = $this->step;
58214 }
58215
58216 if ($this->step === $this->max && !$this->overwrite) {
58217
58218 return;
58219 }
58220
58221 $this->setProgress($this->max);
58222 }
58223
58224
58225
58226
58227 public function display()
58228 {
58229 if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
58230 return;
58231 }
58232
58233 if (null === $this->format) {
58234 $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
58235 }
58236
58237
58238 $self = $this;
58239 $output = $this->output;
58240 $messages = $this->messages;
58241 $this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) use ($self, $output, $messages) {
58242 if ($formatter = $self::getPlaceholderFormatterDefinition($matches[1])) {
58243 $text = \call_user_func($formatter, $self, $output);
58244 } elseif (isset($messages[$matches[1]])) {
58245 $text = $messages[$matches[1]];
58246 } else {
58247 return $matches[0];
58248 }
58249
58250 if (isset($matches[2])) {
58251 $text = sprintf('%'.$matches[2], $text);
58252 }
58253
58254 return $text;
58255 }, $this->format));
58256 }
58257
58258
58259
58260
58261
58262
58263
58264
58265 public function clear()
58266 {
58267 if (!$this->overwrite) {
58268 return;
58269 }
58270
58271 if (null === $this->format) {
58272 $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
58273 }
58274
58275 $this->overwrite('');
58276 }
58277
58278
58279
58280
58281
58282
58283 private function setRealFormat($format)
58284 {
58285
58286 if (!$this->max && null !== self::getFormatDefinition($format.'_nomax')) {
58287 $this->format = self::getFormatDefinition($format.'_nomax');
58288 } elseif (null !== self::getFormatDefinition($format)) {
58289 $this->format = self::getFormatDefinition($format);
58290 } else {
58291 $this->format = $format;
58292 }
58293
58294 $this->formatLineCount = substr_count($this->format, "\n");
58295 }
58296
58297
58298
58299
58300
58301
58302 private function setMaxSteps($max)
58303 {
58304 $this->max = max(0, (int) $max);
58305 $this->stepWidth = $this->max ? Helper::strlen($this->max) : 4;
58306 }
58307
58308
58309
58310
58311
58312
58313 private function overwrite($message)
58314 {
58315 if ($this->overwrite) {
58316 if (!$this->firstRun) {
58317
58318 $this->output->write("\x0D");
58319
58320
58321 $this->output->write("\x1B[2K");
58322
58323
58324 if ($this->formatLineCount > 0) {
58325 $this->output->write(str_repeat("\x1B[1A\x1B[2K", $this->formatLineCount));
58326 }
58327 }
58328 } elseif ($this->step > 0) {
58329 $this->output->writeln('');
58330 }
58331
58332 $this->firstRun = false;
58333
58334 $this->output->write($message);
58335 }
58336
58337 private function determineBestFormat()
58338 {
58339 switch ($this->output->getVerbosity()) {
58340
58341 case OutputInterface::VERBOSITY_VERBOSE:
58342 return $this->max ? 'verbose' : 'verbose_nomax';
58343 case OutputInterface::VERBOSITY_VERY_VERBOSE:
58344 return $this->max ? 'very_verbose' : 'very_verbose_nomax';
58345 case OutputInterface::VERBOSITY_DEBUG:
58346 return $this->max ? 'debug' : 'debug_nomax';
58347 default:
58348 return $this->max ? 'normal' : 'normal_nomax';
58349 }
58350 }
58351
58352 private static function initPlaceholderFormatters()
58353 {
58354 return array(
58355 'bar' => function (ProgressBar $bar, OutputInterface $output) {
58356 $completeBars = floor($bar->getMaxSteps() > 0 ? $bar->getProgressPercent() * $bar->getBarWidth() : $bar->getProgress() % $bar->getBarWidth());
58357 $display = str_repeat($bar->getBarCharacter(), $completeBars);
58358 if ($completeBars < $bar->getBarWidth()) {
58359 $emptyBars = $bar->getBarWidth() - $completeBars - Helper::strlenWithoutDecoration($output->getFormatter(), $bar->getProgressCharacter());
58360 $display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars);
58361 }
58362
58363 return $display;
58364 },
58365 'elapsed' => function (ProgressBar $bar) {
58366 return Helper::formatTime(time() - $bar->getStartTime());
58367 },
58368 'remaining' => function (ProgressBar $bar) {
58369 if (!$bar->getMaxSteps()) {
58370 throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.');
58371 }
58372
58373 if (!$bar->getProgress()) {
58374 $remaining = 0;
58375 } else {
58376 $remaining = round((time() - $bar->getStartTime()) / $bar->getProgress() * ($bar->getMaxSteps() - $bar->getProgress()));
58377 }
58378
58379 return Helper::formatTime($remaining);
58380 },
58381 'estimated' => function (ProgressBar $bar) {
58382 if (!$bar->getMaxSteps()) {
58383 throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.');
58384 }
58385
58386 if (!$bar->getProgress()) {
58387 $estimated = 0;
58388 } else {
58389 $estimated = round((time() - $bar->getStartTime()) / $bar->getProgress() * $bar->getMaxSteps());
58390 }
58391
58392 return Helper::formatTime($estimated);
58393 },
58394 'memory' => function (ProgressBar $bar) {
58395 return Helper::formatMemory(memory_get_usage(true));
58396 },
58397 'current' => function (ProgressBar $bar) {
58398 return str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', STR_PAD_LEFT);
58399 },
58400 'max' => function (ProgressBar $bar) {
58401 return $bar->getMaxSteps();
58402 },
58403 'percent' => function (ProgressBar $bar) {
58404 return floor($bar->getProgressPercent() * 100);
58405 },
58406 );
58407 }
58408
58409 private static function initFormats()
58410 {
58411 return array(
58412 'normal' => ' %current%/%max% [%bar%] %percent:3s%%',
58413 'normal_nomax' => ' %current% [%bar%]',
58414
58415 'verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%',
58416 'verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',
58417
58418 'very_verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%',
58419 'very_verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',
58420
58421 'debug' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%',
58422 'debug_nomax' => ' %current% [%bar%] %elapsed:6s% %memory:6s%',
58423 );
58424 }
58425 }
58426 <?php
58427
58428
58429
58430
58431
58432
58433
58434
58435
58436
58437 namespace Symfony\Component\Console\Helper;
58438
58439 use Symfony\Component\Console\Exception\LogicException;
58440 use Symfony\Component\Console\Output\ConsoleOutputInterface;
58441 use Symfony\Component\Console\Output\NullOutput;
58442 use Symfony\Component\Console\Output\OutputInterface;
58443
58444
58445
58446
58447
58448
58449
58450
58451
58452
58453 class ProgressHelper extends Helper
58454 {
58455 const FORMAT_QUIET = ' %percent%%';
58456 const FORMAT_NORMAL = ' %current%/%max% [%bar%] %percent%%';
58457 const FORMAT_VERBOSE = ' %current%/%max% [%bar%] %percent%% Elapsed: %elapsed%';
58458 const FORMAT_QUIET_NOMAX = ' %current%';
58459 const FORMAT_NORMAL_NOMAX = ' %current% [%bar%]';
58460 const FORMAT_VERBOSE_NOMAX = ' %current% [%bar%] Elapsed: %elapsed%';
58461
58462
58463 private $barWidth = 28;
58464 private $barChar = '=';
58465 private $emptyBarChar = '-';
58466 private $progressChar = '>';
58467 private $format = null;
58468 private $redrawFreq = 1;
58469
58470 private $lastMessagesLength;
58471 private $barCharOriginal;
58472
58473
58474
58475
58476 private $output;
58477
58478
58479
58480
58481
58482
58483 private $current;
58484
58485
58486
58487
58488
58489
58490 private $max;
58491
58492
58493
58494
58495
58496
58497 private $startTime;
58498
58499
58500
58501
58502
58503
58504 private $defaultFormatVars = array(
58505 'current',
58506 'max',
58507 'bar',
58508 'percent',
58509 'elapsed',
58510 );
58511
58512
58513
58514
58515
58516
58517 private $formatVars;
58518
58519
58520
58521
58522
58523
58524 private $widths = array(
58525 'current' => 4,
58526 'max' => 4,
58527 'percent' => 3,
58528 'elapsed' => 6,
58529 );
58530
58531
58532
58533
58534
58535
58536 private $timeFormats = array(
58537 array(0, '???'),
58538 array(2, '1 sec'),
58539 array(59, 'secs', 1),
58540 array(60, '1 min'),
58541 array(3600, 'mins', 60),
58542 array(5400, '1 hr'),
58543 array(86400, 'hrs', 3600),
58544 array(129600, '1 day'),
58545 array(604800, 'days', 86400),
58546 );
58547
58548 public function __construct($triggerDeprecationError = true)
58549 {
58550 if ($triggerDeprecationError) {
58551 @trigger_error('The '.__CLASS__.' class is deprecated since Symfony 2.5 and will be removed in 3.0. Use the Symfony\Component\Console\Helper\ProgressBar class instead.', E_USER_DEPRECATED);
58552 }
58553 }
58554
58555
58556
58557
58558
58559
58560 public function setBarWidth($size)
58561 {
58562 $this->barWidth = (int) $size;
58563 }
58564
58565
58566
58567
58568
58569
58570 public function setBarCharacter($char)
58571 {
58572 $this->barChar = $char;
58573 }
58574
58575
58576
58577
58578
58579
58580 public function setEmptyBarCharacter($char)
58581 {
58582 $this->emptyBarChar = $char;
58583 }
58584
58585
58586
58587
58588
58589
58590 public function setProgressCharacter($char)
58591 {
58592 $this->progressChar = $char;
58593 }
58594
58595
58596
58597
58598
58599
58600 public function setFormat($format)
58601 {
58602 $this->format = $format;
58603 }
58604
58605
58606
58607
58608
58609
58610 public function setRedrawFrequency($freq)
58611 {
58612 $this->redrawFreq = (int) $freq;
58613 }
58614
58615
58616
58617
58618
58619
58620
58621 public function start(OutputInterface $output, $max = null)
58622 {
58623 if ($output instanceof ConsoleOutputInterface) {
58624 $output = $output->getErrorOutput();
58625 }
58626
58627 $this->startTime = time();
58628 $this->current = 0;
58629 $this->max = (int) $max;
58630
58631
58632 $this->output = $output->isDecorated() ? $output : new NullOutput();
58633 $this->lastMessagesLength = 0;
58634 $this->barCharOriginal = '';
58635
58636 if (null === $this->format) {
58637 switch ($output->getVerbosity()) {
58638 case OutputInterface::VERBOSITY_QUIET:
58639 $this->format = self::FORMAT_QUIET_NOMAX;
58640 if ($this->max > 0) {
58641 $this->format = self::FORMAT_QUIET;
58642 }
58643 break;
58644 case OutputInterface::VERBOSITY_VERBOSE:
58645 case OutputInterface::VERBOSITY_VERY_VERBOSE:
58646 case OutputInterface::VERBOSITY_DEBUG:
58647 $this->format = self::FORMAT_VERBOSE_NOMAX;
58648 if ($this->max > 0) {
58649 $this->format = self::FORMAT_VERBOSE;
58650 }
58651 break;
58652 default:
58653 $this->format = self::FORMAT_NORMAL_NOMAX;
58654 if ($this->max > 0) {
58655 $this->format = self::FORMAT_NORMAL;
58656 }
58657 break;
58658 }
58659 }
58660
58661 $this->initialize();
58662 }
58663
58664
58665
58666
58667
58668
58669
58670
58671
58672 public function advance($step = 1, $redraw = false)
58673 {
58674 $this->setCurrent($this->current + $step, $redraw);
58675 }
58676
58677
58678
58679
58680
58681
58682
58683
58684
58685 public function setCurrent($current, $redraw = false)
58686 {
58687 if (null === $this->startTime) {
58688 throw new LogicException('You must start the progress bar before calling setCurrent().');
58689 }
58690
58691 $current = (int) $current;
58692
58693 if ($current < $this->current) {
58694 throw new LogicException('You can\'t regress the progress bar');
58695 }
58696
58697 if (0 === $this->current) {
58698 $redraw = true;
58699 }
58700
58701 $prevPeriod = (int) ($this->current / $this->redrawFreq);
58702
58703 $this->current = $current;
58704
58705 $currPeriod = (int) ($this->current / $this->redrawFreq);
58706 if ($redraw || $prevPeriod !== $currPeriod || $this->max === $this->current) {
58707 $this->display();
58708 }
58709 }
58710
58711
58712
58713
58714
58715
58716
58717
58718 public function display($finish = false)
58719 {
58720 if (null === $this->startTime) {
58721 throw new LogicException('You must start the progress bar before calling display().');
58722 }
58723
58724 $message = $this->format;
58725 foreach ($this->generate($finish) as $name => $value) {
58726 $message = str_replace("%{$name}%", $value, $message);
58727 }
58728 $this->overwrite($this->output, $message);
58729 }
58730
58731
58732
58733
58734
58735
58736
58737
58738 public function clear()
58739 {
58740 $this->overwrite($this->output, '');
58741 }
58742
58743
58744
58745
58746 public function finish()
58747 {
58748 if (null === $this->startTime) {
58749 throw new LogicException('You must start the progress bar before calling finish().');
58750 }
58751
58752 if (null !== $this->startTime) {
58753 if (!$this->max) {
58754 $this->barChar = $this->barCharOriginal;
58755 $this->display(true);
58756 }
58757 $this->startTime = null;
58758 $this->output->writeln('');
58759 $this->output = null;
58760 }
58761 }
58762
58763
58764
58765
58766 private function initialize()
58767 {
58768 $this->formatVars = array();
58769 foreach ($this->defaultFormatVars as $var) {
58770 if (false !== strpos($this->format, "%{$var}%")) {
58771 $this->formatVars[$var] = true;
58772 }
58773 }
58774
58775 if ($this->max > 0) {
58776 $this->widths['max'] = $this->strlen($this->max);
58777 $this->widths['current'] = $this->widths['max'];
58778 } else {
58779 $this->barCharOriginal = $this->barChar;
58780 $this->barChar = $this->emptyBarChar;
58781 }
58782 }
58783
58784
58785
58786
58787
58788
58789
58790
58791 private function generate($finish = false)
58792 {
58793 $vars = array();
58794 $percent = 0;
58795 if ($this->max > 0) {
58796 $percent = (float) $this->current / $this->max;
58797 }
58798
58799 if (isset($this->formatVars['bar'])) {
58800 if ($this->max > 0) {
58801 $completeBars = floor($percent * $this->barWidth);
58802 } else {
58803 if (!$finish) {
58804 $completeBars = floor($this->current % $this->barWidth);
58805 } else {
58806 $completeBars = $this->barWidth;
58807 }
58808 }
58809
58810 $emptyBars = $this->barWidth - $completeBars - $this->strlen($this->progressChar);
58811 $bar = str_repeat($this->barChar, $completeBars);
58812 if ($completeBars < $this->barWidth) {
58813 $bar .= $this->progressChar;
58814 $bar .= str_repeat($this->emptyBarChar, $emptyBars);
58815 }
58816
58817 $vars['bar'] = $bar;
58818 }
58819
58820 if (isset($this->formatVars['elapsed'])) {
58821 $elapsed = time() - $this->startTime;
58822 $vars['elapsed'] = str_pad($this->humaneTime($elapsed), $this->widths['elapsed'], ' ', STR_PAD_LEFT);
58823 }
58824
58825 if (isset($this->formatVars['current'])) {
58826 $vars['current'] = str_pad($this->current, $this->widths['current'], ' ', STR_PAD_LEFT);
58827 }
58828
58829 if (isset($this->formatVars['max'])) {
58830 $vars['max'] = $this->max;
58831 }
58832
58833 if (isset($this->formatVars['percent'])) {
58834 $vars['percent'] = str_pad(floor($percent * 100), $this->widths['percent'], ' ', STR_PAD_LEFT);
58835 }
58836
58837 return $vars;
58838 }
58839
58840
58841
58842
58843
58844
58845
58846
58847 private function humaneTime($secs)
58848 {
58849 $text = '';
58850 foreach ($this->timeFormats as $format) {
58851 if ($secs < $format[0]) {
58852 if (2 == \count($format)) {
58853 $text = $format[1];
58854 break;
58855 } else {
58856 $text = ceil($secs / $format[2]).' '.$format[1];
58857 break;
58858 }
58859 }
58860 }
58861
58862 return $text;
58863 }
58864
58865
58866
58867
58868
58869
58870
58871 private function overwrite(OutputInterface $output, $message)
58872 {
58873 $length = $this->strlen($message);
58874
58875
58876 if (null !== $this->lastMessagesLength && $this->lastMessagesLength > $length) {
58877 $message = str_pad($message, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT);
58878 }
58879
58880
58881 $output->write("\x0D");
58882 $output->write($message);
58883
58884 $this->lastMessagesLength = $this->strlen($message);
58885 }
58886
58887
58888
58889
58890 public function getName()
58891 {
58892 return 'progress';
58893 }
58894 }
58895 <?php
58896
58897
58898
58899
58900
58901
58902
58903
58904
58905
58906 namespace Symfony\Component\Console\Helper;
58907
58908 use Symfony\Component\Console\Exception\InvalidArgumentException;
58909 use Symfony\Component\Console\Exception\LogicException;
58910 use Symfony\Component\Console\Output\OutputInterface;
58911
58912
58913
58914
58915 class ProgressIndicator
58916 {
58917 private $output;
58918 private $startTime;
58919 private $format;
58920 private $message;
58921 private $indicatorValues;
58922 private $indicatorCurrent;
58923 private $indicatorChangeInterval;
58924 private $indicatorUpdateTime;
58925 private $started = false;
58926
58927 private static $formatters;
58928 private static $formats;
58929
58930
58931
58932
58933
58934
58935
58936 public function __construct(OutputInterface $output, $format = null, $indicatorChangeInterval = 100, $indicatorValues = null)
58937 {
58938 $this->output = $output;
58939
58940 if (null === $format) {
58941 $format = $this->determineBestFormat();
58942 }
58943
58944 if (null === $indicatorValues) {
58945 $indicatorValues = array('-', '\\', '|', '/');
58946 }
58947
58948 $indicatorValues = array_values($indicatorValues);
58949
58950 if (2 > \count($indicatorValues)) {
58951 throw new InvalidArgumentException('Must have at least 2 indicator value characters.');
58952 }
58953
58954 $this->format = self::getFormatDefinition($format);
58955 $this->indicatorChangeInterval = $indicatorChangeInterval;
58956 $this->indicatorValues = $indicatorValues;
58957 $this->startTime = time();
58958 }
58959
58960
58961
58962
58963
58964
58965 public function setMessage($message)
58966 {
58967 $this->message = $message;
58968
58969 $this->display();
58970 }
58971
58972
58973
58974
58975
58976
58977
58978
58979 public function getMessage()
58980 {
58981 return $this->message;
58982 }
58983
58984
58985
58986
58987
58988
58989
58990
58991 public function getStartTime()
58992 {
58993 return $this->startTime;
58994 }
58995
58996
58997
58998
58999
59000
59001
59002
59003 public function getCurrentValue()
59004 {
59005 return $this->indicatorValues[$this->indicatorCurrent % \count($this->indicatorValues)];
59006 }
59007
59008
59009
59010
59011
59012
59013 public function start($message)
59014 {
59015 if ($this->started) {
59016 throw new LogicException('Progress indicator already started.');
59017 }
59018
59019 $this->message = $message;
59020 $this->started = true;
59021 $this->startTime = time();
59022 $this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval;
59023 $this->indicatorCurrent = 0;
59024
59025 $this->display();
59026 }
59027
59028
59029
59030
59031 public function advance()
59032 {
59033 if (!$this->started) {
59034 throw new LogicException('Progress indicator has not yet been started.');
59035 }
59036
59037 if (!$this->output->isDecorated()) {
59038 return;
59039 }
59040
59041 $currentTime = $this->getCurrentTimeInMilliseconds();
59042
59043 if ($currentTime < $this->indicatorUpdateTime) {
59044 return;
59045 }
59046
59047 $this->indicatorUpdateTime = $currentTime + $this->indicatorChangeInterval;
59048 ++$this->indicatorCurrent;
59049
59050 $this->display();
59051 }
59052
59053
59054
59055
59056
59057
59058 public function finish($message)
59059 {
59060 if (!$this->started) {
59061 throw new LogicException('Progress indicator has not yet been started.');
59062 }
59063
59064 $this->message = $message;
59065 $this->display();
59066 $this->output->writeln('');
59067 $this->started = false;
59068 }
59069
59070
59071
59072
59073
59074
59075
59076
59077 public static function getFormatDefinition($name)
59078 {
59079 if (!self::$formats) {
59080 self::$formats = self::initFormats();
59081 }
59082
59083 return isset(self::$formats[$name]) ? self::$formats[$name] : null;
59084 }
59085
59086
59087
59088
59089
59090
59091
59092
59093
59094 public static function setPlaceholderFormatterDefinition($name, $callable)
59095 {
59096 if (!self::$formatters) {
59097 self::$formatters = self::initPlaceholderFormatters();
59098 }
59099
59100 self::$formatters[$name] = $callable;
59101 }
59102
59103
59104
59105
59106
59107
59108
59109
59110 public static function getPlaceholderFormatterDefinition($name)
59111 {
59112 if (!self::$formatters) {
59113 self::$formatters = self::initPlaceholderFormatters();
59114 }
59115
59116 return isset(self::$formatters[$name]) ? self::$formatters[$name] : null;
59117 }
59118
59119 private function display()
59120 {
59121 if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
59122 return;
59123 }
59124
59125 $self = $this;
59126
59127 $this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) use ($self) {
59128 if ($formatter = $self::getPlaceholderFormatterDefinition($matches[1])) {
59129 return \call_user_func($formatter, $self);
59130 }
59131
59132 return $matches[0];
59133 }, $this->format));
59134 }
59135
59136 private function determineBestFormat()
59137 {
59138 switch ($this->output->getVerbosity()) {
59139
59140 case OutputInterface::VERBOSITY_VERBOSE:
59141 return $this->output->isDecorated() ? 'verbose' : 'verbose_no_ansi';
59142 case OutputInterface::VERBOSITY_VERY_VERBOSE:
59143 case OutputInterface::VERBOSITY_DEBUG:
59144 return $this->output->isDecorated() ? 'very_verbose' : 'very_verbose_no_ansi';
59145 default:
59146 return $this->output->isDecorated() ? 'normal' : 'normal_no_ansi';
59147 }
59148 }
59149
59150
59151
59152
59153
59154
59155 private function overwrite($message)
59156 {
59157 if ($this->output->isDecorated()) {
59158 $this->output->write("\x0D\x1B[2K");
59159 $this->output->write($message);
59160 } else {
59161 $this->output->writeln($message);
59162 }
59163 }
59164
59165 private function getCurrentTimeInMilliseconds()
59166 {
59167 return round(microtime(true) * 1000);
59168 }
59169
59170 private static function initPlaceholderFormatters()
59171 {
59172 return array(
59173 'indicator' => function (ProgressIndicator $indicator) {
59174 return $indicator->getCurrentValue();
59175 },
59176 'message' => function (ProgressIndicator $indicator) {
59177 return $indicator->getMessage();
59178 },
59179 'elapsed' => function (ProgressIndicator $indicator) {
59180 return Helper::formatTime(time() - $indicator->getStartTime());
59181 },
59182 'memory' => function () {
59183 return Helper::formatMemory(memory_get_usage(true));
59184 },
59185 );
59186 }
59187
59188 private static function initFormats()
59189 {
59190 return array(
59191 'normal' => ' %indicator% %message%',
59192 'normal_no_ansi' => ' %message%',
59193
59194 'verbose' => ' %indicator% %message% (%elapsed:6s%)',
59195 'verbose_no_ansi' => ' %message% (%elapsed:6s%)',
59196
59197 'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)',
59198 'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)',
59199 );
59200 }
59201 }
59202 <?php
59203
59204
59205
59206
59207
59208
59209
59210
59211
59212
59213 namespace Symfony\Component\Console\Helper;
59214
59215 use Symfony\Component\Console\Exception\InvalidArgumentException;
59216 use Symfony\Component\Console\Exception\RuntimeException;
59217 use Symfony\Component\Console\Formatter\OutputFormatter;
59218 use Symfony\Component\Console\Formatter\OutputFormatterStyle;
59219 use Symfony\Component\Console\Input\InputInterface;
59220 use Symfony\Component\Console\Output\ConsoleOutputInterface;
59221 use Symfony\Component\Console\Output\OutputInterface;
59222 use Symfony\Component\Console\Question\ChoiceQuestion;
59223 use Symfony\Component\Console\Question\Question;
59224
59225
59226
59227
59228
59229
59230 class QuestionHelper extends Helper
59231 {
59232 private $inputStream;
59233 private static $shell;
59234 private static $stty;
59235
59236
59237
59238
59239
59240
59241
59242
59243 public function ask(InputInterface $input, OutputInterface $output, Question $question)
59244 {
59245 if ($output instanceof ConsoleOutputInterface) {
59246 $output = $output->getErrorOutput();
59247 }
59248
59249 if (!$input->isInteractive()) {
59250 $default = $question->getDefault();
59251
59252 if (null !== $default && $question instanceof ChoiceQuestion) {
59253 $choices = $question->getChoices();
59254
59255 if (!$question->isMultiselect()) {
59256 return isset($choices[$default]) ? $choices[$default] : $default;
59257 }
59258
59259 $default = explode(',', $default);
59260 foreach ($default as $k => $v) {
59261 $v = trim($v);
59262 $default[$k] = isset($choices[$v]) ? $choices[$v] : $v;
59263 }
59264 }
59265
59266 return $default;
59267 }
59268
59269 if (!$question->getValidator()) {
59270 return $this->doAsk($output, $question);
59271 }
59272
59273 $that = $this;
59274
59275 $interviewer = function () use ($output, $question, $that) {
59276 return $that->doAsk($output, $question);
59277 };
59278
59279 return $this->validateAttempts($interviewer, $output, $question);
59280 }
59281
59282
59283
59284
59285
59286
59287
59288
59289
59290
59291 public function setInputStream($stream)
59292 {
59293 if (!\is_resource($stream)) {
59294 throw new InvalidArgumentException('Input stream must be a valid resource.');
59295 }
59296
59297 $this->inputStream = $stream;
59298 }
59299
59300
59301
59302
59303
59304
59305 public function getInputStream()
59306 {
59307 return $this->inputStream;
59308 }
59309
59310
59311
59312
59313 public function getName()
59314 {
59315 return 'question';
59316 }
59317
59318
59319
59320
59321
59322
59323
59324
59325
59326
59327 public function doAsk(OutputInterface $output, Question $question)
59328 {
59329 $this->writePrompt($output, $question);
59330
59331 $inputStream = $this->inputStream ?: STDIN;
59332 $autocomplete = $question->getAutocompleterValues();
59333
59334 if (null === $autocomplete || !$this->hasSttyAvailable()) {
59335 $ret = false;
59336 if ($question->isHidden()) {
59337 try {
59338 $ret = trim($this->getHiddenResponse($output, $inputStream));
59339 } catch (RuntimeException $e) {
59340 if (!$question->isHiddenFallback()) {
59341 throw $e;
59342 }
59343 }
59344 }
59345
59346 if (false === $ret) {
59347 $ret = fgets($inputStream, 4096);
59348 if (false === $ret) {
59349 throw new RuntimeException('Aborted');
59350 }
59351 $ret = trim($ret);
59352 }
59353 } else {
59354 $ret = trim($this->autocomplete($output, $question, $inputStream, \is_array($autocomplete) ? $autocomplete : iterator_to_array($autocomplete, false)));
59355 }
59356
59357 $ret = \strlen($ret) > 0 ? $ret : $question->getDefault();
59358
59359 if ($normalizer = $question->getNormalizer()) {
59360 return $normalizer($ret);
59361 }
59362
59363 return $ret;
59364 }
59365
59366
59367
59368
59369 protected function writePrompt(OutputInterface $output, Question $question)
59370 {
59371 $message = $question->getQuestion();
59372
59373 if ($question instanceof ChoiceQuestion) {
59374 $maxWidth = max(array_map(array($this, 'strlen'), array_keys($question->getChoices())));
59375
59376 $messages = (array) $question->getQuestion();
59377 foreach ($question->getChoices() as $key => $value) {
59378 $width = $maxWidth - $this->strlen($key);
59379 $messages[] = '  [<info>'.$key.str_repeat(' ', $width).'</info>] '.$value;
59380 }
59381
59382 $output->writeln($messages);
59383
59384 $message = $question->getPrompt();
59385 }
59386
59387 $output->write($message);
59388 }
59389
59390
59391
59392
59393 protected function writeError(OutputInterface $output, \Exception $error)
59394 {
59395 if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) {
59396 $message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error');
59397 } else {
59398 $message = '<error>'.$error->getMessage().'</error>';
59399 }
59400
59401 $output->writeln($message);
59402 }
59403
59404
59405
59406
59407
59408
59409
59410
59411
59412
59413
59414 private function autocomplete(OutputInterface $output, Question $question, $inputStream, array $autocomplete)
59415 {
59416 $ret = '';
59417
59418 $i = 0;
59419 $ofs = -1;
59420 $matches = $autocomplete;
59421 $numMatches = \count($matches);
59422
59423 $sttyMode = shell_exec('stty -g');
59424
59425
59426 shell_exec('stty -icanon -echo');
59427
59428
59429 $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white'));
59430
59431
59432 while (!feof($inputStream)) {
59433 $c = fread($inputStream, 1);
59434
59435
59436 if ("\177" === $c) {
59437 if (0 === $numMatches && 0 !== $i) {
59438 --$i;
59439
59440 $output->write("\033[1D");
59441 }
59442
59443 if (0 === $i) {
59444 $ofs = -1;
59445 $matches = $autocomplete;
59446 $numMatches = \count($matches);
59447 } else {
59448 $numMatches = 0;
59449 }
59450
59451
59452 $ret = substr($ret, 0, $i);
59453 } elseif ("\033" === $c) {
59454
59455 $c .= fread($inputStream, 2);
59456
59457
59458 if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) {
59459 if ('A' === $c[2] && -1 === $ofs) {
59460 $ofs = 0;
59461 }
59462
59463 if (0 === $numMatches) {
59464 continue;
59465 }
59466
59467 $ofs += ('A' === $c[2]) ? -1 : 1;
59468 $ofs = ($numMatches + $ofs) % $numMatches;
59469 }
59470 } elseif (\ord($c) < 32) {
59471 if ("\t" === $c || "\n" === $c) {
59472 if ($numMatches > 0 && -1 !== $ofs) {
59473 $ret = $matches[$ofs];
59474
59475 $output->write(substr($ret, $i));
59476 $i = \strlen($ret);
59477 }
59478
59479 if ("\n" === $c) {
59480 $output->write($c);
59481 break;
59482 }
59483
59484 $numMatches = 0;
59485 }
59486
59487 continue;
59488 } else {
59489 $output->write($c);
59490 $ret .= $c;
59491 ++$i;
59492
59493 $numMatches = 0;
59494 $ofs = 0;
59495
59496 foreach ($autocomplete as $value) {
59497
59498 if (0 === strpos($value, $ret)) {
59499 $matches[$numMatches++] = $value;
59500 }
59501 }
59502 }
59503
59504
59505 $output->write("\033[K");
59506
59507 if ($numMatches > 0 && -1 !== $ofs) {
59508
59509 $output->write("\0337");
59510
59511 $output->write('<hl>'.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $i)).'</hl>');
59512
59513 $output->write("\0338");
59514 }
59515 }
59516
59517
59518 shell_exec(sprintf('stty %s', $sttyMode));
59519
59520 return $ret;
59521 }
59522
59523
59524
59525
59526
59527
59528
59529
59530
59531
59532
59533 private function getHiddenResponse(OutputInterface $output, $inputStream)
59534 {
59535 if ('\\' === \DIRECTORY_SEPARATOR) {
59536 $exe = __DIR__.'/../Resources/bin/hiddeninput.exe';
59537
59538
59539 if ('phar:' === substr(__FILE__, 0, 5)) {
59540 $tmpExe = sys_get_temp_dir().'/hiddeninput.exe';
59541 copy($exe, $tmpExe);
59542 $exe = $tmpExe;
59543 }
59544
59545 $value = rtrim(shell_exec($exe));
59546 $output->writeln('');
59547
59548 if (isset($tmpExe)) {
59549 unlink($tmpExe);
59550 }
59551
59552 return $value;
59553 }
59554
59555 if ($this->hasSttyAvailable()) {
59556 $sttyMode = shell_exec('stty -g');
59557
59558 shell_exec('stty -echo');
59559 $value = fgets($inputStream, 4096);
59560 shell_exec(sprintf('stty %s', $sttyMode));
59561
59562 if (false === $value) {
59563 throw new RuntimeException('Aborted');
59564 }
59565
59566 $value = trim($value);
59567 $output->writeln('');
59568
59569 return $value;
59570 }
59571
59572 if (false !== $shell = $this->getShell()) {
59573 $readCmd = 'csh' === $shell ? 'set mypassword = $<' : 'read -r mypassword';
59574 $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd);
59575 $value = rtrim(shell_exec($command));
59576 $output->writeln('');
59577
59578 return $value;
59579 }
59580
59581 throw new RuntimeException('Unable to hide the response.');
59582 }
59583
59584
59585
59586
59587
59588
59589
59590
59591
59592
59593
59594
59595 private function validateAttempts($interviewer, OutputInterface $output, Question $question)
59596 {
59597 $error = null;
59598 $attempts = $question->getMaxAttempts();
59599 while (null === $attempts || $attempts--) {
59600 if (null !== $error) {
59601 $this->writeError($output, $error);
59602 }
59603
59604 try {
59605 return \call_user_func($question->getValidator(), $interviewer());
59606 } catch (RuntimeException $e) {
59607 throw $e;
59608 } catch (\Exception $error) {
59609 }
59610 }
59611
59612 throw $error;
59613 }
59614
59615
59616
59617
59618
59619
59620 private function getShell()
59621 {
59622 if (null !== self::$shell) {
59623 return self::$shell;
59624 }
59625
59626 self::$shell = false;
59627
59628 if (file_exists('/usr/bin/env')) {
59629
59630 $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null";
59631 foreach (array('bash', 'zsh', 'ksh', 'csh') as $sh) {
59632 if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) {
59633 self::$shell = $sh;
59634 break;
59635 }
59636 }
59637 }
59638
59639 return self::$shell;
59640 }
59641
59642
59643
59644
59645
59646
59647 private function hasSttyAvailable()
59648 {
59649 if (null !== self::$stty) {
59650 return self::$stty;
59651 }
59652
59653 exec('stty 2>&1', $output, $exitcode);
59654
59655 return self::$stty = 0 === $exitcode;
59656 }
59657 }
59658 <?php
59659
59660
59661
59662
59663
59664
59665
59666
59667
59668
59669 namespace Symfony\Component\Console\Helper;
59670
59671 use Symfony\Component\Console\Exception\LogicException;
59672 use Symfony\Component\Console\Formatter\OutputFormatter;
59673 use Symfony\Component\Console\Input\InputInterface;
59674 use Symfony\Component\Console\Output\OutputInterface;
59675 use Symfony\Component\Console\Question\ChoiceQuestion;
59676 use Symfony\Component\Console\Question\ConfirmationQuestion;
59677 use Symfony\Component\Console\Question\Question;
59678 use Symfony\Component\Console\Style\SymfonyStyle;
59679
59680
59681
59682
59683
59684
59685 class SymfonyQuestionHelper extends QuestionHelper
59686 {
59687
59688
59689
59690 public function ask(InputInterface $input, OutputInterface $output, Question $question)
59691 {
59692 $validator = $question->getValidator();
59693 $question->setValidator(function ($value) use ($validator) {
59694 if (null !== $validator) {
59695 $value = $validator($value);
59696 } else {
59697
59698 if (!\is_array($value) && !\is_bool($value) && 0 === \strlen($value)) {
59699 throw new LogicException('A value is required.');
59700 }
59701 }
59702
59703 return $value;
59704 });
59705
59706 return parent::ask($input, $output, $question);
59707 }
59708
59709
59710
59711
59712 protected function writePrompt(OutputInterface $output, Question $question)
59713 {
59714 $text = OutputFormatter::escapeTrailingBackslash($question->getQuestion());
59715 $default = $question->getDefault();
59716
59717 switch (true) {
59718 case null === $default:
59719 $text = sprintf(' <info>%s</info>:', $text);
59720
59721 break;
59722
59723 case $question instanceof ConfirmationQuestion:
59724 $text = sprintf(' <info>%s (yes/no)</info> [<comment>%s</comment>]:', $text, $default ? 'yes' : 'no');
59725
59726 break;
59727
59728 case $question instanceof ChoiceQuestion && $question->isMultiselect():
59729 $choices = $question->getChoices();
59730 $default = explode(',', $default);
59731
59732 foreach ($default as $key => $value) {
59733 $default[$key] = $choices[trim($value)];
59734 }
59735
59736 $text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape(implode(', ', $default)));
59737
59738 break;
59739
59740 case $question instanceof ChoiceQuestion:
59741 $choices = $question->getChoices();
59742 $text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape(isset($choices[$default]) ? $choices[$default] : $default));
59743
59744 break;
59745
59746 default:
59747 $text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape($default));
59748 }
59749
59750 $output->writeln($text);
59751
59752 if ($question instanceof ChoiceQuestion) {
59753 $width = max(array_map('strlen', array_keys($question->getChoices())));
59754
59755 foreach ($question->getChoices() as $key => $value) {
59756 $output->writeln(sprintf("  [<comment>%-${width}s</comment>] %s", $key, $value));
59757 }
59758 }
59759
59760 $output->write(' > ');
59761 }
59762
59763
59764
59765
59766 protected function writeError(OutputInterface $output, \Exception $error)
59767 {
59768 if ($output instanceof SymfonyStyle) {
59769 $output->newLine();
59770 $output->error($error->getMessage());
59771
59772 return;
59773 }
59774
59775 parent::writeError($output, $error);
59776 }
59777 }
59778 <?php
59779
59780
59781
59782
59783
59784
59785
59786
59787
59788
59789 namespace Symfony\Component\Console\Helper;
59790
59791 use Symfony\Component\Console\Exception\InvalidArgumentException;
59792 use Symfony\Component\Console\Output\OutputInterface;
59793
59794
59795
59796
59797
59798
59799
59800
59801
59802 class Table
59803 {
59804
59805
59806
59807 private $headers = array();
59808
59809
59810
59811
59812 private $rows = array();
59813
59814
59815
59816
59817 private $columnWidths = array();
59818
59819
59820
59821
59822
59823
59824 private $numberOfColumns;
59825
59826
59827
59828
59829 private $output;
59830
59831
59832
59833
59834 private $style;
59835
59836
59837
59838
59839 private $columnStyles = array();
59840
59841 private static $styles;
59842
59843 public function __construct(OutputInterface $output)
59844 {
59845 $this->output = $output;
59846
59847 if (!self::$styles) {
59848 self::$styles = self::initStyles();
59849 }
59850
59851 $this->setStyle('default');
59852 }
59853
59854
59855
59856
59857
59858
59859
59860 public static function setStyleDefinition($name, TableStyle $style)
59861 {
59862 if (!self::$styles) {
59863 self::$styles = self::initStyles();
59864 }
59865
59866 self::$styles[$name] = $style;
59867 }
59868
59869
59870
59871
59872
59873
59874
59875
59876 public static function getStyleDefinition($name)
59877 {
59878 if (!self::$styles) {
59879 self::$styles = self::initStyles();
59880 }
59881
59882 if (isset(self::$styles[$name])) {
59883 return self::$styles[$name];
59884 }
59885
59886 throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
59887 }
59888
59889
59890
59891
59892
59893
59894
59895
59896 public function setStyle($name)
59897 {
59898 $this->style = $this->resolveStyle($name);
59899
59900 return $this;
59901 }
59902
59903
59904
59905
59906
59907
59908 public function getStyle()
59909 {
59910 return $this->style;
59911 }
59912
59913
59914
59915
59916
59917
59918
59919
59920
59921 public function setColumnStyle($columnIndex, $name)
59922 {
59923 $columnIndex = (int) $columnIndex;
59924
59925 $this->columnStyles[$columnIndex] = $this->resolveStyle($name);
59926
59927 return $this;
59928 }
59929
59930
59931
59932
59933
59934
59935
59936
59937
59938
59939 public function getColumnStyle($columnIndex)
59940 {
59941 if (isset($this->columnStyles[$columnIndex])) {
59942 return $this->columnStyles[$columnIndex];
59943 }
59944
59945 return $this->getStyle();
59946 }
59947
59948 public function setHeaders(array $headers)
59949 {
59950 $headers = array_values($headers);
59951 if (!empty($headers) && !\is_array($headers[0])) {
59952 $headers = array($headers);
59953 }
59954
59955 $this->headers = $headers;
59956
59957 return $this;
59958 }
59959
59960 public function setRows(array $rows)
59961 {
59962 $this->rows = array();
59963
59964 return $this->addRows($rows);
59965 }
59966
59967 public function addRows(array $rows)
59968 {
59969 foreach ($rows as $row) {
59970 $this->addRow($row);
59971 }
59972
59973 return $this;
59974 }
59975
59976 public function addRow($row)
59977 {
59978 if ($row instanceof TableSeparator) {
59979 $this->rows[] = $row;
59980
59981 return $this;
59982 }
59983
59984 if (!\is_array($row)) {
59985 throw new InvalidArgumentException('A row must be an array or a TableSeparator instance.');
59986 }
59987
59988 $this->rows[] = array_values($row);
59989
59990 return $this;
59991 }
59992
59993 public function setRow($column, array $row)
59994 {
59995 $this->rows[$column] = $row;
59996
59997 return $this;
59998 }
59999
60000
60001
60002
60003
60004
60005
60006
60007
60008
60009
60010
60011
60012
60013 public function render()
60014 {
60015 $this->calculateNumberOfColumns();
60016 $rows = $this->buildTableRows($this->rows);
60017 $headers = $this->buildTableRows($this->headers);
60018
60019 $this->calculateColumnsWidth(array_merge($headers, $rows));
60020
60021 $this->renderRowSeparator();
60022 if (!empty($headers)) {
60023 foreach ($headers as $header) {
60024 $this->renderRow($header, $this->style->getCellHeaderFormat());
60025 $this->renderRowSeparator();
60026 }
60027 }
60028 foreach ($rows as $row) {
60029 if ($row instanceof TableSeparator) {
60030 $this->renderRowSeparator();
60031 } else {
60032 $this->renderRow($row, $this->style->getCellRowFormat());
60033 }
60034 }
60035 if (!empty($rows)) {
60036 $this->renderRowSeparator();
60037 }
60038
60039 $this->cleanup();
60040 }
60041
60042
60043
60044
60045
60046
60047
60048
60049 private function renderRowSeparator()
60050 {
60051 if (0 === $count = $this->numberOfColumns) {
60052 return;
60053 }
60054
60055 if (!$this->style->getHorizontalBorderChar() && !$this->style->getCrossingChar()) {
60056 return;
60057 }
60058
60059 $markup = $this->style->getCrossingChar();
60060 for ($column = 0; $column < $count; ++$column) {
60061 $markup .= str_repeat($this->style->getHorizontalBorderChar(), $this->columnWidths[$column]).$this->style->getCrossingChar();
60062 }
60063
60064 $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup));
60065 }
60066
60067
60068
60069
60070 private function renderColumnSeparator()
60071 {
60072 return sprintf($this->style->getBorderFormat(), $this->style->getVerticalBorderChar());
60073 }
60074
60075
60076
60077
60078
60079
60080
60081
60082
60083
60084
60085 private function renderRow(array $row, $cellFormat)
60086 {
60087 if (empty($row)) {
60088 return;
60089 }
60090
60091 $rowContent = $this->renderColumnSeparator();
60092 foreach ($this->getRowColumns($row) as $column) {
60093 $rowContent .= $this->renderCell($row, $column, $cellFormat);
60094 $rowContent .= $this->renderColumnSeparator();
60095 }
60096 $this->output->writeln($rowContent);
60097 }
60098
60099
60100
60101
60102
60103
60104
60105
60106 private function renderCell(array $row, $column, $cellFormat)
60107 {
60108 $cell = isset($row[$column]) ? $row[$column] : '';
60109 $width = $this->columnWidths[$column];
60110 if ($cell instanceof TableCell && $cell->getColspan() > 1) {
60111
60112 foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) {
60113 $width += $this->getColumnSeparatorWidth() + $this->columnWidths[$nextColumn];
60114 }
60115 }
60116
60117
60118 if (false !== $encoding = mb_detect_encoding($cell, null, true)) {
60119 $width += \strlen($cell) - mb_strwidth($cell, $encoding);
60120 }
60121
60122 $style = $this->getColumnStyle($column);
60123
60124 if ($cell instanceof TableSeparator) {
60125 return sprintf($style->getBorderFormat(), str_repeat($style->getHorizontalBorderChar(), $width));
60126 }
60127
60128 $width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
60129 $content = sprintf($style->getCellRowContentFormat(), $cell);
60130
60131 return sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $style->getPadType()));
60132 }
60133
60134
60135
60136
60137 private function calculateNumberOfColumns()
60138 {
60139 if (null !== $this->numberOfColumns) {
60140 return;
60141 }
60142
60143 $columns = array(0);
60144 foreach (array_merge($this->headers, $this->rows) as $row) {
60145 if ($row instanceof TableSeparator) {
60146 continue;
60147 }
60148
60149 $columns[] = $this->getNumberOfColumns($row);
60150 }
60151
60152 $this->numberOfColumns = max($columns);
60153 }
60154
60155 private function buildTableRows($rows)
60156 {
60157 $unmergedRows = array();
60158 for ($rowKey = 0; $rowKey < \count($rows); ++$rowKey) {
60159 $rows = $this->fillNextRows($rows, $rowKey);
60160
60161
60162 foreach ($rows[$rowKey] as $column => $cell) {
60163 if (!strstr($cell, "\n")) {
60164 continue;
60165 }
60166 $lines = explode("\n", str_replace("\n", "<fg=default;bg=default>\n</>", $cell));
60167 foreach ($lines as $lineKey => $line) {
60168 if ($cell instanceof TableCell) {
60169 $line = new TableCell($line, array('colspan' => $cell->getColspan()));
60170 }
60171 if (0 === $lineKey) {
60172 $rows[$rowKey][$column] = $line;
60173 } else {
60174 $unmergedRows[$rowKey][$lineKey][$column] = $line;
60175 }
60176 }
60177 }
60178 }
60179
60180 $tableRows = array();
60181 foreach ($rows as $rowKey => $row) {
60182 $tableRows[] = $this->fillCells($row);
60183 if (isset($unmergedRows[$rowKey])) {
60184 $tableRows = array_merge($tableRows, $unmergedRows[$rowKey]);
60185 }
60186 }
60187
60188 return $tableRows;
60189 }
60190
60191
60192
60193
60194
60195
60196
60197
60198
60199 private function fillNextRows(array $rows, $line)
60200 {
60201 $unmergedRows = array();
60202 foreach ($rows[$line] as $column => $cell) {
60203 if ($cell instanceof TableCell && $cell->getRowspan() > 1) {
60204 $nbLines = $cell->getRowspan() - 1;
60205 $lines = array($cell);
60206 if (strstr($cell, "\n")) {
60207 $lines = explode("\n", str_replace("\n", "<fg=default;bg=default>\n</>", $cell));
60208 $nbLines = \count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines;
60209
60210 $rows[$line][$column] = new TableCell($lines[0], array('colspan' => $cell->getColspan()));
60211 unset($lines[0]);
60212 }
60213
60214
60215 $unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, array()), $unmergedRows);
60216 foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
60217 $value = isset($lines[$unmergedRowKey - $line]) ? $lines[$unmergedRowKey - $line] : '';
60218 $unmergedRows[$unmergedRowKey][$column] = new TableCell($value, array('colspan' => $cell->getColspan()));
60219 if ($nbLines === $unmergedRowKey - $line) {
60220 break;
60221 }
60222 }
60223 }
60224 }
60225
60226 foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
60227
60228 if (isset($rows[$unmergedRowKey]) && \is_array($rows[$unmergedRowKey]) && ($this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns)) {
60229 foreach ($unmergedRow as $cellKey => $cell) {
60230
60231 array_splice($rows[$unmergedRowKey], $cellKey, 0, array($cell));
60232 }
60233 } else {
60234 $row = $this->copyRow($rows, $unmergedRowKey - 1);
60235 foreach ($unmergedRow as $column => $cell) {
60236 if (!empty($cell)) {
60237 $row[$column] = $unmergedRow[$column];
60238 }
60239 }
60240 array_splice($rows, $unmergedRowKey, 0, array($row));
60241 }
60242 }
60243
60244 return $rows;
60245 }
60246
60247
60248
60249
60250
60251
60252 private function fillCells($row)
60253 {
60254 $newRow = array();
60255 foreach ($row as $column => $cell) {
60256 $newRow[] = $cell;
60257 if ($cell instanceof TableCell && $cell->getColspan() > 1) {
60258 foreach (range($column + 1, $column + $cell->getColspan() - 1) as $position) {
60259
60260 $newRow[] = '';
60261 }
60262 }
60263 }
60264
60265 return $newRow ?: $row;
60266 }
60267
60268
60269
60270
60271
60272
60273
60274 private function copyRow(array $rows, $line)
60275 {
60276 $row = $rows[$line];
60277 foreach ($row as $cellKey => $cellValue) {
60278 $row[$cellKey] = '';
60279 if ($cellValue instanceof TableCell) {
60280 $row[$cellKey] = new TableCell('', array('colspan' => $cellValue->getColspan()));
60281 }
60282 }
60283
60284 return $row;
60285 }
60286
60287
60288
60289
60290
60291
60292 private function getNumberOfColumns(array $row)
60293 {
60294 $columns = \count($row);
60295 foreach ($row as $column) {
60296 $columns += $column instanceof TableCell ? ($column->getColspan() - 1) : 0;
60297 }
60298
60299 return $columns;
60300 }
60301
60302
60303
60304
60305
60306
60307 private function getRowColumns(array $row)
60308 {
60309 $columns = range(0, $this->numberOfColumns - 1);
60310 foreach ($row as $cellKey => $cell) {
60311 if ($cell instanceof TableCell && $cell->getColspan() > 1) {
60312
60313 $columns = array_diff($columns, range($cellKey + 1, $cellKey + $cell->getColspan() - 1));
60314 }
60315 }
60316
60317 return $columns;
60318 }
60319
60320
60321
60322
60323
60324
60325 private function calculateColumnsWidth($rows)
60326 {
60327 for ($column = 0; $column < $this->numberOfColumns; ++$column) {
60328 $lengths = array();
60329 foreach ($rows as $row) {
60330 if ($row instanceof TableSeparator) {
60331 continue;
60332 }
60333
60334 foreach ($row as $i => $cell) {
60335 if ($cell instanceof TableCell) {
60336 $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell);
60337 $textLength = Helper::strlen($textContent);
60338 if ($textLength > 0) {
60339 $contentColumns = str_split($textContent, ceil($textLength / $cell->getColspan()));
60340 foreach ($contentColumns as $position => $content) {
60341 $row[$i + $position] = $content;
60342 }
60343 }
60344 }
60345 }
60346
60347 $lengths[] = $this->getCellWidth($row, $column);
60348 }
60349
60350 $this->columnWidths[$column] = max($lengths) + Helper::strlen($this->style->getCellRowContentFormat()) - 2;
60351 }
60352 }
60353
60354
60355
60356
60357
60358
60359 private function getColumnSeparatorWidth()
60360 {
60361 return Helper::strlen(sprintf($this->style->getBorderFormat(), $this->style->getVerticalBorderChar()));
60362 }
60363
60364
60365
60366
60367
60368
60369
60370
60371
60372 private function getCellWidth(array $row, $column)
60373 {
60374 if (isset($row[$column])) {
60375 $cell = $row[$column];
60376 $cellWidth = Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
60377
60378 return $cellWidth;
60379 }
60380
60381 return 0;
60382 }
60383
60384
60385
60386
60387 private function cleanup()
60388 {
60389 $this->columnWidths = array();
60390 $this->numberOfColumns = null;
60391 }
60392
60393 private static function initStyles()
60394 {
60395 $borderless = new TableStyle();
60396 $borderless
60397 ->setHorizontalBorderChar('=')
60398 ->setVerticalBorderChar(' ')
60399 ->setCrossingChar(' ')
60400 ;
60401
60402 $compact = new TableStyle();
60403 $compact
60404 ->setHorizontalBorderChar('')
60405 ->setVerticalBorderChar(' ')
60406 ->setCrossingChar('')
60407 ->setCellRowContentFormat('%s')
60408 ;
60409
60410 $styleGuide = new TableStyle();
60411 $styleGuide
60412 ->setHorizontalBorderChar('-')
60413 ->setVerticalBorderChar(' ')
60414 ->setCrossingChar(' ')
60415 ->setCellHeaderFormat('%s')
60416 ;
60417
60418 return array(
60419 'default' => new TableStyle(),
60420 'borderless' => $borderless,
60421 'compact' => $compact,
60422 'symfony-style-guide' => $styleGuide,
60423 );
60424 }
60425
60426 private function resolveStyle($name)
60427 {
60428 if ($name instanceof TableStyle) {
60429 return $name;
60430 }
60431
60432 if (isset(self::$styles[$name])) {
60433 return self::$styles[$name];
60434 }
60435
60436 throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
60437 }
60438 }
60439 <?php
60440
60441
60442
60443
60444
60445
60446
60447
60448
60449
60450 namespace Symfony\Component\Console\Helper;
60451
60452 use Symfony\Component\Console\Exception\InvalidArgumentException;
60453
60454
60455
60456
60457 class TableCell
60458 {
60459 private $value;
60460 private $options = array(
60461 'rowspan' => 1,
60462 'colspan' => 1,
60463 );
60464
60465
60466
60467
60468
60469 public function __construct($value = '', array $options = array())
60470 {
60471 if (is_numeric($value) && !\is_string($value)) {
60472 $value = (string) $value;
60473 }
60474
60475 $this->value = $value;
60476
60477
60478 if ($diff = array_diff(array_keys($options), array_keys($this->options))) {
60479 throw new InvalidArgumentException(sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff)));
60480 }
60481
60482 $this->options = array_merge($this->options, $options);
60483 }
60484
60485
60486
60487
60488
60489
60490 public function __toString()
60491 {
60492 return $this->value;
60493 }
60494
60495
60496
60497
60498
60499
60500 public function getColspan()
60501 {
60502 return (int) $this->options['colspan'];
60503 }
60504
60505
60506
60507
60508
60509
60510 public function getRowspan()
60511 {
60512 return (int) $this->options['rowspan'];
60513 }
60514 }
60515 <?php
60516
60517
60518
60519
60520
60521
60522
60523
60524
60525
60526 namespace Symfony\Component\Console\Helper;
60527
60528 use Symfony\Component\Console\Exception\InvalidArgumentException;
60529 use Symfony\Component\Console\Output\NullOutput;
60530 use Symfony\Component\Console\Output\OutputInterface;
60531
60532
60533
60534
60535
60536
60537
60538
60539
60540
60541 class TableHelper extends Helper
60542 {
60543 const LAYOUT_DEFAULT = 0;
60544 const LAYOUT_BORDERLESS = 1;
60545 const LAYOUT_COMPACT = 2;
60546
60547 private $table;
60548
60549 public function __construct($triggerDeprecationError = true)
60550 {
60551 if ($triggerDeprecationError) {
60552 @trigger_error('The '.__CLASS__.' class is deprecated since Symfony 2.5 and will be removed in 3.0. Use the Symfony\Component\Console\Helper\Table class instead.', E_USER_DEPRECATED);
60553 }
60554
60555 $this->table = new Table(new NullOutput());
60556 }
60557
60558
60559
60560
60561
60562
60563
60564
60565
60566
60567 public function setLayout($layout)
60568 {
60569 switch ($layout) {
60570 case self::LAYOUT_BORDERLESS:
60571 $this->table->setStyle('borderless');
60572 break;
60573
60574 case self::LAYOUT_COMPACT:
60575 $this->table->setStyle('compact');
60576 break;
60577
60578 case self::LAYOUT_DEFAULT:
60579 $this->table->setStyle('default');
60580 break;
60581
60582 default:
60583 throw new InvalidArgumentException(sprintf('Invalid table layout "%s".', $layout));
60584 }
60585
60586 return $this;
60587 }
60588
60589 public function setHeaders(array $headers)
60590 {
60591 $this->table->setHeaders($headers);
60592
60593 return $this;
60594 }
60595
60596 public function setRows(array $rows)
60597 {
60598 $this->table->setRows($rows);
60599
60600 return $this;
60601 }
60602
60603 public function addRows(array $rows)
60604 {
60605 $this->table->addRows($rows);
60606
60607 return $this;
60608 }
60609
60610 public function addRow(array $row)
60611 {
60612 $this->table->addRow($row);
60613
60614 return $this;
60615 }
60616
60617 public function setRow($column, array $row)
60618 {
60619 $this->table->setRow($column, $row);
60620
60621 return $this;
60622 }
60623
60624
60625
60626
60627
60628
60629
60630
60631 public function setPaddingChar($paddingChar)
60632 {
60633 $this->table->getStyle()->setPaddingChar($paddingChar);
60634
60635 return $this;
60636 }
60637
60638
60639
60640
60641
60642
60643
60644
60645 public function setHorizontalBorderChar($horizontalBorderChar)
60646 {
60647 $this->table->getStyle()->setHorizontalBorderChar($horizontalBorderChar);
60648
60649 return $this;
60650 }
60651
60652
60653
60654
60655
60656
60657
60658
60659 public function setVerticalBorderChar($verticalBorderChar)
60660 {
60661 $this->table->getStyle()->setVerticalBorderChar($verticalBorderChar);
60662
60663 return $this;
60664 }
60665
60666
60667
60668
60669
60670
60671
60672
60673 public function setCrossingChar($crossingChar)
60674 {
60675 $this->table->getStyle()->setCrossingChar($crossingChar);
60676
60677 return $this;
60678 }
60679
60680
60681
60682
60683
60684
60685
60686
60687 public function setCellHeaderFormat($cellHeaderFormat)
60688 {
60689 $this->table->getStyle()->setCellHeaderFormat($cellHeaderFormat);
60690
60691 return $this;
60692 }
60693
60694
60695
60696
60697
60698
60699
60700
60701 public function setCellRowFormat($cellRowFormat)
60702 {
60703 $this->table->getStyle()->setCellHeaderFormat($cellRowFormat);
60704
60705 return $this;
60706 }
60707
60708
60709
60710
60711
60712
60713
60714
60715 public function setCellRowContentFormat($cellRowContentFormat)
60716 {
60717 $this->table->getStyle()->setCellRowContentFormat($cellRowContentFormat);
60718
60719 return $this;
60720 }
60721
60722
60723
60724
60725
60726
60727
60728
60729 public function setBorderFormat($borderFormat)
60730 {
60731 $this->table->getStyle()->setBorderFormat($borderFormat);
60732
60733 return $this;
60734 }
60735
60736
60737
60738
60739
60740
60741
60742
60743 public function setPadType($padType)
60744 {
60745 $this->table->getStyle()->setPadType($padType);
60746
60747 return $this;
60748 }
60749
60750
60751
60752
60753
60754
60755
60756
60757
60758
60759
60760
60761
60762 public function render(OutputInterface $output)
60763 {
60764 $p = new \ReflectionProperty($this->table, 'output');
60765 $p->setAccessible(true);
60766 $p->setValue($this->table, $output);
60767
60768 $this->table->render();
60769 }
60770
60771
60772
60773
60774 public function getName()
60775 {
60776 return 'table';
60777 }
60778 }
60779 <?php
60780
60781
60782
60783
60784
60785
60786
60787
60788
60789
60790 namespace Symfony\Component\Console\Helper;
60791
60792
60793
60794
60795
60796
60797 class TableSeparator extends TableCell
60798 {
60799 public function __construct(array $options = array())
60800 {
60801 parent::__construct('', $options);
60802 }
60803 }
60804 <?php
60805
60806
60807
60808
60809
60810
60811
60812
60813
60814
60815 namespace Symfony\Component\Console\Helper;
60816
60817 use Symfony\Component\Console\Exception\InvalidArgumentException;
60818 use Symfony\Component\Console\Exception\LogicException;
60819
60820
60821
60822
60823
60824
60825
60826 class TableStyle
60827 {
60828 private $paddingChar = ' ';
60829 private $horizontalBorderChar = '-';
60830 private $verticalBorderChar = '|';
60831 private $crossingChar = '+';
60832 private $cellHeaderFormat = '<info>%s</info>';
60833 private $cellRowFormat = '%s';
60834 private $cellRowContentFormat = ' %s ';
60835 private $borderFormat = '%s';
60836 private $padType = STR_PAD_RIGHT;
60837
60838
60839
60840
60841
60842
60843
60844
60845 public function setPaddingChar($paddingChar)
60846 {
60847 if (!$paddingChar) {
60848 throw new LogicException('The padding char must not be empty');
60849 }
60850
60851 $this->paddingChar = $paddingChar;
60852
60853 return $this;
60854 }
60855
60856
60857
60858
60859
60860
60861 public function getPaddingChar()
60862 {
60863 return $this->paddingChar;
60864 }
60865
60866
60867
60868
60869
60870
60871
60872
60873 public function setHorizontalBorderChar($horizontalBorderChar)
60874 {
60875 $this->horizontalBorderChar = $horizontalBorderChar;
60876
60877 return $this;
60878 }
60879
60880
60881
60882
60883
60884
60885 public function getHorizontalBorderChar()
60886 {
60887 return $this->horizontalBorderChar;
60888 }
60889
60890
60891
60892
60893
60894
60895
60896
60897 public function setVerticalBorderChar($verticalBorderChar)
60898 {
60899 $this->verticalBorderChar = $verticalBorderChar;
60900
60901 return $this;
60902 }
60903
60904
60905
60906
60907
60908
60909 public function getVerticalBorderChar()
60910 {
60911 return $this->verticalBorderChar;
60912 }
60913
60914
60915
60916
60917
60918
60919
60920
60921 public function setCrossingChar($crossingChar)
60922 {
60923 $this->crossingChar = $crossingChar;
60924
60925 return $this;
60926 }
60927
60928
60929
60930
60931
60932
60933 public function getCrossingChar()
60934 {
60935 return $this->crossingChar;
60936 }
60937
60938
60939
60940
60941
60942
60943
60944
60945 public function setCellHeaderFormat($cellHeaderFormat)
60946 {
60947 $this->cellHeaderFormat = $cellHeaderFormat;
60948
60949 return $this;
60950 }
60951
60952
60953
60954
60955
60956
60957 public function getCellHeaderFormat()
60958 {
60959 return $this->cellHeaderFormat;
60960 }
60961
60962
60963
60964
60965
60966
60967
60968
60969 public function setCellRowFormat($cellRowFormat)
60970 {
60971 $this->cellRowFormat = $cellRowFormat;
60972
60973 return $this;
60974 }
60975
60976
60977
60978
60979
60980
60981 public function getCellRowFormat()
60982 {
60983 return $this->cellRowFormat;
60984 }
60985
60986
60987
60988
60989
60990
60991
60992
60993 public function setCellRowContentFormat($cellRowContentFormat)
60994 {
60995 $this->cellRowContentFormat = $cellRowContentFormat;
60996
60997 return $this;
60998 }
60999
61000
61001
61002
61003
61004
61005 public function getCellRowContentFormat()
61006 {
61007 return $this->cellRowContentFormat;
61008 }
61009
61010
61011
61012
61013
61014
61015
61016
61017 public function setBorderFormat($borderFormat)
61018 {
61019 $this->borderFormat = $borderFormat;
61020
61021 return $this;
61022 }
61023
61024
61025
61026
61027
61028
61029 public function getBorderFormat()
61030 {
61031 return $this->borderFormat;
61032 }
61033
61034
61035
61036
61037
61038
61039
61040
61041 public function setPadType($padType)
61042 {
61043 if (!\in_array($padType, array(STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH), true)) {
61044 throw new InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).');
61045 }
61046
61047 $this->padType = $padType;
61048
61049 return $this;
61050 }
61051
61052
61053
61054
61055
61056
61057 public function getPadType()
61058 {
61059 return $this->padType;
61060 }
61061 }
61062 <?php
61063
61064
61065
61066
61067
61068
61069
61070
61071
61072
61073 namespace Symfony\Component\Console\Input;
61074
61075 use Symfony\Component\Console\Exception\RuntimeException;
61076
61077
61078
61079
61080
61081
61082
61083
61084
61085
61086
61087
61088
61089
61090
61091
61092
61093
61094
61095
61096
61097
61098
61099
61100
61101
61102 class ArgvInput extends Input
61103 {
61104 private $tokens;
61105 private $parsed;
61106
61107
61108
61109
61110
61111 public function __construct(array $argv = null, InputDefinition $definition = null)
61112 {
61113 if (null === $argv) {
61114 $argv = $_SERVER['argv'];
61115 }
61116
61117
61118 array_shift($argv);
61119
61120 $this->tokens = $argv;
61121
61122 parent::__construct($definition);
61123 }
61124
61125 protected function setTokens(array $tokens)
61126 {
61127 $this->tokens = $tokens;
61128 }
61129
61130
61131
61132
61133 protected function parse()
61134 {
61135 $parseOptions = true;
61136 $this->parsed = $this->tokens;
61137 while (null !== $token = array_shift($this->parsed)) {
61138 if ($parseOptions && '' == $token) {
61139 $this->parseArgument($token);
61140 } elseif ($parseOptions && '--' == $token) {
61141 $parseOptions = false;
61142 } elseif ($parseOptions && 0 === strpos($token, '--')) {
61143 $this->parseLongOption($token);
61144 } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {
61145 $this->parseShortOption($token);
61146 } else {
61147 $this->parseArgument($token);
61148 }
61149 }
61150 }
61151
61152
61153
61154
61155
61156
61157 private function parseShortOption($token)
61158 {
61159 $name = substr($token, 1);
61160
61161 if (\strlen($name) > 1) {
61162 if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) {
61163
61164 $this->addShortOption($name[0], substr($name, 1));
61165 } else {
61166 $this->parseShortOptionSet($name);
61167 }
61168 } else {
61169 $this->addShortOption($name, null);
61170 }
61171 }
61172
61173
61174
61175
61176
61177
61178
61179
61180 private function parseShortOptionSet($name)
61181 {
61182 $len = \strlen($name);
61183 for ($i = 0; $i < $len; ++$i) {
61184 if (!$this->definition->hasShortcut($name[$i])) {
61185 $encoding = mb_detect_encoding($name, null, true);
61186 throw new RuntimeException(sprintf('The "-%s" option does not exist.', false === $encoding ? $name[$i] : mb_substr($name, $i, 1, $encoding)));
61187 }
61188
61189 $option = $this->definition->getOptionForShortcut($name[$i]);
61190 if ($option->acceptValue()) {
61191 $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));
61192
61193 break;
61194 } else {
61195 $this->addLongOption($option->getName(), null);
61196 }
61197 }
61198 }
61199
61200
61201
61202
61203
61204
61205 private function parseLongOption($token)
61206 {
61207 $name = substr($token, 2);
61208
61209 if (false !== $pos = strpos($name, '=')) {
61210 if (0 === \strlen($value = substr($name, $pos + 1))) {
61211 array_unshift($this->parsed, null);
61212 }
61213 $this->addLongOption(substr($name, 0, $pos), $value);
61214 } else {
61215 $this->addLongOption($name, null);
61216 }
61217 }
61218
61219
61220
61221
61222
61223
61224
61225
61226 private function parseArgument($token)
61227 {
61228 $c = \count($this->arguments);
61229
61230
61231 if ($this->definition->hasArgument($c)) {
61232 $arg = $this->definition->getArgument($c);
61233 $this->arguments[$arg->getName()] = $arg->isArray() ? array($token) : $token;
61234
61235
61236 } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {
61237 $arg = $this->definition->getArgument($c - 1);
61238 $this->arguments[$arg->getName()][] = $token;
61239
61240
61241 } else {
61242 $all = $this->definition->getArguments();
61243 if (\count($all)) {
61244 throw new RuntimeException(sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all))));
61245 }
61246
61247 throw new RuntimeException(sprintf('No arguments expected, got "%s".', $token));
61248 }
61249 }
61250
61251
61252
61253
61254
61255
61256
61257
61258
61259 private function addShortOption($shortcut, $value)
61260 {
61261 if (!$this->definition->hasShortcut($shortcut)) {
61262 throw new RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
61263 }
61264
61265 $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
61266 }
61267
61268
61269
61270
61271
61272
61273
61274
61275
61276 private function addLongOption($name, $value)
61277 {
61278 if (!$this->definition->hasOption($name)) {
61279 throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name));
61280 }
61281
61282 $option = $this->definition->getOption($name);
61283
61284
61285 if (!isset($value[0])) {
61286 $value = null;
61287 }
61288
61289 if (null !== $value && !$option->acceptValue()) {
61290 throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name));
61291 }
61292
61293 if (null === $value && $option->acceptValue() && \count($this->parsed)) {
61294
61295
61296 $next = array_shift($this->parsed);
61297 if (isset($next[0]) && '-' !== $next[0]) {
61298 $value = $next;
61299 } elseif (empty($next)) {
61300 $value = null;
61301 } else {
61302 array_unshift($this->parsed, $next);
61303 }
61304 }
61305
61306 if (null === $value) {
61307 if ($option->isValueRequired()) {
61308 throw new RuntimeException(sprintf('The "--%s" option requires a value.', $name));
61309 }
61310
61311 if (!$option->isArray()) {
61312 $value = $option->isValueOptional() ? $option->getDefault() : true;
61313 }
61314 }
61315
61316 if ($option->isArray()) {
61317 $this->options[$name][] = $value;
61318 } else {
61319 $this->options[$name] = $value;
61320 }
61321 }
61322
61323
61324
61325
61326 public function getFirstArgument()
61327 {
61328 foreach ($this->tokens as $token) {
61329 if ($token && '-' === $token[0]) {
61330 continue;
61331 }
61332
61333 return $token;
61334 }
61335 }
61336
61337
61338
61339
61340 public function hasParameterOption($values)
61341 {
61342 $values = (array) $values;
61343
61344 foreach ($this->tokens as $token) {
61345 foreach ($values as $value) {
61346
61347
61348
61349 $leading = 0 === strpos($value, '--') ? $value.'=' : $value;
61350 if ($token === $value || '' !== $leading && 0 === strpos($token, $leading)) {
61351 return true;
61352 }
61353 }
61354 }
61355
61356 return false;
61357 }
61358
61359
61360
61361
61362 public function getParameterOption($values, $default = false)
61363 {
61364 $values = (array) $values;
61365 $tokens = $this->tokens;
61366
61367 while (0 < \count($tokens)) {
61368 $token = array_shift($tokens);
61369
61370 foreach ($values as $value) {
61371 if ($token === $value) {
61372 return array_shift($tokens);
61373 }
61374
61375
61376
61377 $leading = 0 === strpos($value, '--') ? $value.'=' : $value;
61378 if ('' !== $leading && 0 === strpos($token, $leading)) {
61379 return substr($token, \strlen($leading));
61380 }
61381 }
61382 }
61383
61384 return $default;
61385 }
61386
61387
61388
61389
61390
61391
61392 public function __toString()
61393 {
61394 $self = $this;
61395 $tokens = array_map(function ($token) use ($self) {
61396 if (preg_match('{^(-[^=]+=)(.+)}', $token, $match)) {
61397 return $match[1].$self->escapeToken($match[2]);
61398 }
61399
61400 if ($token && '-' !== $token[0]) {
61401 return $self->escapeToken($token);
61402 }
61403
61404 return $token;
61405 }, $this->tokens);
61406
61407 return implode(' ', $tokens);
61408 }
61409 }
61410 <?php
61411
61412
61413
61414
61415
61416
61417
61418
61419
61420
61421 namespace Symfony\Component\Console\Input;
61422
61423 use Symfony\Component\Console\Exception\InvalidArgumentException;
61424 use Symfony\Component\Console\Exception\InvalidOptionException;
61425
61426
61427
61428
61429
61430
61431
61432
61433
61434
61435 class ArrayInput extends Input
61436 {
61437 private $parameters;
61438
61439 public function __construct(array $parameters, InputDefinition $definition = null)
61440 {
61441 $this->parameters = $parameters;
61442
61443 parent::__construct($definition);
61444 }
61445
61446
61447
61448
61449 public function getFirstArgument()
61450 {
61451 foreach ($this->parameters as $key => $value) {
61452 if ($key && '-' === $key[0]) {
61453 continue;
61454 }
61455
61456 return $value;
61457 }
61458 }
61459
61460
61461
61462
61463 public function hasParameterOption($values)
61464 {
61465 $values = (array) $values;
61466
61467 foreach ($this->parameters as $k => $v) {
61468 if (!\is_int($k)) {
61469 $v = $k;
61470 }
61471
61472 if (\in_array($v, $values)) {
61473 return true;
61474 }
61475 }
61476
61477 return false;
61478 }
61479
61480
61481
61482
61483 public function getParameterOption($values, $default = false)
61484 {
61485 $values = (array) $values;
61486
61487 foreach ($this->parameters as $k => $v) {
61488 if (\is_int($k)) {
61489 if (\in_array($v, $values)) {
61490 return true;
61491 }
61492 } elseif (\in_array($k, $values)) {
61493 return $v;
61494 }
61495 }
61496
61497 return $default;
61498 }
61499
61500
61501
61502
61503
61504
61505 public function __toString()
61506 {
61507 $params = array();
61508 foreach ($this->parameters as $param => $val) {
61509 if ($param && '-' === $param[0]) {
61510 if (\is_array($val)) {
61511 foreach ($val as $v) {
61512 $params[] = $param.('' != $v ? '='.$this->escapeToken($v) : '');
61513 }
61514 } else {
61515 $params[] = $param.('' != $val ? '='.$this->escapeToken($val) : '');
61516 }
61517 } else {
61518 $params[] = \is_array($val) ? implode(' ', array_map(array($this, 'escapeToken'), $val)) : $this->escapeToken($val);
61519 }
61520 }
61521
61522 return implode(' ', $params);
61523 }
61524
61525
61526
61527
61528 protected function parse()
61529 {
61530 foreach ($this->parameters as $key => $value) {
61531 if (0 === strpos($key, '--')) {
61532 $this->addLongOption(substr($key, 2), $value);
61533 } elseif ('-' === $key[0]) {
61534 $this->addShortOption(substr($key, 1), $value);
61535 } else {
61536 $this->addArgument($key, $value);
61537 }
61538 }
61539 }
61540
61541
61542
61543
61544
61545
61546
61547
61548
61549 private function addShortOption($shortcut, $value)
61550 {
61551 if (!$this->definition->hasShortcut($shortcut)) {
61552 throw new InvalidOptionException(sprintf('The "-%s" option does not exist.', $shortcut));
61553 }
61554
61555 $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
61556 }
61557
61558
61559
61560
61561
61562
61563
61564
61565
61566
61567 private function addLongOption($name, $value)
61568 {
61569 if (!$this->definition->hasOption($name)) {
61570 throw new InvalidOptionException(sprintf('The "--%s" option does not exist.', $name));
61571 }
61572
61573 $option = $this->definition->getOption($name);
61574
61575 if (null === $value) {
61576 if ($option->isValueRequired()) {
61577 throw new InvalidOptionException(sprintf('The "--%s" option requires a value.', $name));
61578 }
61579
61580 $value = $option->isValueOptional() ? $option->getDefault() : true;
61581 }
61582
61583 $this->options[$name] = $value;
61584 }
61585
61586
61587
61588
61589
61590
61591
61592
61593
61594 private function addArgument($name, $value)
61595 {
61596 if (!$this->definition->hasArgument($name)) {
61597 throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
61598 }
61599
61600 $this->arguments[$name] = $value;
61601 }
61602 }
61603 <?php
61604
61605
61606
61607
61608
61609
61610
61611
61612
61613
61614 namespace Symfony\Component\Console\Input;
61615
61616 use Symfony\Component\Console\Exception\InvalidArgumentException;
61617 use Symfony\Component\Console\Exception\RuntimeException;
61618
61619
61620
61621
61622
61623
61624
61625
61626
61627
61628
61629
61630 abstract class Input implements InputInterface
61631 {
61632 protected $definition;
61633 protected $options = array();
61634 protected $arguments = array();
61635 protected $interactive = true;
61636
61637 public function __construct(InputDefinition $definition = null)
61638 {
61639 if (null === $definition) {
61640 $this->definition = new InputDefinition();
61641 } else {
61642 $this->bind($definition);
61643 $this->validate();
61644 }
61645 }
61646
61647
61648
61649
61650 public function bind(InputDefinition $definition)
61651 {
61652 $this->arguments = array();
61653 $this->options = array();
61654 $this->definition = $definition;
61655
61656 $this->parse();
61657 }
61658
61659
61660
61661
61662 abstract protected function parse();
61663
61664
61665
61666
61667 public function validate()
61668 {
61669 $definition = $this->definition;
61670 $givenArguments = $this->arguments;
61671
61672 $missingArguments = array_filter(array_keys($definition->getArguments()), function ($argument) use ($definition, $givenArguments) {
61673 return !array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired();
61674 });
61675
61676 if (\count($missingArguments) > 0) {
61677 throw new RuntimeException(sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments)));
61678 }
61679 }
61680
61681
61682
61683
61684 public function isInteractive()
61685 {
61686 return $this->interactive;
61687 }
61688
61689
61690
61691
61692 public function setInteractive($interactive)
61693 {
61694 $this->interactive = (bool) $interactive;
61695 }
61696
61697
61698
61699
61700 public function getArguments()
61701 {
61702 return array_merge($this->definition->getArgumentDefaults(), $this->arguments);
61703 }
61704
61705
61706
61707
61708 public function getArgument($name)
61709 {
61710 if (!$this->definition->hasArgument($name)) {
61711 throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
61712 }
61713
61714 return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name)->getDefault();
61715 }
61716
61717
61718
61719
61720 public function setArgument($name, $value)
61721 {
61722 if (!$this->definition->hasArgument($name)) {
61723 throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
61724 }
61725
61726 $this->arguments[$name] = $value;
61727 }
61728
61729
61730
61731
61732 public function hasArgument($name)
61733 {
61734 return $this->definition->hasArgument($name);
61735 }
61736
61737
61738
61739
61740 public function getOptions()
61741 {
61742 return array_merge($this->definition->getOptionDefaults(), $this->options);
61743 }
61744
61745
61746
61747
61748 public function getOption($name)
61749 {
61750 if (!$this->definition->hasOption($name)) {
61751 throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
61752 }
61753
61754 return isset($this->options[$name]) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
61755 }
61756
61757
61758
61759
61760 public function setOption($name, $value)
61761 {
61762 if (!$this->definition->hasOption($name)) {
61763 throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
61764 }
61765
61766 $this->options[$name] = $value;
61767 }
61768
61769
61770
61771
61772 public function hasOption($name)
61773 {
61774 return $this->definition->hasOption($name);
61775 }
61776
61777
61778
61779
61780
61781
61782
61783
61784 public function escapeToken($token)
61785 {
61786 return preg_match('{^[\w-]+$}', $token) ? $token : escapeshellarg($token);
61787 }
61788 }
61789 <?php
61790
61791
61792
61793
61794
61795
61796
61797
61798
61799
61800 namespace Symfony\Component\Console\Input;
61801
61802 use Symfony\Component\Console\Exception\InvalidArgumentException;
61803 use Symfony\Component\Console\Exception\LogicException;
61804
61805
61806
61807
61808
61809
61810 class InputArgument
61811 {
61812 const REQUIRED = 1;
61813 const OPTIONAL = 2;
61814 const IS_ARRAY = 4;
61815
61816 private $name;
61817 private $mode;
61818 private $default;
61819 private $description;
61820
61821
61822
61823
61824
61825
61826
61827
61828
61829 public function __construct($name, $mode = null, $description = '', $default = null)
61830 {
61831 if (null === $mode) {
61832 $mode = self::OPTIONAL;
61833 } elseif (!\is_int($mode) || $mode > 7 || $mode < 1) {
61834 throw new InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode));
61835 }
61836
61837 $this->name = $name;
61838 $this->mode = $mode;
61839 $this->description = $description;
61840
61841 $this->setDefault($default);
61842 }
61843
61844
61845
61846
61847
61848
61849 public function getName()
61850 {
61851 return $this->name;
61852 }
61853
61854
61855
61856
61857
61858
61859 public function isRequired()
61860 {
61861 return self::REQUIRED === (self::REQUIRED & $this->mode);
61862 }
61863
61864
61865
61866
61867
61868
61869 public function isArray()
61870 {
61871 return self::IS_ARRAY === (self::IS_ARRAY & $this->mode);
61872 }
61873
61874
61875
61876
61877
61878
61879
61880
61881 public function setDefault($default = null)
61882 {
61883 if (self::REQUIRED === $this->mode && null !== $default) {
61884 throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.');
61885 }
61886
61887 if ($this->isArray()) {
61888 if (null === $default) {
61889 $default = array();
61890 } elseif (!\is_array($default)) {
61891 throw new LogicException('A default value for an array argument must be an array.');
61892 }
61893 }
61894
61895 $this->default = $default;
61896 }
61897
61898
61899
61900
61901
61902
61903 public function getDefault()
61904 {
61905 return $this->default;
61906 }
61907
61908
61909
61910
61911
61912
61913 public function getDescription()
61914 {
61915 return $this->description;
61916 }
61917 }
61918 <?php
61919
61920
61921
61922
61923
61924
61925
61926
61927
61928
61929 namespace Symfony\Component\Console\Input;
61930
61931
61932
61933
61934
61935
61936
61937 interface InputAwareInterface
61938 {
61939
61940
61941
61942 public function setInput(InputInterface $input);
61943 }
61944 <?php
61945
61946
61947
61948
61949
61950
61951
61952
61953
61954
61955 namespace Symfony\Component\Console\Input;
61956
61957 use Symfony\Component\Console\Descriptor\TextDescriptor;
61958 use Symfony\Component\Console\Descriptor\XmlDescriptor;
61959 use Symfony\Component\Console\Exception\InvalidArgumentException;
61960 use Symfony\Component\Console\Exception\LogicException;
61961 use Symfony\Component\Console\Output\BufferedOutput;
61962
61963
61964
61965
61966
61967
61968
61969
61970
61971
61972
61973
61974
61975 class InputDefinition
61976 {
61977 private $arguments;
61978 private $requiredCount;
61979 private $hasAnArrayArgument = false;
61980 private $hasOptional;
61981 private $options;
61982 private $shortcuts;
61983
61984
61985
61986
61987 public function __construct(array $definition = array())
61988 {
61989 $this->setDefinition($definition);
61990 }
61991
61992
61993
61994
61995 public function setDefinition(array $definition)
61996 {
61997 $arguments = array();
61998 $options = array();
61999 foreach ($definition as $item) {
62000 if ($item instanceof InputOption) {
62001 $options[] = $item;
62002 } else {
62003 $arguments[] = $item;
62004 }
62005 }
62006
62007 $this->setArguments($arguments);
62008 $this->setOptions($options);
62009 }
62010
62011
62012
62013
62014
62015
62016 public function setArguments($arguments = array())
62017 {
62018 $this->arguments = array();
62019 $this->requiredCount = 0;
62020 $this->hasOptional = false;
62021 $this->hasAnArrayArgument = false;
62022 $this->addArguments($arguments);
62023 }
62024
62025
62026
62027
62028
62029
62030 public function addArguments($arguments = array())
62031 {
62032 if (null !== $arguments) {
62033 foreach ($arguments as $argument) {
62034 $this->addArgument($argument);
62035 }
62036 }
62037 }
62038
62039
62040
62041
62042 public function addArgument(InputArgument $argument)
62043 {
62044 if (isset($this->arguments[$argument->getName()])) {
62045 throw new LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName()));
62046 }
62047
62048 if ($this->hasAnArrayArgument) {
62049 throw new LogicException('Cannot add an argument after an array argument.');
62050 }
62051
62052 if ($argument->isRequired() && $this->hasOptional) {
62053 throw new LogicException('Cannot add a required argument after an optional one.');
62054 }
62055
62056 if ($argument->isArray()) {
62057 $this->hasAnArrayArgument = true;
62058 }
62059
62060 if ($argument->isRequired()) {
62061 ++$this->requiredCount;
62062 } else {
62063 $this->hasOptional = true;
62064 }
62065
62066 $this->arguments[$argument->getName()] = $argument;
62067 }
62068
62069
62070
62071
62072
62073
62074
62075
62076
62077
62078 public function getArgument($name)
62079 {
62080 if (!$this->hasArgument($name)) {
62081 throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
62082 }
62083
62084 $arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments;
62085
62086 return $arguments[$name];
62087 }
62088
62089
62090
62091
62092
62093
62094
62095
62096 public function hasArgument($name)
62097 {
62098 $arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments;
62099
62100 return isset($arguments[$name]);
62101 }
62102
62103
62104
62105
62106
62107
62108 public function getArguments()
62109 {
62110 return $this->arguments;
62111 }
62112
62113
62114
62115
62116
62117
62118 public function getArgumentCount()
62119 {
62120 return $this->hasAnArrayArgument ? PHP_INT_MAX : \count($this->arguments);
62121 }
62122
62123
62124
62125
62126
62127
62128 public function getArgumentRequiredCount()
62129 {
62130 return $this->requiredCount;
62131 }
62132
62133
62134
62135
62136
62137
62138 public function getArgumentDefaults()
62139 {
62140 $values = array();
62141 foreach ($this->arguments as $argument) {
62142 $values[$argument->getName()] = $argument->getDefault();
62143 }
62144
62145 return $values;
62146 }
62147
62148
62149
62150
62151
62152
62153 public function setOptions($options = array())
62154 {
62155 $this->options = array();
62156 $this->shortcuts = array();
62157 $this->addOptions($options);
62158 }
62159
62160
62161
62162
62163
62164
62165 public function addOptions($options = array())
62166 {
62167 foreach ($options as $option) {
62168 $this->addOption($option);
62169 }
62170 }
62171
62172
62173
62174
62175 public function addOption(InputOption $option)
62176 {
62177 if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) {
62178 throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName()));
62179 }
62180
62181 if ($option->getShortcut()) {
62182 foreach (explode('|', $option->getShortcut()) as $shortcut) {
62183 if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) {
62184 throw new LogicException(sprintf('An option with shortcut "%s" already exists.', $shortcut));
62185 }
62186 }
62187 }
62188
62189 $this->options[$option->getName()] = $option;
62190 if ($option->getShortcut()) {
62191 foreach (explode('|', $option->getShortcut()) as $shortcut) {
62192 $this->shortcuts[$shortcut] = $option->getName();
62193 }
62194 }
62195 }
62196
62197
62198
62199
62200
62201
62202
62203
62204
62205
62206 public function getOption($name)
62207 {
62208 if (!$this->hasOption($name)) {
62209 throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
62210 }
62211
62212 return $this->options[$name];
62213 }
62214
62215
62216
62217
62218
62219
62220
62221
62222
62223
62224
62225 public function hasOption($name)
62226 {
62227 return isset($this->options[$name]);
62228 }
62229
62230
62231
62232
62233
62234
62235 public function getOptions()
62236 {
62237 return $this->options;
62238 }
62239
62240
62241
62242
62243
62244
62245
62246
62247 public function hasShortcut($name)
62248 {
62249 return isset($this->shortcuts[$name]);
62250 }
62251
62252
62253
62254
62255
62256
62257
62258
62259 public function getOptionForShortcut($shortcut)
62260 {
62261 return $this->getOption($this->shortcutToName($shortcut));
62262 }
62263
62264
62265
62266
62267
62268
62269 public function getOptionDefaults()
62270 {
62271 $values = array();
62272 foreach ($this->options as $option) {
62273 $values[$option->getName()] = $option->getDefault();
62274 }
62275
62276 return $values;
62277 }
62278
62279
62280
62281
62282
62283
62284
62285
62286
62287
62288 private function shortcutToName($shortcut)
62289 {
62290 if (!isset($this->shortcuts[$shortcut])) {
62291 throw new InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
62292 }
62293
62294 return $this->shortcuts[$shortcut];
62295 }
62296
62297
62298
62299
62300
62301
62302
62303
62304 public function getSynopsis($short = false)
62305 {
62306 $elements = array();
62307
62308 if ($short && $this->getOptions()) {
62309 $elements[] = '[options]';
62310 } elseif (!$short) {
62311 foreach ($this->getOptions() as $option) {
62312 $value = '';
62313 if ($option->acceptValue()) {
62314 $value = sprintf(
62315 ' %s%s%s',
62316 $option->isValueOptional() ? '[' : '',
62317 strtoupper($option->getName()),
62318 $option->isValueOptional() ? ']' : ''
62319 );
62320 }
62321
62322 $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';
62323 $elements[] = sprintf('[%s--%s%s]', $shortcut, $option->getName(), $value);
62324 }
62325 }
62326
62327 if (\count($elements) && $this->getArguments()) {
62328 $elements[] = '[--]';
62329 }
62330
62331 foreach ($this->getArguments() as $argument) {
62332 $element = '<'.$argument->getName().'>';
62333 if (!$argument->isRequired()) {
62334 $element = '['.$element.']';
62335 } elseif ($argument->isArray()) {
62336 $element .= ' ('.$element.')';
62337 }
62338
62339 if ($argument->isArray()) {
62340 $element .= '...';
62341 }
62342
62343 $elements[] = $element;
62344 }
62345
62346 return implode(' ', $elements);
62347 }
62348
62349
62350
62351
62352
62353
62354
62355
62356 public function asText()
62357 {
62358 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);
62359
62360 $descriptor = new TextDescriptor();
62361 $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true);
62362 $descriptor->describe($output, $this, array('raw_output' => true));
62363
62364 return $output->fetch();
62365 }
62366
62367
62368
62369
62370
62371
62372
62373
62374
62375
62376 public function asXml($asDom = false)
62377 {
62378 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);
62379
62380 $descriptor = new XmlDescriptor();
62381
62382 if ($asDom) {
62383 return $descriptor->getInputDefinitionDocument($this);
62384 }
62385
62386 $output = new BufferedOutput();
62387 $descriptor->describe($output, $this);
62388
62389 return $output->fetch();
62390 }
62391 }
62392 <?php
62393
62394
62395
62396
62397
62398
62399
62400
62401
62402
62403 namespace Symfony\Component\Console\Input;
62404
62405 use Symfony\Component\Console\Exception\InvalidArgumentException;
62406 use Symfony\Component\Console\Exception\RuntimeException;
62407
62408
62409
62410
62411
62412
62413 interface InputInterface
62414 {
62415
62416
62417
62418
62419
62420 public function getFirstArgument();
62421
62422
62423
62424
62425
62426
62427
62428
62429
62430
62431
62432
62433
62434 public function hasParameterOption($values);
62435
62436
62437
62438
62439
62440
62441
62442
62443
62444
62445
62446
62447
62448
62449 public function getParameterOption($values, $default = false);
62450
62451
62452
62453
62454
62455
62456 public function bind(InputDefinition $definition);
62457
62458
62459
62460
62461
62462
62463 public function validate();
62464
62465
62466
62467
62468
62469
62470 public function getArguments();
62471
62472
62473
62474
62475
62476
62477
62478
62479
62480
62481 public function getArgument($name);
62482
62483
62484
62485
62486
62487
62488
62489
62490
62491 public function setArgument($name, $value);
62492
62493
62494
62495
62496
62497
62498
62499
62500 public function hasArgument($name);
62501
62502
62503
62504
62505
62506
62507 public function getOptions();
62508
62509
62510
62511
62512
62513
62514
62515
62516
62517
62518 public function getOption($name);
62519
62520
62521
62522
62523
62524
62525
62526
62527
62528 public function setOption($name, $value);
62529
62530
62531
62532
62533
62534
62535
62536
62537 public function hasOption($name);
62538
62539
62540
62541
62542
62543
62544 public function isInteractive();
62545
62546
62547
62548
62549
62550
62551 public function setInteractive($interactive);
62552 }
62553 <?php
62554
62555
62556
62557
62558
62559
62560
62561
62562
62563
62564 namespace Symfony\Component\Console\Input;
62565
62566 use Symfony\Component\Console\Exception\InvalidArgumentException;
62567 use Symfony\Component\Console\Exception\LogicException;
62568
62569
62570
62571
62572
62573
62574 class InputOption
62575 {
62576 const VALUE_NONE = 1;
62577 const VALUE_REQUIRED = 2;
62578 const VALUE_OPTIONAL = 4;
62579 const VALUE_IS_ARRAY = 8;
62580
62581 private $name;
62582 private $shortcut;
62583 private $mode;
62584 private $default;
62585 private $description;
62586
62587
62588
62589
62590
62591
62592
62593
62594
62595
62596 public function __construct($name, $shortcut = null, $mode = null, $description = '', $default = null)
62597 {
62598 if (0 === strpos($name, '--')) {
62599 $name = substr($name, 2);
62600 }
62601
62602 if (empty($name)) {
62603 throw new InvalidArgumentException('An option name cannot be empty.');
62604 }
62605
62606 if (empty($shortcut)) {
62607 $shortcut = null;
62608 }
62609
62610 if (null !== $shortcut) {
62611 if (\is_array($shortcut)) {
62612 $shortcut = implode('|', $shortcut);
62613 }
62614 $shortcuts = preg_split('{(\|)-?}', ltrim($shortcut, '-'));
62615 $shortcuts = array_filter($shortcuts);
62616 $shortcut = implode('|', $shortcuts);
62617
62618 if (empty($shortcut)) {
62619 throw new InvalidArgumentException('An option shortcut cannot be empty.');
62620 }
62621 }
62622
62623 if (null === $mode) {
62624 $mode = self::VALUE_NONE;
62625 } elseif (!\is_int($mode) || $mode > 15 || $mode < 1) {
62626 throw new InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode));
62627 }
62628
62629 $this->name = $name;
62630 $this->shortcut = $shortcut;
62631 $this->mode = $mode;
62632 $this->description = $description;
62633
62634 if ($this->isArray() && !$this->acceptValue()) {
62635 throw new InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.');
62636 }
62637
62638 $this->setDefault($default);
62639 }
62640
62641
62642
62643
62644
62645
62646 public function getShortcut()
62647 {
62648 return $this->shortcut;
62649 }
62650
62651
62652
62653
62654
62655
62656 public function getName()
62657 {
62658 return $this->name;
62659 }
62660
62661
62662
62663
62664
62665
62666 public function acceptValue()
62667 {
62668 return $this->isValueRequired() || $this->isValueOptional();
62669 }
62670
62671
62672
62673
62674
62675
62676 public function isValueRequired()
62677 {
62678 return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode);
62679 }
62680
62681
62682
62683
62684
62685
62686 public function isValueOptional()
62687 {
62688 return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode);
62689 }
62690
62691
62692
62693
62694
62695
62696 public function isArray()
62697 {
62698 return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode);
62699 }
62700
62701
62702
62703
62704
62705
62706
62707
62708 public function setDefault($default = null)
62709 {
62710 if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) {
62711 throw new LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.');
62712 }
62713
62714 if ($this->isArray()) {
62715 if (null === $default) {
62716 $default = array();
62717 } elseif (!\is_array($default)) {
62718 throw new LogicException('A default value for an array option must be an array.');
62719 }
62720 }
62721
62722 $this->default = $this->acceptValue() ? $default : false;
62723 }
62724
62725
62726
62727
62728
62729
62730 public function getDefault()
62731 {
62732 return $this->default;
62733 }
62734
62735
62736
62737
62738
62739
62740 public function getDescription()
62741 {
62742 return $this->description;
62743 }
62744
62745
62746
62747
62748
62749
62750 public function equals(self $option)
62751 {
62752 return $option->getName() === $this->getName()
62753 && $option->getShortcut() === $this->getShortcut()
62754 && $option->getDefault() === $this->getDefault()
62755 && $option->isArray() === $this->isArray()
62756 && $option->isValueRequired() === $this->isValueRequired()
62757 && $option->isValueOptional() === $this->isValueOptional()
62758 ;
62759 }
62760 }
62761 <?php
62762
62763
62764
62765
62766
62767
62768
62769
62770
62771
62772 namespace Symfony\Component\Console\Input;
62773
62774 use Symfony\Component\Console\Exception\InvalidArgumentException;
62775
62776
62777
62778
62779
62780
62781
62782
62783
62784
62785 class StringInput extends ArgvInput
62786 {
62787 const REGEX_STRING = '([^\s]+?)(?:\s|(?<!\\\\)"|(?<!\\\\)\'|$)';
62788 const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';
62789
62790
62791
62792
62793
62794
62795
62796 public function __construct($input, InputDefinition $definition = null)
62797 {
62798 if ($definition) {
62799 @trigger_error('The $definition argument of the '.__METHOD__.' method is deprecated and will be removed in 3.0. Set this parameter with the bind() method instead.', E_USER_DEPRECATED);
62800 }
62801
62802 parent::__construct(array(), null);
62803
62804 $this->setTokens($this->tokenize($input));
62805
62806 if (null !== $definition) {
62807 $this->bind($definition);
62808 }
62809 }
62810
62811
62812
62813
62814
62815
62816
62817
62818
62819
62820 private function tokenize($input)
62821 {
62822 $tokens = array();
62823 $length = \strlen($input);
62824 $cursor = 0;
62825 while ($cursor < $length) {
62826 if (preg_match('/\s+/A', $input, $match, null, $cursor)) {
62827 } elseif (preg_match('/([^="\'\s]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, null, $cursor)) {
62828 $tokens[] = $match[1].$match[2].stripcslashes(str_replace(array('"\'', '\'"', '\'\'', '""'), '', substr($match[3], 1, \strlen($match[3]) - 2)));
62829 } elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, null, $cursor)) {
62830 $tokens[] = stripcslashes(substr($match[0], 1, \strlen($match[0]) - 2));
62831 } elseif (preg_match('/'.self::REGEX_STRING.'/A', $input, $match, null, $cursor)) {
62832 $tokens[] = stripcslashes($match[1]);
62833 } else {
62834
62835 throw new InvalidArgumentException(sprintf('Unable to parse input near "... %s ..."', substr($input, $cursor, 10)));
62836 }
62837
62838 $cursor += \strlen($match[0]);
62839 }
62840
62841 return $tokens;
62842 }
62843 }
62844 Copyright (c) 2004-2018 Fabien Potencier
62845
62846 Permission is hereby granted, free of charge, to any person obtaining a copy
62847 of this software and associated documentation files (the "Software"), to deal
62848 in the Software without restriction, including without limitation the rights
62849 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
62850 copies of the Software, and to permit persons to whom the Software is furnished
62851 to do so, subject to the following conditions:
62852
62853 The above copyright notice and this permission notice shall be included in all
62854 copies or substantial portions of the Software.
62855
62856 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
62857 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62858 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
62859 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
62860 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
62861 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
62862 THE SOFTWARE.
62863 <?php
62864
62865
62866
62867
62868
62869
62870
62871
62872
62873
62874 namespace Symfony\Component\Console\Logger;
62875
62876 use Psr\Log\AbstractLogger;
62877 use Psr\Log\InvalidArgumentException;
62878 use Psr\Log\LogLevel;
62879 use Symfony\Component\Console\Output\ConsoleOutputInterface;
62880 use Symfony\Component\Console\Output\OutputInterface;
62881
62882
62883
62884
62885
62886
62887
62888
62889 class ConsoleLogger extends AbstractLogger
62890 {
62891 const INFO = 'info';
62892 const ERROR = 'error';
62893
62894 private $output;
62895 private $verbosityLevelMap = array(
62896 LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL,
62897 LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL,
62898 LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL,
62899 LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL,
62900 LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL,
62901 LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE,
62902 LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE,
62903 LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG,
62904 );
62905 private $formatLevelMap = array(
62906 LogLevel::EMERGENCY => self::ERROR,
62907 LogLevel::ALERT => self::ERROR,
62908 LogLevel::CRITICAL => self::ERROR,
62909 LogLevel::ERROR => self::ERROR,
62910 LogLevel::WARNING => self::INFO,
62911 LogLevel::NOTICE => self::INFO,
62912 LogLevel::INFO => self::INFO,
62913 LogLevel::DEBUG => self::INFO,
62914 );
62915
62916 public function __construct(OutputInterface $output, array $verbosityLevelMap = array(), array $formatLevelMap = array())
62917 {
62918 $this->output = $output;
62919 $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap;
62920 $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap;
62921 }
62922
62923
62924
62925
62926 public function log($level, $message, array $context = array())
62927 {
62928 if (!isset($this->verbosityLevelMap[$level])) {
62929 throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level));
62930 }
62931
62932
62933 if (self::ERROR === $this->formatLevelMap[$level] && $this->output instanceof ConsoleOutputInterface) {
62934 $output = $this->output->getErrorOutput();
62935 } else {
62936 $output = $this->output;
62937 }
62938
62939 if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) {
62940 $output->writeln(sprintf('<%1$s>[%2$s] %3$s</%1$s>', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)));
62941 }
62942 }
62943
62944
62945
62946
62947
62948
62949
62950
62951
62952
62953
62954 private function interpolate($message, array $context)
62955 {
62956
62957 $replace = array();
62958 foreach ($context as $key => $val) {
62959 if (!\is_array($val) && (!\is_object($val) || method_exists($val, '__toString'))) {
62960 $replace[sprintf('{%s}', $key)] = $val;
62961 }
62962 }
62963
62964
62965 return strtr($message, $replace);
62966 }
62967 }
62968 <?php
62969
62970
62971
62972
62973
62974
62975
62976
62977
62978
62979 namespace Symfony\Component\Console\Output;
62980
62981
62982
62983
62984 class BufferedOutput extends Output
62985 {
62986 private $buffer = '';
62987
62988
62989
62990
62991
62992
62993 public function fetch()
62994 {
62995 $content = $this->buffer;
62996 $this->buffer = '';
62997
62998 return $content;
62999 }
63000
63001
63002
63003
63004 protected function doWrite($message, $newline)
63005 {
63006 $this->buffer .= $message;
63007
63008 if ($newline) {
63009 $this->buffer .= PHP_EOL;
63010 }
63011 }
63012 }
63013 <?php
63014
63015
63016
63017
63018
63019
63020
63021
63022
63023
63024 namespace Symfony\Component\Console\Output;
63025
63026 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
63027
63028
63029
63030
63031
63032
63033
63034
63035
63036
63037
63038
63039
63040
63041 class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
63042 {
63043 private $stderr;
63044
63045
63046
63047
63048
63049
63050 public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null)
63051 {
63052 parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter);
63053
63054 $actualDecorated = $this->isDecorated();
63055 $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated, $this->getFormatter());
63056
63057 if (null === $decorated) {
63058 $this->setDecorated($actualDecorated && $this->stderr->isDecorated());
63059 }
63060 }
63061
63062
63063
63064
63065 public function setDecorated($decorated)
63066 {
63067 parent::setDecorated($decorated);
63068 $this->stderr->setDecorated($decorated);
63069 }
63070
63071
63072
63073
63074 public function setFormatter(OutputFormatterInterface $formatter)
63075 {
63076 parent::setFormatter($formatter);
63077 $this->stderr->setFormatter($formatter);
63078 }
63079
63080
63081
63082
63083 public function setVerbosity($level)
63084 {
63085 parent::setVerbosity($level);
63086 $this->stderr->setVerbosity($level);
63087 }
63088
63089
63090
63091
63092 public function getErrorOutput()
63093 {
63094 return $this->stderr;
63095 }
63096
63097
63098
63099
63100 public function setErrorOutput(OutputInterface $error)
63101 {
63102 $this->stderr = $error;
63103 }
63104
63105
63106
63107
63108
63109
63110
63111 protected function hasStdoutSupport()
63112 {
63113 return false === $this->isRunningOS400();
63114 }
63115
63116
63117
63118
63119
63120
63121
63122 protected function hasStderrSupport()
63123 {
63124 return false === $this->isRunningOS400();
63125 }
63126
63127
63128
63129
63130
63131
63132
63133 private function isRunningOS400()
63134 {
63135 $checks = array(
63136 \function_exists('php_uname') ? php_uname('s') : '',
63137 getenv('OSTYPE'),
63138 PHP_OS,
63139 );
63140
63141 return false !== stripos(implode(';', $checks), 'OS400');
63142 }
63143
63144
63145
63146
63147 private function openOutputStream()
63148 {
63149 $outputStream = $this->hasStdoutSupport() ? 'php://stdout' : 'php://output';
63150
63151 return @fopen($outputStream, 'w') ?: fopen('php://output', 'w');
63152 }
63153
63154
63155
63156
63157 private function openErrorStream()
63158 {
63159 $errorStream = $this->hasStderrSupport() ? 'php://stderr' : 'php://output';
63160
63161 return fopen($errorStream, 'w');
63162 }
63163 }
63164 <?php
63165
63166
63167
63168
63169
63170
63171
63172
63173
63174
63175 namespace Symfony\Component\Console\Output;
63176
63177
63178
63179
63180
63181
63182
63183 interface ConsoleOutputInterface extends OutputInterface
63184 {
63185
63186
63187
63188
63189
63190 public function getErrorOutput();
63191
63192 public function setErrorOutput(OutputInterface $error);
63193 }
63194 <?php
63195
63196
63197
63198
63199
63200
63201
63202
63203
63204
63205 namespace Symfony\Component\Console\Output;
63206
63207 use Symfony\Component\Console\Formatter\OutputFormatter;
63208 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
63209
63210
63211
63212
63213
63214
63215
63216
63217
63218 class NullOutput implements OutputInterface
63219 {
63220
63221
63222
63223 public function setFormatter(OutputFormatterInterface $formatter)
63224 {
63225
63226 }
63227
63228
63229
63230
63231 public function getFormatter()
63232 {
63233
63234 return new OutputFormatter();
63235 }
63236
63237
63238
63239
63240 public function setDecorated($decorated)
63241 {
63242
63243 }
63244
63245
63246
63247
63248 public function isDecorated()
63249 {
63250 return false;
63251 }
63252
63253
63254
63255
63256 public function setVerbosity($level)
63257 {
63258
63259 }
63260
63261
63262
63263
63264 public function getVerbosity()
63265 {
63266 return self::VERBOSITY_QUIET;
63267 }
63268
63269
63270
63271
63272 public function isQuiet()
63273 {
63274 return true;
63275 }
63276
63277
63278
63279
63280 public function isVerbose()
63281 {
63282 return false;
63283 }
63284
63285
63286
63287
63288 public function isVeryVerbose()
63289 {
63290 return false;
63291 }
63292
63293
63294
63295
63296 public function isDebug()
63297 {
63298 return false;
63299 }
63300
63301
63302
63303
63304 public function writeln($messages, $options = self::OUTPUT_NORMAL)
63305 {
63306
63307 }
63308
63309
63310
63311
63312 public function write($messages, $newline = false, $options = self::OUTPUT_NORMAL)
63313 {
63314
63315 }
63316 }
63317 <?php
63318
63319
63320
63321
63322
63323
63324
63325
63326
63327
63328 namespace Symfony\Component\Console\Output;
63329
63330 use Symfony\Component\Console\Formatter\OutputFormatter;
63331 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
63332
63333
63334
63335
63336
63337
63338
63339
63340
63341
63342
63343
63344
63345
63346 abstract class Output implements OutputInterface
63347 {
63348 private $verbosity;
63349 private $formatter;
63350
63351
63352
63353
63354
63355
63356 public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = false, OutputFormatterInterface $formatter = null)
63357 {
63358 $this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity;
63359 $this->formatter = $formatter ?: new OutputFormatter();
63360 $this->formatter->setDecorated($decorated);
63361 }
63362
63363
63364
63365
63366 public function setFormatter(OutputFormatterInterface $formatter)
63367 {
63368 $this->formatter = $formatter;
63369 }
63370
63371
63372
63373
63374 public function getFormatter()
63375 {
63376 return $this->formatter;
63377 }
63378
63379
63380
63381
63382 public function setDecorated($decorated)
63383 {
63384 $this->formatter->setDecorated($decorated);
63385 }
63386
63387
63388
63389
63390 public function isDecorated()
63391 {
63392 return $this->formatter->isDecorated();
63393 }
63394
63395
63396
63397
63398 public function setVerbosity($level)
63399 {
63400 $this->verbosity = (int) $level;
63401 }
63402
63403
63404
63405
63406 public function getVerbosity()
63407 {
63408 return $this->verbosity;
63409 }
63410
63411
63412
63413
63414 public function isQuiet()
63415 {
63416 return self::VERBOSITY_QUIET === $this->verbosity;
63417 }
63418
63419
63420
63421
63422 public function isVerbose()
63423 {
63424 return self::VERBOSITY_VERBOSE <= $this->verbosity;
63425 }
63426
63427
63428
63429
63430 public function isVeryVerbose()
63431 {
63432 return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity;
63433 }
63434
63435
63436
63437
63438 public function isDebug()
63439 {
63440 return self::VERBOSITY_DEBUG <= $this->verbosity;
63441 }
63442
63443
63444
63445
63446 public function writeln($messages, $options = self::OUTPUT_NORMAL)
63447 {
63448 $this->write($messages, true, $options);
63449 }
63450
63451
63452
63453
63454 public function write($messages, $newline = false, $options = self::OUTPUT_NORMAL)
63455 {
63456 $messages = (array) $messages;
63457
63458 $types = self::OUTPUT_NORMAL | self::OUTPUT_RAW | self::OUTPUT_PLAIN;
63459 $type = $types & $options ?: self::OUTPUT_NORMAL;
63460
63461 $verbosities = self::VERBOSITY_QUIET | self::VERBOSITY_NORMAL | self::VERBOSITY_VERBOSE | self::VERBOSITY_VERY_VERBOSE | self::VERBOSITY_DEBUG;
63462 $verbosity = $verbosities & $options ?: self::VERBOSITY_NORMAL;
63463
63464 if ($verbosity > $this->getVerbosity()) {
63465 return;
63466 }
63467
63468 foreach ($messages as $message) {
63469 switch ($type) {
63470 case OutputInterface::OUTPUT_NORMAL:
63471 $message = $this->formatter->format($message);
63472 break;
63473 case OutputInterface::OUTPUT_RAW:
63474 break;
63475 case OutputInterface::OUTPUT_PLAIN:
63476 $message = strip_tags($this->formatter->format($message));
63477 break;
63478 }
63479
63480 $this->doWrite($message, $newline);
63481 }
63482 }
63483
63484
63485
63486
63487
63488
63489
63490 abstract protected function doWrite($message, $newline);
63491 }
63492 <?php
63493
63494
63495
63496
63497
63498
63499
63500
63501
63502
63503 namespace Symfony\Component\Console\Output;
63504
63505 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
63506
63507
63508
63509
63510
63511
63512 interface OutputInterface
63513 {
63514 const VERBOSITY_QUIET = 16;
63515 const VERBOSITY_NORMAL = 32;
63516 const VERBOSITY_VERBOSE = 64;
63517 const VERBOSITY_VERY_VERBOSE = 128;
63518 const VERBOSITY_DEBUG = 256;
63519
63520 const OUTPUT_NORMAL = 1;
63521 const OUTPUT_RAW = 2;
63522 const OUTPUT_PLAIN = 4;
63523
63524
63525
63526
63527
63528
63529
63530
63531 public function write($messages, $newline = false, $options = 0);
63532
63533
63534
63535
63536
63537
63538
63539 public function writeln($messages, $options = 0);
63540
63541
63542
63543
63544
63545
63546 public function setVerbosity($level);
63547
63548
63549
63550
63551
63552
63553 public function getVerbosity();
63554
63555
63556
63557
63558
63559
63560 public function setDecorated($decorated);
63561
63562
63563
63564
63565
63566
63567 public function isDecorated();
63568
63569 public function setFormatter(OutputFormatterInterface $formatter);
63570
63571
63572
63573
63574
63575
63576 public function getFormatter();
63577 }
63578 <?php
63579
63580
63581
63582
63583
63584
63585
63586
63587
63588
63589 namespace Symfony\Component\Console\Output;
63590
63591 use Symfony\Component\Console\Exception\InvalidArgumentException;
63592 use Symfony\Component\Console\Exception\RuntimeException;
63593 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
63594
63595
63596
63597
63598
63599
63600
63601
63602
63603
63604
63605
63606
63607
63608 class StreamOutput extends Output
63609 {
63610 private $stream;
63611
63612
63613
63614
63615
63616
63617
63618
63619
63620 public function __construct($stream, $verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null)
63621 {
63622 if (!\is_resource($stream) || 'stream' !== get_resource_type($stream)) {
63623 throw new InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
63624 }
63625
63626 $this->stream = $stream;
63627
63628 if (null === $decorated) {
63629 $decorated = $this->hasColorSupport();
63630 }
63631
63632 parent::__construct($verbosity, $decorated, $formatter);
63633 }
63634
63635
63636
63637
63638
63639
63640 public function getStream()
63641 {
63642 return $this->stream;
63643 }
63644
63645
63646
63647
63648 protected function doWrite($message, $newline)
63649 {
63650 if ($newline) {
63651 $message .= PHP_EOL;
63652 }
63653
63654 if (false === @fwrite($this->stream, $message)) {
63655
63656 throw new RuntimeException('Unable to write output.');
63657 }
63658
63659 fflush($this->stream);
63660 }
63661
63662
63663
63664
63665
63666
63667
63668
63669
63670
63671
63672
63673
63674
63675 protected function hasColorSupport()
63676 {
63677 if ('Hyper' === getenv('TERM_PROGRAM')) {
63678 return true;
63679 }
63680
63681 if (\DIRECTORY_SEPARATOR === '\\') {
63682 return (\function_exists('sapi_windows_vt100_support')
63683 && @sapi_windows_vt100_support($this->stream))
63684 || false !== getenv('ANSICON')
63685 || 'ON' === getenv('ConEmuANSI')
63686 || 'xterm' === getenv('TERM');
63687 }
63688
63689 if (\function_exists('stream_isatty')) {
63690 return @stream_isatty($this->stream);
63691 }
63692
63693 if (\function_exists('posix_isatty')) {
63694 return @posix_isatty($this->stream);
63695 }
63696
63697 $stat = @fstat($this->stream);
63698
63699 return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
63700 }
63701 }
63702 <?php
63703
63704
63705
63706
63707
63708
63709
63710
63711
63712
63713 namespace Symfony\Component\Console\Question;
63714
63715 use Symfony\Component\Console\Exception\InvalidArgumentException;
63716
63717
63718
63719
63720
63721
63722 class ChoiceQuestion extends Question
63723 {
63724 private $choices;
63725 private $multiselect = false;
63726 private $prompt = ' > ';
63727 private $errorMessage = 'Value "%s" is invalid';
63728
63729
63730
63731
63732
63733
63734 public function __construct($question, array $choices, $default = null)
63735 {
63736 if (!$choices) {
63737 throw new \LogicException('Choice question must have at least 1 choice available.');
63738 }
63739
63740 parent::__construct($question, $default);
63741
63742 $this->choices = $choices;
63743 $this->setValidator($this->getDefaultValidator());
63744 $this->setAutocompleterValues($choices);
63745 }
63746
63747
63748
63749
63750
63751
63752 public function getChoices()
63753 {
63754 return $this->choices;
63755 }
63756
63757
63758
63759
63760
63761
63762
63763
63764
63765
63766 public function setMultiselect($multiselect)
63767 {
63768 $this->multiselect = $multiselect;
63769 $this->setValidator($this->getDefaultValidator());
63770
63771 return $this;
63772 }
63773
63774
63775
63776
63777
63778
63779 public function isMultiselect()
63780 {
63781 return $this->multiselect;
63782 }
63783
63784
63785
63786
63787
63788
63789 public function getPrompt()
63790 {
63791 return $this->prompt;
63792 }
63793
63794
63795
63796
63797
63798
63799
63800
63801 public function setPrompt($prompt)
63802 {
63803 $this->prompt = $prompt;
63804
63805 return $this;
63806 }
63807
63808
63809
63810
63811
63812
63813
63814
63815
63816
63817 public function setErrorMessage($errorMessage)
63818 {
63819 $this->errorMessage = $errorMessage;
63820 $this->setValidator($this->getDefaultValidator());
63821
63822 return $this;
63823 }
63824
63825
63826
63827
63828
63829
63830 private function getDefaultValidator()
63831 {
63832 $choices = $this->choices;
63833 $errorMessage = $this->errorMessage;
63834 $multiselect = $this->multiselect;
63835 $isAssoc = $this->isAssoc($choices);
63836
63837 return function ($selected) use ($choices, $errorMessage, $multiselect, $isAssoc) {
63838
63839 $selectedChoices = str_replace(' ', '', $selected);
63840
63841 if ($multiselect) {
63842
63843 if (!preg_match('/^[^,]+(?:,[^,]+)*$/', $selectedChoices, $matches)) {
63844 throw new InvalidArgumentException(sprintf($errorMessage, $selected));
63845 }
63846 $selectedChoices = explode(',', $selectedChoices);
63847 } else {
63848 $selectedChoices = array($selected);
63849 }
63850
63851 $multiselectChoices = array();
63852 foreach ($selectedChoices as $value) {
63853 $results = array();
63854 foreach ($choices as $key => $choice) {
63855 if ($choice === $value) {
63856 $results[] = $key;
63857 }
63858 }
63859
63860 if (\count($results) > 1) {
63861 throw new InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of %s.', implode(' or ', $results)));
63862 }
63863
63864 $result = array_search($value, $choices);
63865
63866 if (!$isAssoc) {
63867 if (false !== $result) {
63868 $result = $choices[$result];
63869 } elseif (isset($choices[$value])) {
63870 $result = $choices[$value];
63871 }
63872 } elseif (false === $result && isset($choices[$value])) {
63873 $result = $value;
63874 }
63875
63876 if (false === $result) {
63877 throw new InvalidArgumentException(sprintf($errorMessage, $value));
63878 }
63879
63880 $multiselectChoices[] = (string) $result;
63881 }
63882
63883 if ($multiselect) {
63884 return $multiselectChoices;
63885 }
63886
63887 return current($multiselectChoices);
63888 };
63889 }
63890 }
63891 <?php
63892
63893
63894
63895
63896
63897
63898
63899
63900
63901
63902 namespace Symfony\Component\Console\Question;
63903
63904
63905
63906
63907
63908
63909 class ConfirmationQuestion extends Question
63910 {
63911 private $trueAnswerRegex;
63912
63913
63914
63915
63916
63917
63918 public function __construct($question, $default = true, $trueAnswerRegex = '/^y/i')
63919 {
63920 parent::__construct($question, (bool) $default);
63921
63922 $this->trueAnswerRegex = $trueAnswerRegex;
63923 $this->setNormalizer($this->getDefaultNormalizer());
63924 }
63925
63926
63927
63928
63929
63930
63931 private function getDefaultNormalizer()
63932 {
63933 $default = $this->getDefault();
63934 $regex = $this->trueAnswerRegex;
63935
63936 return function ($answer) use ($default, $regex) {
63937 if (\is_bool($answer)) {
63938 return $answer;
63939 }
63940
63941 $answerIsTrue = (bool) preg_match($regex, $answer);
63942 if (false === $default) {
63943 return $answer && $answerIsTrue;
63944 }
63945
63946 return !$answer || $answerIsTrue;
63947 };
63948 }
63949 }
63950 <?php
63951
63952
63953
63954
63955
63956
63957
63958
63959
63960
63961 namespace Symfony\Component\Console\Question;
63962
63963 use Symfony\Component\Console\Exception\InvalidArgumentException;
63964 use Symfony\Component\Console\Exception\LogicException;
63965
63966
63967
63968
63969
63970
63971 class Question
63972 {
63973 private $question;
63974 private $attempts;
63975 private $hidden = false;
63976 private $hiddenFallback = true;
63977 private $autocompleterValues;
63978 private $validator;
63979 private $default;
63980 private $normalizer;
63981
63982
63983
63984
63985
63986 public function __construct($question, $default = null)
63987 {
63988 $this->question = $question;
63989 $this->default = $default;
63990 }
63991
63992
63993
63994
63995
63996
63997 public function getQuestion()
63998 {
63999 return $this->question;
64000 }
64001
64002
64003
64004
64005
64006
64007 public function getDefault()
64008 {
64009 return $this->default;
64010 }
64011
64012
64013
64014
64015
64016
64017 public function isHidden()
64018 {
64019 return $this->hidden;
64020 }
64021
64022
64023
64024
64025
64026
64027
64028
64029
64030
64031 public function setHidden($hidden)
64032 {
64033 if ($this->autocompleterValues) {
64034 throw new LogicException('A hidden question cannot use the autocompleter.');
64035 }
64036
64037 $this->hidden = (bool) $hidden;
64038
64039 return $this;
64040 }
64041
64042
64043
64044
64045
64046
64047 public function isHiddenFallback()
64048 {
64049 return $this->hiddenFallback;
64050 }
64051
64052
64053
64054
64055
64056
64057
64058
64059 public function setHiddenFallback($fallback)
64060 {
64061 $this->hiddenFallback = (bool) $fallback;
64062
64063 return $this;
64064 }
64065
64066
64067
64068
64069
64070
64071 public function getAutocompleterValues()
64072 {
64073 return $this->autocompleterValues;
64074 }
64075
64076
64077
64078
64079
64080
64081
64082
64083
64084
64085
64086 public function setAutocompleterValues($values)
64087 {
64088 if (\is_array($values)) {
64089 $values = $this->isAssoc($values) ? array_merge(array_keys($values), array_values($values)) : array_values($values);
64090 }
64091
64092 if (null !== $values && !\is_array($values) && !$values instanceof \Traversable) {
64093 throw new InvalidArgumentException('Autocompleter values can be either an array, `null` or a `Traversable` object.');
64094 }
64095
64096 if ($this->hidden) {
64097 throw new LogicException('A hidden question cannot use the autocompleter.');
64098 }
64099
64100 $this->autocompleterValues = $values;
64101
64102 return $this;
64103 }
64104
64105
64106
64107
64108
64109
64110
64111
64112 public function setValidator($validator)
64113 {
64114 $this->validator = $validator;
64115
64116 return $this;
64117 }
64118
64119
64120
64121
64122
64123
64124 public function getValidator()
64125 {
64126 return $this->validator;
64127 }
64128
64129
64130
64131
64132
64133
64134
64135
64136
64137
64138
64139
64140 public function setMaxAttempts($attempts)
64141 {
64142 if (null !== $attempts && $attempts < 1) {
64143 throw new InvalidArgumentException('Maximum number of attempts must be a positive value.');
64144 }
64145
64146 $this->attempts = $attempts;
64147
64148 return $this;
64149 }
64150
64151
64152
64153
64154
64155
64156
64157
64158 public function getMaxAttempts()
64159 {
64160 return $this->attempts;
64161 }
64162
64163
64164
64165
64166
64167
64168
64169
64170
64171
64172 public function setNormalizer($normalizer)
64173 {
64174 $this->normalizer = $normalizer;
64175
64176 return $this;
64177 }
64178
64179
64180
64181
64182
64183
64184
64185
64186 public function getNormalizer()
64187 {
64188 return $this->normalizer;
64189 }
64190
64191 protected function isAssoc($array)
64192 {
64193 return (bool) \count(array_filter(array_keys($array), 'is_string'));
64194 }
64195 }
64196 <?php
64197
64198
64199
64200
64201
64202
64203
64204
64205
64206
64207 namespace Symfony\Component\Console;
64208
64209 use Symfony\Component\Console\Exception\RuntimeException;
64210 use Symfony\Component\Console\Input\StringInput;
64211 use Symfony\Component\Console\Output\ConsoleOutput;
64212 use Symfony\Component\Process\PhpExecutableFinder;
64213 use Symfony\Component\Process\ProcessBuilder;
64214
64215
64216
64217
64218
64219
64220
64221
64222
64223
64224
64225
64226 class Shell
64227 {
64228 private $application;
64229 private $history;
64230 private $output;
64231 private $hasReadline;
64232 private $processIsolation = false;
64233
64234
64235
64236
64237
64238 public function __construct(Application $application)
64239 {
64240 @trigger_error('The '.__CLASS__.' class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
64241
64242 $this->hasReadline = \function_exists('readline');
64243 $this->application = $application;
64244 $this->history = getenv('HOME').'/.history_'.$application->getName();
64245 $this->output = new ConsoleOutput();
64246 }
64247
64248
64249
64250
64251 public function run()
64252 {
64253 $this->application->setAutoExit(false);
64254 $this->application->setCatchExceptions(true);
64255
64256 if ($this->hasReadline) {
64257 readline_read_history($this->history);
64258 readline_completion_function(array($this, 'autocompleter'));
64259 }
64260
64261 $this->output->writeln($this->getHeader());
64262 $php = null;
64263 if ($this->processIsolation) {
64264 $finder = new PhpExecutableFinder();
64265 $php = $finder->find();
64266 $this->output->writeln(<<<'EOF'
64267 <info>Running with process isolation, you should consider this:</info>
64268   * each command is executed as separate process,
64269   * commands don't support interactivity, all params must be passed explicitly,
64270   * commands output is not colorized.
64271
64272 EOF
64273 );
64274 }
64275
64276 while (true) {
64277 $command = $this->readline();
64278
64279 if (false === $command) {
64280 $this->output->writeln("\n");
64281
64282 break;
64283 }
64284
64285 if ($this->hasReadline) {
64286 readline_add_history($command);
64287 readline_write_history($this->history);
64288 }
64289
64290 if ($this->processIsolation) {
64291 $pb = new ProcessBuilder();
64292
64293 $process = $pb
64294 ->add($php)
64295 ->add($_SERVER['argv'][0])
64296 ->add($command)
64297 ->inheritEnvironmentVariables(true)
64298 ->getProcess()
64299 ;
64300
64301 $output = $this->output;
64302 $process->run(function ($type, $data) use ($output) {
64303 $output->writeln($data);
64304 });
64305
64306 $ret = $process->getExitCode();
64307 } else {
64308 $ret = $this->application->run(new StringInput($command), $this->output);
64309 }
64310
64311 if (0 !== $ret) {
64312 $this->output->writeln(sprintf('<error>The command terminated with an error status (%s)</error>', $ret));
64313 }
64314 }
64315 }
64316
64317
64318
64319
64320
64321
64322 protected function getHeader()
64323 {
64324 return <<<EOF
64325
64326 Welcome to the <info>{$this->application->getName()}</info> shell (<comment>{$this->application->getVersion()}</comment>).
64327
64328 At the prompt, type <comment>help</comment> for some help,
64329 or <comment>list</comment> to get a list of available commands.
64330
64331 To exit the shell, type <comment>^D</comment>.
64332
64333 EOF;
64334 }
64335
64336
64337
64338
64339
64340
64341 protected function getPrompt()
64342 {
64343
64344 return $this->output->getFormatter()->format($this->application->getName().' > ');
64345 }
64346
64347 protected function getOutput()
64348 {
64349 return $this->output;
64350 }
64351
64352 protected function getApplication()
64353 {
64354 return $this->application;
64355 }
64356
64357
64358
64359
64360
64361
64362
64363
64364 private function autocompleter($text)
64365 {
64366 $info = readline_info();
64367 $text = substr($info['line_buffer'], 0, $info['end']);
64368
64369 if ($info['point'] !== $info['end']) {
64370 return true;
64371 }
64372
64373
64374 if (false === strpos($text, ' ') || !$text) {
64375 return array_keys($this->application->all());
64376 }
64377
64378
64379 try {
64380 $command = $this->application->find(substr($text, 0, strpos($text, ' ')));
64381 } catch (\Exception $e) {
64382 return true;
64383 }
64384
64385 $list = array('--help');
64386 foreach ($command->getDefinition()->getOptions() as $option) {
64387 $list[] = '--'.$option->getName();
64388 }
64389
64390 return $list;
64391 }
64392
64393
64394
64395
64396
64397
64398 private function readline()
64399 {
64400 if ($this->hasReadline) {
64401 $line = readline($this->getPrompt());
64402 } else {
64403 $this->output->write($this->getPrompt());
64404 $line = fgets(STDIN, 1024);
64405 $line = (false === $line || '' === $line) ? false : rtrim($line);
64406 }
64407
64408 return $line;
64409 }
64410
64411 public function getProcessIsolation()
64412 {
64413 return $this->processIsolation;
64414 }
64415
64416 public function setProcessIsolation($processIsolation)
64417 {
64418 $this->processIsolation = (bool) $processIsolation;
64419
64420 if ($this->processIsolation && !class_exists('Symfony\\Component\\Process\\Process')) {
64421 throw new RuntimeException('Unable to isolate processes as the Symfony Process Component is not installed.');
64422 }
64423 }
64424 }
64425 <?php
64426
64427
64428
64429
64430
64431
64432
64433
64434
64435
64436 namespace Symfony\Component\Console\Style;
64437
64438 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
64439 use Symfony\Component\Console\Helper\ProgressBar;
64440 use Symfony\Component\Console\Output\OutputInterface;
64441
64442
64443
64444
64445
64446
64447 abstract class OutputStyle implements OutputInterface, StyleInterface
64448 {
64449 private $output;
64450
64451 public function __construct(OutputInterface $output)
64452 {
64453 $this->output = $output;
64454 }
64455
64456
64457
64458
64459 public function newLine($count = 1)
64460 {
64461 $this->output->write(str_repeat(PHP_EOL, $count));
64462 }
64463
64464
64465
64466
64467
64468
64469 public function createProgressBar($max = 0)
64470 {
64471 return new ProgressBar($this->output, $max);
64472 }
64473
64474
64475
64476
64477 public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
64478 {
64479 $this->output->write($messages, $newline, $type);
64480 }
64481
64482
64483
64484
64485 public function writeln($messages, $type = self::OUTPUT_NORMAL)
64486 {
64487 $this->output->writeln($messages, $type);
64488 }
64489
64490
64491
64492
64493 public function setVerbosity($level)
64494 {
64495 $this->output->setVerbosity($level);
64496 }
64497
64498
64499
64500
64501 public function getVerbosity()
64502 {
64503 return $this->output->getVerbosity();
64504 }
64505
64506
64507
64508
64509 public function setDecorated($decorated)
64510 {
64511 $this->output->setDecorated($decorated);
64512 }
64513
64514
64515
64516
64517 public function isDecorated()
64518 {
64519 return $this->output->isDecorated();
64520 }
64521
64522
64523
64524
64525 public function setFormatter(OutputFormatterInterface $formatter)
64526 {
64527 $this->output->setFormatter($formatter);
64528 }
64529
64530
64531
64532
64533 public function getFormatter()
64534 {
64535 return $this->output->getFormatter();
64536 }
64537 }
64538 <?php
64539
64540
64541
64542
64543
64544
64545
64546
64547
64548
64549 namespace Symfony\Component\Console\Style;
64550
64551
64552
64553
64554
64555
64556 interface StyleInterface
64557 {
64558
64559
64560
64561
64562
64563 public function title($message);
64564
64565
64566
64567
64568
64569
64570 public function section($message);
64571
64572
64573
64574
64575 public function listing(array $elements);
64576
64577
64578
64579
64580
64581
64582 public function text($message);
64583
64584
64585
64586
64587
64588
64589 public function success($message);
64590
64591
64592
64593
64594
64595
64596 public function error($message);
64597
64598
64599
64600
64601
64602
64603 public function warning($message);
64604
64605
64606
64607
64608
64609
64610 public function note($message);
64611
64612
64613
64614
64615
64616
64617 public function caution($message);
64618
64619
64620
64621
64622 public function table(array $headers, array $rows);
64623
64624
64625
64626
64627
64628
64629
64630
64631
64632
64633 public function ask($question, $default = null, $validator = null);
64634
64635
64636
64637
64638
64639
64640
64641
64642
64643 public function askHidden($question, $validator = null);
64644
64645
64646
64647
64648
64649
64650
64651
64652
64653 public function confirm($question, $default = true);
64654
64655
64656
64657
64658
64659
64660
64661
64662
64663
64664 public function choice($question, array $choices, $default = null);
64665
64666
64667
64668
64669
64670
64671 public function newLine($count = 1);
64672
64673
64674
64675
64676
64677
64678 public function progressStart($max = 0);
64679
64680
64681
64682
64683
64684
64685 public function progressAdvance($step = 1);
64686
64687
64688
64689
64690 public function progressFinish();
64691 }
64692 <?php
64693
64694
64695
64696
64697
64698
64699
64700
64701
64702
64703 namespace Symfony\Component\Console\Style;
64704
64705 use Symfony\Component\Console\Application;
64706 use Symfony\Component\Console\Exception\RuntimeException;
64707 use Symfony\Component\Console\Formatter\OutputFormatter;
64708 use Symfony\Component\Console\Helper\Helper;
64709 use Symfony\Component\Console\Helper\ProgressBar;
64710 use Symfony\Component\Console\Helper\SymfonyQuestionHelper;
64711 use Symfony\Component\Console\Helper\Table;
64712 use Symfony\Component\Console\Input\InputInterface;
64713 use Symfony\Component\Console\Output\BufferedOutput;
64714 use Symfony\Component\Console\Output\OutputInterface;
64715 use Symfony\Component\Console\Question\ChoiceQuestion;
64716 use Symfony\Component\Console\Question\ConfirmationQuestion;
64717 use Symfony\Component\Console\Question\Question;
64718
64719
64720
64721
64722
64723
64724 class SymfonyStyle extends OutputStyle
64725 {
64726 const MAX_LINE_LENGTH = 120;
64727
64728 private $input;
64729 private $questionHelper;
64730 private $progressBar;
64731 private $lineLength;
64732 private $bufferedOutput;
64733
64734 public function __construct(InputInterface $input, OutputInterface $output)
64735 {
64736 $this->input = $input;
64737 $this->bufferedOutput = new BufferedOutput($output->getVerbosity(), false, clone $output->getFormatter());
64738
64739 $this->lineLength = min($this->getTerminalWidth() - (int) (\DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH);
64740
64741 parent::__construct($output);
64742 }
64743
64744
64745
64746
64747
64748
64749
64750
64751
64752
64753 public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false)
64754 {
64755 $messages = \is_array($messages) ? array_values($messages) : array($messages);
64756
64757 $this->autoPrependBlock();
64758 $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, true));
64759 $this->newLine();
64760 }
64761
64762
64763
64764
64765 public function title($message)
64766 {
64767 $this->autoPrependBlock();
64768 $this->writeln(array(
64769 sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),
64770 sprintf('<comment>%s</>', str_repeat('=', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
64771 ));
64772 $this->newLine();
64773 }
64774
64775
64776
64777
64778 public function section($message)
64779 {
64780 $this->autoPrependBlock();
64781 $this->writeln(array(
64782 sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),
64783 sprintf('<comment>%s</>', str_repeat('-', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
64784 ));
64785 $this->newLine();
64786 }
64787
64788
64789
64790
64791 public function listing(array $elements)
64792 {
64793 $this->autoPrependText();
64794 $elements = array_map(function ($element) {
64795 return sprintf(' * %s', $element);
64796 }, $elements);
64797
64798 $this->writeln($elements);
64799 $this->newLine();
64800 }
64801
64802
64803
64804
64805 public function text($message)
64806 {
64807 $this->autoPrependText();
64808
64809 $messages = \is_array($message) ? array_values($message) : array($message);
64810 foreach ($messages as $message) {
64811 $this->writeln(sprintf(' %s', $message));
64812 }
64813 }
64814
64815
64816
64817
64818
64819
64820 public function comment($message)
64821 {
64822 $messages = \is_array($message) ? array_values($message) : array($message);
64823
64824 $this->autoPrependBlock();
64825 $this->writeln($this->createBlock($messages, null, null, '<fg=default;bg=default> // </>'));
64826 $this->newLine();
64827 }
64828
64829
64830
64831
64832 public function success($message)
64833 {
64834 $this->block($message, 'OK', 'fg=black;bg=green', ' ', true);
64835 }
64836
64837
64838
64839
64840 public function error($message)
64841 {
64842 $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', true);
64843 }
64844
64845
64846
64847
64848 public function warning($message)
64849 {
64850 $this->block($message, 'WARNING', 'fg=white;bg=red', ' ', true);
64851 }
64852
64853
64854
64855
64856 public function note($message)
64857 {
64858 $this->block($message, 'NOTE', 'fg=yellow', ' ! ');
64859 }
64860
64861
64862
64863
64864 public function caution($message)
64865 {
64866 $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', true);
64867 }
64868
64869
64870
64871
64872 public function table(array $headers, array $rows)
64873 {
64874 $style = clone Table::getStyleDefinition('symfony-style-guide');
64875 $style->setCellHeaderFormat('<info>%s</info>');
64876
64877 $table = new Table($this);
64878 $table->setHeaders($headers);
64879 $table->setRows($rows);
64880 $table->setStyle($style);
64881
64882 $table->render();
64883 $this->newLine();
64884 }
64885
64886
64887
64888
64889 public function ask($question, $default = null, $validator = null)
64890 {
64891 $question = new Question($question, $default);
64892 $question->setValidator($validator);
64893
64894 return $this->askQuestion($question);
64895 }
64896
64897
64898
64899
64900 public function askHidden($question, $validator = null)
64901 {
64902 $question = new Question($question);
64903
64904 $question->setHidden(true);
64905 $question->setValidator($validator);
64906
64907 return $this->askQuestion($question);
64908 }
64909
64910
64911
64912
64913 public function confirm($question, $default = true)
64914 {
64915 return $this->askQuestion(new ConfirmationQuestion($question, $default));
64916 }
64917
64918
64919
64920
64921 public function choice($question, array $choices, $default = null)
64922 {
64923 if (null !== $default) {
64924 $values = array_flip($choices);
64925 $default = $values[$default];
64926 }
64927
64928 return $this->askQuestion(new ChoiceQuestion($question, $choices, $default));
64929 }
64930
64931
64932
64933
64934 public function progressStart($max = 0)
64935 {
64936 $this->progressBar = $this->createProgressBar($max);
64937 $this->progressBar->start();
64938 }
64939
64940
64941
64942
64943 public function progressAdvance($step = 1)
64944 {
64945 $this->getProgressBar()->advance($step);
64946 }
64947
64948
64949
64950
64951 public function progressFinish()
64952 {
64953 $this->getProgressBar()->finish();
64954 $this->newLine(2);
64955 $this->progressBar = null;
64956 }
64957
64958
64959
64960
64961 public function createProgressBar($max = 0)
64962 {
64963 $progressBar = parent::createProgressBar($max);
64964
64965 if ('\\' !== \DIRECTORY_SEPARATOR || 'Hyper' === getenv('TERM_PROGRAM')) {
64966 $progressBar->setEmptyBarCharacter('░'); 
64967 $progressBar->setProgressCharacter('');
64968 $progressBar->setBarCharacter('▓'); 
64969 }
64970
64971 return $progressBar;
64972 }
64973
64974
64975
64976
64977 public function askQuestion(Question $question)
64978 {
64979 if ($this->input->isInteractive()) {
64980 $this->autoPrependBlock();
64981 }
64982
64983 if (!$this->questionHelper) {
64984 $this->questionHelper = new SymfonyQuestionHelper();
64985 }
64986
64987 $answer = $this->questionHelper->ask($this->input, $this, $question);
64988
64989 if ($this->input->isInteractive()) {
64990 $this->newLine();
64991 $this->bufferedOutput->write("\n");
64992 }
64993
64994 return $answer;
64995 }
64996
64997
64998
64999
65000 public function writeln($messages, $type = self::OUTPUT_NORMAL)
65001 {
65002 parent::writeln($messages, $type);
65003 $this->bufferedOutput->writeln($this->reduceBuffer($messages), $type);
65004 }
65005
65006
65007
65008
65009 public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
65010 {
65011 parent::write($messages, $newline, $type);
65012 $this->bufferedOutput->write($this->reduceBuffer($messages), $newline, $type);
65013 }
65014
65015
65016
65017
65018 public function newLine($count = 1)
65019 {
65020 parent::newLine($count);
65021 $this->bufferedOutput->write(str_repeat("\n", $count));
65022 }
65023
65024
65025
65026
65027 private function getProgressBar()
65028 {
65029 if (!$this->progressBar) {
65030 throw new RuntimeException('The ProgressBar is not started.');
65031 }
65032
65033 return $this->progressBar;
65034 }
65035
65036 private function getTerminalWidth()
65037 {
65038 $application = new Application();
65039 $dimensions = $application->getTerminalDimensions();
65040
65041 return $dimensions[0] ?: self::MAX_LINE_LENGTH;
65042 }
65043
65044 private function autoPrependBlock()
65045 {
65046 $chars = substr(str_replace(PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2);
65047
65048 if (!isset($chars[0])) {
65049 return $this->newLine(); 
65050 }
65051
65052 $this->newLine(2 - substr_count($chars, "\n"));
65053 }
65054
65055 private function autoPrependText()
65056 {
65057 $fetched = $this->bufferedOutput->fetch();
65058
65059 if ("\n" !== substr($fetched, -1)) {
65060 $this->newLine();
65061 }
65062 }
65063
65064 private function reduceBuffer($messages)
65065 {
65066
65067
65068 return array_map(function ($value) {
65069 return substr($value, -4);
65070 }, array_merge(array($this->bufferedOutput->fetch()), (array) $messages));
65071 }
65072
65073 private function createBlock($messages, $type = null, $style = null, $prefix = ' ', $padding = false, $escape = false)
65074 {
65075 $indentLength = 0;
65076 $prefixLength = Helper::strlenWithoutDecoration($this->getFormatter(), $prefix);
65077 $lines = array();
65078
65079 if (null !== $type) {
65080 $type = sprintf('[%s] ', $type);
65081 $indentLength = \strlen($type);
65082 $lineIndentation = str_repeat(' ', $indentLength);
65083 }
65084
65085
65086 foreach ($messages as $key => $message) {
65087 if ($escape) {
65088 $message = OutputFormatter::escape($message);
65089 }
65090
65091 $lines = array_merge($lines, explode(PHP_EOL, wordwrap($message, $this->lineLength - $prefixLength - $indentLength, PHP_EOL, true)));
65092
65093 if (\count($messages) > 1 && $key < \count($messages) - 1) {
65094 $lines[] = '';
65095 }
65096 }
65097
65098 $firstLineIndex = 0;
65099 if ($padding && $this->isDecorated()) {
65100 $firstLineIndex = 1;
65101 array_unshift($lines, '');
65102 $lines[] = '';
65103 }
65104
65105 foreach ($lines as $i => &$line) {
65106 if (null !== $type) {
65107 $line = $firstLineIndex === $i ? $type.$line : $lineIndentation.$line;
65108 }
65109
65110 $line = $prefix.$line;
65111 $line .= str_repeat(' ', $this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line));
65112
65113 if ($style) {
65114 $line = sprintf('<%s>%s</>', $style, $line);
65115 }
65116 }
65117
65118 return $lines;
65119 }
65120 }
65121 <?php
65122
65123
65124
65125
65126
65127
65128
65129
65130
65131
65132 namespace Symfony\Component\Console\Tester;
65133
65134 use Symfony\Component\Console\Application;
65135 use Symfony\Component\Console\Input\ArrayInput;
65136 use Symfony\Component\Console\Input\InputInterface;
65137 use Symfony\Component\Console\Output\OutputInterface;
65138 use Symfony\Component\Console\Output\StreamOutput;
65139
65140
65141
65142
65143
65144
65145
65146
65147
65148
65149
65150 class ApplicationTester
65151 {
65152 private $application;
65153 private $input;
65154 private $output;
65155 private $statusCode;
65156
65157 public function __construct(Application $application)
65158 {
65159 $this->application = $application;
65160 }
65161
65162
65163
65164
65165
65166
65167
65168
65169
65170
65171
65172
65173
65174
65175
65176 public function run(array $input, $options = array())
65177 {
65178 $this->input = new ArrayInput($input);
65179 if (isset($options['interactive'])) {
65180 $this->input->setInteractive($options['interactive']);
65181 }
65182
65183 $this->output = new StreamOutput(fopen('php://memory', 'w', false));
65184 if (isset($options['decorated'])) {
65185 $this->output->setDecorated($options['decorated']);
65186 }
65187 if (isset($options['verbosity'])) {
65188 $this->output->setVerbosity($options['verbosity']);
65189 }
65190
65191 return $this->statusCode = $this->application->run($this->input, $this->output);
65192 }
65193
65194
65195
65196
65197
65198
65199
65200
65201 public function getDisplay($normalize = false)
65202 {
65203 rewind($this->output->getStream());
65204
65205 $display = stream_get_contents($this->output->getStream());
65206
65207 if ($normalize) {
65208 $display = str_replace(PHP_EOL, "\n", $display);
65209 }
65210
65211 return $display;
65212 }
65213
65214
65215
65216
65217
65218
65219 public function getInput()
65220 {
65221 return $this->input;
65222 }
65223
65224
65225
65226
65227
65228
65229 public function getOutput()
65230 {
65231 return $this->output;
65232 }
65233
65234
65235
65236
65237
65238
65239 public function getStatusCode()
65240 {
65241 return $this->statusCode;
65242 }
65243 }
65244 <?php
65245
65246
65247
65248
65249
65250
65251
65252
65253
65254
65255 namespace Symfony\Component\Console\Tester;
65256
65257 use Symfony\Component\Console\Command\Command;
65258 use Symfony\Component\Console\Input\ArrayInput;
65259 use Symfony\Component\Console\Input\InputInterface;
65260 use Symfony\Component\Console\Output\OutputInterface;
65261 use Symfony\Component\Console\Output\StreamOutput;
65262
65263
65264
65265
65266
65267
65268 class CommandTester
65269 {
65270 private $command;
65271 private $input;
65272 private $output;
65273 private $statusCode;
65274
65275 public function __construct(Command $command)
65276 {
65277 $this->command = $command;
65278 }
65279
65280
65281
65282
65283
65284
65285
65286
65287
65288
65289
65290
65291
65292
65293
65294 public function execute(array $input, array $options = array())
65295 {
65296
65297
65298 if (!isset($input['command'])
65299 && (null !== $application = $this->command->getApplication())
65300 && $application->getDefinition()->hasArgument('command')
65301 ) {
65302 $input = array_merge(array('command' => $this->command->getName()), $input);
65303 }
65304
65305 $this->input = new ArrayInput($input);
65306 if (isset($options['interactive'])) {
65307 $this->input->setInteractive($options['interactive']);
65308 }
65309
65310 $this->output = new StreamOutput(fopen('php://memory', 'w', false));
65311 $this->output->setDecorated(isset($options['decorated']) ? $options['decorated'] : false);
65312 if (isset($options['verbosity'])) {
65313 $this->output->setVerbosity($options['verbosity']);
65314 }
65315
65316 return $this->statusCode = $this->command->run($this->input, $this->output);
65317 }
65318
65319
65320
65321
65322
65323
65324
65325
65326 public function getDisplay($normalize = false)
65327 {
65328 rewind($this->output->getStream());
65329
65330 $display = stream_get_contents($this->output->getStream());
65331
65332 if ($normalize) {
65333 $display = str_replace(PHP_EOL, "\n", $display);
65334 }
65335
65336 return $display;
65337 }
65338
65339
65340
65341
65342
65343
65344 public function getInput()
65345 {
65346 return $this->input;
65347 }
65348
65349
65350
65351
65352
65353
65354 public function getOutput()
65355 {
65356 return $this->output;
65357 }
65358
65359
65360
65361
65362
65363
65364 public function getStatusCode()
65365 {
65366 return $this->statusCode;
65367 }
65368 }
65369 <?php
65370
65371
65372
65373
65374
65375
65376
65377
65378
65379
65380 namespace Symfony\Component\Debug;
65381
65382 use Psr\Log\AbstractLogger;
65383
65384
65385
65386
65387
65388
65389 class BufferingLogger extends AbstractLogger
65390 {
65391 private $logs = array();
65392
65393 public function log($level, $message, array $context = array())
65394 {
65395 $this->logs[] = array($level, $message, $context);
65396 }
65397
65398 public function cleanLogs()
65399 {
65400 $logs = $this->logs;
65401 $this->logs = array();
65402
65403 return $logs;
65404 }
65405 }
65406 <?php
65407
65408
65409
65410
65411
65412
65413
65414
65415
65416
65417 namespace Symfony\Component\Debug;
65418
65419
65420
65421
65422
65423
65424 class Debug
65425 {
65426 private static $enabled = false;
65427
65428
65429
65430
65431
65432
65433
65434
65435
65436 public static function enable($errorReportingLevel = null, $displayErrors = true)
65437 {
65438 if (static::$enabled) {
65439 return;
65440 }
65441
65442 static::$enabled = true;
65443
65444 if (null !== $errorReportingLevel) {
65445 error_reporting($errorReportingLevel);
65446 } else {
65447 error_reporting(-1);
65448 }
65449
65450 if (!\in_array(\PHP_SAPI, array('cli', 'phpdbg'), true)) {
65451 ini_set('display_errors', 0);
65452 ExceptionHandler::register();
65453 } elseif ($displayErrors && (!filter_var(ini_get('log_errors'), FILTER_VALIDATE_BOOLEAN) || ini_get('error_log'))) {
65454
65455 ini_set('display_errors', 1);
65456 }
65457 if ($displayErrors) {
65458 ErrorHandler::register(new ErrorHandler(new BufferingLogger()));
65459 } else {
65460 ErrorHandler::register()->throwAt(0, true);
65461 }
65462
65463 DebugClassLoader::enable();
65464 }
65465 }
65466 <?php
65467
65468
65469
65470
65471
65472
65473
65474
65475
65476
65477 namespace Symfony\Component\Debug;
65478
65479
65480
65481
65482
65483
65484
65485
65486
65487
65488
65489
65490 class DebugClassLoader
65491 {
65492 private $classLoader;
65493 private $isFinder;
65494 private $loaded = array();
65495 private $wasFinder;
65496 private static $caseCheck;
65497 private static $deprecated = array();
65498 private static $php7Reserved = array('int', 'float', 'bool', 'string', 'true', 'false', 'null');
65499 private static $darwinCache = array('/' => array('/', array()));
65500
65501
65502
65503
65504 public function __construct($classLoader)
65505 {
65506 $this->wasFinder = \is_object($classLoader) && method_exists($classLoader, 'findFile');
65507
65508 if ($this->wasFinder) {
65509 @trigger_error('The '.__METHOD__.' method will no longer support receiving an object into its $classLoader argument in 3.0.', E_USER_DEPRECATED);
65510 $this->classLoader = array($classLoader, 'loadClass');
65511 $this->isFinder = true;
65512 } else {
65513 $this->classLoader = $classLoader;
65514 $this->isFinder = \is_array($classLoader) && method_exists($classLoader[0], 'findFile');
65515 }
65516
65517 if (!isset(self::$caseCheck)) {
65518 $file = file_exists(__FILE__) ? __FILE__ : rtrim(realpath('.'), \DIRECTORY_SEPARATOR);
65519 $i = strrpos($file, \DIRECTORY_SEPARATOR);
65520 $dir = substr($file, 0, 1 + $i);
65521 $file = substr($file, 1 + $i);
65522 $test = strtoupper($file) === $file ? strtolower($file) : strtoupper($file);
65523 $test = realpath($dir.$test);
65524
65525 if (false === $test || false === $i) {
65526
65527 self::$caseCheck = 0;
65528 } elseif (substr($test, -\strlen($file)) === $file) {
65529
65530 self::$caseCheck = 1;
65531 } elseif (false !== stripos(PHP_OS, 'darwin')) {
65532
65533 self::$caseCheck = 2;
65534 } else {
65535
65536 self::$caseCheck = 0;
65537 }
65538 }
65539 }
65540
65541
65542
65543
65544
65545
65546 public function getClassLoader()
65547 {
65548 return $this->wasFinder ? $this->classLoader[0] : $this->classLoader;
65549 }
65550
65551
65552
65553
65554 public static function enable()
65555 {
65556
65557 class_exists('Symfony\Component\Debug\ErrorHandler');
65558 class_exists('Psr\Log\LogLevel');
65559
65560 if (!\is_array($functions = spl_autoload_functions())) {
65561 return;
65562 }
65563
65564 foreach ($functions as $function) {
65565 spl_autoload_unregister($function);
65566 }
65567
65568 foreach ($functions as $function) {
65569 if (!\is_array($function) || !$function[0] instanceof self) {
65570 $function = array(new static($function), 'loadClass');
65571 }
65572
65573 spl_autoload_register($function);
65574 }
65575 }
65576
65577
65578
65579
65580 public static function disable()
65581 {
65582 if (!\is_array($functions = spl_autoload_functions())) {
65583 return;
65584 }
65585
65586 foreach ($functions as $function) {
65587 spl_autoload_unregister($function);
65588 }
65589
65590 foreach ($functions as $function) {
65591 if (\is_array($function) && $function[0] instanceof self) {
65592 $function = $function[0]->getClassLoader();
65593 }
65594
65595 spl_autoload_register($function);
65596 }
65597 }
65598
65599
65600
65601
65602
65603
65604
65605
65606
65607
65608 public function findFile($class)
65609 {
65610 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.5 and will be removed in 3.0.', E_USER_DEPRECATED);
65611
65612 if ($this->wasFinder) {
65613 return $this->classLoader[0]->findFile($class);
65614 }
65615 }
65616
65617
65618
65619
65620
65621
65622
65623
65624
65625
65626 public function loadClass($class)
65627 {
65628 ErrorHandler::stackErrors();
65629
65630 try {
65631 if ($this->isFinder && !isset($this->loaded[$class])) {
65632 $this->loaded[$class] = true;
65633 if ($file = $this->classLoader[0]->findFile($class)) {
65634 require $file;
65635 }
65636 } else {
65637 \call_user_func($this->classLoader, $class);
65638 $file = false;
65639 }
65640 } catch (\Exception $e) {
65641 ErrorHandler::unstackErrors();
65642
65643 throw $e;
65644 } catch (\Throwable $e) {
65645 ErrorHandler::unstackErrors();
65646
65647 throw $e;
65648 }
65649
65650 ErrorHandler::unstackErrors();
65651
65652 $exists = class_exists($class, false) || interface_exists($class, false) || (\function_exists('trait_exists') && trait_exists($class, false));
65653
65654 if ($class && '\\' === $class[0]) {
65655 $class = substr($class, 1);
65656 }
65657
65658 if ($exists) {
65659 $refl = new \ReflectionClass($class);
65660 $name = $refl->getName();
65661
65662 if ($name !== $class && 0 === strcasecmp($name, $class)) {
65663 throw new \RuntimeException(sprintf('Case mismatch between loaded and declared class names: %s vs %s', $class, $name));
65664 }
65665
65666 if (\in_array(strtolower($refl->getShortName()), self::$php7Reserved)) {
65667 @trigger_error(sprintf('%s uses a reserved class name (%s) that will break on PHP 7 and higher', $name, $refl->getShortName()), E_USER_DEPRECATED);
65668 } elseif (preg_match('#\n \* @deprecated (.*?)\r?\n \*(?: @|/$)#s', $refl->getDocComment(), $notice)) {
65669 self::$deprecated[$name] = preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]);
65670 } else {
65671 if (2 > $len = 1 + (strpos($name, '\\') ?: strpos($name, '_'))) {
65672 $len = 0;
65673 $ns = '';
65674 } else {
65675 $ns = substr($name, 0, $len);
65676 }
65677 $parent = get_parent_class($class);
65678
65679 if (!$parent || strncmp($ns, $parent, $len)) {
65680 if ($parent && isset(self::$deprecated[$parent]) && strncmp($ns, $parent, $len)) {
65681 @trigger_error(sprintf('The %s class extends %s that is deprecated %s', $name, $parent, self::$deprecated[$parent]), E_USER_DEPRECATED);
65682 }
65683
65684 $parentInterfaces = array();
65685 $deprecatedInterfaces = array();
65686 if ($parent) {
65687 foreach (class_implements($parent) as $interface) {
65688 $parentInterfaces[$interface] = 1;
65689 }
65690 }
65691
65692 foreach ($refl->getInterfaceNames() as $interface) {
65693 if (isset(self::$deprecated[$interface]) && strncmp($ns, $interface, $len)) {
65694 $deprecatedInterfaces[] = $interface;
65695 }
65696 foreach (class_implements($interface) as $interface) {
65697 $parentInterfaces[$interface] = 1;
65698 }
65699 }
65700
65701 foreach ($deprecatedInterfaces as $interface) {
65702 if (!isset($parentInterfaces[$interface])) {
65703 @trigger_error(sprintf('The %s %s %s that is deprecated %s', $name, $refl->isInterface() ? 'interface extends' : 'class implements', $interface, self::$deprecated[$interface]), E_USER_DEPRECATED);
65704 }
65705 }
65706 }
65707 }
65708 }
65709
65710 if ($file) {
65711 if (!$exists) {
65712 if (false !== strpos($class, '/')) {
65713 throw new \RuntimeException(sprintf('Trying to autoload a class with an invalid name "%s". Be careful that the namespace separator is "\" in PHP, not "/".', $class));
65714 }
65715
65716 throw new \RuntimeException(sprintf('The autoloader expected class "%s" to be defined in file "%s". The file was found but the class was not in it, the class name or namespace probably has a typo.', $class, $file));
65717 }
65718 if (self::$caseCheck) {
65719 $real = explode('\\', $class.strrchr($file, '.'));
65720 $tail = explode(\DIRECTORY_SEPARATOR, str_replace('/', \DIRECTORY_SEPARATOR, $file));
65721
65722 $i = \count($tail) - 1;
65723 $j = \count($real) - 1;
65724
65725 while (isset($tail[$i], $real[$j]) && $tail[$i] === $real[$j]) {
65726 --$i;
65727 --$j;
65728 }
65729
65730 array_splice($tail, 0, $i + 1);
65731 }
65732 if (self::$caseCheck && $tail) {
65733 $tail = \DIRECTORY_SEPARATOR.implode(\DIRECTORY_SEPARATOR, $tail);
65734 $tailLen = \strlen($tail);
65735 $real = $refl->getFileName();
65736
65737 if (2 === self::$caseCheck) {
65738
65739
65740 $i = 1 + strrpos($real, '/');
65741 $file = substr($real, $i);
65742 $real = substr($real, 0, $i);
65743
65744 if (isset(self::$darwinCache[$real])) {
65745 $kDir = $real;
65746 } else {
65747 $kDir = strtolower($real);
65748
65749 if (isset(self::$darwinCache[$kDir])) {
65750 $real = self::$darwinCache[$kDir][0];
65751 } else {
65752 $dir = getcwd();
65753 chdir($real);
65754 $real = getcwd().'/';
65755 chdir($dir);
65756
65757 $dir = $real;
65758 $k = $kDir;
65759 $i = \strlen($dir) - 1;
65760 while (!isset(self::$darwinCache[$k])) {
65761 self::$darwinCache[$k] = array($dir, array());
65762 self::$darwinCache[$dir] = &self::$darwinCache[$k];
65763
65764 while ('/' !== $dir[--$i]) {
65765 }
65766 $k = substr($k, 0, ++$i);
65767 $dir = substr($dir, 0, $i--);
65768 }
65769 }
65770 }
65771
65772 $dirFiles = self::$darwinCache[$kDir][1];
65773
65774 if (isset($dirFiles[$file])) {
65775 $kFile = $file;
65776 } else {
65777 $kFile = strtolower($file);
65778
65779 if (!isset($dirFiles[$kFile])) {
65780 foreach (scandir($real, 2) as $f) {
65781 if ('.' !== $f[0]) {
65782 $dirFiles[$f] = $f;
65783 if ($f === $file) {
65784 $kFile = $k = $file;
65785 } elseif ($f !== $k = strtolower($f)) {
65786 $dirFiles[$k] = $f;
65787 }
65788 }
65789 }
65790 self::$darwinCache[$kDir][1] = $dirFiles;
65791 }
65792 }
65793
65794 $real .= $dirFiles[$kFile];
65795 }
65796
65797 if (0 === substr_compare($real, $tail, -$tailLen, $tailLen, true)
65798 && 0 !== substr_compare($real, $tail, -$tailLen, $tailLen, false)
65799 ) {
65800 throw new \RuntimeException(sprintf('Case mismatch between class and real file names: %s vs %s in %s', substr($tail, -$tailLen + 1), substr($real, -$tailLen + 1), substr($real, 0, -$tailLen + 1)));
65801 }
65802 }
65803
65804 return true;
65805 }
65806 }
65807 }
65808 <?php
65809
65810
65811
65812
65813
65814
65815
65816
65817
65818
65819 namespace Symfony\Component\Debug;
65820
65821 use Psr\Log\LoggerInterface;
65822 use Psr\Log\LogLevel;
65823 use Symfony\Component\Debug\Exception\ContextErrorException;
65824 use Symfony\Component\Debug\Exception\FatalErrorException;
65825 use Symfony\Component\Debug\Exception\FatalThrowableError;
65826 use Symfony\Component\Debug\Exception\OutOfMemoryException;
65827 use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler;
65828 use Symfony\Component\Debug\FatalErrorHandler\FatalErrorHandlerInterface;
65829 use Symfony\Component\Debug\FatalErrorHandler\UndefinedFunctionFatalErrorHandler;
65830 use Symfony\Component\Debug\FatalErrorHandler\UndefinedMethodFatalErrorHandler;
65831
65832
65833
65834
65835
65836
65837
65838
65839
65840
65841
65842
65843
65844
65845
65846
65847
65848
65849
65850
65851
65852
65853
65854 class ErrorHandler
65855 {
65856
65857
65858
65859 const TYPE_DEPRECATION = -100;
65860
65861 private $levels = array(
65862 E_DEPRECATED => 'Deprecated',
65863 E_USER_DEPRECATED => 'User Deprecated',
65864 E_NOTICE => 'Notice',
65865 E_USER_NOTICE => 'User Notice',
65866 E_STRICT => 'Runtime Notice',
65867 E_WARNING => 'Warning',
65868 E_USER_WARNING => 'User Warning',
65869 E_COMPILE_WARNING => 'Compile Warning',
65870 E_CORE_WARNING => 'Core Warning',
65871 E_USER_ERROR => 'User Error',
65872 E_RECOVERABLE_ERROR => 'Catchable Fatal Error',
65873 E_COMPILE_ERROR => 'Compile Error',
65874 E_PARSE => 'Parse Error',
65875 E_ERROR => 'Error',
65876 E_CORE_ERROR => 'Core Error',
65877 );
65878
65879 private $loggers = array(
65880 E_DEPRECATED => array(null, LogLevel::INFO),
65881 E_USER_DEPRECATED => array(null, LogLevel::INFO),
65882 E_NOTICE => array(null, LogLevel::WARNING),
65883 E_USER_NOTICE => array(null, LogLevel::WARNING),
65884 E_STRICT => array(null, LogLevel::WARNING),
65885 E_WARNING => array(null, LogLevel::WARNING),
65886 E_USER_WARNING => array(null, LogLevel::WARNING),
65887 E_COMPILE_WARNING => array(null, LogLevel::WARNING),
65888 E_CORE_WARNING => array(null, LogLevel::WARNING),
65889 E_USER_ERROR => array(null, LogLevel::CRITICAL),
65890 E_RECOVERABLE_ERROR => array(null, LogLevel::CRITICAL),
65891 E_COMPILE_ERROR => array(null, LogLevel::CRITICAL),
65892 E_PARSE => array(null, LogLevel::CRITICAL),
65893 E_ERROR => array(null, LogLevel::CRITICAL),
65894 E_CORE_ERROR => array(null, LogLevel::CRITICAL),
65895 );
65896
65897 private $thrownErrors = 0x1FFF; 
65898 private $scopedErrors = 0x1FFF; 
65899 private $tracedErrors = 0x77FB; 
65900 private $screamedErrors = 0x55; 
65901 private $loggedErrors = 0;
65902
65903 private $loggedTraces = array();
65904 private $isRecursive = 0;
65905 private $isRoot = false;
65906 private $exceptionHandler;
65907 private $bootstrappingLogger;
65908
65909 private static $reservedMemory;
65910 private static $stackedErrors = array();
65911 private static $stackedErrorLevels = array();
65912 private static $toStringException = null;
65913 private static $exitCode = 0;
65914
65915
65916
65917
65918
65919
65920 private $displayErrors = 0x1FFF;
65921
65922
65923
65924
65925
65926
65927
65928
65929
65930 public static function register($handler = null, $replace = true)
65931 {
65932 if (null === self::$reservedMemory) {
65933 self::$reservedMemory = str_repeat('x', 10240);
65934 register_shutdown_function(__CLASS__.'::handleFatalError');
65935 }
65936
65937 $levels = -1;
65938
65939 if ($handlerIsNew = !$handler instanceof self) {
65940
65941 if (null !== $handler) {
65942 $levels = $replace ? $handler : 0;
65943 $replace = true;
65944 }
65945 $handler = new static();
65946 }
65947
65948 if (null === $prev = set_error_handler(array($handler, 'handleError'))) {
65949 restore_error_handler();
65950
65951 set_error_handler(array($handler, 'handleError'), $handler->thrownErrors | $handler->loggedErrors);
65952 $handler->isRoot = true;
65953 }
65954
65955 if ($handlerIsNew && \is_array($prev) && $prev[0] instanceof self) {
65956 $handler = $prev[0];
65957 $replace = false;
65958 }
65959 if (!$replace && $prev) {
65960 restore_error_handler();
65961 $handlerIsRegistered = \is_array($prev) && $handler === $prev[0];
65962 } else {
65963 $handlerIsRegistered = true;
65964 }
65965 if (\is_array($prev = set_exception_handler(array($handler, 'handleException'))) && $prev[0] instanceof self) {
65966 restore_exception_handler();
65967 if (!$handlerIsRegistered) {
65968 $handler = $prev[0];
65969 } elseif ($handler !== $prev[0] && $replace) {
65970 set_exception_handler(array($handler, 'handleException'));
65971 $p = $prev[0]->setExceptionHandler(null);
65972 $handler->setExceptionHandler($p);
65973 $prev[0]->setExceptionHandler($p);
65974 }
65975 } else {
65976 $handler->setExceptionHandler($prev);
65977 }
65978
65979 $handler->throwAt($levels & $handler->thrownErrors, true);
65980
65981 return $handler;
65982 }
65983
65984 public function __construct(BufferingLogger $bootstrappingLogger = null)
65985 {
65986 if ($bootstrappingLogger) {
65987 $this->bootstrappingLogger = $bootstrappingLogger;
65988 $this->setDefaultLogger($bootstrappingLogger);
65989 }
65990 }
65991
65992
65993
65994
65995
65996
65997
65998
65999 public function setDefaultLogger(LoggerInterface $logger, $levels = null, $replace = false)
66000 {
66001 $loggers = array();
66002
66003 if (\is_array($levels)) {
66004 foreach ($levels as $type => $logLevel) {
66005 if (empty($this->loggers[$type][0]) || $replace || $this->loggers[$type][0] === $this->bootstrappingLogger) {
66006 $loggers[$type] = array($logger, $logLevel);
66007 }
66008 }
66009 } else {
66010 if (null === $levels) {
66011 $levels = E_ALL | E_STRICT;
66012 }
66013 foreach ($this->loggers as $type => $log) {
66014 if (($type & $levels) && (empty($log[0]) || $replace || $log[0] === $this->bootstrappingLogger)) {
66015 $log[0] = $logger;
66016 $loggers[$type] = $log;
66017 }
66018 }
66019 }
66020
66021 $this->setLoggers($loggers);
66022 }
66023
66024
66025
66026
66027
66028
66029
66030
66031
66032
66033 public function setLoggers(array $loggers)
66034 {
66035 $prevLogged = $this->loggedErrors;
66036 $prev = $this->loggers;
66037 $flush = array();
66038
66039 foreach ($loggers as $type => $log) {
66040 if (!isset($prev[$type])) {
66041 throw new \InvalidArgumentException('Unknown error type: '.$type);
66042 }
66043 if (!\is_array($log)) {
66044 $log = array($log);
66045 } elseif (!array_key_exists(0, $log)) {
66046 throw new \InvalidArgumentException('No logger provided');
66047 }
66048 if (null === $log[0]) {
66049 $this->loggedErrors &= ~$type;
66050 } elseif ($log[0] instanceof LoggerInterface) {
66051 $this->loggedErrors |= $type;
66052 } else {
66053 throw new \InvalidArgumentException('Invalid logger provided');
66054 }
66055 $this->loggers[$type] = $log + $prev[$type];
66056
66057 if ($this->bootstrappingLogger && $prev[$type][0] === $this->bootstrappingLogger) {
66058 $flush[$type] = $type;
66059 }
66060 }
66061 $this->reRegister($prevLogged | $this->thrownErrors);
66062
66063 if ($flush) {
66064 foreach ($this->bootstrappingLogger->cleanLogs() as $log) {
66065 $type = $log[2]['type'];
66066 if (!isset($flush[$type])) {
66067 $this->bootstrappingLogger->log($log[0], $log[1], $log[2]);
66068 } elseif ($this->loggers[$type][0]) {
66069 $this->loggers[$type][0]->log($this->loggers[$type][1], $log[1], $log[2]);
66070 }
66071 }
66072 }
66073
66074 return $prev;
66075 }
66076
66077
66078
66079
66080
66081
66082
66083
66084
66085
66086 public function setExceptionHandler($handler)
66087 {
66088 if (null !== $handler && !\is_callable($handler)) {
66089 throw new \LogicException('The exception handler must be a valid PHP callable.');
66090 }
66091 $prev = $this->exceptionHandler;
66092 $this->exceptionHandler = $handler;
66093
66094 return $prev;
66095 }
66096
66097
66098
66099
66100
66101
66102
66103
66104
66105 public function throwAt($levels, $replace = false)
66106 {
66107 $prev = $this->thrownErrors;
66108 $this->thrownErrors = ($levels | E_RECOVERABLE_ERROR | E_USER_ERROR) & ~E_USER_DEPRECATED & ~E_DEPRECATED;
66109 if (!$replace) {
66110 $this->thrownErrors |= $prev;
66111 }
66112 $this->reRegister($prev | $this->loggedErrors);
66113
66114
66115 $this->displayErrors = $this->thrownErrors;
66116
66117 return $prev;
66118 }
66119
66120
66121
66122
66123
66124
66125
66126
66127
66128 public function scopeAt($levels, $replace = false)
66129 {
66130 $prev = $this->scopedErrors;
66131 $this->scopedErrors = (int) $levels;
66132 if (!$replace) {
66133 $this->scopedErrors |= $prev;
66134 }
66135
66136 return $prev;
66137 }
66138
66139
66140
66141
66142
66143
66144
66145
66146
66147 public function traceAt($levels, $replace = false)
66148 {
66149 $prev = $this->tracedErrors;
66150 $this->tracedErrors = (int) $levels;
66151 if (!$replace) {
66152 $this->tracedErrors |= $prev;
66153 }
66154
66155 return $prev;
66156 }
66157
66158
66159
66160
66161
66162
66163
66164
66165
66166 public function screamAt($levels, $replace = false)
66167 {
66168 $prev = $this->screamedErrors;
66169 $this->screamedErrors = (int) $levels;
66170 if (!$replace) {
66171 $this->screamedErrors |= $prev;
66172 }
66173
66174 return $prev;
66175 }
66176
66177
66178
66179
66180 private function reRegister($prev)
66181 {
66182 if ($prev !== $this->thrownErrors | $this->loggedErrors) {
66183 $handler = set_error_handler('var_dump');
66184 $handler = \is_array($handler) ? $handler[0] : null;
66185 restore_error_handler();
66186 if ($handler === $this) {
66187 restore_error_handler();
66188 if ($this->isRoot) {
66189 set_error_handler(array($this, 'handleError'), $this->thrownErrors | $this->loggedErrors);
66190 } else {
66191 set_error_handler(array($this, 'handleError'));
66192 }
66193 }
66194 }
66195 }
66196
66197
66198
66199
66200
66201
66202
66203
66204
66205
66206
66207
66208
66209
66210
66211 public function handleError($type, $message, $file, $line)
66212 {
66213 $level = error_reporting();
66214 $silenced = 0 === ($level & $type);
66215 $level |= E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED;
66216 $log = $this->loggedErrors & $type;
66217 $throw = $this->thrownErrors & $type & $level;
66218 $type &= $level | $this->screamedErrors;
66219
66220 if (!$type || (!$log && !$throw)) {
66221 return !$silenced && $type && $log;
66222 }
66223 $scope = $this->scopedErrors & $type;
66224
66225 if (4 < $numArgs = \func_num_args()) {
66226 $context = $scope ? (func_get_arg(4) ?: array()) : array();
66227 $backtrace = 5 < $numArgs ? func_get_arg(5) : null; 
66228 } else {
66229 $context = array();
66230 $backtrace = null;
66231 }
66232
66233 if (isset($context['GLOBALS']) && $scope) {
66234 $e = $context; 
66235 unset($e['GLOBALS'], $context); 
66236 $context = $e;
66237 }
66238
66239 if (null !== $backtrace && $type & E_ERROR) {
66240
66241
66242
66243 $this->handleFatalError(compact('type', 'message', 'file', 'line', 'backtrace'));
66244
66245 return true;
66246 }
66247
66248 if ($throw) {
66249 if (null !== self::$toStringException) {
66250 $throw = self::$toStringException;
66251 self::$toStringException = null;
66252 } elseif ($scope && class_exists('Symfony\Component\Debug\Exception\ContextErrorException')) {
66253
66254 $throw = new ContextErrorException($this->levels[$type].': '.$message, 0, $type, $file, $line, $context);
66255 } else {
66256 $throw = new \ErrorException($this->levels[$type].': '.$message, 0, $type, $file, $line);
66257 }
66258
66259 if (\PHP_VERSION_ID <= 50407 && (\PHP_VERSION_ID >= 50400 || \PHP_VERSION_ID <= 50317)) {
66260
66261
66262
66263
66264 $throw->errorHandlerCanary = new ErrorHandlerCanary();
66265 }
66266
66267 if (E_USER_ERROR & $type) {
66268 $backtrace = $backtrace ?: $throw->getTrace();
66269
66270 for ($i = 1; isset($backtrace[$i]); ++$i) {
66271 if (isset($backtrace[$i]['function'], $backtrace[$i]['type'], $backtrace[$i - 1]['function'])
66272 && '__toString' === $backtrace[$i]['function']
66273 && '->' === $backtrace[$i]['type']
66274 && !isset($backtrace[$i - 1]['class'])
66275 && ('trigger_error' === $backtrace[$i - 1]['function'] || 'user_error' === $backtrace[$i - 1]['function'])
66276 ) {
66277
66278
66279
66280
66281
66282
66283
66284 foreach ($context as $e) {
66285 if (($e instanceof \Exception || $e instanceof \Throwable) && $e->__toString() === $message) {
66286 if (1 === $i) {
66287
66288 $throw = $e;
66289 break;
66290 }
66291 self::$toStringException = $e;
66292
66293 return true;
66294 }
66295 }
66296
66297 if (1 < $i) {
66298
66299 $this->handleException($throw);
66300
66301
66302 return false;
66303 }
66304 }
66305 }
66306 }
66307
66308 throw $throw;
66309 }
66310
66311
66312 $e = md5("{$type}/{$line}/{$file}\x00{$message}", true);
66313 $trace = true;
66314
66315 if (!($this->tracedErrors & $type) || isset($this->loggedTraces[$e])) {
66316 $trace = false;
66317 } else {
66318 $this->loggedTraces[$e] = 1;
66319 }
66320
66321 $e = compact('type', 'file', 'line', 'level');
66322
66323 if ($type & $level) {
66324 if ($scope) {
66325 $e['scope_vars'] = $context;
66326 if ($trace) {
66327 $e['stack'] = $backtrace ?: debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT);
66328 }
66329 } elseif ($trace) {
66330 if (null === $backtrace) {
66331 $e['stack'] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
66332 } else {
66333 foreach ($backtrace as &$frame) {
66334 unset($frame['args'], $frame);
66335 }
66336 $e['stack'] = $backtrace;
66337 }
66338 }
66339 }
66340
66341 if ($this->isRecursive) {
66342 $log = 0;
66343 } elseif (self::$stackedErrorLevels) {
66344 self::$stackedErrors[] = array($this->loggers[$type][0], ($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG, $message, $e);
66345 } else {
66346 try {
66347 $this->isRecursive = true;
66348 $this->loggers[$type][0]->log(($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG, $message, $e);
66349 $this->isRecursive = false;
66350 } catch (\Exception $e) {
66351 $this->isRecursive = false;
66352
66353 throw $e;
66354 } catch (\Throwable $e) {
66355 $this->isRecursive = false;
66356
66357 throw $e;
66358 }
66359 }
66360
66361 return !$silenced && $type && $log;
66362 }
66363
66364
66365
66366
66367
66368
66369
66370
66371
66372 public function handleException($exception, array $error = null)
66373 {
66374 if (null === $error) {
66375 self::$exitCode = 255;
66376 }
66377 if (!$exception instanceof \Exception) {
66378 $exception = new FatalThrowableError($exception);
66379 }
66380 $type = $exception instanceof FatalErrorException ? $exception->getSeverity() : E_ERROR;
66381 $handlerException = null;
66382
66383 if (($this->loggedErrors & $type) || $exception instanceof FatalThrowableError) {
66384 $e = array(
66385 'type' => $type,
66386 'file' => $exception->getFile(),
66387 'line' => $exception->getLine(),
66388 'level' => error_reporting(),
66389 'stack' => $exception->getTrace(),
66390 );
66391 if ($exception instanceof FatalErrorException) {
66392 if ($exception instanceof FatalThrowableError) {
66393 $error = array(
66394 'type' => $type,
66395 'message' => $message = $exception->getMessage(),
66396 'file' => $e['file'],
66397 'line' => $e['line'],
66398 );
66399 } else {
66400 $message = 'Fatal '.$exception->getMessage();
66401 }
66402 } elseif ($exception instanceof \ErrorException) {
66403 $message = 'Uncaught '.$exception->getMessage();
66404 if ($exception instanceof ContextErrorException) {
66405 $e['context'] = $exception->getContext();
66406 }
66407 } else {
66408 $message = 'Uncaught Exception: '.$exception->getMessage();
66409 }
66410 }
66411 if ($this->loggedErrors & $type) {
66412 try {
66413 $this->loggers[$type][0]->log($this->loggers[$type][1], $message, $e);
66414 } catch (\Exception $handlerException) {
66415 } catch (\Throwable $handlerException) {
66416 }
66417 }
66418 if ($exception instanceof FatalErrorException && !$exception instanceof OutOfMemoryException && $error) {
66419 foreach ($this->getFatalErrorHandlers() as $handler) {
66420 if ($e = $handler->handleError($error, $exception)) {
66421 $exception = $e;
66422 break;
66423 }
66424 }
66425 }
66426 $exceptionHandler = $this->exceptionHandler;
66427 $this->exceptionHandler = null;
66428 try {
66429 if (null !== $exceptionHandler) {
66430 return \call_user_func($exceptionHandler, $exception);
66431 }
66432 $handlerException = $handlerException ?: $exception;
66433 } catch (\Exception $handlerException) {
66434 } catch (\Throwable $handlerException) {
66435 }
66436 if ($exception === $handlerException) {
66437 self::$reservedMemory = null; 
66438 throw $exception; 
66439 }
66440 $this->handleException($handlerException);
66441 }
66442
66443
66444
66445
66446
66447
66448
66449
66450 public static function handleFatalError(array $error = null)
66451 {
66452 if (null === self::$reservedMemory) {
66453 return;
66454 }
66455
66456 $handler = self::$reservedMemory = null;
66457 $handlers = array();
66458 $previousHandler = null;
66459 $sameHandlerLimit = 10;
66460
66461 while (!\is_array($handler) || !$handler[0] instanceof self) {
66462 $handler = set_exception_handler('var_dump');
66463 restore_exception_handler();
66464
66465 if (!$handler) {
66466 break;
66467 }
66468 restore_exception_handler();
66469
66470 if ($handler !== $previousHandler) {
66471 array_unshift($handlers, $handler);
66472 $previousHandler = $handler;
66473 } elseif (0 === --$sameHandlerLimit) {
66474 $handler = null;
66475 break;
66476 }
66477 }
66478 foreach ($handlers as $h) {
66479 set_exception_handler($h);
66480 }
66481 if (!$handler) {
66482 return;
66483 }
66484 if ($handler !== $h) {
66485 $handler[0]->setExceptionHandler($h);
66486 }
66487 $handler = $handler[0];
66488 $handlers = array();
66489
66490 if ($exit = null === $error) {
66491 $error = error_get_last();
66492 }
66493
66494 try {
66495 while (self::$stackedErrorLevels) {
66496 static::unstackErrors();
66497 }
66498 } catch (\Exception $exception) {
66499
66500 } catch (\Throwable $exception) {
66501
66502 }
66503
66504 if ($error && $error['type'] &= E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR) {
66505
66506 $handler->throwAt(0, true);
66507 $trace = isset($error['backtrace']) ? $error['backtrace'] : null;
66508
66509 if (0 === strpos($error['message'], 'Allowed memory') || 0 === strpos($error['message'], 'Out of memory')) {
66510 $exception = new OutOfMemoryException($handler->levels[$error['type']].': '.$error['message'], 0, $error['type'], $error['file'], $error['line'], 2, false, $trace);
66511 } else {
66512 $exception = new FatalErrorException($handler->levels[$error['type']].': '.$error['message'], 0, $error['type'], $error['file'], $error['line'], 2, true, $trace);
66513 }
66514 }
66515
66516 try {
66517 if (isset($exception)) {
66518 self::$exitCode = 255;
66519 $handler->handleException($exception, $error);
66520 }
66521 } catch (FatalErrorException $e) {
66522
66523 }
66524
66525 if ($exit && self::$exitCode) {
66526 $exitCode = self::$exitCode;
66527 register_shutdown_function('register_shutdown_function', function () use ($exitCode) { exit($exitCode); });
66528 }
66529 }
66530
66531
66532
66533
66534
66535
66536
66537
66538
66539
66540
66541
66542 public static function stackErrors()
66543 {
66544 self::$stackedErrorLevels[] = error_reporting(error_reporting() | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR);
66545 }
66546
66547
66548
66549
66550 public static function unstackErrors()
66551 {
66552 $level = array_pop(self::$stackedErrorLevels);
66553
66554 if (null !== $level) {
66555 $e = error_reporting($level);
66556 if ($e !== ($level | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)) {
66557
66558 error_reporting($e);
66559 }
66560 }
66561
66562 if (empty(self::$stackedErrorLevels)) {
66563 $errors = self::$stackedErrors;
66564 self::$stackedErrors = array();
66565
66566 foreach ($errors as $e) {
66567 $e[0]->log($e[1], $e[2], $e[3]);
66568 }
66569 }
66570 }
66571
66572
66573
66574
66575
66576
66577
66578
66579 protected function getFatalErrorHandlers()
66580 {
66581 return array(
66582 new UndefinedFunctionFatalErrorHandler(),
66583 new UndefinedMethodFatalErrorHandler(),
66584 new ClassNotFoundFatalErrorHandler(),
66585 );
66586 }
66587
66588
66589
66590
66591
66592
66593
66594
66595 public function setLevel($level)
66596 {
66597 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.6 and will be removed in 3.0. Use the throwAt() method instead.', E_USER_DEPRECATED);
66598
66599 $level = null === $level ? error_reporting() : $level;
66600 $this->throwAt($level, true);
66601 }
66602
66603
66604
66605
66606
66607
66608
66609
66610 public function setDisplayErrors($displayErrors)
66611 {
66612 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.6 and will be removed in 3.0. Use the throwAt() method instead.', E_USER_DEPRECATED);
66613
66614 if ($displayErrors) {
66615 $this->throwAt($this->displayErrors, true);
66616 } else {
66617 $displayErrors = $this->displayErrors;
66618 $this->throwAt(0, true);
66619 $this->displayErrors = $displayErrors;
66620 }
66621 }
66622
66623
66624
66625
66626
66627
66628
66629
66630
66631 public static function setLogger(LoggerInterface $logger, $channel = 'deprecation')
66632 {
66633 @trigger_error('The '.__METHOD__.' static method is deprecated since Symfony 2.6 and will be removed in 3.0. Use the setLoggers() or setDefaultLogger() methods instead.', E_USER_DEPRECATED);
66634
66635 $handler = set_error_handler('var_dump');
66636 $handler = \is_array($handler) ? $handler[0] : null;
66637 restore_error_handler();
66638 if (!$handler instanceof self) {
66639 return;
66640 }
66641 if ('deprecation' === $channel) {
66642 $handler->setDefaultLogger($logger, E_DEPRECATED | E_USER_DEPRECATED, true);
66643 $handler->screamAt(E_DEPRECATED | E_USER_DEPRECATED);
66644 } elseif ('scream' === $channel) {
66645 $handler->setDefaultLogger($logger, E_ALL | E_STRICT, false);
66646 $handler->screamAt(E_ALL | E_STRICT);
66647 } elseif ('emergency' === $channel) {
66648 $handler->setDefaultLogger($logger, E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR, true);
66649 $handler->screamAt(E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR);
66650 }
66651 }
66652
66653
66654
66655
66656 public function handle($level, $message, $file = 'unknown', $line = 0, $context = array())
66657 {
66658 $this->handleError(E_USER_DEPRECATED, 'The '.__METHOD__.' method is deprecated since Symfony 2.6 and will be removed in 3.0. Use the handleError() method instead.', __FILE__, __LINE__, array());
66659
66660 return $this->handleError($level, $message, $file, $line, (array) $context);
66661 }
66662
66663
66664
66665
66666
66667
66668 public function handleFatal()
66669 {
66670 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.6 and will be removed in 3.0. Use the handleFatalError() method instead.', E_USER_DEPRECATED);
66671
66672 static::handleFatalError();
66673 }
66674 }
66675
66676
66677
66678
66679
66680
66681
66682
66683 class ErrorHandlerCanary
66684 {
66685 private static $displayErrors = null;
66686
66687 public function __construct()
66688 {
66689 if (null === self::$displayErrors) {
66690 self::$displayErrors = ini_set('display_errors', 1);
66691 }
66692 }
66693
66694 public function __destruct()
66695 {
66696 if (null !== self::$displayErrors) {
66697 ini_set('display_errors', self::$displayErrors);
66698 self::$displayErrors = null;
66699 }
66700 }
66701 }
66702 <?php
66703
66704
66705
66706
66707
66708
66709
66710
66711
66712
66713 namespace Symfony\Component\Debug\Exception;
66714
66715
66716
66717
66718
66719
66720 class ClassNotFoundException extends FatalErrorException
66721 {
66722 public function __construct($message, \ErrorException $previous)
66723 {
66724 parent::__construct(
66725 $message,
66726 $previous->getCode(),
66727 $previous->getSeverity(),
66728 $previous->getFile(),
66729 $previous->getLine(),
66730 null,
66731 true,
66732 null,
66733 $previous->getPrevious()
66734 );
66735 $this->setTrace($previous->getTrace());
66736 }
66737 }
66738 <?php
66739
66740
66741
66742
66743
66744
66745
66746
66747
66748
66749 namespace Symfony\Component\Debug\Exception;
66750
66751
66752
66753
66754
66755
66756 class ContextErrorException extends \ErrorException
66757 {
66758 private $context = array();
66759
66760 public function __construct($message, $code, $severity, $filename, $lineno, $context = array())
66761 {
66762 parent::__construct($message, $code, $severity, $filename, $lineno);
66763 $this->context = $context;
66764 }
66765
66766
66767
66768
66769 public function getContext()
66770 {
66771 return $this->context;
66772 }
66773 }
66774 <?php
66775
66776
66777
66778
66779
66780
66781
66782
66783
66784
66785 namespace Symfony\Component\Debug\Exception;
66786
66787 @trigger_error('The '.__NAMESPACE__.'\DummyException class is deprecated since Symfony 2.5 and will be removed in 3.0.', E_USER_DEPRECATED);
66788
66789
66790
66791
66792
66793
66794 class DummyException extends \ErrorException
66795 {
66796 }
66797 <?php
66798
66799
66800
66801
66802
66803
66804
66805
66806
66807
66808 namespace Symfony\Component\HttpKernel\Exception;
66809
66810
66811
66812
66813
66814
66815
66816
66817
66818
66819 class FatalErrorException extends \ErrorException
66820 {
66821 }
66822
66823 namespace Symfony\Component\Debug\Exception;
66824
66825 use Symfony\Component\HttpKernel\Exception\FatalErrorException as LegacyFatalErrorException;
66826
66827
66828
66829
66830
66831
66832 class FatalErrorException extends LegacyFatalErrorException
66833 {
66834 public function __construct($message, $code, $severity, $filename, $lineno, $traceOffset = null, $traceArgs = true, array $trace = null, $previous = null)
66835 {
66836 parent::__construct($message, $code, $severity, $filename, $lineno, $previous);
66837
66838 if (null !== $trace) {
66839 if (!$traceArgs) {
66840 foreach ($trace as &$frame) {
66841 unset($frame['args'], $frame['this'], $frame);
66842 }
66843 }
66844
66845 $this->setTrace($trace);
66846 } elseif (null !== $traceOffset) {
66847 if (\function_exists('xdebug_get_function_stack')) {
66848 $trace = xdebug_get_function_stack();
66849 if (0 < $traceOffset) {
66850 array_splice($trace, -$traceOffset);
66851 }
66852
66853 foreach ($trace as &$frame) {
66854 if (!isset($frame['type'])) {
66855
66856 if (isset($frame['class'])) {
66857 $frame['type'] = '::';
66858 }
66859 } elseif ('dynamic' === $frame['type']) {
66860 $frame['type'] = '->';
66861 } elseif ('static' === $frame['type']) {
66862 $frame['type'] = '::';
66863 }
66864
66865
66866 if (!$traceArgs) {
66867 unset($frame['params'], $frame['args']);
66868 } elseif (isset($frame['params']) && !isset($frame['args'])) {
66869 $frame['args'] = $frame['params'];
66870 unset($frame['params']);
66871 }
66872 }
66873
66874 unset($frame);
66875 $trace = array_reverse($trace);
66876 } elseif (\function_exists('symfony_debug_backtrace')) {
66877 $trace = symfony_debug_backtrace();
66878 if (0 < $traceOffset) {
66879 array_splice($trace, 0, $traceOffset);
66880 }
66881 } else {
66882 $trace = array();
66883 }
66884
66885 $this->setTrace($trace);
66886 }
66887 }
66888
66889 protected function setTrace($trace)
66890 {
66891 $traceReflector = new \ReflectionProperty('Exception', 'trace');
66892 $traceReflector->setAccessible(true);
66893 $traceReflector->setValue($this, $trace);
66894 }
66895 }
66896 <?php
66897
66898
66899
66900
66901
66902
66903
66904
66905
66906
66907 namespace Symfony\Component\Debug\Exception;
66908
66909
66910
66911
66912
66913
66914 class FatalThrowableError extends FatalErrorException
66915 {
66916 public function __construct(\Throwable $e)
66917 {
66918 if ($e instanceof \ParseError) {
66919 $message = 'Parse error: '.$e->getMessage();
66920 $severity = E_PARSE;
66921 } elseif ($e instanceof \TypeError) {
66922 $message = 'Type error: '.$e->getMessage();
66923 $severity = E_RECOVERABLE_ERROR;
66924 } else {
66925 $message = $e->getMessage();
66926 $severity = E_ERROR;
66927 }
66928
66929 \ErrorException::__construct(
66930 $message,
66931 $e->getCode(),
66932 $severity,
66933 $e->getFile(),
66934 $e->getLine(),
66935 $e->getPrevious()
66936 );
66937
66938 $this->setTrace($e->getTrace());
66939 }
66940 }
66941 <?php
66942
66943
66944
66945
66946
66947
66948
66949
66950
66951
66952 namespace Symfony\Component\HttpKernel\Exception;
66953
66954 use Symfony\Component\Debug\Exception\FlattenException as DebugFlattenException;
66955
66956
66957
66958
66959
66960
66961
66962
66963
66964
66965 class FlattenException
66966 {
66967 private $handler;
66968
66969 public static function __callStatic($method, $args)
66970 {
66971 if (!method_exists('Symfony\Component\Debug\Exception\FlattenException', $method)) {
66972 throw new \BadMethodCallException(sprintf('Call to undefined method %s::%s()', \get_called_class(), $method));
66973 }
66974
66975 return \call_user_func_array(array('Symfony\Component\Debug\Exception\FlattenException', $method), $args);
66976 }
66977
66978 public function __call($method, $args)
66979 {
66980 if (!isset($this->handler)) {
66981 $this->handler = new DebugFlattenException();
66982 }
66983
66984 if (!method_exists($this->handler, $method)) {
66985 throw new \BadMethodCallException(sprintf('Call to undefined method %s::%s()', \get_class($this), $method));
66986 }
66987
66988 return \call_user_func_array(array($this->handler, $method), $args);
66989 }
66990 }
66991
66992 namespace Symfony\Component\Debug\Exception;
66993
66994 use Symfony\Component\HttpKernel\Exception\FlattenException as LegacyFlattenException;
66995 use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
66996
66997
66998
66999
67000
67001
67002
67003
67004 class FlattenException extends LegacyFlattenException
67005 {
67006 private $message;
67007 private $code;
67008 private $previous;
67009 private $trace;
67010 private $class;
67011 private $statusCode;
67012 private $headers;
67013 private $file;
67014 private $line;
67015
67016 public static function create(\Exception $exception, $statusCode = null, array $headers = array())
67017 {
67018 $e = new static();
67019 $e->setMessage($exception->getMessage());
67020 $e->setCode($exception->getCode());
67021
67022 if ($exception instanceof HttpExceptionInterface) {
67023 $statusCode = $exception->getStatusCode();
67024 $headers = array_merge($headers, $exception->getHeaders());
67025 }
67026
67027 if (null === $statusCode) {
67028 $statusCode = 500;
67029 }
67030
67031 $e->setStatusCode($statusCode);
67032 $e->setHeaders($headers);
67033 $e->setTraceFromException($exception);
67034 $e->setClass(\get_class($exception));
67035 $e->setFile($exception->getFile());
67036 $e->setLine($exception->getLine());
67037
67038 $previous = $exception->getPrevious();
67039
67040 if ($previous instanceof \Exception) {
67041 $e->setPrevious(static::create($previous));
67042 } elseif ($previous instanceof \Throwable) {
67043 $e->setPrevious(static::create(new FatalThrowableError($previous)));
67044 }
67045
67046 return $e;
67047 }
67048
67049 public function toArray()
67050 {
67051 $exceptions = array();
67052 foreach (array_merge(array($this), $this->getAllPrevious()) as $exception) {
67053 $exceptions[] = array(
67054 'message' => $exception->getMessage(),
67055 'class' => $exception->getClass(),
67056 'trace' => $exception->getTrace(),
67057 );
67058 }
67059
67060 return $exceptions;
67061 }
67062
67063 public function getStatusCode()
67064 {
67065 return $this->statusCode;
67066 }
67067
67068 public function setStatusCode($code)
67069 {
67070 $this->statusCode = $code;
67071 }
67072
67073 public function getHeaders()
67074 {
67075 return $this->headers;
67076 }
67077
67078 public function setHeaders(array $headers)
67079 {
67080 $this->headers = $headers;
67081 }
67082
67083 public function getClass()
67084 {
67085 return $this->class;
67086 }
67087
67088 public function setClass($class)
67089 {
67090 $this->class = $class;
67091 }
67092
67093 public function getFile()
67094 {
67095 return $this->file;
67096 }
67097
67098 public function setFile($file)
67099 {
67100 $this->file = $file;
67101 }
67102
67103 public function getLine()
67104 {
67105 return $this->line;
67106 }
67107
67108 public function setLine($line)
67109 {
67110 $this->line = $line;
67111 }
67112
67113 public function getMessage()
67114 {
67115 return $this->message;
67116 }
67117
67118 public function setMessage($message)
67119 {
67120 $this->message = $message;
67121 }
67122
67123 public function getCode()
67124 {
67125 return $this->code;
67126 }
67127
67128 public function setCode($code)
67129 {
67130 $this->code = $code;
67131 }
67132
67133 public function getPrevious()
67134 {
67135 return $this->previous;
67136 }
67137
67138 public function setPrevious(FlattenException $previous)
67139 {
67140 $this->previous = $previous;
67141 }
67142
67143 public function getAllPrevious()
67144 {
67145 $exceptions = array();
67146 $e = $this;
67147 while ($e = $e->getPrevious()) {
67148 $exceptions[] = $e;
67149 }
67150
67151 return $exceptions;
67152 }
67153
67154 public function getTrace()
67155 {
67156 return $this->trace;
67157 }
67158
67159 public function setTraceFromException(\Exception $exception)
67160 {
67161 $this->setTrace($exception->getTrace(), $exception->getFile(), $exception->getLine());
67162 }
67163
67164 public function setTrace($trace, $file, $line)
67165 {
67166 $this->trace = array();
67167 $this->trace[] = array(
67168 'namespace' => '',
67169 'short_class' => '',
67170 'class' => '',
67171 'type' => '',
67172 'function' => '',
67173 'file' => $file,
67174 'line' => $line,
67175 'args' => array(),
67176 );
67177 foreach ($trace as $entry) {
67178 $class = '';
67179 $namespace = '';
67180 if (isset($entry['class'])) {
67181 $parts = explode('\\', $entry['class']);
67182 $class = array_pop($parts);
67183 $namespace = implode('\\', $parts);
67184 }
67185
67186 $this->trace[] = array(
67187 'namespace' => $namespace,
67188 'short_class' => $class,
67189 'class' => isset($entry['class']) ? $entry['class'] : '',
67190 'type' => isset($entry['type']) ? $entry['type'] : '',
67191 'function' => isset($entry['function']) ? $entry['function'] : null,
67192 'file' => isset($entry['file']) ? $entry['file'] : null,
67193 'line' => isset($entry['line']) ? $entry['line'] : null,
67194 'args' => isset($entry['args']) ? $this->flattenArgs($entry['args']) : array(),
67195 );
67196 }
67197 }
67198
67199 private function flattenArgs($args, $level = 0, &$count = 0)
67200 {
67201 $result = array();
67202 foreach ($args as $key => $value) {
67203 if (++$count > 1e4) {
67204 return array('array', '*SKIPPED over 10000 entries*');
67205 }
67206 if ($value instanceof \__PHP_Incomplete_Class) {
67207
67208 $result[$key] = array('incomplete-object', $this->getClassNameFromIncomplete($value));
67209 } elseif (\is_object($value)) {
67210 $result[$key] = array('object', \get_class($value));
67211 } elseif (\is_array($value)) {
67212 if ($level > 10) {
67213 $result[$key] = array('array', '*DEEP NESTED ARRAY*');
67214 } else {
67215 $result[$key] = array('array', $this->flattenArgs($value, $level + 1, $count));
67216 }
67217 } elseif (null === $value) {
67218 $result[$key] = array('null', null);
67219 } elseif (\is_bool($value)) {
67220 $result[$key] = array('boolean', $value);
67221 } elseif (\is_resource($value)) {
67222 $result[$key] = array('resource', get_resource_type($value));
67223 } else {
67224 $result[$key] = array('string', (string) $value);
67225 }
67226 }
67227
67228 return $result;
67229 }
67230
67231 private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value)
67232 {
67233 $array = new \ArrayObject($value);
67234
67235 return $array['__PHP_Incomplete_Class_Name'];
67236 }
67237 }
67238 <?php
67239
67240
67241
67242
67243
67244
67245
67246
67247
67248
67249 namespace Symfony\Component\Debug\Exception;
67250
67251
67252
67253
67254
67255
67256 class OutOfMemoryException extends FatalErrorException
67257 {
67258 }
67259 <?php
67260
67261
67262
67263
67264
67265
67266
67267
67268
67269
67270 namespace Symfony\Component\Debug\Exception;
67271
67272
67273
67274
67275
67276
67277 class UndefinedFunctionException extends FatalErrorException
67278 {
67279 public function __construct($message, \ErrorException $previous)
67280 {
67281 parent::__construct(
67282 $message,
67283 $previous->getCode(),
67284 $previous->getSeverity(),
67285 $previous->getFile(),
67286 $previous->getLine(),
67287 null,
67288 true,
67289 null,
67290 $previous->getPrevious()
67291 );
67292 $this->setTrace($previous->getTrace());
67293 }
67294 }
67295 <?php
67296
67297
67298
67299
67300
67301
67302
67303
67304
67305
67306 namespace Symfony\Component\Debug\Exception;
67307
67308
67309
67310
67311
67312
67313 class UndefinedMethodException extends FatalErrorException
67314 {
67315 public function __construct($message, \ErrorException $previous)
67316 {
67317 parent::__construct(
67318 $message,
67319 $previous->getCode(),
67320 $previous->getSeverity(),
67321 $previous->getFile(),
67322 $previous->getLine(),
67323 null,
67324 true,
67325 null,
67326 $previous->getPrevious()
67327 );
67328 $this->setTrace($previous->getTrace());
67329 }
67330 }
67331 <?php
67332
67333
67334
67335
67336
67337
67338
67339
67340
67341
67342 namespace Symfony\Component\Debug;
67343
67344 use Symfony\Component\Debug\Exception\FlattenException;
67345 use Symfony\Component\Debug\Exception\OutOfMemoryException;
67346 use Symfony\Component\HttpFoundation\Response;
67347
67348
67349
67350
67351
67352
67353
67354
67355
67356
67357
67358
67359
67360 class ExceptionHandler
67361 {
67362 private $debug;
67363 private $charset;
67364 private $handler;
67365 private $caughtBuffer;
67366 private $caughtLength;
67367 private $fileLinkFormat;
67368
67369 public function __construct($debug = true, $charset = null, $fileLinkFormat = null)
67370 {
67371 if (false !== strpos($charset, '%')) {
67372 @trigger_error('Providing $fileLinkFormat as second argument to '.__METHOD__.' is deprecated since Symfony 2.8 and will be unsupported in 3.0. Please provide it as third argument, after $charset.', E_USER_DEPRECATED);
67373
67374
67375 $pivot = $fileLinkFormat;
67376 $fileLinkFormat = $charset;
67377 $charset = $pivot;
67378 }
67379 $this->debug = $debug;
67380 $this->charset = $charset ?: ini_get('default_charset') ?: 'UTF-8';
67381 $this->fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
67382 }
67383
67384
67385
67386
67387
67388
67389
67390
67391
67392
67393 public static function register($debug = true, $charset = null, $fileLinkFormat = null)
67394 {
67395 $handler = new static($debug, $charset, $fileLinkFormat);
67396
67397 $prev = set_exception_handler(array($handler, 'handle'));
67398 if (\is_array($prev) && $prev[0] instanceof ErrorHandler) {
67399 restore_exception_handler();
67400 $prev[0]->setExceptionHandler(array($handler, 'handle'));
67401 }
67402
67403 return $handler;
67404 }
67405
67406
67407
67408
67409
67410
67411
67412
67413 public function setHandler($handler)
67414 {
67415 if (null !== $handler && !\is_callable($handler)) {
67416 throw new \LogicException('The exception handler must be a valid PHP callable.');
67417 }
67418 $old = $this->handler;
67419 $this->handler = $handler;
67420
67421 return $old;
67422 }
67423
67424
67425
67426
67427
67428
67429
67430
67431 public function setFileLinkFormat($format)
67432 {
67433 $old = $this->fileLinkFormat;
67434 $this->fileLinkFormat = $format;
67435
67436 return $old;
67437 }
67438
67439
67440
67441
67442
67443
67444
67445
67446
67447 public function handle(\Exception $exception)
67448 {
67449 if (null === $this->handler || $exception instanceof OutOfMemoryException) {
67450 $this->failSafeHandle($exception);
67451
67452 return;
67453 }
67454
67455 $caughtLength = $this->caughtLength = 0;
67456
67457 ob_start(array($this, 'catchOutput'));
67458 $this->failSafeHandle($exception);
67459 while (null === $this->caughtBuffer && ob_end_flush()) {
67460
67461 }
67462 if (isset($this->caughtBuffer[0])) {
67463 ob_start(array($this, 'cleanOutput'));
67464 echo $this->caughtBuffer;
67465 $caughtLength = ob_get_length();
67466 }
67467 $this->caughtBuffer = null;
67468
67469 try {
67470 \call_user_func($this->handler, $exception);
67471 $this->caughtLength = $caughtLength;
67472 } catch (\Exception $e) {
67473 if (!$caughtLength) {
67474
67475 throw $exception;
67476 }
67477 }
67478 }
67479
67480
67481
67482
67483
67484
67485
67486
67487 private function failSafeHandle(\Exception $exception)
67488 {
67489 if (class_exists('Symfony\Component\HttpFoundation\Response', false)
67490 && __CLASS__ !== \get_class($this)
67491 && ($reflector = new \ReflectionMethod($this, 'createResponse'))
67492 && __CLASS__ !== $reflector->class
67493 ) {
67494 $response = $this->createResponse($exception);
67495 $response->sendHeaders();
67496 $response->sendContent();
67497 @trigger_error(sprintf("The %s::createResponse method is deprecated since Symfony 2.8 and won't be called anymore when handling an exception in 3.0.", $reflector->class), E_USER_DEPRECATED);
67498
67499 return;
67500 }
67501
67502 $this->sendPhpResponse($exception);
67503 }
67504
67505
67506
67507
67508
67509
67510
67511
67512
67513 public function sendPhpResponse($exception)
67514 {
67515 if (!$exception instanceof FlattenException) {
67516 $exception = FlattenException::create($exception);
67517 }
67518
67519 if (!headers_sent()) {
67520 header(sprintf('HTTP/1.0 %s', $exception->getStatusCode()));
67521 foreach ($exception->getHeaders() as $name => $value) {
67522 header($name.': '.$value, false);
67523 }
67524 header('Content-Type: text/html; charset='.$this->charset);
67525 }
67526
67527 echo $this->decorate($this->getContent($exception), $this->getStylesheet($exception));
67528 }
67529
67530
67531
67532
67533
67534
67535
67536
67537
67538
67539 public function createResponse($exception)
67540 {
67541 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
67542
67543 if (!$exception instanceof FlattenException) {
67544 $exception = FlattenException::create($exception);
67545 }
67546
67547 return Response::create($this->getHtml($exception), $exception->getStatusCode(), $exception->getHeaders())->setCharset($this->charset);
67548 }
67549
67550
67551
67552
67553
67554
67555
67556
67557 public function getHtml($exception)
67558 {
67559 if (!$exception instanceof FlattenException) {
67560 $exception = FlattenException::create($exception);
67561 }
67562
67563 return $this->decorate($this->getContent($exception), $this->getStylesheet($exception));
67564 }
67565
67566
67567
67568
67569
67570
67571 public function getContent(FlattenException $exception)
67572 {
67573 switch ($exception->getStatusCode()) {
67574 case 404:
67575 $title = 'Sorry, the page you are looking for could not be found.';
67576 break;
67577 default:
67578 $title = 'Whoops, looks like something went wrong.';
67579 }
67580
67581 $content = '';
67582 if ($this->debug) {
67583 try {
67584 $count = \count($exception->getAllPrevious());
67585 $total = $count + 1;
67586 foreach ($exception->toArray() as $position => $e) {
67587 $ind = $count - $position + 1;
67588 $class = $this->formatClass($e['class']);
67589 $message = nl2br($this->escapeHtml($e['message']));
67590 $content .= sprintf(<<<'EOF'
67591                         <h2 class="block_exception clear_fix">
67592                             <span class="exception_counter">%d/%d</span>
67593                             <span class="exception_title">%s%s:</span>
67594                             <span class="exception_message">%s</span>
67595                         </h2>
67596                         <div class="block">
67597                             <ol class="traces list_exception">
67598
67599 EOF
67600 , $ind, $total, $class, $this->formatPath($e['trace'][0]['file'], $e['trace'][0]['line']), $message);
67601 foreach ($e['trace'] as $trace) {
67602 $content .= '       <li>';
67603 if ($trace['function']) {
67604 $content .= sprintf('at %s%s%s(%s)', $this->formatClass($trace['class']), $trace['type'], $trace['function'], $this->formatArgs($trace['args']));
67605 }
67606 if (isset($trace['file']) && isset($trace['line'])) {
67607 $content .= $this->formatPath($trace['file'], $trace['line']);
67608 }
67609 $content .= "</li>\n";
67610 }
67611
67612 $content .= "    </ol>\n</div>\n";
67613 }
67614 } catch (\Exception $e) {
67615
67616 if ($this->debug) {
67617 $title = sprintf('Exception thrown when handling an exception (%s: %s)', \get_class($e), $this->escapeHtml($e->getMessage()));
67618 } else {
67619 $title = 'Whoops, looks like something went wrong.';
67620 }
67621 }
67622 }
67623
67624 return <<<EOF
67625             <div id="sf-resetcontent" class="sf-reset">
67626                 <h1>$title</h1>
67627                 $content
67628             </div>
67629 EOF;
67630 }
67631
67632
67633
67634
67635
67636
67637 public function getStylesheet(FlattenException $exception)
67638 {
67639 return <<<'EOF'
67640             .sf-reset { font: 11px Verdana, Arial, sans-serif; color: #333 }
67641             .sf-reset .clear { clear:both; height:0; font-size:0; line-height:0; }
67642             .sf-reset .clear_fix:after { display:block; height:0; clear:both; visibility:hidden; }
67643             .sf-reset .clear_fix { display:inline-block; }
67644             .sf-reset * html .clear_fix { height:1%; }
67645             .sf-reset .clear_fix { display:block; }
67646             .sf-reset, .sf-reset .block { margin: auto }
67647             .sf-reset abbr { border-bottom: 1px dotted #000; cursor: help; }
67648             .sf-reset p { font-size:14px; line-height:20px; color:#868686; padding-bottom:20px }
67649             .sf-reset strong { font-weight:bold; }
67650             .sf-reset a { color:#6c6159; cursor: default; }
67651             .sf-reset a img { border:none; }
67652             .sf-reset a:hover { text-decoration:underline; }
67653             .sf-reset em { font-style:italic; }
67654             .sf-reset h1, .sf-reset h2 { font: 20px Georgia, "Times New Roman", Times, serif }
67655             .sf-reset .exception_counter { background-color: #fff; color: #333; padding: 6px; float: left; margin-right: 10px; float: left; display: block; }
67656             .sf-reset .exception_title { margin-left: 3em; margin-bottom: 0.7em; display: block; }
67657             .sf-reset .exception_message { margin-left: 3em; display: block; }
67658             .sf-reset .traces li { font-size:12px; padding: 2px 4px; list-style-type:decimal; margin-left:20px; }
67659             .sf-reset .block { background-color:#FFFFFF; padding:10px 28px; margin-bottom:20px;
67660                 -webkit-border-bottom-right-radius: 16px;
67661                 -webkit-border-bottom-left-radius: 16px;
67662                 -moz-border-radius-bottomright: 16px;
67663                 -moz-border-radius-bottomleft: 16px;
67664                 border-bottom-right-radius: 16px;
67665                 border-bottom-left-radius: 16px;
67666                 border-bottom:1px solid #ccc;
67667                 border-right:1px solid #ccc;
67668                 border-left:1px solid #ccc;
67669                 word-wrap: break-word;
67670             }
67671             .sf-reset .block_exception { background-color:#ddd; color: #333; padding:20px;
67672                 -webkit-border-top-left-radius: 16px;
67673                 -webkit-border-top-right-radius: 16px;
67674                 -moz-border-radius-topleft: 16px;
67675                 -moz-border-radius-topright: 16px;
67676                 border-top-left-radius: 16px;
67677                 border-top-right-radius: 16px;
67678                 border-top:1px solid #ccc;
67679                 border-right:1px solid #ccc;
67680                 border-left:1px solid #ccc;
67681                 overflow: hidden;
67682                 word-wrap: break-word;
67683             }
67684             .sf-reset a { background:none; color:#868686; text-decoration:none; }
67685             .sf-reset a:hover { background:none; color:#313131; text-decoration:underline; }
67686             .sf-reset ol { padding: 10px 0; }
67687             .sf-reset h1 { background-color:#FFFFFF; padding: 15px 28px; margin-bottom: 20px;
67688                 -webkit-border-radius: 10px;
67689                 -moz-border-radius: 10px;
67690                 border-radius: 10px;
67691                 border: 1px solid #ccc;
67692             }
67693 EOF;
67694 }
67695
67696 private function decorate($content, $css)
67697 {
67698 return <<<EOF
67699 <!DOCTYPE html>
67700 <html>
67701     <head>
67702         <meta charset="{$this->charset}" />
67703         <meta name="robots" content="noindex,nofollow" />
67704         <style>
67705             /* Copyright (c) 2010, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.com/yui/license.html */
67706             html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:text-top;}sub{vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}input,textarea,select{*font-size:100%;}legend{color:#000;}
67707
67708             html { background: #eee; padding: 10px }
67709             img { border: 0; }
67710             #sf-resetcontent { width:970px; margin:0 auto; }
67711             $css
67712         </style>
67713     </head>
67714     <body>
67715         $content
67716     </body>
67717 </html>
67718 EOF;
67719 }
67720
67721 private function formatClass($class)
67722 {
67723 $parts = explode('\\', $class);
67724
67725 return sprintf('<abbr title="%s">%s</abbr>', $class, array_pop($parts));
67726 }
67727
67728 private function formatPath($path, $line)
67729 {
67730 $path = $this->escapeHtml($path);
67731 $file = preg_match('#[^/\\\\]*$#', $path, $file) ? $file[0] : $path;
67732
67733 if ($linkFormat = $this->fileLinkFormat) {
67734 $link = strtr($this->escapeHtml($linkFormat), array('%f' => $path, '%l' => (int) $line));
67735
67736 return sprintf(' in <a href="%s" title="Go to source">%s line %d</a>', $link, $file, $line);
67737 }
67738
67739 return sprintf(' in <a title="%s line %3$d" ondblclick="var f=this.innerHTML;this.innerHTML=this.title;this.title=f;">%s line %d</a>', $path, $file, $line);
67740 }
67741
67742
67743
67744
67745
67746
67747
67748
67749 private function formatArgs(array $args)
67750 {
67751 $result = array();
67752 foreach ($args as $key => $item) {
67753 if ('object' === $item[0]) {
67754 $formattedValue = sprintf('<em>object</em>(%s)', $this->formatClass($item[1]));
67755 } elseif ('array' === $item[0]) {
67756 $formattedValue = sprintf('<em>array</em>(%s)', \is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]);
67757 } elseif ('string' === $item[0]) {
67758 $formattedValue = sprintf("'%s'", $this->escapeHtml($item[1]));
67759 } elseif ('null' === $item[0]) {
67760 $formattedValue = '<em>null</em>';
67761 } elseif ('boolean' === $item[0]) {
67762 $formattedValue = '<em>'.strtolower(var_export($item[1], true)).'</em>';
67763 } elseif ('resource' === $item[0]) {
67764 $formattedValue = '<em>resource</em>';
67765 } else {
67766 $formattedValue = str_replace("\n", '', var_export($this->escapeHtml((string) $item[1]), true));
67767 }
67768
67769 $result[] = \is_int($key) ? $formattedValue : sprintf("'%s' => %s", $this->escapeHtml($key), $formattedValue);
67770 }
67771
67772 return implode(', ', $result);
67773 }
67774
67775
67776
67777
67778
67779
67780 protected static function utf8Htmlize($str)
67781 {
67782 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.7 and will be removed in 3.0.', E_USER_DEPRECATED);
67783
67784 return htmlspecialchars($str, ENT_QUOTES | (\PHP_VERSION_ID >= 50400 ? ENT_SUBSTITUTE : 0), 'UTF-8');
67785 }
67786
67787
67788
67789
67790 private function escapeHtml($str)
67791 {
67792 return htmlspecialchars($str, ENT_QUOTES | (\PHP_VERSION_ID >= 50400 ? ENT_SUBSTITUTE : 0), $this->charset);
67793 }
67794
67795
67796
67797
67798 public function catchOutput($buffer)
67799 {
67800 $this->caughtBuffer = $buffer;
67801
67802 return '';
67803 }
67804
67805
67806
67807
67808 public function cleanOutput($buffer)
67809 {
67810 if ($this->caughtLength) {
67811
67812 $cleanBuffer = substr_replace($buffer, '', 0, $this->caughtLength);
67813 if (isset($cleanBuffer[0])) {
67814 $buffer = $cleanBuffer;
67815 }
67816 }
67817
67818 return $buffer;
67819 }
67820 }
67821 <?php
67822
67823
67824
67825
67826
67827
67828
67829
67830
67831
67832 namespace Symfony\Component\Debug\FatalErrorHandler;
67833
67834 use Composer\Autoload\ClassLoader as ComposerClassLoader;
67835 use Symfony\Component\ClassLoader\ClassLoader as SymfonyClassLoader;
67836 use Symfony\Component\ClassLoader\UniversalClassLoader as SymfonyUniversalClassLoader;
67837 use Symfony\Component\Debug\DebugClassLoader;
67838 use Symfony\Component\Debug\Exception\ClassNotFoundException;
67839 use Symfony\Component\Debug\Exception\FatalErrorException;
67840
67841
67842
67843
67844
67845
67846 class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
67847 {
67848
67849
67850
67851 public function handleError(array $error, FatalErrorException $exception)
67852 {
67853 $messageLen = \strlen($error['message']);
67854 $notFoundSuffix = '\' not found';
67855 $notFoundSuffixLen = \strlen($notFoundSuffix);
67856 if ($notFoundSuffixLen > $messageLen) {
67857 return;
67858 }
67859
67860 if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
67861 return;
67862 }
67863
67864 foreach (array('class', 'interface', 'trait') as $typeName) {
67865 $prefix = ucfirst($typeName).' \'';
67866 $prefixLen = \strlen($prefix);
67867 if (0 !== strpos($error['message'], $prefix)) {
67868 continue;
67869 }
67870
67871 $fullyQualifiedClassName = substr($error['message'], $prefixLen, -$notFoundSuffixLen);
67872 if (false !== $namespaceSeparatorIndex = strrpos($fullyQualifiedClassName, '\\')) {
67873 $className = substr($fullyQualifiedClassName, $namespaceSeparatorIndex + 1);
67874 $namespacePrefix = substr($fullyQualifiedClassName, 0, $namespaceSeparatorIndex);
67875 $message = sprintf('Attempted to load %s "%s" from namespace "%s".', $typeName, $className, $namespacePrefix);
67876 $tail = ' for another namespace?';
67877 } else {
67878 $className = $fullyQualifiedClassName;
67879 $message = sprintf('Attempted to load %s "%s" from the global namespace.', $typeName, $className);
67880 $tail = '?';
67881 }
67882
67883 if ($candidates = $this->getClassCandidates($className)) {
67884 $tail = array_pop($candidates).'"?';
67885 if ($candidates) {
67886 $tail = ' for e.g. "'.implode('", "', $candidates).'" or "'.$tail;
67887 } else {
67888 $tail = ' for "'.$tail;
67889 }
67890 }
67891 $message .= "\nDid you forget a \"use\" statement".$tail;
67892
67893 return new ClassNotFoundException($message, $exception);
67894 }
67895 }
67896
67897
67898
67899
67900
67901
67902
67903
67904
67905
67906
67907 private function getClassCandidates($class)
67908 {
67909 if (!\is_array($functions = spl_autoload_functions())) {
67910 return array();
67911 }
67912
67913
67914 $classes = array();
67915
67916 foreach ($functions as $function) {
67917 if (!\is_array($function)) {
67918 continue;
67919 }
67920
67921 if ($function[0] instanceof DebugClassLoader) {
67922 $function = $function[0]->getClassLoader();
67923
67924
67925 if (\is_object($function)) {
67926 $function = array($function);
67927 }
67928
67929 if (!\is_array($function)) {
67930 continue;
67931 }
67932 }
67933
67934 if ($function[0] instanceof ComposerClassLoader || $function[0] instanceof SymfonyClassLoader || $function[0] instanceof SymfonyUniversalClassLoader) {
67935 foreach ($function[0]->getPrefixes() as $prefix => $paths) {
67936 foreach ($paths as $path) {
67937 $classes = array_merge($classes, $this->findClassInPath($path, $class, $prefix));
67938 }
67939 }
67940 }
67941 if ($function[0] instanceof ComposerClassLoader) {
67942 foreach ($function[0]->getPrefixesPsr4() as $prefix => $paths) {
67943 foreach ($paths as $path) {
67944 $classes = array_merge($classes, $this->findClassInPath($path, $class, $prefix));
67945 }
67946 }
67947 }
67948 }
67949
67950 return array_unique($classes);
67951 }
67952
67953
67954
67955
67956
67957
67958
67959
67960 private function findClassInPath($path, $class, $prefix)
67961 {
67962 if (!$path = realpath($path.'/'.strtr($prefix, '\\_', '//')) ?: realpath($path.'/'.\dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path)) {
67963 return array();
67964 }
67965
67966 $classes = array();
67967 $filename = $class.'.php';
67968 foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
67969 if ($filename == $file->getFileName() && $class = $this->convertFileToClass($path, $file->getPathName(), $prefix)) {
67970 $classes[] = $class;
67971 }
67972 }
67973
67974 return $classes;
67975 }
67976
67977
67978
67979
67980
67981
67982
67983
67984 private function convertFileToClass($path, $file, $prefix)
67985 {
67986 $candidates = array(
67987
67988 $namespacedClass = str_replace(array($path.\DIRECTORY_SEPARATOR, '.php', '/'), array('', '', '\\'), $file),
67989
67990 $prefix.$namespacedClass,
67991
67992 $prefix.'\\'.$namespacedClass,
67993
67994 str_replace('\\', '_', $namespacedClass),
67995
67996 str_replace('\\', '_', $prefix.$namespacedClass),
67997
67998 str_replace('\\', '_', $prefix.'\\'.$namespacedClass),
67999 );
68000
68001 if ($prefix) {
68002 $candidates = array_filter($candidates, function ($candidate) use ($prefix) { return 0 === strpos($candidate, $prefix); });
68003 }
68004
68005
68006
68007
68008 foreach ($candidates as $candidate) {
68009 if ($this->classExists($candidate)) {
68010 return $candidate;
68011 }
68012 }
68013
68014 require_once $file;
68015
68016 foreach ($candidates as $candidate) {
68017 if ($this->classExists($candidate)) {
68018 return $candidate;
68019 }
68020 }
68021 }
68022
68023
68024
68025
68026
68027
68028 private function classExists($class)
68029 {
68030 return class_exists($class, false) || interface_exists($class, false) || (\function_exists('trait_exists') && trait_exists($class, false));
68031 }
68032 }
68033 <?php
68034
68035
68036
68037
68038
68039
68040
68041
68042
68043
68044 namespace Symfony\Component\Debug\FatalErrorHandler;
68045
68046 use Symfony\Component\Debug\Exception\FatalErrorException;
68047
68048
68049
68050
68051
68052
68053 interface FatalErrorHandlerInterface
68054 {
68055
68056
68057
68058
68059
68060
68061
68062
68063 public function handleError(array $error, FatalErrorException $exception);
68064 }
68065 <?php
68066
68067
68068
68069
68070
68071
68072
68073
68074
68075
68076 namespace Symfony\Component\Debug\FatalErrorHandler;
68077
68078 use Symfony\Component\Debug\Exception\FatalErrorException;
68079 use Symfony\Component\Debug\Exception\UndefinedFunctionException;
68080
68081
68082
68083
68084
68085
68086 class UndefinedFunctionFatalErrorHandler implements FatalErrorHandlerInterface
68087 {
68088
68089
68090
68091 public function handleError(array $error, FatalErrorException $exception)
68092 {
68093 $messageLen = \strlen($error['message']);
68094 $notFoundSuffix = '()';
68095 $notFoundSuffixLen = \strlen($notFoundSuffix);
68096 if ($notFoundSuffixLen > $messageLen) {
68097 return;
68098 }
68099
68100 if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
68101 return;
68102 }
68103
68104 $prefix = 'Call to undefined function ';
68105 $prefixLen = \strlen($prefix);
68106 if (0 !== strpos($error['message'], $prefix)) {
68107 return;
68108 }
68109
68110 $fullyQualifiedFunctionName = substr($error['message'], $prefixLen, -$notFoundSuffixLen);
68111 if (false !== $namespaceSeparatorIndex = strrpos($fullyQualifiedFunctionName, '\\')) {
68112 $functionName = substr($fullyQualifiedFunctionName, $namespaceSeparatorIndex + 1);
68113 $namespacePrefix = substr($fullyQualifiedFunctionName, 0, $namespaceSeparatorIndex);
68114 $message = sprintf('Attempted to call function "%s" from namespace "%s".', $functionName, $namespacePrefix);
68115 } else {
68116 $functionName = $fullyQualifiedFunctionName;
68117 $message = sprintf('Attempted to call function "%s" from the global namespace.', $functionName);
68118 }
68119
68120 $candidates = array();
68121 foreach (get_defined_functions() as $type => $definedFunctionNames) {
68122 foreach ($definedFunctionNames as $definedFunctionName) {
68123 if (false !== $namespaceSeparatorIndex = strrpos($definedFunctionName, '\\')) {
68124 $definedFunctionNameBasename = substr($definedFunctionName, $namespaceSeparatorIndex + 1);
68125 } else {
68126 $definedFunctionNameBasename = $definedFunctionName;
68127 }
68128
68129 if ($definedFunctionNameBasename === $functionName) {
68130 $candidates[] = '\\'.$definedFunctionName;
68131 }
68132 }
68133 }
68134
68135 if ($candidates) {
68136 sort($candidates);
68137 $last = array_pop($candidates).'"?';
68138 if ($candidates) {
68139 $candidates = 'e.g. "'.implode('", "', $candidates).'" or "'.$last;
68140 } else {
68141 $candidates = '"'.$last;
68142 }
68143 $message .= "\nDid you mean to call ".$candidates;
68144 }
68145
68146 return new UndefinedFunctionException($message, $exception);
68147 }
68148 }
68149 <?php
68150
68151
68152
68153
68154
68155
68156
68157
68158
68159
68160 namespace Symfony\Component\Debug\FatalErrorHandler;
68161
68162 use Symfony\Component\Debug\Exception\FatalErrorException;
68163 use Symfony\Component\Debug\Exception\UndefinedMethodException;
68164
68165
68166
68167
68168
68169
68170 class UndefinedMethodFatalErrorHandler implements FatalErrorHandlerInterface
68171 {
68172
68173
68174
68175 public function handleError(array $error, FatalErrorException $exception)
68176 {
68177 preg_match('/^Call to undefined method (.*)::(.*)\(\)$/', $error['message'], $matches);
68178 if (!$matches) {
68179 return;
68180 }
68181
68182 $className = $matches[1];
68183 $methodName = $matches[2];
68184
68185 $message = sprintf('Attempted to call an undefined method named "%s" of class "%s".', $methodName, $className);
68186
68187 if (!class_exists($className) || null === $methods = get_class_methods($className)) {
68188
68189 return new UndefinedMethodException($message, $exception);
68190 }
68191
68192 $candidates = array();
68193 foreach ($methods as $definedMethodName) {
68194 $lev = levenshtein($methodName, $definedMethodName);
68195 if ($lev <= \strlen($methodName) / 3 || false !== strpos($definedMethodName, $methodName)) {
68196 $candidates[] = $definedMethodName;
68197 }
68198 }
68199
68200 if ($candidates) {
68201 sort($candidates);
68202 $last = array_pop($candidates).'"?';
68203 if ($candidates) {
68204 $candidates = 'e.g. "'.implode('", "', $candidates).'" or "'.$last;
68205 } else {
68206 $candidates = '"'.$last;
68207 }
68208
68209 $message .= "\nDid you mean to call ".$candidates;
68210 }
68211
68212 return new UndefinedMethodException($message, $exception);
68213 }
68214 }
68215 Copyright (c) 2004-2018 Fabien Potencier
68216
68217 Permission is hereby granted, free of charge, to any person obtaining a copy
68218 of this software and associated documentation files (the "Software"), to deal
68219 in the Software without restriction, including without limitation the rights
68220 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
68221 copies of the Software, and to permit persons to whom the Software is furnished
68222 to do so, subject to the following conditions:
68223
68224 The above copyright notice and this permission notice shall be included in all
68225 copies or substantial portions of the Software.
68226
68227 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
68228 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
68229 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
68230 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
68231 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
68232 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
68233 THE SOFTWARE.
68234 <?php
68235
68236
68237
68238
68239
68240
68241
68242
68243
68244
68245 namespace Symfony\Component\Filesystem\Exception;
68246
68247
68248
68249
68250
68251
68252 interface ExceptionInterface
68253 {
68254 }
68255 <?php
68256
68257
68258
68259
68260
68261
68262
68263
68264
68265
68266 namespace Symfony\Component\Filesystem\Exception;
68267
68268
68269
68270
68271
68272
68273
68274 class FileNotFoundException extends IOException
68275 {
68276 public function __construct($message = null, $code = 0, \Exception $previous = null, $path = null)
68277 {
68278 if (null === $message) {
68279 if (null === $path) {
68280 $message = 'File could not be found.';
68281 } else {
68282 $message = sprintf('File "%s" could not be found.', $path);
68283 }
68284 }
68285
68286 parent::__construct($message, $code, $previous, $path);
68287 }
68288 }
68289 <?php
68290
68291
68292
68293
68294
68295
68296
68297
68298
68299
68300 namespace Symfony\Component\Filesystem\Exception;
68301
68302
68303
68304
68305
68306
68307
68308
68309 class IOException extends \RuntimeException implements IOExceptionInterface
68310 {
68311 private $path;
68312
68313 public function __construct($message, $code = 0, \Exception $previous = null, $path = null)
68314 {
68315 $this->path = $path;
68316
68317 parent::__construct($message, $code, $previous);
68318 }
68319
68320
68321
68322
68323 public function getPath()
68324 {
68325 return $this->path;
68326 }
68327 }
68328 <?php
68329
68330
68331
68332
68333
68334
68335
68336
68337
68338
68339 namespace Symfony\Component\Filesystem\Exception;
68340
68341
68342
68343
68344
68345
68346 interface IOExceptionInterface extends ExceptionInterface
68347 {
68348
68349
68350
68351
68352
68353 public function getPath();
68354 }
68355 <?php
68356
68357
68358
68359
68360
68361
68362
68363
68364
68365
68366 namespace Symfony\Component\Filesystem;
68367
68368 use Symfony\Component\Filesystem\Exception\FileNotFoundException;
68369 use Symfony\Component\Filesystem\Exception\IOException;
68370
68371
68372
68373
68374
68375
68376 class Filesystem
68377 {
68378 private static $lastError;
68379
68380
68381
68382
68383
68384
68385
68386
68387
68388
68389
68390
68391
68392
68393
68394 public function copy($originFile, $targetFile, $overwriteNewerFiles = false)
68395 {
68396 $originIsLocal = stream_is_local($originFile) || 0 === stripos($originFile, 'file://');
68397 if ($originIsLocal && !is_file($originFile)) {
68398 throw new FileNotFoundException(sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile);
68399 }
68400
68401 $this->mkdir(\dirname($targetFile));
68402
68403 $doCopy = true;
68404 if (!$overwriteNewerFiles && null === parse_url($originFile, PHP_URL_HOST) && is_file($targetFile)) {
68405 $doCopy = filemtime($originFile) > filemtime($targetFile);
68406 }
68407
68408 if ($doCopy) {
68409
68410 if (false === $source = @fopen($originFile, 'r')) {
68411 throw new IOException(sprintf('Failed to copy "%s" to "%s" because source file could not be opened for reading.', $originFile, $targetFile), 0, null, $originFile);
68412 }
68413
68414
68415 if (false === $target = @fopen($targetFile, 'w', null, stream_context_create(array('ftp' => array('overwrite' => true))))) {
68416 throw new IOException(sprintf('Failed to copy "%s" to "%s" because target file could not be opened for writing.', $originFile, $targetFile), 0, null, $originFile);
68417 }
68418
68419 $bytesCopied = stream_copy_to_stream($source, $target);
68420 fclose($source);
68421 fclose($target);
68422 unset($source, $target);
68423
68424 if (!is_file($targetFile)) {
68425 throw new IOException(sprintf('Failed to copy "%s" to "%s".', $originFile, $targetFile), 0, null, $originFile);
68426 }
68427
68428 if ($originIsLocal) {
68429
68430 @chmod($targetFile, fileperms($targetFile) | (fileperms($originFile) & 0111));
68431
68432 if ($bytesCopied !== $bytesOrigin = filesize($originFile)) {
68433 throw new IOException(sprintf('Failed to copy the whole content of "%s" to "%s" (%g of %g bytes copied).', $originFile, $targetFile, $bytesCopied, $bytesOrigin), 0, null, $originFile);
68434 }
68435 }
68436 }
68437 }
68438
68439
68440
68441
68442
68443
68444
68445
68446
68447 public function mkdir($dirs, $mode = 0777)
68448 {
68449 foreach ($this->toIterator($dirs) as $dir) {
68450 if (is_dir($dir)) {
68451 continue;
68452 }
68453
68454 if (!self::box('mkdir', $dir, $mode, true)) {
68455 if (!is_dir($dir)) {
68456
68457 if (self::$lastError) {
68458 throw new IOException(sprintf('Failed to create "%s": %s.', $dir, self::$lastError), 0, null, $dir);
68459 }
68460 throw new IOException(sprintf('Failed to create "%s"', $dir), 0, null, $dir);
68461 }
68462 }
68463 }
68464 }
68465
68466
68467
68468
68469
68470
68471
68472
68473 public function exists($files)
68474 {
68475 $maxPathLength = PHP_MAXPATHLEN - 2;
68476
68477 foreach ($this->toIterator($files) as $file) {
68478 if (\strlen($file) > $maxPathLength) {
68479 throw new IOException(sprintf('Could not check if file exist because path length exceeds %d characters.', $maxPathLength), 0, null, $file);
68480 }
68481
68482 if (!file_exists($file)) {
68483 return false;
68484 }
68485 }
68486
68487 return true;
68488 }
68489
68490
68491
68492
68493
68494
68495
68496
68497
68498
68499 public function touch($files, $time = null, $atime = null)
68500 {
68501 foreach ($this->toIterator($files) as $file) {
68502 $touch = $time ? @touch($file, $time, $atime) : @touch($file);
68503 if (true !== $touch) {
68504 throw new IOException(sprintf('Failed to touch "%s".', $file), 0, null, $file);
68505 }
68506 }
68507 }
68508
68509
68510
68511
68512
68513
68514
68515
68516 public function remove($files)
68517 {
68518 if ($files instanceof \Traversable) {
68519 $files = iterator_to_array($files, false);
68520 } elseif (!\is_array($files)) {
68521 $files = array($files);
68522 }
68523 $files = array_reverse($files);
68524 foreach ($files as $file) {
68525 if (is_link($file)) {
68526
68527 if (!(self::box('unlink', $file) || '\\' !== \DIRECTORY_SEPARATOR || self::box('rmdir', $file)) && file_exists($file)) {
68528 throw new IOException(sprintf('Failed to remove symlink "%s": %s.', $file, self::$lastError));
68529 }
68530 } elseif (is_dir($file)) {
68531 $this->remove(new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS));
68532
68533 if (!self::box('rmdir', $file) && file_exists($file)) {
68534 throw new IOException(sprintf('Failed to remove directory "%s": %s.', $file, self::$lastError));
68535 }
68536 } elseif (!self::box('unlink', $file) && file_exists($file)) {
68537 throw new IOException(sprintf('Failed to remove file "%s": %s.', $file, self::$lastError));
68538 }
68539 }
68540 }
68541
68542
68543
68544
68545
68546
68547
68548
68549
68550
68551
68552 public function chmod($files, $mode, $umask = 0000, $recursive = false)
68553 {
68554 foreach ($this->toIterator($files) as $file) {
68555 if (true !== @chmod($file, $mode & ~$umask)) {
68556 throw new IOException(sprintf('Failed to chmod file "%s".', $file), 0, null, $file);
68557 }
68558 if ($recursive && is_dir($file) && !is_link($file)) {
68559 $this->chmod(new \FilesystemIterator($file), $mode, $umask, true);
68560 }
68561 }
68562 }
68563
68564
68565
68566
68567
68568
68569
68570
68571
68572
68573 public function chown($files, $user, $recursive = false)
68574 {
68575 foreach ($this->toIterator($files) as $file) {
68576 if ($recursive && is_dir($file) && !is_link($file)) {
68577 $this->chown(new \FilesystemIterator($file), $user, true);
68578 }
68579 if (is_link($file) && \function_exists('lchown')) {
68580 if (true !== @lchown($file, $user)) {
68581 throw new IOException(sprintf('Failed to chown file "%s".', $file), 0, null, $file);
68582 }
68583 } else {
68584 if (true !== @chown($file, $user)) {
68585 throw new IOException(sprintf('Failed to chown file "%s".', $file), 0, null, $file);
68586 }
68587 }
68588 }
68589 }
68590
68591
68592
68593
68594
68595
68596
68597
68598
68599
68600 public function chgrp($files, $group, $recursive = false)
68601 {
68602 foreach ($this->toIterator($files) as $file) {
68603 if ($recursive && is_dir($file) && !is_link($file)) {
68604 $this->chgrp(new \FilesystemIterator($file), $group, true);
68605 }
68606 if (is_link($file) && \function_exists('lchgrp')) {
68607 if (true !== @lchgrp($file, $group) || (\defined('HHVM_VERSION') && !posix_getgrnam($group))) {
68608 throw new IOException(sprintf('Failed to chgrp file "%s".', $file), 0, null, $file);
68609 }
68610 } else {
68611 if (true !== @chgrp($file, $group)) {
68612 throw new IOException(sprintf('Failed to chgrp file "%s".', $file), 0, null, $file);
68613 }
68614 }
68615 }
68616 }
68617
68618
68619
68620
68621
68622
68623
68624
68625
68626
68627
68628 public function rename($origin, $target, $overwrite = false)
68629 {
68630
68631 if (!$overwrite && $this->isReadable($target)) {
68632 throw new IOException(sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target);
68633 }
68634
68635 if (true !== @rename($origin, $target)) {
68636 if (is_dir($origin)) {
68637
68638 $this->mirror($origin, $target, null, array('override' => $overwrite, 'delete' => $overwrite));
68639 $this->remove($origin);
68640
68641 return;
68642 }
68643 throw new IOException(sprintf('Cannot rename "%s" to "%s".', $origin, $target), 0, null, $target);
68644 }
68645 }
68646
68647
68648
68649
68650
68651
68652
68653
68654
68655
68656 private function isReadable($filename)
68657 {
68658 $maxPathLength = PHP_MAXPATHLEN - 2;
68659
68660 if (\strlen($filename) > $maxPathLength) {
68661 throw new IOException(sprintf('Could not check if file is readable because path length exceeds %d characters.', $maxPathLength), 0, null, $filename);
68662 }
68663
68664 return is_readable($filename);
68665 }
68666
68667
68668
68669
68670
68671
68672
68673
68674
68675
68676 public function symlink($originDir, $targetDir, $copyOnWindows = false)
68677 {
68678 if ('\\' === \DIRECTORY_SEPARATOR) {
68679 $originDir = strtr($originDir, '/', '\\');
68680 $targetDir = strtr($targetDir, '/', '\\');
68681
68682 if ($copyOnWindows) {
68683 $this->mirror($originDir, $targetDir);
68684
68685 return;
68686 }
68687 }
68688
68689 $this->mkdir(\dirname($targetDir));
68690
68691 if (is_link($targetDir)) {
68692 if (readlink($targetDir) === $originDir) {
68693 return;
68694 }
68695 $this->remove($targetDir);
68696 }
68697
68698 if (!self::box('symlink', $originDir, $targetDir)) {
68699 if (null !== self::$lastError) {
68700 if ('\\' === \DIRECTORY_SEPARATOR && false !== strpos(self::$lastError, 'error code(1314)')) {
68701 throw new IOException('Unable to create symlink due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?', 0, null, $targetDir);
68702 }
68703 }
68704 throw new IOException(sprintf('Failed to create symbolic link from "%s" to "%s".', $originDir, $targetDir), 0, null, $targetDir);
68705 }
68706 }
68707
68708
68709
68710
68711
68712
68713
68714
68715
68716 public function makePathRelative($endPath, $startPath)
68717 {
68718
68719 if ('\\' === \DIRECTORY_SEPARATOR) {
68720 $endPath = str_replace('\\', '/', $endPath);
68721 $startPath = str_replace('\\', '/', $startPath);
68722 }
68723
68724 $stripDriveLetter = function ($path) {
68725 if (\strlen($path) > 2 && ':' === $path[1] && '/' === $path[2] && ctype_alpha($path[0])) {
68726 return substr($path, 2);
68727 }
68728
68729 return $path;
68730 };
68731
68732 $endPath = $stripDriveLetter($endPath);
68733 $startPath = $stripDriveLetter($startPath);
68734
68735
68736 $startPathArr = explode('/', trim($startPath, '/'));
68737 $endPathArr = explode('/', trim($endPath, '/'));
68738
68739 $normalizePathArray = function ($pathSegments, $absolute) {
68740 $result = array();
68741
68742 foreach ($pathSegments as $segment) {
68743 if ('..' === $segment && ($absolute || \count($result))) {
68744 array_pop($result);
68745 } elseif ('.' !== $segment) {
68746 $result[] = $segment;
68747 }
68748 }
68749
68750 return $result;
68751 };
68752
68753 $startPathArr = $normalizePathArray($startPathArr, static::isAbsolutePath($startPath));
68754 $endPathArr = $normalizePathArray($endPathArr, static::isAbsolutePath($endPath));
68755
68756
68757 $index = 0;
68758 while (isset($startPathArr[$index]) && isset($endPathArr[$index]) && $startPathArr[$index] === $endPathArr[$index]) {
68759 ++$index;
68760 }
68761
68762
68763 if (1 === \count($startPathArr) && '' === $startPathArr[0]) {
68764 $depth = 0;
68765 } else {
68766 $depth = \count($startPathArr) - $index;
68767 }
68768
68769
68770 $traverser = str_repeat('../', $depth);
68771
68772 $endPathRemainder = implode('/', \array_slice($endPathArr, $index));
68773
68774
68775 $relativePath = $traverser.('' !== $endPathRemainder ? $endPathRemainder.'/' : '');
68776
68777 return '' === $relativePath ? './' : $relativePath;
68778 }
68779
68780
68781
68782
68783
68784
68785
68786
68787
68788
68789
68790
68791
68792
68793
68794
68795
68796
68797
68798
68799 public function mirror($originDir, $targetDir, \Traversable $iterator = null, $options = array())
68800 {
68801 $targetDir = rtrim($targetDir, '/\\');
68802 $originDir = rtrim($originDir, '/\\');
68803 $originDirLen = \strlen($originDir);
68804
68805
68806 if ($this->exists($targetDir) && isset($options['delete']) && $options['delete']) {
68807 $deleteIterator = $iterator;
68808 if (null === $deleteIterator) {
68809 $flags = \FilesystemIterator::SKIP_DOTS;
68810 $deleteIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($targetDir, $flags), \RecursiveIteratorIterator::CHILD_FIRST);
68811 }
68812 $targetDirLen = \strlen($targetDir);
68813 foreach ($deleteIterator as $file) {
68814 $origin = $originDir.substr($file->getPathname(), $targetDirLen);
68815 if (!$this->exists($origin)) {
68816 $this->remove($file);
68817 }
68818 }
68819 }
68820
68821 $copyOnWindows = false;
68822 if (isset($options['copy_on_windows'])) {
68823 $copyOnWindows = $options['copy_on_windows'];
68824 }
68825
68826 if (null === $iterator) {
68827 $flags = $copyOnWindows ? \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS : \FilesystemIterator::SKIP_DOTS;
68828 $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($originDir, $flags), \RecursiveIteratorIterator::SELF_FIRST);
68829 }
68830
68831 if ($this->exists($originDir)) {
68832 $this->mkdir($targetDir);
68833 }
68834
68835 foreach ($iterator as $file) {
68836 $target = $targetDir.substr($file->getPathname(), $originDirLen);
68837
68838 if ($copyOnWindows) {
68839 if (is_file($file)) {
68840 $this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
68841 } elseif (is_dir($file)) {
68842 $this->mkdir($target);
68843 } else {
68844 throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file);
68845 }
68846 } else {
68847 if (is_link($file)) {
68848 $this->symlink($file->getLinkTarget(), $target);
68849 } elseif (is_dir($file)) {
68850 $this->mkdir($target);
68851 } elseif (is_file($file)) {
68852 $this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
68853 } else {
68854 throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file);
68855 }
68856 }
68857 }
68858 }
68859
68860
68861
68862
68863
68864
68865
68866
68867 public function isAbsolutePath($file)
68868 {
68869 return strspn($file, '/\\', 0, 1)
68870 || (\strlen($file) > 3 && ctype_alpha($file[0])
68871 && ':' === substr($file, 1, 1)
68872 && strspn($file, '/\\', 2, 1)
68873 )
68874 || null !== parse_url($file, PHP_URL_SCHEME)
68875 ;
68876 }
68877
68878
68879
68880
68881
68882
68883
68884
68885
68886
68887 public function tempnam($dir, $prefix)
68888 {
68889 list($scheme, $hierarchy) = $this->getSchemeAndHierarchy($dir);
68890
68891
68892 if (null === $scheme || 'file' === $scheme || 'gs' === $scheme) {
68893 $tmpFile = @tempnam($hierarchy, $prefix);
68894
68895
68896 if (false !== $tmpFile) {
68897 if (null !== $scheme && 'gs' !== $scheme) {
68898 return $scheme.'://'.$tmpFile;
68899 }
68900
68901 return $tmpFile;
68902 }
68903
68904 throw new IOException('A temporary file could not be created.');
68905 }
68906
68907
68908 for ($i = 0; $i < 10; ++$i) {
68909
68910 $tmpFile = $dir.'/'.$prefix.uniqid(mt_rand(), true);
68911
68912
68913
68914 $handle = @fopen($tmpFile, 'x+');
68915
68916
68917 if (false === $handle) {
68918 continue;
68919 }
68920
68921
68922 @fclose($handle);
68923
68924 return $tmpFile;
68925 }
68926
68927 throw new IOException('A temporary file could not be created.');
68928 }
68929
68930
68931
68932
68933
68934
68935
68936
68937
68938
68939
68940 public function dumpFile($filename, $content, $mode = 0666)
68941 {
68942 $dir = \dirname($filename);
68943
68944 if (!is_dir($dir)) {
68945 $this->mkdir($dir);
68946 }
68947
68948 if (!is_writable($dir)) {
68949 throw new IOException(sprintf('Unable to write to the "%s" directory.', $dir), 0, null, $dir);
68950 }
68951
68952 $tmpFile = $this->tempnam($dir, basename($filename));
68953
68954 if (false === @file_put_contents($tmpFile, $content)) {
68955 throw new IOException(sprintf('Failed to write file "%s".', $filename), 0, null, $filename);
68956 }
68957
68958 if (null !== $mode) {
68959 if (\func_num_args() > 2) {
68960 @trigger_error('Support for modifying file permissions is deprecated since Symfony 2.3.12 and will be removed in 3.0.', E_USER_DEPRECATED);
68961 }
68962
68963 $this->chmod($tmpFile, $mode);
68964 } elseif (file_exists($filename)) {
68965 @chmod($tmpFile, fileperms($filename));
68966 }
68967
68968 $this->rename($tmpFile, $filename, true);
68969 }
68970
68971
68972
68973
68974
68975
68976 private function toIterator($files)
68977 {
68978 if (!$files instanceof \Traversable) {
68979 $files = new \ArrayObject(\is_array($files) ? $files : array($files));
68980 }
68981
68982 return $files;
68983 }
68984
68985
68986
68987
68988
68989
68990
68991
68992 private function getSchemeAndHierarchy($filename)
68993 {
68994 $components = explode('://', $filename, 2);
68995
68996 return 2 === \count($components) ? array($components[0], $components[1]) : array(null, $components[0]);
68997 }
68998
68999 private static function box($func)
69000 {
69001 self::$lastError = null;
69002 \set_error_handler(__CLASS__.'::handleError');
69003 try {
69004 $result = \call_user_func_array($func, \array_slice(\func_get_args(), 1));
69005 \restore_error_handler();
69006
69007 return $result;
69008 } catch (\Throwable $e) {
69009 } catch (\Exception $e) {
69010 }
69011 \restore_error_handler();
69012
69013 throw $e;
69014 }
69015
69016
69017
69018
69019 public static function handleError($type, $msg)
69020 {
69021 self::$lastError = $msg;
69022 }
69023 }
69024 Copyright (c) 2004-2018 Fabien Potencier
69025
69026 Permission is hereby granted, free of charge, to any person obtaining a copy
69027 of this software and associated documentation files (the "Software"), to deal
69028 in the Software without restriction, including without limitation the rights
69029 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
69030 copies of the Software, and to permit persons to whom the Software is furnished
69031 to do so, subject to the following conditions:
69032
69033 The above copyright notice and this permission notice shall be included in all
69034 copies or substantial portions of the Software.
69035
69036 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
69037 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
69038 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
69039 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
69040 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
69041 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
69042 THE SOFTWARE.
69043 <?php
69044
69045
69046
69047
69048
69049
69050
69051
69052
69053
69054 namespace Symfony\Component\Filesystem;
69055
69056 use Symfony\Component\Filesystem\Exception\IOException;
69057
69058
69059
69060
69061
69062
69063
69064
69065
69066
69067
69068
69069
69070
69071 class LockHandler
69072 {
69073 private $file;
69074 private $handle;
69075
69076
69077
69078
69079
69080
69081
69082 public function __construct($name, $lockPath = null)
69083 {
69084 $lockPath = $lockPath ?: sys_get_temp_dir();
69085
69086 if (!is_dir($lockPath)) {
69087 $fs = new Filesystem();
69088 $fs->mkdir($lockPath);
69089 }
69090
69091 if (!is_writable($lockPath)) {
69092 throw new IOException(sprintf('The directory "%s" is not writable.', $lockPath), 0, null, $lockPath);
69093 }
69094
69095 $this->file = sprintf('%s/sf.%s.%s.lock', $lockPath, preg_replace('/[^a-z0-9\._-]+/i', '-', $name), hash('sha256', $name));
69096 }
69097
69098
69099
69100
69101
69102
69103
69104
69105
69106
69107 public function lock($blocking = false)
69108 {
69109 if ($this->handle) {
69110 return true;
69111 }
69112
69113 $error = null;
69114
69115
69116 set_error_handler(function ($errno, $msg) use (&$error) {
69117 $error = $msg;
69118 });
69119
69120 if (!$this->handle = fopen($this->file, 'r+') ?: fopen($this->file, 'r')) {
69121 if ($this->handle = fopen($this->file, 'x')) {
69122 chmod($this->file, 0666);
69123 } elseif (!$this->handle = fopen($this->file, 'r+') ?: fopen($this->file, 'r')) {
69124 usleep(100); 
69125 $this->handle = fopen($this->file, 'r+') ?: fopen($this->file, 'r');
69126 }
69127 }
69128 restore_error_handler();
69129
69130 if (!$this->handle) {
69131 throw new IOException($error, 0, null, $this->file);
69132 }
69133
69134
69135
69136 if (!flock($this->handle, LOCK_EX | ($blocking ? 0 : LOCK_NB))) {
69137 fclose($this->handle);
69138 $this->handle = null;
69139
69140 return false;
69141 }
69142
69143 return true;
69144 }
69145
69146
69147
69148
69149 public function release()
69150 {
69151 if ($this->handle) {
69152 flock($this->handle, LOCK_UN | LOCK_NB);
69153 fclose($this->handle);
69154 $this->handle = null;
69155 }
69156 }
69157 }
69158 <?php
69159
69160
69161
69162
69163
69164
69165
69166
69167
69168
69169 namespace Symfony\Component\Finder\Adapter;
69170
69171 @trigger_error('The '.__NAMESPACE__.'\AbstractAdapter class is deprecated since Symfony 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);
69172
69173
69174
69175
69176
69177
69178
69179
69180 abstract class AbstractAdapter implements AdapterInterface
69181 {
69182 protected $followLinks = false;
69183 protected $mode = 0;
69184 protected $minDepth = 0;
69185 protected $maxDepth = PHP_INT_MAX;
69186 protected $exclude = array();
69187 protected $names = array();
69188 protected $notNames = array();
69189 protected $contains = array();
69190 protected $notContains = array();
69191 protected $sizes = array();
69192 protected $dates = array();
69193 protected $filters = array();
69194 protected $sort = false;
69195 protected $paths = array();
69196 protected $notPaths = array();
69197 protected $ignoreUnreadableDirs = false;
69198
69199 private static $areSupported = array();
69200
69201
69202
69203
69204 public function isSupported()
69205 {
69206 $name = $this->getName();
69207
69208 if (!array_key_exists($name, self::$areSupported)) {
69209 self::$areSupported[$name] = $this->canBeUsed();
69210 }
69211
69212 return self::$areSupported[$name];
69213 }
69214
69215
69216
69217
69218 public function setFollowLinks($followLinks)
69219 {
69220 $this->followLinks = $followLinks;
69221
69222 return $this;
69223 }
69224
69225
69226
69227
69228 public function setMode($mode)
69229 {
69230 $this->mode = $mode;
69231
69232 return $this;
69233 }
69234
69235
69236
69237
69238 public function setDepths(array $depths)
69239 {
69240 $this->minDepth = 0;
69241 $this->maxDepth = PHP_INT_MAX;
69242
69243 foreach ($depths as $comparator) {
69244 switch ($comparator->getOperator()) {
69245 case '>':
69246 $this->minDepth = $comparator->getTarget() + 1;
69247 break;
69248 case '>=':
69249 $this->minDepth = $comparator->getTarget();
69250 break;
69251 case '<':
69252 $this->maxDepth = $comparator->getTarget() - 1;
69253 break;
69254 case '<=':
69255 $this->maxDepth = $comparator->getTarget();
69256 break;
69257 default:
69258 $this->minDepth = $this->maxDepth = $comparator->getTarget();
69259 }
69260 }
69261
69262 return $this;
69263 }
69264
69265
69266
69267
69268 public function setExclude(array $exclude)
69269 {
69270 $this->exclude = $exclude;
69271
69272 return $this;
69273 }
69274
69275
69276
69277
69278 public function setNames(array $names)
69279 {
69280 $this->names = $names;
69281
69282 return $this;
69283 }
69284
69285
69286
69287
69288 public function setNotNames(array $notNames)
69289 {
69290 $this->notNames = $notNames;
69291
69292 return $this;
69293 }
69294
69295
69296
69297
69298 public function setContains(array $contains)
69299 {
69300 $this->contains = $contains;
69301
69302 return $this;
69303 }
69304
69305
69306
69307
69308 public function setNotContains(array $notContains)
69309 {
69310 $this->notContains = $notContains;
69311
69312 return $this;
69313 }
69314
69315
69316
69317
69318 public function setSizes(array $sizes)
69319 {
69320 $this->sizes = $sizes;
69321
69322 return $this;
69323 }
69324
69325
69326
69327
69328 public function setDates(array $dates)
69329 {
69330 $this->dates = $dates;
69331
69332 return $this;
69333 }
69334
69335
69336
69337
69338 public function setFilters(array $filters)
69339 {
69340 $this->filters = $filters;
69341
69342 return $this;
69343 }
69344
69345
69346
69347
69348 public function setSort($sort)
69349 {
69350 $this->sort = $sort;
69351
69352 return $this;
69353 }
69354
69355
69356
69357
69358 public function setPath(array $paths)
69359 {
69360 $this->paths = $paths;
69361
69362 return $this;
69363 }
69364
69365
69366
69367
69368 public function setNotPath(array $notPaths)
69369 {
69370 $this->notPaths = $notPaths;
69371
69372 return $this;
69373 }
69374
69375
69376
69377
69378 public function ignoreUnreadableDirs($ignore = true)
69379 {
69380 $this->ignoreUnreadableDirs = (bool) $ignore;
69381
69382 return $this;
69383 }
69384
69385
69386
69387
69388
69389
69390
69391
69392
69393
69394
69395
69396 abstract protected function canBeUsed();
69397 }
69398 <?php
69399
69400
69401
69402
69403
69404
69405
69406
69407
69408
69409 namespace Symfony\Component\Finder\Adapter;
69410
69411 @trigger_error('The '.__NAMESPACE__.'\AbstractFindAdapter class is deprecated since Symfony 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);
69412
69413 use Symfony\Component\Finder\Comparator\DateComparator;
69414 use Symfony\Component\Finder\Comparator\NumberComparator;
69415 use Symfony\Component\Finder\Exception\AccessDeniedException;
69416 use Symfony\Component\Finder\Expression\Expression;
69417 use Symfony\Component\Finder\Iterator;
69418 use Symfony\Component\Finder\Shell\Command;
69419 use Symfony\Component\Finder\Shell\Shell;
69420
69421
69422
69423
69424
69425
69426
69427
69428 abstract class AbstractFindAdapter extends AbstractAdapter
69429 {
69430 protected $shell;
69431
69432 public function __construct()
69433 {
69434 $this->shell = new Shell();
69435 }
69436
69437
69438
69439
69440 public function searchInDirectory($dir)
69441 {
69442
69443 $dir = realpath($dir);
69444
69445
69446 if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode && ($this->contains || $this->notContains)) {
69447 return new Iterator\FilePathsIterator(array(), $dir);
69448 }
69449
69450 $command = Command::create();
69451 $find = $this->buildFindCommand($command, $dir);
69452
69453 if ($this->followLinks) {
69454 $find->add('-follow');
69455 }
69456
69457 $find->add('-mindepth')->add($this->minDepth + 1);
69458
69459 if (PHP_INT_MAX !== $this->maxDepth) {
69460 $find->add('-maxdepth')->add($this->maxDepth + 1);
69461 }
69462
69463 if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode) {
69464 $find->add('-type d');
69465 } elseif (Iterator\FileTypeFilterIterator::ONLY_FILES === $this->mode) {
69466 $find->add('-type f');
69467 }
69468
69469 $this->buildNamesFiltering($find, $this->names);
69470 $this->buildNamesFiltering($find, $this->notNames, true);
69471 $this->buildPathsFiltering($find, $dir, $this->paths);
69472 $this->buildPathsFiltering($find, $dir, $this->notPaths, true);
69473 $this->buildSizesFiltering($find, $this->sizes);
69474 $this->buildDatesFiltering($find, $this->dates);
69475
69476 $useGrep = $this->shell->testCommand('grep') && $this->shell->testCommand('xargs');
69477 $useSort = \is_int($this->sort) && $this->shell->testCommand('sort') && $this->shell->testCommand('cut');
69478
69479 if ($useGrep && ($this->contains || $this->notContains)) {
69480 $grep = $command->ins('grep');
69481 $this->buildContentFiltering($grep, $this->contains);
69482 $this->buildContentFiltering($grep, $this->notContains, true);
69483 }
69484
69485 if ($useSort) {
69486 $this->buildSorting($command, $this->sort);
69487 }
69488
69489 $command->setErrorHandler(
69490 $this->ignoreUnreadableDirs
69491
69492 ? function ($stderr) { }
69493 : function ($stderr) { throw new AccessDeniedException($stderr); }
69494 );
69495
69496 $paths = $this->shell->testCommand('uniq') ? $command->add('| uniq')->execute() : array_unique($command->execute());
69497 $iterator = new Iterator\FilePathsIterator($paths, $dir);
69498
69499 if ($this->exclude) {
69500 $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
69501 }
69502
69503 if (!$useGrep && ($this->contains || $this->notContains)) {
69504 $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
69505 }
69506
69507 if ($this->filters) {
69508 $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
69509 }
69510
69511 if (!$useSort && $this->sort) {
69512 $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
69513 $iterator = $iteratorAggregate->getIterator();
69514 }
69515
69516 return $iterator;
69517 }
69518
69519
69520
69521
69522 protected function canBeUsed()
69523 {
69524 return $this->shell->testCommand('find');
69525 }
69526
69527
69528
69529
69530
69531
69532
69533 protected function buildFindCommand(Command $command, $dir)
69534 {
69535 return $command
69536 ->ins('find')
69537 ->add('find ')
69538 ->arg($dir)
69539 ->add('-noleaf'); 
69540 }
69541
69542
69543
69544
69545
69546
69547 private function buildNamesFiltering(Command $command, array $names, $not = false)
69548 {
69549 if (0 === \count($names)) {
69550 return;
69551 }
69552
69553 $command->add($not ? '-not' : null)->cmd('(');
69554
69555 foreach ($names as $i => $name) {
69556 $expr = Expression::create($name);
69557
69558
69559 if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
69560 $expr = Expression::create($expr->getGlob()->toRegex(false));
69561 }
69562
69563
69564
69565
69566 if ($expr->isRegex()) {
69567 $regex = $expr->getRegex();
69568 $regex->prepend($regex->hasStartFlag() ? '/' : '/[^/]*')
69569 ->setStartFlag(false)
69570 ->setStartJoker(true)
69571 ->replaceJokers('[^/]');
69572 if (!$regex->hasEndFlag() || $regex->hasEndJoker()) {
69573 $regex->setEndJoker(false)->append('[^/]*');
69574 }
69575 }
69576
69577 $command
69578 ->add($i > 0 ? '-or' : null)
69579 ->add($expr->isRegex()
69580 ? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
69581 : ($expr->isCaseSensitive() ? '-name' : '-iname')
69582 )
69583 ->arg($expr->renderPattern());
69584 }
69585
69586 $command->cmd(')');
69587 }
69588
69589
69590
69591
69592
69593
69594
69595 private function buildPathsFiltering(Command $command, $dir, array $paths, $not = false)
69596 {
69597 if (0 === \count($paths)) {
69598 return;
69599 }
69600
69601 $command->add($not ? '-not' : null)->cmd('(');
69602
69603 foreach ($paths as $i => $path) {
69604 $expr = Expression::create($path);
69605
69606
69607 if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
69608 $expr = Expression::create($expr->getGlob()->toRegex(false));
69609 }
69610
69611
69612 if ($expr->isRegex()) {
69613 $regex = $expr->getRegex();
69614 $regex->prepend($regex->hasStartFlag() ? preg_quote($dir).\DIRECTORY_SEPARATOR : '.*')->setEndJoker(!$regex->hasEndFlag());
69615 } else {
69616 $expr->prepend('*')->append('*');
69617 }
69618
69619 $command
69620 ->add($i > 0 ? '-or' : null)
69621 ->add($expr->isRegex()
69622 ? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
69623 : ($expr->isCaseSensitive() ? '-path' : '-ipath')
69624 )
69625 ->arg($expr->renderPattern());
69626 }
69627
69628 $command->cmd(')');
69629 }
69630
69631
69632
69633
69634
69635 private function buildSizesFiltering(Command $command, array $sizes)
69636 {
69637 foreach ($sizes as $i => $size) {
69638 $command->add($i > 0 ? '-and' : null);
69639
69640 switch ($size->getOperator()) {
69641 case '<=':
69642 $command->add('-size -'.($size->getTarget() + 1).'c');
69643 break;
69644 case '>=':
69645 $command->add('-size +'.($size->getTarget() - 1).'c');
69646 break;
69647 case '>':
69648 $command->add('-size +'.$size->getTarget().'c');
69649 break;
69650 case '!=':
69651 $command->add('-size -'.$size->getTarget().'c');
69652 $command->add('-size +'.$size->getTarget().'c');
69653 break;
69654 case '<':
69655 default:
69656 $command->add('-size -'.$size->getTarget().'c');
69657 }
69658 }
69659 }
69660
69661
69662
69663
69664
69665 private function buildDatesFiltering(Command $command, array $dates)
69666 {
69667 foreach ($dates as $i => $date) {
69668 $command->add($i > 0 ? '-and' : null);
69669
69670 $mins = (int) round((time() - $date->getTarget()) / 60);
69671
69672 if (0 > $mins) {
69673
69674 $command->add(' -mmin -0');
69675
69676 return;
69677 }
69678
69679 switch ($date->getOperator()) {
69680 case '<=':
69681 $command->add('-mmin +'.($mins - 1));
69682 break;
69683 case '>=':
69684 $command->add('-mmin -'.($mins + 1));
69685 break;
69686 case '>':
69687 $command->add('-mmin -'.$mins);
69688 break;
69689 case '!=':
69690 $command->add('-mmin +'.$mins.' -or -mmin -'.$mins);
69691 break;
69692 case '<':
69693 default:
69694 $command->add('-mmin +'.$mins);
69695 }
69696 }
69697 }
69698
69699
69700
69701
69702
69703
69704
69705 private function buildSorting(Command $command, $sort)
69706 {
69707 $this->buildFormatSorting($command, $sort);
69708 }
69709
69710
69711
69712
69713
69714 abstract protected function buildFormatSorting(Command $command, $sort);
69715
69716
69717
69718
69719
69720
69721 abstract protected function buildContentFiltering(Command $command, array $contains, $not = false);
69722 }
69723 <?php
69724
69725
69726
69727
69728
69729
69730
69731
69732
69733
69734 namespace Symfony\Component\Finder\Adapter;
69735
69736
69737
69738
69739
69740
69741 interface AdapterInterface
69742 {
69743
69744
69745
69746
69747
69748 public function setFollowLinks($followLinks);
69749
69750
69751
69752
69753
69754
69755 public function setMode($mode);
69756
69757
69758
69759
69760 public function setExclude(array $exclude);
69761
69762
69763
69764
69765 public function setDepths(array $depths);
69766
69767
69768
69769
69770 public function setNames(array $names);
69771
69772
69773
69774
69775 public function setNotNames(array $notNames);
69776
69777
69778
69779
69780 public function setContains(array $contains);
69781
69782
69783
69784
69785 public function setNotContains(array $notContains);
69786
69787
69788
69789
69790 public function setSizes(array $sizes);
69791
69792
69793
69794
69795 public function setDates(array $dates);
69796
69797
69798
69799
69800 public function setFilters(array $filters);
69801
69802
69803
69804
69805
69806
69807 public function setSort($sort);
69808
69809
69810
69811
69812 public function setPath(array $paths);
69813
69814
69815
69816
69817 public function setNotPath(array $notPaths);
69818
69819
69820
69821
69822
69823
69824 public function ignoreUnreadableDirs($ignore = true);
69825
69826
69827
69828
69829
69830
69831 public function searchInDirectory($dir);
69832
69833
69834
69835
69836
69837
69838 public function isSupported();
69839
69840
69841
69842
69843
69844
69845 public function getName();
69846 }
69847 <?php
69848
69849
69850
69851
69852
69853
69854
69855
69856
69857
69858 namespace Symfony\Component\Finder\Adapter;
69859
69860 @trigger_error('The '.__NAMESPACE__.'\BsdFindAdapter class is deprecated since Symfony 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);
69861
69862 use Symfony\Component\Finder\Expression\Expression;
69863 use Symfony\Component\Finder\Iterator\SortableIterator;
69864 use Symfony\Component\Finder\Shell\Command;
69865 use Symfony\Component\Finder\Shell\Shell;
69866
69867
69868
69869
69870
69871
69872
69873
69874 class BsdFindAdapter extends AbstractFindAdapter
69875 {
69876
69877
69878
69879 public function getName()
69880 {
69881 return 'bsd_find';
69882 }
69883
69884
69885
69886
69887 protected function canBeUsed()
69888 {
69889 return \in_array($this->shell->getType(), array(Shell::TYPE_BSD, Shell::TYPE_DARWIN)) && parent::canBeUsed();
69890 }
69891
69892
69893
69894
69895 protected function buildFormatSorting(Command $command, $sort)
69896 {
69897 switch ($sort) {
69898 case SortableIterator::SORT_BY_NAME:
69899 $command->ins('sort')->add('| sort');
69900
69901 return;
69902 case SortableIterator::SORT_BY_TYPE:
69903 $format = '%HT';
69904 break;
69905 case SortableIterator::SORT_BY_ACCESSED_TIME:
69906 $format = '%a';
69907 break;
69908 case SortableIterator::SORT_BY_CHANGED_TIME:
69909 $format = '%c';
69910 break;
69911 case SortableIterator::SORT_BY_MODIFIED_TIME:
69912 $format = '%m';
69913 break;
69914 default:
69915 throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort));
69916 }
69917
69918 $command
69919 ->add('-print0 | xargs -0 stat -f')
69920 ->arg($format.'%t%N')
69921 ->add('| sort | cut -f 2');
69922 }
69923
69924
69925
69926
69927 protected function buildFindCommand(Command $command, $dir)
69928 {
69929 parent::buildFindCommand($command, $dir)->addAtIndex('-E', 1);
69930
69931 return $command;
69932 }
69933
69934
69935
69936
69937 protected function buildContentFiltering(Command $command, array $contains, $not = false)
69938 {
69939 foreach ($contains as $contain) {
69940 $expr = Expression::create($contain);
69941
69942
69943 $command
69944 ->add('| grep -v \'^$\'')
69945 ->add('| xargs -I{} grep -I')
69946 ->add($expr->isCaseSensitive() ? null : '-i')
69947 ->add($not ? '-L' : '-l')
69948 ->add('-Ee')->arg($expr->renderPattern())
69949 ->add('{}')
69950 ;
69951 }
69952 }
69953 }
69954 <?php
69955
69956
69957
69958
69959
69960
69961
69962
69963
69964
69965 namespace Symfony\Component\Finder\Adapter;
69966
69967 @trigger_error('The '.__NAMESPACE__.'\GnuFindAdapter class is deprecated since Symfony 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);
69968
69969 use Symfony\Component\Finder\Expression\Expression;
69970 use Symfony\Component\Finder\Iterator\SortableIterator;
69971 use Symfony\Component\Finder\Shell\Command;
69972 use Symfony\Component\Finder\Shell\Shell;
69973
69974
69975
69976
69977
69978
69979
69980
69981 class GnuFindAdapter extends AbstractFindAdapter
69982 {
69983
69984
69985
69986 public function getName()
69987 {
69988 return 'gnu_find';
69989 }
69990
69991
69992
69993
69994 protected function buildFormatSorting(Command $command, $sort)
69995 {
69996 switch ($sort) {
69997 case SortableIterator::SORT_BY_NAME:
69998 $command->ins('sort')->add('| sort');
69999
70000 return;
70001 case SortableIterator::SORT_BY_TYPE:
70002 $format = '%y';
70003 break;
70004 case SortableIterator::SORT_BY_ACCESSED_TIME:
70005 $format = '%A@';
70006 break;
70007 case SortableIterator::SORT_BY_CHANGED_TIME:
70008 $format = '%C@';
70009 break;
70010 case SortableIterator::SORT_BY_MODIFIED_TIME:
70011 $format = '%T@';
70012 break;
70013 default:
70014 throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort));
70015 }
70016
70017 $command
70018 ->get('find')
70019 ->add('-printf')
70020 ->arg($format.' %h/%f\\n')
70021 ->add('| sort | cut')
70022 ->arg('-d ')
70023 ->arg('-f2-')
70024 ;
70025 }
70026
70027
70028
70029
70030 protected function canBeUsed()
70031 {
70032 return Shell::TYPE_UNIX === $this->shell->getType() && parent::canBeUsed();
70033 }
70034
70035
70036
70037
70038 protected function buildFindCommand(Command $command, $dir)
70039 {
70040 return parent::buildFindCommand($command, $dir)->add('-regextype posix-extended');
70041 }
70042
70043
70044
70045
70046 protected function buildContentFiltering(Command $command, array $contains, $not = false)
70047 {
70048 foreach ($contains as $contain) {
70049 $expr = Expression::create($contain);
70050
70051
70052 $command
70053 ->add('| xargs -I{} -r grep -I')
70054 ->add($expr->isCaseSensitive() ? null : '-i')
70055 ->add($not ? '-L' : '-l')
70056 ->add('-Ee')->arg($expr->renderPattern())
70057 ->add('{}')
70058 ;
70059 }
70060 }
70061 }
70062 <?php
70063
70064
70065
70066
70067
70068
70069
70070
70071
70072
70073 namespace Symfony\Component\Finder\Adapter;
70074
70075 @trigger_error('The '.__NAMESPACE__.'\PhpAdapter class is deprecated since Symfony 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);
70076
70077 use Symfony\Component\Finder\Iterator;
70078
70079
70080
70081
70082
70083
70084
70085
70086 class PhpAdapter extends AbstractAdapter
70087 {
70088
70089
70090
70091 public function searchInDirectory($dir)
70092 {
70093 $flags = \RecursiveDirectoryIterator::SKIP_DOTS;
70094
70095 if ($this->followLinks) {
70096 $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
70097 }
70098
70099 $iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs);
70100
70101 if ($this->exclude) {
70102 $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
70103 }
70104
70105 $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);
70106
70107 if ($this->minDepth > 0 || $this->maxDepth < PHP_INT_MAX) {
70108 $iterator = new Iterator\DepthRangeFilterIterator($iterator, $this->minDepth, $this->maxDepth);
70109 }
70110
70111 if ($this->mode) {
70112 $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
70113 }
70114
70115 if ($this->names || $this->notNames) {
70116 $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
70117 }
70118
70119 if ($this->contains || $this->notContains) {
70120 $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
70121 }
70122
70123 if ($this->sizes) {
70124 $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
70125 }
70126
70127 if ($this->dates) {
70128 $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
70129 }
70130
70131 if ($this->filters) {
70132 $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
70133 }
70134
70135 if ($this->paths || $this->notPaths) {
70136 $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
70137 }
70138
70139 if ($this->sort) {
70140 $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
70141 $iterator = $iteratorAggregate->getIterator();
70142 }
70143
70144 return $iterator;
70145 }
70146
70147
70148
70149
70150 public function getName()
70151 {
70152 return 'php';
70153 }
70154
70155
70156
70157
70158 protected function canBeUsed()
70159 {
70160 return true;
70161 }
70162 }
70163 <?php
70164
70165
70166
70167
70168
70169
70170
70171
70172
70173
70174 namespace Symfony\Component\Finder\Comparator;
70175
70176
70177
70178
70179
70180
70181 class Comparator
70182 {
70183 private $target;
70184 private $operator = '==';
70185
70186
70187
70188
70189
70190
70191 public function getTarget()
70192 {
70193 return $this->target;
70194 }
70195
70196
70197
70198
70199
70200
70201 public function setTarget($target)
70202 {
70203 $this->target = $target;
70204 }
70205
70206
70207
70208
70209
70210
70211 public function getOperator()
70212 {
70213 return $this->operator;
70214 }
70215
70216
70217
70218
70219
70220
70221
70222
70223 public function setOperator($operator)
70224 {
70225 if (!$operator) {
70226 $operator = '==';
70227 }
70228
70229 if (!\in_array($operator, array('>', '<', '>=', '<=', '==', '!='))) {
70230 throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator));
70231 }
70232
70233 $this->operator = $operator;
70234 }
70235
70236
70237
70238
70239
70240
70241
70242
70243 public function test($test)
70244 {
70245 switch ($this->operator) {
70246 case '>':
70247 return $test > $this->target;
70248 case '>=':
70249 return $test >= $this->target;
70250 case '<':
70251 return $test < $this->target;
70252 case '<=':
70253 return $test <= $this->target;
70254 case '!=':
70255 return $test != $this->target;
70256 }
70257
70258 return $test == $this->target;
70259 }
70260 }
70261 <?php
70262
70263
70264
70265
70266
70267
70268
70269
70270
70271
70272 namespace Symfony\Component\Finder\Comparator;
70273
70274
70275
70276
70277
70278
70279 class DateComparator extends Comparator
70280 {
70281
70282
70283
70284
70285
70286 public function __construct($test)
70287 {
70288 if (!preg_match('#^\s*(==|!=|[<>]=?|after|since|before|until)?\s*(.+?)\s*$#i', $test, $matches)) {
70289 throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a date test.', $test));
70290 }
70291
70292 try {
70293 $date = new \DateTime($matches[2]);
70294 $target = $date->format('U');
70295 } catch (\Exception $e) {
70296 throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2]));
70297 }
70298
70299 $operator = isset($matches[1]) ? $matches[1] : '==';
70300 if ('since' === $operator || 'after' === $operator) {
70301 $operator = '>';
70302 }
70303
70304 if ('until' === $operator || 'before' === $operator) {
70305 $operator = '<';
70306 }
70307
70308 $this->setOperator($operator);
70309 $this->setTarget($target);
70310 }
70311 }
70312 <?php
70313
70314
70315
70316
70317
70318
70319
70320
70321
70322
70323 namespace Symfony\Component\Finder\Comparator;
70324
70325
70326
70327
70328
70329
70330
70331
70332
70333
70334
70335
70336
70337
70338
70339
70340
70341
70342
70343
70344
70345
70346 class NumberComparator extends Comparator
70347 {
70348
70349
70350
70351
70352
70353 public function __construct($test)
70354 {
70355 if (!preg_match('#^\s*(==|!=|[<>]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $test, $matches)) {
70356 throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a number test.', $test));
70357 }
70358
70359 $target = $matches[2];
70360 if (!is_numeric($target)) {
70361 throw new \InvalidArgumentException(sprintf('Invalid number "%s".', $target));
70362 }
70363 if (isset($matches[3])) {
70364
70365 switch (strtolower($matches[3])) {
70366 case 'k':
70367 $target *= 1000;
70368 break;
70369 case 'ki':
70370 $target *= 1024;
70371 break;
70372 case 'm':
70373 $target *= 1000000;
70374 break;
70375 case 'mi':
70376 $target *= 1024 * 1024;
70377 break;
70378 case 'g':
70379 $target *= 1000000000;
70380 break;
70381 case 'gi':
70382 $target *= 1024 * 1024 * 1024;
70383 break;
70384 }
70385 }
70386
70387 $this->setTarget($target);
70388 $this->setOperator(isset($matches[1]) ? $matches[1] : '==');
70389 }
70390 }
70391 <?php
70392
70393
70394
70395
70396
70397
70398
70399
70400
70401
70402 namespace Symfony\Component\Finder\Exception;
70403
70404
70405
70406
70407 class AccessDeniedException extends \UnexpectedValueException
70408 {
70409 }
70410 <?php
70411
70412
70413
70414
70415
70416
70417
70418
70419
70420
70421 namespace Symfony\Component\Finder\Exception;
70422
70423 @trigger_error('The '.__NAMESPACE__.'\AdapterFailureException class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
70424
70425 use Symfony\Component\Finder\Adapter\AdapterInterface;
70426
70427
70428
70429
70430
70431
70432
70433
70434 class AdapterFailureException extends \RuntimeException implements ExceptionInterface
70435 {
70436 private $adapter;
70437
70438
70439
70440
70441
70442
70443 public function __construct(AdapterInterface $adapter, $message = null, \Exception $previous = null)
70444 {
70445 $this->adapter = $adapter;
70446 parent::__construct($message ?: 'Search failed with "'.$adapter->getName().'" adapter.', $previous);
70447 }
70448
70449
70450
70451
70452 public function getAdapter()
70453 {
70454 return $this->adapter;
70455 }
70456 }
70457 <?php
70458
70459
70460
70461
70462
70463
70464
70465
70466
70467
70468 namespace Symfony\Component\Finder\Exception;
70469
70470
70471
70472
70473 interface ExceptionInterface
70474 {
70475
70476
70477
70478 public function getAdapter();
70479 }
70480 <?php
70481
70482
70483
70484
70485
70486
70487
70488
70489
70490
70491 namespace Symfony\Component\Finder\Exception;
70492
70493 @trigger_error('The '.__NAMESPACE__.'\OperationNotPermitedException class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
70494
70495
70496
70497
70498
70499
70500 class OperationNotPermitedException extends AdapterFailureException
70501 {
70502 }
70503 <?php
70504
70505
70506
70507
70508
70509
70510
70511
70512
70513
70514 namespace Symfony\Component\Finder\Exception;
70515
70516 @trigger_error('The '.__NAMESPACE__.'\ShellCommandFailureException class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
70517
70518 use Symfony\Component\Finder\Adapter\AdapterInterface;
70519 use Symfony\Component\Finder\Shell\Command;
70520
70521
70522
70523
70524
70525
70526 class ShellCommandFailureException extends AdapterFailureException
70527 {
70528 private $command;
70529
70530 public function __construct(AdapterInterface $adapter, Command $command, \Exception $previous = null)
70531 {
70532 $this->command = $command;
70533 parent::__construct($adapter, 'Shell command failed: "'.$command->join().'".', $previous);
70534 }
70535
70536
70537
70538
70539 public function getCommand()
70540 {
70541 return $this->command;
70542 }
70543 }
70544 <?php
70545
70546
70547
70548
70549
70550
70551
70552
70553
70554
70555 namespace Symfony\Component\Finder\Expression;
70556
70557 @trigger_error('The '.__NAMESPACE__.'\Expression class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
70558
70559
70560
70561
70562 class Expression implements ValueInterface
70563 {
70564 const TYPE_REGEX = 1;
70565 const TYPE_GLOB = 2;
70566
70567
70568
70569
70570 private $value;
70571
70572
70573
70574
70575
70576
70577 public static function create($expr)
70578 {
70579 return new self($expr);
70580 }
70581
70582
70583
70584
70585 public function __construct($expr)
70586 {
70587 try {
70588 $this->value = Regex::create($expr);
70589 } catch (\InvalidArgumentException $e) {
70590 $this->value = new Glob($expr);
70591 }
70592 }
70593
70594
70595
70596
70597 public function __toString()
70598 {
70599 return $this->render();
70600 }
70601
70602
70603
70604
70605 public function render()
70606 {
70607 return $this->value->render();
70608 }
70609
70610
70611
70612
70613 public function renderPattern()
70614 {
70615 return $this->value->renderPattern();
70616 }
70617
70618
70619
70620
70621 public function isCaseSensitive()
70622 {
70623 return $this->value->isCaseSensitive();
70624 }
70625
70626
70627
70628
70629 public function getType()
70630 {
70631 return $this->value->getType();
70632 }
70633
70634
70635
70636
70637 public function prepend($expr)
70638 {
70639 $this->value->prepend($expr);
70640
70641 return $this;
70642 }
70643
70644
70645
70646
70647 public function append($expr)
70648 {
70649 $this->value->append($expr);
70650
70651 return $this;
70652 }
70653
70654
70655
70656
70657 public function isRegex()
70658 {
70659 return self::TYPE_REGEX === $this->value->getType();
70660 }
70661
70662
70663
70664
70665 public function isGlob()
70666 {
70667 return self::TYPE_GLOB === $this->value->getType();
70668 }
70669
70670
70671
70672
70673
70674
70675 public function getGlob()
70676 {
70677 if (self::TYPE_GLOB !== $this->value->getType()) {
70678 throw new \LogicException('Regex can\'t be transformed to glob.');
70679 }
70680
70681 return $this->value;
70682 }
70683
70684
70685
70686
70687 public function getRegex()
70688 {
70689 return self::TYPE_REGEX === $this->value->getType() ? $this->value : $this->value->toRegex();
70690 }
70691 }
70692 <?php
70693
70694
70695
70696
70697
70698
70699
70700
70701
70702
70703 namespace Symfony\Component\Finder\Expression;
70704
70705 @trigger_error('The '.__NAMESPACE__.'\Glob class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
70706
70707 use Symfony\Component\Finder\Glob as FinderGlob;
70708
70709
70710
70711
70712 class Glob implements ValueInterface
70713 {
70714 private $pattern;
70715
70716
70717
70718
70719 public function __construct($pattern)
70720 {
70721 $this->pattern = $pattern;
70722 }
70723
70724
70725
70726
70727 public function render()
70728 {
70729 return $this->pattern;
70730 }
70731
70732
70733
70734
70735 public function renderPattern()
70736 {
70737 return $this->pattern;
70738 }
70739
70740
70741
70742
70743 public function getType()
70744 {
70745 return Expression::TYPE_GLOB;
70746 }
70747
70748
70749
70750
70751 public function isCaseSensitive()
70752 {
70753 return true;
70754 }
70755
70756
70757
70758
70759 public function prepend($expr)
70760 {
70761 $this->pattern = $expr.$this->pattern;
70762
70763 return $this;
70764 }
70765
70766
70767
70768
70769 public function append($expr)
70770 {
70771 $this->pattern .= $expr;
70772
70773 return $this;
70774 }
70775
70776
70777
70778
70779
70780
70781 public function isExpandable()
70782 {
70783 return false !== strpos($this->pattern, '{')
70784 && false !== strpos($this->pattern, '}');
70785 }
70786
70787
70788
70789
70790
70791
70792
70793 public function toRegex($strictLeadingDot = true, $strictWildcardSlash = true)
70794 {
70795 $regex = FinderGlob::toRegex($this->pattern, $strictLeadingDot, $strictWildcardSlash, '');
70796
70797 return new Regex($regex);
70798 }
70799 }
70800 <?php
70801
70802
70803
70804
70805
70806
70807
70808
70809
70810
70811 namespace Symfony\Component\Finder\Expression;
70812
70813 @trigger_error('The '.__NAMESPACE__.'\Regex class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
70814
70815
70816
70817
70818 class Regex implements ValueInterface
70819 {
70820 const START_FLAG = '^';
70821 const END_FLAG = '$';
70822 const BOUNDARY = '~';
70823 const JOKER = '.*';
70824 const ESCAPING = '\\';
70825
70826
70827
70828
70829 private $pattern;
70830
70831
70832
70833
70834 private $options;
70835
70836
70837
70838
70839 private $startFlag;
70840
70841
70842
70843
70844 private $endFlag;
70845
70846
70847
70848
70849 private $startJoker;
70850
70851
70852
70853
70854 private $endJoker;
70855
70856
70857
70858
70859
70860
70861
70862
70863 public static function create($expr)
70864 {
70865 if (preg_match('/^(.{3,}?)([imsxuADU]*)$/', $expr, $m)) {
70866 $start = substr($m[1], 0, 1);
70867 $end = substr($m[1], -1);
70868
70869 if (
70870 ($start === $end && !preg_match('/[*?[:alnum:] \\\\]/', $start))
70871 || ('{' === $start && '}' === $end)
70872 || ('(' === $start && ')' === $end)
70873 ) {
70874 return new self(substr($m[1], 1, -1), $m[2], $end);
70875 }
70876 }
70877
70878 throw new \InvalidArgumentException('Given expression is not a regex.');
70879 }
70880
70881
70882
70883
70884
70885
70886 public function __construct($pattern, $options = '', $delimiter = null)
70887 {
70888 if (null !== $delimiter) {
70889
70890 $pattern = str_replace('\\'.$delimiter, $delimiter, $pattern);
70891 }
70892
70893 $this->parsePattern($pattern);
70894 $this->options = $options;
70895 }
70896
70897
70898
70899
70900 public function __toString()
70901 {
70902 return $this->render();
70903 }
70904
70905
70906
70907
70908 public function render()
70909 {
70910 return self::BOUNDARY
70911 .$this->renderPattern()
70912 .self::BOUNDARY
70913 .$this->options;
70914 }
70915
70916
70917
70918
70919 public function renderPattern()
70920 {
70921 return ($this->startFlag ? self::START_FLAG : '')
70922 .($this->startJoker ? self::JOKER : '')
70923 .str_replace(self::BOUNDARY, '\\'.self::BOUNDARY, $this->pattern)
70924 .($this->endJoker ? self::JOKER : '')
70925 .($this->endFlag ? self::END_FLAG : '');
70926 }
70927
70928
70929
70930
70931 public function isCaseSensitive()
70932 {
70933 return !$this->hasOption('i');
70934 }
70935
70936
70937
70938
70939 public function getType()
70940 {
70941 return Expression::TYPE_REGEX;
70942 }
70943
70944
70945
70946
70947 public function prepend($expr)
70948 {
70949 $this->pattern = $expr.$this->pattern;
70950
70951 return $this;
70952 }
70953
70954
70955
70956
70957 public function append($expr)
70958 {
70959 $this->pattern .= $expr;
70960
70961 return $this;
70962 }
70963
70964
70965
70966
70967
70968
70969 public function hasOption($option)
70970 {
70971 return false !== strpos($this->options, $option);
70972 }
70973
70974
70975
70976
70977
70978
70979 public function addOption($option)
70980 {
70981 if (!$this->hasOption($option)) {
70982 $this->options .= $option;
70983 }
70984
70985 return $this;
70986 }
70987
70988
70989
70990
70991
70992
70993 public function removeOption($option)
70994 {
70995 $this->options = str_replace($option, '', $this->options);
70996
70997 return $this;
70998 }
70999
71000
71001
71002
71003
71004
71005 public function setStartFlag($startFlag)
71006 {
71007 $this->startFlag = $startFlag;
71008
71009 return $this;
71010 }
71011
71012
71013
71014
71015 public function hasStartFlag()
71016 {
71017 return $this->startFlag;
71018 }
71019
71020
71021
71022
71023
71024
71025 public function setEndFlag($endFlag)
71026 {
71027 $this->endFlag = (bool) $endFlag;
71028
71029 return $this;
71030 }
71031
71032
71033
71034
71035 public function hasEndFlag()
71036 {
71037 return $this->endFlag;
71038 }
71039
71040
71041
71042
71043
71044
71045 public function setStartJoker($startJoker)
71046 {
71047 $this->startJoker = $startJoker;
71048
71049 return $this;
71050 }
71051
71052
71053
71054
71055 public function hasStartJoker()
71056 {
71057 return $this->startJoker;
71058 }
71059
71060
71061
71062
71063
71064
71065 public function setEndJoker($endJoker)
71066 {
71067 $this->endJoker = (bool) $endJoker;
71068
71069 return $this;
71070 }
71071
71072
71073
71074
71075 public function hasEndJoker()
71076 {
71077 return $this->endJoker;
71078 }
71079
71080
71081
71082
71083 public function replaceJokers($replacement)
71084 {
71085 $replace = function ($subject) use ($replacement) {
71086 $subject = $subject[0];
71087 $replace = 0 === substr_count($subject, '\\') % 2;
71088
71089 return $replace ? str_replace('.', $replacement, $subject) : $subject;
71090 };
71091
71092 $this->pattern = preg_replace_callback('~[\\\\]*\\.~', $replace, $this->pattern);
71093
71094 return $this;
71095 }
71096
71097
71098
71099
71100 private function parsePattern($pattern)
71101 {
71102 if ($this->startFlag = self::START_FLAG === substr($pattern, 0, 1)) {
71103 $pattern = substr($pattern, 1);
71104 }
71105
71106 if ($this->startJoker = self::JOKER === substr($pattern, 0, 2)) {
71107 $pattern = substr($pattern, 2);
71108 }
71109
71110 if ($this->endFlag = (self::END_FLAG === substr($pattern, -1) && self::ESCAPING !== substr($pattern, -2, -1))) {
71111 $pattern = substr($pattern, 0, -1);
71112 }
71113
71114 if ($this->endJoker = (self::JOKER === substr($pattern, -2) && self::ESCAPING !== substr($pattern, -3, -2))) {
71115 $pattern = substr($pattern, 0, -2);
71116 }
71117
71118 $this->pattern = $pattern;
71119 }
71120 }
71121 <?php
71122
71123
71124
71125
71126
71127
71128
71129
71130
71131
71132 namespace Symfony\Component\Finder\Expression;
71133
71134 @trigger_error('The '.__NAMESPACE__.'\ValueInterface interface is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
71135
71136
71137
71138
71139 interface ValueInterface
71140 {
71141
71142
71143
71144
71145
71146 public function render();
71147
71148
71149
71150
71151
71152
71153 public function renderPattern();
71154
71155
71156
71157
71158
71159
71160 public function isCaseSensitive();
71161
71162
71163
71164
71165
71166
71167 public function getType();
71168
71169
71170
71171
71172
71173
71174 public function prepend($expr);
71175
71176
71177
71178
71179
71180
71181 public function append($expr);
71182 }
71183 <?php
71184
71185
71186
71187
71188
71189
71190
71191
71192
71193
71194 namespace Symfony\Component\Finder;
71195
71196 use Symfony\Component\Finder\Adapter\AdapterInterface;
71197 use Symfony\Component\Finder\Adapter\BsdFindAdapter;
71198 use Symfony\Component\Finder\Adapter\GnuFindAdapter;
71199 use Symfony\Component\Finder\Adapter\PhpAdapter;
71200 use Symfony\Component\Finder\Comparator\DateComparator;
71201 use Symfony\Component\Finder\Comparator\NumberComparator;
71202 use Symfony\Component\Finder\Exception\ExceptionInterface;
71203 use Symfony\Component\Finder\Iterator\CustomFilterIterator;
71204 use Symfony\Component\Finder\Iterator\DateRangeFilterIterator;
71205 use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator;
71206 use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator;
71207 use Symfony\Component\Finder\Iterator\FilecontentFilterIterator;
71208 use Symfony\Component\Finder\Iterator\FilenameFilterIterator;
71209 use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator;
71210 use Symfony\Component\Finder\Iterator\SortableIterator;
71211
71212
71213
71214
71215
71216
71217
71218
71219
71220
71221
71222
71223
71224
71225 class Finder implements \IteratorAggregate, \Countable
71226 {
71227 const IGNORE_VCS_FILES = 1;
71228 const IGNORE_DOT_FILES = 2;
71229
71230 private $mode = 0;
71231 private $names = array();
71232 private $notNames = array();
71233 private $exclude = array();
71234 private $filters = array();
71235 private $depths = array();
71236 private $sizes = array();
71237 private $followLinks = false;
71238 private $sort = false;
71239 private $ignore = 0;
71240 private $dirs = array();
71241 private $dates = array();
71242 private $iterators = array();
71243 private $contains = array();
71244 private $notContains = array();
71245 private $adapters = null;
71246 private $paths = array();
71247 private $notPaths = array();
71248 private $ignoreUnreadableDirs = false;
71249
71250 private static $vcsPatterns = array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg');
71251
71252 public function __construct()
71253 {
71254 $this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
71255 }
71256
71257
71258
71259
71260
71261
71262 public static function create()
71263 {
71264 return new static();
71265 }
71266
71267
71268
71269
71270
71271
71272
71273
71274
71275
71276
71277 public function addAdapter(AdapterInterface $adapter, $priority = 0)
71278 {
71279 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
71280
71281 $this->initDefaultAdapters();
71282
71283 $this->adapters[$adapter->getName()] = array(
71284 'adapter' => $adapter,
71285 'priority' => $priority,
71286 'selected' => false,
71287 );
71288
71289 return $this->sortAdapters();
71290 }
71291
71292
71293
71294
71295
71296
71297
71298
71299 public function useBestAdapter()
71300 {
71301 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
71302
71303 $this->initDefaultAdapters();
71304
71305 $this->resetAdapterSelection();
71306
71307 return $this->sortAdapters();
71308 }
71309
71310
71311
71312
71313
71314
71315
71316
71317
71318
71319
71320
71321 public function setAdapter($name)
71322 {
71323 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
71324
71325 $this->initDefaultAdapters();
71326
71327 if (!isset($this->adapters[$name])) {
71328 throw new \InvalidArgumentException(sprintf('Adapter "%s" does not exist.', $name));
71329 }
71330
71331 $this->resetAdapterSelection();
71332 $this->adapters[$name]['selected'] = true;
71333
71334 return $this->sortAdapters();
71335 }
71336
71337
71338
71339
71340
71341
71342
71343
71344 public function removeAdapters()
71345 {
71346 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
71347
71348 $this->adapters = array();
71349
71350 return $this;
71351 }
71352
71353
71354
71355
71356
71357
71358
71359
71360 public function getAdapters()
71361 {
71362 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
71363
71364 $this->initDefaultAdapters();
71365
71366 return array_values(array_map(function (array $adapter) {
71367 return $adapter['adapter'];
71368 }, $this->adapters));
71369 }
71370
71371
71372
71373
71374
71375
71376 public function directories()
71377 {
71378 $this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES;
71379
71380 return $this;
71381 }
71382
71383
71384
71385
71386
71387
71388 public function files()
71389 {
71390 $this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES;
71391
71392 return $this;
71393 }
71394
71395
71396
71397
71398
71399
71400
71401
71402
71403
71404
71405
71406
71407
71408
71409
71410 public function depth($level)
71411 {
71412 $this->depths[] = new Comparator\NumberComparator($level);
71413
71414 return $this;
71415 }
71416
71417
71418
71419
71420
71421
71422
71423
71424
71425
71426
71427
71428
71429
71430
71431
71432
71433
71434
71435 public function date($date)
71436 {
71437 $this->dates[] = new Comparator\DateComparator($date);
71438
71439 return $this;
71440 }
71441
71442
71443
71444
71445
71446
71447
71448
71449
71450
71451
71452
71453
71454
71455
71456
71457 public function name($pattern)
71458 {
71459 $this->names[] = $pattern;
71460
71461 return $this;
71462 }
71463
71464
71465
71466
71467
71468
71469
71470
71471
71472
71473 public function notName($pattern)
71474 {
71475 $this->notNames[] = $pattern;
71476
71477 return $this;
71478 }
71479
71480
71481
71482
71483
71484
71485
71486
71487
71488
71489
71490
71491
71492
71493
71494 public function contains($pattern)
71495 {
71496 $this->contains[] = $pattern;
71497
71498 return $this;
71499 }
71500
71501
71502
71503
71504
71505
71506
71507
71508
71509
71510
71511
71512
71513
71514
71515 public function notContains($pattern)
71516 {
71517 $this->notContains[] = $pattern;
71518
71519 return $this;
71520 }
71521
71522
71523
71524
71525
71526
71527
71528
71529
71530
71531
71532
71533
71534
71535
71536
71537
71538 public function path($pattern)
71539 {
71540 $this->paths[] = $pattern;
71541
71542 return $this;
71543 }
71544
71545
71546
71547
71548
71549
71550
71551
71552
71553
71554
71555
71556
71557
71558
71559
71560
71561 public function notPath($pattern)
71562 {
71563 $this->notPaths[] = $pattern;
71564
71565 return $this;
71566 }
71567
71568
71569
71570
71571
71572
71573
71574
71575
71576
71577
71578
71579
71580
71581
71582 public function size($size)
71583 {
71584 $this->sizes[] = new Comparator\NumberComparator($size);
71585
71586 return $this;
71587 }
71588
71589
71590
71591
71592
71593
71594
71595
71596
71597
71598
71599
71600
71601
71602 public function exclude($dirs)
71603 {
71604 $this->exclude = array_merge($this->exclude, (array) $dirs);
71605
71606 return $this;
71607 }
71608
71609
71610
71611
71612
71613
71614
71615
71616
71617
71618
71619
71620 public function ignoreDotFiles($ignoreDotFiles)
71621 {
71622 if ($ignoreDotFiles) {
71623 $this->ignore |= static::IGNORE_DOT_FILES;
71624 } else {
71625 $this->ignore &= ~static::IGNORE_DOT_FILES;
71626 }
71627
71628 return $this;
71629 }
71630
71631
71632
71633
71634
71635
71636
71637
71638
71639
71640
71641
71642 public function ignoreVCS($ignoreVCS)
71643 {
71644 if ($ignoreVCS) {
71645 $this->ignore |= static::IGNORE_VCS_FILES;
71646 } else {
71647 $this->ignore &= ~static::IGNORE_VCS_FILES;
71648 }
71649
71650 return $this;
71651 }
71652
71653
71654
71655
71656
71657
71658
71659
71660 public static function addVCSPattern($pattern)
71661 {
71662 foreach ((array) $pattern as $p) {
71663 self::$vcsPatterns[] = $p;
71664 }
71665
71666 self::$vcsPatterns = array_unique(self::$vcsPatterns);
71667 }
71668
71669
71670
71671
71672
71673
71674
71675
71676
71677
71678
71679
71680 public function sort(\Closure $closure)
71681 {
71682 $this->sort = $closure;
71683
71684 return $this;
71685 }
71686
71687
71688
71689
71690
71691
71692
71693
71694
71695
71696 public function sortByName()
71697 {
71698 $this->sort = Iterator\SortableIterator::SORT_BY_NAME;
71699
71700 return $this;
71701 }
71702
71703
71704
71705
71706
71707
71708
71709
71710
71711
71712 public function sortByType()
71713 {
71714 $this->sort = Iterator\SortableIterator::SORT_BY_TYPE;
71715
71716 return $this;
71717 }
71718
71719
71720
71721
71722
71723
71724
71725
71726
71727
71728
71729
71730 public function sortByAccessedTime()
71731 {
71732 $this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME;
71733
71734 return $this;
71735 }
71736
71737
71738
71739
71740
71741
71742
71743
71744
71745
71746
71747
71748
71749
71750 public function sortByChangedTime()
71751 {
71752 $this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME;
71753
71754 return $this;
71755 }
71756
71757
71758
71759
71760
71761
71762
71763
71764
71765
71766
71767
71768 public function sortByModifiedTime()
71769 {
71770 $this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME;
71771
71772 return $this;
71773 }
71774
71775
71776
71777
71778
71779
71780
71781
71782
71783
71784
71785 public function filter(\Closure $closure)
71786 {
71787 $this->filters[] = $closure;
71788
71789 return $this;
71790 }
71791
71792
71793
71794
71795
71796
71797 public function followLinks()
71798 {
71799 $this->followLinks = true;
71800
71801 return $this;
71802 }
71803
71804
71805
71806
71807
71808
71809
71810
71811
71812
71813 public function ignoreUnreadableDirs($ignore = true)
71814 {
71815 $this->ignoreUnreadableDirs = (bool) $ignore;
71816
71817 return $this;
71818 }
71819
71820
71821
71822
71823
71824
71825
71826
71827
71828
71829 public function in($dirs)
71830 {
71831 $resolvedDirs = array();
71832
71833 foreach ((array) $dirs as $dir) {
71834 if (is_dir($dir)) {
71835 $resolvedDirs[] = $this->normalizeDir($dir);
71836 } elseif ($glob = glob($dir, (\defined('GLOB_BRACE') ? GLOB_BRACE : 0) | GLOB_ONLYDIR)) {
71837 $resolvedDirs = array_merge($resolvedDirs, array_map(array($this, 'normalizeDir'), $glob));
71838 } else {
71839 throw new \InvalidArgumentException(sprintf('The "%s" directory does not exist.', $dir));
71840 }
71841 }
71842
71843 $this->dirs = array_merge($this->dirs, $resolvedDirs);
71844
71845 return $this;
71846 }
71847
71848
71849
71850
71851
71852
71853
71854
71855
71856
71857 public function getIterator()
71858 {
71859 if (0 === \count($this->dirs) && 0 === \count($this->iterators)) {
71860 throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.');
71861 }
71862
71863 if (1 === \count($this->dirs) && 0 === \count($this->iterators)) {
71864 return $this->searchInDirectory($this->dirs[0]);
71865 }
71866
71867 $iterator = new \AppendIterator();
71868 foreach ($this->dirs as $dir) {
71869 $iterator->append($this->searchInDirectory($dir));
71870 }
71871
71872 foreach ($this->iterators as $it) {
71873 $iterator->append($it);
71874 }
71875
71876 return $iterator;
71877 }
71878
71879
71880
71881
71882
71883
71884
71885
71886
71887
71888
71889
71890 public function append($iterator)
71891 {
71892 if ($iterator instanceof \IteratorAggregate) {
71893 $this->iterators[] = $iterator->getIterator();
71894 } elseif ($iterator instanceof \Iterator) {
71895 $this->iterators[] = $iterator;
71896 } elseif ($iterator instanceof \Traversable || \is_array($iterator)) {
71897 $it = new \ArrayIterator();
71898 foreach ($iterator as $file) {
71899 $it->append($file instanceof \SplFileInfo ? $file : new \SplFileInfo($file));
71900 }
71901 $this->iterators[] = $it;
71902 } else {
71903 throw new \InvalidArgumentException('Finder::append() method wrong argument type.');
71904 }
71905
71906 return $this;
71907 }
71908
71909
71910
71911
71912
71913
71914 public function count()
71915 {
71916 return iterator_count($this->getIterator());
71917 }
71918
71919
71920
71921
71922 private function sortAdapters()
71923 {
71924 uasort($this->adapters, function (array $a, array $b) {
71925 if ($a['selected'] || $b['selected']) {
71926 return $a['selected'] ? -1 : 1;
71927 }
71928
71929 return $a['priority'] > $b['priority'] ? -1 : 1;
71930 });
71931
71932 return $this;
71933 }
71934
71935
71936
71937
71938
71939
71940 private function searchInDirectory($dir)
71941 {
71942 if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
71943 $this->exclude = array_merge($this->exclude, self::$vcsPatterns);
71944 }
71945
71946 if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
71947 $this->notPaths[] = '#(^|/)\..+(/|$)#';
71948 }
71949
71950 if ($this->adapters) {
71951 foreach ($this->adapters as $adapter) {
71952 if ($adapter['adapter']->isSupported()) {
71953 try {
71954 return $this
71955 ->buildAdapter($adapter['adapter'])
71956 ->searchInDirectory($dir);
71957 } catch (ExceptionInterface $e) {
71958 }
71959 }
71960 }
71961 }
71962
71963 $minDepth = 0;
71964 $maxDepth = PHP_INT_MAX;
71965
71966 foreach ($this->depths as $comparator) {
71967 switch ($comparator->getOperator()) {
71968 case '>':
71969 $minDepth = $comparator->getTarget() + 1;
71970 break;
71971 case '>=':
71972 $minDepth = $comparator->getTarget();
71973 break;
71974 case '<':
71975 $maxDepth = $comparator->getTarget() - 1;
71976 break;
71977 case '<=':
71978 $maxDepth = $comparator->getTarget();
71979 break;
71980 default:
71981 $minDepth = $maxDepth = $comparator->getTarget();
71982 }
71983 }
71984
71985 $flags = \RecursiveDirectoryIterator::SKIP_DOTS;
71986
71987 if ($this->followLinks) {
71988 $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
71989 }
71990
71991 $iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs);
71992
71993 if ($this->exclude) {
71994 $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
71995 }
71996
71997 $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);
71998
71999 if ($minDepth > 0 || $maxDepth < PHP_INT_MAX) {
72000 $iterator = new Iterator\DepthRangeFilterIterator($iterator, $minDepth, $maxDepth);
72001 }
72002
72003 if ($this->mode) {
72004 $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
72005 }
72006
72007 if ($this->names || $this->notNames) {
72008 $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
72009 }
72010
72011 if ($this->contains || $this->notContains) {
72012 $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
72013 }
72014
72015 if ($this->sizes) {
72016 $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
72017 }
72018
72019 if ($this->dates) {
72020 $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
72021 }
72022
72023 if ($this->filters) {
72024 $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
72025 }
72026
72027 if ($this->paths || $this->notPaths) {
72028 $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
72029 }
72030
72031 if ($this->sort) {
72032 $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
72033 $iterator = $iteratorAggregate->getIterator();
72034 }
72035
72036 return $iterator;
72037 }
72038
72039
72040
72041
72042 private function buildAdapter(AdapterInterface $adapter)
72043 {
72044 return $adapter
72045 ->setFollowLinks($this->followLinks)
72046 ->setDepths($this->depths)
72047 ->setMode($this->mode)
72048 ->setExclude($this->exclude)
72049 ->setNames($this->names)
72050 ->setNotNames($this->notNames)
72051 ->setContains($this->contains)
72052 ->setNotContains($this->notContains)
72053 ->setSizes($this->sizes)
72054 ->setDates($this->dates)
72055 ->setFilters($this->filters)
72056 ->setSort($this->sort)
72057 ->setPath($this->paths)
72058 ->setNotPath($this->notPaths)
72059 ->ignoreUnreadableDirs($this->ignoreUnreadableDirs);
72060 }
72061
72062
72063
72064
72065 private function resetAdapterSelection()
72066 {
72067 $this->adapters = array_map(function (array $properties) {
72068 $properties['selected'] = false;
72069
72070 return $properties;
72071 }, $this->adapters);
72072 }
72073
72074 private function initDefaultAdapters()
72075 {
72076 if (null === $this->adapters) {
72077 $this->adapters = array();
72078 $this
72079 ->addAdapter(new GnuFindAdapter())
72080 ->addAdapter(new BsdFindAdapter())
72081 ->addAdapter(new PhpAdapter(), -50)
72082 ->setAdapter('php')
72083 ;
72084 }
72085 }
72086
72087
72088
72089
72090
72091
72092
72093
72094 private function normalizeDir($dir)
72095 {
72096 return rtrim($dir, '/'.\DIRECTORY_SEPARATOR);
72097 }
72098 }
72099 <?php
72100
72101
72102
72103
72104
72105
72106
72107
72108
72109
72110 namespace Symfony\Component\Finder;
72111
72112
72113
72114
72115
72116
72117
72118
72119
72120
72121
72122
72123
72124
72125
72126
72127
72128
72129
72130
72131
72132
72133
72134 class Glob
72135 {
72136
72137
72138
72139
72140
72141
72142
72143
72144
72145
72146 public static function toRegex($glob, $strictLeadingDot = true, $strictWildcardSlash = true, $delimiter = '#')
72147 {
72148 $firstByte = true;
72149 $escaping = false;
72150 $inCurlies = 0;
72151 $regex = '';
72152 $sizeGlob = \strlen($glob);
72153 for ($i = 0; $i < $sizeGlob; ++$i) {
72154 $car = $glob[$i];
72155 if ($firstByte) {
72156 if ($strictLeadingDot && '.' !== $car) {
72157 $regex .= '(?=[^\.])';
72158 }
72159
72160 $firstByte = false;
72161 }
72162
72163 if ('/' === $car) {
72164 $firstByte = true;
72165 }
72166
72167 if ($delimiter === $car || '.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
72168 $regex .= "\\$car";
72169 } elseif ('*' === $car) {
72170 $regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
72171 } elseif ('?' === $car) {
72172 $regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
72173 } elseif ('{' === $car) {
72174 $regex .= $escaping ? '\\{' : '(';
72175 if (!$escaping) {
72176 ++$inCurlies;
72177 }
72178 } elseif ('}' === $car && $inCurlies) {
72179 $regex .= $escaping ? '}' : ')';
72180 if (!$escaping) {
72181 --$inCurlies;
72182 }
72183 } elseif (',' === $car && $inCurlies) {
72184 $regex .= $escaping ? ',' : '|';
72185 } elseif ('\\' === $car) {
72186 if ($escaping) {
72187 $regex .= '\\\\';
72188 $escaping = false;
72189 } else {
72190 $escaping = true;
72191 }
72192
72193 continue;
72194 } else {
72195 $regex .= $car;
72196 }
72197 $escaping = false;
72198 }
72199
72200 return $delimiter.'^'.$regex.'$'.$delimiter;
72201 }
72202 }
72203 <?php
72204
72205
72206
72207
72208
72209
72210
72211
72212
72213
72214 namespace Symfony\Component\Finder\Iterator;
72215
72216
72217
72218
72219
72220
72221
72222
72223
72224 class CustomFilterIterator extends FilterIterator
72225 {
72226 private $filters = array();
72227
72228
72229
72230
72231
72232
72233
72234 public function __construct(\Iterator $iterator, array $filters)
72235 {
72236 foreach ($filters as $filter) {
72237 if (!\is_callable($filter)) {
72238 throw new \InvalidArgumentException('Invalid PHP callback.');
72239 }
72240 }
72241 $this->filters = $filters;
72242
72243 parent::__construct($iterator);
72244 }
72245
72246
72247
72248
72249
72250
72251 public function accept()
72252 {
72253 $fileinfo = $this->current();
72254
72255 foreach ($this->filters as $filter) {
72256 if (false === \call_user_func($filter, $fileinfo)) {
72257 return false;
72258 }
72259 }
72260
72261 return true;
72262 }
72263 }
72264 <?php
72265
72266
72267
72268
72269
72270
72271
72272
72273
72274
72275 namespace Symfony\Component\Finder\Iterator;
72276
72277 use Symfony\Component\Finder\Comparator\DateComparator;
72278
72279
72280
72281
72282
72283
72284 class DateRangeFilterIterator extends FilterIterator
72285 {
72286 private $comparators = array();
72287
72288
72289
72290
72291
72292 public function __construct(\Iterator $iterator, array $comparators)
72293 {
72294 $this->comparators = $comparators;
72295
72296 parent::__construct($iterator);
72297 }
72298
72299
72300
72301
72302
72303
72304 public function accept()
72305 {
72306 $fileinfo = $this->current();
72307
72308 if (!file_exists($fileinfo->getPathname())) {
72309 return false;
72310 }
72311
72312 $filedate = $fileinfo->getMTime();
72313 foreach ($this->comparators as $compare) {
72314 if (!$compare->test($filedate)) {
72315 return false;
72316 }
72317 }
72318
72319 return true;
72320 }
72321 }
72322 <?php
72323
72324
72325
72326
72327
72328
72329
72330
72331
72332
72333 namespace Symfony\Component\Finder\Iterator;
72334
72335
72336
72337
72338
72339
72340 class DepthRangeFilterIterator extends FilterIterator
72341 {
72342 private $minDepth = 0;
72343
72344
72345
72346
72347
72348
72349 public function __construct(\RecursiveIteratorIterator $iterator, $minDepth = 0, $maxDepth = PHP_INT_MAX)
72350 {
72351 $this->minDepth = $minDepth;
72352 $iterator->setMaxDepth(PHP_INT_MAX === $maxDepth ? -1 : $maxDepth);
72353
72354 parent::__construct($iterator);
72355 }
72356
72357
72358
72359
72360
72361
72362 public function accept()
72363 {
72364 return $this->getInnerIterator()->getDepth() >= $this->minDepth;
72365 }
72366 }
72367 <?php
72368
72369
72370
72371
72372
72373
72374
72375
72376
72377
72378 namespace Symfony\Component\Finder\Iterator;
72379
72380
72381
72382
72383
72384
72385 class ExcludeDirectoryFilterIterator extends FilterIterator implements \RecursiveIterator
72386 {
72387 private $iterator;
72388 private $isRecursive;
72389 private $excludedDirs = array();
72390 private $excludedPattern;
72391
72392
72393
72394
72395
72396 public function __construct(\Iterator $iterator, array $directories)
72397 {
72398 $this->iterator = $iterator;
72399 $this->isRecursive = $iterator instanceof \RecursiveIterator;
72400 $patterns = array();
72401 foreach ($directories as $directory) {
72402 $directory = rtrim($directory, '/');
72403 if (!$this->isRecursive || false !== strpos($directory, '/')) {
72404 $patterns[] = preg_quote($directory, '#');
72405 } else {
72406 $this->excludedDirs[$directory] = true;
72407 }
72408 }
72409 if ($patterns) {
72410 $this->excludedPattern = '#(?:^|/)(?:'.implode('|', $patterns).')(?:/|$)#';
72411 }
72412
72413 parent::__construct($iterator);
72414 }
72415
72416
72417
72418
72419
72420
72421 public function accept()
72422 {
72423 if ($this->isRecursive && isset($this->excludedDirs[$this->getFilename()]) && $this->isDir()) {
72424 return false;
72425 }
72426
72427 if ($this->excludedPattern) {
72428 $path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath();
72429 $path = str_replace('\\', '/', $path);
72430
72431 return !preg_match($this->excludedPattern, $path);
72432 }
72433
72434 return true;
72435 }
72436
72437 public function hasChildren()
72438 {
72439 return $this->isRecursive && $this->iterator->hasChildren();
72440 }
72441
72442 public function getChildren()
72443 {
72444 $children = new self($this->iterator->getChildren(), array());
72445 $children->excludedDirs = $this->excludedDirs;
72446 $children->excludedPattern = $this->excludedPattern;
72447
72448 return $children;
72449 }
72450 }
72451 <?php
72452
72453
72454
72455
72456
72457
72458
72459
72460
72461
72462 namespace Symfony\Component\Finder\Iterator;
72463
72464 @trigger_error('The '.__NAMESPACE__.'\FilePathsIterator class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
72465
72466 use Symfony\Component\Finder\SplFileInfo;
72467
72468
72469
72470
72471
72472
72473
72474
72475 class FilePathsIterator extends \ArrayIterator
72476 {
72477
72478
72479
72480 private $baseDir;
72481
72482
72483
72484
72485 private $baseDirLength;
72486
72487
72488
72489
72490 private $subPath;
72491
72492
72493
72494
72495 private $subPathname;
72496
72497
72498
72499
72500 private $current;
72501
72502
72503
72504
72505
72506 public function __construct(array $paths, $baseDir)
72507 {
72508 $this->baseDir = $baseDir;
72509 $this->baseDirLength = \strlen($baseDir);
72510
72511 parent::__construct($paths);
72512 }
72513
72514
72515
72516
72517
72518
72519
72520 public function __call($name, array $arguments)
72521 {
72522 return \call_user_func_array(array($this->current(), $name), $arguments);
72523 }
72524
72525
72526
72527
72528
72529
72530 public function current()
72531 {
72532 return $this->current;
72533 }
72534
72535
72536
72537
72538 public function key()
72539 {
72540 return $this->current->getPathname();
72541 }
72542
72543 public function next()
72544 {
72545 parent::next();
72546 $this->buildProperties();
72547 }
72548
72549 public function rewind()
72550 {
72551 parent::rewind();
72552 $this->buildProperties();
72553 }
72554
72555
72556
72557
72558 public function getSubPath()
72559 {
72560 return $this->subPath;
72561 }
72562
72563
72564
72565
72566 public function getSubPathname()
72567 {
72568 return $this->subPathname;
72569 }
72570
72571 private function buildProperties()
72572 {
72573 $absolutePath = parent::current();
72574
72575 if ($this->baseDir === substr($absolutePath, 0, $this->baseDirLength)) {
72576 $this->subPathname = ltrim(substr($absolutePath, $this->baseDirLength), '/\\');
72577 $dir = \dirname($this->subPathname);
72578 $this->subPath = '.' === $dir ? '' : $dir;
72579 } else {
72580 $this->subPath = $this->subPathname = '';
72581 }
72582
72583 $this->current = new SplFileInfo(parent::current(), $this->subPath, $this->subPathname);
72584 }
72585 }
72586 <?php
72587
72588
72589
72590
72591
72592
72593
72594
72595
72596
72597 namespace Symfony\Component\Finder\Iterator;
72598
72599
72600
72601
72602
72603
72604 class FileTypeFilterIterator extends FilterIterator
72605 {
72606 const ONLY_FILES = 1;
72607 const ONLY_DIRECTORIES = 2;
72608
72609 private $mode;
72610
72611
72612
72613
72614
72615 public function __construct(\Iterator $iterator, $mode)
72616 {
72617 $this->mode = $mode;
72618
72619 parent::__construct($iterator);
72620 }
72621
72622
72623
72624
72625
72626
72627 public function accept()
72628 {
72629 $fileinfo = $this->current();
72630 if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $fileinfo->isFile()) {
72631 return false;
72632 } elseif (self::ONLY_FILES === (self::ONLY_FILES & $this->mode) && $fileinfo->isDir()) {
72633 return false;
72634 }
72635
72636 return true;
72637 }
72638 }
72639 <?php
72640
72641
72642
72643
72644
72645
72646
72647
72648
72649
72650 namespace Symfony\Component\Finder\Iterator;
72651
72652
72653
72654
72655
72656
72657
72658 class FilecontentFilterIterator extends MultiplePcreFilterIterator
72659 {
72660
72661
72662
72663
72664
72665 public function accept()
72666 {
72667 if (!$this->matchRegexps && !$this->noMatchRegexps) {
72668 return true;
72669 }
72670
72671 $fileinfo = $this->current();
72672
72673 if ($fileinfo->isDir() || !$fileinfo->isReadable()) {
72674 return false;
72675 }
72676
72677 $content = $fileinfo->getContents();
72678 if (!$content) {
72679 return false;
72680 }
72681
72682 return $this->isAccepted($content);
72683 }
72684
72685
72686
72687
72688
72689
72690
72691
72692 protected function toRegex($str)
72693 {
72694 return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
72695 }
72696 }
72697 <?php
72698
72699
72700
72701
72702
72703
72704
72705
72706
72707
72708 namespace Symfony\Component\Finder\Iterator;
72709
72710 use Symfony\Component\Finder\Glob;
72711
72712
72713
72714
72715
72716
72717 class FilenameFilterIterator extends MultiplePcreFilterIterator
72718 {
72719
72720
72721
72722
72723
72724 public function accept()
72725 {
72726 return $this->isAccepted($this->current()->getFilename());
72727 }
72728
72729
72730
72731
72732
72733
72734
72735
72736
72737
72738
72739 protected function toRegex($str)
72740 {
72741 return $this->isRegex($str) ? $str : Glob::toRegex($str);
72742 }
72743 }
72744 <?php
72745
72746
72747
72748
72749
72750
72751
72752
72753
72754
72755 namespace Symfony\Component\Finder\Iterator;
72756
72757
72758
72759
72760
72761
72762
72763
72764
72765 abstract class FilterIterator extends \FilterIterator
72766 {
72767
72768
72769
72770
72771
72772
72773 public function rewind()
72774 {
72775 if (\PHP_VERSION_ID > 50607 || (\PHP_VERSION_ID > 50523 && \PHP_VERSION_ID < 50600)) {
72776 parent::rewind();
72777
72778 return;
72779 }
72780
72781 $iterator = $this;
72782 while ($iterator instanceof \OuterIterator) {
72783 $innerIterator = $iterator->getInnerIterator();
72784
72785 if ($innerIterator instanceof RecursiveDirectoryIterator) {
72786
72787 if ($innerIterator->isRewindable()) {
72788 $innerIterator->next();
72789 $innerIterator->rewind();
72790 }
72791 } elseif ($innerIterator instanceof \FilesystemIterator) {
72792 $innerIterator->next();
72793 $innerIterator->rewind();
72794 }
72795
72796 $iterator = $innerIterator;
72797 }
72798
72799 parent::rewind();
72800 }
72801 }
72802 <?php
72803
72804
72805
72806
72807
72808
72809
72810
72811
72812
72813 namespace Symfony\Component\Finder\Iterator;
72814
72815
72816
72817
72818
72819
72820 abstract class MultiplePcreFilterIterator extends FilterIterator
72821 {
72822 protected $matchRegexps = array();
72823 protected $noMatchRegexps = array();
72824
72825
72826
72827
72828
72829
72830 public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns)
72831 {
72832 foreach ($matchPatterns as $pattern) {
72833 $this->matchRegexps[] = $this->toRegex($pattern);
72834 }
72835
72836 foreach ($noMatchPatterns as $pattern) {
72837 $this->noMatchRegexps[] = $this->toRegex($pattern);
72838 }
72839
72840 parent::__construct($iterator);
72841 }
72842
72843
72844
72845
72846
72847
72848
72849
72850
72851
72852
72853
72854 protected function isAccepted($string)
72855 {
72856
72857 foreach ($this->noMatchRegexps as $regex) {
72858 if (preg_match($regex, $string)) {
72859 return false;
72860 }
72861 }
72862
72863
72864 if ($this->matchRegexps) {
72865 foreach ($this->matchRegexps as $regex) {
72866 if (preg_match($regex, $string)) {
72867 return true;
72868 }
72869 }
72870
72871 return false;
72872 }
72873
72874
72875 return true;
72876 }
72877
72878
72879
72880
72881
72882
72883
72884
72885 protected function isRegex($str)
72886 {
72887 if (preg_match('/^(.{3,}?)[imsxuADU]*$/', $str, $m)) {
72888 $start = substr($m[1], 0, 1);
72889 $end = substr($m[1], -1);
72890
72891 if ($start === $end) {
72892 return !preg_match('/[*?[:alnum:] \\\\]/', $start);
72893 }
72894
72895 foreach (array(array('{', '}'), array('(', ')'), array('[', ']'), array('<', '>')) as $delimiters) {
72896 if ($start === $delimiters[0] && $end === $delimiters[1]) {
72897 return true;
72898 }
72899 }
72900 }
72901
72902 return false;
72903 }
72904
72905
72906
72907
72908
72909
72910
72911
72912 abstract protected function toRegex($str);
72913 }
72914 <?php
72915
72916
72917
72918
72919
72920
72921
72922
72923
72924
72925 namespace Symfony\Component\Finder\Iterator;
72926
72927
72928
72929
72930
72931
72932
72933 class PathFilterIterator extends MultiplePcreFilterIterator
72934 {
72935
72936
72937
72938
72939
72940 public function accept()
72941 {
72942 $filename = $this->current()->getRelativePathname();
72943
72944 if ('\\' === \DIRECTORY_SEPARATOR) {
72945 $filename = str_replace('\\', '/', $filename);
72946 }
72947
72948 return $this->isAccepted($filename);
72949 }
72950
72951
72952
72953
72954
72955
72956
72957
72958
72959
72960
72961
72962
72963
72964
72965 protected function toRegex($str)
72966 {
72967 return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
72968 }
72969 }
72970 <?php
72971
72972
72973
72974
72975
72976
72977
72978
72979
72980
72981 namespace Symfony\Component\Finder\Iterator;
72982
72983 use Symfony\Component\Finder\Exception\AccessDeniedException;
72984 use Symfony\Component\Finder\SplFileInfo;
72985
72986
72987
72988
72989
72990
72991 class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
72992 {
72993
72994
72995
72996 private $ignoreUnreadableDirs;
72997
72998
72999
73000
73001 private $rewindable;
73002
73003
73004 private $rootPath;
73005 private $subPath;
73006 private $directorySeparator = '/';
73007
73008
73009
73010
73011
73012
73013
73014
73015 public function __construct($path, $flags, $ignoreUnreadableDirs = false)
73016 {
73017 if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
73018 throw new \RuntimeException('This iterator only support returning current as fileinfo.');
73019 }
73020
73021 parent::__construct($path, $flags);
73022 $this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
73023 $this->rootPath = (string) $path;
73024 if ('/' !== \DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) {
73025 $this->directorySeparator = \DIRECTORY_SEPARATOR;
73026 }
73027 }
73028
73029
73030
73031
73032
73033
73034 public function current()
73035 {
73036
73037
73038 if (null === $subPathname = $this->subPath) {
73039 $subPathname = $this->subPath = (string) $this->getSubPath();
73040 }
73041 if ('' !== $subPathname) {
73042 $subPathname .= $this->directorySeparator;
73043 }
73044 $subPathname .= $this->getFilename();
73045
73046 return new SplFileInfo($this->rootPath.$this->directorySeparator.$subPathname, $this->subPath, $subPathname);
73047 }
73048
73049
73050
73051
73052
73053
73054 public function getChildren()
73055 {
73056 try {
73057 $children = parent::getChildren();
73058
73059 if ($children instanceof self) {
73060
73061 $children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;
73062
73063
73064 $children->rewindable = &$this->rewindable;
73065 $children->rootPath = $this->rootPath;
73066 }
73067
73068 return $children;
73069 } catch (\UnexpectedValueException $e) {
73070 if ($this->ignoreUnreadableDirs) {
73071
73072 return new \RecursiveArrayIterator(array());
73073 } else {
73074 throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
73075 }
73076 }
73077 }
73078
73079
73080
73081
73082 public function rewind()
73083 {
73084 if (false === $this->isRewindable()) {
73085 return;
73086 }
73087
73088
73089 if (\PHP_VERSION_ID < 50523 || \PHP_VERSION_ID >= 50600 && \PHP_VERSION_ID < 50607) {
73090 parent::next();
73091 }
73092
73093 parent::rewind();
73094 }
73095
73096
73097
73098
73099
73100
73101 public function isRewindable()
73102 {
73103 if (null !== $this->rewindable) {
73104 return $this->rewindable;
73105 }
73106
73107
73108 if ('' === $this->getPath()) {
73109 return $this->rewindable = false;
73110 }
73111
73112 if (false !== $stream = @opendir($this->getPath())) {
73113 $infos = stream_get_meta_data($stream);
73114 closedir($stream);
73115
73116 if ($infos['seekable']) {
73117 return $this->rewindable = true;
73118 }
73119 }
73120
73121 return $this->rewindable = false;
73122 }
73123 }
73124 <?php
73125
73126
73127
73128
73129
73130
73131
73132
73133
73134
73135 namespace Symfony\Component\Finder\Iterator;
73136
73137 use Symfony\Component\Finder\Comparator\NumberComparator;
73138
73139
73140
73141
73142
73143
73144 class SizeRangeFilterIterator extends FilterIterator
73145 {
73146 private $comparators = array();
73147
73148
73149
73150
73151
73152 public function __construct(\Iterator $iterator, array $comparators)
73153 {
73154 $this->comparators = $comparators;
73155
73156 parent::__construct($iterator);
73157 }
73158
73159
73160
73161
73162
73163
73164 public function accept()
73165 {
73166 $fileinfo = $this->current();
73167 if (!$fileinfo->isFile()) {
73168 return true;
73169 }
73170
73171 $filesize = $fileinfo->getSize();
73172 foreach ($this->comparators as $compare) {
73173 if (!$compare->test($filesize)) {
73174 return false;
73175 }
73176 }
73177
73178 return true;
73179 }
73180 }
73181 <?php
73182
73183
73184
73185
73186
73187
73188
73189
73190
73191
73192 namespace Symfony\Component\Finder\Iterator;
73193
73194
73195
73196
73197
73198
73199 class SortableIterator implements \IteratorAggregate
73200 {
73201 const SORT_BY_NAME = 1;
73202 const SORT_BY_TYPE = 2;
73203 const SORT_BY_ACCESSED_TIME = 3;
73204 const SORT_BY_CHANGED_TIME = 4;
73205 const SORT_BY_MODIFIED_TIME = 5;
73206
73207 private $iterator;
73208 private $sort;
73209
73210
73211
73212
73213
73214
73215
73216 public function __construct(\Traversable $iterator, $sort)
73217 {
73218 $this->iterator = $iterator;
73219
73220 if (self::SORT_BY_NAME === $sort) {
73221 $this->sort = function ($a, $b) {
73222 return strcmp($a->getRealpath() ?: $a->getPathname(), $b->getRealpath() ?: $b->getPathname());
73223 };
73224 } elseif (self::SORT_BY_TYPE === $sort) {
73225 $this->sort = function ($a, $b) {
73226 if ($a->isDir() && $b->isFile()) {
73227 return -1;
73228 } elseif ($a->isFile() && $b->isDir()) {
73229 return 1;
73230 }
73231
73232 return strcmp($a->getRealpath() ?: $a->getPathname(), $b->getRealpath() ?: $b->getPathname());
73233 };
73234 } elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
73235 $this->sort = function ($a, $b) {
73236 return $a->getATime() - $b->getATime();
73237 };
73238 } elseif (self::SORT_BY_CHANGED_TIME === $sort) {
73239 $this->sort = function ($a, $b) {
73240 return $a->getCTime() - $b->getCTime();
73241 };
73242 } elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
73243 $this->sort = function ($a, $b) {
73244 return $a->getMTime() - $b->getMTime();
73245 };
73246 } elseif (\is_callable($sort)) {
73247 $this->sort = $sort;
73248 } else {
73249 throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');
73250 }
73251 }
73252
73253 public function getIterator()
73254 {
73255 $array = iterator_to_array($this->iterator, true);
73256 uasort($array, $this->sort);
73257
73258 return new \ArrayIterator($array);
73259 }
73260 }
73261 Copyright (c) 2004-2018 Fabien Potencier
73262
73263 Permission is hereby granted, free of charge, to any person obtaining a copy
73264 of this software and associated documentation files (the "Software"), to deal
73265 in the Software without restriction, including without limitation the rights
73266 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
73267 copies of the Software, and to permit persons to whom the Software is furnished
73268 to do so, subject to the following conditions:
73269
73270 The above copyright notice and this permission notice shall be included in all
73271 copies or substantial portions of the Software.
73272
73273 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
73274 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
73275 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
73276 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
73277 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
73278 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
73279 THE SOFTWARE.
73280 <?php
73281
73282
73283
73284
73285
73286
73287
73288
73289
73290
73291 namespace Symfony\Component\Finder\Shell;
73292
73293 @trigger_error('The '.__NAMESPACE__.'\Command class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
73294
73295
73296
73297
73298
73299
73300 class Command
73301 {
73302 private $parent;
73303 private $bits = array();
73304 private $labels = array();
73305
73306
73307
73308
73309 private $errorHandler;
73310
73311 public function __construct(Command $parent = null)
73312 {
73313 $this->parent = $parent;
73314 }
73315
73316
73317
73318
73319
73320
73321 public function __toString()
73322 {
73323 return $this->join();
73324 }
73325
73326
73327
73328
73329
73330
73331 public static function create(Command $parent = null)
73332 {
73333 return new self($parent);
73334 }
73335
73336
73337
73338
73339
73340
73341
73342
73343 public static function escape($input)
73344 {
73345 return escapeshellcmd($input);
73346 }
73347
73348
73349
73350
73351
73352
73353
73354
73355 public static function quote($input)
73356 {
73357 return escapeshellarg($input);
73358 }
73359
73360
73361
73362
73363
73364
73365
73366
73367 public function add($bit)
73368 {
73369 $this->bits[] = $bit;
73370
73371 return $this;
73372 }
73373
73374
73375
73376
73377
73378
73379
73380
73381 public function top($bit)
73382 {
73383 array_unshift($this->bits, $bit);
73384
73385 foreach ($this->labels as $label => $index) {
73386 ++$this->labels[$label];
73387 }
73388
73389 return $this;
73390 }
73391
73392
73393
73394
73395
73396
73397
73398
73399 public function arg($arg)
73400 {
73401 $this->bits[] = self::quote($arg);
73402
73403 return $this;
73404 }
73405
73406
73407
73408
73409
73410
73411
73412
73413 public function cmd($esc)
73414 {
73415 $this->bits[] = self::escape($esc);
73416
73417 return $this;
73418 }
73419
73420
73421
73422
73423
73424
73425
73426
73427
73428
73429 public function ins($label)
73430 {
73431 if (isset($this->labels[$label])) {
73432 throw new \RuntimeException(sprintf('Label "%s" already exists.', $label));
73433 }
73434
73435 $this->bits[] = self::create($this);
73436 $this->labels[$label] = \count($this->bits) - 1;
73437
73438 return $this->bits[$this->labels[$label]];
73439 }
73440
73441
73442
73443
73444
73445
73446
73447
73448
73449
73450 public function get($label)
73451 {
73452 if (!isset($this->labels[$label])) {
73453 throw new \RuntimeException(sprintf('Label "%s" does not exist.', $label));
73454 }
73455
73456 return $this->bits[$this->labels[$label]];
73457 }
73458
73459
73460
73461
73462
73463
73464
73465
73466 public function end()
73467 {
73468 if (null === $this->parent) {
73469 throw new \RuntimeException('Calling end on root command doesn\'t make sense.');
73470 }
73471
73472 return $this->parent;
73473 }
73474
73475
73476
73477
73478
73479
73480 public function length()
73481 {
73482 return \count($this->bits);
73483 }
73484
73485
73486
73487
73488 public function setErrorHandler(\Closure $errorHandler)
73489 {
73490 $this->errorHandler = $errorHandler;
73491
73492 return $this;
73493 }
73494
73495
73496
73497
73498 public function getErrorHandler()
73499 {
73500 return $this->errorHandler;
73501 }
73502
73503
73504
73505
73506
73507
73508
73509
73510 public function execute()
73511 {
73512 if (null === $errorHandler = $this->errorHandler) {
73513 exec($this->join(), $output);
73514 } else {
73515 $process = proc_open($this->join(), array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $pipes);
73516 $output = preg_split('~(\r\n|\r|\n)~', stream_get_contents($pipes[1]), -1, PREG_SPLIT_NO_EMPTY);
73517
73518 if ($error = stream_get_contents($pipes[2])) {
73519 $errorHandler($error);
73520 }
73521
73522 proc_close($process);
73523 }
73524
73525 return $output ?: array();
73526 }
73527
73528
73529
73530
73531
73532
73533 public function join()
73534 {
73535 return implode(' ', array_filter(
73536 array_map(function ($bit) {
73537 return $bit instanceof Command ? $bit->join() : ($bit ?: null);
73538 }, $this->bits),
73539 function ($bit) { return null !== $bit; }
73540 ));
73541 }
73542
73543
73544
73545
73546
73547
73548
73549
73550
73551 public function addAtIndex($bit, $index)
73552 {
73553 array_splice($this->bits, $index, 0, $bit instanceof self ? array($bit) : $bit);
73554
73555 return $this;
73556 }
73557 }
73558 <?php
73559
73560
73561
73562
73563
73564
73565
73566
73567
73568
73569 namespace Symfony\Component\Finder\Shell;
73570
73571 @trigger_error('The '.__NAMESPACE__.'\Shell class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
73572
73573
73574
73575
73576
73577
73578 class Shell
73579 {
73580 const TYPE_UNIX = 1;
73581 const TYPE_DARWIN = 2;
73582 const TYPE_CYGWIN = 3;
73583 const TYPE_WINDOWS = 4;
73584 const TYPE_BSD = 5;
73585
73586
73587
73588
73589 private $type;
73590
73591
73592
73593
73594
73595
73596 public function getType()
73597 {
73598 if (null === $this->type) {
73599 $this->type = $this->guessType();
73600 }
73601
73602 return $this->type;
73603 }
73604
73605
73606
73607
73608
73609
73610
73611
73612 public function testCommand($command)
73613 {
73614 if (!\function_exists('exec')) {
73615 return false;
73616 }
73617
73618
73619 $testCommand = 'which ';
73620 if (self::TYPE_WINDOWS === $this->type) {
73621 $testCommand = 'where ';
73622 }
73623
73624 $command = escapeshellcmd($command);
73625
73626 exec($testCommand.$command, $output, $code);
73627
73628 return 0 === $code && \count($output) > 0;
73629 }
73630
73631
73632
73633
73634
73635
73636 private function guessType()
73637 {
73638 $os = strtolower(PHP_OS);
73639
73640 if (false !== strpos($os, 'cygwin')) {
73641 return self::TYPE_CYGWIN;
73642 }
73643
73644 if (false !== strpos($os, 'darwin')) {
73645 return self::TYPE_DARWIN;
73646 }
73647
73648 if (false !== strpos($os, 'bsd')) {
73649 return self::TYPE_BSD;
73650 }
73651
73652 if (0 === strpos($os, 'win')) {
73653 return self::TYPE_WINDOWS;
73654 }
73655
73656 return self::TYPE_UNIX;
73657 }
73658 }
73659 <?php
73660
73661
73662
73663
73664
73665
73666
73667
73668
73669
73670 namespace Symfony\Component\Finder;
73671
73672
73673
73674
73675
73676
73677 class SplFileInfo extends \SplFileInfo
73678 {
73679 private $relativePath;
73680 private $relativePathname;
73681
73682
73683
73684
73685
73686
73687 public function __construct($file, $relativePath, $relativePathname)
73688 {
73689 parent::__construct($file);
73690 $this->relativePath = $relativePath;
73691 $this->relativePathname = $relativePathname;
73692 }
73693
73694
73695
73696
73697
73698
73699
73700
73701 public function getRelativePath()
73702 {
73703 return $this->relativePath;
73704 }
73705
73706
73707
73708
73709
73710
73711
73712
73713 public function getRelativePathname()
73714 {
73715 return $this->relativePathname;
73716 }
73717
73718
73719
73720
73721
73722
73723
73724
73725 public function getContents()
73726 {
73727 set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
73728 $content = file_get_contents($this->getPathname());
73729 restore_error_handler();
73730 if (false === $content) {
73731 throw new \RuntimeException($error);
73732 }
73733
73734 return $content;
73735 }
73736 }
73737 <?php
73738
73739
73740
73741
73742
73743
73744
73745
73746
73747
73748 namespace Symfony\Polyfill\Ctype;
73749
73750
73751
73752
73753
73754
73755
73756
73757 final class Ctype
73758 {
73759
73760
73761
73762
73763
73764
73765
73766
73767
73768 public static function ctype_alnum($text)
73769 {
73770 $text = self::convert_int_to_char_for_ctype($text);
73771
73772 return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text);
73773 }
73774
73775
73776
73777
73778
73779
73780
73781
73782
73783
73784 public static function ctype_alpha($text)
73785 {
73786 $text = self::convert_int_to_char_for_ctype($text);
73787
73788 return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text);
73789 }
73790
73791
73792
73793
73794
73795
73796
73797
73798
73799
73800 public static function ctype_cntrl($text)
73801 {
73802 $text = self::convert_int_to_char_for_ctype($text);
73803
73804 return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text);
73805 }
73806
73807
73808
73809
73810
73811
73812
73813
73814
73815
73816 public static function ctype_digit($text)
73817 {
73818 $text = self::convert_int_to_char_for_ctype($text);
73819
73820 return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text);
73821 }
73822
73823
73824
73825
73826
73827
73828
73829
73830
73831
73832 public static function ctype_graph($text)
73833 {
73834 $text = self::convert_int_to_char_for_ctype($text);
73835
73836 return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text);
73837 }
73838
73839
73840
73841
73842
73843
73844
73845
73846
73847
73848 public static function ctype_lower($text)
73849 {
73850 $text = self::convert_int_to_char_for_ctype($text);
73851
73852 return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text);
73853 }
73854
73855
73856
73857
73858
73859
73860
73861
73862
73863
73864 public static function ctype_print($text)
73865 {
73866 $text = self::convert_int_to_char_for_ctype($text);
73867
73868 return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text);
73869 }
73870
73871
73872
73873
73874
73875
73876
73877
73878
73879
73880 public static function ctype_punct($text)
73881 {
73882 $text = self::convert_int_to_char_for_ctype($text);
73883
73884 return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text);
73885 }
73886
73887
73888
73889
73890
73891
73892
73893
73894
73895
73896 public static function ctype_space($text)
73897 {
73898 $text = self::convert_int_to_char_for_ctype($text);
73899
73900 return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text);
73901 }
73902
73903
73904
73905
73906
73907
73908
73909
73910
73911
73912 public static function ctype_upper($text)
73913 {
73914 $text = self::convert_int_to_char_for_ctype($text);
73915
73916 return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text);
73917 }
73918
73919
73920
73921
73922
73923
73924
73925
73926
73927
73928 public static function ctype_xdigit($text)
73929 {
73930 $text = self::convert_int_to_char_for_ctype($text);
73931
73932 return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text);
73933 }
73934
73935
73936
73937
73938
73939
73940
73941
73942
73943
73944
73945
73946
73947 private static function convert_int_to_char_for_ctype($int)
73948 {
73949 if (!\is_int($int)) {
73950 return $int;
73951 }
73952
73953 if ($int < -128 || $int > 255) {
73954 return (string) $int;
73955 }
73956
73957 if ($int < 0) {
73958 $int += 256;
73959 }
73960
73961 return \chr($int);
73962 }
73963 }
73964 Copyright (c) 2018-2019 Fabien Potencier
73965
73966 Permission is hereby granted, free of charge, to any person obtaining a copy
73967 of this software and associated documentation files (the "Software"), to deal
73968 in the Software without restriction, including without limitation the rights
73969 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
73970 copies of the Software, and to permit persons to whom the Software is furnished
73971 to do so, subject to the following conditions:
73972
73973 The above copyright notice and this permission notice shall be included in all
73974 copies or substantial portions of the Software.
73975
73976 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
73977 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
73978 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
73979 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
73980 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
73981 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
73982 THE SOFTWARE.
73983 <?php
73984
73985
73986
73987
73988
73989
73990
73991
73992
73993
73994 use Symfony\Polyfill\Ctype as p;
73995
73996 if (!function_exists('ctype_alnum')) {
73997 function ctype_alnum($input) { return p\Ctype::ctype_alnum($input); }
73998 }
73999 if (!function_exists('ctype_alpha')) {
74000 function ctype_alpha($input) { return p\Ctype::ctype_alpha($input); }
74001 }
74002 if (!function_exists('ctype_cntrl')) {
74003 function ctype_cntrl($input) { return p\Ctype::ctype_cntrl($input); }
74004 }
74005 if (!function_exists('ctype_digit')) {
74006 function ctype_digit($input) { return p\Ctype::ctype_digit($input); }
74007 }
74008 if (!function_exists('ctype_graph')) {
74009 function ctype_graph($input) { return p\Ctype::ctype_graph($input); }
74010 }
74011 if (!function_exists('ctype_lower')) {
74012 function ctype_lower($input) { return p\Ctype::ctype_lower($input); }
74013 }
74014 if (!function_exists('ctype_print')) {
74015 function ctype_print($input) { return p\Ctype::ctype_print($input); }
74016 }
74017 if (!function_exists('ctype_punct')) {
74018 function ctype_punct($input) { return p\Ctype::ctype_punct($input); }
74019 }
74020 if (!function_exists('ctype_space')) {
74021 function ctype_space($input) { return p\Ctype::ctype_space($input); }
74022 }
74023 if (!function_exists('ctype_upper')) {
74024 function ctype_upper($input) { return p\Ctype::ctype_upper($input); }
74025 }
74026 if (!function_exists('ctype_xdigit')) {
74027 function ctype_xdigit($input) { return p\Ctype::ctype_xdigit($input); }
74028 }
74029 Copyright (c) 2015-2019 Fabien Potencier
74030
74031 Permission is hereby granted, free of charge, to any person obtaining a copy
74032 of this software and associated documentation files (the "Software"), to deal
74033 in the Software without restriction, including without limitation the rights
74034 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
74035 copies of the Software, and to permit persons to whom the Software is furnished
74036 to do so, subject to the following conditions:
74037
74038 The above copyright notice and this permission notice shall be included in all
74039 copies or substantial portions of the Software.
74040
74041 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
74042 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
74043 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
74044 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
74045 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
74046 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
74047 THE SOFTWARE.
74048 <?php
74049
74050
74051
74052
74053
74054
74055
74056
74057
74058
74059 namespace Symfony\Polyfill\Mbstring;
74060
74061
74062
74063
74064
74065
74066
74067
74068
74069
74070
74071
74072
74073
74074
74075
74076
74077
74078
74079
74080
74081
74082
74083
74084
74085
74086
74087
74088
74089
74090
74091
74092
74093
74094
74095
74096
74097
74098
74099
74100
74101
74102
74103
74104
74105
74106
74107
74108
74109
74110
74111
74112
74113
74114
74115 final class Mbstring
74116 {
74117 const MB_CASE_FOLD = PHP_INT_MAX;
74118
74119 private static $encodingList = array('ASCII', 'UTF-8');
74120 private static $language = 'neutral';
74121 private static $internalEncoding = 'UTF-8';
74122 private static $caseFold = array(
74123 array('µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"),
74124 array('μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'),
74125 );
74126
74127 public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
74128 {
74129 if (\is_array($fromEncoding) || false !== strpos($fromEncoding, ',')) {
74130 $fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
74131 } else {
74132 $fromEncoding = self::getEncoding($fromEncoding);
74133 }
74134
74135 $toEncoding = self::getEncoding($toEncoding);
74136
74137 if ('BASE64' === $fromEncoding) {
74138 $s = base64_decode($s);
74139 $fromEncoding = $toEncoding;
74140 }
74141
74142 if ('BASE64' === $toEncoding) {
74143 return base64_encode($s);
74144 }
74145
74146 if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {
74147 if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {
74148 $fromEncoding = 'Windows-1252';
74149 }
74150 if ('UTF-8' !== $fromEncoding) {
74151 $s = iconv($fromEncoding, 'UTF-8//IGNORE', $s);
74152 }
74153
74154 return preg_replace_callback('/[\x80-\xFF]+/', array(__CLASS__, 'html_encoding_callback'), $s);
74155 }
74156
74157 if ('HTML-ENTITIES' === $fromEncoding) {
74158 $s = html_entity_decode($s, ENT_COMPAT, 'UTF-8');
74159 $fromEncoding = 'UTF-8';
74160 }
74161
74162 return iconv($fromEncoding, $toEncoding.'//IGNORE', $s);
74163 }
74164
74165 public static function mb_convert_variables($toEncoding, $fromEncoding, &$a = null, &$b = null, &$c = null, &$d = null, &$e = null, &$f = null)
74166 {
74167 $vars = array(&$a, &$b, &$c, &$d, &$e, &$f);
74168
74169 $ok = true;
74170 array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
74171 if (false === $v = Mbstring::mb_convert_encoding($v, $toEncoding, $fromEncoding)) {
74172 $ok = false;
74173 }
74174 });
74175
74176 return $ok ? $fromEncoding : false;
74177 }
74178
74179 public static function mb_decode_mimeheader($s)
74180 {
74181 return iconv_mime_decode($s, 2, self::$internalEncoding);
74182 }
74183
74184 public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)
74185 {
74186 trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', E_USER_WARNING);
74187 }
74188
74189 public static function mb_decode_numericentity($s, $convmap, $encoding = null)
74190 {
74191 if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) {
74192 trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', E_USER_WARNING);
74193
74194 return null;
74195 }
74196
74197 if (!\is_array($convmap) || !$convmap) {
74198 return false;
74199 }
74200
74201 if (null !== $encoding && !\is_scalar($encoding)) {
74202 trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', E_USER_WARNING);
74203
74204 return ''; 
74205 }
74206
74207 $s = (string) $s;
74208 if ('' === $s) {
74209 return '';
74210 }
74211
74212 $encoding = self::getEncoding($encoding);
74213
74214 if ('UTF-8' === $encoding) {
74215 $encoding = null;
74216 if (!preg_match('//u', $s)) {
74217 $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
74218 }
74219 } else {
74220 $s = iconv($encoding, 'UTF-8//IGNORE', $s);
74221 }
74222
74223 $cnt = floor(\count($convmap) / 4) * 4;
74224
74225 for ($i = 0; $i < $cnt; $i += 4) {
74226
74227 $convmap[$i] += $convmap[$i + 2];
74228 $convmap[$i + 1] += $convmap[$i + 2];
74229 }
74230
74231 $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) {
74232 $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];
74233 for ($i = 0; $i < $cnt; $i += 4) {
74234 if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
74235 return Mbstring::mb_chr($c - $convmap[$i + 2]);
74236 }
74237 }
74238
74239 return $m[0];
74240 }, $s);
74241
74242 if (null === $encoding) {
74243 return $s;
74244 }
74245
74246 return iconv('UTF-8', $encoding.'//IGNORE', $s);
74247 }
74248
74249 public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)
74250 {
74251 if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) {
74252 trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', E_USER_WARNING);
74253
74254 return null;
74255 }
74256
74257 if (!\is_array($convmap) || !$convmap) {
74258 return false;
74259 }
74260
74261 if (null !== $encoding && !\is_scalar($encoding)) {
74262 trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', E_USER_WARNING);
74263
74264 return null; 
74265 }
74266
74267 if (null !== $is_hex && !\is_scalar($is_hex)) {
74268 trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', E_USER_WARNING);
74269
74270 return null;
74271 }
74272
74273 $s = (string) $s;
74274 if ('' === $s) {
74275 return '';
74276 }
74277
74278 $encoding = self::getEncoding($encoding);
74279
74280 if ('UTF-8' === $encoding) {
74281 $encoding = null;
74282 if (!preg_match('//u', $s)) {
74283 $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
74284 }
74285 } else {
74286 $s = iconv($encoding, 'UTF-8//IGNORE', $s);
74287 }
74288
74289 static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
74290
74291 $cnt = floor(\count($convmap) / 4) * 4;
74292 $i = 0;
74293 $len = \strlen($s);
74294 $result = '';
74295
74296 while ($i < $len) {
74297 $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
74298 $uchr = substr($s, $i, $ulen);
74299 $i += $ulen;
74300 $c = self::mb_ord($uchr);
74301
74302 for ($j = 0; $j < $cnt; $j += 4) {
74303 if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
74304 $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];
74305 $result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
74306 continue 2;
74307 }
74308 }
74309 $result .= $uchr;
74310 }
74311
74312 if (null === $encoding) {
74313 return $result;
74314 }
74315
74316 return iconv('UTF-8', $encoding.'//IGNORE', $result);
74317 }
74318
74319 public static function mb_convert_case($s, $mode, $encoding = null)
74320 {
74321 $s = (string) $s;
74322 if ('' === $s) {
74323 return '';
74324 }
74325
74326 $encoding = self::getEncoding($encoding);
74327
74328 if ('UTF-8' === $encoding) {
74329 $encoding = null;
74330 if (!preg_match('//u', $s)) {
74331 $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
74332 }
74333 } else {
74334 $s = iconv($encoding, 'UTF-8//IGNORE', $s);
74335 }
74336
74337 if (MB_CASE_TITLE == $mode) {
74338 static $titleRegexp = null;
74339 if (null === $titleRegexp) {
74340 $titleRegexp = self::getData('titleCaseRegexp');
74341 }
74342 $s = preg_replace_callback($titleRegexp, array(__CLASS__, 'title_case'), $s);
74343 } else {
74344 if (MB_CASE_UPPER == $mode) {
74345 static $upper = null;
74346 if (null === $upper) {
74347 $upper = self::getData('upperCase');
74348 }
74349 $map = $upper;
74350 } else {
74351 if (self::MB_CASE_FOLD === $mode) {
74352 $s = str_replace(self::$caseFold[0], self::$caseFold[1], $s);
74353 }
74354
74355 static $lower = null;
74356 if (null === $lower) {
74357 $lower = self::getData('lowerCase');
74358 }
74359 $map = $lower;
74360 }
74361
74362 static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
74363
74364 $i = 0;
74365 $len = \strlen($s);
74366
74367 while ($i < $len) {
74368 $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
74369 $uchr = substr($s, $i, $ulen);
74370 $i += $ulen;
74371
74372 if (isset($map[$uchr])) {
74373 $uchr = $map[$uchr];
74374 $nlen = \strlen($uchr);
74375
74376 if ($nlen == $ulen) {
74377 $nlen = $i;
74378 do {
74379 $s[--$nlen] = $uchr[--$ulen];
74380 } while ($ulen);
74381 } else {
74382 $s = substr_replace($s, $uchr, $i - $ulen, $ulen);
74383 $len += $nlen - $ulen;
74384 $i += $nlen - $ulen;
74385 }
74386 }
74387 }
74388 }
74389
74390 if (null === $encoding) {
74391 return $s;
74392 }
74393
74394 return iconv('UTF-8', $encoding.'//IGNORE', $s);
74395 }
74396
74397 public static function mb_internal_encoding($encoding = null)
74398 {
74399 if (null === $encoding) {
74400 return self::$internalEncoding;
74401 }
74402
74403 $encoding = self::getEncoding($encoding);
74404
74405 if ('UTF-8' === $encoding || false !== @iconv($encoding, $encoding, ' ')) {
74406 self::$internalEncoding = $encoding;
74407
74408 return true;
74409 }
74410
74411 return false;
74412 }
74413
74414 public static function mb_language($lang = null)
74415 {
74416 if (null === $lang) {
74417 return self::$language;
74418 }
74419
74420 switch ($lang = strtolower($lang)) {
74421 case 'uni':
74422 case 'neutral':
74423 self::$language = $lang;
74424
74425 return true;
74426 }
74427
74428 return false;
74429 }
74430
74431 public static function mb_list_encodings()
74432 {
74433 return array('UTF-8');
74434 }
74435
74436 public static function mb_encoding_aliases($encoding)
74437 {
74438 switch (strtoupper($encoding)) {
74439 case 'UTF8':
74440 case 'UTF-8':
74441 return array('utf8');
74442 }
74443
74444 return false;
74445 }
74446
74447 public static function mb_check_encoding($var = null, $encoding = null)
74448 {
74449 if (null === $encoding) {
74450 if (null === $var) {
74451 return false;
74452 }
74453 $encoding = self::$internalEncoding;
74454 }
74455
74456 return self::mb_detect_encoding($var, array($encoding)) || false !== @iconv($encoding, $encoding, $var);
74457 }
74458
74459 public static function mb_detect_encoding($str, $encodingList = null, $strict = false)
74460 {
74461 if (null === $encodingList) {
74462 $encodingList = self::$encodingList;
74463 } else {
74464 if (!\is_array($encodingList)) {
74465 $encodingList = array_map('trim', explode(',', $encodingList));
74466 }
74467 $encodingList = array_map('strtoupper', $encodingList);
74468 }
74469
74470 foreach ($encodingList as $enc) {
74471 switch ($enc) {
74472 case 'ASCII':
74473 if (!preg_match('/[\x80-\xFF]/', $str)) {
74474 return $enc;
74475 }
74476 break;
74477
74478 case 'UTF8':
74479 case 'UTF-8':
74480 if (preg_match('//u', $str)) {
74481 return 'UTF-8';
74482 }
74483 break;
74484
74485 default:
74486 if (0 === strncmp($enc, 'ISO-8859-', 9)) {
74487 return $enc;
74488 }
74489 }
74490 }
74491
74492 return false;
74493 }
74494
74495 public static function mb_detect_order($encodingList = null)
74496 {
74497 if (null === $encodingList) {
74498 return self::$encodingList;
74499 }
74500
74501 if (!\is_array($encodingList)) {
74502 $encodingList = array_map('trim', explode(',', $encodingList));
74503 }
74504 $encodingList = array_map('strtoupper', $encodingList);
74505
74506 foreach ($encodingList as $enc) {
74507 switch ($enc) {
74508 default:
74509 if (strncmp($enc, 'ISO-8859-', 9)) {
74510 return false;
74511 }
74512
74513 case 'ASCII':
74514 case 'UTF8':
74515 case 'UTF-8':
74516 }
74517 }
74518
74519 self::$encodingList = $encodingList;
74520
74521 return true;
74522 }
74523
74524 public static function mb_strlen($s, $encoding = null)
74525 {
74526 $encoding = self::getEncoding($encoding);
74527 if ('CP850' === $encoding || 'ASCII' === $encoding) {
74528 return \strlen($s);
74529 }
74530
74531 return @iconv_strlen($s, $encoding);
74532 }
74533
74534 public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
74535 {
74536 $encoding = self::getEncoding($encoding);
74537 if ('CP850' === $encoding || 'ASCII' === $encoding) {
74538 return strpos($haystack, $needle, $offset);
74539 }
74540
74541 $needle = (string) $needle;
74542 if ('' === $needle) {
74543 trigger_error(__METHOD__.': Empty delimiter', E_USER_WARNING);
74544
74545 return false;
74546 }
74547
74548 return iconv_strpos($haystack, $needle, $offset, $encoding);
74549 }
74550
74551 public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
74552 {
74553 $encoding = self::getEncoding($encoding);
74554 if ('CP850' === $encoding || 'ASCII' === $encoding) {
74555 return strrpos($haystack, $needle, $offset);
74556 }
74557
74558 if ($offset != (int) $offset) {
74559 $offset = 0;
74560 } elseif ($offset = (int) $offset) {
74561 if ($offset < 0) {
74562 if (0 > $offset += self::mb_strlen($needle)) {
74563 $haystack = self::mb_substr($haystack, 0, $offset, $encoding);
74564 }
74565 $offset = 0;
74566 } else {
74567 $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
74568 }
74569 }
74570
74571 $pos = iconv_strrpos($haystack, $needle, $encoding);
74572
74573 return false !== $pos ? $offset + $pos : false;
74574 }
74575
74576 public static function mb_str_split($string, $split_length = 1, $encoding = null)
74577 {
74578 if (null !== $string && !\is_scalar($string) && !(\is_object($string) && \method_exists($string, '__toString'))) {
74579 trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', E_USER_WARNING);
74580
74581 return null;
74582 }
74583
74584 if (1 > $split_length = (int) $split_length) {
74585 trigger_error('The length of each segment must be greater than zero', E_USER_WARNING);
74586
74587 return false;
74588 }
74589
74590 if (null === $encoding) {
74591 $encoding = mb_internal_encoding();
74592 }
74593
74594 if ('UTF-8' === $encoding = self::getEncoding($encoding)) {
74595 $rx = '/(';
74596 while (65535 < $split_length) {
74597 $rx .= '.{65535}';
74598 $split_length -= 65535;
74599 }
74600 $rx .= '.{'.$split_length.'})/us';
74601
74602 return preg_split($rx, $string, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
74603 }
74604
74605 $result = array();
74606 $length = mb_strlen($string, $encoding);
74607
74608 for ($i = 0; $i < $length; $i += $split_length) {
74609 $result[] = mb_substr($string, $i, $split_length, $encoding);
74610 }
74611
74612 return $result;
74613 }
74614
74615 public static function mb_strtolower($s, $encoding = null)
74616 {
74617 return self::mb_convert_case($s, MB_CASE_LOWER, $encoding);
74618 }
74619
74620 public static function mb_strtoupper($s, $encoding = null)
74621 {
74622 return self::mb_convert_case($s, MB_CASE_UPPER, $encoding);
74623 }
74624
74625 public static function mb_substitute_character($c = null)
74626 {
74627 if (0 === strcasecmp($c, 'none')) {
74628 return true;
74629 }
74630
74631 return null !== $c ? false : 'none';
74632 }
74633
74634 public static function mb_substr($s, $start, $length = null, $encoding = null)
74635 {
74636 $encoding = self::getEncoding($encoding);
74637 if ('CP850' === $encoding || 'ASCII' === $encoding) {
74638 return (string) substr($s, $start, null === $length ? 2147483647 : $length);
74639 }
74640
74641 if ($start < 0) {
74642 $start = iconv_strlen($s, $encoding) + $start;
74643 if ($start < 0) {
74644 $start = 0;
74645 }
74646 }
74647
74648 if (null === $length) {
74649 $length = 2147483647;
74650 } elseif ($length < 0) {
74651 $length = iconv_strlen($s, $encoding) + $length - $start;
74652 if ($length < 0) {
74653 return '';
74654 }
74655 }
74656
74657 return (string) iconv_substr($s, $start, $length, $encoding);
74658 }
74659
74660 public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
74661 {
74662 $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
74663 $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
74664
74665 return self::mb_strpos($haystack, $needle, $offset, $encoding);
74666 }
74667
74668 public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)
74669 {
74670 $pos = self::mb_stripos($haystack, $needle, 0, $encoding);
74671
74672 return self::getSubpart($pos, $part, $haystack, $encoding);
74673 }
74674
74675 public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)
74676 {
74677 $encoding = self::getEncoding($encoding);
74678 if ('CP850' === $encoding || 'ASCII' === $encoding) {
74679 $pos = strrpos($haystack, $needle);
74680 } else {
74681 $needle = self::mb_substr($needle, 0, 1, $encoding);
74682 $pos = iconv_strrpos($haystack, $needle, $encoding);
74683 }
74684
74685 return self::getSubpart($pos, $part, $haystack, $encoding);
74686 }
74687
74688 public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
74689 {
74690 $needle = self::mb_substr($needle, 0, 1, $encoding);
74691 $pos = self::mb_strripos($haystack, $needle, $encoding);
74692
74693 return self::getSubpart($pos, $part, $haystack, $encoding);
74694 }
74695
74696 public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
74697 {
74698 $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
74699 $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
74700
74701 return self::mb_strrpos($haystack, $needle, $offset, $encoding);
74702 }
74703
74704 public static function mb_strstr($haystack, $needle, $part = false, $encoding = null)
74705 {
74706 $pos = strpos($haystack, $needle);
74707 if (false === $pos) {
74708 return false;
74709 }
74710 if ($part) {
74711 return substr($haystack, 0, $pos);
74712 }
74713
74714 return substr($haystack, $pos);
74715 }
74716
74717 public static function mb_get_info($type = 'all')
74718 {
74719 $info = array(
74720 'internal_encoding' => self::$internalEncoding,
74721 'http_output' => 'pass',
74722 'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)',
74723 'func_overload' => 0,
74724 'func_overload_list' => 'no overload',
74725 'mail_charset' => 'UTF-8',
74726 'mail_header_encoding' => 'BASE64',
74727 'mail_body_encoding' => 'BASE64',
74728 'illegal_chars' => 0,
74729 'encoding_translation' => 'Off',
74730 'language' => self::$language,
74731 'detect_order' => self::$encodingList,
74732 'substitute_character' => 'none',
74733 'strict_detection' => 'Off',
74734 );
74735
74736 if ('all' === $type) {
74737 return $info;
74738 }
74739 if (isset($info[$type])) {
74740 return $info[$type];
74741 }
74742
74743 return false;
74744 }
74745
74746 public static function mb_http_input($type = '')
74747 {
74748 return false;
74749 }
74750
74751 public static function mb_http_output($encoding = null)
74752 {
74753 return null !== $encoding ? 'pass' === $encoding : 'pass';
74754 }
74755
74756 public static function mb_strwidth($s, $encoding = null)
74757 {
74758 $encoding = self::getEncoding($encoding);
74759
74760 if ('UTF-8' !== $encoding) {
74761 $s = iconv($encoding, 'UTF-8//IGNORE', $s);
74762 }
74763
74764 $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);
74765
74766 return ($wide << 1) + iconv_strlen($s, 'UTF-8');
74767 }
74768
74769 public static function mb_substr_count($haystack, $needle, $encoding = null)
74770 {
74771 return substr_count($haystack, $needle);
74772 }
74773
74774 public static function mb_output_handler($contents, $status)
74775 {
74776 return $contents;
74777 }
74778
74779 public static function mb_chr($code, $encoding = null)
74780 {
74781 if (0x80 > $code %= 0x200000) {
74782 $s = \chr($code);
74783 } elseif (0x800 > $code) {
74784 $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
74785 } elseif (0x10000 > $code) {
74786 $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
74787 } else {
74788 $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
74789 }
74790
74791 if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
74792 $s = mb_convert_encoding($s, $encoding, 'UTF-8');
74793 }
74794
74795 return $s;
74796 }
74797
74798 public static function mb_ord($s, $encoding = null)
74799 {
74800 if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
74801 $s = mb_convert_encoding($s, 'UTF-8', $encoding);
74802 }
74803
74804 if (1 === \strlen($s)) {
74805 return \ord($s);
74806 }
74807
74808 $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
74809 if (0xF0 <= $code) {
74810 return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
74811 }
74812 if (0xE0 <= $code) {
74813 return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
74814 }
74815 if (0xC0 <= $code) {
74816 return (($code - 0xC0) << 6) + $s[2] - 0x80;
74817 }
74818
74819 return $code;
74820 }
74821
74822 private static function getSubpart($pos, $part, $haystack, $encoding)
74823 {
74824 if (false === $pos) {
74825 return false;
74826 }
74827 if ($part) {
74828 return self::mb_substr($haystack, 0, $pos, $encoding);
74829 }
74830
74831 return self::mb_substr($haystack, $pos, null, $encoding);
74832 }
74833
74834 private static function html_encoding_callback(array $m)
74835 {
74836 $i = 1;
74837 $entities = '';
74838 $m = unpack('C*', htmlentities($m[0], ENT_COMPAT, 'UTF-8'));
74839
74840 while (isset($m[$i])) {
74841 if (0x80 > $m[$i]) {
74842 $entities .= \chr($m[$i++]);
74843 continue;
74844 }
74845 if (0xF0 <= $m[$i]) {
74846 $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
74847 } elseif (0xE0 <= $m[$i]) {
74848 $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
74849 } else {
74850 $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
74851 }
74852
74853 $entities .= '&#'.$c.';';
74854 }
74855
74856 return $entities;
74857 }
74858
74859 private static function title_case(array $s)
74860 {
74861 return self::mb_convert_case($s[1], MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], MB_CASE_LOWER, 'UTF-8');
74862 }
74863
74864 private static function getData($file)
74865 {
74866 if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
74867 return require $file;
74868 }
74869
74870 return false;
74871 }
74872
74873 private static function getEncoding($encoding)
74874 {
74875 if (null === $encoding) {
74876 return self::$internalEncoding;
74877 }
74878
74879 if ('UTF-8' === $encoding) {
74880 return 'UTF-8';
74881 }
74882
74883 $encoding = strtoupper($encoding);
74884
74885 if ('8BIT' === $encoding || 'BINARY' === $encoding) {
74886 return 'CP850';
74887 }
74888
74889 if ('UTF8' === $encoding) {
74890 return 'UTF-8';
74891 }
74892
74893 return $encoding;
74894 }
74895 }
74896 <?php
74897
74898 return array (
74899 'A' => 'a',
74900 'B' => 'b',
74901 'C' => 'c',
74902 'D' => 'd',
74903 'E' => 'e',
74904 'F' => 'f',
74905 'G' => 'g',
74906 'H' => 'h',
74907 'I' => 'i',
74908 'J' => 'j',
74909 'K' => 'k',
74910 'L' => 'l',
74911 'M' => 'm',
74912 'N' => 'n',
74913 'O' => 'o',
74914 'P' => 'p',
74915 'Q' => 'q',
74916 'R' => 'r',
74917 'S' => 's',
74918 'T' => 't',
74919 'U' => 'u',
74920 'V' => 'v',
74921 'W' => 'w',
74922 'X' => 'x',
74923 'Y' => 'y',
74924 'Z' => 'z',
74925 'À' => 'à',
74926 'Á' => 'á',
74927 'Â' => 'â',
74928 'Ã' => 'ã',
74929 'Ä' => 'ä',
74930 'Å' => 'å',
74931 'Æ' => 'æ',
74932 'Ç' => 'ç',
74933 'È' => 'è',
74934 'É' => 'é',
74935 'Ê' => 'ê',
74936 'Ë' => 'ë',
74937 'Ì' => 'ì',
74938 'Í' => 'í',
74939 'Î' => 'î',
74940 'Ï' => 'ï',
74941 'Ð' => 'ð',
74942 'Ñ' => 'ñ',
74943 'Ò' => 'ò',
74944 'Ó' => 'ó',
74945 'Ô' => 'ô',
74946 'Õ' => 'õ',
74947 'Ö' => 'ö',
74948 'Ø' => 'ø',
74949 'Ù' => 'ù',
74950 'Ú' => 'ú',
74951 'Û' => 'û',
74952 'Ü' => 'ü',
74953 'Ý' => 'ý',
74954 'Þ' => 'þ',
74955 'Ā' => 'ā',
74956 'Ă' => 'ă',
74957 'Ą' => 'ą',
74958 'Ć' => 'ć',
74959 'Ĉ' => 'ĉ',
74960 'Ċ' => 'ċ',
74961 'Č' => 'č',
74962 'Ď' => 'ď',
74963 'Đ' => 'đ',
74964 'Ē' => 'ē',
74965 'Ĕ' => 'ĕ',
74966 'Ė' => 'ė',
74967 'Ę' => 'ę',
74968 'Ě' => 'ě',
74969 'Ĝ' => 'ĝ',
74970 'Ğ' => 'ğ',
74971 'Ġ' => 'ġ',
74972 'Ģ' => 'ģ',
74973 'Ĥ' => 'ĥ',
74974 'Ħ' => 'ħ',
74975 'Ĩ' => 'ĩ',
74976 'Ī' => 'ī',
74977 'Ĭ' => 'ĭ',
74978 'Į' => 'į',
74979 'İ' => 'i',
74980 'IJ' => 'ij',
74981 'Ĵ' => 'ĵ',
74982 'Ķ' => 'ķ',
74983 'Ĺ' => 'ĺ',
74984 'Ļ' => 'ļ',
74985 'Ľ' => 'ľ',
74986 'Ŀ' => 'ŀ',
74987 'Ł' => 'ł',
74988 'Ń' => 'ń',
74989 'Ņ' => 'ņ',
74990 'Ň' => 'ň',
74991 'Ŋ' => 'ŋ',
74992 'Ō' => 'ō',
74993 'Ŏ' => 'ŏ',
74994 'Ő' => 'ő',
74995 'Œ' => 'œ',
74996 'Ŕ' => 'ŕ',
74997 'Ŗ' => 'ŗ',
74998 'Ř' => 'ř',
74999 'Ś' => 'ś',
75000 'Ŝ' => 'ŝ',
75001 'Ş' => 'ş',
75002 'Š' => 'š',
75003 'Ţ' => 'ţ',
75004 'Ť' => 'ť',
75005 'Ŧ' => 'ŧ',
75006 'Ũ' => 'ũ',
75007 'Ū' => 'ū',
75008 'Ŭ' => 'ŭ',
75009 'Ů' => 'ů',
75010 'Ű' => 'ű',
75011 'Ų' => 'ų',
75012 'Ŵ' => 'ŵ',
75013 'Ŷ' => 'ŷ',
75014 'Ÿ' => 'ÿ',
75015 'Ź' => 'ź',
75016 'Ż' => 'ż',
75017 'Ž' => 'ž',
75018 'Ɓ' => 'ɓ',
75019 'Ƃ' => 'ƃ',
75020 'Ƅ' => 'ƅ',
75021 'Ɔ' => 'ɔ',
75022 'Ƈ' => 'ƈ',
75023 'Ɖ' => 'ɖ',
75024 'Ɗ' => 'ɗ',
75025 'Ƌ' => 'ƌ',
75026 'Ǝ' => 'ǝ',
75027 'Ə' => 'ə',
75028 'Ɛ' => 'ɛ',
75029 'Ƒ' => 'ƒ',
75030 'Ɠ' => 'ɠ',
75031 'Ɣ' => 'ɣ',
75032 'Ɩ' => 'ɩ',
75033 'Ɨ' => 'ɨ',
75034 'Ƙ' => 'ƙ',
75035 'Ɯ' => 'ɯ',
75036 'Ɲ' => 'ɲ',
75037 'Ɵ' => 'ɵ',
75038 'Ơ' => 'ơ',
75039 'Ƣ' => 'ƣ',
75040 'Ƥ' => 'ƥ',
75041 'Ʀ' => 'ʀ',
75042 'Ƨ' => 'ƨ',
75043 'Ʃ' => 'ʃ',
75044 'Ƭ' => 'ƭ',
75045 'Ʈ' => 'ʈ',
75046 'Ư' => 'ư',
75047 'Ʊ' => 'ʊ',
75048 'Ʋ' => 'ʋ',
75049 'Ƴ' => 'ƴ',
75050 'Ƶ' => 'ƶ',
75051 'Ʒ' => 'ʒ',
75052 'Ƹ' => 'ƹ',
75053 'Ƽ' => 'ƽ',
75054 'DŽ' => 'dž',
75055 'Dž' => 'dž',
75056 'LJ' => 'lj',
75057 'Lj' => 'lj',
75058 'NJ' => 'nj',
75059 'Nj' => 'nj',
75060 'Ǎ' => 'ǎ',
75061 'Ǐ' => 'ǐ',
75062 'Ǒ' => 'ǒ',
75063 'Ǔ' => 'ǔ',
75064 'Ǖ' => 'ǖ',
75065 'Ǘ' => 'ǘ',
75066 'Ǚ' => 'ǚ',
75067 'Ǜ' => 'ǜ',
75068 'Ǟ' => 'ǟ',
75069 'Ǡ' => 'ǡ',
75070 'Ǣ' => 'ǣ',
75071 'Ǥ' => 'ǥ',
75072 'Ǧ' => 'ǧ',
75073 'Ǩ' => 'ǩ',
75074 'Ǫ' => 'ǫ',
75075 'Ǭ' => 'ǭ',
75076 'Ǯ' => 'ǯ',
75077 'DZ' => 'dz',
75078 'Dz' => 'dz',
75079 'Ǵ' => 'ǵ',
75080 'Ƕ' => 'ƕ',
75081 'Ƿ' => 'ƿ',
75082 'Ǹ' => 'ǹ',
75083 'Ǻ' => 'ǻ',
75084 'Ǽ' => 'ǽ',
75085 'Ǿ' => 'ǿ',
75086 'Ȁ' => 'ȁ',
75087 'Ȃ' => 'ȃ',
75088 'Ȅ' => 'ȅ',
75089 'Ȇ' => 'ȇ',
75090 'Ȉ' => 'ȉ',
75091 'Ȋ' => 'ȋ',
75092 'Ȍ' => 'ȍ',
75093 'Ȏ' => 'ȏ',
75094 'Ȑ' => 'ȑ',
75095 'Ȓ' => 'ȓ',
75096 'Ȕ' => 'ȕ',
75097 'Ȗ' => 'ȗ',
75098 'Ș' => 'ș',
75099 'Ț' => 'ț',
75100 'Ȝ' => 'ȝ',
75101 'Ȟ' => 'ȟ',
75102 'Ƞ' => 'ƞ',
75103 'Ȣ' => 'ȣ',
75104 'Ȥ' => 'ȥ',
75105 'Ȧ' => 'ȧ',
75106 'Ȩ' => 'ȩ',
75107 'Ȫ' => 'ȫ',
75108 'Ȭ' => 'ȭ',
75109 'Ȯ' => 'ȯ',
75110 'Ȱ' => 'ȱ',
75111 'Ȳ' => 'ȳ',
75112 'Ⱥ' => 'ⱥ',
75113 'Ȼ' => 'ȼ',
75114 'Ƚ' => 'ƚ',
75115 'Ⱦ' => 'ⱦ',
75116 'Ɂ' => 'ɂ',
75117 'Ƀ' => 'ƀ',
75118 'Ʉ' => 'ʉ',
75119 'Ʌ' => 'ʌ',
75120 'Ɇ' => 'ɇ',
75121 'Ɉ' => 'ɉ',
75122 'Ɋ' => 'ɋ',
75123 'Ɍ' => 'ɍ',
75124 'Ɏ' => 'ɏ',
75125 'Ͱ' => 'ͱ',
75126 'Ͳ' => 'ͳ',
75127 'Ͷ' => 'ͷ',
75128 'Ϳ' => 'ϳ',
75129 'Ά' => 'ά',
75130 'Έ' => 'έ',
75131 'Ή' => 'ή',
75132 'Ί' => 'ί',
75133 'Ό' => 'ό',
75134 'Ύ' => 'ύ',
75135 'Ώ' => 'ώ',
75136 'Α' => 'α',
75137 'Β' => 'β',
75138 'Γ' => 'γ',
75139 'Δ' => 'δ',
75140 'Ε' => 'ε',
75141 'Ζ' => 'ζ',
75142 'Η' => 'η',
75143 'Θ' => 'θ',
75144 'Ι' => 'ι',
75145 'Κ' => 'κ',
75146 'Λ' => 'λ',
75147 'Μ' => 'μ',
75148 'Ν' => 'ν',
75149 'Ξ' => 'ξ',
75150 'Ο' => 'ο',
75151 'Π' => 'π',
75152 'Ρ' => 'ρ',
75153 'Σ' => 'σ',
75154 'Τ' => 'τ',
75155 'Υ' => 'υ',
75156 'Φ' => 'φ',
75157 'Χ' => 'χ',
75158 'Ψ' => 'ψ',
75159 'Ω' => 'ω',
75160 'Ϊ' => 'ϊ',
75161 'Ϋ' => 'ϋ',
75162 'Ϗ' => 'ϗ',
75163 'Ϙ' => 'ϙ',
75164 'Ϛ' => 'ϛ',
75165 'Ϝ' => 'ϝ',
75166 'Ϟ' => 'ϟ',
75167 'Ϡ' => 'ϡ',
75168 'Ϣ' => 'ϣ',
75169 'Ϥ' => 'ϥ',
75170 'Ϧ' => 'ϧ',
75171 'Ϩ' => 'ϩ',
75172 'Ϫ' => 'ϫ',
75173 'Ϭ' => 'ϭ',
75174 'Ϯ' => 'ϯ',
75175 'ϴ' => 'θ',
75176 'Ϸ' => 'ϸ',
75177 'Ϲ' => 'ϲ',
75178 'Ϻ' => 'ϻ',
75179 'Ͻ' => 'ͻ',
75180 'Ͼ' => 'ͼ',
75181 'Ͽ' => 'ͽ',
75182 'Ѐ' => 'ѐ',
75183 'Ё' => 'ё',
75184 'Ђ' => 'ђ',
75185 'Ѓ' => 'ѓ',
75186 'Є' => 'є',
75187 'Ѕ' => 'ѕ',
75188 'І' => 'і',
75189 'Ї' => 'ї',
75190 'Ј' => 'ј',
75191 'Љ' => 'љ',
75192 'Њ' => 'њ',
75193 'Ћ' => 'ћ',
75194 'Ќ' => 'ќ',
75195 'Ѝ' => 'ѝ',
75196 'Ў' => 'ў',
75197 'Џ' => 'џ',
75198 'А' => 'а',
75199 'Б' => 'б',
75200 'В' => 'в',
75201 'Г' => 'г',
75202 'Д' => 'д',
75203 'Е' => 'е',
75204 'Ж' => 'ж',
75205 'З' => 'з',
75206 'И' => 'и',
75207 'Й' => 'й',
75208 'К' => 'к',
75209 'Л' => 'л',
75210 'М' => 'м',
75211 'Н' => 'н',
75212 'О' => 'о',
75213 'П' => 'п',
75214 'Р' => 'р',
75215 'С' => 'с',
75216 'Т' => 'т',
75217 'У' => 'у',
75218 'Ф' => 'ф',
75219 'Х' => 'х',
75220 'Ц' => 'ц',
75221 'Ч' => 'ч',
75222 'Ш' => 'ш',
75223 'Щ' => 'щ',
75224 'Ъ' => 'ъ',
75225 'Ы' => 'ы',
75226 'Ь' => 'ь',
75227 'Э' => 'э',
75228 'Ю' => 'ю',
75229 'Я' => 'я',
75230 'Ѡ' => 'ѡ',
75231 'Ѣ' => 'ѣ',
75232 'Ѥ' => 'ѥ',
75233 'Ѧ' => 'ѧ',
75234 'Ѩ' => 'ѩ',
75235 'Ѫ' => 'ѫ',
75236 'Ѭ' => 'ѭ',
75237 'Ѯ' => 'ѯ',
75238 'Ѱ' => 'ѱ',
75239 'Ѳ' => 'ѳ',
75240 'Ѵ' => 'ѵ',
75241 'Ѷ' => 'ѷ',
75242 'Ѹ' => 'ѹ',
75243 'Ѻ' => 'ѻ',
75244 'Ѽ' => 'ѽ',
75245 'Ѿ' => 'ѿ',
75246 'Ҁ' => 'ҁ',
75247 'Ҋ' => 'ҋ',
75248 'Ҍ' => 'ҍ',
75249 'Ҏ' => 'ҏ',
75250 'Ґ' => 'ґ',
75251 'Ғ' => 'ғ',
75252 'Ҕ' => 'ҕ',
75253 'Җ' => 'җ',
75254 'Ҙ' => 'ҙ',
75255 'Қ' => 'қ',
75256 'Ҝ' => 'ҝ',
75257 'Ҟ' => 'ҟ',
75258 'Ҡ' => 'ҡ',
75259 'Ң' => 'ң',
75260 'Ҥ' => 'ҥ',
75261 'Ҧ' => 'ҧ',
75262 'Ҩ' => 'ҩ',
75263 'Ҫ' => 'ҫ',
75264 'Ҭ' => 'ҭ',
75265 'Ү' => 'ү',
75266 'Ұ' => 'ұ',
75267 'Ҳ' => 'ҳ',
75268 'Ҵ' => 'ҵ',
75269 'Ҷ' => 'ҷ',
75270 'Ҹ' => 'ҹ',
75271 'Һ' => 'һ',
75272 'Ҽ' => 'ҽ',
75273 'Ҿ' => 'ҿ',
75274 'Ӏ' => 'ӏ',
75275 'Ӂ' => 'ӂ',
75276 'Ӄ' => 'ӄ',
75277 'Ӆ' => 'ӆ',
75278 'Ӈ' => 'ӈ',
75279 'Ӊ' => 'ӊ',
75280 'Ӌ' => 'ӌ',
75281 'Ӎ' => 'ӎ',
75282 'Ӑ' => 'ӑ',
75283 'Ӓ' => 'ӓ',
75284 'Ӕ' => 'ӕ',
75285 'Ӗ' => 'ӗ',
75286 'Ә' => 'ә',
75287 'Ӛ' => 'ӛ',
75288 'Ӝ' => 'ӝ',
75289 'Ӟ' => 'ӟ',
75290 'Ӡ' => 'ӡ',
75291 'Ӣ' => 'ӣ',
75292 'Ӥ' => 'ӥ',
75293 'Ӧ' => 'ӧ',
75294 'Ө' => 'ө',
75295 'Ӫ' => 'ӫ',
75296 'Ӭ' => 'ӭ',
75297 'Ӯ' => 'ӯ',
75298 'Ӱ' => 'ӱ',
75299 'Ӳ' => 'ӳ',
75300 'Ӵ' => 'ӵ',
75301 'Ӷ' => 'ӷ',
75302 'Ӹ' => 'ӹ',
75303 'Ӻ' => 'ӻ',
75304 'Ӽ' => 'ӽ',
75305 'Ӿ' => 'ӿ',
75306 'Ԁ' => 'ԁ',
75307 'Ԃ' => 'ԃ',
75308 'Ԅ' => 'ԅ',
75309 'Ԇ' => 'ԇ',
75310 'Ԉ' => 'ԉ',
75311 'Ԋ' => 'ԋ',
75312 'Ԍ' => 'ԍ',
75313 'Ԏ' => 'ԏ',
75314 'Ԑ' => 'ԑ',
75315 'Ԓ' => 'ԓ',
75316 'Ԕ' => 'ԕ',
75317 'Ԗ' => 'ԗ',
75318 'Ԙ' => 'ԙ',
75319 'Ԛ' => 'ԛ',
75320 'Ԝ' => 'ԝ',
75321 'Ԟ' => 'ԟ',
75322 'Ԡ' => 'ԡ',
75323 'Ԣ' => 'ԣ',
75324 'Ԥ' => 'ԥ',
75325 'Ԧ' => 'ԧ',
75326 'Ԩ' => 'ԩ',
75327 'Ԫ' => 'ԫ',
75328 'Ԭ' => 'ԭ',
75329 'Ԯ' => 'ԯ',
75330 'Ա' => 'ա',
75331 'Բ' => 'բ',
75332 'Գ' => 'գ',
75333 'Դ' => 'դ',
75334 'Ե' => 'ե',
75335 'Զ' => 'զ',
75336 'Է' => 'է',
75337 'Ը' => 'ը',
75338 'Թ' => 'թ',
75339 'Ժ' => 'ժ',
75340 'Ի' => 'ի',
75341 'Լ' => 'լ',
75342 'Խ' => 'խ',
75343 'Ծ' => 'ծ',
75344 'Կ' => 'կ',
75345 'Հ' => 'հ',
75346 'Ձ' => 'ձ',
75347 'Ղ' => 'ղ',
75348 'Ճ' => 'ճ',
75349 'Մ' => 'մ',
75350 'Յ' => 'յ',
75351 'Ն' => 'ն',
75352 'Շ' => 'շ',
75353 'Ո' => 'ո',
75354 'Չ' => 'չ',
75355 'Պ' => 'պ',
75356 'Ջ' => 'ջ',
75357 'Ռ' => 'ռ',
75358 'Ս' => 'ս',
75359 'Վ' => 'վ',
75360 'Տ' => 'տ',
75361 'Ր' => 'ր',
75362 'Ց' => 'ց',
75363 'Ւ' => 'ւ',
75364 'Փ' => 'փ',
75365 'Ք' => 'ք',
75366 'Օ' => 'օ',
75367 'Ֆ' => 'ֆ',
75368 'Ⴀ' => 'ⴀ',
75369 'Ⴁ' => 'ⴁ',
75370 'Ⴂ' => 'ⴂ',
75371 'Ⴃ' => 'ⴃ',
75372 'Ⴄ' => 'ⴄ',
75373 'Ⴅ' => 'ⴅ',
75374 'Ⴆ' => 'ⴆ',
75375 'Ⴇ' => 'ⴇ',
75376 'Ⴈ' => 'ⴈ',
75377 'Ⴉ' => 'ⴉ',
75378 'Ⴊ' => 'ⴊ',
75379 'Ⴋ' => 'ⴋ',
75380 'Ⴌ' => 'ⴌ',
75381 'Ⴍ' => 'ⴍ',
75382 'Ⴎ' => 'ⴎ',
75383 'Ⴏ' => 'ⴏ',
75384 'Ⴐ' => 'ⴐ',
75385 'Ⴑ' => 'ⴑ',
75386 'Ⴒ' => 'ⴒ',
75387 'Ⴓ' => 'ⴓ',
75388 'Ⴔ' => 'ⴔ',
75389 'Ⴕ' => 'ⴕ',
75390 'Ⴖ' => 'ⴖ',
75391 'Ⴗ' => 'ⴗ',
75392 'Ⴘ' => 'ⴘ',
75393 'Ⴙ' => 'ⴙ',
75394 'Ⴚ' => 'ⴚ',
75395 'Ⴛ' => 'ⴛ',
75396 'Ⴜ' => 'ⴜ',
75397 'Ⴝ' => 'ⴝ',
75398 'Ⴞ' => 'ⴞ',
75399 'Ⴟ' => 'ⴟ',
75400 'Ⴠ' => 'ⴠ',
75401 'Ⴡ' => 'ⴡ',
75402 'Ⴢ' => 'ⴢ',
75403 'Ⴣ' => 'ⴣ',
75404 'Ⴤ' => 'ⴤ',
75405 'Ⴥ' => 'ⴥ',
75406 'Ⴧ' => 'ⴧ',
75407 'Ⴭ' => 'ⴭ',
75408 'Ꭰ' => 'ꭰ',
75409 'Ꭱ' => 'ꭱ',
75410 'Ꭲ' => 'ꭲ',
75411 'Ꭳ' => 'ꭳ',
75412 'Ꭴ' => 'ꭴ',
75413 'Ꭵ' => 'ꭵ',
75414 'Ꭶ' => 'ꭶ',
75415 'Ꭷ' => 'ꭷ',
75416 'Ꭸ' => 'ꭸ',
75417 'Ꭹ' => 'ꭹ',
75418 'Ꭺ' => 'ꭺ',
75419 'Ꭻ' => 'ꭻ',
75420 'Ꭼ' => 'ꭼ',
75421 'Ꭽ' => 'ꭽ',
75422 'Ꭾ' => 'ꭾ',
75423 'Ꭿ' => 'ꭿ',
75424 'Ꮀ' => 'ꮀ',
75425 'Ꮁ' => 'ꮁ',
75426 'Ꮂ' => 'ꮂ',
75427 'Ꮃ' => 'ꮃ',
75428 'Ꮄ' => 'ꮄ',
75429 'Ꮅ' => 'ꮅ',
75430 'Ꮆ' => 'ꮆ',
75431 'Ꮇ' => 'ꮇ',
75432 'Ꮈ' => 'ꮈ',
75433 'Ꮉ' => 'ꮉ',
75434 'Ꮊ' => 'ꮊ',
75435 'Ꮋ' => 'ꮋ',
75436 'Ꮌ' => 'ꮌ',
75437 'Ꮍ' => 'ꮍ',
75438 'Ꮎ' => 'ꮎ',
75439 'Ꮏ' => 'ꮏ',
75440 'Ꮐ' => 'ꮐ',
75441 'Ꮑ' => 'ꮑ',
75442 'Ꮒ' => 'ꮒ',
75443 'Ꮓ' => 'ꮓ',
75444 'Ꮔ' => 'ꮔ',
75445 'Ꮕ' => 'ꮕ',
75446 'Ꮖ' => 'ꮖ',
75447 'Ꮗ' => 'ꮗ',
75448 'Ꮘ' => 'ꮘ',
75449 'Ꮙ' => 'ꮙ',
75450 'Ꮚ' => 'ꮚ',
75451 'Ꮛ' => 'ꮛ',
75452 'Ꮜ' => 'ꮜ',
75453 'Ꮝ' => 'ꮝ',
75454 'Ꮞ' => 'ꮞ',
75455 'Ꮟ' => 'ꮟ',
75456 'Ꮠ' => 'ꮠ',
75457 'Ꮡ' => 'ꮡ',
75458 'Ꮢ' => 'ꮢ',
75459 'Ꮣ' => 'ꮣ',
75460 'Ꮤ' => 'ꮤ',
75461 'Ꮥ' => 'ꮥ',
75462 'Ꮦ' => 'ꮦ',
75463 'Ꮧ' => 'ꮧ',
75464 'Ꮨ' => 'ꮨ',
75465 'Ꮩ' => 'ꮩ',
75466 'Ꮪ' => 'ꮪ',
75467 'Ꮫ' => 'ꮫ',
75468 'Ꮬ' => 'ꮬ',
75469 'Ꮭ' => 'ꮭ',
75470 'Ꮮ' => 'ꮮ',
75471 'Ꮯ' => 'ꮯ',
75472 'Ꮰ' => 'ꮰ',
75473 'Ꮱ' => 'ꮱ',
75474 'Ꮲ' => 'ꮲ',
75475 'Ꮳ' => 'ꮳ',
75476 'Ꮴ' => 'ꮴ',
75477 'Ꮵ' => 'ꮵ',
75478 'Ꮶ' => 'ꮶ',
75479 'Ꮷ' => 'ꮷ',
75480 'Ꮸ' => 'ꮸ',
75481 'Ꮹ' => 'ꮹ',
75482 'Ꮺ' => 'ꮺ',
75483 'Ꮻ' => 'ꮻ',
75484 'Ꮼ' => 'ꮼ',
75485 'Ꮽ' => 'ꮽ',
75486 'Ꮾ' => 'ꮾ',
75487 'Ꮿ' => 'ꮿ',
75488 'Ᏸ' => 'ᏸ',
75489 'Ᏹ' => 'ᏹ',
75490 'Ᏺ' => 'ᏺ',
75491 'Ᏻ' => 'ᏻ',
75492 'Ᏼ' => 'ᏼ',
75493 'Ᏽ' => 'ᏽ',
75494 'Ა' => 'ა',
75495 'Ბ' => 'ბ',
75496 'Გ' => 'გ',
75497 'Დ' => 'დ',
75498 'Ე' => 'ე',
75499 'Ვ' => 'ვ',
75500 'Ზ' => 'ზ',
75501 'Თ' => 'თ',
75502 'Ი' => 'ი',
75503 'Კ' => 'კ',
75504 'Ლ' => 'ლ',
75505 'Მ' => 'მ',
75506 'Ნ' => 'ნ',
75507 'Ო' => 'ო',
75508 'Პ' => 'პ',
75509 'Ჟ' => 'ჟ',
75510 'Რ' => 'რ',
75511 'Ს' => 'ს',
75512 'Ტ' => 'ტ',
75513 'Უ' => 'უ',
75514 'Ფ' => 'ფ',
75515 'Ქ' => 'ქ',
75516 'Ღ' => 'ღ',
75517 'Ყ' => 'ყ',
75518 'Შ' => 'შ',
75519 'Ჩ' => 'ჩ',
75520 'Ც' => 'ც',
75521 'Ძ' => 'ძ',
75522 'Წ' => 'წ',
75523 'Ჭ' => 'ჭ',
75524 'Ხ' => 'ხ',
75525 'Ჯ' => 'ჯ',
75526 'Ჰ' => 'ჰ',
75527 'Ჱ' => 'ჱ',
75528 'Ჲ' => 'ჲ',
75529 'Ჳ' => 'ჳ',
75530 'Ჴ' => 'ჴ',
75531 'Ჵ' => 'ჵ',
75532 'Ჶ' => 'ჶ',
75533 'Ჷ' => 'ჷ',
75534 'Ჸ' => 'ჸ',
75535 'Ჹ' => 'ჹ',
75536 'Ჺ' => 'ჺ',
75537 'Ჽ' => 'ჽ',
75538 'Ჾ' => 'ჾ',
75539 'Ჿ' => 'ჿ',
75540 'Ḁ' => 'ḁ',
75541 'Ḃ' => 'ḃ',
75542 'Ḅ' => 'ḅ',
75543 'Ḇ' => 'ḇ',
75544 'Ḉ' => 'ḉ',
75545 'Ḋ' => 'ḋ',
75546 'Ḍ' => 'ḍ',
75547 'Ḏ' => 'ḏ',
75548 'Ḑ' => 'ḑ',
75549 'Ḓ' => 'ḓ',
75550 'Ḕ' => 'ḕ',
75551 'Ḗ' => 'ḗ',
75552 'Ḙ' => 'ḙ',
75553 'Ḛ' => 'ḛ',
75554 'Ḝ' => 'ḝ',
75555 'Ḟ' => 'ḟ',
75556 'Ḡ' => 'ḡ',
75557 'Ḣ' => 'ḣ',
75558 'Ḥ' => 'ḥ',
75559 'Ḧ' => 'ḧ',
75560 'Ḩ' => 'ḩ',
75561 'Ḫ' => 'ḫ',
75562 'Ḭ' => 'ḭ',
75563 'Ḯ' => 'ḯ',
75564 'Ḱ' => 'ḱ',
75565 'Ḳ' => 'ḳ',
75566 'Ḵ' => 'ḵ',
75567 'Ḷ' => 'ḷ',
75568 'Ḹ' => 'ḹ',
75569 'Ḻ' => 'ḻ',
75570 'Ḽ' => 'ḽ',
75571 'Ḿ' => 'ḿ',
75572 'Ṁ' => 'ṁ',
75573 'Ṃ' => 'ṃ',
75574 'Ṅ' => 'ṅ',
75575 'Ṇ' => 'ṇ',
75576 'Ṉ' => 'ṉ',
75577 'Ṋ' => 'ṋ',
75578 'Ṍ' => 'ṍ',
75579 'Ṏ' => 'ṏ',
75580 'Ṑ' => 'ṑ',
75581 'Ṓ' => 'ṓ',
75582 'Ṕ' => 'ṕ',
75583 'Ṗ' => 'ṗ',
75584 'Ṙ' => 'ṙ',
75585 'Ṛ' => 'ṛ',
75586 'Ṝ' => 'ṝ',
75587 'Ṟ' => 'ṟ',
75588 'Ṡ' => 'ṡ',
75589 'Ṣ' => 'ṣ',
75590 'Ṥ' => 'ṥ',
75591 'Ṧ' => 'ṧ',
75592 'Ṩ' => 'ṩ',
75593 'Ṫ' => 'ṫ',
75594 'Ṭ' => 'ṭ',
75595 'Ṯ' => 'ṯ',
75596 'Ṱ' => 'ṱ',
75597 'Ṳ' => 'ṳ',
75598 'Ṵ' => 'ṵ',
75599 'Ṷ' => 'ṷ',
75600 'Ṹ' => 'ṹ',
75601 'Ṻ' => 'ṻ',
75602 'Ṽ' => 'ṽ',
75603 'Ṿ' => 'ṿ',
75604 'Ẁ' => 'ẁ',
75605 'Ẃ' => 'ẃ',
75606 'Ẅ' => 'ẅ',
75607 'Ẇ' => 'ẇ',
75608 'Ẉ' => 'ẉ',
75609 'Ẋ' => 'ẋ',
75610 'Ẍ' => 'ẍ',
75611 'Ẏ' => 'ẏ',
75612 'Ẑ' => 'ẑ',
75613 'Ẓ' => 'ẓ',
75614 'Ẕ' => 'ẕ',
75615 'ẞ' => 'ß',
75616 'Ạ' => 'ạ',
75617 'Ả' => 'ả',
75618 'Ấ' => 'ấ',
75619 'Ầ' => 'ầ',
75620 'Ẩ' => 'ẩ',
75621 'Ẫ' => 'ẫ',
75622 'Ậ' => 'ậ',
75623 'Ắ' => 'ắ',
75624 'Ằ' => 'ằ',
75625 'Ẳ' => 'ẳ',
75626 'Ẵ' => 'ẵ',
75627 'Ặ' => 'ặ',
75628 'Ẹ' => 'ẹ',
75629 'Ẻ' => 'ẻ',
75630 'Ẽ' => 'ẽ',
75631 'Ế' => 'ế',
75632 'Ề' => 'ề',
75633 'Ể' => 'ể',
75634 'Ễ' => 'ễ',
75635 'Ệ' => 'ệ',
75636 'Ỉ' => 'ỉ',
75637 'Ị' => 'ị',
75638 'Ọ' => 'ọ',
75639 'Ỏ' => 'ỏ',
75640 'Ố' => 'ố',
75641 'Ồ' => 'ồ',
75642 'Ổ' => 'ổ',
75643 'Ỗ' => 'ỗ',
75644 'Ộ' => 'ộ',
75645 'Ớ' => 'ớ',
75646 'Ờ' => 'ờ',
75647 'Ở' => 'ở',
75648 'Ỡ' => 'ỡ',
75649 'Ợ' => 'ợ',
75650 'Ụ' => 'ụ',
75651 'Ủ' => 'ủ',
75652 'Ứ' => 'ứ',
75653 'Ừ' => 'ừ',
75654 'Ử' => 'ử',
75655 'Ữ' => 'ữ',
75656 'Ự' => 'ự',
75657 'Ỳ' => 'ỳ',
75658 'Ỵ' => 'ỵ',
75659 'Ỷ' => 'ỷ',
75660 'Ỹ' => 'ỹ',
75661 'Ỻ' => 'ỻ',
75662 'Ỽ' => 'ỽ',
75663 'Ỿ' => 'ỿ',
75664 'Ἀ' => 'ἀ',
75665 'Ἁ' => 'ἁ',
75666 'Ἂ' => 'ἂ',
75667 'Ἃ' => 'ἃ',
75668 'Ἄ' => 'ἄ',
75669 'Ἅ' => 'ἅ',
75670 'Ἆ' => 'ἆ',
75671 'Ἇ' => 'ἇ',
75672 'Ἐ' => 'ἐ',
75673 'Ἑ' => 'ἑ',
75674 'Ἒ' => 'ἒ',
75675 'Ἓ' => 'ἓ',
75676 'Ἔ' => 'ἔ',
75677 'Ἕ' => 'ἕ',
75678 'Ἠ' => 'ἠ',
75679 'Ἡ' => 'ἡ',
75680 'Ἢ' => 'ἢ',
75681 'Ἣ' => 'ἣ',
75682 'Ἤ' => 'ἤ',
75683 'Ἥ' => 'ἥ',
75684 'Ἦ' => 'ἦ',
75685 'Ἧ' => 'ἧ',
75686 'Ἰ' => 'ἰ',
75687 'Ἱ' => 'ἱ',
75688 'Ἲ' => 'ἲ',
75689 'Ἳ' => 'ἳ',
75690 'Ἴ' => 'ἴ',
75691 'Ἵ' => 'ἵ',
75692 'Ἶ' => 'ἶ',
75693 'Ἷ' => 'ἷ',
75694 'Ὀ' => 'ὀ',
75695 'Ὁ' => 'ὁ',
75696 'Ὂ' => 'ὂ',
75697 'Ὃ' => 'ὃ',
75698 'Ὄ' => 'ὄ',
75699 'Ὅ' => 'ὅ',
75700 'Ὑ' => 'ὑ',
75701 'Ὓ' => 'ὓ',
75702 'Ὕ' => 'ὕ',
75703 'Ὗ' => 'ὗ',
75704 'Ὠ' => 'ὠ',
75705 'Ὡ' => 'ὡ',
75706 'Ὢ' => 'ὢ',
75707 'Ὣ' => 'ὣ',
75708 'Ὤ' => 'ὤ',
75709 'Ὥ' => 'ὥ',
75710 'Ὦ' => 'ὦ',
75711 'Ὧ' => 'ὧ',
75712 'ᾈ' => 'ᾀ',
75713 'ᾉ' => 'ᾁ',
75714 'ᾊ' => 'ᾂ',
75715 'ᾋ' => 'ᾃ',
75716 'ᾌ' => 'ᾄ',
75717 'ᾍ' => 'ᾅ',
75718 'ᾎ' => 'ᾆ',
75719 'ᾏ' => 'ᾇ',
75720 'ᾘ' => 'ᾐ',
75721 'ᾙ' => 'ᾑ',
75722 'ᾚ' => 'ᾒ',
75723 'ᾛ' => 'ᾓ',
75724 'ᾜ' => 'ᾔ',
75725 'ᾝ' => 'ᾕ',
75726 'ᾞ' => 'ᾖ',
75727 'ᾟ' => 'ᾗ',
75728 'ᾨ' => 'ᾠ',
75729 'ᾩ' => 'ᾡ',
75730 'ᾪ' => 'ᾢ',
75731 'ᾫ' => 'ᾣ',
75732 'ᾬ' => 'ᾤ',
75733 'ᾭ' => 'ᾥ',
75734 'ᾮ' => 'ᾦ',
75735 'ᾯ' => 'ᾧ',
75736 'Ᾰ' => 'ᾰ',
75737 'Ᾱ' => 'ᾱ',
75738 'Ὰ' => 'ὰ',
75739 'Ά' => 'ά',
75740 'ᾼ' => 'ᾳ',
75741 'Ὲ' => 'ὲ',
75742 'Έ' => 'έ',
75743 'Ὴ' => 'ὴ',
75744 'Ή' => 'ή',
75745 'ῌ' => 'ῃ',
75746 'Ῐ' => 'ῐ',
75747 'Ῑ' => 'ῑ',
75748 'Ὶ' => 'ὶ',
75749 'Ί' => 'ί',
75750 'Ῠ' => 'ῠ',
75751 'Ῡ' => 'ῡ',
75752 'Ὺ' => 'ὺ',
75753 'Ύ' => 'ύ',
75754 'Ῥ' => 'ῥ',
75755 'Ὸ' => 'ὸ',
75756 'Ό' => 'ό',
75757 'Ὼ' => 'ὼ',
75758 'Ώ' => 'ώ',
75759 'ῼ' => 'ῳ',
75760 'Ω' => 'ω',
75761 'K' => 'k',
75762 'Å' => 'å',
75763 'Ⅎ' => 'ⅎ',
75764 'Ⅰ' => 'ⅰ',
75765 'Ⅱ' => 'ⅱ',
75766 'Ⅲ' => 'ⅲ',
75767 'Ⅳ' => 'ⅳ',
75768 'Ⅴ' => 'ⅴ',
75769 'Ⅵ' => 'ⅵ',
75770 'Ⅶ' => 'ⅶ',
75771 'Ⅷ' => 'ⅷ',
75772 'Ⅸ' => 'ⅸ',
75773 'Ⅹ' => 'ⅹ',
75774 'Ⅺ' => 'ⅺ',
75775 'Ⅻ' => 'ⅻ',
75776 'Ⅼ' => 'ⅼ',
75777 'Ⅽ' => 'ⅽ',
75778 'Ⅾ' => 'ⅾ',
75779 'Ⅿ' => 'ⅿ',
75780 'Ↄ' => 'ↄ',
75781 'Ⓐ' => 'ⓐ',
75782 'Ⓑ' => 'ⓑ',
75783 'Ⓒ' => 'ⓒ',
75784 'Ⓓ' => 'ⓓ',
75785 'Ⓔ' => 'ⓔ',
75786 'Ⓕ' => 'ⓕ',
75787 'Ⓖ' => 'ⓖ',
75788 'Ⓗ' => 'ⓗ',
75789 'Ⓘ' => 'ⓘ',
75790 'Ⓙ' => 'ⓙ',
75791 'Ⓚ' => 'ⓚ',
75792 'Ⓛ' => 'ⓛ',
75793 'Ⓜ' => 'ⓜ',
75794 'Ⓝ' => 'ⓝ',
75795 'Ⓞ' => 'ⓞ',
75796 'Ⓟ' => 'ⓟ',
75797 'Ⓠ' => 'ⓠ',
75798 'Ⓡ' => 'ⓡ',
75799 'Ⓢ' => 'ⓢ',
75800 'Ⓣ' => 'ⓣ',
75801 'Ⓤ' => 'ⓤ',
75802 'Ⓥ' => 'ⓥ',
75803 'Ⓦ' => 'ⓦ',
75804 'Ⓧ' => 'ⓧ',
75805 'Ⓨ' => 'ⓨ',
75806 'Ⓩ' => 'ⓩ',
75807 'Ⰰ' => 'ⰰ',
75808 'Ⰱ' => 'ⰱ',
75809 'Ⰲ' => 'ⰲ',
75810 'Ⰳ' => 'ⰳ',
75811 'Ⰴ' => 'ⰴ',
75812 'Ⰵ' => 'ⰵ',
75813 'Ⰶ' => 'ⰶ',
75814 'Ⰷ' => 'ⰷ',
75815 'Ⰸ' => 'ⰸ',
75816 'Ⰹ' => 'ⰹ',
75817 'Ⰺ' => 'ⰺ',
75818 'Ⰻ' => 'ⰻ',
75819 'Ⰼ' => 'ⰼ',
75820 'Ⰽ' => 'ⰽ',
75821 'Ⰾ' => 'ⰾ',
75822 'Ⰿ' => 'ⰿ',
75823 'Ⱀ' => 'ⱀ',
75824 'Ⱁ' => 'ⱁ',
75825 'Ⱂ' => 'ⱂ',
75826 'Ⱃ' => 'ⱃ',
75827 'Ⱄ' => 'ⱄ',
75828 'Ⱅ' => 'ⱅ',
75829 'Ⱆ' => 'ⱆ',
75830 'Ⱇ' => 'ⱇ',
75831 'Ⱈ' => 'ⱈ',
75832 'Ⱉ' => 'ⱉ',
75833 'Ⱊ' => 'ⱊ',
75834 'Ⱋ' => 'ⱋ',
75835 'Ⱌ' => 'ⱌ',
75836 'Ⱍ' => 'ⱍ',
75837 'Ⱎ' => 'ⱎ',
75838 'Ⱏ' => 'ⱏ',
75839 'Ⱐ' => 'ⱐ',
75840 'Ⱑ' => 'ⱑ',
75841 'Ⱒ' => 'ⱒ',
75842 'Ⱓ' => 'ⱓ',
75843 'Ⱔ' => 'ⱔ',
75844 'Ⱕ' => 'ⱕ',
75845 'Ⱖ' => 'ⱖ',
75846 'Ⱗ' => 'ⱗ',
75847 'Ⱘ' => 'ⱘ',
75848 'Ⱙ' => 'ⱙ',
75849 'Ⱚ' => 'ⱚ',
75850 'Ⱛ' => 'ⱛ',
75851 'Ⱜ' => 'ⱜ',
75852 'Ⱝ' => 'ⱝ',
75853 'Ⱞ' => 'ⱞ',
75854 'Ⱡ' => 'ⱡ',
75855 'Ɫ' => 'ɫ',
75856 'Ᵽ' => 'ᵽ',
75857 'Ɽ' => 'ɽ',
75858 'Ⱨ' => 'ⱨ',
75859 'Ⱪ' => 'ⱪ',
75860 'Ⱬ' => 'ⱬ',
75861 'Ɑ' => 'ɑ',
75862 'Ɱ' => 'ɱ',
75863 'Ɐ' => 'ɐ',
75864 'Ɒ' => 'ɒ',
75865 'Ⱳ' => 'ⱳ',
75866 'Ⱶ' => 'ⱶ',
75867 'Ȿ' => 'ȿ',
75868 'Ɀ' => 'ɀ',
75869 'Ⲁ' => 'ⲁ',
75870 'Ⲃ' => 'ⲃ',
75871 'Ⲅ' => 'ⲅ',
75872 'Ⲇ' => 'ⲇ',
75873 'Ⲉ' => 'ⲉ',
75874 'Ⲋ' => 'ⲋ',
75875 'Ⲍ' => 'ⲍ',
75876 'Ⲏ' => 'ⲏ',
75877 'Ⲑ' => 'ⲑ',
75878 'Ⲓ' => 'ⲓ',
75879 'Ⲕ' => 'ⲕ',
75880 'Ⲗ' => 'ⲗ',
75881 'Ⲙ' => 'ⲙ',
75882 'Ⲛ' => 'ⲛ',
75883 'Ⲝ' => 'ⲝ',
75884 'Ⲟ' => 'ⲟ',
75885 'Ⲡ' => 'ⲡ',
75886 'Ⲣ' => 'ⲣ',
75887 'Ⲥ' => 'ⲥ',
75888 'Ⲧ' => 'ⲧ',
75889 'Ⲩ' => 'ⲩ',
75890 'Ⲫ' => 'ⲫ',
75891 'Ⲭ' => 'ⲭ',
75892 'Ⲯ' => 'ⲯ',
75893 'Ⲱ' => 'ⲱ',
75894 'Ⲳ' => 'ⲳ',
75895 'Ⲵ' => 'ⲵ',
75896 'Ⲷ' => 'ⲷ',
75897 'Ⲹ' => 'ⲹ',
75898 'Ⲻ' => 'ⲻ',
75899 'Ⲽ' => 'ⲽ',
75900 'Ⲿ' => 'ⲿ',
75901 'Ⳁ' => 'ⳁ',
75902 'Ⳃ' => 'ⳃ',
75903 'Ⳅ' => 'ⳅ',
75904 'Ⳇ' => 'ⳇ',
75905 'Ⳉ' => 'ⳉ',
75906 'Ⳋ' => 'ⳋ',
75907 'Ⳍ' => 'ⳍ',
75908 'Ⳏ' => 'ⳏ',
75909 'Ⳑ' => 'ⳑ',
75910 'Ⳓ' => 'ⳓ',
75911 'Ⳕ' => 'ⳕ',
75912 'Ⳗ' => 'ⳗ',
75913 'Ⳙ' => 'ⳙ',
75914 'Ⳛ' => 'ⳛ',
75915 'Ⳝ' => 'ⳝ',
75916 'Ⳟ' => 'ⳟ',
75917 'Ⳡ' => 'ⳡ',
75918 'Ⳣ' => 'ⳣ',
75919 'Ⳬ' => 'ⳬ',
75920 'Ⳮ' => 'ⳮ',
75921 'Ⳳ' => 'ⳳ',
75922 'Ꙁ' => 'ꙁ',
75923 'Ꙃ' => 'ꙃ',
75924 'Ꙅ' => 'ꙅ',
75925 'Ꙇ' => 'ꙇ',
75926 'Ꙉ' => 'ꙉ',
75927 'Ꙋ' => 'ꙋ',
75928 'Ꙍ' => 'ꙍ',
75929 'Ꙏ' => 'ꙏ',
75930 'Ꙑ' => 'ꙑ',
75931 'Ꙓ' => 'ꙓ',
75932 'Ꙕ' => 'ꙕ',
75933 'Ꙗ' => 'ꙗ',
75934 'Ꙙ' => 'ꙙ',
75935 'Ꙛ' => 'ꙛ',
75936 'Ꙝ' => 'ꙝ',
75937 'Ꙟ' => 'ꙟ',
75938 'Ꙡ' => 'ꙡ',
75939 'Ꙣ' => 'ꙣ',
75940 'Ꙥ' => 'ꙥ',
75941 'Ꙧ' => 'ꙧ',
75942 'Ꙩ' => 'ꙩ',
75943 'Ꙫ' => 'ꙫ',
75944 'Ꙭ' => 'ꙭ',
75945 'Ꚁ' => 'ꚁ',
75946 'Ꚃ' => 'ꚃ',
75947 'Ꚅ' => 'ꚅ',
75948 'Ꚇ' => 'ꚇ',
75949 'Ꚉ' => 'ꚉ',
75950 'Ꚋ' => 'ꚋ',
75951 'Ꚍ' => 'ꚍ',
75952 'Ꚏ' => 'ꚏ',
75953 'Ꚑ' => 'ꚑ',
75954 'Ꚓ' => 'ꚓ',
75955 'Ꚕ' => 'ꚕ',
75956 'Ꚗ' => 'ꚗ',
75957 'Ꚙ' => 'ꚙ',
75958 'Ꚛ' => 'ꚛ',
75959 'Ꜣ' => 'ꜣ',
75960 'Ꜥ' => 'ꜥ',
75961 'Ꜧ' => 'ꜧ',
75962 'Ꜩ' => 'ꜩ',
75963 'Ꜫ' => 'ꜫ',
75964 'Ꜭ' => 'ꜭ',
75965 'Ꜯ' => 'ꜯ',
75966 'Ꜳ' => 'ꜳ',
75967 'Ꜵ' => 'ꜵ',
75968 'Ꜷ' => 'ꜷ',
75969 'Ꜹ' => 'ꜹ',
75970 'Ꜻ' => 'ꜻ',
75971 'Ꜽ' => 'ꜽ',
75972 'Ꜿ' => 'ꜿ',
75973 'Ꝁ' => 'ꝁ',
75974 'Ꝃ' => 'ꝃ',
75975 'Ꝅ' => 'ꝅ',
75976 'Ꝇ' => 'ꝇ',
75977 'Ꝉ' => 'ꝉ',
75978 'Ꝋ' => 'ꝋ',
75979 'Ꝍ' => 'ꝍ',
75980 'Ꝏ' => 'ꝏ',
75981 'Ꝑ' => 'ꝑ',
75982 'Ꝓ' => 'ꝓ',
75983 'Ꝕ' => 'ꝕ',
75984 'Ꝗ' => 'ꝗ',
75985 'Ꝙ' => 'ꝙ',
75986 'Ꝛ' => 'ꝛ',
75987 'Ꝝ' => 'ꝝ',
75988 'Ꝟ' => 'ꝟ',
75989 'Ꝡ' => 'ꝡ',
75990 'Ꝣ' => 'ꝣ',
75991 'Ꝥ' => 'ꝥ',
75992 'Ꝧ' => 'ꝧ',
75993 'Ꝩ' => 'ꝩ',
75994 'Ꝫ' => 'ꝫ',
75995 'Ꝭ' => 'ꝭ',
75996 'Ꝯ' => 'ꝯ',
75997 'Ꝺ' => 'ꝺ',
75998 'Ꝼ' => 'ꝼ',
75999 'Ᵹ' => 'ᵹ',
76000 'Ꝿ' => 'ꝿ',
76001 'Ꞁ' => 'ꞁ',
76002 'Ꞃ' => 'ꞃ',
76003 'Ꞅ' => 'ꞅ',
76004 'Ꞇ' => 'ꞇ',
76005 'Ꞌ' => 'ꞌ',
76006 'Ɥ' => 'ɥ',
76007 'Ꞑ' => 'ꞑ',
76008 'Ꞓ' => 'ꞓ',
76009 'Ꞗ' => 'ꞗ',
76010 'Ꞙ' => 'ꞙ',
76011 'Ꞛ' => 'ꞛ',
76012 'Ꞝ' => 'ꞝ',
76013 'Ꞟ' => 'ꞟ',
76014 'Ꞡ' => 'ꞡ',
76015 'Ꞣ' => 'ꞣ',
76016 'Ꞥ' => 'ꞥ',
76017 'Ꞧ' => 'ꞧ',
76018 'Ꞩ' => 'ꞩ',
76019 'Ɦ' => 'ɦ',
76020 'Ɜ' => 'ɜ',
76021 'Ɡ' => 'ɡ',
76022 'Ɬ' => 'ɬ',
76023 'Ɪ' => 'ɪ',
76024 'Ʞ' => 'ʞ',
76025 'Ʇ' => 'ʇ',
76026 'Ʝ' => 'ʝ',
76027 'Ꭓ' => 'ꭓ',
76028 'Ꞵ' => 'ꞵ',
76029 'Ꞷ' => 'ꞷ',
76030 'Ꞹ' => 'ꞹ',
76031 'Ꞻ' => 'ꞻ',
76032 'Ꞽ' => 'ꞽ',
76033 'Ꞿ' => 'ꞿ',
76034 'Ꟃ' => 'ꟃ',
76035 'Ꞔ' => 'ꞔ',
76036 'Ʂ' => 'ʂ',
76037 'Ᶎ' => 'ᶎ',
76038 'Ꟈ' => 'ꟈ',
76039 'Ꟊ' => 'ꟊ',
76040 'Ꟶ' => 'ꟶ',
76041 'A' => 'a',
76042 'B' => 'b',
76043 'C' => 'c',
76044 'D' => 'd',
76045 'E' => 'e',
76046 'F' => 'f',
76047 'G' => 'g',
76048 'H' => 'h',
76049 'I' => 'i',
76050 'J' => 'j',
76051 'K' => 'k',
76052 'L' => 'l',
76053 'M' => 'm',
76054 'N' => 'n',
76055 'O' => 'o',
76056 'P' => 'p',
76057 'Q' => 'q',
76058 'R' => 'r',
76059 'S' => 's',
76060 'T' => 't',
76061 'U' => 'u',
76062 'V' => 'v',
76063 'W' => 'w',
76064 'X' => 'x',
76065 'Y' => 'y',
76066 'Z' => 'z',
76067 '𐐀' => '𐐨',
76068 '𐐁' => '𐐩',
76069 '𐐂' => '𐐪',
76070 '𐐃' => '𐐫',
76071 '𐐄' => '𐐬',
76072 '𐐅' => '𐐭',
76073 '𐐆' => '𐐮',
76074 '𐐇' => '𐐯',
76075 '𐐈' => '𐐰',
76076 '𐐉' => '𐐱',
76077 '𐐊' => '𐐲',
76078 '𐐋' => '𐐳',
76079 '𐐌' => '𐐴',
76080 '𐐍' => '𐐵',
76081 '𐐎' => '𐐶',
76082 '𐐏' => '𐐷',
76083 '𐐐' => '𐐸',
76084 '𐐑' => '𐐹',
76085 '𐐒' => '𐐺',
76086 '𐐓' => '𐐻',
76087 '𐐔' => '𐐼',
76088 '𐐕' => '𐐽',
76089 '𐐖' => '𐐾',
76090 '𐐗' => '𐐿',
76091 '𐐘' => '𐑀',
76092 '𐐙' => '𐑁',
76093 '𐐚' => '𐑂',
76094 '𐐛' => '𐑃',
76095 '𐐜' => '𐑄',
76096 '𐐝' => '𐑅',
76097 '𐐞' => '𐑆',
76098 '𐐟' => '𐑇',
76099 '𐐠' => '𐑈',
76100 '𐐡' => '𐑉',
76101 '𐐢' => '𐑊',
76102 '𐐣' => '𐑋',
76103 '𐐤' => '𐑌',
76104 '𐐥' => '𐑍',
76105 '𐐦' => '𐑎',
76106 '𐐧' => '𐑏',
76107 '𐒰' => '𐓘',
76108 '𐒱' => '𐓙',
76109 '𐒲' => '𐓚',
76110 '𐒳' => '𐓛',
76111 '𐒴' => '𐓜',
76112 '𐒵' => '𐓝',
76113 '𐒶' => '𐓞',
76114 '𐒷' => '𐓟',
76115 '𐒸' => '𐓠',
76116 '𐒹' => '𐓡',
76117 '𐒺' => '𐓢',
76118 '𐒻' => '𐓣',
76119 '𐒼' => '𐓤',
76120 '𐒽' => '𐓥',
76121 '𐒾' => '𐓦',
76122 '𐒿' => '𐓧',
76123 '𐓀' => '𐓨',
76124 '𐓁' => '𐓩',
76125 '𐓂' => '𐓪',
76126 '𐓃' => '𐓫',
76127 '𐓄' => '𐓬',
76128 '𐓅' => '𐓭',
76129 '𐓆' => '𐓮',
76130 '𐓇' => '𐓯',
76131 '𐓈' => '𐓰',
76132 '𐓉' => '𐓱',
76133 '𐓊' => '𐓲',
76134 '𐓋' => '𐓳',
76135 '𐓌' => '𐓴',
76136 '𐓍' => '𐓵',
76137 '𐓎' => '𐓶',
76138 '𐓏' => '𐓷',
76139 '𐓐' => '𐓸',
76140 '𐓑' => '𐓹',
76141 '𐓒' => '𐓺',
76142 '𐓓' => '𐓻',
76143 '𐲀' => '𐳀',
76144 '𐲁' => '𐳁',
76145 '𐲂' => '𐳂',
76146 '𐲃' => '𐳃',
76147 '𐲄' => '𐳄',
76148 '𐲅' => '𐳅',
76149 '𐲆' => '𐳆',
76150 '𐲇' => '𐳇',
76151 '𐲈' => '𐳈',
76152 '𐲉' => '𐳉',
76153 '𐲊' => '𐳊',
76154 '𐲋' => '𐳋',
76155 '𐲌' => '𐳌',
76156 '𐲍' => '𐳍',
76157 '𐲎' => '𐳎',
76158 '𐲏' => '𐳏',
76159 '𐲐' => '𐳐',
76160 '𐲑' => '𐳑',
76161 '𐲒' => '𐳒',
76162 '𐲓' => '𐳓',
76163 '𐲔' => '𐳔',
76164 '𐲕' => '𐳕',
76165 '𐲖' => '𐳖',
76166 '𐲗' => '𐳗',
76167 '𐲘' => '𐳘',
76168 '𐲙' => '𐳙',
76169 '𐲚' => '𐳚',
76170 '𐲛' => '𐳛',
76171 '𐲜' => '𐳜',
76172 '𐲝' => '𐳝',
76173 '𐲞' => '𐳞',
76174 '𐲟' => '𐳟',
76175 '𐲠' => '𐳠',
76176 '𐲡' => '𐳡',
76177 '𐲢' => '𐳢',
76178 '𐲣' => '𐳣',
76179 '𐲤' => '𐳤',
76180 '𐲥' => '𐳥',
76181 '𐲦' => '𐳦',
76182 '𐲧' => '𐳧',
76183 '𐲨' => '𐳨',
76184 '𐲩' => '𐳩',
76185 '𐲪' => '𐳪',
76186 '𐲫' => '𐳫',
76187 '𐲬' => '𐳬',
76188 '𐲭' => '𐳭',
76189 '𐲮' => '𐳮',
76190 '𐲯' => '𐳯',
76191 '𐲰' => '𐳰',
76192 '𐲱' => '𐳱',
76193 '𐲲' => '𐳲',
76194 '𑢠' => '𑣀',
76195 '𑢡' => '𑣁',
76196 '𑢢' => '𑣂',
76197 '𑢣' => '𑣃',
76198 '𑢤' => '𑣄',
76199 '𑢥' => '𑣅',
76200 '𑢦' => '𑣆',
76201 '𑢧' => '𑣇',
76202 '𑢨' => '𑣈',
76203 '𑢩' => '𑣉',
76204 '𑢪' => '𑣊',
76205 '𑢫' => '𑣋',
76206 '𑢬' => '𑣌',
76207 '𑢭' => '𑣍',
76208 '𑢮' => '𑣎',
76209 '𑢯' => '𑣏',
76210 '𑢰' => '𑣐',
76211 '𑢱' => '𑣑',
76212 '𑢲' => '𑣒',
76213 '𑢳' => '𑣓',
76214 '𑢴' => '𑣔',
76215 '𑢵' => '𑣕',
76216 '𑢶' => '𑣖',
76217 '𑢷' => '𑣗',
76218 '𑢸' => '𑣘',
76219 '𑢹' => '𑣙',
76220 '𑢺' => '𑣚',
76221 '𑢻' => '𑣛',
76222 '𑢼' => '𑣜',
76223 '𑢽' => '𑣝',
76224 '𑢾' => '𑣞',
76225 '𑢿' => '𑣟',
76226 '𖹀' => '𖹠',
76227 '𖹁' => '𖹡',
76228 '𖹂' => '𖹢',
76229 '𖹃' => '𖹣',
76230 '𖹄' => '𖹤',
76231 '𖹅' => '𖹥',
76232 '𖹆' => '𖹦',
76233 '𖹇' => '𖹧',
76234 '𖹈' => '𖹨',
76235 '𖹉' => '𖹩',
76236 '𖹊' => '𖹪',
76237 '𖹋' => '𖹫',
76238 '𖹌' => '𖹬',
76239 '𖹍' => '𖹭',
76240 '𖹎' => '𖹮',
76241 '𖹏' => '𖹯',
76242 '𖹐' => '𖹰',
76243 '𖹑' => '𖹱',
76244 '𖹒' => '𖹲',
76245 '𖹓' => '𖹳',
76246 '𖹔' => '𖹴',
76247 '𖹕' => '𖹵',
76248 '𖹖' => '𖹶',
76249 '𖹗' => '𖹷',
76250 '𖹘' => '𖹸',
76251 '𖹙' => '𖹹',
76252 '𖹚' => '𖹺',
76253 '𖹛' => '𖹻',
76254 '𖹜' => '𖹼',
76255 '𖹝' => '𖹽',
76256 '𖹞' => '𖹾',
76257 '𖹟' => '𖹿',
76258 '𞤀' => '𞤢',
76259 '𞤁' => '𞤣',
76260 '𞤂' => '𞤤',
76261 '𞤃' => '𞤥',
76262 '𞤄' => '𞤦',
76263 '𞤅' => '𞤧',
76264 '𞤆' => '𞤨',
76265 '𞤇' => '𞤩',
76266 '𞤈' => '𞤪',
76267 '𞤉' => '𞤫',
76268 '𞤊' => '𞤬',
76269 '𞤋' => '𞤭',
76270 '𞤌' => '𞤮',
76271 '𞤍' => '𞤯',
76272 '𞤎' => '𞤰',
76273 '𞤏' => '𞤱',
76274 '𞤐' => '𞤲',
76275 '𞤑' => '𞤳',
76276 '𞤒' => '𞤴',
76277 '𞤓' => '𞤵',
76278 '𞤔' => '𞤶',
76279 '𞤕' => '𞤷',
76280 '𞤖' => '𞤸',
76281 '𞤗' => '𞤹',
76282 '𞤘' => '𞤺',
76283 '𞤙' => '𞤻',
76284 '𞤚' => '𞤼',
76285 '𞤛' => '𞤽',
76286 '𞤜' => '𞤾',
76287 '𞤝' => '𞤿',
76288 '𞤞' => '𞥀',
76289 '𞤟' => '𞥁',
76290 '𞤠' => '𞥂',
76291 '𞤡' => '𞥃',
76292 );
76293 <?php
76294
76295
76296
76297 return '/(?<![\x{0027}\x{002E}\x{003A}\x{005E}\x{0060}\x{00A8}\x{00AD}\x{00AF}\x{00B4}\x{00B7}\x{00B8}\x{02B0}-\x{02C1}\x{02C2}-\x{02C5}\x{02C6}-\x{02D1}\x{02D2}-\x{02DF}\x{02E0}-\x{02E4}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EE}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037A}\x{0384}-\x{0385}\x{0387}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0559}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{05F4}\x{0600}-\x{0605}\x{0610}-\x{061A}\x{061C}\x{0640}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DD}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\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{07F4}-\x{07F5}\x{07FA}\x{07FD}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{0859}-\x{085B}\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{0971}\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{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{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E46}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EB9}\x{0EBB}-\x{0EBC}\x{0EC6}\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{10FC}\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{17D7}\x{17DD}\x{180B}-\x{180D}\x{180E}\x{1843}\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{1AA7}\x{1AB0}-\x{1ABD}\x{1ABE}\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{1C78}-\x{1C7D}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1D2C}-\x{1D6A}\x{1D78}\x{1D9B}-\x{1DBF}\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{200F}\x{2018}\x{2019}\x{2024}\x{2027}\x{202A}-\x{202E}\x{2060}-\x{2064}\x{2066}-\x{206F}\x{2071}\x{207F}\x{2090}-\x{209C}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2C7C}-\x{2C7D}\x{2CEF}-\x{2CF1}\x{2D6F}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E2F}\x{3005}\x{302A}-\x{302D}\x{3031}-\x{3035}\x{303B}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{309D}-\x{309E}\x{30FC}-\x{30FE}\x{A015}\x{A4F8}-\x{A4FD}\x{A60C}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A67F}\x{A69C}-\x{A69D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A770}\x{A788}\x{A789}-\x{A78A}\x{A7F8}-\x{A7F9}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\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{A9CF}\x{A9E5}\x{A9E6}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA70}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AADD}\x{AAEC}-\x{AAED}\x{AAF3}-\x{AAF4}\x{AAF6}\x{AB5B}\x{AB5C}-\x{AB5F}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FBB2}-\x{FBC1}\x{FE00}-\x{FE0F}\x{FE13}\x{FE20}-\x{FE2F}\x{FE52}\x{FE55}\x{FEFF}\x{FF07}\x{FF0E}\x{FF1A}\x{FF3E}\x{FF40}\x{FF70}\x{FF9E}-\x{FF9F}\x{FFE3}\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{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{110BD}\x{110CD}\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{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{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{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16B40}-\x{16B43}\x{16F8F}-\x{16F92}\x{16F93}-\x{16F9F}\x{16FE0}-\x{16FE1}\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{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{1F3FB}-\x{1F3FF}\x{E0001}\x{E0020}-\x{E007F}\x{E0100}-\x{E01EF}])(\pL)(\pL*+)/u';
76298 <?php
76299
76300 return array (
76301 'a' => 'A',
76302 'b' => 'B',
76303 'c' => 'C',
76304 'd' => 'D',
76305 'e' => 'E',
76306 'f' => 'F',
76307 'g' => 'G',
76308 'h' => 'H',
76309 'i' => 'I',
76310 'j' => 'J',
76311 'k' => 'K',
76312 'l' => 'L',
76313 'm' => 'M',
76314 'n' => 'N',
76315 'o' => 'O',
76316 'p' => 'P',
76317 'q' => 'Q',
76318 'r' => 'R',
76319 's' => 'S',
76320 't' => 'T',
76321 'u' => 'U',
76322 'v' => 'V',
76323 'w' => 'W',
76324 'x' => 'X',
76325 'y' => 'Y',
76326 'z' => 'Z',
76327 'µ' => 'Μ',
76328 'à' => 'À',
76329 'á' => 'Á',
76330 'â' => 'Â',
76331 'ã' => 'Ã',
76332 'ä' => 'Ä',
76333 'å' => 'Å',
76334 'æ' => 'Æ',
76335 'ç' => 'Ç',
76336 'è' => 'È',
76337 'é' => 'É',
76338 'ê' => 'Ê',
76339 'ë' => 'Ë',
76340 'ì' => 'Ì',
76341 'í' => 'Í',
76342 'î' => 'Î',
76343 'ï' => 'Ï',
76344 'ð' => 'Ð',
76345 'ñ' => 'Ñ',
76346 'ò' => 'Ò',
76347 'ó' => 'Ó',
76348 'ô' => 'Ô',
76349 'õ' => 'Õ',
76350 'ö' => 'Ö',
76351 'ø' => 'Ø',
76352 'ù' => 'Ù',
76353 'ú' => 'Ú',
76354 'û' => 'Û',
76355 'ü' => 'Ü',
76356 'ý' => 'Ý',
76357 'þ' => 'Þ',
76358 'ÿ' => 'Ÿ',
76359 'ā' => 'Ā',
76360 'ă' => 'Ă',
76361 'ą' => 'Ą',
76362 'ć' => 'Ć',
76363 'ĉ' => 'Ĉ',
76364 'ċ' => 'Ċ',
76365 'č' => 'Č',
76366 'ď' => 'Ď',
76367 'đ' => 'Đ',
76368 'ē' => 'Ē',
76369 'ĕ' => 'Ĕ',
76370 'ė' => 'Ė',
76371 'ę' => 'Ę',
76372 'ě' => 'Ě',
76373 'ĝ' => 'Ĝ',
76374 'ğ' => 'Ğ',
76375 'ġ' => 'Ġ',
76376 'ģ' => 'Ģ',
76377 'ĥ' => 'Ĥ',
76378 'ħ' => 'Ħ',
76379 'ĩ' => 'Ĩ',
76380 'ī' => 'Ī',
76381 'ĭ' => 'Ĭ',
76382 'į' => 'Į',
76383 'ı' => 'I',
76384 'ij' => 'IJ',
76385 'ĵ' => 'Ĵ',
76386 'ķ' => 'Ķ',
76387 'ĺ' => 'Ĺ',
76388 'ļ' => 'Ļ',
76389 'ľ' => 'Ľ',
76390 'ŀ' => 'Ŀ',
76391 'ł' => 'Ł',
76392 'ń' => 'Ń',
76393 'ņ' => 'Ņ',
76394 'ň' => 'Ň',
76395 'ŋ' => 'Ŋ',
76396 'ō' => 'Ō',
76397 'ŏ' => 'Ŏ',
76398 'ő' => 'Ő',
76399 'œ' => 'Œ',
76400 'ŕ' => 'Ŕ',
76401 'ŗ' => 'Ŗ',
76402 'ř' => 'Ř',
76403 'ś' => 'Ś',
76404 'ŝ' => 'Ŝ',
76405 'ş' => 'Ş',
76406 'š' => 'Š',
76407 'ţ' => 'Ţ',
76408 'ť' => 'Ť',
76409 'ŧ' => 'Ŧ',
76410 'ũ' => 'Ũ',
76411 'ū' => 'Ū',
76412 'ŭ' => 'Ŭ',
76413 'ů' => 'Ů',
76414 'ű' => 'Ű',
76415 'ų' => 'Ų',
76416 'ŵ' => 'Ŵ',
76417 'ŷ' => 'Ŷ',
76418 'ź' => 'Ź',
76419 'ż' => 'Ż',
76420 'ž' => 'Ž',
76421 'ſ' => 'S',
76422 'ƀ' => 'Ƀ',
76423 'ƃ' => 'Ƃ',
76424 'ƅ' => 'Ƅ',
76425 'ƈ' => 'Ƈ',
76426 'ƌ' => 'Ƌ',
76427 'ƒ' => 'Ƒ',
76428 'ƕ' => 'Ƕ',
76429 'ƙ' => 'Ƙ',
76430 'ƚ' => 'Ƚ',
76431 'ƞ' => 'Ƞ',
76432 'ơ' => 'Ơ',
76433 'ƣ' => 'Ƣ',
76434 'ƥ' => 'Ƥ',
76435 'ƨ' => 'Ƨ',
76436 'ƭ' => 'Ƭ',
76437 'ư' => 'Ư',
76438 'ƴ' => 'Ƴ',
76439 'ƶ' => 'Ƶ',
76440 'ƹ' => 'Ƹ',
76441 'ƽ' => 'Ƽ',
76442 'ƿ' => 'Ƿ',
76443 'Dž' => 'DŽ',
76444 'dž' => 'DŽ',
76445 'Lj' => 'LJ',
76446 'lj' => 'LJ',
76447 'Nj' => 'NJ',
76448 'nj' => 'NJ',
76449 'ǎ' => 'Ǎ',
76450 'ǐ' => 'Ǐ',
76451 'ǒ' => 'Ǒ',
76452 'ǔ' => 'Ǔ',
76453 'ǖ' => 'Ǖ',
76454 'ǘ' => 'Ǘ',
76455 'ǚ' => 'Ǚ',
76456 'ǜ' => 'Ǜ',
76457 'ǝ' => 'Ǝ',
76458 'ǟ' => 'Ǟ',
76459 'ǡ' => 'Ǡ',
76460 'ǣ' => 'Ǣ',
76461 'ǥ' => 'Ǥ',
76462 'ǧ' => 'Ǧ',
76463 'ǩ' => 'Ǩ',
76464 'ǫ' => 'Ǫ',
76465 'ǭ' => 'Ǭ',
76466 'ǯ' => 'Ǯ',
76467 'Dz' => 'DZ',
76468 'dz' => 'DZ',
76469 'ǵ' => 'Ǵ',
76470 'ǹ' => 'Ǹ',
76471 'ǻ' => 'Ǻ',
76472 'ǽ' => 'Ǽ',
76473 'ǿ' => 'Ǿ',
76474 'ȁ' => 'Ȁ',
76475 'ȃ' => 'Ȃ',
76476 'ȅ' => 'Ȅ',
76477 'ȇ' => 'Ȇ',
76478 'ȉ' => 'Ȉ',
76479 'ȋ' => 'Ȋ',
76480 'ȍ' => 'Ȍ',
76481 'ȏ' => 'Ȏ',
76482 'ȑ' => 'Ȑ',
76483 'ȓ' => 'Ȓ',
76484 'ȕ' => 'Ȕ',
76485 'ȗ' => 'Ȗ',
76486 'ș' => 'Ș',
76487 'ț' => 'Ț',
76488 'ȝ' => 'Ȝ',
76489 'ȟ' => 'Ȟ',
76490 'ȣ' => 'Ȣ',
76491 'ȥ' => 'Ȥ',
76492 'ȧ' => 'Ȧ',
76493 'ȩ' => 'Ȩ',
76494 'ȫ' => 'Ȫ',
76495 'ȭ' => 'Ȭ',
76496 'ȯ' => 'Ȯ',
76497 'ȱ' => 'Ȱ',
76498 'ȳ' => 'Ȳ',
76499 'ȼ' => 'Ȼ',
76500 'ȿ' => 'Ȿ',
76501 'ɀ' => 'Ɀ',
76502 'ɂ' => 'Ɂ',
76503 'ɇ' => 'Ɇ',
76504 'ɉ' => 'Ɉ',
76505 'ɋ' => 'Ɋ',
76506 'ɍ' => 'Ɍ',
76507 'ɏ' => 'Ɏ',
76508 'ɐ' => 'Ɐ',
76509 'ɑ' => 'Ɑ',
76510 'ɒ' => 'Ɒ',
76511 'ɓ' => 'Ɓ',
76512 'ɔ' => 'Ɔ',
76513 'ɖ' => 'Ɖ',
76514 'ɗ' => 'Ɗ',
76515 'ə' => 'Ə',
76516 'ɛ' => 'Ɛ',
76517 'ɜ' => 'Ɜ',
76518 'ɠ' => 'Ɠ',
76519 'ɡ' => 'Ɡ',
76520 'ɣ' => 'Ɣ',
76521 'ɥ' => 'Ɥ',
76522 'ɦ' => 'Ɦ',
76523 'ɨ' => 'Ɨ',
76524 'ɩ' => 'Ɩ',
76525 'ɪ' => 'Ɪ',
76526 'ɫ' => 'Ɫ',
76527 'ɬ' => 'Ɬ',
76528 'ɯ' => 'Ɯ',
76529 'ɱ' => 'Ɱ',
76530 'ɲ' => 'Ɲ',
76531 'ɵ' => 'Ɵ',
76532 'ɽ' => 'Ɽ',
76533 'ʀ' => 'Ʀ',
76534 'ʂ' => 'Ʂ',
76535 'ʃ' => 'Ʃ',
76536 'ʇ' => 'Ʇ',
76537 'ʈ' => 'Ʈ',
76538 'ʉ' => 'Ʉ',
76539 'ʊ' => 'Ʊ',
76540 'ʋ' => 'Ʋ',
76541 'ʌ' => 'Ʌ',
76542 'ʒ' => 'Ʒ',
76543 'ʝ' => 'Ʝ',
76544 'ʞ' => 'Ʞ',
76545 'ͅ' => 'Ι',
76546 'ͱ' => 'Ͱ',
76547 'ͳ' => 'Ͳ',
76548 'ͷ' => 'Ͷ',
76549 'ͻ' => 'Ͻ',
76550 'ͼ' => 'Ͼ',
76551 'ͽ' => 'Ͽ',
76552 'ά' => 'Ά',
76553 'έ' => 'Έ',
76554 'ή' => 'Ή',
76555 'ί' => 'Ί',
76556 'α' => 'Α',
76557 'β' => 'Β',
76558 'γ' => 'Γ',
76559 'δ' => 'Δ',
76560 'ε' => 'Ε',
76561 'ζ' => 'Ζ',
76562 'η' => 'Η',
76563 'θ' => 'Θ',
76564 'ι' => 'Ι',
76565 'κ' => 'Κ',
76566 'λ' => 'Λ',
76567 'μ' => 'Μ',
76568 'ν' => 'Ν',
76569 'ξ' => 'Ξ',
76570 'ο' => 'Ο',
76571 'π' => 'Π',
76572 'ρ' => 'Ρ',
76573 'ς' => 'Σ',
76574 'σ' => 'Σ',
76575 'τ' => 'Τ',
76576 'υ' => 'Υ',
76577 'φ' => 'Φ',
76578 'χ' => 'Χ',
76579 'ψ' => 'Ψ',
76580 'ω' => 'Ω',
76581 'ϊ' => 'Ϊ',
76582 'ϋ' => 'Ϋ',
76583 'ό' => 'Ό',
76584 'ύ' => 'Ύ',
76585 'ώ' => 'Ώ',
76586 'ϐ' => 'Β',
76587 'ϑ' => 'Θ',
76588 'ϕ' => 'Φ',
76589 'ϖ' => 'Π',
76590 'ϗ' => 'Ϗ',
76591 'ϙ' => 'Ϙ',
76592 'ϛ' => 'Ϛ',
76593 'ϝ' => 'Ϝ',
76594 'ϟ' => 'Ϟ',
76595 'ϡ' => 'Ϡ',
76596 'ϣ' => 'Ϣ',
76597 'ϥ' => 'Ϥ',
76598 'ϧ' => 'Ϧ',
76599 'ϩ' => 'Ϩ',
76600 'ϫ' => 'Ϫ',
76601 'ϭ' => 'Ϭ',
76602 'ϯ' => 'Ϯ',
76603 'ϰ' => 'Κ',
76604 'ϱ' => 'Ρ',
76605 'ϲ' => 'Ϲ',
76606 'ϳ' => 'Ϳ',
76607 'ϵ' => 'Ε',
76608 'ϸ' => 'Ϸ',
76609 'ϻ' => 'Ϻ',
76610 'а' => 'А',
76611 'б' => 'Б',
76612 'в' => 'В',
76613 'г' => 'Г',
76614 'д' => 'Д',
76615 'е' => 'Е',
76616 'ж' => 'Ж',
76617 'з' => 'З',
76618 'и' => 'И',
76619 'й' => 'Й',
76620 'к' => 'К',
76621 'л' => 'Л',
76622 'м' => 'М',
76623 'н' => 'Н',
76624 'о' => 'О',
76625 'п' => 'П',
76626 'р' => 'Р',
76627 'с' => 'С',
76628 'т' => 'Т',
76629 'у' => 'У',
76630 'ф' => 'Ф',
76631 'х' => 'Х',
76632 'ц' => 'Ц',
76633 'ч' => 'Ч',
76634 'ш' => 'Ш',
76635 'щ' => 'Щ',
76636 'ъ' => 'Ъ',
76637 'ы' => 'Ы',
76638 'ь' => 'Ь',
76639 'э' => 'Э',
76640 'ю' => 'Ю',
76641 'я' => 'Я',
76642 'ѐ' => 'Ѐ',
76643 'ё' => 'Ё',
76644 'ђ' => 'Ђ',
76645 'ѓ' => 'Ѓ',
76646 'є' => 'Є',
76647 'ѕ' => 'Ѕ',
76648 'і' => 'І',
76649 'ї' => 'Ї',
76650 'ј' => 'Ј',
76651 'љ' => 'Љ',
76652 'њ' => 'Њ',
76653 'ћ' => 'Ћ',
76654 'ќ' => 'Ќ',
76655 'ѝ' => 'Ѝ',
76656 'ў' => 'Ў',
76657 'џ' => 'Џ',
76658 'ѡ' => 'Ѡ',
76659 'ѣ' => 'Ѣ',
76660 'ѥ' => 'Ѥ',
76661 'ѧ' => 'Ѧ',
76662 'ѩ' => 'Ѩ',
76663 'ѫ' => 'Ѫ',
76664 'ѭ' => 'Ѭ',
76665 'ѯ' => 'Ѯ',
76666 'ѱ' => 'Ѱ',
76667 'ѳ' => 'Ѳ',
76668 'ѵ' => 'Ѵ',
76669 'ѷ' => 'Ѷ',
76670 'ѹ' => 'Ѹ',
76671 'ѻ' => 'Ѻ',
76672 'ѽ' => 'Ѽ',
76673 'ѿ' => 'Ѿ',
76674 'ҁ' => 'Ҁ',
76675 'ҋ' => 'Ҋ',
76676 'ҍ' => 'Ҍ',
76677 'ҏ' => 'Ҏ',
76678 'ґ' => 'Ґ',
76679 'ғ' => 'Ғ',
76680 'ҕ' => 'Ҕ',
76681 'җ' => 'Җ',
76682 'ҙ' => 'Ҙ',
76683 'қ' => 'Қ',
76684 'ҝ' => 'Ҝ',
76685 'ҟ' => 'Ҟ',
76686 'ҡ' => 'Ҡ',
76687 'ң' => 'Ң',
76688 'ҥ' => 'Ҥ',
76689 'ҧ' => 'Ҧ',
76690 'ҩ' => 'Ҩ',
76691 'ҫ' => 'Ҫ',
76692 'ҭ' => 'Ҭ',
76693 'ү' => 'Ү',
76694 'ұ' => 'Ұ',
76695 'ҳ' => 'Ҳ',
76696 'ҵ' => 'Ҵ',
76697 'ҷ' => 'Ҷ',
76698 'ҹ' => 'Ҹ',
76699 'һ' => 'Һ',
76700 'ҽ' => 'Ҽ',
76701 'ҿ' => 'Ҿ',
76702 'ӂ' => 'Ӂ',
76703 'ӄ' => 'Ӄ',
76704 'ӆ' => 'Ӆ',
76705 'ӈ' => 'Ӈ',
76706 'ӊ' => 'Ӊ',
76707 'ӌ' => 'Ӌ',
76708 'ӎ' => 'Ӎ',
76709 'ӏ' => 'Ӏ',
76710 'ӑ' => 'Ӑ',
76711 'ӓ' => 'Ӓ',
76712 'ӕ' => 'Ӕ',
76713 'ӗ' => 'Ӗ',
76714 'ә' => 'Ә',
76715 'ӛ' => 'Ӛ',
76716 'ӝ' => 'Ӝ',
76717 'ӟ' => 'Ӟ',
76718 'ӡ' => 'Ӡ',
76719 'ӣ' => 'Ӣ',
76720 'ӥ' => 'Ӥ',
76721 'ӧ' => 'Ӧ',
76722 'ө' => 'Ө',
76723 'ӫ' => 'Ӫ',
76724 'ӭ' => 'Ӭ',
76725 'ӯ' => 'Ӯ',
76726 'ӱ' => 'Ӱ',
76727 'ӳ' => 'Ӳ',
76728 'ӵ' => 'Ӵ',
76729 'ӷ' => 'Ӷ',
76730 'ӹ' => 'Ӹ',
76731 'ӻ' => 'Ӻ',
76732 'ӽ' => 'Ӽ',
76733 'ӿ' => 'Ӿ',
76734 'ԁ' => 'Ԁ',
76735 'ԃ' => 'Ԃ',
76736 'ԅ' => 'Ԅ',
76737 'ԇ' => 'Ԇ',
76738 'ԉ' => 'Ԉ',
76739 'ԋ' => 'Ԋ',
76740 'ԍ' => 'Ԍ',
76741 'ԏ' => 'Ԏ',
76742 'ԑ' => 'Ԑ',
76743 'ԓ' => 'Ԓ',
76744 'ԕ' => 'Ԕ',
76745 'ԗ' => 'Ԗ',
76746 'ԙ' => 'Ԙ',
76747 'ԛ' => 'Ԛ',
76748 'ԝ' => 'Ԝ',
76749 'ԟ' => 'Ԟ',
76750 'ԡ' => 'Ԡ',
76751 'ԣ' => 'Ԣ',
76752 'ԥ' => 'Ԥ',
76753 'ԧ' => 'Ԧ',
76754 'ԩ' => 'Ԩ',
76755 'ԫ' => 'Ԫ',
76756 'ԭ' => 'Ԭ',
76757 'ԯ' => 'Ԯ',
76758 'ա' => 'Ա',
76759 'բ' => 'Բ',
76760 'գ' => 'Գ',
76761 'դ' => 'Դ',
76762 'ե' => 'Ե',
76763 'զ' => 'Զ',
76764 'է' => 'Է',
76765 'ը' => 'Ը',
76766 'թ' => 'Թ',
76767 'ժ' => 'Ժ',
76768 'ի' => 'Ի',
76769 'լ' => 'Լ',
76770 'խ' => 'Խ',
76771 'ծ' => 'Ծ',
76772 'կ' => 'Կ',
76773 'հ' => 'Հ',
76774 'ձ' => 'Ձ',
76775 'ղ' => 'Ղ',
76776 'ճ' => 'Ճ',
76777 'մ' => 'Մ',
76778 'յ' => 'Յ',
76779 'ն' => 'Ն',
76780 'շ' => 'Շ',
76781 'ո' => 'Ո',
76782 'չ' => 'Չ',
76783 'պ' => 'Պ',
76784 'ջ' => 'Ջ',
76785 'ռ' => 'Ռ',
76786 'ս' => 'Ս',
76787 'վ' => 'Վ',
76788 'տ' => 'Տ',
76789 'ր' => 'Ր',
76790 'ց' => 'Ց',
76791 'ւ' => 'Ւ',
76792 'փ' => 'Փ',
76793 'ք' => 'Ք',
76794 'օ' => 'Օ',
76795 'ֆ' => 'Ֆ',
76796 'ა' => 'Ა',
76797 'ბ' => 'Ბ',
76798 'გ' => 'Გ',
76799 'დ' => 'Დ',
76800 'ე' => 'Ე',
76801 'ვ' => 'Ვ',
76802 'ზ' => 'Ზ',
76803 'თ' => 'Თ',
76804 'ი' => 'Ი',
76805 'კ' => 'Კ',
76806 'ლ' => 'Ლ',
76807 'მ' => 'Მ',
76808 'ნ' => 'Ნ',
76809 'ო' => 'Ო',
76810 'პ' => 'Პ',
76811 'ჟ' => 'Ჟ',
76812 'რ' => 'Რ',
76813 'ს' => 'Ს',
76814 'ტ' => 'Ტ',
76815 'უ' => 'Უ',
76816 'ფ' => 'Ფ',
76817 'ქ' => 'Ქ',
76818 'ღ' => 'Ღ',
76819 'ყ' => 'Ყ',
76820 'შ' => 'Შ',
76821 'ჩ' => 'Ჩ',
76822 'ც' => 'Ც',
76823 'ძ' => 'Ძ',
76824 'წ' => 'Წ',
76825 'ჭ' => 'Ჭ',
76826 'ხ' => 'Ხ',
76827 'ჯ' => 'Ჯ',
76828 'ჰ' => 'Ჰ',
76829 'ჱ' => 'Ჱ',
76830 'ჲ' => 'Ჲ',
76831 'ჳ' => 'Ჳ',
76832 'ჴ' => 'Ჴ',
76833 'ჵ' => 'Ჵ',
76834 'ჶ' => 'Ჶ',
76835 'ჷ' => 'Ჷ',
76836 'ჸ' => 'Ჸ',
76837 'ჹ' => 'Ჹ',
76838 'ჺ' => 'Ჺ',
76839 'ჽ' => 'Ჽ',
76840 'ჾ' => 'Ჾ',
76841 'ჿ' => 'Ჿ',
76842 'ᏸ' => 'Ᏸ',
76843 'ᏹ' => 'Ᏹ',
76844 'ᏺ' => 'Ᏺ',
76845 'ᏻ' => 'Ᏻ',
76846 'ᏼ' => 'Ᏼ',
76847 'ᏽ' => 'Ᏽ',
76848 'ᲀ' => 'В',
76849 'ᲁ' => 'Д',
76850 'ᲂ' => 'О',
76851 'ᲃ' => 'С',
76852 'ᲄ' => 'Т',
76853 'ᲅ' => 'Т',
76854 'ᲆ' => 'Ъ',
76855 'ᲇ' => 'Ѣ',
76856 'ᲈ' => 'Ꙋ',
76857 'ᵹ' => 'Ᵹ',
76858 'ᵽ' => 'Ᵽ',
76859 'ᶎ' => 'Ᶎ',
76860 'ḁ' => 'Ḁ',
76861 'ḃ' => 'Ḃ',
76862 'ḅ' => 'Ḅ',
76863 'ḇ' => 'Ḇ',
76864 'ḉ' => 'Ḉ',
76865 'ḋ' => 'Ḋ',
76866 'ḍ' => 'Ḍ',
76867 'ḏ' => 'Ḏ',
76868 'ḑ' => 'Ḑ',
76869 'ḓ' => 'Ḓ',
76870 'ḕ' => 'Ḕ',
76871 'ḗ' => 'Ḗ',
76872 'ḙ' => 'Ḙ',
76873 'ḛ' => 'Ḛ',
76874 'ḝ' => 'Ḝ',
76875 'ḟ' => 'Ḟ',
76876 'ḡ' => 'Ḡ',
76877 'ḣ' => 'Ḣ',
76878 'ḥ' => 'Ḥ',
76879 'ḧ' => 'Ḧ',
76880 'ḩ' => 'Ḩ',
76881 'ḫ' => 'Ḫ',
76882 'ḭ' => 'Ḭ',
76883 'ḯ' => 'Ḯ',
76884 'ḱ' => 'Ḱ',
76885 'ḳ' => 'Ḳ',
76886 'ḵ' => 'Ḵ',
76887 'ḷ' => 'Ḷ',
76888 'ḹ' => 'Ḹ',
76889 'ḻ' => 'Ḻ',
76890 'ḽ' => 'Ḽ',
76891 'ḿ' => 'Ḿ',
76892 'ṁ' => 'Ṁ',
76893 'ṃ' => 'Ṃ',
76894 'ṅ' => 'Ṅ',
76895 'ṇ' => 'Ṇ',
76896 'ṉ' => 'Ṉ',
76897 'ṋ' => 'Ṋ',
76898 'ṍ' => 'Ṍ',
76899 'ṏ' => 'Ṏ',
76900 'ṑ' => 'Ṑ',
76901 'ṓ' => 'Ṓ',
76902 'ṕ' => 'Ṕ',
76903 'ṗ' => 'Ṗ',
76904 'ṙ' => 'Ṙ',
76905 'ṛ' => 'Ṛ',
76906 'ṝ' => 'Ṝ',
76907 'ṟ' => 'Ṟ',
76908 'ṡ' => 'Ṡ',
76909 'ṣ' => 'Ṣ',
76910 'ṥ' => 'Ṥ',
76911 'ṧ' => 'Ṧ',
76912 'ṩ' => 'Ṩ',
76913 'ṫ' => 'Ṫ',
76914 'ṭ' => 'Ṭ',
76915 'ṯ' => 'Ṯ',
76916 'ṱ' => 'Ṱ',
76917 'ṳ' => 'Ṳ',
76918 'ṵ' => 'Ṵ',
76919 'ṷ' => 'Ṷ',
76920 'ṹ' => 'Ṹ',
76921 'ṻ' => 'Ṻ',
76922 'ṽ' => 'Ṽ',
76923 'ṿ' => 'Ṿ',
76924 'ẁ' => 'Ẁ',
76925 'ẃ' => 'Ẃ',
76926 'ẅ' => 'Ẅ',
76927 'ẇ' => 'Ẇ',
76928 'ẉ' => 'Ẉ',
76929 'ẋ' => 'Ẋ',
76930 'ẍ' => 'Ẍ',
76931 'ẏ' => 'Ẏ',
76932 'ẑ' => 'Ẑ',
76933 'ẓ' => 'Ẓ',
76934 'ẕ' => 'Ẕ',
76935 'ẛ' => 'Ṡ',
76936 'ạ' => 'Ạ',
76937 'ả' => 'Ả',
76938 'ấ' => 'Ấ',
76939 'ầ' => 'Ầ',
76940 'ẩ' => 'Ẩ',
76941 'ẫ' => 'Ẫ',
76942 'ậ' => 'Ậ',
76943 'ắ' => 'Ắ',
76944 'ằ' => 'Ằ',
76945 'ẳ' => 'Ẳ',
76946 'ẵ' => 'Ẵ',
76947 'ặ' => 'Ặ',
76948 'ẹ' => 'Ẹ',
76949 'ẻ' => 'Ẻ',
76950 'ẽ' => 'Ẽ',
76951 'ế' => 'Ế',
76952 'ề' => 'Ề',
76953 'ể' => 'Ể',
76954 'ễ' => 'Ễ',
76955 'ệ' => 'Ệ',
76956 'ỉ' => 'Ỉ',
76957 'ị' => 'Ị',
76958 'ọ' => 'Ọ',
76959 'ỏ' => 'Ỏ',
76960 'ố' => 'Ố',
76961 'ồ' => 'Ồ',
76962 'ổ' => 'Ổ',
76963 'ỗ' => 'Ỗ',
76964 'ộ' => 'Ộ',
76965 'ớ' => 'Ớ',
76966 'ờ' => 'Ờ',
76967 'ở' => 'Ở',
76968 'ỡ' => 'Ỡ',
76969 'ợ' => 'Ợ',
76970 'ụ' => 'Ụ',
76971 'ủ' => 'Ủ',
76972 'ứ' => 'Ứ',
76973 'ừ' => 'Ừ',
76974 'ử' => 'Ử',
76975 'ữ' => 'Ữ',
76976 'ự' => 'Ự',
76977 'ỳ' => 'Ỳ',
76978 'ỵ' => 'Ỵ',
76979 'ỷ' => 'Ỷ',
76980 'ỹ' => 'Ỹ',
76981 'ỻ' => 'Ỻ',
76982 'ỽ' => 'Ỽ',
76983 'ỿ' => 'Ỿ',
76984 'ἀ' => 'Ἀ',
76985 'ἁ' => 'Ἁ',
76986 'ἂ' => 'Ἂ',
76987 'ἃ' => 'Ἃ',
76988 'ἄ' => 'Ἄ',
76989 'ἅ' => 'Ἅ',
76990 'ἆ' => 'Ἆ',
76991 'ἇ' => 'Ἇ',
76992 'ἐ' => 'Ἐ',
76993 'ἑ' => 'Ἑ',
76994 'ἒ' => 'Ἒ',
76995 'ἓ' => 'Ἓ',
76996 'ἔ' => 'Ἔ',
76997 'ἕ' => 'Ἕ',
76998 'ἠ' => 'Ἠ',
76999 'ἡ' => 'Ἡ',
77000 'ἢ' => 'Ἢ',
77001 'ἣ' => 'Ἣ',
77002 'ἤ' => 'Ἤ',
77003 'ἥ' => 'Ἥ',
77004 'ἦ' => 'Ἦ',
77005 'ἧ' => 'Ἧ',
77006 'ἰ' => 'Ἰ',
77007 'ἱ' => 'Ἱ',
77008 'ἲ' => 'Ἲ',
77009 'ἳ' => 'Ἳ',
77010 'ἴ' => 'Ἴ',
77011 'ἵ' => 'Ἵ',
77012 'ἶ' => 'Ἶ',
77013 'ἷ' => 'Ἷ',
77014 'ὀ' => 'Ὀ',
77015 'ὁ' => 'Ὁ',
77016 'ὂ' => 'Ὂ',
77017 'ὃ' => 'Ὃ',
77018 'ὄ' => 'Ὄ',
77019 'ὅ' => 'Ὅ',
77020 'ὑ' => 'Ὑ',
77021 'ὓ' => 'Ὓ',
77022 'ὕ' => 'Ὕ',
77023 'ὗ' => 'Ὗ',
77024 'ὠ' => 'Ὠ',
77025 'ὡ' => 'Ὡ',
77026 'ὢ' => 'Ὢ',
77027 'ὣ' => 'Ὣ',
77028 'ὤ' => 'Ὤ',
77029 'ὥ' => 'Ὥ',
77030 'ὦ' => 'Ὦ',
77031 'ὧ' => 'Ὧ',
77032 'ὰ' => 'Ὰ',
77033 'ά' => 'Ά',
77034 'ὲ' => 'Ὲ',
77035 'έ' => 'Έ',
77036 'ὴ' => 'Ὴ',
77037 'ή' => 'Ή',
77038 'ὶ' => 'Ὶ',
77039 'ί' => 'Ί',
77040 'ὸ' => 'Ὸ',
77041 'ό' => 'Ό',
77042 'ὺ' => 'Ὺ',
77043 'ύ' => 'Ύ',
77044 'ὼ' => 'Ὼ',
77045 'ώ' => 'Ώ',
77046 'ᾀ' => 'ᾈ',
77047 'ᾁ' => 'ᾉ',
77048 'ᾂ' => 'ᾊ',
77049 'ᾃ' => 'ᾋ',
77050 'ᾄ' => 'ᾌ',
77051 'ᾅ' => 'ᾍ',
77052 'ᾆ' => 'ᾎ',
77053 'ᾇ' => 'ᾏ',
77054 'ᾐ' => 'ᾘ',
77055 'ᾑ' => 'ᾙ',
77056 'ᾒ' => 'ᾚ',
77057 'ᾓ' => 'ᾛ',
77058 'ᾔ' => 'ᾜ',
77059 'ᾕ' => 'ᾝ',
77060 'ᾖ' => 'ᾞ',
77061 'ᾗ' => 'ᾟ',
77062 'ᾠ' => 'ᾨ',
77063 'ᾡ' => 'ᾩ',
77064 'ᾢ' => 'ᾪ',
77065 'ᾣ' => 'ᾫ',
77066 'ᾤ' => 'ᾬ',
77067 'ᾥ' => 'ᾭ',
77068 'ᾦ' => 'ᾮ',
77069 'ᾧ' => 'ᾯ',
77070 'ᾰ' => 'Ᾰ',
77071 'ᾱ' => 'Ᾱ',
77072 'ᾳ' => 'ᾼ',
77073 'ι' => 'Ι',
77074 'ῃ' => 'ῌ',
77075 'ῐ' => 'Ῐ',
77076 'ῑ' => 'Ῑ',
77077 'ῠ' => 'Ῠ',
77078 'ῡ' => 'Ῡ',
77079 'ῥ' => 'Ῥ',
77080 'ῳ' => 'ῼ',
77081 'ⅎ' => 'Ⅎ',
77082 'ⅰ' => 'Ⅰ',
77083 'ⅱ' => 'Ⅱ',
77084 'ⅲ' => 'Ⅲ',
77085 'ⅳ' => 'Ⅳ',
77086 'ⅴ' => 'Ⅴ',
77087 'ⅵ' => 'Ⅵ',
77088 'ⅶ' => 'Ⅶ',
77089 'ⅷ' => 'Ⅷ',
77090 'ⅸ' => 'Ⅸ',
77091 'ⅹ' => 'Ⅹ',
77092 'ⅺ' => 'Ⅺ',
77093 'ⅻ' => 'Ⅻ',
77094 'ⅼ' => 'Ⅼ',
77095 'ⅽ' => 'Ⅽ',
77096 'ⅾ' => 'Ⅾ',
77097 'ⅿ' => 'Ⅿ',
77098 'ↄ' => 'Ↄ',
77099 'ⓐ' => 'Ⓐ',
77100 'ⓑ' => 'Ⓑ',
77101 'ⓒ' => 'Ⓒ',
77102 'ⓓ' => 'Ⓓ',
77103 'ⓔ' => 'Ⓔ',
77104 'ⓕ' => 'Ⓕ',
77105 'ⓖ' => 'Ⓖ',
77106 'ⓗ' => 'Ⓗ',
77107 'ⓘ' => 'Ⓘ',
77108 'ⓙ' => 'Ⓙ',
77109 'ⓚ' => 'Ⓚ',
77110 'ⓛ' => 'Ⓛ',
77111 'ⓜ' => 'Ⓜ',
77112 'ⓝ' => 'Ⓝ',
77113 'ⓞ' => 'Ⓞ',
77114 'ⓟ' => 'Ⓟ',
77115 'ⓠ' => 'Ⓠ',
77116 'ⓡ' => 'Ⓡ',
77117 'ⓢ' => 'Ⓢ',
77118 'ⓣ' => 'Ⓣ',
77119 'ⓤ' => 'Ⓤ',
77120 'ⓥ' => 'Ⓥ',
77121 'ⓦ' => 'Ⓦ',
77122 'ⓧ' => 'Ⓧ',
77123 'ⓨ' => 'Ⓨ',
77124 'ⓩ' => 'Ⓩ',
77125 'ⰰ' => 'Ⰰ',
77126 'ⰱ' => 'Ⰱ',
77127 'ⰲ' => 'Ⰲ',
77128 'ⰳ' => 'Ⰳ',
77129 'ⰴ' => 'Ⰴ',
77130 'ⰵ' => 'Ⰵ',
77131 'ⰶ' => 'Ⰶ',
77132 'ⰷ' => 'Ⰷ',
77133 'ⰸ' => 'Ⰸ',
77134 'ⰹ' => 'Ⰹ',
77135 'ⰺ' => 'Ⰺ',
77136 'ⰻ' => 'Ⰻ',
77137 'ⰼ' => 'Ⰼ',
77138 'ⰽ' => 'Ⰽ',
77139 'ⰾ' => 'Ⰾ',
77140 'ⰿ' => 'Ⰿ',
77141 'ⱀ' => 'Ⱀ',
77142 'ⱁ' => 'Ⱁ',
77143 'ⱂ' => 'Ⱂ',
77144 'ⱃ' => 'Ⱃ',
77145 'ⱄ' => 'Ⱄ',
77146 'ⱅ' => 'Ⱅ',
77147 'ⱆ' => 'Ⱆ',
77148 'ⱇ' => 'Ⱇ',
77149 'ⱈ' => 'Ⱈ',
77150 'ⱉ' => 'Ⱉ',
77151 'ⱊ' => 'Ⱊ',
77152 'ⱋ' => 'Ⱋ',
77153 'ⱌ' => 'Ⱌ',
77154 'ⱍ' => 'Ⱍ',
77155 'ⱎ' => 'Ⱎ',
77156 'ⱏ' => 'Ⱏ',
77157 'ⱐ' => 'Ⱐ',
77158 'ⱑ' => 'Ⱑ',
77159 'ⱒ' => 'Ⱒ',
77160 'ⱓ' => 'Ⱓ',
77161 'ⱔ' => 'Ⱔ',
77162 'ⱕ' => 'Ⱕ',
77163 'ⱖ' => 'Ⱖ',
77164 'ⱗ' => 'Ⱗ',
77165 'ⱘ' => 'Ⱘ',
77166 'ⱙ' => 'Ⱙ',
77167 'ⱚ' => 'Ⱚ',
77168 'ⱛ' => 'Ⱛ',
77169 'ⱜ' => 'Ⱜ',
77170 'ⱝ' => 'Ⱝ',
77171 'ⱞ' => 'Ⱞ',
77172 'ⱡ' => 'Ⱡ',
77173 'ⱥ' => 'Ⱥ',
77174 'ⱦ' => 'Ⱦ',
77175 'ⱨ' => 'Ⱨ',
77176 'ⱪ' => 'Ⱪ',
77177 'ⱬ' => 'Ⱬ',
77178 'ⱳ' => 'Ⱳ',
77179 'ⱶ' => 'Ⱶ',
77180 'ⲁ' => 'Ⲁ',
77181 'ⲃ' => 'Ⲃ',
77182 'ⲅ' => 'Ⲅ',
77183 'ⲇ' => 'Ⲇ',
77184 'ⲉ' => 'Ⲉ',
77185 'ⲋ' => 'Ⲋ',
77186 'ⲍ' => 'Ⲍ',
77187 'ⲏ' => 'Ⲏ',
77188 'ⲑ' => 'Ⲑ',
77189 'ⲓ' => 'Ⲓ',
77190 'ⲕ' => 'Ⲕ',
77191 'ⲗ' => 'Ⲗ',
77192 'ⲙ' => 'Ⲙ',
77193 'ⲛ' => 'Ⲛ',
77194 'ⲝ' => 'Ⲝ',
77195 'ⲟ' => 'Ⲟ',
77196 'ⲡ' => 'Ⲡ',
77197 'ⲣ' => 'Ⲣ',
77198 'ⲥ' => 'Ⲥ',
77199 'ⲧ' => 'Ⲧ',
77200 'ⲩ' => 'Ⲩ',
77201 'ⲫ' => 'Ⲫ',
77202 'ⲭ' => 'Ⲭ',
77203 'ⲯ' => 'Ⲯ',
77204 'ⲱ' => 'Ⲱ',
77205 'ⲳ' => 'Ⲳ',
77206 'ⲵ' => 'Ⲵ',
77207 'ⲷ' => 'Ⲷ',
77208 'ⲹ' => 'Ⲹ',
77209 'ⲻ' => 'Ⲻ',
77210 'ⲽ' => 'Ⲽ',
77211 'ⲿ' => 'Ⲿ',
77212 'ⳁ' => 'Ⳁ',
77213 'ⳃ' => 'Ⳃ',
77214 'ⳅ' => 'Ⳅ',
77215 'ⳇ' => 'Ⳇ',
77216 'ⳉ' => 'Ⳉ',
77217 'ⳋ' => 'Ⳋ',
77218 'ⳍ' => 'Ⳍ',
77219 'ⳏ' => 'Ⳏ',
77220 'ⳑ' => 'Ⳑ',
77221 'ⳓ' => 'Ⳓ',
77222 'ⳕ' => 'Ⳕ',
77223 'ⳗ' => 'Ⳗ',
77224 'ⳙ' => 'Ⳙ',
77225 'ⳛ' => 'Ⳛ',
77226 'ⳝ' => 'Ⳝ',
77227 'ⳟ' => 'Ⳟ',
77228 'ⳡ' => 'Ⳡ',
77229 'ⳣ' => 'Ⳣ',
77230 'ⳬ' => 'Ⳬ',
77231 'ⳮ' => 'Ⳮ',
77232 'ⳳ' => 'Ⳳ',
77233 'ⴀ' => 'Ⴀ',
77234 'ⴁ' => 'Ⴁ',
77235 'ⴂ' => 'Ⴂ',
77236 'ⴃ' => 'Ⴃ',
77237 'ⴄ' => 'Ⴄ',
77238 'ⴅ' => 'Ⴅ',
77239 'ⴆ' => 'Ⴆ',
77240 'ⴇ' => 'Ⴇ',
77241 'ⴈ' => 'Ⴈ',
77242 'ⴉ' => 'Ⴉ',
77243 'ⴊ' => 'Ⴊ',
77244 'ⴋ' => 'Ⴋ',
77245 'ⴌ' => 'Ⴌ',
77246 'ⴍ' => 'Ⴍ',
77247 'ⴎ' => 'Ⴎ',
77248 'ⴏ' => 'Ⴏ',
77249 'ⴐ' => 'Ⴐ',
77250 'ⴑ' => 'Ⴑ',
77251 'ⴒ' => 'Ⴒ',
77252 'ⴓ' => 'Ⴓ',
77253 'ⴔ' => 'Ⴔ',
77254 'ⴕ' => 'Ⴕ',
77255 'ⴖ' => 'Ⴖ',
77256 'ⴗ' => 'Ⴗ',
77257 'ⴘ' => 'Ⴘ',
77258 'ⴙ' => 'Ⴙ',
77259 'ⴚ' => 'Ⴚ',
77260 'ⴛ' => 'Ⴛ',
77261 'ⴜ' => 'Ⴜ',
77262 'ⴝ' => 'Ⴝ',
77263 'ⴞ' => 'Ⴞ',
77264 'ⴟ' => 'Ⴟ',
77265 'ⴠ' => 'Ⴠ',
77266 'ⴡ' => 'Ⴡ',
77267 'ⴢ' => 'Ⴢ',
77268 'ⴣ' => 'Ⴣ',
77269 'ⴤ' => 'Ⴤ',
77270 'ⴥ' => 'Ⴥ',
77271 'ⴧ' => 'Ⴧ',
77272 'ⴭ' => 'Ⴭ',
77273 'ꙁ' => 'Ꙁ',
77274 'ꙃ' => 'Ꙃ',
77275 'ꙅ' => 'Ꙅ',
77276 'ꙇ' => 'Ꙇ',
77277 'ꙉ' => 'Ꙉ',
77278 'ꙋ' => 'Ꙋ',
77279 'ꙍ' => 'Ꙍ',
77280 'ꙏ' => 'Ꙏ',
77281 'ꙑ' => 'Ꙑ',
77282 'ꙓ' => 'Ꙓ',
77283 'ꙕ' => 'Ꙕ',
77284 'ꙗ' => 'Ꙗ',
77285 'ꙙ' => 'Ꙙ',
77286 'ꙛ' => 'Ꙛ',
77287 'ꙝ' => 'Ꙝ',
77288 'ꙟ' => 'Ꙟ',
77289 'ꙡ' => 'Ꙡ',
77290 'ꙣ' => 'Ꙣ',
77291 'ꙥ' => 'Ꙥ',
77292 'ꙧ' => 'Ꙧ',
77293 'ꙩ' => 'Ꙩ',
77294 'ꙫ' => 'Ꙫ',
77295 'ꙭ' => 'Ꙭ',
77296 'ꚁ' => 'Ꚁ',
77297 'ꚃ' => 'Ꚃ',
77298 'ꚅ' => 'Ꚅ',
77299 'ꚇ' => 'Ꚇ',
77300 'ꚉ' => 'Ꚉ',
77301 'ꚋ' => 'Ꚋ',
77302 'ꚍ' => 'Ꚍ',
77303 'ꚏ' => 'Ꚏ',
77304 'ꚑ' => 'Ꚑ',
77305 'ꚓ' => 'Ꚓ',
77306 'ꚕ' => 'Ꚕ',
77307 'ꚗ' => 'Ꚗ',
77308 'ꚙ' => 'Ꚙ',
77309 'ꚛ' => 'Ꚛ',
77310 'ꜣ' => 'Ꜣ',
77311 'ꜥ' => 'Ꜥ',
77312 'ꜧ' => 'Ꜧ',
77313 'ꜩ' => 'Ꜩ',
77314 'ꜫ' => 'Ꜫ',
77315 'ꜭ' => 'Ꜭ',
77316 'ꜯ' => 'Ꜯ',
77317 'ꜳ' => 'Ꜳ',
77318 'ꜵ' => 'Ꜵ',
77319 'ꜷ' => 'Ꜷ',
77320 'ꜹ' => 'Ꜹ',
77321 'ꜻ' => 'Ꜻ',
77322 'ꜽ' => 'Ꜽ',
77323 'ꜿ' => 'Ꜿ',
77324 'ꝁ' => 'Ꝁ',
77325 'ꝃ' => 'Ꝃ',
77326 'ꝅ' => 'Ꝅ',
77327 'ꝇ' => 'Ꝇ',
77328 'ꝉ' => 'Ꝉ',
77329 'ꝋ' => 'Ꝋ',
77330 'ꝍ' => 'Ꝍ',
77331 'ꝏ' => 'Ꝏ',
77332 'ꝑ' => 'Ꝑ',
77333 'ꝓ' => 'Ꝓ',
77334 'ꝕ' => 'Ꝕ',
77335 'ꝗ' => 'Ꝗ',
77336 'ꝙ' => 'Ꝙ',
77337 'ꝛ' => 'Ꝛ',
77338 'ꝝ' => 'Ꝝ',
77339 'ꝟ' => 'Ꝟ',
77340 'ꝡ' => 'Ꝡ',
77341 'ꝣ' => 'Ꝣ',
77342 'ꝥ' => 'Ꝥ',
77343 'ꝧ' => 'Ꝧ',
77344 'ꝩ' => 'Ꝩ',
77345 'ꝫ' => 'Ꝫ',
77346 'ꝭ' => 'Ꝭ',
77347 'ꝯ' => 'Ꝯ',
77348 'ꝺ' => 'Ꝺ',
77349 'ꝼ' => 'Ꝼ',
77350 'ꝿ' => 'Ꝿ',
77351 'ꞁ' => 'Ꞁ',
77352 'ꞃ' => 'Ꞃ',
77353 'ꞅ' => 'Ꞅ',
77354 'ꞇ' => 'Ꞇ',
77355 'ꞌ' => 'Ꞌ',
77356 'ꞑ' => 'Ꞑ',
77357 'ꞓ' => 'Ꞓ',
77358 'ꞔ' => 'Ꞔ',
77359 'ꞗ' => 'Ꞗ',
77360 'ꞙ' => 'Ꞙ',
77361 'ꞛ' => 'Ꞛ',
77362 'ꞝ' => 'Ꞝ',
77363 'ꞟ' => 'Ꞟ',
77364 'ꞡ' => 'Ꞡ',
77365 'ꞣ' => 'Ꞣ',
77366 'ꞥ' => 'Ꞥ',
77367 'ꞧ' => 'Ꞧ',
77368 'ꞩ' => 'Ꞩ',
77369 'ꞵ' => 'Ꞵ',
77370 'ꞷ' => 'Ꞷ',
77371 'ꞹ' => 'Ꞹ',
77372 'ꞻ' => 'Ꞻ',
77373 'ꞽ' => 'Ꞽ',
77374 'ꞿ' => 'Ꞿ',
77375 'ꟃ' => 'Ꟃ',
77376 'ꟈ' => 'Ꟈ',
77377 'ꟊ' => 'Ꟊ',
77378 'ꟶ' => 'Ꟶ',
77379 'ꭓ' => 'Ꭓ',
77380 'ꭰ' => 'Ꭰ',
77381 'ꭱ' => 'Ꭱ',
77382 'ꭲ' => 'Ꭲ',
77383 'ꭳ' => 'Ꭳ',
77384 'ꭴ' => 'Ꭴ',
77385 'ꭵ' => 'Ꭵ',
77386 'ꭶ' => 'Ꭶ',
77387 'ꭷ' => 'Ꭷ',
77388 'ꭸ' => 'Ꭸ',
77389 'ꭹ' => 'Ꭹ',
77390 'ꭺ' => 'Ꭺ',
77391 'ꭻ' => 'Ꭻ',
77392 'ꭼ' => 'Ꭼ',
77393 'ꭽ' => 'Ꭽ',
77394 'ꭾ' => 'Ꭾ',
77395 'ꭿ' => 'Ꭿ',
77396 'ꮀ' => 'Ꮀ',
77397 'ꮁ' => 'Ꮁ',
77398 'ꮂ' => 'Ꮂ',
77399 'ꮃ' => 'Ꮃ',
77400 'ꮄ' => 'Ꮄ',
77401 'ꮅ' => 'Ꮅ',
77402 'ꮆ' => 'Ꮆ',
77403 'ꮇ' => 'Ꮇ',
77404 'ꮈ' => 'Ꮈ',
77405 'ꮉ' => 'Ꮉ',
77406 'ꮊ' => 'Ꮊ',
77407 'ꮋ' => 'Ꮋ',
77408 'ꮌ' => 'Ꮌ',
77409 'ꮍ' => 'Ꮍ',
77410 'ꮎ' => 'Ꮎ',
77411 'ꮏ' => 'Ꮏ',
77412 'ꮐ' => 'Ꮐ',
77413 'ꮑ' => 'Ꮑ',
77414 'ꮒ' => 'Ꮒ',
77415 'ꮓ' => 'Ꮓ',
77416 'ꮔ' => 'Ꮔ',
77417 'ꮕ' => 'Ꮕ',
77418 'ꮖ' => 'Ꮖ',
77419 'ꮗ' => 'Ꮗ',
77420 'ꮘ' => 'Ꮘ',
77421 'ꮙ' => 'Ꮙ',
77422 'ꮚ' => 'Ꮚ',
77423 'ꮛ' => 'Ꮛ',
77424 'ꮜ' => 'Ꮜ',
77425 'ꮝ' => 'Ꮝ',
77426 'ꮞ' => 'Ꮞ',
77427 'ꮟ' => 'Ꮟ',
77428 'ꮠ' => 'Ꮠ',
77429 'ꮡ' => 'Ꮡ',
77430 'ꮢ' => 'Ꮢ',
77431 'ꮣ' => 'Ꮣ',
77432 'ꮤ' => 'Ꮤ',
77433 'ꮥ' => 'Ꮥ',
77434 'ꮦ' => 'Ꮦ',
77435 'ꮧ' => 'Ꮧ',
77436 'ꮨ' => 'Ꮨ',
77437 'ꮩ' => 'Ꮩ',
77438 'ꮪ' => 'Ꮪ',
77439 'ꮫ' => 'Ꮫ',
77440 'ꮬ' => 'Ꮬ',
77441 'ꮭ' => 'Ꮭ',
77442 'ꮮ' => 'Ꮮ',
77443 'ꮯ' => 'Ꮯ',
77444 'ꮰ' => 'Ꮰ',
77445 'ꮱ' => 'Ꮱ',
77446 'ꮲ' => 'Ꮲ',
77447 'ꮳ' => 'Ꮳ',
77448 'ꮴ' => 'Ꮴ',
77449 'ꮵ' => 'Ꮵ',
77450 'ꮶ' => 'Ꮶ',
77451 'ꮷ' => 'Ꮷ',
77452 'ꮸ' => 'Ꮸ',
77453 'ꮹ' => 'Ꮹ',
77454 'ꮺ' => 'Ꮺ',
77455 'ꮻ' => 'Ꮻ',
77456 'ꮼ' => 'Ꮼ',
77457 'ꮽ' => 'Ꮽ',
77458 'ꮾ' => 'Ꮾ',
77459 'ꮿ' => 'Ꮿ',
77460 'a' => 'A',
77461 'b' => 'B',
77462 'c' => 'C',
77463 'd' => 'D',
77464 'e' => 'E',
77465 'f' => 'F',
77466 'g' => 'G',
77467 'h' => 'H',
77468 'i' => 'I',
77469 'j' => 'J',
77470 'k' => 'K',
77471 'l' => 'L',
77472 'm' => 'M',
77473 'n' => 'N',
77474 'o' => 'O',
77475 'p' => 'P',
77476 'q' => 'Q',
77477 'r' => 'R',
77478 's' => 'S',
77479 't' => 'T',
77480 'u' => 'U',
77481 'v' => 'V',
77482 'w' => 'W',
77483 'x' => 'X',
77484 'y' => 'Y',
77485 'z' => 'Z',
77486 '𐐨' => '𐐀',
77487 '𐐩' => '𐐁',
77488 '𐐪' => '𐐂',
77489 '𐐫' => '𐐃',
77490 '𐐬' => '𐐄',
77491 '𐐭' => '𐐅',
77492 '𐐮' => '𐐆',
77493 '𐐯' => '𐐇',
77494 '𐐰' => '𐐈',
77495 '𐐱' => '𐐉',
77496 '𐐲' => '𐐊',
77497 '𐐳' => '𐐋',
77498 '𐐴' => '𐐌',
77499 '𐐵' => '𐐍',
77500 '𐐶' => '𐐎',
77501 '𐐷' => '𐐏',
77502 '𐐸' => '𐐐',
77503 '𐐹' => '𐐑',
77504 '𐐺' => '𐐒',
77505 '𐐻' => '𐐓',
77506 '𐐼' => '𐐔',
77507 '𐐽' => '𐐕',
77508 '𐐾' => '𐐖',
77509 '𐐿' => '𐐗',
77510 '𐑀' => '𐐘',
77511 '𐑁' => '𐐙',
77512 '𐑂' => '𐐚',
77513 '𐑃' => '𐐛',
77514 '𐑄' => '𐐜',
77515 '𐑅' => '𐐝',
77516 '𐑆' => '𐐞',
77517 '𐑇' => '𐐟',
77518 '𐑈' => '𐐠',
77519 '𐑉' => '𐐡',
77520 '𐑊' => '𐐢',
77521 '𐑋' => '𐐣',
77522 '𐑌' => '𐐤',
77523 '𐑍' => '𐐥',
77524 '𐑎' => '𐐦',
77525 '𐑏' => '𐐧',
77526 '𐓘' => '𐒰',
77527 '𐓙' => '𐒱',
77528 '𐓚' => '𐒲',
77529 '𐓛' => '𐒳',
77530 '𐓜' => '𐒴',
77531 '𐓝' => '𐒵',
77532 '𐓞' => '𐒶',
77533 '𐓟' => '𐒷',
77534 '𐓠' => '𐒸',
77535 '𐓡' => '𐒹',
77536 '𐓢' => '𐒺',
77537 '𐓣' => '𐒻',
77538 '𐓤' => '𐒼',
77539 '𐓥' => '𐒽',
77540 '𐓦' => '𐒾',
77541 '𐓧' => '𐒿',
77542 '𐓨' => '𐓀',
77543 '𐓩' => '𐓁',
77544 '𐓪' => '𐓂',
77545 '𐓫' => '𐓃',
77546 '𐓬' => '𐓄',
77547 '𐓭' => '𐓅',
77548 '𐓮' => '𐓆',
77549 '𐓯' => '𐓇',
77550 '𐓰' => '𐓈',
77551 '𐓱' => '𐓉',
77552 '𐓲' => '𐓊',
77553 '𐓳' => '𐓋',
77554 '𐓴' => '𐓌',
77555 '𐓵' => '𐓍',
77556 '𐓶' => '𐓎',
77557 '𐓷' => '𐓏',
77558 '𐓸' => '𐓐',
77559 '𐓹' => '𐓑',
77560 '𐓺' => '𐓒',
77561 '𐓻' => '𐓓',
77562 '𐳀' => '𐲀',
77563 '𐳁' => '𐲁',
77564 '𐳂' => '𐲂',
77565 '𐳃' => '𐲃',
77566 '𐳄' => '𐲄',
77567 '𐳅' => '𐲅',
77568 '𐳆' => '𐲆',
77569 '𐳇' => '𐲇',
77570 '𐳈' => '𐲈',
77571 '𐳉' => '𐲉',
77572 '𐳊' => '𐲊',
77573 '𐳋' => '𐲋',
77574 '𐳌' => '𐲌',
77575 '𐳍' => '𐲍',
77576 '𐳎' => '𐲎',
77577 '𐳏' => '𐲏',
77578 '𐳐' => '𐲐',
77579 '𐳑' => '𐲑',
77580 '𐳒' => '𐲒',
77581 '𐳓' => '𐲓',
77582 '𐳔' => '𐲔',
77583 '𐳕' => '𐲕',
77584 '𐳖' => '𐲖',
77585 '𐳗' => '𐲗',
77586 '𐳘' => '𐲘',
77587 '𐳙' => '𐲙',
77588 '𐳚' => '𐲚',
77589 '𐳛' => '𐲛',
77590 '𐳜' => '𐲜',
77591 '𐳝' => '𐲝',
77592 '𐳞' => '𐲞',
77593 '𐳟' => '𐲟',
77594 '𐳠' => '𐲠',
77595 '𐳡' => '𐲡',
77596 '𐳢' => '𐲢',
77597 '𐳣' => '𐲣',
77598 '𐳤' => '𐲤',
77599 '𐳥' => '𐲥',
77600 '𐳦' => '𐲦',
77601 '𐳧' => '𐲧',
77602 '𐳨' => '𐲨',
77603 '𐳩' => '𐲩',
77604 '𐳪' => '𐲪',
77605 '𐳫' => '𐲫',
77606 '𐳬' => '𐲬',
77607 '𐳭' => '𐲭',
77608 '𐳮' => '𐲮',
77609 '𐳯' => '𐲯',
77610 '𐳰' => '𐲰',
77611 '𐳱' => '𐲱',
77612 '𐳲' => '𐲲',
77613 '𑣀' => '𑢠',
77614 '𑣁' => '𑢡',
77615 '𑣂' => '𑢢',
77616 '𑣃' => '𑢣',
77617 '𑣄' => '𑢤',
77618 '𑣅' => '𑢥',
77619 '𑣆' => '𑢦',
77620 '𑣇' => '𑢧',
77621 '𑣈' => '𑢨',
77622 '𑣉' => '𑢩',
77623 '𑣊' => '𑢪',
77624 '𑣋' => '𑢫',
77625 '𑣌' => '𑢬',
77626 '𑣍' => '𑢭',
77627 '𑣎' => '𑢮',
77628 '𑣏' => '𑢯',
77629 '𑣐' => '𑢰',
77630 '𑣑' => '𑢱',
77631 '𑣒' => '𑢲',
77632 '𑣓' => '𑢳',
77633 '𑣔' => '𑢴',
77634 '𑣕' => '𑢵',
77635 '𑣖' => '𑢶',
77636 '𑣗' => '𑢷',
77637 '𑣘' => '𑢸',
77638 '𑣙' => '𑢹',
77639 '𑣚' => '𑢺',
77640 '𑣛' => '𑢻',
77641 '𑣜' => '𑢼',
77642 '𑣝' => '𑢽',
77643 '𑣞' => '𑢾',
77644 '𑣟' => '𑢿',
77645 '𖹠' => '𖹀',
77646 '𖹡' => '𖹁',
77647 '𖹢' => '𖹂',
77648 '𖹣' => '𖹃',
77649 '𖹤' => '𖹄',
77650 '𖹥' => '𖹅',
77651 '𖹦' => '𖹆',
77652 '𖹧' => '𖹇',
77653 '𖹨' => '𖹈',
77654 '𖹩' => '𖹉',
77655 '𖹪' => '𖹊',
77656 '𖹫' => '𖹋',
77657 '𖹬' => '𖹌',
77658 '𖹭' => '𖹍',
77659 '𖹮' => '𖹎',
77660 '𖹯' => '𖹏',
77661 '𖹰' => '𖹐',
77662 '𖹱' => '𖹑',
77663 '𖹲' => '𖹒',
77664 '𖹳' => '𖹓',
77665 '𖹴' => '𖹔',
77666 '𖹵' => '𖹕',
77667 '𖹶' => '𖹖',
77668 '𖹷' => '𖹗',
77669 '𖹸' => '𖹘',
77670 '𖹹' => '𖹙',
77671 '𖹺' => '𖹚',
77672 '𖹻' => '𖹛',
77673 '𖹼' => '𖹜',
77674 '𖹽' => '𖹝',
77675 '𖹾' => '𖹞',
77676 '𖹿' => '𖹟',
77677 '𞤢' => '𞤀',
77678 '𞤣' => '𞤁',
77679 '𞤤' => '𞤂',
77680 '𞤥' => '𞤃',
77681 '𞤦' => '𞤄',
77682 '𞤧' => '𞤅',
77683 '𞤨' => '𞤆',
77684 '𞤩' => '𞤇',
77685 '𞤪' => '𞤈',
77686 '𞤫' => '𞤉',
77687 '𞤬' => '𞤊',
77688 '𞤭' => '𞤋',
77689 '𞤮' => '𞤌',
77690 '𞤯' => '𞤍',
77691 '𞤰' => '𞤎',
77692 '𞤱' => '𞤏',
77693 '𞤲' => '𞤐',
77694 '𞤳' => '𞤑',
77695 '𞤴' => '𞤒',
77696 '𞤵' => '𞤓',
77697 '𞤶' => '𞤔',
77698 '𞤷' => '𞤕',
77699 '𞤸' => '𞤖',
77700 '𞤹' => '𞤗',
77701 '𞤺' => '𞤘',
77702 '𞤻' => '𞤙',
77703 '𞤼' => '𞤚',
77704 '𞤽' => '𞤛',
77705 '𞤾' => '𞤜',
77706 '𞤿' => '𞤝',
77707 '𞥀' => '𞤞',
77708 '𞥁' => '𞤟',
77709 '𞥂' => '𞤠',
77710 '𞥃' => '𞤡',
77711 );
77712 <?php
77713
77714
77715
77716
77717
77718
77719
77720
77721
77722
77723 use Symfony\Polyfill\Mbstring as p;
77724
77725 if (!function_exists('mb_convert_encoding')) {
77726 function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); }
77727 }
77728 if (!function_exists('mb_decode_mimeheader')) {
77729 function mb_decode_mimeheader($string) { return p\Mbstring::mb_decode_mimeheader($string); }
77730 }
77731 if (!function_exists('mb_encode_mimeheader')) {
77732 function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = null, $indent = null) { return p\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent); }
77733 }
77734 if (!function_exists('mb_decode_numericentity')) {
77735 function mb_decode_numericentity($string, $map, $encoding = null) { return p\Mbstring::mb_decode_numericentity($string, $map, $encoding); }
77736 }
77737 if (!function_exists('mb_encode_numericentity')) {
77738 function mb_encode_numericentity($string, $map, $encoding = null, $hex = false) { return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); }
77739 }
77740 if (!function_exists('mb_convert_case')) {
77741 function mb_convert_case($string, $mode, $encoding = null) { return p\Mbstring::mb_convert_case($string, $mode, $encoding); }
77742 }
77743 if (!function_exists('mb_internal_encoding')) {
77744 function mb_internal_encoding($encoding = null) { return p\Mbstring::mb_internal_encoding($encoding); }
77745 }
77746 if (!function_exists('mb_language')) {
77747 function mb_language($language = null) { return p\Mbstring::mb_language($language); }
77748 }
77749 if (!function_exists('mb_list_encodings')) {
77750 function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); }
77751 }
77752 if (!function_exists('mb_encoding_aliases')) {
77753 function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); }
77754 }
77755 if (!function_exists('mb_check_encoding')) {
77756 function mb_check_encoding($value = null, $encoding = null) { return p\Mbstring::mb_check_encoding($value, $encoding); }
77757 }
77758 if (!function_exists('mb_detect_encoding')) {
77759 function mb_detect_encoding($string, $encodings = null, $strict = false) { return p\Mbstring::mb_detect_encoding($string, $encodings, $strict); }
77760 }
77761 if (!function_exists('mb_detect_order')) {
77762 function mb_detect_order($encoding = null) { return p\Mbstring::mb_detect_order($encoding); }
77763 }
77764 if (!function_exists('mb_parse_str')) {
77765 function mb_parse_str($string, &$result = array()) { parse_str($string, $result); }
77766 }
77767 if (!function_exists('mb_strlen')) {
77768 function mb_strlen($string, $encoding = null) { return p\Mbstring::mb_strlen($string, $encoding); }
77769 }
77770 if (!function_exists('mb_strpos')) {
77771 function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); }
77772 }
77773 if (!function_exists('mb_strtolower')) {
77774 function mb_strtolower($string, $encoding = null) { return p\Mbstring::mb_strtolower($string, $encoding); }
77775 }
77776 if (!function_exists('mb_strtoupper')) {
77777 function mb_strtoupper($string, $encoding = null) { return p\Mbstring::mb_strtoupper($string, $encoding); }
77778 }
77779 if (!function_exists('mb_substitute_character')) {
77780 function mb_substitute_character($substitute_character = null) { return p\Mbstring::mb_substitute_character($substitute_character); }
77781 }
77782 if (!function_exists('mb_substr')) {
77783 function mb_substr($string, $start, $length = 2147483647, $encoding = null) { return p\Mbstring::mb_substr($string, $start, $length, $encoding); }
77784 }
77785 if (!function_exists('mb_stripos')) {
77786 function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); }
77787 }
77788 if (!function_exists('mb_stristr')) {
77789 function mb_stristr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); }
77790 }
77791 if (!function_exists('mb_strrchr')) {
77792 function mb_strrchr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); }
77793 }
77794 if (!function_exists('mb_strrichr')) {
77795 function mb_strrichr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); }
77796 }
77797 if (!function_exists('mb_strripos')) {
77798 function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); }
77799 }
77800 if (!function_exists('mb_strrpos')) {
77801 function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); }
77802 }
77803 if (!function_exists('mb_strstr')) {
77804 function mb_strstr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); }
77805 }
77806 if (!function_exists('mb_get_info')) {
77807 function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); }
77808 }
77809 if (!function_exists('mb_http_output')) {
77810 function mb_http_output($encoding = null) { return p\Mbstring::mb_http_output($encoding); }
77811 }
77812 if (!function_exists('mb_strwidth')) {
77813 function mb_strwidth($string, $encoding = null) { return p\Mbstring::mb_strwidth($string, $encoding); }
77814 }
77815 if (!function_exists('mb_substr_count')) {
77816 function mb_substr_count($haystack, $needle, $encoding = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $encoding); }
77817 }
77818 if (!function_exists('mb_output_handler')) {
77819 function mb_output_handler($string, $status) { return p\Mbstring::mb_output_handler($string, $status); }
77820 }
77821 if (!function_exists('mb_http_input')) {
77822 function mb_http_input($type = '') { return p\Mbstring::mb_http_input($type); }
77823 }
77824
77825 if (PHP_VERSION_ID >= 80000) {
77826 require_once __DIR__.'/Resources/mb_convert_variables.php8';
77827 } elseif (!function_exists('mb_convert_variables')) {
77828 function mb_convert_variables($toEncoding, $fromEncoding, &$a = null, &$b = null, &$c = null, &$d = null, &$e = null, &$f = null) { return p\Mbstring::mb_convert_variables($toEncoding, $fromEncoding, $a, $b, $c, $d, $e, $f); }
77829 }
77830
77831 if (!function_exists('mb_ord')) {
77832 function mb_ord($string, $encoding = null) { return p\Mbstring::mb_ord($string, $encoding); }
77833 }
77834 if (!function_exists('mb_chr')) {
77835 function mb_chr($codepoint, $encoding = null) { return p\Mbstring::mb_chr($codepoint, $encoding); }
77836 }
77837 if (!function_exists('mb_scrub')) {
77838 function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); }
77839 }
77840 if (!function_exists('mb_str_split')) {
77841 function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); }
77842 }
77843
77844 if (extension_loaded('mbstring')) {
77845 return;
77846 }
77847
77848 if (!defined('MB_CASE_UPPER')) {
77849 define('MB_CASE_UPPER', 0);
77850 }
77851 if (!defined('MB_CASE_LOWER')) {
77852 define('MB_CASE_LOWER', 1);
77853 }
77854 if (!defined('MB_CASE_TITLE')) {
77855 define('MB_CASE_TITLE', 2);
77856 }
77857 <?php
77858
77859
77860
77861
77862
77863
77864
77865
77866
77867
77868 namespace Symfony\Component\Process\Exception;
77869
77870
77871
77872
77873
77874
77875 interface ExceptionInterface
77876 {
77877 }
77878 <?php
77879
77880
77881
77882
77883
77884
77885
77886
77887
77888
77889 namespace Symfony\Component\Process\Exception;
77890
77891
77892
77893
77894
77895
77896 class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
77897 {
77898 }
77899 <?php
77900
77901
77902
77903
77904
77905
77906
77907
77908
77909
77910 namespace Symfony\Component\Process\Exception;
77911
77912
77913
77914
77915
77916
77917 class LogicException extends \LogicException implements ExceptionInterface
77918 {
77919 }
77920 <?php
77921
77922
77923
77924
77925
77926
77927
77928
77929
77930
77931 namespace Symfony\Component\Process\Exception;
77932
77933 use Symfony\Component\Process\Process;
77934
77935
77936
77937
77938
77939
77940 class ProcessFailedException extends RuntimeException
77941 {
77942 private $process;
77943
77944 public function __construct(Process $process)
77945 {
77946 if ($process->isSuccessful()) {
77947 throw new InvalidArgumentException('Expected a failed process, but the given process was successful.');
77948 }
77949
77950 $error = sprintf('The command "%s" failed.'."\n\nExit Code: %s(%s)\n\nWorking directory: %s",
77951 $process->getCommandLine(),
77952 $process->getExitCode(),
77953 $process->getExitCodeText(),
77954 $process->getWorkingDirectory()
77955 );
77956
77957 if (!$process->isOutputDisabled()) {
77958 $error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s",
77959 $process->getOutput(),
77960 $process->getErrorOutput()
77961 );
77962 }
77963
77964 parent::__construct($error);
77965
77966 $this->process = $process;
77967 }
77968
77969 public function getProcess()
77970 {
77971 return $this->process;
77972 }
77973 }
77974 <?php
77975
77976
77977
77978
77979
77980
77981
77982
77983
77984
77985 namespace Symfony\Component\Process\Exception;
77986
77987 use Symfony\Component\Process\Process;
77988
77989
77990
77991
77992
77993
77994 class ProcessTimedOutException extends RuntimeException
77995 {
77996 const TYPE_GENERAL = 1;
77997 const TYPE_IDLE = 2;
77998
77999 private $process;
78000 private $timeoutType;
78001
78002 public function __construct(Process $process, $timeoutType)
78003 {
78004 $this->process = $process;
78005 $this->timeoutType = $timeoutType;
78006
78007 parent::__construct(sprintf(
78008 'The process "%s" exceeded the timeout of %s seconds.',
78009 $process->getCommandLine(),
78010 $this->getExceededTimeout()
78011 ));
78012 }
78013
78014 public function getProcess()
78015 {
78016 return $this->process;
78017 }
78018
78019 public function isGeneralTimeout()
78020 {
78021 return self::TYPE_GENERAL === $this->timeoutType;
78022 }
78023
78024 public function isIdleTimeout()
78025 {
78026 return self::TYPE_IDLE === $this->timeoutType;
78027 }
78028
78029 public function getExceededTimeout()
78030 {
78031 switch ($this->timeoutType) {
78032 case self::TYPE_GENERAL:
78033 return $this->process->getTimeout();
78034
78035 case self::TYPE_IDLE:
78036 return $this->process->getIdleTimeout();
78037
78038 default:
78039 throw new \LogicException(sprintf('Unknown timeout type "%d".', $this->timeoutType));
78040 }
78041 }
78042 }
78043 <?php
78044
78045
78046
78047
78048
78049
78050
78051
78052
78053
78054 namespace Symfony\Component\Process\Exception;
78055
78056
78057
78058
78059
78060
78061 class RuntimeException extends \RuntimeException implements ExceptionInterface
78062 {
78063 }
78064 <?php
78065
78066
78067
78068
78069
78070
78071
78072
78073
78074
78075 namespace Symfony\Component\Process;
78076
78077
78078
78079
78080
78081
78082
78083 class ExecutableFinder
78084 {
78085 private $suffixes = array('.exe', '.bat', '.cmd', '.com');
78086
78087
78088
78089
78090 public function setSuffixes(array $suffixes)
78091 {
78092 $this->suffixes = $suffixes;
78093 }
78094
78095
78096
78097
78098
78099
78100 public function addSuffix($suffix)
78101 {
78102 $this->suffixes[] = $suffix;
78103 }
78104
78105
78106
78107
78108
78109
78110
78111
78112
78113
78114 public function find($name, $default = null, array $extraDirs = array())
78115 {
78116 if (ini_get('open_basedir')) {
78117 $searchPath = explode(PATH_SEPARATOR, ini_get('open_basedir'));
78118 $dirs = array();
78119 foreach ($searchPath as $path) {
78120
78121 if (@is_dir($path)) {
78122 $dirs[] = $path;
78123 } else {
78124 if (basename($path) == $name && @is_executable($path)) {
78125 return $path;
78126 }
78127 }
78128 }
78129 } else {
78130 $dirs = array_merge(
78131 explode(PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
78132 $extraDirs
78133 );
78134 }
78135
78136 $suffixes = array('');
78137 if ('\\' === \DIRECTORY_SEPARATOR) {
78138 $pathExt = getenv('PATHEXT');
78139 $suffixes = array_merge($pathExt ? explode(PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes);
78140 }
78141 foreach ($suffixes as $suffix) {
78142 foreach ($dirs as $dir) {
78143 if (@is_file($file = $dir.\DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === \DIRECTORY_SEPARATOR || @is_executable($file))) {
78144 return $file;
78145 }
78146 }
78147 }
78148
78149 return $default;
78150 }
78151 }
78152 Copyright (c) 2004-2018 Fabien Potencier
78153
78154 Permission is hereby granted, free of charge, to any person obtaining a copy
78155 of this software and associated documentation files (the "Software"), to deal
78156 in the Software without restriction, including without limitation the rights
78157 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
78158 copies of the Software, and to permit persons to whom the Software is furnished
78159 to do so, subject to the following conditions:
78160
78161 The above copyright notice and this permission notice shall be included in all
78162 copies or substantial portions of the Software.
78163
78164 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
78165 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
78166 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
78167 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
78168 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
78169 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
78170 THE SOFTWARE.
78171 <?php
78172
78173
78174
78175
78176
78177
78178
78179
78180
78181
78182 namespace Symfony\Component\Process;
78183
78184
78185
78186
78187
78188
78189
78190 class PhpExecutableFinder
78191 {
78192 private $executableFinder;
78193
78194 public function __construct()
78195 {
78196 $this->executableFinder = new ExecutableFinder();
78197 }
78198
78199
78200
78201
78202
78203
78204
78205
78206 public function find($includeArgs = true)
78207 {
78208 $args = $this->findArguments();
78209 $args = $includeArgs && $args ? ' '.implode(' ', $args) : '';
78210
78211
78212 if (\defined('HHVM_VERSION')) {
78213 return (getenv('PHP_BINARY') ?: PHP_BINARY).$args;
78214 }
78215
78216
78217 if (\defined('PHP_BINARY') && PHP_BINARY && \in_array(\PHP_SAPI, array('cli', 'cli-server', 'phpdbg'), true)) {
78218 return PHP_BINARY.$args;
78219 }
78220
78221 if ($php = getenv('PHP_PATH')) {
78222 if (!@is_executable($php)) {
78223 return false;
78224 }
78225
78226 return $php;
78227 }
78228
78229 if ($php = getenv('PHP_PEAR_PHP_BIN')) {
78230 if (@is_executable($php)) {
78231 return $php;
78232 }
78233 }
78234
78235 if (@is_executable($php = PHP_BINDIR.('\\' === \DIRECTORY_SEPARATOR ? '\\php.exe' : '/php'))) {
78236 return $php;
78237 }
78238
78239 $dirs = array(PHP_BINDIR);
78240 if ('\\' === \DIRECTORY_SEPARATOR) {
78241 $dirs[] = 'C:\xampp\php\\';
78242 }
78243
78244 return $this->executableFinder->find('php', false, $dirs);
78245 }
78246
78247
78248
78249
78250
78251
78252 public function findArguments()
78253 {
78254 $arguments = array();
78255
78256 if (\defined('HHVM_VERSION')) {
78257 $arguments[] = '--php';
78258 } elseif ('phpdbg' === \PHP_SAPI) {
78259 $arguments[] = '-qrr';
78260 }
78261
78262 return $arguments;
78263 }
78264 }
78265 <?php
78266
78267
78268
78269
78270
78271
78272
78273
78274
78275
78276 namespace Symfony\Component\Process;
78277
78278 use Symfony\Component\Process\Exception\RuntimeException;
78279
78280
78281
78282
78283
78284
78285
78286
78287
78288
78289 class PhpProcess extends Process
78290 {
78291
78292
78293
78294
78295
78296
78297
78298 public function __construct($script, $cwd = null, array $env = null, $timeout = 60, array $options = array())
78299 {
78300 $executableFinder = new PhpExecutableFinder();
78301 if (false === $php = $executableFinder->find()) {
78302 $php = null;
78303 }
78304 if ('phpdbg' === \PHP_SAPI) {
78305 $file = tempnam(sys_get_temp_dir(), 'dbg');
78306 file_put_contents($file, $script);
78307 register_shutdown_function('unlink', $file);
78308 $php .= ' '.ProcessUtils::escapeArgument($file);
78309 $script = null;
78310 }
78311 if ('\\' !== \DIRECTORY_SEPARATOR && null !== $php) {
78312
78313
78314
78315 $php = 'exec '.$php;
78316 }
78317
78318 parent::__construct($php, $cwd, $env, $script, $timeout, $options);
78319 }
78320
78321
78322
78323
78324 public function setPhpBinary($php)
78325 {
78326 $this->setCommandLine($php);
78327 }
78328
78329
78330
78331
78332 public function start($callback = null)
78333 {
78334 if (null === $this->getCommandLine()) {
78335 throw new RuntimeException('Unable to find the PHP executable.');
78336 }
78337
78338 parent::start($callback);
78339 }
78340 }
78341 <?php
78342
78343
78344
78345
78346
78347
78348
78349
78350
78351
78352 namespace Symfony\Component\Process\Pipes;
78353
78354
78355
78356
78357
78358
78359 abstract class AbstractPipes implements PipesInterface
78360 {
78361 public $pipes = array();
78362
78363 private $inputBuffer = '';
78364 private $input;
78365 private $blocked = true;
78366 private $lastError;
78367
78368
78369
78370
78371 public function __construct($input)
78372 {
78373 if (\is_resource($input)) {
78374 $this->input = $input;
78375 } elseif (\is_string($input)) {
78376 $this->inputBuffer = $input;
78377 } else {
78378 $this->inputBuffer = (string) $input;
78379 }
78380 }
78381
78382
78383
78384
78385 public function close()
78386 {
78387 foreach ($this->pipes as $pipe) {
78388 fclose($pipe);
78389 }
78390 $this->pipes = array();
78391 }
78392
78393
78394
78395
78396
78397
78398 protected function hasSystemCallBeenInterrupted()
78399 {
78400 $lastError = $this->lastError;
78401 $this->lastError = null;
78402
78403
78404 return null !== $lastError && false !== stripos($lastError, 'interrupted system call');
78405 }
78406
78407
78408
78409
78410 protected function unblock()
78411 {
78412 if (!$this->blocked) {
78413 return;
78414 }
78415
78416 foreach ($this->pipes as $pipe) {
78417 stream_set_blocking($pipe, 0);
78418 }
78419 if (null !== $this->input) {
78420 stream_set_blocking($this->input, 0);
78421 }
78422
78423 $this->blocked = false;
78424 }
78425
78426
78427
78428
78429 protected function write()
78430 {
78431 if (!isset($this->pipes[0])) {
78432 return;
78433 }
78434 $input = $this->input;
78435 $r = $e = array();
78436 $w = array($this->pipes[0]);
78437
78438
78439 if (false === @stream_select($r, $w, $e, 0, 0)) {
78440 return;
78441 }
78442
78443 foreach ($w as $stdin) {
78444 if (isset($this->inputBuffer[0])) {
78445 $written = fwrite($stdin, $this->inputBuffer);
78446 $this->inputBuffer = substr($this->inputBuffer, $written);
78447 if (isset($this->inputBuffer[0])) {
78448 return array($this->pipes[0]);
78449 }
78450 }
78451
78452 if ($input) {
78453 for (;;) {
78454 $data = fread($input, self::CHUNK_SIZE);
78455 if (!isset($data[0])) {
78456 break;
78457 }
78458 $written = fwrite($stdin, $data);
78459 $data = substr($data, $written);
78460 if (isset($data[0])) {
78461 $this->inputBuffer = $data;
78462
78463 return array($this->pipes[0]);
78464 }
78465 }
78466 if (feof($input)) {
78467
78468
78469 $this->input = null;
78470 }
78471 }
78472 }
78473
78474
78475 if (null === $this->input && !isset($this->inputBuffer[0])) {
78476 fclose($this->pipes[0]);
78477 unset($this->pipes[0]);
78478 } elseif (!$w) {
78479 return array($this->pipes[0]);
78480 }
78481 }
78482
78483
78484
78485
78486 public function handleError($type, $msg)
78487 {
78488 $this->lastError = $msg;
78489 }
78490 }
78491 <?php
78492
78493
78494
78495
78496
78497
78498
78499
78500
78501
78502 namespace Symfony\Component\Process\Pipes;
78503
78504
78505
78506
78507
78508
78509
78510
78511 interface PipesInterface
78512 {
78513 const CHUNK_SIZE = 16384;
78514
78515
78516
78517
78518
78519
78520 public function getDescriptors();
78521
78522
78523
78524
78525
78526
78527 public function getFiles();
78528
78529
78530
78531
78532
78533
78534
78535
78536
78537 public function readAndWrite($blocking, $close = false);
78538
78539
78540
78541
78542
78543
78544 public function areOpen();
78545
78546
78547
78548
78549 public function close();
78550 }
78551 <?php
78552
78553
78554
78555
78556
78557
78558
78559
78560
78561
78562 namespace Symfony\Component\Process\Pipes;
78563
78564 use Symfony\Component\Process\Process;
78565
78566
78567
78568
78569
78570
78571
78572
78573 class UnixPipes extends AbstractPipes
78574 {
78575 private $ttyMode;
78576 private $ptyMode;
78577 private $disableOutput;
78578
78579 public function __construct($ttyMode, $ptyMode, $input, $disableOutput)
78580 {
78581 $this->ttyMode = (bool) $ttyMode;
78582 $this->ptyMode = (bool) $ptyMode;
78583 $this->disableOutput = (bool) $disableOutput;
78584
78585 parent::__construct($input);
78586 }
78587
78588 public function __destruct()
78589 {
78590 $this->close();
78591 }
78592
78593
78594
78595
78596 public function getDescriptors()
78597 {
78598 if ($this->disableOutput) {
78599 $nullstream = fopen('/dev/null', 'c');
78600
78601 return array(
78602 array('pipe', 'r'),
78603 $nullstream,
78604 $nullstream,
78605 );
78606 }
78607
78608 if ($this->ttyMode) {
78609 return array(
78610 array('file', '/dev/tty', 'r'),
78611 array('file', '/dev/tty', 'w'),
78612 array('file', '/dev/tty', 'w'),
78613 );
78614 }
78615
78616 if ($this->ptyMode && Process::isPtySupported()) {
78617 return array(
78618 array('pty'),
78619 array('pty'),
78620 array('pty'),
78621 );
78622 }
78623
78624 return array(
78625 array('pipe', 'r'),
78626 array('pipe', 'w'), 
78627 array('pipe', 'w'), 
78628 );
78629 }
78630
78631
78632
78633
78634 public function getFiles()
78635 {
78636 return array();
78637 }
78638
78639
78640
78641
78642 public function readAndWrite($blocking, $close = false)
78643 {
78644 $this->unblock();
78645 $w = $this->write();
78646
78647 $read = $e = array();
78648 $r = $this->pipes;
78649 unset($r[0]);
78650
78651
78652 set_error_handler(array($this, 'handleError'));
78653 if (($r || $w) && false === stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {
78654 restore_error_handler();
78655
78656
78657 if (!$this->hasSystemCallBeenInterrupted()) {
78658 $this->pipes = array();
78659 }
78660
78661 return $read;
78662 }
78663 restore_error_handler();
78664
78665 foreach ($r as $pipe) {
78666
78667
78668 $read[$type = array_search($pipe, $this->pipes, true)] = '';
78669
78670 do {
78671 $data = fread($pipe, self::CHUNK_SIZE);
78672 $read[$type] .= $data;
78673 } while (isset($data[0]) && ($close || isset($data[self::CHUNK_SIZE - 1])));
78674
78675 if (!isset($read[$type][0])) {
78676 unset($read[$type]);
78677 }
78678
78679 if ($close && feof($pipe)) {
78680 fclose($pipe);
78681 unset($this->pipes[$type]);
78682 }
78683 }
78684
78685 return $read;
78686 }
78687
78688
78689
78690
78691 public function areOpen()
78692 {
78693 return (bool) $this->pipes;
78694 }
78695
78696
78697
78698
78699
78700
78701
78702
78703
78704 public static function create(Process $process, $input)
78705 {
78706 return new static($process->isTty(), $process->isPty(), $input, $process->isOutputDisabled());
78707 }
78708 }
78709 <?php
78710
78711
78712
78713
78714
78715
78716
78717
78718
78719
78720 namespace Symfony\Component\Process\Pipes;
78721
78722 use Symfony\Component\Process\Exception\RuntimeException;
78723 use Symfony\Component\Process\Process;
78724
78725
78726
78727
78728
78729
78730
78731
78732
78733
78734
78735 class WindowsPipes extends AbstractPipes
78736 {
78737 private $files = array();
78738 private $fileHandles = array();
78739 private $lockHandles = array();
78740 private $readBytes = array(
78741 Process::STDOUT => 0,
78742 Process::STDERR => 0,
78743 );
78744 private $disableOutput;
78745
78746 public function __construct($disableOutput, $input)
78747 {
78748 $this->disableOutput = (bool) $disableOutput;
78749
78750 if (!$this->disableOutput) {
78751
78752
78753
78754
78755 $pipes = array(
78756 Process::STDOUT => Process::OUT,
78757 Process::STDERR => Process::ERR,
78758 );
78759 $tmpDir = sys_get_temp_dir();
78760 $lastError = 'unknown reason';
78761 set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; });
78762 for ($i = 0;; ++$i) {
78763 foreach ($pipes as $pipe => $name) {
78764 $file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name);
78765
78766 if (!$h = fopen($file.'.lock', 'w')) {
78767 restore_error_handler();
78768 throw new RuntimeException(sprintf('A temporary file could not be opened to write the process output: %s', $lastError));
78769 }
78770 if (!flock($h, LOCK_EX | LOCK_NB)) {
78771 continue 2;
78772 }
78773 if (isset($this->lockHandles[$pipe])) {
78774 flock($this->lockHandles[$pipe], LOCK_UN);
78775 fclose($this->lockHandles[$pipe]);
78776 }
78777 $this->lockHandles[$pipe] = $h;
78778
78779 if (!fclose(fopen($file, 'w')) || !$h = fopen($file, 'r')) {
78780 flock($this->lockHandles[$pipe], LOCK_UN);
78781 fclose($this->lockHandles[$pipe]);
78782 unset($this->lockHandles[$pipe]);
78783 continue 2;
78784 }
78785 $this->fileHandles[$pipe] = $h;
78786 $this->files[$pipe] = $file;
78787 }
78788 break;
78789 }
78790 restore_error_handler();
78791 }
78792
78793 parent::__construct($input);
78794 }
78795
78796 public function __destruct()
78797 {
78798 $this->close();
78799 }
78800
78801
78802
78803
78804 public function getDescriptors()
78805 {
78806 if ($this->disableOutput) {
78807 $nullstream = fopen('NUL', 'c');
78808
78809 return array(
78810 array('pipe', 'r'),
78811 $nullstream,
78812 $nullstream,
78813 );
78814 }
78815
78816
78817
78818
78819 return array(
78820 array('pipe', 'r'),
78821 array('file', 'NUL', 'w'),
78822 array('file', 'NUL', 'w'),
78823 );
78824 }
78825
78826
78827
78828
78829 public function getFiles()
78830 {
78831 return $this->files;
78832 }
78833
78834
78835
78836
78837 public function readAndWrite($blocking, $close = false)
78838 {
78839 $this->unblock();
78840 $w = $this->write();
78841 $read = $r = $e = array();
78842
78843 if ($blocking) {
78844 if ($w) {
78845 @stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6);
78846 } elseif ($this->fileHandles) {
78847 usleep(Process::TIMEOUT_PRECISION * 1E6);
78848 }
78849 }
78850 foreach ($this->fileHandles as $type => $fileHandle) {
78851 $data = stream_get_contents($fileHandle, -1, $this->readBytes[$type]);
78852
78853 if (isset($data[0])) {
78854 $this->readBytes[$type] += \strlen($data);
78855 $read[$type] = $data;
78856 }
78857 if ($close) {
78858 ftruncate($fileHandle, 0);
78859 fclose($fileHandle);
78860 flock($this->lockHandles[$type], LOCK_UN);
78861 fclose($this->lockHandles[$type]);
78862 unset($this->fileHandles[$type], $this->lockHandles[$type]);
78863 }
78864 }
78865
78866 return $read;
78867 }
78868
78869
78870
78871
78872 public function areOpen()
78873 {
78874 return $this->pipes && $this->fileHandles;
78875 }
78876
78877
78878
78879
78880 public function close()
78881 {
78882 parent::close();
78883 foreach ($this->fileHandles as $type => $handle) {
78884 ftruncate($handle, 0);
78885 fclose($handle);
78886 flock($this->lockHandles[$type], LOCK_UN);
78887 fclose($this->lockHandles[$type]);
78888 }
78889 $this->fileHandles = $this->lockHandles = array();
78890 }
78891
78892
78893
78894
78895
78896
78897
78898
78899
78900 public static function create(Process $process, $input)
78901 {
78902 return new static($process->isOutputDisabled(), $input);
78903 }
78904 }
78905 <?php
78906
78907
78908
78909
78910
78911
78912
78913
78914
78915
78916 namespace Symfony\Component\Process;
78917
78918 use Symfony\Component\Process\Exception\InvalidArgumentException;
78919 use Symfony\Component\Process\Exception\LogicException;
78920 use Symfony\Component\Process\Exception\ProcessFailedException;
78921 use Symfony\Component\Process\Exception\ProcessTimedOutException;
78922 use Symfony\Component\Process\Exception\RuntimeException;
78923 use Symfony\Component\Process\Pipes\PipesInterface;
78924 use Symfony\Component\Process\Pipes\UnixPipes;
78925 use Symfony\Component\Process\Pipes\WindowsPipes;
78926
78927
78928
78929
78930
78931
78932
78933
78934 class Process
78935 {
78936 const ERR = 'err';
78937 const OUT = 'out';
78938
78939 const STATUS_READY = 'ready';
78940 const STATUS_STARTED = 'started';
78941 const STATUS_TERMINATED = 'terminated';
78942
78943 const STDIN = 0;
78944 const STDOUT = 1;
78945 const STDERR = 2;
78946
78947
78948 const TIMEOUT_PRECISION = 0.2;
78949
78950 private $callback;
78951 private $commandline;
78952 private $cwd;
78953 private $env;
78954 private $input;
78955 private $starttime;
78956 private $lastOutputTime;
78957 private $timeout;
78958 private $idleTimeout;
78959 private $options;
78960 private $exitcode;
78961 private $fallbackStatus = array();
78962 private $processInformation;
78963 private $outputDisabled = false;
78964 private $stdout;
78965 private $stderr;
78966 private $enhanceWindowsCompatibility = true;
78967 private $enhanceSigchildCompatibility;
78968 private $process;
78969 private $status = self::STATUS_READY;
78970 private $incrementalOutputOffset = 0;
78971 private $incrementalErrorOutputOffset = 0;
78972 private $tty;
78973 private $pty;
78974
78975 private $useFileHandles = false;
78976
78977 private $processPipes;
78978
78979 private $latestSignal;
78980
78981 private static $sigchild;
78982
78983
78984
78985
78986
78987
78988 public static $exitCodes = array(
78989 0 => 'OK',
78990 1 => 'General error',
78991 2 => 'Misuse of shell builtins',
78992
78993 126 => 'Invoked command cannot execute',
78994 127 => 'Command not found',
78995 128 => 'Invalid exit argument',
78996
78997
78998 129 => 'Hangup',
78999 130 => 'Interrupt',
79000 131 => 'Quit and dump core',
79001 132 => 'Illegal instruction',
79002 133 => 'Trace/breakpoint trap',
79003 134 => 'Process aborted',
79004 135 => 'Bus error: "access to undefined portion of memory object"',
79005 136 => 'Floating point exception: "erroneous arithmetic operation"',
79006 137 => 'Kill (terminate immediately)',
79007 138 => 'User-defined 1',
79008 139 => 'Segmentation violation',
79009 140 => 'User-defined 2',
79010 141 => 'Write to pipe with no one reading',
79011 142 => 'Signal raised by alarm',
79012 143 => 'Termination (request to terminate)',
79013
79014 145 => 'Child process terminated, stopped (or continued*)',
79015 146 => 'Continue if stopped',
79016 147 => 'Stop executing temporarily',
79017 148 => 'Terminal stop signal',
79018 149 => 'Background process attempting to read from tty ("in")',
79019 150 => 'Background process attempting to write to tty ("out")',
79020 151 => 'Urgent data available on socket',
79021 152 => 'CPU time limit exceeded',
79022 153 => 'File size limit exceeded',
79023 154 => 'Signal raised by timer counting virtual time: "virtual timer expired"',
79024 155 => 'Profiling timer expired',
79025
79026 157 => 'Pollable event',
79027
79028 159 => 'Bad syscall',
79029 );
79030
79031
79032
79033
79034
79035
79036
79037
79038
79039
79040
79041 public function __construct($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = array())
79042 {
79043 if (!\function_exists('proc_open')) {
79044 throw new RuntimeException('The Process class relies on proc_open, which is not available on your PHP installation.');
79045 }
79046
79047 $this->commandline = $commandline;
79048 $this->cwd = $cwd;
79049
79050
79051
79052
79053
79054 if (null === $this->cwd && (\defined('ZEND_THREAD_SAFE') || '\\' === \DIRECTORY_SEPARATOR)) {
79055 $this->cwd = getcwd();
79056 }
79057 if (null !== $env) {
79058 $this->setEnv($env);
79059 }
79060
79061 $this->setInput($input);
79062 $this->setTimeout($timeout);
79063 $this->useFileHandles = '\\' === \DIRECTORY_SEPARATOR;
79064 $this->pty = false;
79065 $this->enhanceSigchildCompatibility = '\\' !== \DIRECTORY_SEPARATOR && $this->isSigchildEnabled();
79066 $this->options = array_replace(array('suppress_errors' => true, 'binary_pipes' => true), $options);
79067 }
79068
79069 public function __destruct()
79070 {
79071 $this->stop(0);
79072 }
79073
79074 public function __clone()
79075 {
79076 $this->resetProcessData();
79077 }
79078
79079
79080
79081
79082
79083
79084
79085
79086
79087
79088
79089
79090
79091
79092
79093
79094
79095
79096
79097
79098 public function run($callback = null)
79099 {
79100 $this->start($callback);
79101
79102 return $this->wait();
79103 }
79104
79105
79106
79107
79108
79109
79110
79111
79112
79113
79114
79115
79116
79117
79118 public function mustRun($callback = null)
79119 {
79120 if (!$this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
79121 throw new RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.');
79122 }
79123
79124 if (0 !== $this->run($callback)) {
79125 throw new ProcessFailedException($this);
79126 }
79127
79128 return $this;
79129 }
79130
79131
79132
79133
79134
79135
79136
79137
79138
79139
79140
79141
79142
79143
79144
79145
79146
79147
79148
79149
79150 public function start($callback = null)
79151 {
79152 if ($this->isRunning()) {
79153 throw new RuntimeException('Process is already running');
79154 }
79155 if ($this->outputDisabled && null !== $callback) {
79156 throw new LogicException('Output has been disabled, enable it to allow the use of a callback.');
79157 }
79158
79159 $this->resetProcessData();
79160 $this->starttime = $this->lastOutputTime = microtime(true);
79161 $this->callback = $this->buildCallback($callback);
79162 $descriptors = $this->getDescriptors();
79163
79164 $commandline = $this->commandline;
79165
79166 if ('\\' === \DIRECTORY_SEPARATOR && $this->enhanceWindowsCompatibility) {
79167 $commandline = 'cmd /V:ON /E:ON /D /C "('.$commandline.')';
79168 foreach ($this->processPipes->getFiles() as $offset => $filename) {
79169 $commandline .= ' '.$offset.'>'.ProcessUtils::escapeArgument($filename);
79170 }
79171 $commandline .= '"';
79172
79173 if (!isset($this->options['bypass_shell'])) {
79174 $this->options['bypass_shell'] = true;
79175 }
79176 } elseif (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
79177
79178 $descriptors[3] = array('pipe', 'w');
79179
79180
79181 $commandline = '{ ('.$this->commandline.') <&3 3<&- 3>/dev/null & } 3<&0;';
79182 $commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code';
79183
79184
79185
79186 $ptsWorkaround = fopen(__FILE__, 'r');
79187 }
79188
79189 $this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $this->env, $this->options);
79190
79191 if (!\is_resource($this->process)) {
79192 throw new RuntimeException('Unable to launch a new process.');
79193 }
79194 $this->status = self::STATUS_STARTED;
79195
79196 if (isset($descriptors[3])) {
79197 $this->fallbackStatus['pid'] = (int) fgets($this->processPipes->pipes[3]);
79198 }
79199
79200 if ($this->tty) {
79201 return;
79202 }
79203
79204 $this->updateStatus(false);
79205 $this->checkTimeout();
79206 }
79207
79208
79209
79210
79211
79212
79213
79214
79215
79216
79217
79218
79219
79220
79221
79222
79223 public function restart($callback = null)
79224 {
79225 if ($this->isRunning()) {
79226 throw new RuntimeException('Process is already running');
79227 }
79228
79229 $process = clone $this;
79230 $process->start($callback);
79231
79232 return $process;
79233 }
79234
79235
79236
79237
79238
79239
79240
79241
79242
79243
79244
79245
79246
79247
79248
79249
79250 public function wait($callback = null)
79251 {
79252 $this->requireProcessIsStarted(__FUNCTION__);
79253
79254 $this->updateStatus(false);
79255 if (null !== $callback) {
79256 $this->callback = $this->buildCallback($callback);
79257 }
79258
79259 do {
79260 $this->checkTimeout();
79261 $running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
79262 $this->readPipes($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
79263 } while ($running);
79264
79265 while ($this->isRunning()) {
79266 usleep(1000);
79267 }
79268
79269 if ($this->processInformation['signaled'] && $this->processInformation['termsig'] !== $this->latestSignal) {
79270 throw new RuntimeException(sprintf('The process has been signaled with signal "%s".', $this->processInformation['termsig']));
79271 }
79272
79273 return $this->exitcode;
79274 }
79275
79276
79277
79278
79279
79280
79281 public function getPid()
79282 {
79283 return $this->isRunning() ? $this->processInformation['pid'] : null;
79284 }
79285
79286
79287
79288
79289
79290
79291
79292
79293
79294
79295
79296
79297 public function signal($signal)
79298 {
79299 $this->doSignal($signal, true);
79300
79301 return $this;
79302 }
79303
79304
79305
79306
79307
79308
79309
79310
79311
79312 public function disableOutput()
79313 {
79314 if ($this->isRunning()) {
79315 throw new RuntimeException('Disabling output while the process is running is not possible.');
79316 }
79317 if (null !== $this->idleTimeout) {
79318 throw new LogicException('Output can not be disabled while an idle timeout is set.');
79319 }
79320
79321 $this->outputDisabled = true;
79322
79323 return $this;
79324 }
79325
79326
79327
79328
79329
79330
79331
79332
79333 public function enableOutput()
79334 {
79335 if ($this->isRunning()) {
79336 throw new RuntimeException('Enabling output while the process is running is not possible.');
79337 }
79338
79339 $this->outputDisabled = false;
79340
79341 return $this;
79342 }
79343
79344
79345
79346
79347
79348
79349 public function isOutputDisabled()
79350 {
79351 return $this->outputDisabled;
79352 }
79353
79354
79355
79356
79357
79358
79359
79360
79361
79362 public function getOutput()
79363 {
79364 $this->readPipesForOutput(__FUNCTION__);
79365
79366 if (false === $ret = stream_get_contents($this->stdout, -1, 0)) {
79367 return '';
79368 }
79369
79370 return $ret;
79371 }
79372
79373
79374
79375
79376
79377
79378
79379
79380
79381
79382
79383
79384 public function getIncrementalOutput()
79385 {
79386 $this->readPipesForOutput(__FUNCTION__);
79387
79388 $latest = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
79389 $this->incrementalOutputOffset = ftell($this->stdout);
79390
79391 if (false === $latest) {
79392 return '';
79393 }
79394
79395 return $latest;
79396 }
79397
79398
79399
79400
79401
79402
79403 public function clearOutput()
79404 {
79405 ftruncate($this->stdout, 0);
79406 fseek($this->stdout, 0);
79407 $this->incrementalOutputOffset = 0;
79408
79409 return $this;
79410 }
79411
79412
79413
79414
79415
79416
79417
79418
79419
79420 public function getErrorOutput()
79421 {
79422 $this->readPipesForOutput(__FUNCTION__);
79423
79424 if (false === $ret = stream_get_contents($this->stderr, -1, 0)) {
79425 return '';
79426 }
79427
79428 return $ret;
79429 }
79430
79431
79432
79433
79434
79435
79436
79437
79438
79439
79440
79441
79442
79443 public function getIncrementalErrorOutput()
79444 {
79445 $this->readPipesForOutput(__FUNCTION__);
79446
79447 $latest = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
79448 $this->incrementalErrorOutputOffset = ftell($this->stderr);
79449
79450 if (false === $latest) {
79451 return '';
79452 }
79453
79454 return $latest;
79455 }
79456
79457
79458
79459
79460
79461
79462 public function clearErrorOutput()
79463 {
79464 ftruncate($this->stderr, 0);
79465 fseek($this->stderr, 0);
79466 $this->incrementalErrorOutputOffset = 0;
79467
79468 return $this;
79469 }
79470
79471
79472
79473
79474
79475
79476
79477
79478 public function getExitCode()
79479 {
79480 if (!$this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
79481 throw new RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.');
79482 }
79483
79484 $this->updateStatus(false);
79485
79486 return $this->exitcode;
79487 }
79488
79489
79490
79491
79492
79493
79494
79495
79496
79497
79498
79499
79500 public function getExitCodeText()
79501 {
79502 if (null === $exitcode = $this->getExitCode()) {
79503 return;
79504 }
79505
79506 return isset(self::$exitCodes[$exitcode]) ? self::$exitCodes[$exitcode] : 'Unknown error';
79507 }
79508
79509
79510
79511
79512
79513
79514 public function isSuccessful()
79515 {
79516 return 0 === $this->getExitCode();
79517 }
79518
79519
79520
79521
79522
79523
79524
79525
79526
79527
79528
79529 public function hasBeenSignaled()
79530 {
79531 $this->requireProcessIsTerminated(__FUNCTION__);
79532
79533 if (!$this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
79534 throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
79535 }
79536
79537 return $this->processInformation['signaled'];
79538 }
79539
79540
79541
79542
79543
79544
79545
79546
79547
79548
79549
79550 public function getTermSignal()
79551 {
79552 $this->requireProcessIsTerminated(__FUNCTION__);
79553
79554 if ($this->isSigchildEnabled() && (!$this->enhanceSigchildCompatibility || -1 === $this->processInformation['termsig'])) {
79555 throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
79556 }
79557
79558 return $this->processInformation['termsig'];
79559 }
79560
79561
79562
79563
79564
79565
79566
79567
79568
79569
79570 public function hasBeenStopped()
79571 {
79572 $this->requireProcessIsTerminated(__FUNCTION__);
79573
79574 return $this->processInformation['stopped'];
79575 }
79576
79577
79578
79579
79580
79581
79582
79583
79584
79585
79586 public function getStopSignal()
79587 {
79588 $this->requireProcessIsTerminated(__FUNCTION__);
79589
79590 return $this->processInformation['stopsig'];
79591 }
79592
79593
79594
79595
79596
79597
79598 public function isRunning()
79599 {
79600 if (self::STATUS_STARTED !== $this->status) {
79601 return false;
79602 }
79603
79604 $this->updateStatus(false);
79605
79606 return $this->processInformation['running'];
79607 }
79608
79609
79610
79611
79612
79613
79614 public function isStarted()
79615 {
79616 return self::STATUS_READY != $this->status;
79617 }
79618
79619
79620
79621
79622
79623
79624 public function isTerminated()
79625 {
79626 $this->updateStatus(false);
79627
79628 return self::STATUS_TERMINATED == $this->status;
79629 }
79630
79631
79632
79633
79634
79635
79636
79637
79638 public function getStatus()
79639 {
79640 $this->updateStatus(false);
79641
79642 return $this->status;
79643 }
79644
79645
79646
79647
79648
79649
79650
79651
79652
79653 public function stop($timeout = 10, $signal = null)
79654 {
79655 $timeoutMicro = microtime(true) + $timeout;
79656 if ($this->isRunning()) {
79657
79658 $this->doSignal(15, false);
79659 do {
79660 usleep(1000);
79661 } while ($this->isRunning() && microtime(true) < $timeoutMicro);
79662
79663 if ($this->isRunning()) {
79664
79665
79666 $this->doSignal($signal ?: 9, false);
79667 }
79668 }
79669
79670 if ($this->isRunning()) {
79671 if (isset($this->fallbackStatus['pid'])) {
79672 unset($this->fallbackStatus['pid']);
79673
79674 return $this->stop(0, $signal);
79675 }
79676 $this->close();
79677 }
79678
79679 return $this->exitcode;
79680 }
79681
79682
79683
79684
79685
79686
79687
79688
79689 public function addOutput($line)
79690 {
79691 $this->lastOutputTime = microtime(true);
79692
79693 fseek($this->stdout, 0, SEEK_END);
79694 fwrite($this->stdout, $line);
79695 fseek($this->stdout, $this->incrementalOutputOffset);
79696 }
79697
79698
79699
79700
79701
79702
79703
79704
79705 public function addErrorOutput($line)
79706 {
79707 $this->lastOutputTime = microtime(true);
79708
79709 fseek($this->stderr, 0, SEEK_END);
79710 fwrite($this->stderr, $line);
79711 fseek($this->stderr, $this->incrementalErrorOutputOffset);
79712 }
79713
79714
79715
79716
79717
79718
79719 public function getCommandLine()
79720 {
79721 return $this->commandline;
79722 }
79723
79724
79725
79726
79727
79728
79729
79730
79731 public function setCommandLine($commandline)
79732 {
79733 $this->commandline = $commandline;
79734
79735 return $this;
79736 }
79737
79738
79739
79740
79741
79742
79743 public function getTimeout()
79744 {
79745 return $this->timeout;
79746 }
79747
79748
79749
79750
79751
79752
79753 public function getIdleTimeout()
79754 {
79755 return $this->idleTimeout;
79756 }
79757
79758
79759
79760
79761
79762
79763
79764
79765
79766
79767
79768
79769 public function setTimeout($timeout)
79770 {
79771 $this->timeout = $this->validateTimeout($timeout);
79772
79773 return $this;
79774 }
79775
79776
79777
79778
79779
79780
79781
79782
79783
79784
79785
79786
79787
79788 public function setIdleTimeout($timeout)
79789 {
79790 if (null !== $timeout && $this->outputDisabled) {
79791 throw new LogicException('Idle timeout can not be set while the output is disabled.');
79792 }
79793
79794 $this->idleTimeout = $this->validateTimeout($timeout);
79795
79796 return $this;
79797 }
79798
79799
79800
79801
79802
79803
79804
79805
79806
79807
79808 public function setTty($tty)
79809 {
79810 if ('\\' === \DIRECTORY_SEPARATOR && $tty) {
79811 throw new RuntimeException('TTY mode is not supported on Windows platform.');
79812 }
79813 if ($tty) {
79814 static $isTtySupported;
79815
79816 if (null === $isTtySupported) {
79817 $isTtySupported = (bool) @proc_open('echo 1 >/dev/null', array(array('file', '/dev/tty', 'r'), array('file', '/dev/tty', 'w'), array('file', '/dev/tty', 'w')), $pipes);
79818 }
79819
79820 if (!$isTtySupported) {
79821 throw new RuntimeException('TTY mode requires /dev/tty to be read/writable.');
79822 }
79823 }
79824
79825 $this->tty = (bool) $tty;
79826
79827 return $this;
79828 }
79829
79830
79831
79832
79833
79834
79835 public function isTty()
79836 {
79837 return $this->tty;
79838 }
79839
79840
79841
79842
79843
79844
79845
79846
79847 public function setPty($bool)
79848 {
79849 $this->pty = (bool) $bool;
79850
79851 return $this;
79852 }
79853
79854
79855
79856
79857
79858
79859 public function isPty()
79860 {
79861 return $this->pty;
79862 }
79863
79864
79865
79866
79867
79868
79869 public function getWorkingDirectory()
79870 {
79871 if (null === $this->cwd) {
79872
79873
79874 return getcwd() ?: null;
79875 }
79876
79877 return $this->cwd;
79878 }
79879
79880
79881
79882
79883
79884
79885
79886
79887 public function setWorkingDirectory($cwd)
79888 {
79889 $this->cwd = $cwd;
79890
79891 return $this;
79892 }
79893
79894
79895
79896
79897
79898
79899 public function getEnv()
79900 {
79901 return $this->env;
79902 }
79903
79904
79905
79906
79907
79908
79909
79910
79911
79912
79913
79914
79915
79916
79917 public function setEnv(array $env)
79918 {
79919
79920 $env = array_filter($env, function ($value) {
79921 return !\is_array($value);
79922 });
79923
79924 $this->env = array();
79925 foreach ($env as $key => $value) {
79926 $this->env[$key] = (string) $value;
79927 }
79928
79929 return $this;
79930 }
79931
79932
79933
79934
79935
79936
79937
79938
79939
79940
79941 public function getStdin()
79942 {
79943 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.5 and will be removed in 3.0. Use the getInput() method instead.', E_USER_DEPRECATED);
79944
79945 return $this->getInput();
79946 }
79947
79948
79949
79950
79951
79952
79953 public function getInput()
79954 {
79955 return $this->input;
79956 }
79957
79958
79959
79960
79961
79962
79963
79964
79965
79966
79967
79968
79969
79970
79971 public function setStdin($stdin)
79972 {
79973 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.5 and will be removed in 3.0. Use the setInput() method instead.', E_USER_DEPRECATED);
79974
79975 return $this->setInput($stdin);
79976 }
79977
79978
79979
79980
79981
79982
79983
79984
79985
79986
79987
79988
79989
79990
79991 public function setInput($input)
79992 {
79993 if ($this->isRunning()) {
79994 throw new LogicException('Input can not be set while the process is running.');
79995 }
79996
79997 $this->input = ProcessUtils::validateInput(__METHOD__, $input);
79998
79999 return $this;
80000 }
80001
80002
80003
80004
80005
80006
80007 public function getOptions()
80008 {
80009 return $this->options;
80010 }
80011
80012
80013
80014
80015
80016
80017
80018
80019 public function setOptions(array $options)
80020 {
80021 $this->options = $options;
80022
80023 return $this;
80024 }
80025
80026
80027
80028
80029
80030
80031
80032
80033 public function getEnhanceWindowsCompatibility()
80034 {
80035 return $this->enhanceWindowsCompatibility;
80036 }
80037
80038
80039
80040
80041
80042
80043
80044
80045 public function setEnhanceWindowsCompatibility($enhance)
80046 {
80047 $this->enhanceWindowsCompatibility = (bool) $enhance;
80048
80049 return $this;
80050 }
80051
80052
80053
80054
80055
80056
80057 public function getEnhanceSigchildCompatibility()
80058 {
80059 return $this->enhanceSigchildCompatibility;
80060 }
80061
80062
80063
80064
80065
80066
80067
80068
80069
80070
80071
80072
80073 public function setEnhanceSigchildCompatibility($enhance)
80074 {
80075 $this->enhanceSigchildCompatibility = (bool) $enhance;
80076
80077 return $this;
80078 }
80079
80080
80081
80082
80083
80084
80085
80086
80087
80088 public function checkTimeout()
80089 {
80090 if (self::STATUS_STARTED !== $this->status) {
80091 return;
80092 }
80093
80094 if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
80095 $this->stop(0);
80096
80097 throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_GENERAL);
80098 }
80099
80100 if (null !== $this->idleTimeout && $this->idleTimeout < microtime(true) - $this->lastOutputTime) {
80101 $this->stop(0);
80102
80103 throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_IDLE);
80104 }
80105 }
80106
80107
80108
80109
80110
80111
80112 public static function isPtySupported()
80113 {
80114 static $result;
80115
80116 if (null !== $result) {
80117 return $result;
80118 }
80119
80120 if ('\\' === \DIRECTORY_SEPARATOR) {
80121 return $result = false;
80122 }
80123
80124 return $result = (bool) @proc_open('echo 1 >/dev/null', array(array('pty'), array('pty'), array('pty')), $pipes);
80125 }
80126
80127
80128
80129
80130
80131
80132 private function getDescriptors()
80133 {
80134 if ('\\' === \DIRECTORY_SEPARATOR) {
80135 $this->processPipes = WindowsPipes::create($this, $this->input);
80136 } else {
80137 $this->processPipes = UnixPipes::create($this, $this->input);
80138 }
80139
80140 return $this->processPipes->getDescriptors();
80141 }
80142
80143
80144
80145
80146
80147
80148
80149
80150
80151
80152
80153 protected function buildCallback($callback)
80154 {
80155 $that = $this;
80156 $out = self::OUT;
80157 $callback = function ($type, $data) use ($that, $callback, $out) {
80158 if ($out == $type) {
80159 $that->addOutput($data);
80160 } else {
80161 $that->addErrorOutput($data);
80162 }
80163
80164 if (null !== $callback) {
80165 \call_user_func($callback, $type, $data);
80166 }
80167 };
80168
80169 return $callback;
80170 }
80171
80172
80173
80174
80175
80176
80177 protected function updateStatus($blocking)
80178 {
80179 if (self::STATUS_STARTED !== $this->status) {
80180 return;
80181 }
80182
80183 $this->processInformation = proc_get_status($this->process);
80184 $running = $this->processInformation['running'];
80185
80186 $this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running);
80187
80188 if ($this->fallbackStatus && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
80189 $this->processInformation = $this->fallbackStatus + $this->processInformation;
80190 }
80191
80192 if (!$running) {
80193 $this->close();
80194 }
80195 }
80196
80197
80198
80199
80200
80201
80202 protected function isSigchildEnabled()
80203 {
80204 if (null !== self::$sigchild) {
80205 return self::$sigchild;
80206 }
80207
80208 if (!\function_exists('phpinfo') || \defined('HHVM_VERSION')) {
80209 return self::$sigchild = false;
80210 }
80211
80212 ob_start();
80213 phpinfo(INFO_GENERAL);
80214
80215 return self::$sigchild = false !== strpos(ob_get_clean(), '--enable-sigchild');
80216 }
80217
80218
80219
80220
80221
80222
80223
80224
80225 private function readPipesForOutput($caller)
80226 {
80227 if ($this->outputDisabled) {
80228 throw new LogicException('Output has been disabled.');
80229 }
80230
80231 $this->requireProcessIsStarted($caller);
80232
80233 $this->updateStatus(false);
80234 }
80235
80236
80237
80238
80239
80240
80241
80242
80243
80244
80245 private function validateTimeout($timeout)
80246 {
80247 $timeout = (float) $timeout;
80248
80249 if (0.0 === $timeout) {
80250 $timeout = null;
80251 } elseif ($timeout < 0) {
80252 throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
80253 }
80254
80255 return $timeout;
80256 }
80257
80258
80259
80260
80261
80262
80263
80264 private function readPipes($blocking, $close)
80265 {
80266 $result = $this->processPipes->readAndWrite($blocking, $close);
80267
80268 $callback = $this->callback;
80269 foreach ($result as $type => $data) {
80270 if (3 !== $type) {
80271 $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data);
80272 } elseif (!isset($this->fallbackStatus['signaled'])) {
80273 $this->fallbackStatus['exitcode'] = (int) $data;
80274 }
80275 }
80276 }
80277
80278
80279
80280
80281
80282
80283 private function close()
80284 {
80285 $this->processPipes->close();
80286 if (\is_resource($this->process)) {
80287 proc_close($this->process);
80288 }
80289 $this->exitcode = $this->processInformation['exitcode'];
80290 $this->status = self::STATUS_TERMINATED;
80291
80292 if (-1 === $this->exitcode) {
80293 if ($this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) {
80294
80295 $this->exitcode = 128 + $this->processInformation['termsig'];
80296 } elseif ($this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
80297 $this->processInformation['signaled'] = true;
80298 $this->processInformation['termsig'] = -1;
80299 }
80300 }
80301
80302
80303
80304
80305 $this->callback = null;
80306
80307 return $this->exitcode;
80308 }
80309
80310
80311
80312
80313 private function resetProcessData()
80314 {
80315 $this->starttime = null;
80316 $this->callback = null;
80317 $this->exitcode = null;
80318 $this->fallbackStatus = array();
80319 $this->processInformation = null;
80320 $this->stdout = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+b');
80321 $this->stderr = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+b');
80322 $this->process = null;
80323 $this->latestSignal = null;
80324 $this->status = self::STATUS_READY;
80325 $this->incrementalOutputOffset = 0;
80326 $this->incrementalErrorOutputOffset = 0;
80327 }
80328
80329
80330
80331
80332
80333
80334
80335
80336
80337
80338
80339
80340
80341 private function doSignal($signal, $throwException)
80342 {
80343 if (null === $pid = $this->getPid()) {
80344 if ($throwException) {
80345 throw new LogicException('Can not send signal on a non running process.');
80346 }
80347
80348 return false;
80349 }
80350
80351 if ('\\' === \DIRECTORY_SEPARATOR) {
80352 exec(sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode);
80353 if ($exitCode && $this->isRunning()) {
80354 if ($throwException) {
80355 throw new RuntimeException(sprintf('Unable to kill the process (%s).', implode(' ', $output)));
80356 }
80357
80358 return false;
80359 }
80360 } else {
80361 if (!$this->enhanceSigchildCompatibility || !$this->isSigchildEnabled()) {
80362 $ok = @proc_terminate($this->process, $signal);
80363 } elseif (\function_exists('posix_kill')) {
80364 $ok = @posix_kill($pid, $signal);
80365 } elseif ($ok = proc_open(sprintf('kill -%d %d', $signal, $pid), array(2 => array('pipe', 'w')), $pipes)) {
80366 $ok = false === fgets($pipes[2]);
80367 }
80368 if (!$ok) {
80369 if ($throwException) {
80370 throw new RuntimeException(sprintf('Error while sending signal `%s`.', $signal));
80371 }
80372
80373 return false;
80374 }
80375 }
80376
80377 $this->latestSignal = (int) $signal;
80378 $this->fallbackStatus['signaled'] = true;
80379 $this->fallbackStatus['exitcode'] = -1;
80380 $this->fallbackStatus['termsig'] = $this->latestSignal;
80381
80382 return true;
80383 }
80384
80385
80386
80387
80388
80389
80390
80391
80392 private function requireProcessIsStarted($functionName)
80393 {
80394 if (!$this->isStarted()) {
80395 throw new LogicException(sprintf('Process must be started before calling %s.', $functionName));
80396 }
80397 }
80398
80399
80400
80401
80402
80403
80404
80405
80406 private function requireProcessIsTerminated($functionName)
80407 {
80408 if (!$this->isTerminated()) {
80409 throw new LogicException(sprintf('Process must be terminated before calling %s.', $functionName));
80410 }
80411 }
80412 }
80413 <?php
80414
80415
80416
80417
80418
80419
80420
80421
80422
80423
80424 namespace Symfony\Component\Process;
80425
80426 use Symfony\Component\Process\Exception\InvalidArgumentException;
80427 use Symfony\Component\Process\Exception\LogicException;
80428
80429
80430
80431
80432 class ProcessBuilder
80433 {
80434 private $arguments;
80435 private $cwd;
80436 private $env = array();
80437 private $input;
80438 private $timeout = 60;
80439 private $options = array();
80440 private $inheritEnv = true;
80441 private $prefix = array();
80442 private $outputDisabled = false;
80443
80444
80445
80446
80447 public function __construct(array $arguments = array())
80448 {
80449 $this->arguments = $arguments;
80450 }
80451
80452
80453
80454
80455
80456
80457
80458
80459 public static function create(array $arguments = array())
80460 {
80461 return new static($arguments);
80462 }
80463
80464
80465
80466
80467
80468
80469
80470
80471 public function add($argument)
80472 {
80473 $this->arguments[] = $argument;
80474
80475 return $this;
80476 }
80477
80478
80479
80480
80481
80482
80483
80484
80485
80486
80487 public function setPrefix($prefix)
80488 {
80489 $this->prefix = \is_array($prefix) ? $prefix : array($prefix);
80490
80491 return $this;
80492 }
80493
80494
80495
80496
80497
80498
80499
80500
80501
80502
80503
80504 public function setArguments(array $arguments)
80505 {
80506 $this->arguments = $arguments;
80507
80508 return $this;
80509 }
80510
80511
80512
80513
80514
80515
80516
80517
80518 public function setWorkingDirectory($cwd)
80519 {
80520 $this->cwd = $cwd;
80521
80522 return $this;
80523 }
80524
80525
80526
80527
80528
80529
80530
80531
80532 public function inheritEnvironmentVariables($inheritEnv = true)
80533 {
80534 $this->inheritEnv = $inheritEnv;
80535
80536 return $this;
80537 }
80538
80539
80540
80541
80542
80543
80544
80545
80546
80547
80548
80549
80550 public function setEnv($name, $value)
80551 {
80552 $this->env[$name] = $value;
80553
80554 return $this;
80555 }
80556
80557
80558
80559
80560
80561
80562
80563
80564
80565
80566
80567
80568 public function addEnvironmentVariables(array $variables)
80569 {
80570 $this->env = array_replace($this->env, $variables);
80571
80572 return $this;
80573 }
80574
80575
80576
80577
80578
80579
80580
80581
80582
80583
80584
80585
80586 public function setInput($input)
80587 {
80588 $this->input = ProcessUtils::validateInput(__METHOD__, $input);
80589
80590 return $this;
80591 }
80592
80593
80594
80595
80596
80597
80598
80599
80600
80601
80602
80603
80604 public function setTimeout($timeout)
80605 {
80606 if (null === $timeout) {
80607 $this->timeout = null;
80608
80609 return $this;
80610 }
80611
80612 $timeout = (float) $timeout;
80613
80614 if ($timeout < 0) {
80615 throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
80616 }
80617
80618 $this->timeout = $timeout;
80619
80620 return $this;
80621 }
80622
80623
80624
80625
80626
80627
80628
80629
80630
80631 public function setOption($name, $value)
80632 {
80633 $this->options[$name] = $value;
80634
80635 return $this;
80636 }
80637
80638
80639
80640
80641
80642
80643 public function disableOutput()
80644 {
80645 $this->outputDisabled = true;
80646
80647 return $this;
80648 }
80649
80650
80651
80652
80653
80654
80655 public function enableOutput()
80656 {
80657 $this->outputDisabled = false;
80658
80659 return $this;
80660 }
80661
80662
80663
80664
80665
80666
80667
80668
80669 public function getProcess()
80670 {
80671 if (0 === \count($this->prefix) && 0 === \count($this->arguments)) {
80672 throw new LogicException('You must add() command arguments before calling getProcess().');
80673 }
80674
80675 $options = $this->options;
80676
80677 $arguments = array_merge($this->prefix, $this->arguments);
80678 $script = implode(' ', array_map(array(__NAMESPACE__.'\\ProcessUtils', 'escapeArgument'), $arguments));
80679
80680 if ($this->inheritEnv) {
80681
80682 $env = array_replace($_ENV, $_SERVER, $this->env);
80683 } else {
80684 $env = $this->env;
80685 }
80686
80687 $process = new Process($script, $this->cwd, $env, $this->input, $this->timeout, $options);
80688
80689 if ($this->outputDisabled) {
80690 $process->disableOutput();
80691 }
80692
80693 return $process;
80694 }
80695 }
80696 <?php
80697
80698
80699
80700
80701
80702
80703
80704
80705
80706
80707 namespace Symfony\Component\Process;
80708
80709 use Symfony\Component\Process\Exception\InvalidArgumentException;
80710
80711
80712
80713
80714
80715
80716
80717
80718 class ProcessUtils
80719 {
80720
80721
80722
80723 private function __construct()
80724 {
80725 }
80726
80727
80728
80729
80730
80731
80732
80733
80734 public static function escapeArgument($argument)
80735 {
80736
80737
80738
80739
80740 if ('\\' === \DIRECTORY_SEPARATOR) {
80741 if ('' === $argument) {
80742 return escapeshellarg($argument);
80743 }
80744
80745 $escapedArgument = '';
80746 $quote = false;
80747 foreach (preg_split('/(")/', $argument, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $part) {
80748 if ('"' === $part) {
80749 $escapedArgument .= '\\"';
80750 } elseif (self::isSurroundedBy($part, '%')) {
80751
80752 $escapedArgument .= '^%"'.substr($part, 1, -1).'"^%';
80753 } else {
80754
80755 if ('\\' === substr($part, -1)) {
80756 $part .= '\\';
80757 }
80758 $quote = true;
80759 $escapedArgument .= $part;
80760 }
80761 }
80762 if ($quote) {
80763 $escapedArgument = '"'.$escapedArgument.'"';
80764 }
80765
80766 return $escapedArgument;
80767 }
80768
80769 return "'".str_replace("'", "'\\''", $argument)."'";
80770 }
80771
80772
80773
80774
80775
80776
80777
80778
80779
80780
80781
80782
80783
80784 public static function validateInput($caller, $input)
80785 {
80786 if (null !== $input) {
80787 if (\is_resource($input)) {
80788 return $input;
80789 }
80790 if (\is_string($input)) {
80791 return $input;
80792 }
80793 if (is_scalar($input)) {
80794 return (string) $input;
80795 }
80796
80797 if (\is_object($input) && method_exists($input, '__toString')) {
80798 @trigger_error('Passing an object as an input is deprecated since Symfony 2.5 and will be removed in 3.0.', E_USER_DEPRECATED);
80799
80800 return (string) $input;
80801 }
80802
80803 throw new InvalidArgumentException(sprintf('%s only accepts strings or stream resources.', $caller));
80804 }
80805
80806 return $input;
80807 }
80808
80809 private static function isSurroundedBy($arg, $char)
80810 {
80811 return 2 < \strlen($arg) && $char === $arg[0] && $char === $arg[\strlen($arg) - 1];
80812 }
80813 }
80814 Copyright (c) 2011 Jordi Boggiano
80815
80816 Permission is hereby granted, free of charge, to any person obtaining a copy
80817 of this software and associated documentation files (the "Software"), to deal
80818 in the Software without restriction, including without limitation the rights
80819 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
80820 copies of the Software, and to permit persons to whom the Software is furnished
80821 to do so, subject to the following conditions:
80822
80823 The above copyright notice and this permission notice shall be included in all
80824 copies or substantial portions of the Software.
80825
80826 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
80827 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
80828 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
80829 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
80830 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
80831 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
80832 THE SOFTWARE.
80833 <?php
80834
80835
80836
80837
80838
80839
80840
80841
80842
80843
80844 namespace Seld\JsonLint;
80845
80846 class DuplicateKeyException extends ParsingException
80847 {
80848
80849
80850
80851
80852
80853 public function __construct($message, $key, array $details = array())
80854 {
80855 $details['key'] = $key;
80856 parent::__construct($message, $details);
80857 }
80858
80859 public function getKey()
80860 {
80861 return $this->details['key'];
80862 }
80863
80864
80865
80866
80867 public function getDetails()
80868 {
80869 return $this->details;
80870 }
80871 }
80872 <?php
80873
80874
80875
80876
80877
80878
80879
80880
80881
80882
80883 namespace Seld\JsonLint;
80884 use stdClass;
80885
80886
80887
80888
80889
80890
80891
80892
80893
80894
80895
80896
80897
80898
80899 class JsonParser
80900 {
80901 const DETECT_KEY_CONFLICTS = 1;
80902 const ALLOW_DUPLICATE_KEYS = 2;
80903 const PARSE_TO_ASSOC = 4;
80904
80905 private $lexer;
80906
80907 private $flags;
80908 private $stack;
80909 private $vstack; 
80910 private $lstack; 
80911
80912
80913
80914
80915 private $symbols = array(
80916 'error' => 2,
80917 'JSONString' => 3,
80918 'STRING' => 4,
80919 'JSONNumber' => 5,
80920 'NUMBER' => 6,
80921 'JSONNullLiteral' => 7,
80922 'NULL' => 8,
80923 'JSONBooleanLiteral' => 9,
80924 'TRUE' => 10,
80925 'FALSE' => 11,
80926 'JSONText' => 12,
80927 'JSONValue' => 13,
80928 'EOF' => 14,
80929 'JSONObject' => 15,
80930 'JSONArray' => 16,
80931 '{' => 17,
80932 '}' => 18,
80933 'JSONMemberList' => 19,
80934 'JSONMember' => 20,
80935 ':' => 21,
80936 ',' => 22,
80937 '[' => 23,
80938 ']' => 24,
80939 'JSONElementList' => 25,
80940 '$accept' => 0,
80941 '$end' => 1,
80942 );
80943
80944
80945
80946
80947 private $terminals_ = array(
80948 2 => "error",
80949 4 => "STRING",
80950 6 => "NUMBER",
80951 8 => "NULL",
80952 10 => "TRUE",
80953 11 => "FALSE",
80954 14 => "EOF",
80955 17 => "{",
80956 18 => "}",
80957 21 => ":",
80958 22 => ",",
80959 23 => "[",
80960 24 => "]",
80961 );
80962
80963 private $productions_ = array(
80964 0,
80965 array(3, 1),
80966 array(5, 1),
80967 array(7, 1),
80968 array(9, 1),
80969 array(9, 1),
80970 array(12, 2),
80971 array(13, 1),
80972 array(13, 1),
80973 array(13, 1),
80974 array(13, 1),
80975 array(13, 1),
80976 array(13, 1),
80977 array(15, 2),
80978 array(15, 3),
80979 array(20, 3),
80980 array(19, 1),
80981 array(19, 3),
80982 array(16, 2),
80983 array(16, 3),
80984 array(25, 1),
80985 array(25, 3)
80986 );
80987
80988 private $table = array(array(3 => 5, 4 => array(1,12), 5 => 6, 6 => array(1,13), 7 => 3, 8 => array(1,9), 9 => 4, 10 => array(1,10), 11 => array(1,11), 12 => 1, 13 => 2, 15 => 7, 16 => 8, 17 => array(1,14), 23 => array(1,15)), array( 1 => array(3)), array( 14 => array(1,16)), array( 14 => array(2,7), 18 => array(2,7), 22 => array(2,7), 24 => array(2,7)), array( 14 => array(2,8), 18 => array(2,8), 22 => array(2,8), 24 => array(2,8)), array( 14 => array(2,9), 18 => array(2,9), 22 => array(2,9), 24 => array(2,9)), array( 14 => array(2,10), 18 => array(2,10), 22 => array(2,10), 24 => array(2,10)), array( 14 => array(2,11), 18 => array(2,11), 22 => array(2,11), 24 => array(2,11)), array( 14 => array(2,12), 18 => array(2,12), 22 => array(2,12), 24 => array(2,12)), array( 14 => array(2,3), 18 => array(2,3), 22 => array(2,3), 24 => array(2,3)), array( 14 => array(2,4), 18 => array(2,4), 22 => array(2,4), 24 => array(2,4)), array( 14 => array(2,5), 18 => array(2,5), 22 => array(2,5), 24 => array(2,5)), array( 14 => array(2,1), 18 => array(2,1), 21 => array(2,1), 22 => array(2,1), 24 => array(2,1)), array( 14 => array(2,2), 18 => array(2,2), 22 => array(2,2), 24 => array(2,2)), array( 3 => 20, 4 => array(1,12), 18 => array(1,17), 19 => 18, 20 => 19 ), array( 3 => 5, 4 => array(1,12), 5 => 6, 6 => array(1,13), 7 => 3, 8 => array(1,9), 9 => 4, 10 => array(1,10), 11 => array(1,11), 13 => 23, 15 => 7, 16 => 8, 17 => array(1,14), 23 => array(1,15), 24 => array(1,21), 25 => 22 ), array( 1 => array(2,6)), array( 14 => array(2,13), 18 => array(2,13), 22 => array(2,13), 24 => array(2,13)), array( 18 => array(1,24), 22 => array(1,25)), array( 18 => array(2,16), 22 => array(2,16)), array( 21 => array(1,26)), array( 14 => array(2,18), 18 => array(2,18), 22 => array(2,18), 24 => array(2,18)), array( 22 => array(1,28), 24 => array(1,27)), array( 22 => array(2,20), 24 => array(2,20)), array( 14 => array(2,14), 18 => array(2,14), 22 => array(2,14), 24 => array(2,14)), array( 3 => 20, 4 => array(1,12), 20 => 29 ), array( 3 => 5, 4 => array(1,12), 5 => 6, 6 => array(1,13), 7 => 3, 8 => array(1,9), 9 => 4, 10 => array(1,10), 11 => array(1,11), 13 => 30, 15 => 7, 16 => 8, 17 => array(1,14), 23 => array(1,15)), array( 14 => array(2,19), 18 => array(2,19), 22 => array(2,19), 24 => array(2,19)), array( 3 => 5, 4 => array(1,12), 5 => 6, 6 => array(1,13), 7 => 3, 8 => array(1,9), 9 => 4, 10 => array(1,10), 11 => array(1,11), 13 => 31, 15 => 7, 16 => 8, 17 => array(1,14), 23 => array(1,15)), array( 18 => array(2,17), 22 => array(2,17)), array( 18 => array(2,15), 22 => array(2,15)), array( 22 => array(2,21), 24 => array(2,21)),
80989 );
80990
80991 private $defaultActions = array(
80992 16 => array(2, 6)
80993 );
80994
80995
80996
80997
80998
80999
81000 public function lint($input, $flags = 0)
81001 {
81002 try {
81003 $this->parse($input, $flags);
81004 } catch (ParsingException $e) {
81005 return $e;
81006 }
81007 return null;
81008 }
81009
81010
81011
81012
81013
81014
81015
81016 public function parse($input, $flags = 0)
81017 {
81018 $this->failOnBOM($input);
81019
81020 $this->flags = $flags;
81021
81022 $this->stack = array(0);
81023 $this->vstack = array(null);
81024 $this->lstack = array();
81025
81026 $yytext = '';
81027 $yylineno = 0;
81028 $yyleng = 0;
81029 $recovering = 0;
81030 $TERROR = 2;
81031 $EOF = 1;
81032
81033 $this->lexer = new Lexer();
81034 $this->lexer->setInput($input);
81035
81036 $yyloc = $this->lexer->yylloc;
81037 $this->lstack[] = $yyloc;
81038
81039 $symbol = null;
81040 $preErrorSymbol = null;
81041 $state = null;
81042 $action = null;
81043 $a = null;
81044 $r = null;
81045 $yyval = new stdClass;
81046 $p = null;
81047 $len = null;
81048 $newState = null;
81049 $expected = null;
81050 $errStr = null;
81051
81052 while (true) {
81053
81054 $state = $this->stack[\count($this->stack)-1];
81055
81056
81057 if (isset($this->defaultActions[$state])) {
81058 $action = $this->defaultActions[$state];
81059 } else {
81060 if ($symbol == null) {
81061 $symbol = $this->lex();
81062 }
81063
81064 $action = isset($this->table[$state][$symbol]) ? $this->table[$state][$symbol] : false;
81065 }
81066
81067
81068 if (!$action || !$action[0]) {
81069 if (!$recovering) {
81070
81071 $expected = array();
81072 foreach ($this->table[$state] as $p => $ignore) {
81073 if (isset($this->terminals_[$p]) && $p > 2) {
81074 $expected[] = "'" . $this->terminals_[$p] . "'";
81075 }
81076 }
81077
81078 $message = null;
81079 if (\in_array("'STRING'", $expected) && \in_array(substr($this->lexer->match, 0, 1), array('"', "'"))) {
81080 $message = "Invalid string";
81081 if ("'" === substr($this->lexer->match, 0, 1)) {
81082 $message .= ", it appears you used single quotes instead of double quotes";
81083 } elseif (preg_match('{".+?(\\\\[^"bfnrt/\\\\u](...)?)}', $this->lexer->getFullUpcomingInput(), $match)) {
81084 $message .= ", it appears you have an unescaped backslash at: ".$match[1];
81085 } elseif (preg_match('{"(?:[^"]+|\\\\")*$}m', $this->lexer->getFullUpcomingInput())) {
81086 $message .= ", it appears you forgot to terminate a string, or attempted to write a multiline string which is invalid";
81087 }
81088 }
81089
81090 $errStr = 'Parse error on line ' . ($yylineno+1) . ":\n";
81091 $errStr .= $this->lexer->showPosition() . "\n";
81092 if ($message) {
81093 $errStr .= $message;
81094 } else {
81095 $errStr .= (\count($expected) > 1) ? "Expected one of: " : "Expected: ";
81096 $errStr .= implode(', ', $expected);
81097 }
81098
81099 if (',' === substr(trim($this->lexer->getPastInput()), -1)) {
81100 $errStr .= " - It appears you have an extra trailing comma";
81101 }
81102
81103 $this->parseError($errStr, array(
81104 'text' => $this->lexer->match,
81105 'token' => !empty($this->terminals_[$symbol]) ? $this->terminals_[$symbol] : $symbol,
81106 'line' => $this->lexer->yylineno,
81107 'loc' => $yyloc,
81108 'expected' => $expected,
81109 ));
81110 }
81111
81112
81113 if ($recovering == 3) {
81114 if ($symbol == $EOF) {
81115 throw new ParsingException($errStr ?: 'Parsing halted.');
81116 }
81117
81118
81119 $yyleng = $this->lexer->yyleng;
81120 $yytext = $this->lexer->yytext;
81121 $yylineno = $this->lexer->yylineno;
81122 $yyloc = $this->lexer->yylloc;
81123 $symbol = $this->lex();
81124 }
81125
81126
81127 while (true) {
81128
81129 if (\array_key_exists($TERROR, $this->table[$state])) {
81130 break;
81131 }
81132 if ($state == 0) {
81133 throw new ParsingException($errStr ?: 'Parsing halted.');
81134 }
81135 $this->popStack(1);
81136 $state = $this->stack[\count($this->stack)-1];
81137 }
81138
81139 $preErrorSymbol = $symbol; 
81140 $symbol = $TERROR; 
81141 $state = $this->stack[\count($this->stack)-1];
81142 $action = isset($this->table[$state][$TERROR]) ? $this->table[$state][$TERROR] : false;
81143 $recovering = 3; 
81144 }
81145
81146
81147 if (\is_array($action[0]) && \count($action) > 1) {
81148 throw new ParsingException('Parse Error: multiple actions possible at state: ' . $state . ', token: ' . $symbol);
81149 }
81150
81151 switch ($action[0]) {
81152 case 1: 
81153 $this->stack[] = $symbol;
81154 $this->vstack[] = $this->lexer->yytext;
81155 $this->lstack[] = $this->lexer->yylloc;
81156 $this->stack[] = $action[1]; 
81157 $symbol = null;
81158 if (!$preErrorSymbol) { 
81159 $yyleng = $this->lexer->yyleng;
81160 $yytext = $this->lexer->yytext;
81161 $yylineno = $this->lexer->yylineno;
81162 $yyloc = $this->lexer->yylloc;
81163 if ($recovering > 0) {
81164 $recovering--;
81165 }
81166 } else { 
81167 $symbol = $preErrorSymbol;
81168 $preErrorSymbol = null;
81169 }
81170 break;
81171
81172 case 2: 
81173 $len = $this->productions_[$action[1]][1];
81174
81175
81176 $yyval->token = $this->vstack[\count($this->vstack) - $len]; 
81177
81178 $yyval->store = array( 
81179 'first_line' => $this->lstack[\count($this->lstack) - ($len ?: 1)]['first_line'],
81180 'last_line' => $this->lstack[\count($this->lstack) - 1]['last_line'],
81181 'first_column' => $this->lstack[\count($this->lstack) - ($len ?: 1)]['first_column'],
81182 'last_column' => $this->lstack[\count($this->lstack) - 1]['last_column'],
81183 );
81184 $r = $this->performAction($yyval, $yytext, $yyleng, $yylineno, $action[1], $this->vstack);
81185
81186 if (!$r instanceof Undefined) {
81187 return $r;
81188 }
81189
81190 if ($len) {
81191 $this->popStack($len);
81192 }
81193
81194 $this->stack[] = $this->productions_[$action[1]][0]; 
81195 $this->vstack[] = $yyval->token;
81196 $this->lstack[] = $yyval->store;
81197 $newState = $this->table[$this->stack[\count($this->stack)-2]][$this->stack[\count($this->stack)-1]];
81198 $this->stack[] = $newState;
81199 break;
81200
81201 case 3: 
81202
81203 return true;
81204 }
81205 }
81206 }
81207
81208 protected function parseError($str, $hash)
81209 {
81210 throw new ParsingException($str, $hash);
81211 }
81212
81213
81214
81215
81216 private function performAction(stdClass $yyval, $yytext, $yyleng, $yylineno, $yystate, &$tokens)
81217 {
81218
81219 $len = \count($tokens) - 1;
81220 switch ($yystate) {
81221 case 1:
81222 $yytext = preg_replace_callback('{(?:\\\\["bfnrt/\\\\]|\\\\u[a-fA-F0-9]{4})}', array($this, 'stringInterpolation'), $yytext);
81223 $yyval->token = $yytext;
81224 break;
81225 case 2:
81226 if (strpos($yytext, 'e') !== false || strpos($yytext, 'E') !== false) {
81227 $yyval->token = \floatval($yytext);
81228 } else {
81229 $yyval->token = strpos($yytext, '.') === false ? \intval($yytext) : \floatval($yytext);
81230 }
81231 break;
81232 case 3:
81233 $yyval->token = null;
81234 break;
81235 case 4:
81236 $yyval->token = true;
81237 break;
81238 case 5:
81239 $yyval->token = false;
81240 break;
81241 case 6:
81242 return $yyval->token = $tokens[$len-1];
81243 case 13:
81244 if ($this->flags & self::PARSE_TO_ASSOC) {
81245 $yyval->token = array();
81246 } else {
81247 $yyval->token = new stdClass;
81248 }
81249 break;
81250 case 14:
81251 $yyval->token = $tokens[$len-1];
81252 break;
81253 case 15:
81254 $yyval->token = array($tokens[$len-2], $tokens[$len]);
81255 break;
81256 case 16:
81257 if (PHP_VERSION_ID < 70100) {
81258 $property = $tokens[$len][0] === '' ? '_empty_' : $tokens[$len][0];
81259 } else {
81260 $property = $tokens[$len][0];
81261 }
81262 if ($this->flags & self::PARSE_TO_ASSOC) {
81263 $yyval->token = array();
81264 $yyval->token[$property] = $tokens[$len][1];
81265 } else {
81266 $yyval->token = new stdClass;
81267 $yyval->token->$property = $tokens[$len][1];
81268 }
81269 break;
81270 case 17:
81271 if ($this->flags & self::PARSE_TO_ASSOC) {
81272 $yyval->token =& $tokens[$len-2];
81273 $key = $tokens[$len][0];
81274 if (($this->flags & self::DETECT_KEY_CONFLICTS) && isset($tokens[$len-2][$key])) {
81275 $errStr = 'Parse error on line ' . ($yylineno+1) . ":\n";
81276 $errStr .= $this->lexer->showPosition() . "\n";
81277 $errStr .= "Duplicate key: ".$tokens[$len][0];
81278 throw new DuplicateKeyException($errStr, $tokens[$len][0], array('line' => $yylineno+1));
81279 } elseif (($this->flags & self::ALLOW_DUPLICATE_KEYS) && isset($tokens[$len-2][$key])) {
81280 $duplicateCount = 1;
81281 do {
81282 $duplicateKey = $key . '.' . $duplicateCount++;
81283 } while (isset($tokens[$len-2][$duplicateKey]));
81284 $key = $duplicateKey;
81285 }
81286 $tokens[$len-2][$key] = $tokens[$len][1];
81287 } else {
81288 $yyval->token = $tokens[$len-2];
81289 if (PHP_VERSION_ID < 70100) {
81290 $key = $tokens[$len][0] === '' ? '_empty_' : $tokens[$len][0];
81291 } else {
81292 $key = $tokens[$len][0];
81293 }
81294 if (($this->flags & self::DETECT_KEY_CONFLICTS) && isset($tokens[$len-2]->{$key})) {
81295 $errStr = 'Parse error on line ' . ($yylineno+1) . ":\n";
81296 $errStr .= $this->lexer->showPosition() . "\n";
81297 $errStr .= "Duplicate key: ".$tokens[$len][0];
81298 throw new DuplicateKeyException($errStr, $tokens[$len][0], array('line' => $yylineno+1));
81299 } elseif (($this->flags & self::ALLOW_DUPLICATE_KEYS) && isset($tokens[$len-2]->{$key})) {
81300 $duplicateCount = 1;
81301 do {
81302 $duplicateKey = $key . '.' . $duplicateCount++;
81303 } while (isset($tokens[$len-2]->$duplicateKey));
81304 $key = $duplicateKey;
81305 }
81306 $tokens[$len-2]->$key = $tokens[$len][1];
81307 }
81308 break;
81309 case 18:
81310 $yyval->token = array();
81311 break;
81312 case 19:
81313 $yyval->token = $tokens[$len-1];
81314 break;
81315 case 20:
81316 $yyval->token = array($tokens[$len]);
81317 break;
81318 case 21:
81319 $tokens[$len-2][] = $tokens[$len];
81320 $yyval->token = $tokens[$len-2];
81321 break;
81322 }
81323
81324 return new Undefined();
81325 }
81326
81327 private function stringInterpolation($match)
81328 {
81329 switch ($match[0]) {
81330 case '\\\\':
81331 return '\\';
81332 case '\"':
81333 return '"';
81334 case '\b':
81335 return \chr(8);
81336 case '\f':
81337 return \chr(12);
81338 case '\n':
81339 return "\n";
81340 case '\r':
81341 return "\r";
81342 case '\t':
81343 return "\t";
81344 case '\/':
81345 return "/";
81346 default:
81347 return html_entity_decode('&#x'.ltrim(substr($match[0], 2), '0').';', ENT_QUOTES, 'UTF-8');
81348 }
81349 }
81350
81351 private function popStack($n)
81352 {
81353 $this->stack = \array_slice($this->stack, 0, - (2 * $n));
81354 $this->vstack = \array_slice($this->vstack, 0, - $n);
81355 $this->lstack = \array_slice($this->lstack, 0, - $n);
81356 }
81357
81358 private function lex()
81359 {
81360 $token = $this->lexer->lex() ?: 1; 
81361
81362 if (!is_numeric($token)) {
81363 $token = isset($this->symbols[$token]) ? $this->symbols[$token] : $token;
81364 }
81365
81366 return $token;
81367 }
81368
81369 private function failOnBOM($input)
81370 {
81371
81372 $bom = "\xEF\xBB\xBF";
81373
81374 if (substr($input, 0, 3) === $bom) {
81375 $this->parseError("BOM detected, make sure your input does not include a Unicode Byte-Order-Mark", array());
81376 }
81377 }
81378 }
81379 <?php
81380
81381
81382
81383
81384
81385
81386
81387
81388
81389
81390 namespace Seld\JsonLint;
81391
81392
81393
81394
81395
81396
81397 class Lexer
81398 {
81399 private $EOF = 1;
81400
81401
81402
81403 private $rules = array(
81404 0 => '/\G\s+/',
81405 1 => '/\G-?([0-9]|[1-9][0-9]+)(\.[0-9]+)?([eE][+-]?[0-9]+)?\b/',
81406 2 => '{\G"(?>\\\\["bfnrt/\\\\]|\\\\u[a-fA-F0-9]{4}|[^\0-\x1f\\\\"]++)*+"}',
81407 3 => '/\G\{/',
81408 4 => '/\G\}/',
81409 5 => '/\G\[/',
81410 6 => '/\G\]/',
81411 7 => '/\G,/',
81412 8 => '/\G:/',
81413 9 => '/\Gtrue\b/',
81414 10 => '/\Gfalse\b/',
81415 11 => '/\Gnull\b/',
81416 12 => '/\G$/',
81417 13 => '/\G./',
81418 );
81419
81420 private $conditions = array(
81421 "INITIAL" => array(
81422 "rules" => array(0,1,2,3,4,5,6,7,8,9,10,11,12,13),
81423 "inclusive" => true,
81424 ),
81425 );
81426
81427 private $conditionStack;
81428 private $input;
81429 private $more;
81430 private $done;
81431 private $offset;
81432
81433 public $match;
81434 public $yylineno;
81435 public $yyleng;
81436 public $yytext;
81437 public $yylloc;
81438
81439 public function lex()
81440 {
81441 $r = $this->next();
81442 if (!$r instanceof Undefined) {
81443 return $r;
81444 }
81445
81446 return $this->lex();
81447 }
81448
81449 public function setInput($input)
81450 {
81451 $this->input = $input;
81452 $this->more = false;
81453 $this->done = false;
81454 $this->offset = 0;
81455 $this->yylineno = $this->yyleng = 0;
81456 $this->yytext = $this->match = '';
81457 $this->conditionStack = array('INITIAL');
81458 $this->yylloc = array('first_line' => 1, 'first_column' => 0, 'last_line' => 1, 'last_column' => 0);
81459
81460 return $this;
81461 }
81462
81463 public function showPosition()
81464 {
81465 $pre = str_replace("\n", '', $this->getPastInput());
81466 $c = str_repeat('-', max(0, \strlen($pre) - 1)); 
81467
81468 return $pre . str_replace("\n", '', $this->getUpcomingInput()) . "\n" . $c . "^";
81469 }
81470
81471 public function getPastInput()
81472 {
81473 $pastLength = $this->offset - \strlen($this->match);
81474
81475 return ($pastLength > 20 ? '...' : '') . substr($this->input, max(0, $pastLength - 20), min(20, $pastLength));
81476 }
81477
81478 public function getUpcomingInput()
81479 {
81480 $next = $this->match;
81481 if (\strlen($next) < 20) {
81482 $next .= substr($this->input, $this->offset, 20 - \strlen($next));
81483 }
81484
81485 return substr($next, 0, 20) . (\strlen($next) > 20 ? '...' : '');
81486 }
81487
81488 public function getFullUpcomingInput()
81489 {
81490 $next = $this->match;
81491 if (substr($next, 0, 1) === '"' && substr_count($next, '"') === 1) {
81492 $len = \strlen($this->input);
81493 $strEnd = min(strpos($this->input, '"', $this->offset + 1) ?: $len, strpos($this->input, "\n", $this->offset + 1) ?: $len);
81494 $next .= substr($this->input, $this->offset, $strEnd - $this->offset);
81495 } elseif (\strlen($next) < 20) {
81496 $next .= substr($this->input, $this->offset, 20 - \strlen($next));
81497 }
81498
81499 return $next;
81500 }
81501
81502 protected function parseError($str, $hash)
81503 {
81504 throw new \Exception($str);
81505 }
81506
81507 private function next()
81508 {
81509 if ($this->done) {
81510 return $this->EOF;
81511 }
81512 if ($this->offset === \strlen($this->input)) {
81513 $this->done = true;
81514 }
81515
81516 $token = null;
81517 $match = null;
81518 $col = null;
81519 $lines = null;
81520
81521 if (!$this->more) {
81522 $this->yytext = '';
81523 $this->match = '';
81524 }
81525
81526 $rules = $this->getCurrentRules();
81527 $rulesLen = \count($rules);
81528
81529 for ($i=0; $i < $rulesLen; $i++) {
81530 if (preg_match($this->rules[$rules[$i]], $this->input, $match, 0, $this->offset)) {
81531 preg_match_all('/\n.*/', $match[0], $lines);
81532 $lines = $lines[0];
81533 if ($lines) {
81534 $this->yylineno += \count($lines);
81535 }
81536
81537 $this->yylloc = array(
81538 'first_line' => $this->yylloc['last_line'],
81539 'last_line' => $this->yylineno+1,
81540 'first_column' => $this->yylloc['last_column'],
81541 'last_column' => $lines ? \strlen($lines[\count($lines) - 1]) - 1 : $this->yylloc['last_column'] + \strlen($match[0]),
81542 );
81543 $this->yytext .= $match[0];
81544 $this->match .= $match[0];
81545 $this->yyleng = \strlen($this->yytext);
81546 $this->more = false;
81547 $this->offset += \strlen($match[0]);
81548 $token = $this->performAction($rules[$i], $this->conditionStack[\count($this->conditionStack)-1]);
81549 if ($token) {
81550 return $token;
81551 }
81552
81553 return new Undefined();
81554 }
81555 }
81556
81557 if ($this->offset === \strlen($this->input)) {
81558 return $this->EOF;
81559 }
81560
81561 $this->parseError(
81562 'Lexical error on line ' . ($this->yylineno+1) . ". Unrecognized text.\n" . $this->showPosition(),
81563 array(
81564 'text' => "",
81565 'token' => null,
81566 'line' => $this->yylineno,
81567 )
81568 );
81569 }
81570
81571 private function getCurrentRules()
81572 {
81573 return $this->conditions[$this->conditionStack[\count($this->conditionStack)-1]]['rules'];
81574 }
81575
81576 private function performAction($avoiding_name_collisions, $YY_START)
81577 {
81578 switch ($avoiding_name_collisions) {
81579 case 0:
81580 break;
81581 case 1:
81582 return 6;
81583 case 2:
81584 $this->yytext = substr($this->yytext, 1, $this->yyleng-2);
81585
81586 return 4;
81587 case 3:
81588 return 17;
81589 case 4:
81590 return 18;
81591 case 5:
81592 return 23;
81593 case 6:
81594 return 24;
81595 case 7:
81596 return 22;
81597 case 8:
81598 return 21;
81599 case 9:
81600 return 10;
81601 case 10:
81602 return 11;
81603 case 11:
81604 return 8;
81605 case 12:
81606 return 14;
81607 case 13:
81608 return 'INVALID';
81609 }
81610 }
81611 }
81612 <?php
81613
81614
81615
81616
81617
81618
81619
81620
81621
81622
81623 namespace Seld\JsonLint;
81624
81625 class ParsingException extends \Exception
81626 {
81627 protected $details;
81628
81629
81630
81631
81632
81633 public function __construct($message, $details = array())
81634 {
81635 $this->details = $details;
81636 parent::__construct($message);
81637 }
81638
81639
81640
81641
81642 public function getDetails()
81643 {
81644 return $this->details;
81645 }
81646 }
81647 <?php
81648
81649
81650
81651
81652
81653
81654
81655
81656
81657
81658 namespace Seld\JsonLint;
81659
81660 class Undefined
81661 {
81662 }
81663 MIT License
81664
81665 Copyright (c) 2016
81666
81667 Permission is hereby granted, free of charge, to any person obtaining a copy
81668 of this software and associated documentation files (the "Software"), to deal
81669 in the Software without restriction, including without limitation the rights
81670 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
81671 copies of the Software, and to permit persons to whom the Software is
81672 furnished to do so, subject to the following conditions:
81673
81674 The above copyright notice and this permission notice shall be included in all
81675 copies or substantial portions of the Software.
81676
81677 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
81678 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
81679 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
81680 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
81681 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
81682 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
81683 SOFTWARE.
81684 <?php
81685
81686 require __DIR__ . '/../vendor/autoload.php';
81687
81688 $data = json_decode(file_get_contents('data.json'));
81689
81690
81691 $validator = new JsonSchema\Validator();
81692 $validator->check($data, (object) array('$ref' => 'file://' . realpath('schema.json')));
81693
81694 if ($validator->isValid()) {
81695 echo "The supplied JSON validates against the schema.\n";
81696 } else {
81697 echo "JSON does not validate. Violations:\n";
81698 foreach ($validator->getErrors() as $error) {
81699 echo sprintf("[%s] %s\n", $error['property'], $error['message']);
81700 }
81701 }
81702 <?php
81703
81704
81705
81706
81707
81708
81709
81710
81711 namespace JsonSchema\Constraints;
81712
81713 use JsonSchema\Entity\JsonPointer;
81714 use JsonSchema\Exception\InvalidArgumentException;
81715 use JsonSchema\Exception\ValidationException;
81716 use JsonSchema\Validator;
81717
81718
81719
81720
81721
81722 class BaseConstraint
81723 {
81724
81725
81726
81727 protected $errors = array();
81728
81729
81730
81731
81732 protected $errorMask = Validator::ERROR_NONE;
81733
81734
81735
81736
81737 protected $factory;
81738
81739
81740
81741
81742 public function __construct(Factory $factory = null)
81743 {
81744 $this->factory = $factory ?: new Factory();
81745 }
81746
81747 public function addError(JsonPointer $path = null, $message, $constraint = '', array $more = null)
81748 {
81749 $error = array(
81750 'property' => $this->convertJsonPointerIntoPropertyPath($path ?: new JsonPointer('')),
81751 'pointer' => ltrim(strval($path ?: new JsonPointer('')), '#'),
81752 'message' => $message,
81753 'constraint' => $constraint,
81754 'context' => $this->factory->getErrorContext(),
81755 );
81756
81757 if ($this->factory->getConfig(Constraint::CHECK_MODE_EXCEPTIONS)) {
81758 throw new ValidationException(sprintf('Error validating %s: %s', $error['pointer'], $error['message']));
81759 }
81760
81761 if (is_array($more) && count($more) > 0) {
81762 $error += $more;
81763 }
81764
81765 $this->errors[] = $error;
81766 $this->errorMask |= $error['context'];
81767 }
81768
81769 public function addErrors(array $errors)
81770 {
81771 if ($errors) {
81772 $this->errors = array_merge($this->errors, $errors);
81773 $errorMask = &$this->errorMask;
81774 array_walk($errors, function ($error) use (&$errorMask) {
81775 if (isset($error['context'])) {
81776 $errorMask |= $error['context'];
81777 }
81778 });
81779 }
81780 }
81781
81782 public function getErrors($errorContext = Validator::ERROR_ALL)
81783 {
81784 if ($errorContext === Validator::ERROR_ALL) {
81785 return $this->errors;
81786 }
81787
81788 return array_filter($this->errors, function ($error) use ($errorContext) {
81789 if ($errorContext & $error['context']) {
81790 return true;
81791 }
81792 });
81793 }
81794
81795 public function numErrors($errorContext = Validator::ERROR_ALL)
81796 {
81797 if ($errorContext === Validator::ERROR_ALL) {
81798 return count($this->errors);
81799 }
81800
81801 return count($this->getErrors($errorContext));
81802 }
81803
81804 public function isValid()
81805 {
81806 return !$this->getErrors();
81807 }
81808
81809
81810
81811
81812
81813 public function reset()
81814 {
81815 $this->errors = array();
81816 $this->errorMask = Validator::ERROR_NONE;
81817 }
81818
81819
81820
81821
81822
81823
81824 public function getErrorMask()
81825 {
81826 return $this->errorMask;
81827 }
81828
81829
81830
81831
81832
81833
81834
81835
81836 public static function arrayToObjectRecursive($array)
81837 {
81838 $json = json_encode($array);
81839 if (json_last_error() !== \JSON_ERROR_NONE) {
81840 $message = 'Unable to encode schema array as JSON';
81841 if (function_exists('json_last_error_msg')) {
81842 $message .= ': ' . json_last_error_msg();
81843 }
81844 throw new InvalidArgumentException($message);
81845 }
81846
81847 return (object) json_decode($json);
81848 }
81849 }
81850 <?php
81851
81852
81853
81854
81855
81856
81857
81858
81859 namespace JsonSchema\Constraints;
81860
81861 use JsonSchema\Entity\JsonPointer;
81862
81863
81864
81865
81866
81867
81868
81869 class CollectionConstraint extends Constraint
81870 {
81871
81872
81873
81874 public function check(&$value, $schema = null, JsonPointer $path = null, $i = null)
81875 {
81876
81877 if (isset($schema->minItems) && count($value) < $schema->minItems) {
81878 $this->addError($path, 'There must be a minimum of ' . $schema->minItems . ' items in the array', 'minItems', array('minItems' => $schema->minItems));
81879 }
81880
81881
81882 if (isset($schema->maxItems) && count($value) > $schema->maxItems) {
81883 $this->addError($path, 'There must be a maximum of ' . $schema->maxItems . ' items in the array', 'maxItems', array('maxItems' => $schema->maxItems));
81884 }
81885
81886
81887 if (isset($schema->uniqueItems) && $schema->uniqueItems) {
81888 $unique = $value;
81889 if (is_array($value) && count($value)) {
81890 $unique = array_map(function ($e) {
81891 return var_export($e, true);
81892 }, $value);
81893 }
81894 if (count(array_unique($unique)) != count($value)) {
81895 $this->addError($path, 'There are no duplicates allowed in the array', 'uniqueItems');
81896 }
81897 }
81898
81899
81900 if (isset($schema->items)) {
81901 $this->validateItems($value, $schema, $path, $i);
81902 }
81903 }
81904
81905
81906
81907
81908
81909
81910
81911
81912
81913 protected function validateItems(&$value, $schema = null, JsonPointer $path = null, $i = null)
81914 {
81915 if (is_object($schema->items)) {
81916
81917 foreach ($value as $k => &$v) {
81918 $initErrors = $this->getErrors();
81919
81920
81921 $this->checkUndefined($v, $schema->items, $path, $k);
81922
81923
81924 if (count($initErrors) < count($this->getErrors()) && (isset($schema->additionalItems) && $schema->additionalItems !== false)) {
81925 $secondErrors = $this->getErrors();
81926 $this->checkUndefined($v, $schema->additionalItems, $path, $k);
81927 }
81928
81929
81930 if (isset($secondErrors) && count($secondErrors) < count($this->getErrors())) {
81931 $this->errors = $secondErrors;
81932 } elseif (isset($secondErrors) && count($secondErrors) === count($this->getErrors())) {
81933 $this->errors = $initErrors;
81934 }
81935 }
81936 unset($v); 
81937
81938 } else {
81939
81940 foreach ($value as $k => &$v) {
81941 if (array_key_exists($k, $schema->items)) {
81942 $this->checkUndefined($v, $schema->items[$k], $path, $k);
81943 } else {
81944
81945 if (property_exists($schema, 'additionalItems')) {
81946 if ($schema->additionalItems !== false) {
81947 $this->checkUndefined($v, $schema->additionalItems, $path, $k);
81948 } else {
81949 $this->addError(
81950 $path, 'The item ' . $i . '[' . $k . '] is not defined and the definition does not allow additional items', 'additionalItems', array('additionalItems' => $schema->additionalItems));
81951 }
81952 } else {
81953
81954 $this->checkUndefined($v, new \stdClass(), $path, $k);
81955 }
81956 }
81957 }
81958 unset($v); 
81959
81960
81961
81962 if (count($value) > 0) {
81963 for ($k = count($value); $k < count($schema->items); $k++) {
81964 $undefinedInstance = $this->factory->createInstanceFor('undefined');
81965 $this->checkUndefined($undefinedInstance, $schema->items[$k], $path, $k);
81966 }
81967 }
81968 }
81969 }
81970 }
81971 <?php
81972
81973
81974
81975
81976
81977
81978
81979
81980 namespace JsonSchema\Constraints;
81981
81982 use JsonSchema\Entity\JsonPointer;
81983
81984
81985
81986
81987
81988
81989
81990 abstract class Constraint extends BaseConstraint implements ConstraintInterface
81991 {
81992 protected $inlineSchemaProperty = '$schema';
81993
81994 const CHECK_MODE_NONE = 0x00000000;
81995 const CHECK_MODE_NORMAL = 0x00000001;
81996 const CHECK_MODE_TYPE_CAST = 0x00000002;
81997 const CHECK_MODE_COERCE_TYPES = 0x00000004;
81998 const CHECK_MODE_APPLY_DEFAULTS = 0x00000008;
81999 const CHECK_MODE_EXCEPTIONS = 0x00000010;
82000 const CHECK_MODE_DISABLE_FORMAT = 0x00000020;
82001 const CHECK_MODE_ONLY_REQUIRED_DEFAULTS = 0x00000080;
82002 const CHECK_MODE_VALIDATE_SCHEMA = 0x00000100;
82003
82004
82005
82006
82007
82008
82009
82010
82011
82012 protected function incrementPath(JsonPointer $path = null, $i)
82013 {
82014 $path = $path ?: new JsonPointer('');
82015 $path = $path->withPropertyPaths(
82016 array_merge(
82017 $path->getPropertyPaths(),
82018 array_filter(array($i), 'strlen')
82019 )
82020 );
82021
82022 return $path;
82023 }
82024
82025
82026
82027
82028
82029
82030
82031
82032
82033 protected function checkArray(&$value, $schema = null, JsonPointer $path = null, $i = null)
82034 {
82035 $validator = $this->factory->createInstanceFor('collection');
82036 $validator->check($value, $schema, $path, $i);
82037
82038 $this->addErrors($validator->getErrors());
82039 }
82040
82041
82042
82043
82044
82045
82046
82047
82048
82049
82050
82051 protected function checkObject(&$value, $schema = null, JsonPointer $path = null, $properties = null,
82052 $additionalProperties = null, $patternProperties = null, $appliedDefaults = array())
82053 {
82054 $validator = $this->factory->createInstanceFor('object');
82055 $validator->check($value, $schema, $path, $properties, $additionalProperties, $patternProperties, $appliedDefaults);
82056
82057 $this->addErrors($validator->getErrors());
82058 }
82059
82060
82061
82062
82063
82064
82065
82066
82067
82068 protected function checkType(&$value, $schema = null, JsonPointer $path = null, $i = null)
82069 {
82070 $validator = $this->factory->createInstanceFor('type');
82071 $validator->check($value, $schema, $path, $i);
82072
82073 $this->addErrors($validator->getErrors());
82074 }
82075
82076
82077
82078
82079
82080
82081
82082
82083
82084 protected function checkUndefined(&$value, $schema = null, JsonPointer $path = null, $i = null, $fromDefault = false)
82085 {
82086 $validator = $this->factory->createInstanceFor('undefined');
82087
82088 $validator->check($value, $this->factory->getSchemaStorage()->resolveRefSchema($schema), $path, $i, $fromDefault);
82089
82090 $this->addErrors($validator->getErrors());
82091 }
82092
82093
82094
82095
82096
82097
82098
82099
82100
82101 protected function checkString($value, $schema = null, JsonPointer $path = null, $i = null)
82102 {
82103 $validator = $this->factory->createInstanceFor('string');
82104 $validator->check($value, $schema, $path, $i);
82105
82106 $this->addErrors($validator->getErrors());
82107 }
82108
82109
82110
82111
82112
82113
82114
82115
82116
82117 protected function checkNumber($value, $schema = null, JsonPointer $path = null, $i = null)
82118 {
82119 $validator = $this->factory->createInstanceFor('number');
82120 $validator->check($value, $schema, $path, $i);
82121
82122 $this->addErrors($validator->getErrors());
82123 }
82124
82125
82126
82127
82128
82129
82130
82131
82132
82133 protected function checkEnum($value, $schema = null, JsonPointer $path = null, $i = null)
82134 {
82135 $validator = $this->factory->createInstanceFor('enum');
82136 $validator->check($value, $schema, $path, $i);
82137
82138 $this->addErrors($validator->getErrors());
82139 }
82140
82141
82142
82143
82144
82145
82146
82147
82148
82149 protected function checkFormat($value, $schema = null, JsonPointer $path = null, $i = null)
82150 {
82151 $validator = $this->factory->createInstanceFor('format');
82152 $validator->check($value, $schema, $path, $i);
82153
82154 $this->addErrors($validator->getErrors());
82155 }
82156
82157
82158
82159
82160
82161
82162 protected function getTypeCheck()
82163 {
82164 return $this->factory->getTypeCheck();
82165 }
82166
82167
82168
82169
82170
82171
82172 protected function convertJsonPointerIntoPropertyPath(JsonPointer $pointer)
82173 {
82174 $result = array_map(
82175 function ($path) {
82176 return sprintf(is_numeric($path) ? '[%d]' : '.%s', $path);
82177 },
82178 $pointer->getPropertyPaths()
82179 );
82180
82181 return trim(implode('', $result), '.');
82182 }
82183 }
82184 <?php
82185
82186
82187
82188
82189
82190
82191
82192
82193 namespace JsonSchema\Constraints;
82194
82195 use JsonSchema\Entity\JsonPointer;
82196
82197
82198
82199
82200
82201
82202 interface ConstraintInterface
82203 {
82204
82205
82206
82207
82208
82209 public function getErrors();
82210
82211
82212
82213
82214
82215
82216 public function addErrors(array $errors);
82217
82218
82219
82220
82221
82222
82223
82224
82225
82226 public function addError(JsonPointer $path = null, $message, $constraint='', array $more = null);
82227
82228
82229
82230
82231
82232
82233 public function isValid();
82234
82235
82236
82237
82238
82239
82240
82241
82242
82243
82244
82245
82246
82247 public function check(&$value, $schema = null, JsonPointer $path = null, $i = null);
82248 }
82249 <?php
82250
82251
82252
82253
82254
82255
82256
82257
82258 namespace JsonSchema\Constraints;
82259
82260 use JsonSchema\Entity\JsonPointer;
82261
82262
82263
82264
82265
82266
82267
82268 class EnumConstraint extends Constraint
82269 {
82270
82271
82272
82273 public function check(&$element, $schema = null, JsonPointer $path = null, $i = null)
82274 {
82275
82276 if ($element instanceof UndefinedConstraint && (!isset($schema->required) || !$schema->required)) {
82277 return;
82278 }
82279 $type = gettype($element);
82280
82281 foreach ($schema->enum as $enum) {
82282 $enumType = gettype($enum);
82283 if ($this->factory->getConfig(self::CHECK_MODE_TYPE_CAST) && $type == 'array' && $enumType == 'object') {
82284 if ((object) $element == $enum) {
82285 return;
82286 }
82287 }
82288
82289 if ($type === gettype($enum)) {
82290 if ($type == 'object') {
82291 if ($element == $enum) {
82292 return;
82293 }
82294 } elseif ($element === $enum) {
82295 return;
82296 }
82297 }
82298 }
82299
82300 $this->addError($path, 'Does not have a value in the enumeration ' . json_encode($schema->enum), 'enum', array('enum' => $schema->enum));
82301 }
82302 }
82303 <?php
82304
82305
82306
82307
82308
82309
82310
82311
82312 namespace JsonSchema\Constraints;
82313
82314 use JsonSchema\Exception\InvalidArgumentException;
82315 use JsonSchema\SchemaStorage;
82316 use JsonSchema\SchemaStorageInterface;
82317 use JsonSchema\Uri\UriRetriever;
82318 use JsonSchema\UriRetrieverInterface;
82319 use JsonSchema\Validator;
82320
82321
82322
82323
82324 class Factory
82325 {
82326
82327
82328
82329 protected $schemaStorage;
82330
82331
82332
82333
82334 protected $uriRetriever;
82335
82336
82337
82338
82339 private $checkMode = Constraint::CHECK_MODE_NORMAL;
82340
82341
82342
82343
82344 private $typeCheck = array();
82345
82346
82347
82348
82349 protected $errorContext = Validator::ERROR_DOCUMENT_VALIDATION;
82350
82351
82352
82353
82354 protected $constraintMap = array(
82355 'array' => 'JsonSchema\Constraints\CollectionConstraint',
82356 'collection' => 'JsonSchema\Constraints\CollectionConstraint',
82357 'object' => 'JsonSchema\Constraints\ObjectConstraint',
82358 'type' => 'JsonSchema\Constraints\TypeConstraint',
82359 'undefined' => 'JsonSchema\Constraints\UndefinedConstraint',
82360 'string' => 'JsonSchema\Constraints\StringConstraint',
82361 'number' => 'JsonSchema\Constraints\NumberConstraint',
82362 'enum' => 'JsonSchema\Constraints\EnumConstraint',
82363 'format' => 'JsonSchema\Constraints\FormatConstraint',
82364 'schema' => 'JsonSchema\Constraints\SchemaConstraint',
82365 'validator' => 'JsonSchema\Validator'
82366 );
82367
82368
82369
82370
82371 private $instanceCache = array();
82372
82373
82374
82375
82376
82377
82378 public function __construct(
82379 SchemaStorageInterface $schemaStorage = null,
82380 UriRetrieverInterface $uriRetriever = null,
82381 $checkMode = Constraint::CHECK_MODE_NORMAL
82382 ) {
82383
82384 $this->setConfig($checkMode);
82385
82386 $this->uriRetriever = $uriRetriever ?: new UriRetriever();
82387 $this->schemaStorage = $schemaStorage ?: new SchemaStorage($this->uriRetriever);
82388 }
82389
82390
82391
82392
82393
82394
82395 public function setConfig($checkMode = Constraint::CHECK_MODE_NORMAL)
82396 {
82397 $this->checkMode = $checkMode;
82398 }
82399
82400
82401
82402
82403
82404
82405 public function addConfig($options)
82406 {
82407 $this->checkMode |= $options;
82408 }
82409
82410
82411
82412
82413
82414
82415 public function removeConfig($options)
82416 {
82417 $this->checkMode &= ~$options;
82418 }
82419
82420
82421
82422
82423
82424
82425
82426
82427 public function getConfig($options = null)
82428 {
82429 if ($options === null) {
82430 return $this->checkMode;
82431 }
82432
82433 return $this->checkMode & $options;
82434 }
82435
82436
82437
82438
82439 public function getUriRetriever()
82440 {
82441 return $this->uriRetriever;
82442 }
82443
82444 public function getSchemaStorage()
82445 {
82446 return $this->schemaStorage;
82447 }
82448
82449 public function getTypeCheck()
82450 {
82451 if (!isset($this->typeCheck[$this->checkMode])) {
82452 $this->typeCheck[$this->checkMode] = ($this->checkMode & Constraint::CHECK_MODE_TYPE_CAST)
82453 ? new TypeCheck\LooseTypeCheck()
82454 : new TypeCheck\StrictTypeCheck();
82455 }
82456
82457 return $this->typeCheck[$this->checkMode];
82458 }
82459
82460
82461
82462
82463
82464
82465
82466 public function setConstraintClass($name, $class)
82467 {
82468
82469 if (!class_exists($class)) {
82470 throw new InvalidArgumentException('Unknown constraint ' . $name);
82471 }
82472
82473 if (!in_array('JsonSchema\Constraints\ConstraintInterface', class_implements($class))) {
82474 throw new InvalidArgumentException('Invalid class ' . $name);
82475 }
82476 $this->constraintMap[$name] = $class;
82477
82478 return $this;
82479 }
82480
82481
82482
82483
82484
82485
82486
82487
82488
82489
82490 public function createInstanceFor($constraintName)
82491 {
82492 if (!isset($this->constraintMap[$constraintName])) {
82493 throw new InvalidArgumentException('Unknown constraint ' . $constraintName);
82494 }
82495
82496 if (!isset($this->instanceCache[$constraintName])) {
82497 $this->instanceCache[$constraintName] = new $this->constraintMap[$constraintName]($this);
82498 }
82499
82500 return clone $this->instanceCache[$constraintName];
82501 }
82502
82503
82504
82505
82506
82507
82508 public function getErrorContext()
82509 {
82510 return $this->errorContext;
82511 }
82512
82513
82514
82515
82516
82517
82518 public function setErrorContext($errorContext)
82519 {
82520 $this->errorContext = $errorContext;
82521 }
82522 }
82523 <?php
82524
82525
82526
82527
82528
82529
82530
82531
82532 namespace JsonSchema\Constraints;
82533
82534 use JsonSchema\Entity\JsonPointer;
82535 use JsonSchema\Rfc3339;
82536
82537
82538
82539
82540
82541
82542
82543
82544 class FormatConstraint extends Constraint
82545 {
82546
82547
82548
82549 public function check(&$element, $schema = null, JsonPointer $path = null, $i = null)
82550 {
82551 if (!isset($schema->format) || $this->factory->getConfig(self::CHECK_MODE_DISABLE_FORMAT)) {
82552 return;
82553 }
82554
82555 switch ($schema->format) {
82556 case 'date':
82557 if (!$date = $this->validateDateTime($element, 'Y-m-d')) {
82558 $this->addError($path, sprintf('Invalid date %s, expected format YYYY-MM-DD', json_encode($element)), 'format', array('format' => $schema->format));
82559 }
82560 break;
82561
82562 case 'time':
82563 if (!$this->validateDateTime($element, 'H:i:s')) {
82564 $this->addError($path, sprintf('Invalid time %s, expected format hh:mm:ss', json_encode($element)), 'format', array('format' => $schema->format));
82565 }
82566 break;
82567
82568 case 'date-time':
82569 if (null === Rfc3339::createFromString($element)) {
82570 $this->addError($path, sprintf('Invalid date-time %s, expected format YYYY-MM-DDThh:mm:ssZ or YYYY-MM-DDThh:mm:ss+hh:mm', json_encode($element)), 'format', array('format' => $schema->format));
82571 }
82572 break;
82573
82574 case 'utc-millisec':
82575 if (!$this->validateDateTime($element, 'U')) {
82576 $this->addError($path, sprintf('Invalid time %s, expected integer of milliseconds since Epoch', json_encode($element)), 'format', array('format' => $schema->format));
82577 }
82578 break;
82579
82580 case 'regex':
82581 if (!$this->validateRegex($element)) {
82582 $this->addError($path, 'Invalid regex format ' . $element, 'format', array('format' => $schema->format));
82583 }
82584 break;
82585
82586 case 'color':
82587 if (!$this->validateColor($element)) {
82588 $this->addError($path, 'Invalid color', 'format', array('format' => $schema->format));
82589 }
82590 break;
82591
82592 case 'style':
82593 if (!$this->validateStyle($element)) {
82594 $this->addError($path, 'Invalid style', 'format', array('format' => $schema->format));
82595 }
82596 break;
82597
82598 case 'phone':
82599 if (!$this->validatePhone($element)) {
82600 $this->addError($path, 'Invalid phone number', 'format', array('format' => $schema->format));
82601 }
82602 break;
82603
82604 case 'uri':
82605 if (null === filter_var($element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE)) {
82606 $this->addError($path, 'Invalid URL format', 'format', array('format' => $schema->format));
82607 }
82608 break;
82609
82610 case 'uriref':
82611 case 'uri-reference':
82612 if (null === filter_var($element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE)) {
82613
82614
82615
82616 if (substr($element, 0, 2) === '//') { 
82617 $validURL = filter_var('scheme:' . $element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE);
82618 } elseif (substr($element, 0, 1) === '/') { 
82619 $validURL = filter_var('scheme://host' . $element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE);
82620 } elseif (strlen($element)) { 
82621 $pathParts = explode('/', $element, 2);
82622 if (strpos($pathParts[0], ':') !== false) {
82623 $validURL = null;
82624 } else {
82625 $validURL = filter_var('scheme://host/' . $element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE);
82626 }
82627 } else {
82628 $validURL = null;
82629 }
82630 if ($validURL === null) {
82631 $this->addError($path, 'Invalid URL format', 'format', array('format' => $schema->format));
82632 }
82633 }
82634 break;
82635
82636 case 'email':
82637 $filterFlags = FILTER_NULL_ON_FAILURE;
82638 if (defined('FILTER_FLAG_EMAIL_UNICODE')) {
82639
82640 $filterFlags |= constant('FILTER_FLAG_EMAIL_UNICODE'); 
82641 }
82642 if (null === filter_var($element, FILTER_VALIDATE_EMAIL, $filterFlags)) {
82643 $this->addError($path, 'Invalid email', 'format', array('format' => $schema->format));
82644 }
82645 break;
82646
82647 case 'ip-address':
82648 case 'ipv4':
82649 if (null === filter_var($element, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV4)) {
82650 $this->addError($path, 'Invalid IP address', 'format', array('format' => $schema->format));
82651 }
82652 break;
82653
82654 case 'ipv6':
82655 if (null === filter_var($element, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV6)) {
82656 $this->addError($path, 'Invalid IP address', 'format', array('format' => $schema->format));
82657 }
82658 break;
82659
82660 case 'host-name':
82661 case 'hostname':
82662 if (!$this->validateHostname($element)) {
82663 $this->addError($path, 'Invalid hostname', 'format', array('format' => $schema->format));
82664 }
82665 break;
82666
82667 default:
82668
82669
82670
82671
82672
82673
82674 break;
82675 }
82676 }
82677
82678 protected function validateDateTime($datetime, $format)
82679 {
82680 $dt = \DateTime::createFromFormat($format, $datetime);
82681
82682 if (!$dt) {
82683 return false;
82684 }
82685
82686 if ($datetime === $dt->format($format)) {
82687 return true;
82688 }
82689
82690
82691
82692
82693
82694 if ((strpos('u', $format) !== -1) && (preg_match('/\.\d+Z$/', $datetime))) {
82695 return true;
82696 }
82697
82698 return false;
82699 }
82700
82701 protected function validateRegex($regex)
82702 {
82703 return false !== @preg_match('/' . $regex . '/u', '');
82704 }
82705
82706 protected function validateColor($color)
82707 {
82708 if (in_array(strtolower($color), array('aqua', 'black', 'blue', 'fuchsia',
82709 'gray', 'green', 'lime', 'maroon', 'navy', 'olive', 'orange', 'purple',
82710 'red', 'silver', 'teal', 'white', 'yellow'))) {
82711 return true;
82712 }
82713
82714 return preg_match('/^#([a-f0-9]{3}|[a-f0-9]{6})$/i', $color);
82715 }
82716
82717 protected function validateStyle($style)
82718 {
82719 $properties = explode(';', rtrim($style, ';'));
82720 $invalidEntries = preg_grep('/^\s*[-a-z]+\s*:\s*.+$/i', $properties, PREG_GREP_INVERT);
82721
82722 return empty($invalidEntries);
82723 }
82724
82725 protected function validatePhone($phone)
82726 {
82727 return preg_match('/^\+?(\(\d{3}\)|\d{3}) \d{3} \d{4}$/', $phone);
82728 }
82729
82730 protected function validateHostname($host)
82731 {
82732 $hostnameRegex = '/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/i';
82733
82734 return preg_match($hostnameRegex, $host);
82735 }
82736 }
82737 <?php
82738
82739
82740
82741
82742
82743
82744
82745
82746 namespace JsonSchema\Constraints;
82747
82748 use JsonSchema\Entity\JsonPointer;
82749
82750
82751
82752
82753
82754
82755
82756 class NumberConstraint extends Constraint
82757 {
82758
82759
82760
82761 public function check(&$element, $schema = null, JsonPointer $path = null, $i = null)
82762 {
82763
82764 if (isset($schema->exclusiveMinimum)) {
82765 if (isset($schema->minimum)) {
82766 if ($schema->exclusiveMinimum && $element <= $schema->minimum) {
82767 $this->addError($path, 'Must have a minimum value of ' . $schema->minimum, 'exclusiveMinimum', array('minimum' => $schema->minimum));
82768 } elseif ($element < $schema->minimum) {
82769 $this->addError($path, 'Must have a minimum value of ' . $schema->minimum, 'minimum', array('minimum' => $schema->minimum));
82770 }
82771 } else {
82772 $this->addError($path, 'Use of exclusiveMinimum requires presence of minimum', 'missingMinimum');
82773 }
82774 } elseif (isset($schema->minimum) && $element < $schema->minimum) {
82775 $this->addError($path, 'Must have a minimum value of ' . $schema->minimum, 'minimum', array('minimum' => $schema->minimum));
82776 }
82777
82778
82779 if (isset($schema->exclusiveMaximum)) {
82780 if (isset($schema->maximum)) {
82781 if ($schema->exclusiveMaximum && $element >= $schema->maximum) {
82782 $this->addError($path, 'Must have a maximum value of ' . $schema->maximum, 'exclusiveMaximum', array('maximum' => $schema->maximum));
82783 } elseif ($element > $schema->maximum) {
82784 $this->addError($path, 'Must have a maximum value of ' . $schema->maximum, 'maximum', array('maximum' => $schema->maximum));
82785 }
82786 } else {
82787 $this->addError($path, 'Use of exclusiveMaximum requires presence of maximum', 'missingMaximum');
82788 }
82789 } elseif (isset($schema->maximum) && $element > $schema->maximum) {
82790 $this->addError($path, 'Must have a maximum value of ' . $schema->maximum, 'maximum', array('maximum' => $schema->maximum));
82791 }
82792
82793
82794 if (isset($schema->divisibleBy) && $this->fmod($element, $schema->divisibleBy) != 0) {
82795 $this->addError($path, 'Is not divisible by ' . $schema->divisibleBy, 'divisibleBy', array('divisibleBy' => $schema->divisibleBy));
82796 }
82797
82798
82799 if (isset($schema->multipleOf) && $this->fmod($element, $schema->multipleOf) != 0) {
82800 $this->addError($path, 'Must be a multiple of ' . $schema->multipleOf, 'multipleOf', array('multipleOf' => $schema->multipleOf));
82801 }
82802
82803 $this->checkFormat($element, $schema, $path, $i);
82804 }
82805
82806 private function fmod($number1, $number2)
82807 {
82808 $modulus = ($number1 - round($number1 / $number2) * $number2);
82809 $precision = 0.0000000001;
82810
82811 if (-$precision < $modulus && $modulus < $precision) {
82812 return 0.0;
82813 }
82814
82815 return $modulus;
82816 }
82817 }
82818 <?php
82819
82820
82821
82822
82823
82824
82825
82826
82827 namespace JsonSchema\Constraints;
82828
82829 use JsonSchema\Entity\JsonPointer;
82830
82831
82832
82833
82834
82835
82836
82837 class ObjectConstraint extends Constraint
82838 {
82839
82840
82841
82842 protected $appliedDefaults = array();
82843
82844
82845
82846
82847 public function check(&$element, $schema = null, JsonPointer $path = null, $properties = null,
82848 $additionalProp = null, $patternProperties = null, $appliedDefaults = array())
82849 {
82850 if ($element instanceof UndefinedConstraint) {
82851 return;
82852 }
82853
82854 $this->appliedDefaults = $appliedDefaults;
82855
82856 $matches = array();
82857 if ($patternProperties) {
82858
82859 $matches = $this->validatePatternProperties($element, $path, $patternProperties);
82860 }
82861
82862 if ($properties) {
82863
82864 $this->validateProperties($element, $properties, $path);
82865 }
82866
82867
82868 $this->validateElement($element, $matches, $schema, $path, $properties, $additionalProp);
82869 }
82870
82871 public function validatePatternProperties($element, JsonPointer $path = null, $patternProperties)
82872 {
82873 $try = array('/', '#', '+', '~', '%');
82874 $matches = array();
82875 foreach ($patternProperties as $pregex => $schema) {
82876 $delimiter = '/';
82877
82878 foreach ($try as $delimiter) {
82879 if (strpos($pregex, $delimiter) === false) { 
82880 break;
82881 }
82882 }
82883
82884
82885 if (@preg_match($delimiter . $pregex . $delimiter . 'u', '') === false) {
82886 $this->addError($path, 'The pattern "' . $pregex . '" is invalid', 'pregex', array('pregex' => $pregex));
82887 continue;
82888 }
82889 foreach ($element as $i => $value) {
82890 if (preg_match($delimiter . $pregex . $delimiter . 'u', $i)) {
82891 $matches[] = $i;
82892 $this->checkUndefined($value, $schema ?: new \stdClass(), $path, $i, in_array($i, $this->appliedDefaults));
82893 }
82894 }
82895 }
82896
82897 return $matches;
82898 }
82899
82900
82901
82902
82903
82904
82905
82906
82907
82908
82909
82910 public function validateElement($element, $matches, $schema = null, JsonPointer $path = null,
82911 $properties = null, $additionalProp = null)
82912 {
82913 $this->validateMinMaxConstraint($element, $schema, $path);
82914
82915 foreach ($element as $i => $value) {
82916 $definition = $this->getProperty($properties, $i);
82917
82918
82919 if (!in_array($i, $matches) && $additionalProp === false && $this->inlineSchemaProperty !== $i && !$definition) {
82920 $this->addError($path, 'The property ' . $i . ' is not defined and the definition does not allow additional properties', 'additionalProp');
82921 }
82922
82923
82924 if (!in_array($i, $matches) && $additionalProp && !$definition) {
82925 if ($additionalProp === true) {
82926 $this->checkUndefined($value, null, $path, $i, in_array($i, $this->appliedDefaults));
82927 } else {
82928 $this->checkUndefined($value, $additionalProp, $path, $i, in_array($i, $this->appliedDefaults));
82929 }
82930 }
82931
82932
82933 $require = $this->getProperty($definition, 'requires');
82934 if ($require && !$this->getProperty($element, $require)) {
82935 $this->addError($path, 'The presence of the property ' . $i . ' requires that ' . $require . ' also be present', 'requires');
82936 }
82937
82938 $property = $this->getProperty($element, $i, $this->factory->createInstanceFor('undefined'));
82939 if (is_object($property)) {
82940 $this->validateMinMaxConstraint(!($property instanceof UndefinedConstraint) ? $property : $element, $definition, $path);
82941 }
82942 }
82943 }
82944
82945
82946
82947
82948
82949
82950
82951
82952 public function validateProperties(&$element, $properties = null, JsonPointer $path = null)
82953 {
82954 $undefinedConstraint = $this->factory->createInstanceFor('undefined');
82955
82956 foreach ($properties as $i => $value) {
82957 $property = &$this->getProperty($element, $i, $undefinedConstraint);
82958 $definition = $this->getProperty($properties, $i);
82959
82960 if (is_object($definition)) {
82961
82962 $this->checkUndefined($property, $definition, $path, $i, in_array($i, $this->appliedDefaults));
82963 }
82964 }
82965 }
82966
82967
82968
82969
82970
82971
82972
82973
82974
82975
82976 protected function &getProperty(&$element, $property, $fallback = null)
82977 {
82978 if (is_array($element) && (isset($element[$property]) || array_key_exists($property, $element)) ) {
82979 return $element[$property];
82980 } elseif (is_object($element) && property_exists($element, $property)) {
82981 return $element->$property;
82982 }
82983
82984 return $fallback;
82985 }
82986
82987
82988
82989
82990
82991
82992
82993
82994 protected function validateMinMaxConstraint($element, $objectDefinition, JsonPointer $path = null)
82995 {
82996
82997 if (isset($objectDefinition->minProperties) && !is_object($objectDefinition->minProperties)) {
82998 if ($this->getTypeCheck()->propertyCount($element) < $objectDefinition->minProperties) {
82999 $this->addError($path, 'Must contain a minimum of ' . $objectDefinition->minProperties . ' properties', 'minProperties', array('minProperties' => $objectDefinition->minProperties));
83000 }
83001 }
83002
83003 if (isset($objectDefinition->maxProperties) && !is_object($objectDefinition->maxProperties)) {
83004 if ($this->getTypeCheck()->propertyCount($element) > $objectDefinition->maxProperties) {
83005 $this->addError($path, 'Must contain no more than ' . $objectDefinition->maxProperties . ' properties', 'maxProperties', array('maxProperties' => $objectDefinition->maxProperties));
83006 }
83007 }
83008 }
83009 }
83010 <?php
83011
83012
83013
83014
83015
83016
83017
83018
83019 namespace JsonSchema\Constraints;
83020
83021 use JsonSchema\Entity\JsonPointer;
83022 use JsonSchema\Exception\InvalidArgumentException;
83023 use JsonSchema\Exception\InvalidSchemaException;
83024 use JsonSchema\Exception\RuntimeException;
83025 use JsonSchema\Validator;
83026
83027
83028
83029
83030
83031
83032
83033 class SchemaConstraint extends Constraint
83034 {
83035 const DEFAULT_SCHEMA_SPEC = 'http://json-schema.org/draft-04/schema#';
83036
83037
83038
83039
83040 public function check(&$element, $schema = null, JsonPointer $path = null, $i = null)
83041 {
83042 if ($schema !== null) {
83043
83044 $validationSchema = $schema;
83045 } elseif ($this->getTypeCheck()->propertyExists($element, $this->inlineSchemaProperty)) {
83046
83047 $validationSchema = $this->getTypeCheck()->propertyGet($element, $this->inlineSchemaProperty);
83048 } else {
83049 throw new InvalidArgumentException('no schema found to verify against');
83050 }
83051
83052
83053 if (is_array($validationSchema)) {
83054 $validationSchema = BaseConstraint::arrayToObjectRecursive($validationSchema);
83055 }
83056
83057
83058
83059 if ($this->factory->getConfig(self::CHECK_MODE_VALIDATE_SCHEMA)) {
83060 if (!$this->getTypeCheck()->isObject($validationSchema)) {
83061 throw new RuntimeException('Cannot validate the schema of a non-object');
83062 }
83063 if ($this->getTypeCheck()->propertyExists($validationSchema, '$schema')) {
83064 $schemaSpec = $this->getTypeCheck()->propertyGet($validationSchema, '$schema');
83065 } else {
83066 $schemaSpec = self::DEFAULT_SCHEMA_SPEC;
83067 }
83068
83069
83070 $schemaStorage = $this->factory->getSchemaStorage();
83071 if (!$this->getTypeCheck()->isObject($schemaSpec)) {
83072 $schemaSpec = $schemaStorage->getSchema($schemaSpec);
83073 }
83074
83075
83076 $initialErrorCount = $this->numErrors();
83077 $initialConfig = $this->factory->getConfig();
83078 $initialContext = $this->factory->getErrorContext();
83079 $this->factory->removeConfig(self::CHECK_MODE_VALIDATE_SCHEMA | self::CHECK_MODE_APPLY_DEFAULTS);
83080 $this->factory->addConfig(self::CHECK_MODE_TYPE_CAST);
83081 $this->factory->setErrorContext(Validator::ERROR_SCHEMA_VALIDATION);
83082
83083
83084 try {
83085 $this->check($validationSchema, $schemaSpec);
83086 } catch (\Exception $e) {
83087 if ($this->factory->getConfig(self::CHECK_MODE_EXCEPTIONS)) {
83088 throw new InvalidSchemaException('Schema did not pass validation', 0, $e);
83089 }
83090 }
83091 if ($this->numErrors() > $initialErrorCount) {
83092 $this->addError($path, 'Schema is not valid', 'schema');
83093 }
83094
83095
83096 $this->factory->setConfig($initialConfig);
83097 $this->factory->setErrorContext($initialContext);
83098 }
83099
83100
83101 $this->checkUndefined($element, $validationSchema, $path, $i);
83102 }
83103 }
83104 <?php
83105
83106
83107
83108
83109
83110
83111
83112
83113 namespace JsonSchema\Constraints;
83114
83115 use JsonSchema\Entity\JsonPointer;
83116
83117
83118
83119
83120
83121
83122
83123 class StringConstraint extends Constraint
83124 {
83125
83126
83127
83128 public function check(&$element, $schema = null, JsonPointer $path = null, $i = null)
83129 {
83130
83131 if (isset($schema->maxLength) && $this->strlen($element) > $schema->maxLength) {
83132 $this->addError($path, 'Must be at most ' . $schema->maxLength . ' characters long', 'maxLength', array(
83133 'maxLength' => $schema->maxLength,
83134 ));
83135 }
83136
83137
83138 if (isset($schema->minLength) && $this->strlen($element) < $schema->minLength) {
83139 $this->addError($path, 'Must be at least ' . $schema->minLength . ' characters long', 'minLength', array(
83140 'minLength' => $schema->minLength,
83141 ));
83142 }
83143
83144
83145 if (isset($schema->pattern) && !preg_match('#' . str_replace('#', '\\#', $schema->pattern) . '#u', $element)) {
83146 $this->addError($path, 'Does not match the regex pattern ' . $schema->pattern, 'pattern', array(
83147 'pattern' => $schema->pattern,
83148 ));
83149 }
83150
83151 $this->checkFormat($element, $schema, $path, $i);
83152 }
83153
83154 private function strlen($string)
83155 {
83156 if (extension_loaded('mbstring')) {
83157 return mb_strlen($string, mb_detect_encoding($string));
83158 }
83159
83160
83161 return strlen($string); 
83162 }
83163 }
83164 <?php
83165
83166 namespace JsonSchema\Constraints\TypeCheck;
83167
83168 class LooseTypeCheck implements TypeCheckInterface
83169 {
83170 public static function isObject($value)
83171 {
83172 return
83173 is_object($value) ||
83174 (is_array($value) && (count($value) == 0 || self::isAssociativeArray($value)));
83175 }
83176
83177 public static function isArray($value)
83178 {
83179 return
83180 is_array($value) &&
83181 (count($value) == 0 || !self::isAssociativeArray($value));
83182 }
83183
83184 public static function propertyGet($value, $property)
83185 {
83186 if (is_object($value)) {
83187 return $value->{$property};
83188 }
83189
83190 return $value[$property];
83191 }
83192
83193 public static function propertySet(&$value, $property, $data)
83194 {
83195 if (is_object($value)) {
83196 $value->{$property} = $data;
83197 } else {
83198 $value[$property] = $data;
83199 }
83200 }
83201
83202 public static function propertyExists($value, $property)
83203 {
83204 if (is_object($value)) {
83205 return property_exists($value, $property);
83206 }
83207
83208 return array_key_exists($property, $value);
83209 }
83210
83211 public static function propertyCount($value)
83212 {
83213 if (is_object($value)) {
83214 return count(get_object_vars($value));
83215 }
83216
83217 return count($value);
83218 }
83219
83220
83221
83222
83223
83224
83225
83226
83227 private static function isAssociativeArray($arr)
83228 {
83229 return array_keys($arr) !== range(0, count($arr) - 1);
83230 }
83231 }
83232 <?php
83233
83234 namespace JsonSchema\Constraints\TypeCheck;
83235
83236 class StrictTypeCheck implements TypeCheckInterface
83237 {
83238 public static function isObject($value)
83239 {
83240 return is_object($value);
83241 }
83242
83243 public static function isArray($value)
83244 {
83245 return is_array($value);
83246 }
83247
83248 public static function propertyGet($value, $property)
83249 {
83250 return $value->{$property};
83251 }
83252
83253 public static function propertySet(&$value, $property, $data)
83254 {
83255 $value->{$property} = $data;
83256 }
83257
83258 public static function propertyExists($value, $property)
83259 {
83260 return property_exists($value, $property);
83261 }
83262
83263 public static function propertyCount($value)
83264 {
83265 if (!is_object($value)) {
83266 return 0;
83267 }
83268
83269 return count(get_object_vars($value));
83270 }
83271 }
83272 <?php
83273
83274 namespace JsonSchema\Constraints\TypeCheck;
83275
83276 interface TypeCheckInterface
83277 {
83278 public static function isObject($value);
83279
83280 public static function isArray($value);
83281
83282 public static function propertyGet($value, $property);
83283
83284 public static function propertySet(&$value, $property, $data);
83285
83286 public static function propertyExists($value, $property);
83287
83288 public static function propertyCount($value);
83289 }
83290 <?php
83291
83292
83293
83294
83295
83296
83297
83298
83299 namespace JsonSchema\Constraints;
83300
83301 use JsonSchema\Entity\JsonPointer;
83302 use JsonSchema\Exception\InvalidArgumentException;
83303 use UnexpectedValueException as StandardUnexpectedValueException;
83304
83305
83306
83307
83308
83309
83310
83311 class TypeConstraint extends Constraint
83312 {
83313
83314
83315
83316 public static $wording = array(
83317 'integer' => 'an integer',
83318 'number' => 'a number',
83319 'boolean' => 'a boolean',
83320 'object' => 'an object',
83321 'array' => 'an array',
83322 'string' => 'a string',
83323 'null' => 'a null',
83324 'any' => null, 
83325 0 => null, 
83326 );
83327
83328
83329
83330
83331 public function check(&$value = null, $schema = null, JsonPointer $path = null, $i = null)
83332 {
83333 $type = isset($schema->type) ? $schema->type : null;
83334 $isValid = false;
83335 $wording = array();
83336
83337 if (is_array($type)) {
83338 $this->validateTypesArray($value, $type, $wording, $isValid, $path);
83339 } elseif (is_object($type)) {
83340 $this->checkUndefined($value, $type, $path);
83341
83342 return;
83343 } else {
83344 $isValid = $this->validateType($value, $type);
83345 }
83346
83347 if ($isValid === false) {
83348 if (!is_array($type)) {
83349 $this->validateTypeNameWording($type);
83350 $wording[] = self::$wording[$type];
83351 }
83352 $this->addError($path, ucwords(gettype($value)) . ' value found, but ' .
83353 $this->implodeWith($wording, ', ', 'or') . ' is required', 'type');
83354 }
83355 }
83356
83357
83358
83359
83360
83361
83362
83363
83364
83365
83366
83367
83368 protected function validateTypesArray(&$value, array $type, &$validTypesWording, &$isValid, $path)
83369 {
83370 foreach ($type as $tp) {
83371
83372
83373 if (is_object($tp)) {
83374 if (!$isValid) {
83375 $validator = $this->factory->createInstanceFor('type');
83376 $subSchema = new \stdClass();
83377 $subSchema->type = $tp;
83378 $validator->check($value, $subSchema, $path, null);
83379 $error = $validator->getErrors();
83380 $isValid = !(bool) $error;
83381 $validTypesWording[] = self::$wording['object'];
83382 }
83383 } else {
83384 $this->validateTypeNameWording($tp);
83385 $validTypesWording[] = self::$wording[$tp];
83386 if (!$isValid) {
83387 $isValid = $this->validateType($value, $tp);
83388 }
83389 }
83390 }
83391 }
83392
83393
83394
83395
83396
83397
83398
83399
83400
83401
83402
83403
83404 protected function implodeWith(array $elements, $delimiter = ', ', $listEnd = false)
83405 {
83406 if ($listEnd === false || !isset($elements[1])) {
83407 return implode($delimiter, $elements);
83408 }
83409 $lastElement = array_slice($elements, -1);
83410 $firsElements = join($delimiter, array_slice($elements, 0, -1));
83411 $implodedElements = array_merge(array($firsElements), $lastElement);
83412
83413 return join(" $listEnd ", $implodedElements);
83414 }
83415
83416
83417
83418
83419
83420
83421
83422
83423
83424 protected function validateTypeNameWording($type)
83425 {
83426 if (!isset(self::$wording[$type])) {
83427 throw new StandardUnexpectedValueException(
83428 sprintf(
83429 'No wording for %s available, expected wordings are: [%s]',
83430 var_export($type, true),
83431 implode(', ', array_filter(self::$wording)))
83432 );
83433 }
83434 }
83435
83436
83437
83438
83439
83440
83441
83442
83443
83444
83445
83446 protected function validateType(&$value, $type)
83447 {
83448
83449 if (!$type) {
83450 return true;
83451 }
83452
83453 if ('any' === $type) {
83454 return true;
83455 }
83456
83457 if ('object' === $type) {
83458 return $this->getTypeCheck()->isObject($value);
83459 }
83460
83461 if ('array' === $type) {
83462 return $this->getTypeCheck()->isArray($value);
83463 }
83464
83465 $coerce = $this->factory->getConfig(Constraint::CHECK_MODE_COERCE_TYPES);
83466
83467 if ('integer' === $type) {
83468 if ($coerce) {
83469 $value = $this->toInteger($value);
83470 }
83471
83472 return is_int($value);
83473 }
83474
83475 if ('number' === $type) {
83476 if ($coerce) {
83477 $value = $this->toNumber($value);
83478 }
83479
83480 return is_numeric($value) && !is_string($value);
83481 }
83482
83483 if ('boolean' === $type) {
83484 if ($coerce) {
83485 $value = $this->toBoolean($value);
83486 }
83487
83488 return is_bool($value);
83489 }
83490
83491 if ('string' === $type) {
83492 return is_string($value);
83493 }
83494
83495 if ('email' === $type) {
83496 return is_string($value);
83497 }
83498
83499 if ('null' === $type) {
83500 return is_null($value);
83501 }
83502
83503 throw new InvalidArgumentException((is_object($value) ? 'object' : $value) . ' is an invalid type for ' . $type);
83504 }
83505
83506
83507
83508
83509
83510
83511
83512
83513 protected function toBoolean($value)
83514 {
83515 if ($value === 'true') {
83516 return true;
83517 }
83518
83519 if ($value === 'false') {
83520 return false;
83521 }
83522
83523 return $value;
83524 }
83525
83526
83527
83528
83529
83530
83531
83532
83533 protected function toNumber($value)
83534 {
83535 if (is_numeric($value)) {
83536 return $value + 0; 
83537 }
83538
83539 return $value;
83540 }
83541
83542 protected function toInteger($value)
83543 {
83544 if (is_numeric($value) && (int) $value == $value) {
83545 return (int) $value; 
83546 }
83547
83548 return $value;
83549 }
83550 }
83551 <?php
83552
83553
83554
83555
83556
83557
83558
83559
83560 namespace JsonSchema\Constraints;
83561
83562 use JsonSchema\Constraints\TypeCheck\LooseTypeCheck;
83563 use JsonSchema\Entity\JsonPointer;
83564 use JsonSchema\Exception\ValidationException;
83565 use JsonSchema\Uri\UriResolver;
83566
83567
83568
83569
83570
83571
83572
83573 class UndefinedConstraint extends Constraint
83574 {
83575
83576
83577
83578 protected $appliedDefaults = array();
83579
83580
83581
83582
83583 public function check(&$value, $schema = null, JsonPointer $path = null, $i = null, $fromDefault = false)
83584 {
83585 if (is_null($schema) || !is_object($schema)) {
83586 return;
83587 }
83588
83589 $path = $this->incrementPath($path ?: new JsonPointer(''), $i);
83590 if ($fromDefault) {
83591 $path->setFromDefault();
83592 }
83593
83594
83595 $this->validateCommonProperties($value, $schema, $path, $i);
83596
83597
83598 $this->validateOfProperties($value, $schema, $path, '');
83599
83600
83601 $this->validateTypes($value, $schema, $path, $i);
83602 }
83603
83604
83605
83606
83607
83608
83609
83610
83611
83612 public function validateTypes(&$value, $schema, JsonPointer $path, $i = null)
83613 {
83614
83615 if ($this->getTypeCheck()->isArray($value)) {
83616 $this->checkArray($value, $schema, $path, $i);
83617 }
83618
83619
83620 if (LooseTypeCheck::isObject($value)) { 
83621
83622
83623 $this->checkObject(
83624 $value,
83625 $schema,
83626 $path,
83627 isset($schema->properties) ? $schema->properties : null,
83628 isset($schema->additionalProperties) ? $schema->additionalProperties : null,
83629 isset($schema->patternProperties) ? $schema->patternProperties : null,
83630 $this->appliedDefaults
83631 );
83632 }
83633
83634
83635 if (is_string($value)) {
83636 $this->checkString($value, $schema, $path, $i);
83637 }
83638
83639
83640 if (is_numeric($value)) {
83641 $this->checkNumber($value, $schema, $path, $i);
83642 }
83643
83644
83645 if (isset($schema->enum)) {
83646 $this->checkEnum($value, $schema, $path, $i);
83647 }
83648 }
83649
83650
83651
83652
83653
83654
83655
83656
83657
83658 protected function validateCommonProperties(&$value, $schema, JsonPointer $path, $i = '')
83659 {
83660
83661 if (isset($schema->extends)) {
83662 if (is_string($schema->extends)) {
83663 $schema->extends = $this->validateUri($schema, $schema->extends);
83664 }
83665 if (is_array($schema->extends)) {
83666 foreach ($schema->extends as $extends) {
83667 $this->checkUndefined($value, $extends, $path, $i);
83668 }
83669 } else {
83670 $this->checkUndefined($value, $schema->extends, $path, $i);
83671 }
83672 }
83673
83674
83675 if (!$path->fromDefault()) {
83676 $this->applyDefaultValues($value, $schema, $path);
83677 }
83678
83679
83680 if ($this->getTypeCheck()->isObject($value)) {
83681 if (!($value instanceof self) && isset($schema->required) && is_array($schema->required)) {
83682
83683 foreach ($schema->required as $required) {
83684 if (!$this->getTypeCheck()->propertyExists($value, $required)) {
83685 $this->addError(
83686 $this->incrementPath($path ?: new JsonPointer(''), $required),
83687 'The property ' . $required . ' is required',
83688 'required'
83689 );
83690 }
83691 }
83692 } elseif (isset($schema->required) && !is_array($schema->required)) {
83693
83694 if ($schema->required && $value instanceof self) {
83695 $propertyPaths = $path->getPropertyPaths();
83696 $propertyName = end($propertyPaths);
83697 $this->addError(
83698 $path,
83699 'The property ' . $propertyName . ' is required',
83700 'required'
83701 );
83702 }
83703 } else {
83704
83705
83706 if ($value instanceof self) {
83707 return;
83708 }
83709 }
83710 }
83711
83712
83713 if (!($value instanceof self)) {
83714 $this->checkType($value, $schema, $path, $i);
83715 }
83716
83717
83718 if (isset($schema->disallow)) {
83719 $initErrors = $this->getErrors();
83720
83721 $typeSchema = new \stdClass();
83722 $typeSchema->type = $schema->disallow;
83723 $this->checkType($value, $typeSchema, $path);
83724
83725
83726 if (count($this->getErrors()) == count($initErrors)) {
83727 $this->addError($path, 'Disallowed value was matched', 'disallow');
83728 } else {
83729 $this->errors = $initErrors;
83730 }
83731 }
83732
83733 if (isset($schema->not)) {
83734 $initErrors = $this->getErrors();
83735 $this->checkUndefined($value, $schema->not, $path, $i);
83736
83737
83738 if (count($this->getErrors()) == count($initErrors)) {
83739 $this->addError($path, 'Matched a schema which it should not', 'not');
83740 } else {
83741 $this->errors = $initErrors;
83742 }
83743 }
83744
83745
83746 if (isset($schema->dependencies) && $this->getTypeCheck()->isObject($value)) {
83747 $this->validateDependencies($value, $schema->dependencies, $path);
83748 }
83749 }
83750
83751
83752
83753
83754
83755
83756
83757
83758
83759
83760 private function shouldApplyDefaultValue($requiredOnly, $schema, $name = null, $parentSchema = null)
83761 {
83762
83763 if (!$requiredOnly) {
83764 return true;
83765 }
83766
83767 if (
83768 $name !== null
83769 && isset($parentSchema->required)
83770 && is_array($parentSchema->required)
83771 && in_array($name, $parentSchema->required)
83772 ) {
83773 return true;
83774 }
83775
83776 if (isset($schema->required) && !is_array($schema->required) && $schema->required) {
83777 return true;
83778 }
83779
83780 return false;
83781 }
83782
83783
83784
83785
83786
83787
83788
83789
83790 protected function applyDefaultValues(&$value, $schema, $path)
83791 {
83792
83793 if (!$this->factory->getConfig(self::CHECK_MODE_APPLY_DEFAULTS)) {
83794 return;
83795 }
83796
83797
83798 $requiredOnly = $this->factory->getConfig(self::CHECK_MODE_ONLY_REQUIRED_DEFAULTS);
83799 if (isset($schema->properties) && LooseTypeCheck::isObject($value)) {
83800
83801 foreach ($schema->properties as $currentProperty => $propertyDefinition) {
83802 $propertyDefinition = $this->factory->getSchemaStorage()->resolveRefSchema($propertyDefinition);
83803 if (
83804 !LooseTypeCheck::propertyExists($value, $currentProperty)
83805 && property_exists($propertyDefinition, 'default')
83806 && $this->shouldApplyDefaultValue($requiredOnly, $propertyDefinition, $currentProperty, $schema)
83807 ) {
83808
83809 if (is_object($propertyDefinition->default)) {
83810 LooseTypeCheck::propertySet($value, $currentProperty, clone $propertyDefinition->default);
83811 } else {
83812 LooseTypeCheck::propertySet($value, $currentProperty, $propertyDefinition->default);
83813 }
83814 $this->appliedDefaults[] = $currentProperty;
83815 }
83816 }
83817 } elseif (isset($schema->items) && LooseTypeCheck::isArray($value)) {
83818 $items = array();
83819 if (LooseTypeCheck::isArray($schema->items)) {
83820 $items = $schema->items;
83821 } elseif (isset($schema->minItems) && count($value) < $schema->minItems) {
83822 $items = array_fill(count($value), $schema->minItems - count($value), $schema->items);
83823 }
83824
83825 foreach ($items as $currentItem => $itemDefinition) {
83826 $itemDefinition = $this->factory->getSchemaStorage()->resolveRefSchema($itemDefinition);
83827 if (
83828 !array_key_exists($currentItem, $value)
83829 && property_exists($itemDefinition, 'default')
83830 && $this->shouldApplyDefaultValue($requiredOnly, $itemDefinition)) {
83831 if (is_object($itemDefinition->default)) {
83832 $value[$currentItem] = clone $itemDefinition->default;
83833 } else {
83834 $value[$currentItem] = $itemDefinition->default;
83835 }
83836 }
83837 $path->setFromDefault();
83838 }
83839 } elseif (
83840 $value instanceof self
83841 && property_exists($schema, 'default')
83842 && $this->shouldApplyDefaultValue($requiredOnly, $schema)) {
83843
83844 $value = is_object($schema->default) ? clone $schema->default : $schema->default;
83845 $path->setFromDefault();
83846 }
83847 }
83848
83849
83850
83851
83852
83853
83854
83855
83856
83857 protected function validateOfProperties(&$value, $schema, JsonPointer $path, $i = '')
83858 {
83859
83860 if ($value instanceof self) {
83861 return;
83862 }
83863
83864 if (isset($schema->allOf)) {
83865 $isValid = true;
83866 foreach ($schema->allOf as $allOf) {
83867 $initErrors = $this->getErrors();
83868 $this->checkUndefined($value, $allOf, $path, $i);
83869 $isValid = $isValid && (count($this->getErrors()) == count($initErrors));
83870 }
83871 if (!$isValid) {
83872 $this->addError($path, 'Failed to match all schemas', 'allOf');
83873 }
83874 }
83875
83876 if (isset($schema->anyOf)) {
83877 $isValid = false;
83878 $startErrors = $this->getErrors();
83879 $caughtException = null;
83880 foreach ($schema->anyOf as $anyOf) {
83881 $initErrors = $this->getErrors();
83882 try {
83883 $this->checkUndefined($value, $anyOf, $path, $i);
83884 if ($isValid = (count($this->getErrors()) == count($initErrors))) {
83885 break;
83886 }
83887 } catch (ValidationException $e) {
83888 $isValid = false;
83889 }
83890 }
83891 if (!$isValid) {
83892 $this->addError($path, 'Failed to match at least one schema', 'anyOf');
83893 } else {
83894 $this->errors = $startErrors;
83895 }
83896 }
83897
83898 if (isset($schema->oneOf)) {
83899 $allErrors = array();
83900 $matchedSchemas = 0;
83901 $startErrors = $this->getErrors();
83902 foreach ($schema->oneOf as $oneOf) {
83903 try {
83904 $this->errors = array();
83905 $this->checkUndefined($value, $oneOf, $path, $i);
83906 if (count($this->getErrors()) == 0) {
83907 $matchedSchemas++;
83908 }
83909 $allErrors = array_merge($allErrors, array_values($this->getErrors()));
83910 } catch (ValidationException $e) {
83911
83912
83913 }
83914 }
83915 if ($matchedSchemas !== 1) {
83916 $this->addErrors(array_merge($allErrors, $startErrors));
83917 $this->addError($path, 'Failed to match exactly one schema', 'oneOf');
83918 } else {
83919 $this->errors = $startErrors;
83920 }
83921 }
83922 }
83923
83924
83925
83926
83927
83928
83929
83930
83931
83932 protected function validateDependencies($value, $dependencies, JsonPointer $path, $i = '')
83933 {
83934 foreach ($dependencies as $key => $dependency) {
83935 if ($this->getTypeCheck()->propertyExists($value, $key)) {
83936 if (is_string($dependency)) {
83937
83938 if (!$this->getTypeCheck()->propertyExists($value, $dependency)) {
83939 $this->addError($path, "$key depends on $dependency and $dependency is missing", 'dependencies');
83940 }
83941 } elseif (is_array($dependency)) {
83942
83943 foreach ($dependency as $d) {
83944 if (!$this->getTypeCheck()->propertyExists($value, $d)) {
83945 $this->addError($path, "$key depends on $d and $d is missing", 'dependencies');
83946 }
83947 }
83948 } elseif (is_object($dependency)) {
83949
83950 $this->checkUndefined($value, $dependency, $path, $i);
83951 }
83952 }
83953 }
83954 }
83955
83956 protected function validateUri($schema, $schemaUri = null)
83957 {
83958 $resolver = new UriResolver();
83959 $retriever = $this->factory->getUriRetriever();
83960
83961 $jsonSchema = null;
83962 if ($resolver->isValid($schemaUri)) {
83963 $schemaId = property_exists($schema, 'id') ? $schema->id : null;
83964 $jsonSchema = $retriever->retrieve($schemaId, $schemaUri);
83965 }
83966
83967 return $jsonSchema;
83968 }
83969 }
83970 <?php
83971
83972
83973
83974
83975
83976
83977
83978
83979 namespace JsonSchema\Entity;
83980
83981 use JsonSchema\Exception\InvalidArgumentException;
83982
83983
83984
83985
83986
83987
83988 class JsonPointer
83989 {
83990
83991 private $filename;
83992
83993
83994 private $propertyPaths = array();
83995
83996
83997
83998
83999 private $fromDefault = false;
84000
84001
84002
84003
84004
84005
84006 public function __construct($value)
84007 {
84008 if (!is_string($value)) {
84009 throw new InvalidArgumentException('Ref value must be a string');
84010 }
84011
84012 $splitRef = explode('#', $value, 2);
84013 $this->filename = $splitRef[0];
84014 if (array_key_exists(1, $splitRef)) {
84015 $this->propertyPaths = $this->decodePropertyPaths($splitRef[1]);
84016 }
84017 }
84018
84019
84020
84021
84022
84023
84024 private function decodePropertyPaths($propertyPathString)
84025 {
84026 $paths = array();
84027 foreach (explode('/', trim($propertyPathString, '/')) as $path) {
84028 $path = $this->decodePath($path);
84029 if (is_string($path) && '' !== $path) {
84030 $paths[] = $path;
84031 }
84032 }
84033
84034 return $paths;
84035 }
84036
84037
84038
84039
84040 private function encodePropertyPaths()
84041 {
84042 return array_map(
84043 array($this, 'encodePath'),
84044 $this->getPropertyPaths()
84045 );
84046 }
84047
84048
84049
84050
84051
84052
84053 private function decodePath($path)
84054 {
84055 return strtr($path, array('~1' => '/', '~0' => '~', '%25' => '%'));
84056 }
84057
84058
84059
84060
84061
84062
84063 private function encodePath($path)
84064 {
84065 return strtr($path, array('/' => '~1', '~' => '~0', '%' => '%25'));
84066 }
84067
84068
84069
84070
84071 public function getFilename()
84072 {
84073 return $this->filename;
84074 }
84075
84076
84077
84078
84079 public function getPropertyPaths()
84080 {
84081 return $this->propertyPaths;
84082 }
84083
84084
84085
84086
84087
84088
84089 public function withPropertyPaths(array $propertyPaths)
84090 {
84091 $new = clone $this;
84092 $new->propertyPaths = $propertyPaths;
84093
84094 return $new;
84095 }
84096
84097
84098
84099
84100 public function getPropertyPathAsString()
84101 {
84102 return rtrim('#/' . implode('/', $this->encodePropertyPaths()), '/');
84103 }
84104
84105
84106
84107
84108 public function __toString()
84109 {
84110 return $this->getFilename() . $this->getPropertyPathAsString();
84111 }
84112
84113
84114
84115
84116 public function setFromDefault()
84117 {
84118 $this->fromDefault = true;
84119 }
84120
84121
84122
84123
84124
84125
84126 public function fromDefault()
84127 {
84128 return $this->fromDefault;
84129 }
84130 }
84131 <?php
84132
84133 namespace JsonSchema\Exception;
84134
84135 interface ExceptionInterface
84136 {
84137 }
84138 <?php
84139
84140
84141
84142
84143
84144
84145
84146
84147 namespace JsonSchema\Exception;
84148
84149
84150
84151
84152 class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
84153 {
84154 }
84155 <?php
84156
84157
84158
84159
84160
84161
84162
84163
84164 namespace JsonSchema\Exception;
84165
84166
84167
84168
84169 class InvalidConfigException extends RuntimeException
84170 {
84171 }
84172 <?php
84173
84174
84175
84176
84177
84178
84179
84180
84181 namespace JsonSchema\Exception;
84182
84183
84184
84185
84186 class InvalidSchemaException extends RuntimeException
84187 {
84188 }
84189 <?php
84190
84191
84192
84193
84194
84195
84196
84197
84198 namespace JsonSchema\Exception;
84199
84200
84201
84202
84203 class InvalidSchemaMediaTypeException extends RuntimeException
84204 {
84205 }
84206 <?php
84207
84208
84209
84210
84211
84212
84213
84214
84215 namespace JsonSchema\Exception;
84216
84217
84218
84219
84220 class InvalidSourceUriException extends InvalidArgumentException
84221 {
84222 }
84223 <?php
84224
84225
84226
84227
84228
84229
84230
84231
84232 namespace JsonSchema\Exception;
84233
84234
84235
84236
84237 class JsonDecodingException extends RuntimeException
84238 {
84239 public function __construct($code = JSON_ERROR_NONE, \Exception $previous = null)
84240 {
84241 switch ($code) {
84242 case JSON_ERROR_DEPTH:
84243 $message = 'The maximum stack depth has been exceeded';
84244 break;
84245 case JSON_ERROR_STATE_MISMATCH:
84246 $message = 'Invalid or malformed JSON';
84247 break;
84248 case JSON_ERROR_CTRL_CHAR:
84249 $message = 'Control character error, possibly incorrectly encoded';
84250 break;
84251 case JSON_ERROR_UTF8:
84252 $message = 'Malformed UTF-8 characters, possibly incorrectly encoded';
84253 break;
84254 case JSON_ERROR_SYNTAX:
84255 $message = 'JSON syntax is malformed';
84256 break;
84257 default:
84258 $message = 'Syntax error';
84259 }
84260 parent::__construct($message, $code, $previous);
84261 }
84262 }
84263 <?php
84264
84265
84266
84267
84268
84269
84270
84271
84272 namespace JsonSchema\Exception;
84273
84274
84275
84276
84277 class ResourceNotFoundException extends RuntimeException
84278 {
84279 }
84280 <?php
84281
84282
84283
84284
84285
84286
84287
84288
84289 namespace JsonSchema\Exception;
84290
84291
84292
84293
84294 class RuntimeException extends \RuntimeException implements ExceptionInterface
84295 {
84296 }
84297 <?php
84298
84299
84300
84301
84302
84303
84304
84305
84306 namespace JsonSchema\Exception;
84307
84308
84309
84310
84311
84312
84313 class UnresolvableJsonPointerException extends InvalidArgumentException
84314 {
84315 }
84316 <?php
84317
84318
84319
84320
84321
84322
84323
84324
84325 namespace JsonSchema\Exception;
84326
84327
84328
84329
84330 class UriResolverException extends RuntimeException
84331 {
84332 }
84333 <?php
84334
84335
84336
84337
84338
84339
84340
84341
84342 namespace JsonSchema\Exception;
84343
84344 class ValidationException extends RuntimeException
84345 {
84346 }
84347 <?php
84348
84349
84350
84351
84352
84353
84354
84355
84356 namespace JsonSchema\Iterator;
84357
84358
84359
84360
84361
84362
84363 class ObjectIterator implements \Iterator, \Countable
84364 {
84365
84366 private $object;
84367
84368
84369 private $position = 0;
84370
84371
84372 private $data = array();
84373
84374
84375 private $initialized = false;
84376
84377
84378
84379
84380 public function __construct($object)
84381 {
84382 $this->object = $object;
84383 }
84384
84385
84386
84387
84388 public function current()
84389 {
84390 $this->initialize();
84391
84392 return $this->data[$this->position];
84393 }
84394
84395
84396
84397
84398 public function next()
84399 {
84400 $this->initialize();
84401 $this->position++;
84402 }
84403
84404
84405
84406
84407 public function key()
84408 {
84409 $this->initialize();
84410
84411 return $this->position;
84412 }
84413
84414
84415
84416
84417 public function valid()
84418 {
84419 $this->initialize();
84420
84421 return isset($this->data[$this->position]);
84422 }
84423
84424
84425
84426
84427 public function rewind()
84428 {
84429 $this->initialize();
84430 $this->position = 0;
84431 }
84432
84433
84434
84435
84436 public function count()
84437 {
84438 $this->initialize();
84439
84440 return count($this->data);
84441 }
84442
84443
84444
84445
84446 private function initialize()
84447 {
84448 if (!$this->initialized) {
84449 $this->data = $this->buildDataFromObject($this->object);
84450 $this->initialized = true;
84451 }
84452 }
84453
84454
84455
84456
84457
84458
84459 private function buildDataFromObject($object)
84460 {
84461 $result = array();
84462
84463 $stack = new \SplStack();
84464 $stack->push($object);
84465
84466 while (!$stack->isEmpty()) {
84467 $current = $stack->pop();
84468 if (is_object($current)) {
84469 array_push($result, $current);
84470 }
84471
84472 foreach ($this->getDataFromItem($current) as $propertyName => $propertyValue) {
84473 if (is_object($propertyValue) || is_array($propertyValue)) {
84474 $stack->push($propertyValue);
84475 }
84476 }
84477 }
84478
84479 return $result;
84480 }
84481
84482
84483
84484
84485
84486
84487 private function getDataFromItem($item)
84488 {
84489 if (!is_object($item) && !is_array($item)) {
84490 return array();
84491 }
84492
84493 return is_object($item) ? get_object_vars($item) : $item;
84494 }
84495 }
84496 <?php
84497
84498 namespace JsonSchema;
84499
84500 class Rfc3339
84501 {
84502 const REGEX = '/^(\d{4}-\d{2}-\d{2}[T ]{1}\d{2}:\d{2}:\d{2})(\.\d+)?(Z|([+-]\d{2}):?(\d{2}))$/';
84503
84504
84505
84506
84507
84508
84509
84510
84511 public static function createFromString($string)
84512 {
84513 if (!preg_match(self::REGEX, strtoupper($string), $matches)) {
84514 return null;
84515 }
84516
84517 $dateAndTime = $matches[1];
84518 $microseconds = $matches[2] ?: '.000000';
84519 $timeZone = 'Z' !== $matches[3] ? $matches[4] . ':' . $matches[5] : '+00:00';
84520 $dateFormat = strpos($dateAndTime, 'T') === false ? 'Y-m-d H:i:s.uP' : 'Y-m-d\TH:i:s.uP';
84521 $dateTime = \DateTime::createFromFormat($dateFormat, $dateAndTime . $microseconds . $timeZone, new \DateTimeZone('UTC'));
84522
84523 return $dateTime ?: null;
84524 }
84525 }
84526 <?php
84527
84528 namespace JsonSchema;
84529
84530 use JsonSchema\Constraints\BaseConstraint;
84531 use JsonSchema\Entity\JsonPointer;
84532 use JsonSchema\Exception\UnresolvableJsonPointerException;
84533 use JsonSchema\Uri\UriResolver;
84534 use JsonSchema\Uri\UriRetriever;
84535
84536 class SchemaStorage implements SchemaStorageInterface
84537 {
84538 const INTERNAL_PROVIDED_SCHEMA_URI = 'internal://provided-schema/';
84539
84540 protected $uriRetriever;
84541 protected $uriResolver;
84542 protected $schemas = array();
84543
84544 public function __construct(
84545 UriRetrieverInterface $uriRetriever = null,
84546 UriResolverInterface $uriResolver = null
84547 ) {
84548 $this->uriRetriever = $uriRetriever ?: new UriRetriever();
84549 $this->uriResolver = $uriResolver ?: new UriResolver();
84550 }
84551
84552
84553
84554
84555 public function getUriRetriever()
84556 {
84557 return $this->uriRetriever;
84558 }
84559
84560
84561
84562
84563 public function getUriResolver()
84564 {
84565 return $this->uriResolver;
84566 }
84567
84568
84569
84570
84571 public function addSchema($id, $schema = null)
84572 {
84573 if (is_null($schema) && $id !== self::INTERNAL_PROVIDED_SCHEMA_URI) {
84574
84575
84576
84577 $schema = $this->uriRetriever->retrieve($id);
84578 }
84579
84580
84581 if (is_array($schema)) {
84582 $schema = BaseConstraint::arrayToObjectRecursive($schema);
84583 }
84584
84585
84586
84587 if (is_object($schema) && property_exists($schema, 'id')) {
84588 if ($schema->id == 'http://json-schema.org/draft-04/schema#') {
84589 $schema->properties->id->format = 'uri-reference';
84590 } elseif ($schema->id == 'http://json-schema.org/draft-03/schema#') {
84591 $schema->properties->id->format = 'uri-reference';
84592 $schema->properties->{'$ref'}->format = 'uri-reference';
84593 }
84594 }
84595
84596
84597 $this->expandRefs($schema, $id);
84598
84599 $this->schemas[$id] = $schema;
84600 }
84601
84602
84603
84604
84605
84606
84607
84608 private function expandRefs(&$schema, $base = null)
84609 {
84610 if (!is_object($schema)) {
84611 if (is_array($schema)) {
84612 foreach ($schema as &$member) {
84613 $this->expandRefs($member, $base);
84614 }
84615 }
84616
84617 return;
84618 }
84619
84620 if (property_exists($schema, 'id') && is_string($schema->id) && $base != $schema->id) {
84621 $base = $this->uriResolver->resolve($schema->id, $base);
84622 }
84623
84624 if (property_exists($schema, '$ref') && is_string($schema->{'$ref'})) {
84625 $refPointer = new JsonPointer($this->uriResolver->resolve($schema->{'$ref'}, $base));
84626 $schema->{'$ref'} = (string) $refPointer;
84627 }
84628
84629 foreach ($schema as &$member) {
84630 $this->expandRefs($member, $base);
84631 }
84632 }
84633
84634
84635
84636
84637 public function getSchema($id)
84638 {
84639 if (!array_key_exists($id, $this->schemas)) {
84640 $this->addSchema($id);
84641 }
84642
84643 return $this->schemas[$id];
84644 }
84645
84646
84647
84648
84649 public function resolveRef($ref)
84650 {
84651 $jsonPointer = new JsonPointer($ref);
84652
84653
84654 $fileName = $jsonPointer->getFilename();
84655 if (!strlen($fileName)) {
84656 throw new UnresolvableJsonPointerException(sprintf(
84657 "Could not resolve fragment '%s': no file is defined",
84658 $jsonPointer->getPropertyPathAsString()
84659 ));
84660 }
84661
84662
84663 $refSchema = $this->getSchema($fileName);
84664 foreach ($jsonPointer->getPropertyPaths() as $path) {
84665 if (is_object($refSchema) && property_exists($refSchema, $path)) {
84666 $refSchema = $this->resolveRefSchema($refSchema->{$path});
84667 } elseif (is_array($refSchema) && array_key_exists($path, $refSchema)) {
84668 $refSchema = $this->resolveRefSchema($refSchema[$path]);
84669 } else {
84670 throw new UnresolvableJsonPointerException(sprintf(
84671 'File: %s is found, but could not resolve fragment: %s',
84672 $jsonPointer->getFilename(),
84673 $jsonPointer->getPropertyPathAsString()
84674 ));
84675 }
84676 }
84677
84678 return $refSchema;
84679 }
84680
84681
84682
84683
84684 public function resolveRefSchema($refSchema)
84685 {
84686 if (is_object($refSchema) && property_exists($refSchema, '$ref') && is_string($refSchema->{'$ref'})) {
84687 $newSchema = $this->resolveRef($refSchema->{'$ref'});
84688 $refSchema = (object) (get_object_vars($refSchema) + get_object_vars($newSchema));
84689 unset($refSchema->{'$ref'});
84690 }
84691
84692 return $refSchema;
84693 }
84694 }
84695 <?php
84696
84697 namespace JsonSchema;
84698
84699 interface SchemaStorageInterface
84700 {
84701
84702
84703
84704
84705
84706
84707 public function addSchema($id, $schema = null);
84708
84709
84710
84711
84712
84713
84714
84715
84716 public function getSchema($id);
84717
84718
84719
84720
84721
84722
84723
84724
84725 public function resolveRef($ref);
84726
84727
84728
84729
84730
84731
84732
84733
84734 public function resolveRefSchema($refSchema);
84735 }
84736 <?php
84737
84738
84739
84740
84741
84742
84743 namespace JsonSchema\Uri\Retrievers;
84744
84745
84746
84747
84748
84749
84750
84751 abstract class AbstractRetriever implements UriRetrieverInterface
84752 {
84753
84754
84755
84756
84757
84758 protected $contentType;
84759
84760
84761
84762
84763
84764
84765 public function getContentType()
84766 {
84767 return $this->contentType;
84768 }
84769 }
84770 <?php
84771
84772
84773
84774
84775
84776
84777
84778
84779 namespace JsonSchema\Uri\Retrievers;
84780
84781 use JsonSchema\Exception\RuntimeException;
84782 use JsonSchema\Validator;
84783
84784
84785
84786
84787
84788
84789 class Curl extends AbstractRetriever
84790 {
84791 protected $messageBody;
84792
84793 public function __construct()
84794 {
84795 if (!function_exists('curl_init')) {
84796
84797 throw new RuntimeException('cURL not installed'); 
84798 }
84799 }
84800
84801
84802
84803
84804
84805
84806 public function retrieve($uri)
84807 {
84808 $ch = curl_init();
84809
84810 curl_setopt($ch, CURLOPT_URL, $uri);
84811 curl_setopt($ch, CURLOPT_HEADER, true);
84812 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
84813 curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: ' . Validator::SCHEMA_MEDIA_TYPE));
84814
84815 $response = curl_exec($ch);
84816 if (false === $response) {
84817 throw new \JsonSchema\Exception\ResourceNotFoundException('JSON schema not found');
84818 }
84819
84820 $this->fetchMessageBody($response);
84821 $this->fetchContentType($response);
84822
84823 curl_close($ch);
84824
84825 return $this->messageBody;
84826 }
84827
84828
84829
84830
84831 private function fetchMessageBody($response)
84832 {
84833 preg_match("/(?:\r\n){2}(.*)$/ms", $response, $match);
84834 $this->messageBody = $match[1];
84835 }
84836
84837
84838
84839
84840
84841
84842 protected function fetchContentType($response)
84843 {
84844 if (0 < preg_match("/Content-Type:(\V*)/ims", $response, $match)) {
84845 $this->contentType = trim($match[1]);
84846
84847 return true;
84848 }
84849
84850 return false;
84851 }
84852 }
84853 <?php
84854
84855
84856
84857
84858
84859
84860
84861
84862 namespace JsonSchema\Uri\Retrievers;
84863
84864 use JsonSchema\Exception\ResourceNotFoundException;
84865
84866
84867
84868
84869
84870
84871 class FileGetContents extends AbstractRetriever
84872 {
84873 protected $messageBody;
84874
84875
84876
84877
84878
84879
84880 public function retrieve($uri)
84881 {
84882 $errorMessage = null;
84883 set_error_handler(function ($errno, $errstr) use (&$errorMessage) {
84884 $errorMessage = $errstr;
84885 });
84886 $response = file_get_contents($uri);
84887 restore_error_handler();
84888
84889 if ($errorMessage) {
84890 throw new ResourceNotFoundException($errorMessage);
84891 }
84892
84893 if (false === $response) {
84894 throw new ResourceNotFoundException('JSON schema not found at ' . $uri);
84895 }
84896
84897 if ($response == ''
84898 && substr($uri, 0, 7) == 'file://' && substr($uri, -1) == '/'
84899 ) {
84900 throw new ResourceNotFoundException('JSON schema not found at ' . $uri);
84901 }
84902
84903 $this->messageBody = $response;
84904 if (!empty($http_response_header)) {
84905
84906
84907 $this->fetchContentType($http_response_header); 
84908 } else { 
84909
84910 $this->contentType = null;
84911 }
84912
84913 return $this->messageBody;
84914 }
84915
84916
84917
84918
84919
84920
84921 private function fetchContentType(array $headers)
84922 {
84923 foreach ($headers as $header) {
84924 if ($this->contentType = self::getContentTypeMatchInHeader($header)) {
84925 return true;
84926 }
84927 }
84928
84929 return false;
84930 }
84931
84932
84933
84934
84935
84936
84937 protected static function getContentTypeMatchInHeader($header)
84938 {
84939 if (0 < preg_match("/Content-Type:(\V*)/ims", $header, $match)) {
84940 return trim($match[1]);
84941 }
84942
84943 return null;
84944 }
84945 }
84946 <?php
84947
84948 namespace JsonSchema\Uri\Retrievers;
84949
84950 use JsonSchema\Validator;
84951
84952
84953
84954
84955
84956
84957
84958
84959
84960
84961
84962
84963
84964 class PredefinedArray extends AbstractRetriever
84965 {
84966
84967
84968
84969
84970
84971 private $schemas;
84972
84973
84974
84975
84976
84977
84978
84979 public function __construct(array $schemas, $contentType = Validator::SCHEMA_MEDIA_TYPE)
84980 {
84981 $this->schemas = $schemas;
84982 $this->contentType = $contentType;
84983 }
84984
84985
84986
84987
84988
84989
84990 public function retrieve($uri)
84991 {
84992 if (!array_key_exists($uri, $this->schemas)) {
84993 throw new \JsonSchema\Exception\ResourceNotFoundException(sprintf(
84994 'The JSON schema "%s" was not found.',
84995 $uri
84996 ));
84997 }
84998
84999 return $this->schemas[$uri];
85000 }
85001 }
85002 <?php
85003
85004
85005
85006
85007
85008
85009
85010
85011 namespace JsonSchema\Uri\Retrievers;
85012
85013
85014
85015
85016
85017
85018 interface UriRetrieverInterface
85019 {
85020
85021
85022
85023
85024
85025
85026
85027
85028
85029 public function retrieve($uri);
85030
85031
85032
85033
85034
85035
85036 public function getContentType();
85037 }
85038 <?php
85039
85040
85041
85042
85043
85044
85045
85046
85047 namespace JsonSchema\Uri;
85048
85049 use JsonSchema\Exception\UriResolverException;
85050 use JsonSchema\UriResolverInterface;
85051
85052
85053
85054
85055
85056
85057 class UriResolver implements UriResolverInterface
85058 {
85059
85060
85061
85062
85063
85064
85065
85066 public function parse($uri)
85067 {
85068 preg_match('|^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?|', $uri, $match);
85069
85070 $components = array();
85071 if (5 < count($match)) {
85072 $components = array(
85073 'scheme' => $match[2],
85074 'authority' => $match[4],
85075 'path' => $match[5]
85076 );
85077 }
85078 if (7 < count($match)) {
85079 $components['query'] = $match[7];
85080 }
85081 if (9 < count($match)) {
85082 $components['fragment'] = $match[9];
85083 }
85084
85085 return $components;
85086 }
85087
85088
85089
85090
85091
85092
85093
85094
85095 public function generate(array $components)
85096 {
85097 $uri = $components['scheme'] . '://'
85098 . $components['authority']
85099 . $components['path'];
85100
85101 if (array_key_exists('query', $components) && strlen($components['query'])) {
85102 $uri .= '?' . $components['query'];
85103 }
85104 if (array_key_exists('fragment', $components)) {
85105 $uri .= '#' . $components['fragment'];
85106 }
85107
85108 return $uri;
85109 }
85110
85111
85112
85113
85114 public function resolve($uri, $baseUri = null)
85115 {
85116
85117 if (
85118 !is_null($baseUri) &&
85119 !filter_var($baseUri, \FILTER_VALIDATE_URL) &&
85120 !preg_match('|^[^/]+://|u', $baseUri)
85121 ) {
85122 if (is_file($baseUri)) {
85123 $baseUri = 'file://' . realpath($baseUri);
85124 } elseif (is_dir($baseUri)) {
85125 $baseUri = 'file://' . realpath($baseUri) . '/';
85126 } else {
85127 $baseUri = 'file://' . getcwd() . '/' . $baseUri;
85128 }
85129 }
85130
85131 if ($uri == '') {
85132 return $baseUri;
85133 }
85134
85135 $components = $this->parse($uri);
85136 $path = $components['path'];
85137
85138 if (!empty($components['scheme'])) {
85139 return $uri;
85140 }
85141 $baseComponents = $this->parse($baseUri);
85142 $basePath = $baseComponents['path'];
85143
85144 $baseComponents['path'] = self::combineRelativePathWithBasePath($path, $basePath);
85145 if (isset($components['fragment'])) {
85146 $baseComponents['fragment'] = $components['fragment'];
85147 }
85148
85149 return $this->generate($baseComponents);
85150 }
85151
85152
85153
85154
85155
85156
85157
85158
85159
85160
85161
85162 public static function combineRelativePathWithBasePath($relativePath, $basePath)
85163 {
85164 $relativePath = self::normalizePath($relativePath);
85165 if ($relativePath == '') {
85166 return $basePath;
85167 }
85168 if ($relativePath[0] == '/') {
85169 return $relativePath;
85170 }
85171
85172 $basePathSegments = explode('/', $basePath);
85173
85174 preg_match('|^/?(\.\./(?:\./)*)*|', $relativePath, $match);
85175 $numLevelUp = strlen($match[0]) /3 + 1;
85176 if ($numLevelUp >= count($basePathSegments)) {
85177 throw new UriResolverException(sprintf("Unable to resolve URI '%s' from base '%s'", $relativePath, $basePath));
85178 }
85179
85180 $basePathSegments = array_slice($basePathSegments, 0, -$numLevelUp);
85181 $path = preg_replace('|^/?(\.\./(\./)*)*|', '', $relativePath);
85182
85183 return implode('/', $basePathSegments) . '/' . $path;
85184 }
85185
85186
85187
85188
85189
85190
85191
85192
85193 private static function normalizePath($path)
85194 {
85195 $path = preg_replace('|((?<!\.)\./)*|', '', $path);
85196 $path = preg_replace('|//|', '/', $path);
85197
85198 return $path;
85199 }
85200
85201
85202
85203
85204
85205
85206 public function isValid($uri)
85207 {
85208 $components = $this->parse($uri);
85209
85210 return !empty($components);
85211 }
85212 }
85213 <?php
85214
85215
85216
85217
85218
85219
85220
85221
85222 namespace JsonSchema\Uri;
85223
85224 use JsonSchema\Exception\InvalidSchemaMediaTypeException;
85225 use JsonSchema\Exception\JsonDecodingException;
85226 use JsonSchema\Exception\ResourceNotFoundException;
85227 use JsonSchema\Uri\Retrievers\FileGetContents;
85228 use JsonSchema\Uri\Retrievers\UriRetrieverInterface;
85229 use JsonSchema\UriRetrieverInterface as BaseUriRetrieverInterface;
85230 use JsonSchema\Validator;
85231
85232
85233
85234
85235
85236
85237 class UriRetriever implements BaseUriRetrieverInterface
85238 {
85239
85240
85241
85242 protected $translationMap = array(
85243
85244 '|^https?://json-schema.org/draft-(0[34])/schema#?|' => 'package://dist/schema/json-schema-draft-$1.json'
85245 );
85246
85247
85248
85249
85250 protected $allowedInvalidContentTypeEndpoints = array(
85251 'http://json-schema.org/',
85252 'https://json-schema.org/'
85253 );
85254
85255
85256
85257
85258 protected $uriRetriever = null;
85259
85260
85261
85262
85263
85264
85265 private $schemaCache = array();
85266
85267
85268
85269
85270
85271
85272 public function addInvalidContentTypeEndpoint($endpoint)
85273 {
85274 $this->allowedInvalidContentTypeEndpoints[] = $endpoint;
85275 }
85276
85277
85278
85279
85280
85281
85282
85283
85284
85285 public function confirmMediaType($uriRetriever, $uri)
85286 {
85287 $contentType = $uriRetriever->getContentType();
85288
85289 if (is_null($contentType)) {
85290
85291 return;
85292 }
85293
85294 if (in_array($contentType, array(Validator::SCHEMA_MEDIA_TYPE, 'application/json'))) {
85295 return;
85296 }
85297
85298 foreach ($this->allowedInvalidContentTypeEndpoints as $endpoint) {
85299 if (strpos($uri, $endpoint) === 0) {
85300 return true;
85301 }
85302 }
85303
85304 throw new InvalidSchemaMediaTypeException(sprintf('Media type %s expected', Validator::SCHEMA_MEDIA_TYPE));
85305 }
85306
85307
85308
85309
85310
85311
85312
85313
85314
85315 public function getUriRetriever()
85316 {
85317 if (is_null($this->uriRetriever)) {
85318 $this->setUriRetriever(new FileGetContents());
85319 }
85320
85321 return $this->uriRetriever;
85322 }
85323
85324
85325
85326
85327
85328
85329
85330
85331
85332
85333
85334
85335
85336
85337
85338 public function resolvePointer($jsonSchema, $uri)
85339 {
85340 $resolver = new UriResolver();
85341 $parsed = $resolver->parse($uri);
85342 if (empty($parsed['fragment'])) {
85343 return $jsonSchema;
85344 }
85345
85346 $path = explode('/', $parsed['fragment']);
85347 while ($path) {
85348 $pathElement = array_shift($path);
85349 if (!empty($pathElement)) {
85350 $pathElement = str_replace('~1', '/', $pathElement);
85351 $pathElement = str_replace('~0', '~', $pathElement);
85352 if (!empty($jsonSchema->$pathElement)) {
85353 $jsonSchema = $jsonSchema->$pathElement;
85354 } else {
85355 throw new ResourceNotFoundException(
85356 'Fragment "' . $parsed['fragment'] . '" not found'
85357 . ' in ' . $uri
85358 );
85359 }
85360
85361 if (!is_object($jsonSchema)) {
85362 throw new ResourceNotFoundException(
85363 'Fragment part "' . $pathElement . '" is no object '
85364 . ' in ' . $uri
85365 );
85366 }
85367 }
85368 }
85369
85370 return $jsonSchema;
85371 }
85372
85373
85374
85375
85376 public function retrieve($uri, $baseUri = null, $translate = true)
85377 {
85378 $resolver = new UriResolver();
85379 $resolvedUri = $fetchUri = $resolver->resolve($uri, $baseUri);
85380
85381
85382 $arParts = $resolver->parse($resolvedUri);
85383 if (isset($arParts['fragment'])) {
85384 unset($arParts['fragment']);
85385 $fetchUri = $resolver->generate($arParts);
85386 }
85387
85388
85389 if ($translate) {
85390 $fetchUri = $this->translate($fetchUri);
85391 }
85392
85393 $jsonSchema = $this->loadSchema($fetchUri);
85394
85395
85396 $jsonSchema = $this->resolvePointer($jsonSchema, $resolvedUri);
85397
85398 if ($jsonSchema instanceof \stdClass) {
85399 $jsonSchema->id = $resolvedUri;
85400 }
85401
85402 return $jsonSchema;
85403 }
85404
85405
85406
85407
85408
85409
85410
85411
85412
85413 protected function loadSchema($fetchUri)
85414 {
85415 if (isset($this->schemaCache[$fetchUri])) {
85416 return $this->schemaCache[$fetchUri];
85417 }
85418
85419 $uriRetriever = $this->getUriRetriever();
85420 $contents = $this->uriRetriever->retrieve($fetchUri);
85421 $this->confirmMediaType($uriRetriever, $fetchUri);
85422 $jsonSchema = json_decode($contents);
85423
85424 if (JSON_ERROR_NONE < $error = json_last_error()) {
85425 throw new JsonDecodingException($error);
85426 }
85427
85428 $this->schemaCache[$fetchUri] = $jsonSchema;
85429
85430 return $jsonSchema;
85431 }
85432
85433
85434
85435
85436
85437
85438
85439
85440 public function setUriRetriever(UriRetrieverInterface $uriRetriever)
85441 {
85442 $this->uriRetriever = $uriRetriever;
85443
85444 return $this;
85445 }
85446
85447
85448
85449
85450
85451
85452
85453
85454 public function parse($uri)
85455 {
85456 preg_match('|^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?|', $uri, $match);
85457
85458 $components = array();
85459 if (5 < count($match)) {
85460 $components = array(
85461 'scheme' => $match[2],
85462 'authority' => $match[4],
85463 'path' => $match[5]
85464 );
85465 }
85466
85467 if (7 < count($match)) {
85468 $components['query'] = $match[7];
85469 }
85470
85471 if (9 < count($match)) {
85472 $components['fragment'] = $match[9];
85473 }
85474
85475 return $components;
85476 }
85477
85478
85479
85480
85481
85482
85483
85484
85485 public function generate(array $components)
85486 {
85487 $uri = $components['scheme'] . '://'
85488 . $components['authority']
85489 . $components['path'];
85490
85491 if (array_key_exists('query', $components)) {
85492 $uri .= $components['query'];
85493 }
85494
85495 if (array_key_exists('fragment', $components)) {
85496 $uri .= $components['fragment'];
85497 }
85498
85499 return $uri;
85500 }
85501
85502
85503
85504
85505
85506
85507
85508
85509
85510 public function resolve($uri, $baseUri = null)
85511 {
85512 $components = $this->parse($uri);
85513 $path = $components['path'];
85514
85515 if ((array_key_exists('scheme', $components)) && ('http' === $components['scheme'])) {
85516 return $uri;
85517 }
85518
85519 $baseComponents = $this->parse($baseUri);
85520 $basePath = $baseComponents['path'];
85521
85522 $baseComponents['path'] = UriResolver::combineRelativePathWithBasePath($path, $basePath);
85523
85524 return $this->generate($baseComponents);
85525 }
85526
85527
85528
85529
85530
85531
85532 public function isValid($uri)
85533 {
85534 $components = $this->parse($uri);
85535
85536 return !empty($components);
85537 }
85538
85539
85540
85541
85542 public function setTranslation($from, $to)
85543 {
85544 $this->translationMap[$from] = $to;
85545 }
85546
85547
85548
85549
85550 public function translate($uri)
85551 {
85552 foreach ($this->translationMap as $from => $to) {
85553 $uri = preg_replace($from, $to, $uri);
85554 }
85555
85556
85557 $uri = preg_replace('|^package://|', sprintf('file://%s/', realpath(__DIR__ . '/../../..')), $uri);
85558
85559 return $uri;
85560 }
85561 }
85562 <?php
85563
85564
85565
85566
85567
85568
85569
85570
85571 namespace JsonSchema;
85572
85573
85574
85575
85576 interface UriResolverInterface
85577 {
85578
85579
85580
85581
85582
85583
85584
85585
85586 public function resolve($uri, $baseUri = null);
85587 }
85588 <?php
85589
85590
85591
85592
85593
85594
85595
85596
85597 namespace JsonSchema;
85598
85599
85600
85601
85602 interface UriRetrieverInterface
85603 {
85604
85605
85606
85607
85608
85609
85610
85611
85612 public function retrieve($uri, $baseUri = null);
85613 }
85614 <?php
85615
85616
85617
85618
85619
85620
85621
85622
85623 namespace JsonSchema;
85624
85625 use JsonSchema\Constraints\BaseConstraint;
85626 use JsonSchema\Constraints\Constraint;
85627
85628
85629
85630
85631
85632
85633
85634
85635
85636 class Validator extends BaseConstraint
85637 {
85638 const SCHEMA_MEDIA_TYPE = 'application/schema+json';
85639
85640 const ERROR_NONE = 0x00000000;
85641 const ERROR_ALL = 0xFFFFFFFF;
85642 const ERROR_DOCUMENT_VALIDATION = 0x00000001;
85643 const ERROR_SCHEMA_VALIDATION = 0x00000002;
85644
85645
85646
85647
85648
85649
85650
85651
85652 public function validate(&$value, $schema = null, $checkMode = null)
85653 {
85654
85655 if (is_array($schema)) {
85656 $schema = self::arrayToObjectRecursive($schema);
85657 }
85658
85659
85660 $initialCheckMode = $this->factory->getConfig();
85661 if ($checkMode !== null) {
85662 $this->factory->setConfig($checkMode);
85663 }
85664
85665
85666 if (is_object($schema) && property_exists($schema, 'id')) {
85667 $schemaURI = $schema->id;
85668 } else {
85669 $schemaURI = SchemaStorage::INTERNAL_PROVIDED_SCHEMA_URI;
85670 }
85671 $this->factory->getSchemaStorage()->addSchema($schemaURI, $schema);
85672
85673 $validator = $this->factory->createInstanceFor('schema');
85674 $validator->check(
85675 $value,
85676 $this->factory->getSchemaStorage()->getSchema($schemaURI)
85677 );
85678
85679 $this->factory->setConfig($initialCheckMode);
85680
85681 $this->addErrors(array_unique($validator->getErrors(), SORT_REGULAR));
85682
85683 return $validator->getErrorMask();
85684 }
85685
85686
85687
85688
85689 public function check($value, $schema)
85690 {
85691 return $this->validate($value, $schema);
85692 }
85693
85694
85695
85696
85697 public function coerce(&$value, $schema)
85698 {
85699 return $this->validate($value, $schema, Constraint::CHECK_MODE_COERCE_TYPES);
85700 }
85701 }
85702 Copyright (C) 2015 Composer
85703
85704 Permission is hereby granted, free of charge, to any person obtaining a copy of
85705 this software and associated documentation files (the "Software"), to deal in
85706 the Software without restriction, including without limitation the rights to
85707 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
85708 of the Software, and to permit persons to whom the Software is furnished to do
85709 so, subject to the following conditions:
85710
85711 The above copyright notice and this permission notice shall be included in all
85712 copies or substantial portions of the Software.
85713
85714 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
85715 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
85716 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
85717 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
85718 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
85719 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
85720 SOFTWARE.
85721 <?php
85722
85723
85724
85725
85726
85727
85728
85729
85730
85731
85732 namespace Composer\Spdx;
85733
85734 class SpdxLicenses
85735 {
85736
85737 const LICENSES_FILE = 'spdx-licenses.json';
85738
85739
85740 const EXCEPTIONS_FILE = 'spdx-exceptions.json';
85741
85742
85743
85744
85745
85746
85747
85748
85749
85750
85751
85752
85753
85754
85755 private $licenses;
85756
85757
85758
85759
85760 private $licensesExpression;
85761
85762
85763
85764
85765
85766
85767
85768
85769
85770
85771
85772
85773
85774
85775 private $exceptions;
85776
85777
85778
85779
85780 private $exceptionsExpression;
85781
85782 public function __construct()
85783 {
85784 $this->loadLicenses();
85785 $this->loadExceptions();
85786 }
85787
85788
85789
85790
85791
85792
85793
85794
85795
85796
85797
85798
85799
85800 public function getLicenseByIdentifier($identifier)
85801 {
85802 $key = strtolower($identifier);
85803
85804 if (!isset($this->licenses[$key])) {
85805 return;
85806 }
85807
85808 list($identifier, $name, $isOsiApproved, $isDeprecatedLicenseId) = $this->licenses[$key];
85809
85810 return array(
85811 $name,
85812 $isOsiApproved,
85813 'https://spdx.org/licenses/' . $identifier . '.html#licenseText',
85814 $isDeprecatedLicenseId,
85815 );
85816 }
85817
85818
85819
85820
85821
85822
85823 public function getLicenses()
85824 {
85825 return $this->licenses;
85826 }
85827
85828
85829
85830
85831
85832
85833
85834
85835
85836
85837
85838
85839
85840 public function getExceptionByIdentifier($identifier)
85841 {
85842 $key = strtolower($identifier);
85843
85844 if (!isset($this->exceptions[$key])) {
85845 return;
85846 }
85847
85848 list($identifier, $name) = $this->exceptions[$key];
85849
85850 return array(
85851 $name,
85852 'https://spdx.org/licenses/' . $identifier . '.html#licenseExceptionText',
85853 );
85854 }
85855
85856
85857
85858
85859
85860
85861
85862
85863 public function getIdentifierByName($name)
85864 {
85865 foreach ($this->licenses as $licenseData) {
85866 if ($licenseData[1] === $name) {
85867 return $licenseData[0];
85868 }
85869 }
85870
85871 foreach ($this->exceptions as $licenseData) {
85872 if ($licenseData[1] === $name) {
85873 return $licenseData[0];
85874 }
85875 }
85876 }
85877
85878
85879
85880
85881
85882
85883
85884
85885 public function isOsiApprovedByIdentifier($identifier)
85886 {
85887 return $this->licenses[strtolower($identifier)][2];
85888 }
85889
85890
85891
85892
85893
85894
85895
85896
85897 public function isDeprecatedByIdentifier($identifier)
85898 {
85899 return $this->licenses[strtolower($identifier)][3];
85900 }
85901
85902
85903
85904
85905
85906
85907
85908
85909 public function validate($license)
85910 {
85911 if (is_array($license)) {
85912 $count = count($license);
85913 if ($count !== count(array_filter($license, 'is_string'))) {
85914 throw new \InvalidArgumentException('Array of strings expected.');
85915 }
85916 $license = $count > 1 ? '(' . implode(' OR ', $license) . ')' : (string) reset($license);
85917 }
85918
85919 if (!is_string($license)) {
85920 throw new \InvalidArgumentException(sprintf(
85921 'Array or String expected, %s given.',
85922 gettype($license)
85923 ));
85924 }
85925
85926 return $this->isValidLicenseString($license);
85927 }
85928
85929
85930
85931
85932 public static function getResourcesDir()
85933 {
85934 return dirname(__DIR__) . '/res';
85935 }
85936
85937 private function loadLicenses()
85938 {
85939 if (null !== $this->licenses) {
85940 return;
85941 }
85942
85943 $json = file_get_contents(self::getResourcesDir() . '/' . self::LICENSES_FILE);
85944 $this->licenses = array();
85945
85946 foreach (json_decode($json, true) as $identifier => $license) {
85947 $this->licenses[strtolower($identifier)] = array($identifier, $license[0], $license[1], $license[2]);
85948 }
85949 }
85950
85951 private function loadExceptions()
85952 {
85953 if (null !== $this->exceptions) {
85954 return;
85955 }
85956
85957 $json = file_get_contents(self::getResourcesDir() . '/' . self::EXCEPTIONS_FILE);
85958 $this->exceptions = array();
85959
85960 foreach (json_decode($json, true) as $identifier => $exception) {
85961 $this->exceptions[strtolower($identifier)] = array($identifier, $exception[0]);
85962 }
85963 }
85964
85965
85966
85967
85968 private function getLicensesExpression()
85969 {
85970 if (null === $this->licensesExpression) {
85971 $licenses = array_map('preg_quote', array_keys($this->licenses));
85972 rsort($licenses);
85973 $licenses = implode('|', $licenses);
85974 $this->licensesExpression = $licenses;
85975 }
85976
85977 return $this->licensesExpression;
85978 }
85979
85980
85981
85982
85983 private function getExceptionsExpression()
85984 {
85985 if (null === $this->exceptionsExpression) {
85986 $exceptions = array_map('preg_quote', array_keys($this->exceptions));
85987 rsort($exceptions);
85988 $exceptions = implode('|', $exceptions);
85989 $this->exceptionsExpression = $exceptions;
85990 }
85991
85992 return $this->exceptionsExpression;
85993 }
85994
85995
85996
85997
85998
85999
86000
86001
86002 private function isValidLicenseString($license)
86003 {
86004 if (isset($this->licenses[strtolower($license)])) {
86005 return true;
86006 }
86007
86008 $licenses = $this->getLicensesExpression();
86009 $exceptions = $this->getExceptionsExpression();
86010
86011 $regex = <<<REGEX
86012 {
86013 (?(DEFINE)
86014     # idstring: 1*( ALPHA / DIGIT / - / . )
86015     (?<idstring>[\pL\pN.-]{1,})
86016
86017     # license-id: taken from list
86018     (?<licenseid>${licenses})
86019
86020     # license-exception-id: taken from list
86021     (?<licenseexceptionid>${exceptions})
86022
86023     # license-ref: [DocumentRef-1*(idstring):]LicenseRef-1*(idstring)
86024     (?<licenseref>(?:DocumentRef-(?&idstring):)?LicenseRef-(?&idstring))
86025
86026     # simple-expresssion: license-id / license-id+ / license-ref
86027     (?<simple_expression>(?&licenseid)\+? | (?&licenseid) | (?&licenseref))
86028
86029     # compound-expression: 1*(
86030     #   simple-expression /
86031     #   simple-expression WITH license-exception-id /
86032     #   compound-expression AND compound-expression /
86033     #   compound-expression OR compound-expression
86034     # ) / ( compound-expression ) )
86035     (?<compound_head>
86036         (?&simple_expression) ( \s+ WITH \s+ (?&licenseexceptionid))?
86037             | \( \s* (?&compound_expression) \s* \)
86038     )
86039     (?<compound_expression>
86040         (?&compound_head) (?: \s+ (?:AND|OR) \s+ (?&compound_expression))?
86041     )
86042
86043     # license-expression: 1*1(simple-expression / compound-expression)
86044     (?<license_expression>(?&compound_expression) | (?&simple_expression))
86045 ) # end of define
86046
86047 ^(NONE | NOASSERTION | (?&license_expression))$
86048 }xi
86049 REGEX;
86050
86051 $match = preg_match($regex, $license);
86052
86053 if (0 === $match) {
86054 return false;
86055 }
86056
86057 if (false === $match) {
86058 throw new \RuntimeException('Regex failed to compile/run.');
86059 }
86060
86061 return true;
86062 }
86063 }
86064 Copyright (C) 2015 Composer
86065
86066 Permission is hereby granted, free of charge, to any person obtaining a copy of
86067 this software and associated documentation files (the "Software"), to deal in
86068 the Software without restriction, including without limitation the rights to
86069 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
86070 of the Software, and to permit persons to whom the Software is furnished to do
86071 so, subject to the following conditions:
86072
86073 The above copyright notice and this permission notice shall be included in all
86074 copies or substantial portions of the Software.
86075
86076 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
86077 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
86078 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
86079 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
86080 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
86081 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
86082 SOFTWARE.
86083 <?php
86084
86085
86086
86087
86088
86089
86090
86091
86092
86093
86094 namespace Composer\Semver;
86095
86096 use Composer\Semver\Constraint\Constraint;
86097
86098 class Comparator
86099 {
86100
86101
86102
86103
86104
86105
86106
86107
86108 public static function greaterThan($version1, $version2)
86109 {
86110 return self::compare($version1, '>', $version2);
86111 }
86112
86113
86114
86115
86116
86117
86118
86119
86120
86121 public static function greaterThanOrEqualTo($version1, $version2)
86122 {
86123 return self::compare($version1, '>=', $version2);
86124 }
86125
86126
86127
86128
86129
86130
86131
86132
86133
86134 public static function lessThan($version1, $version2)
86135 {
86136 return self::compare($version1, '<', $version2);
86137 }
86138
86139
86140
86141
86142
86143
86144
86145
86146
86147 public static function lessThanOrEqualTo($version1, $version2)
86148 {
86149 return self::compare($version1, '<=', $version2);
86150 }
86151
86152
86153
86154
86155
86156
86157
86158
86159
86160 public static function equalTo($version1, $version2)
86161 {
86162 return self::compare($version1, '==', $version2);
86163 }
86164
86165
86166
86167
86168
86169
86170
86171
86172
86173 public static function notEqualTo($version1, $version2)
86174 {
86175 return self::compare($version1, '!=', $version2);
86176 }
86177
86178
86179
86180
86181
86182
86183
86184
86185
86186
86187 public static function compare($version1, $operator, $version2)
86188 {
86189 $constraint = new Constraint($operator, $version2);
86190
86191 return $constraint->matches(new Constraint('==', $version1));
86192 }
86193 }
86194 <?php
86195
86196
86197
86198
86199
86200
86201
86202
86203
86204
86205 namespace Composer\Semver\Constraint;
86206
86207 trigger_error('The ' . __NAMESPACE__ . '\AbstractConstraint abstract class is deprecated, there is no replacement for it, it will be removed in the next major version.', E_USER_DEPRECATED);
86208
86209
86210
86211
86212 abstract class AbstractConstraint implements ConstraintInterface
86213 {
86214
86215 protected $prettyString;
86216
86217
86218
86219
86220
86221
86222 public function matches(ConstraintInterface $provider)
86223 {
86224 if ($provider instanceof $this) {
86225
86226 return $this->matchSpecific($provider);
86227 }
86228
86229
86230 return $provider->matches($this);
86231 }
86232
86233
86234
86235
86236 public function setPrettyString($prettyString)
86237 {
86238 $this->prettyString = $prettyString;
86239 }
86240
86241
86242
86243
86244 public function getPrettyString()
86245 {
86246 if ($this->prettyString) {
86247 return $this->prettyString;
86248 }
86249
86250 return $this->__toString();
86251 }
86252
86253
86254
86255
86256 }
86257 <?php
86258
86259
86260
86261
86262
86263
86264
86265
86266
86267
86268 namespace Composer\Semver\Constraint;
86269
86270
86271
86272
86273 class Constraint implements ConstraintInterface
86274 {
86275
86276 const OP_EQ = 0;
86277 const OP_LT = 1;
86278 const OP_LE = 2;
86279 const OP_GT = 3;
86280 const OP_GE = 4;
86281 const OP_NE = 5;
86282
86283
86284
86285
86286
86287
86288 private static $transOpStr = array(
86289 '=' => self::OP_EQ,
86290 '==' => self::OP_EQ,
86291 '<' => self::OP_LT,
86292 '<=' => self::OP_LE,
86293 '>' => self::OP_GT,
86294 '>=' => self::OP_GE,
86295 '<>' => self::OP_NE,
86296 '!=' => self::OP_NE,
86297 );
86298
86299
86300
86301
86302
86303
86304 private static $transOpInt = array(
86305 self::OP_EQ => '==',
86306 self::OP_LT => '<',
86307 self::OP_LE => '<=',
86308 self::OP_GT => '>',
86309 self::OP_GE => '>=',
86310 self::OP_NE => '!=',
86311 );
86312
86313
86314 protected $operator;
86315
86316
86317 protected $version;
86318
86319
86320 protected $prettyString;
86321
86322
86323
86324
86325
86326
86327 public function matches(ConstraintInterface $provider)
86328 {
86329 if ($provider instanceof $this) {
86330 return $this->matchSpecific($provider);
86331 }
86332
86333
86334 return $provider->matches($this);
86335 }
86336
86337
86338
86339
86340 public function setPrettyString($prettyString)
86341 {
86342 $this->prettyString = $prettyString;
86343 }
86344
86345
86346
86347
86348 public function getPrettyString()
86349 {
86350 if ($this->prettyString) {
86351 return $this->prettyString;
86352 }
86353
86354 return $this->__toString();
86355 }
86356
86357
86358
86359
86360
86361
86362 public static function getSupportedOperators()
86363 {
86364 return array_keys(self::$transOpStr);
86365 }
86366
86367
86368
86369
86370
86371
86372
86373
86374
86375 public function __construct($operator, $version)
86376 {
86377 if (!isset(self::$transOpStr[$operator])) {
86378 throw new \InvalidArgumentException(sprintf(
86379 'Invalid operator "%s" given, expected one of: %s',
86380 $operator,
86381 implode(', ', self::getSupportedOperators())
86382 ));
86383 }
86384
86385 $this->operator = self::$transOpStr[$operator];
86386 $this->version = $version;
86387 }
86388
86389
86390
86391
86392
86393
86394
86395
86396
86397
86398
86399 public function versionCompare($a, $b, $operator, $compareBranches = false)
86400 {
86401 if (!isset(self::$transOpStr[$operator])) {
86402 throw new \InvalidArgumentException(sprintf(
86403 'Invalid operator "%s" given, expected one of: %s',
86404 $operator,
86405 implode(', ', self::getSupportedOperators())
86406 ));
86407 }
86408
86409 $aIsBranch = 'dev-' === substr($a, 0, 4);
86410 $bIsBranch = 'dev-' === substr($b, 0, 4);
86411
86412 if ($aIsBranch && $bIsBranch) {
86413 return $operator === '==' && $a === $b;
86414 }
86415
86416
86417 if (!$compareBranches && ($aIsBranch || $bIsBranch)) {
86418 return false;
86419 }
86420
86421 return version_compare($a, $b, $operator);
86422 }
86423
86424
86425
86426
86427
86428
86429
86430 public function matchSpecific(Constraint $provider, $compareBranches = false)
86431 {
86432 $noEqualOp = str_replace('=', '', self::$transOpInt[$this->operator]);
86433 $providerNoEqualOp = str_replace('=', '', self::$transOpInt[$provider->operator]);
86434
86435 $isEqualOp = self::OP_EQ === $this->operator;
86436 $isNonEqualOp = self::OP_NE === $this->operator;
86437 $isProviderEqualOp = self::OP_EQ === $provider->operator;
86438 $isProviderNonEqualOp = self::OP_NE === $provider->operator;
86439
86440
86441
86442 if ($isNonEqualOp || $isProviderNonEqualOp) {
86443 return (!$isEqualOp && !$isProviderEqualOp)
86444 || $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
86445 }
86446
86447
86448
86449 if ($this->operator !== self::OP_EQ && $noEqualOp === $providerNoEqualOp) {
86450 return true;
86451 }
86452
86453 if ($this->versionCompare($provider->version, $this->version, self::$transOpInt[$this->operator], $compareBranches)) {
86454
86455
86456 return !($provider->version === $this->version
86457 && self::$transOpInt[$provider->operator] === $providerNoEqualOp
86458 && self::$transOpInt[$this->operator] !== $noEqualOp);
86459 }
86460
86461 return false;
86462 }
86463
86464
86465
86466
86467 public function __toString()
86468 {
86469 return self::$transOpInt[$this->operator] . ' ' . $this->version;
86470 }
86471 }
86472 <?php
86473
86474
86475
86476
86477
86478
86479
86480
86481
86482
86483 namespace Composer\Semver\Constraint;
86484
86485 interface ConstraintInterface
86486 {
86487
86488
86489
86490
86491
86492 public function matches(ConstraintInterface $provider);
86493
86494
86495
86496
86497 public function getPrettyString();
86498
86499
86500
86501
86502 public function __toString();
86503 }
86504 <?php
86505
86506
86507
86508
86509
86510
86511
86512
86513
86514
86515 namespace Composer\Semver\Constraint;
86516
86517
86518
86519
86520 class EmptyConstraint implements ConstraintInterface
86521 {
86522
86523 protected $prettyString;
86524
86525
86526
86527
86528
86529
86530 public function matches(ConstraintInterface $provider)
86531 {
86532 return true;
86533 }
86534
86535
86536
86537
86538 public function setPrettyString($prettyString)
86539 {
86540 $this->prettyString = $prettyString;
86541 }
86542
86543
86544
86545
86546 public function getPrettyString()
86547 {
86548 if ($this->prettyString) {
86549 return $this->prettyString;
86550 }
86551
86552 return (string) $this;
86553 }
86554
86555
86556
86557
86558 public function __toString()
86559 {
86560 return '[]';
86561 }
86562 }
86563 <?php
86564
86565
86566
86567
86568
86569
86570
86571
86572
86573
86574 namespace Composer\Semver\Constraint;
86575
86576
86577
86578
86579 class MultiConstraint implements ConstraintInterface
86580 {
86581
86582 protected $constraints;
86583
86584
86585 protected $prettyString;
86586
86587
86588 protected $conjunctive;
86589
86590
86591
86592
86593
86594 public function __construct(array $constraints, $conjunctive = true)
86595 {
86596 $this->constraints = $constraints;
86597 $this->conjunctive = $conjunctive;
86598 }
86599
86600
86601
86602
86603 public function getConstraints()
86604 {
86605 return $this->constraints;
86606 }
86607
86608
86609
86610
86611 public function isConjunctive()
86612 {
86613 return $this->conjunctive;
86614 }
86615
86616
86617
86618
86619 public function isDisjunctive()
86620 {
86621 return !$this->conjunctive;
86622 }
86623
86624
86625
86626
86627
86628
86629 public function matches(ConstraintInterface $provider)
86630 {
86631 if (false === $this->conjunctive) {
86632 foreach ($this->constraints as $constraint) {
86633 if ($constraint->matches($provider)) {
86634 return true;
86635 }
86636 }
86637
86638 return false;
86639 }
86640
86641 foreach ($this->constraints as $constraint) {
86642 if (!$constraint->matches($provider)) {
86643 return false;
86644 }
86645 }
86646
86647 return true;
86648 }
86649
86650
86651
86652
86653 public function setPrettyString($prettyString)
86654 {
86655 $this->prettyString = $prettyString;
86656 }
86657
86658
86659
86660
86661 public function getPrettyString()
86662 {
86663 if ($this->prettyString) {
86664 return $this->prettyString;
86665 }
86666
86667 return (string) $this;
86668 }
86669
86670
86671
86672
86673 public function __toString()
86674 {
86675 $constraints = array();
86676 foreach ($this->constraints as $constraint) {
86677 $constraints[] = (string) $constraint;
86678 }
86679
86680 return '[' . implode($this->conjunctive ? ' ' : ' || ', $constraints) . ']';
86681 }
86682 }
86683 <?php
86684
86685
86686
86687
86688
86689
86690
86691
86692
86693
86694 namespace Composer\Semver;
86695
86696 use Composer\Semver\Constraint\Constraint;
86697
86698 class Semver
86699 {
86700 const SORT_ASC = 1;
86701 const SORT_DESC = -1;
86702
86703
86704 private static $versionParser;
86705
86706
86707
86708
86709
86710
86711
86712
86713
86714 public static function satisfies($version, $constraints)
86715 {
86716 if (null === self::$versionParser) {
86717 self::$versionParser = new VersionParser();
86718 }
86719
86720 $versionParser = self::$versionParser;
86721 $provider = new Constraint('==', $versionParser->normalize($version));
86722 $parsedConstraints = $versionParser->parseConstraints($constraints);
86723
86724 return $parsedConstraints->matches($provider);
86725 }
86726
86727
86728
86729
86730
86731
86732
86733
86734
86735 public static function satisfiedBy(array $versions, $constraints)
86736 {
86737 $versions = array_filter($versions, function ($version) use ($constraints) {
86738 return Semver::satisfies($version, $constraints);
86739 });
86740
86741 return array_values($versions);
86742 }
86743
86744
86745
86746
86747
86748
86749
86750
86751 public static function sort(array $versions)
86752 {
86753 return self::usort($versions, self::SORT_ASC);
86754 }
86755
86756
86757
86758
86759
86760
86761
86762
86763 public static function rsort(array $versions)
86764 {
86765 return self::usort($versions, self::SORT_DESC);
86766 }
86767
86768
86769
86770
86771
86772
86773
86774 private static function usort(array $versions, $direction)
86775 {
86776 if (null === self::$versionParser) {
86777 self::$versionParser = new VersionParser();
86778 }
86779
86780 $versionParser = self::$versionParser;
86781 $normalized = array();
86782
86783
86784
86785 foreach ($versions as $key => $version) {
86786 $normalized[] = array($versionParser->normalize($version), $key);
86787 }
86788
86789 usort($normalized, function (array $left, array $right) use ($direction) {
86790 if ($left[0] === $right[0]) {
86791 return 0;
86792 }
86793
86794 if (Comparator::lessThan($left[0], $right[0])) {
86795 return -$direction;
86796 }
86797
86798 return $direction;
86799 });
86800
86801
86802 $sorted = array();
86803 foreach ($normalized as $item) {
86804 $sorted[] = $versions[$item[1]];
86805 }
86806
86807 return $sorted;
86808 }
86809 }
86810 <?php
86811
86812
86813
86814
86815
86816
86817
86818
86819
86820
86821 namespace Composer\Semver;
86822
86823 use Composer\Semver\Constraint\ConstraintInterface;
86824 use Composer\Semver\Constraint\EmptyConstraint;
86825 use Composer\Semver\Constraint\MultiConstraint;
86826 use Composer\Semver\Constraint\Constraint;
86827
86828
86829
86830
86831
86832
86833 class VersionParser
86834 {
86835
86836
86837
86838
86839
86840
86841
86842
86843
86844
86845
86846
86847
86848 private static $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)((?:[.-]?\d+)*+)?)?([.-]?dev)?';
86849
86850
86851 private static $stabilitiesRegex = 'stable|RC|beta|alpha|dev';
86852
86853
86854
86855
86856
86857
86858
86859
86860 public static function parseStability($version)
86861 {
86862 $version = preg_replace('{#.+$}i', '', $version);
86863
86864 if (strpos($version, 'dev-') === 0 || '-dev' === substr($version, -4)) {
86865 return 'dev';
86866 }
86867
86868 preg_match('{' . self::$modifierRegex . '(?:\+.*)?$}i', strtolower($version), $match);
86869
86870 if (!empty($match[3])) {
86871 return 'dev';
86872 }
86873
86874 if (!empty($match[1])) {
86875 if ('beta' === $match[1] || 'b' === $match[1]) {
86876 return 'beta';
86877 }
86878 if ('alpha' === $match[1] || 'a' === $match[1]) {
86879 return 'alpha';
86880 }
86881 if ('rc' === $match[1]) {
86882 return 'RC';
86883 }
86884 }
86885
86886 return 'stable';
86887 }
86888
86889
86890
86891
86892
86893
86894 public static function normalizeStability($stability)
86895 {
86896 $stability = strtolower($stability);
86897
86898 return $stability === 'rc' ? 'RC' : $stability;
86899 }
86900
86901
86902
86903
86904
86905
86906
86907
86908
86909
86910
86911 public function normalize($version, $fullVersion = null)
86912 {
86913 $version = trim($version);
86914 $origVersion = $version;
86915 if (null === $fullVersion) {
86916 $fullVersion = $version;
86917 }
86918
86919
86920 if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $version, $match)) {
86921 $version = $match[1];
86922 }
86923
86924
86925 if (preg_match('{@(?:' . self::$stabilitiesRegex . ')$}i', $version, $match)) {
86926 $version = substr($version, 0, strlen($version) - strlen($match[0]));
86927 }
86928
86929
86930 if (preg_match('{^(?:dev-)?(?:master|trunk|default)$}i', $version)) {
86931 return '9999999-dev';
86932 }
86933
86934
86935 if (stripos($version, 'dev-') === 0) {
86936 return 'dev-' . substr($version, 4);
86937 }
86938
86939
86940 if (preg_match('{^([^,\s+]++)\+[^\s]++$}', $version, $match)) {
86941 $version = $match[1];
86942 }
86943
86944
86945 if (preg_match('{^v?(\d{1,5})(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
86946 $version = $matches[1]
86947 . (!empty($matches[2]) ? $matches[2] : '.0')
86948 . (!empty($matches[3]) ? $matches[3] : '.0')
86949 . (!empty($matches[4]) ? $matches[4] : '.0');
86950 $index = 5;
86951
86952 } elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)' . self::$modifierRegex . '$}i', $version, $matches)) {
86953 $version = preg_replace('{\D}', '.', $matches[1]);
86954 $index = 2;
86955 }
86956
86957
86958 if (isset($index)) {
86959 if (!empty($matches[$index])) {
86960 if ('stable' === $matches[$index]) {
86961 return $version;
86962 }
86963 $version .= '-' . $this->expandStability($matches[$index]) . (isset($matches[$index + 1]) && '' !== $matches[$index + 1] ? ltrim($matches[$index + 1], '.-') : '');
86964 }
86965
86966 if (!empty($matches[$index + 2])) {
86967 $version .= '-dev';
86968 }
86969
86970 return $version;
86971 }
86972
86973
86974 if (preg_match('{(.*?)[.-]?dev$}i', $version, $match)) {
86975 try {
86976 $normalized = $this->normalizeBranch($match[1]);
86977
86978
86979
86980 if (strpos($normalized, 'dev-') === false) {
86981 return $normalized;
86982 }
86983 } catch (\Exception $e) {
86984 }
86985 }
86986
86987 $extraMessage = '';
86988 if (preg_match('{ +as +' . preg_quote($version) . '(?:@(?:'.self::$stabilitiesRegex.'))?$}', $fullVersion)) {
86989 $extraMessage = ' in "' . $fullVersion . '", the alias must be an exact version';
86990 } elseif (preg_match('{^' . preg_quote($version) . '(?:@(?:'.self::$stabilitiesRegex.'))? +as +}', $fullVersion)) {
86991 $extraMessage = ' in "' . $fullVersion . '", the alias source must be an exact version, if it is a branch name you should prefix it with dev-';
86992 }
86993
86994 throw new \UnexpectedValueException('Invalid version string "' . $origVersion . '"' . $extraMessage);
86995 }
86996
86997
86998
86999
87000
87001
87002
87003
87004 public function parseNumericAliasPrefix($branch)
87005 {
87006 if (preg_match('{^(?P<version>(\d++\\.)*\d++)(?:\.x)?-dev$}i', $branch, $matches)) {
87007 return $matches['version'] . '.';
87008 }
87009
87010 return false;
87011 }
87012
87013
87014
87015
87016
87017
87018
87019
87020 public function normalizeBranch($name)
87021 {
87022 $name = trim($name);
87023
87024 if (in_array($name, array('master', 'trunk', 'default'))) {
87025 return $this->normalize($name);
87026 }
87027
87028 if (preg_match('{^v?(\d++)(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?$}i', $name, $matches)) {
87029 $version = '';
87030 for ($i = 1; $i < 5; ++$i) {
87031 $version .= isset($matches[$i]) ? str_replace(array('*', 'X'), 'x', $matches[$i]) : '.x';
87032 }
87033
87034 return str_replace('x', '9999999', $version) . '-dev';
87035 }
87036
87037 return 'dev-' . $name;
87038 }
87039
87040
87041
87042
87043
87044
87045
87046
87047 public function parseConstraints($constraints)
87048 {
87049 $prettyConstraint = $constraints;
87050
87051 $orConstraints = preg_split('{\s*\|\|?\s*}', trim($constraints));
87052 $orGroups = array();
87053
87054 foreach ($orConstraints as $constraints) {
87055 $andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraints);
87056 if (count($andConstraints) > 1) {
87057 $constraintObjects = array();
87058 foreach ($andConstraints as $constraint) {
87059 foreach ($this->parseConstraint($constraint) as $parsedConstraint) {
87060 $constraintObjects[] = $parsedConstraint;
87061 }
87062 }
87063 } else {
87064 $constraintObjects = $this->parseConstraint($andConstraints[0]);
87065 }
87066
87067 if (1 === count($constraintObjects)) {
87068 $constraint = $constraintObjects[0];
87069 } else {
87070 $constraint = new MultiConstraint($constraintObjects);
87071 }
87072
87073 $orGroups[] = $constraint;
87074 }
87075
87076 if (1 === count($orGroups)) {
87077 $constraint = $orGroups[0];
87078 } elseif (2 === count($orGroups)
87079
87080
87081 && $orGroups[0] instanceof MultiConstraint
87082 && $orGroups[1] instanceof MultiConstraint
87083 && 2 === count($orGroups[0]->getConstraints())
87084 && 2 === count($orGroups[1]->getConstraints())
87085 && ($a = (string) $orGroups[0])
87086 && strpos($a, '[>=') === 0 && (false !== ($posA = strpos($a, '<', 4)))
87087 && ($b = (string) $orGroups[1])
87088 && strpos($b, '[>=') === 0 && (false !== ($posB = strpos($b, '<', 4)))
87089 && substr($a, $posA + 2, -1) === substr($b, 4, $posB - 5)
87090 ) {
87091 $constraint = new MultiConstraint(array(
87092 new Constraint('>=', substr($a, 4, $posA - 5)),
87093 new Constraint('<', substr($b, $posB + 2, -1)),
87094 ));
87095 } else {
87096 $constraint = new MultiConstraint($orGroups, false);
87097 }
87098
87099 $constraint->setPrettyString($prettyConstraint);
87100
87101 return $constraint;
87102 }
87103
87104
87105
87106
87107
87108
87109
87110
87111 private function parseConstraint($constraint)
87112 {
87113
87114 if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $constraint, $match)) {
87115 $constraint = $match[1];
87116 }
87117
87118
87119 if (preg_match('{^([^,\s]*?)@(' . self::$stabilitiesRegex . ')$}i', $constraint, $match)) {
87120 $constraint = '' !== $match[1] ? $match[1] : '*';
87121 if ($match[2] !== 'stable') {
87122 $stabilityModifier = $match[2];
87123 }
87124 }
87125
87126
87127 if (preg_match('{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i', $constraint, $match)) {
87128 $constraint = $match[1];
87129 }
87130
87131 if (preg_match('{^v?[xX*](\.[xX*])*$}i', $constraint)) {
87132 return array(new EmptyConstraint());
87133 }
87134
87135 $versionRegex = 'v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.(\d++))?(?:' . self::$modifierRegex . '|\.([xX*][.-]?dev))(?:\+[^\s]+)?';
87136
87137
87138
87139
87140
87141
87142 if (preg_match('{^~>?' . $versionRegex . '$}i', $constraint, $matches)) {
87143 if (strpos($constraint, '~>') === 0) {
87144 throw new \UnexpectedValueException(
87145 'Could not parse version constraint ' . $constraint . ': ' .
87146 'Invalid operator "~>", you probably meant to use the "~" operator'
87147 );
87148 }
87149
87150
87151 if (isset($matches[4]) && '' !== $matches[4] && null !== $matches[4]) {
87152 $position = 4;
87153 } elseif (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
87154 $position = 3;
87155 } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
87156 $position = 2;
87157 } else {
87158 $position = 1;
87159 }
87160
87161
87162 if (!empty($matches[8])) {
87163 $position++;
87164 }
87165
87166
87167 $stabilitySuffix = '';
87168 if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) {
87169 $stabilitySuffix .= '-dev';
87170 }
87171
87172 $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
87173 $lowerBound = new Constraint('>=', $lowVersion);
87174
87175
87176
87177 $highPosition = max(1, $position - 1);
87178 $highVersion = $this->manipulateVersionString($matches, $highPosition, 1) . '-dev';
87179 $upperBound = new Constraint('<', $highVersion);
87180
87181 return array(
87182 $lowerBound,
87183 $upperBound,
87184 );
87185 }
87186
87187
87188
87189
87190
87191
87192 if (preg_match('{^\^' . $versionRegex . '($)}i', $constraint, $matches)) {
87193
87194 if ('0' !== $matches[1] || '' === $matches[2] || null === $matches[2]) {
87195 $position = 1;
87196 } elseif ('0' !== $matches[2] || '' === $matches[3] || null === $matches[3]) {
87197 $position = 2;
87198 } else {
87199 $position = 3;
87200 }
87201
87202
87203 $stabilitySuffix = '';
87204 if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) {
87205 $stabilitySuffix .= '-dev';
87206 }
87207
87208 $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
87209 $lowerBound = new Constraint('>=', $lowVersion);
87210
87211
87212
87213 $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
87214 $upperBound = new Constraint('<', $highVersion);
87215
87216 return array(
87217 $lowerBound,
87218 $upperBound,
87219 );
87220 }
87221
87222
87223
87224
87225
87226 if (preg_match('{^v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.[xX*])++$}', $constraint, $matches)) {
87227 if (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
87228 $position = 3;
87229 } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
87230 $position = 2;
87231 } else {
87232 $position = 1;
87233 }
87234
87235 $lowVersion = $this->manipulateVersionString($matches, $position) . '-dev';
87236 $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
87237
87238 if ($lowVersion === '0.0.0.0-dev') {
87239 return array(new Constraint('<', $highVersion));
87240 }
87241
87242 return array(
87243 new Constraint('>=', $lowVersion),
87244 new Constraint('<', $highVersion),
87245 );
87246 }
87247
87248
87249
87250
87251
87252
87253
87254 if (preg_match('{^(?P<from>' . $versionRegex . ') +- +(?P<to>' . $versionRegex . ')($)}i', $constraint, $matches)) {
87255
87256 $lowStabilitySuffix = '';
87257 if (empty($matches[6]) && empty($matches[8]) && empty($matches[9])) {
87258 $lowStabilitySuffix = '-dev';
87259 }
87260
87261 $lowVersion = $this->normalize($matches['from']);
87262 $lowerBound = new Constraint('>=', $lowVersion . $lowStabilitySuffix);
87263
87264 $empty = function ($x) {
87265 return ($x === 0 || $x === '0') ? false : empty($x);
87266 };
87267
87268 if ((!$empty($matches[12]) && !$empty($matches[13])) || !empty($matches[15]) || !empty($matches[17]) || !empty($matches[18])) {
87269 $highVersion = $this->normalize($matches['to']);
87270 $upperBound = new Constraint('<=', $highVersion);
87271 } else {
87272 $highMatch = array('', $matches[11], $matches[12], $matches[13], $matches[14]);
87273
87274
87275 $this->normalize($matches['to']);
87276
87277 $highVersion = $this->manipulateVersionString($highMatch, $empty($matches[12]) ? 1 : 2, 1) . '-dev';
87278 $upperBound = new Constraint('<', $highVersion);
87279 }
87280
87281 return array(
87282 $lowerBound,
87283 $upperBound,
87284 );
87285 }
87286
87287
87288 if (preg_match('{^(<>|!=|>=?|<=?|==?)?\s*(.*)}', $constraint, $matches)) {
87289 try {
87290 try {
87291 $version = $this->normalize($matches[2]);
87292 } catch (\UnexpectedValueException $e) {
87293
87294
87295 if (substr($matches[2], -4) === '-dev' && preg_match('{^[0-9a-zA-Z-./]+$}', $matches[2])) {
87296 $version = $this->normalize('dev-'.substr($matches[2], 0, -4));
87297 } else {
87298 throw $e;
87299 }
87300 }
87301
87302 $op = $matches[1] ?: '=';
87303
87304 if ($op !== '==' && $op !== '=' && !empty($stabilityModifier) && self::parseStability($version) === 'stable') {
87305 $version .= '-' . $stabilityModifier;
87306 } elseif ('<' === $op || '>=' === $op) {
87307 if (!preg_match('/-' . self::$modifierRegex . '$/', strtolower($matches[2]))) {
87308 if (strpos($matches[2], 'dev-') !== 0) {
87309 $version .= '-dev';
87310 }
87311 }
87312 }
87313
87314 return array(new Constraint($matches[1] ?: '=', $version));
87315 } catch (\Exception $e) {
87316 }
87317 }
87318
87319 $message = 'Could not parse version constraint ' . $constraint;
87320 if (isset($e)) {
87321 $message .= ': ' . $e->getMessage();
87322 }
87323
87324 throw new \UnexpectedValueException($message);
87325 }
87326
87327
87328
87329
87330
87331
87332
87333
87334
87335
87336
87337
87338
87339 private function manipulateVersionString($matches, $position, $increment = 0, $pad = '0')
87340 {
87341 for ($i = 4; $i > 0; --$i) {
87342 if ($i > $position) {
87343 $matches[$i] = $pad;
87344 } elseif ($i === $position && $increment) {
87345 $matches[$i] += $increment;
87346
87347 if ($matches[$i] < 0) {
87348 $matches[$i] = $pad;
87349 --$position;
87350
87351
87352 if ($i === 1) {
87353 return null;
87354 }
87355 }
87356 }
87357 }
87358
87359 return $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.' . $matches[4];
87360 }
87361
87362
87363
87364
87365
87366
87367
87368
87369 private function expandStability($stability)
87370 {
87371 $stability = strtolower($stability);
87372
87373 switch ($stability) {
87374 case 'a':
87375 return 'alpha';
87376 case 'b':
87377 return 'beta';
87378 case 'p':
87379 case 'pl':
87380 return 'patch';
87381 case 'rc':
87382 return 'RC';
87383 default:
87384 return $stability;
87385 }
87386 }
87387 }
87388 Copyright (C) 2016 Composer
87389
87390 Permission is hereby granted, free of charge, to any person obtaining a copy of
87391 this software and associated documentation files (the "Software"), to deal in
87392 the Software without restriction, including without limitation the rights to
87393 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
87394 of the Software, and to permit persons to whom the Software is furnished to do
87395 so, subject to the following conditions:
87396
87397 The above copyright notice and this permission notice shall be included in all
87398 copies or substantial portions of the Software.
87399
87400 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
87401 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
87402 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
87403 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
87404 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
87405 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
87406 SOFTWARE.
87407 <?php
87408
87409
87410
87411
87412
87413
87414
87415
87416
87417
87418 namespace Composer\CaBundle;
87419
87420 use Psr\Log\LoggerInterface;
87421 use Symfony\Component\Process\PhpProcess;
87422
87423
87424
87425
87426
87427 class CaBundle
87428 {
87429
87430 private static $caPath;
87431
87432 private static $caFileValidity = array();
87433
87434 private static $useOpensslParse;
87435
87436
87437
87438
87439
87440
87441
87442
87443
87444
87445
87446
87447
87448
87449
87450
87451
87452
87453
87454
87455
87456
87457
87458
87459
87460
87461
87462
87463
87464
87465
87466
87467
87468
87469
87470
87471
87472
87473 public static function getSystemCaRootBundlePath(LoggerInterface $logger = null)
87474 {
87475 if (self::$caPath !== null) {
87476 return self::$caPath;
87477 }
87478 $caBundlePaths = array();
87479
87480
87481
87482 $caBundlePaths[] = self::getEnvVariable('SSL_CERT_FILE');
87483
87484
87485
87486 $caBundlePaths[] = self::getEnvVariable('SSL_CERT_DIR');
87487
87488 $caBundlePaths[] = ini_get('openssl.cafile');
87489 $caBundlePaths[] = ini_get('openssl.capath');
87490
87491 $otherLocations = array(
87492 '/etc/pki/tls/certs/ca-bundle.crt', 
87493 '/etc/ssl/certs/ca-certificates.crt', 
87494 '/etc/ssl/ca-bundle.pem', 
87495 '/usr/local/share/certs/ca-root-nss.crt', 
87496 '/usr/ssl/certs/ca-bundle.crt', 
87497 '/opt/local/share/curl/curl-ca-bundle.crt', 
87498 '/usr/local/share/curl/curl-ca-bundle.crt', 
87499 '/usr/share/ssl/certs/ca-bundle.crt', 
87500 '/etc/ssl/cert.pem', 
87501 '/usr/local/etc/ssl/cert.pem', 
87502 '/usr/local/etc/openssl/cert.pem', 
87503 '/usr/local/etc/openssl@1.1/cert.pem', 
87504 );
87505
87506 foreach($otherLocations as $location) {
87507 $otherLocations[] = dirname($location);
87508 }
87509
87510 $caBundlePaths = array_merge($caBundlePaths, $otherLocations);
87511
87512 foreach ($caBundlePaths as $caBundle) {
87513 if ($caBundle && self::caFileUsable($caBundle, $logger)) {
87514 return self::$caPath = $caBundle;
87515 }
87516
87517 if ($caBundle && self::caDirUsable($caBundle)) {
87518 return self::$caPath = $caBundle;
87519 }
87520 }
87521
87522 return self::$caPath = static::getBundledCaBundlePath(); 
87523 }
87524
87525
87526
87527
87528
87529
87530
87531
87532 public static function getBundledCaBundlePath()
87533 {
87534 $caBundleFile = __DIR__.'/../res/cacert.pem';
87535
87536
87537
87538 if (0 === strpos($caBundleFile, 'phar://')) {
87539 $tempCaBundleFile = tempnam(sys_get_temp_dir(), 'openssl-ca-bundle-');
87540 if (false === $tempCaBundleFile) {
87541 throw new \RuntimeException('Could not create a temporary file to store the bundled CA file');
87542 }
87543
87544 file_put_contents(
87545 $tempCaBundleFile,
87546 file_get_contents($caBundleFile)
87547 );
87548
87549 register_shutdown_function(function() use ($tempCaBundleFile) {
87550 @unlink($tempCaBundleFile);
87551 });
87552
87553 $caBundleFile = $tempCaBundleFile;
87554 }
87555
87556 return $caBundleFile;
87557 }
87558
87559
87560
87561
87562
87563
87564
87565
87566
87567 public static function validateCaFile($filename, LoggerInterface $logger = null)
87568 {
87569 static $warned = false;
87570
87571 if (isset(self::$caFileValidity[$filename])) {
87572 return self::$caFileValidity[$filename];
87573 }
87574
87575 $contents = file_get_contents($filename);
87576
87577
87578
87579 if (!static::isOpensslParseSafe()) {
87580 if (!$warned && $logger) {
87581 $logger->warning(sprintf(
87582 'Your version of PHP, %s, is affected by CVE-2013-6420 and cannot safely perform certificate validation, we strongly suggest you upgrade.',
87583 PHP_VERSION
87584 ));
87585 $warned = true;
87586 }
87587
87588 $isValid = !empty($contents);
87589 } elseif (is_string($contents) && strlen($contents) > 0) {
87590 $contents = preg_replace("/^(\\-+(?:BEGIN|END))\\s+TRUSTED\\s+(CERTIFICATE\\-+)\$/m", '$1 $2', $contents);
87591 if (null === $contents) {
87592
87593 $isValid = false;
87594 } else {
87595 $isValid = (bool) openssl_x509_parse($contents);
87596 }
87597 } else {
87598 $isValid = false;
87599 }
87600
87601 if ($logger) {
87602 $logger->debug('Checked CA file '.realpath($filename).': '.($isValid ? 'valid' : 'invalid'));
87603 }
87604
87605 return self::$caFileValidity[$filename] = $isValid;
87606 }
87607
87608
87609
87610
87611
87612
87613
87614
87615
87616 public static function isOpensslParseSafe()
87617 {
87618 if (null !== self::$useOpensslParse) {
87619 return self::$useOpensslParse;
87620 }
87621
87622 if (PHP_VERSION_ID >= 50600) {
87623 return self::$useOpensslParse = true;
87624 }
87625
87626
87627
87628
87629
87630 if (
87631 (PHP_VERSION_ID < 50400 && PHP_VERSION_ID >= 50328)
87632 || (PHP_VERSION_ID < 50500 && PHP_VERSION_ID >= 50423)
87633 || PHP_VERSION_ID >= 50507
87634 ) {
87635
87636 return self::$useOpensslParse = true;
87637 }
87638
87639 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
87640
87641 return self::$useOpensslParse = false;
87642 }
87643
87644 $compareDistroVersionPrefix = function ($prefix, $fixedVersion) {
87645 $regex = '{^'.preg_quote($prefix).'([0-9]+)$}';
87646
87647 if (preg_match($regex, PHP_VERSION, $m)) {
87648 return ((int) $m[1]) >= $fixedVersion;
87649 }
87650
87651 return false;
87652 };
87653
87654
87655 if (
87656 $compareDistroVersionPrefix('5.3.3-7+squeeze', 18) 
87657 || $compareDistroVersionPrefix('5.4.4-14+deb7u', 7) 
87658 || $compareDistroVersionPrefix('5.3.10-1ubuntu3.', 9) 
87659 ) {
87660 return self::$useOpensslParse = true;
87661 }
87662
87663
87664 if (!class_exists('Symfony\Component\Process\PhpProcess')) {
87665 return self::$useOpensslParse = false;
87666 }
87667
87668
87669
87670
87671
87672
87673
87674
87675
87676
87677 $cert = 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVwRENDQTR5Z0F3SUJBZ0lKQUp6dThyNnU2ZUJjTUEwR0NTcUdTSWIzRFFFQkJRVUFNSUhETVFzd0NRWUQKVlFRR0V3SkVSVEVjTUJvR0ExVUVDQXdUVG05eVpISm9aV2x1TFZkbGMzUm1ZV3hsYmpFUU1BNEdBMVVFQnd3SApTOE9Ed3Jac2JqRVVNQklHQTFVRUNnd0xVMlZyZEdsdmJrVnBibk14SHpBZEJnTlZCQXNNRmsxaGJHbGphVzkxCmN5QkRaWEowSUZObFkzUnBiMjR4SVRBZkJnTlZCQU1NR0cxaGJHbGphVzkxY3k1elpXdDBhVzl1WldsdWN5NWsKWlRFcU1DZ0dDU3FHU0liM0RRRUpBUlliYzNSbFptRnVMbVZ6YzJWeVFITmxhM1JwYjI1bGFXNXpMbVJsTUhVWQpaREU1TnpBd01UQXhNREF3TURBd1dnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBCkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEKQUFBQUFBQVhEVEUwTVRFeU9ERXhNemt6TlZvd2djTXhDekFKQmdOVkJBWVRBa1JGTVJ3d0dnWURWUVFJREJOTwpiM0prY21obGFXNHRWMlZ6ZEdaaGJHVnVNUkF3RGdZRFZRUUhEQWRMdzRQQ3RteHVNUlF3RWdZRFZRUUtEQXRUClpXdDBhVzl1UldsdWN6RWZNQjBHQTFVRUN3d1dUV0ZzYVdOcGIzVnpJRU5sY25RZ1UyVmpkR2x2YmpFaE1COEcKQTFVRUF3d1liV0ZzYVdOcGIzVnpMbk5sYTNScGIyNWxhVzV6TG1SbE1Tb3dLQVlKS29aSWh2Y05BUWtCRmh0egpkR1ZtWVc0dVpYTnpaWEpBYzJWcmRHbHZibVZwYm5NdVpHVXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCCkR3QXdnZ0VLQW9JQkFRRERBZjNobDdKWTBYY0ZuaXlFSnBTU0RxbjBPcUJyNlFQNjV1c0pQUnQvOFBhRG9xQnUKd0VZVC9OYSs2ZnNnUGpDMHVLOURaZ1dnMnRIV1dvYW5TYmxBTW96NVBINlorUzRTSFJaN2UyZERJalBqZGhqaAowbUxnMlVNTzV5cDBWNzk3R2dzOWxOdDZKUmZIODFNTjJvYlhXczROdHp0TE11RDZlZ3FwcjhkRGJyMzRhT3M4CnBrZHVpNVVhd1Raa3N5NXBMUEhxNWNNaEZHbTA2djY1Q0xvMFYyUGQ5K0tBb2tQclBjTjVLTEtlYno3bUxwazYKU01lRVhPS1A0aWRFcXh5UTdPN2ZCdUhNZWRzUWh1K3ByWTNzaTNCVXlLZlF0UDVDWm5YMmJwMHdLSHhYMTJEWAoxbmZGSXQ5RGJHdkhUY3lPdU4rblpMUEJtM3ZXeG50eUlJdlZBZ01CQUFHalFqQkFNQWtHQTFVZEV3UUNNQUF3CkVRWUpZSVpJQVliNFFnRUJCQVFEQWdlQU1Bc0dBMVVkRHdRRUF3SUZvREFUQmdOVkhTVUVEREFLQmdnckJnRUYKQlFjREFqQU5CZ2txaGtpRzl3MEJBUVVGQUFPQ0FRRUFHMGZaWVlDVGJkajFYWWMrMVNub2FQUit2SThDOENhRAo4KzBVWWhkbnlVNGdnYTBCQWNEclk5ZTk0ZUVBdTZacXljRjZGakxxWFhkQWJvcHBXb2NyNlQ2R0QxeDMzQ2tsClZBcnpHL0t4UW9oR0QySmVxa2hJTWxEb214SE83a2EzOStPYThpMnZXTFZ5alU4QVp2V01BcnVIYTRFRU55RzcKbFcyQWFnYUZLRkNyOVRuWFRmcmR4R1ZFYnY3S1ZRNmJkaGc1cDVTanBXSDErTXEwM3VSM1pYUEJZZHlWODMxOQpvMGxWajFLRkkyRENML2xpV2lzSlJvb2YrMWNSMzVDdGQwd1lCY3BCNlRac2xNY09QbDc2ZHdLd0pnZUpvMlFnClpzZm1jMnZDMS9xT2xOdU5xLzBUenprVkd2OEVUVDNDZ2FVK1VYZTRYT1Z2a2NjZWJKbjJkZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K';
87678 $script = <<<'EOT'
87679
87680 error_reporting(-1);
87681 $info = openssl_x509_parse(base64_decode('%s'));
87682 var_dump(PHP_VERSION, $info['issuer']['emailAddress'], $info['validFrom_time_t']);
87683
87684 EOT;
87685 $script = '<'."?php\n".sprintf($script, $cert);
87686
87687 try {
87688 $process = new PhpProcess($script);
87689 $process->mustRun();
87690 } catch (\Exception $e) {
87691
87692
87693 return self::$useOpensslParse = false;
87694 }
87695
87696 $output = preg_split('{\r?\n}', trim($process->getOutput()));
87697 $errorOutput = trim($process->getErrorOutput());
87698
87699 if (
87700 is_array($output)
87701 && count($output) === 3
87702 && $output[0] === sprintf('string(%d) "%s"', strlen(PHP_VERSION), PHP_VERSION)
87703 && $output[1] === 'string(27) "stefan.esser@sektioneins.de"'
87704 && $output[2] === 'int(-1)'
87705 && preg_match('{openssl_x509_parse\(\): illegal (?:ASN1 data type for|length in) timestamp in - on line \d+}', $errorOutput)
87706 ) {
87707
87708 return self::$useOpensslParse = true;
87709 }
87710
87711 return self::$useOpensslParse = false;
87712 }
87713
87714
87715
87716
87717
87718 public static function reset()
87719 {
87720 self::$caFileValidity = array();
87721 self::$caPath = null;
87722 self::$useOpensslParse = null;
87723 }
87724
87725
87726
87727
87728
87729 private static function getEnvVariable($name)
87730 {
87731 if (isset($_SERVER[$name])) {
87732 return (string) $_SERVER[$name];
87733 }
87734
87735 if (PHP_SAPI === 'cli' && ($value = getenv($name)) !== false && $value !== null) {
87736 return (string) $value;
87737 }
87738
87739 return false;
87740 }
87741
87742
87743
87744
87745
87746 private static function caFileUsable($certFile, LoggerInterface $logger = null)
87747 {
87748 return $certFile && @is_file($certFile) && @is_readable($certFile) && static::validateCaFile($certFile, $logger);
87749 }
87750
87751
87752
87753
87754
87755 private static function caDirUsable($certDir)
87756 {
87757 return $certDir && @is_dir($certDir) && @is_readable($certDir) && glob($certDir . '/*');
87758 }
87759 }
87760 MIT License
87761
87762 Copyright (c) 2017 Composer
87763
87764 Permission is hereby granted, free of charge, to any person obtaining a copy
87765 of this software and associated documentation files (the "Software"), to deal
87766 in the Software without restriction, including without limitation the rights
87767 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
87768 copies of the Software, and to permit persons to whom the Software is
87769 furnished to do so, subject to the following conditions:
87770
87771 The above copyright notice and this permission notice shall be included in all
87772 copies or substantial portions of the Software.
87773
87774 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
87775 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
87776 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
87777 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
87778 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
87779 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
87780 SOFTWARE.
87781 <?php
87782
87783
87784
87785
87786
87787
87788
87789
87790
87791
87792 namespace Composer\XdebugHandler;
87793
87794
87795
87796
87797 class PhpConfig
87798 {
87799
87800
87801
87802
87803
87804 public function useOriginal()
87805 {
87806 $this->getDataAndReset();
87807 return array();
87808 }
87809
87810
87811
87812
87813
87814
87815 public function useStandard()
87816 {
87817 if ($data = $this->getDataAndReset()) {
87818 return array('-n', '-c', $data['tmpIni']);
87819 }
87820
87821 return array();
87822 }
87823
87824
87825
87826
87827
87828
87829 public function usePersistent()
87830 {
87831 if ($data = $this->getDataAndReset()) {
87832 Process::setEnv('PHPRC', $data['tmpIni']);
87833 Process::setEnv('PHP_INI_SCAN_DIR', '');
87834 }
87835
87836 return array();
87837 }
87838
87839
87840
87841
87842
87843
87844 private function getDataAndReset()
87845 {
87846 if ($data = XdebugHandler::getRestartSettings()) {
87847 Process::setEnv('PHPRC', $data['phprc']);
87848 Process::setEnv('PHP_INI_SCAN_DIR', $data['scanDir']);
87849 }
87850
87851 return $data;
87852 }
87853 }
87854 <?php
87855
87856
87857
87858
87859
87860
87861
87862
87863
87864
87865 namespace Composer\XdebugHandler;
87866
87867
87868
87869
87870
87871
87872
87873
87874 class Process
87875 {
87876
87877
87878
87879
87880
87881
87882
87883
87884
87885
87886 public static function addColorOption(array $args, $colorOption)
87887 {
87888 if (!$colorOption
87889 || in_array($colorOption, $args)
87890 || !preg_match('/^--([a-z]+$)|(^--[a-z]+=)/', $colorOption, $matches)) {
87891 return $args;
87892 }
87893
87894 if (isset($matches[2])) {
87895
87896 if (false !== ($index = array_search($matches[2].'auto', $args))) {
87897 $args[$index] = $colorOption;
87898 return $args;
87899 } elseif (preg_grep('/^'.$matches[2].'/', $args)) {
87900 return $args;
87901 }
87902 } elseif (in_array('--no-'.$matches[1], $args)) {
87903 return $args;
87904 }
87905
87906
87907 if (false !== getenv('NO_COLOR')) {
87908 return $args;
87909 }
87910
87911 if (false !== ($index = array_search('--', $args))) {
87912
87913 array_splice($args, $index, 0, $colorOption);
87914 } else {
87915 $args[] = $colorOption;
87916 }
87917
87918 return $args;
87919 }
87920
87921
87922
87923
87924
87925
87926
87927
87928
87929
87930
87931
87932
87933 public static function escape($arg, $meta = true, $module = false)
87934 {
87935 if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
87936 return "'".str_replace("'", "'\\''", $arg)."'";
87937 }
87938
87939 $quote = strpbrk($arg, " \t") !== false || $arg === '';
87940
87941 $arg = preg_replace('/(\\\\*)"/', '$1$1\\"', $arg, -1, $dquotes);
87942
87943 if ($meta) {
87944 $meta = $dquotes || preg_match('/%[^%]+%/', $arg);
87945
87946 if (!$meta) {
87947 $quote = $quote || strpbrk($arg, '^&|<>()') !== false;
87948 } elseif ($module && !$dquotes && $quote) {
87949 $meta = false;
87950 }
87951 }
87952
87953 if ($quote) {
87954 $arg = '"'.preg_replace('/(\\\\*)$/', '$1$1', $arg).'"';
87955 }
87956
87957 if ($meta) {
87958 $arg = preg_replace('/(["^&|<>()%])/', '^$1', $arg);
87959 }
87960
87961 return $arg;
87962 }
87963
87964
87965
87966
87967
87968
87969
87970
87971
87972
87973
87974 public static function supportsColor($output)
87975 {
87976 if ('Hyper' === getenv('TERM_PROGRAM')) {
87977 return true;
87978 }
87979
87980 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
87981 return (function_exists('sapi_windows_vt100_support')
87982 && sapi_windows_vt100_support($output))
87983 || false !== getenv('ANSICON')
87984 || 'ON' === getenv('ConEmuANSI')
87985 || 'xterm' === getenv('TERM');
87986 }
87987
87988 if (function_exists('stream_isatty')) {
87989 return stream_isatty($output);
87990 }
87991
87992 if (function_exists('posix_isatty')) {
87993 return posix_isatty($output);
87994 }
87995
87996 $stat = fstat($output);
87997
87998 return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
87999 }
88000
88001
88002
88003
88004
88005
88006
88007
88008
88009 public static function setEnv($name, $value = false)
88010 {
88011 $unset = false === $value;
88012
88013 if (!putenv($unset ? $name : $name.'='.$value)) {
88014 return false;
88015 }
88016
88017 if ($unset) {
88018 unset($_SERVER[$name]);
88019 } else {
88020 $_SERVER[$name] = $value;
88021 }
88022
88023
88024 if (false !== stripos((string) ini_get('variables_order'), 'E')) {
88025 if ($unset) {
88026 unset($_ENV[$name]);
88027 } else {
88028 $_ENV[$name] = $value;
88029 }
88030 }
88031
88032 return true;
88033 }
88034 }
88035 <?php
88036
88037
88038
88039
88040
88041
88042
88043
88044
88045
88046 namespace Composer\XdebugHandler;
88047
88048 use Psr\Log\LoggerInterface;
88049 use Psr\Log\LogLevel;
88050
88051
88052
88053
88054
88055 class Status
88056 {
88057 const ENV_RESTART = 'XDEBUG_HANDLER_RESTART';
88058 const CHECK = 'Check';
88059 const ERROR = 'Error';
88060 const INFO = 'Info';
88061 const NORESTART = 'NoRestart';
88062 const RESTART = 'Restart';
88063 const RESTARTING = 'Restarting';
88064 const RESTARTED = 'Restarted';
88065
88066 private $debug;
88067 private $envAllowXdebug;
88068 private $loaded;
88069 private $logger;
88070 private $time;
88071
88072
88073
88074
88075
88076
88077
88078 public function __construct($envAllowXdebug, $debug)
88079 {
88080 $start = getenv(self::ENV_RESTART);
88081 Process::setEnv(self::ENV_RESTART);
88082 $this->time = $start ? round((microtime(true) - $start) * 1000) : 0;
88083
88084 $this->envAllowXdebug = $envAllowXdebug;
88085 $this->debug = $debug && defined('STDERR');
88086 }
88087
88088
88089
88090
88091 public function setLogger(LoggerInterface $logger)
88092 {
88093 $this->logger = $logger;
88094 }
88095
88096
88097
88098
88099
88100
88101
88102 public function report($op, $data)
88103 {
88104 if ($this->logger || $this->debug) {
88105 call_user_func(array($this, 'report'.$op), $data);
88106 }
88107 }
88108
88109
88110
88111
88112
88113
88114
88115 private function output($text, $level = null)
88116 {
88117 if ($this->logger) {
88118 $this->logger->log($level ?: LogLevel::DEBUG, $text);
88119 }
88120
88121 if ($this->debug) {
88122 fwrite(STDERR, sprintf('xdebug-handler[%d] %s', getmypid(), $text.PHP_EOL));
88123 }
88124 }
88125
88126 private function reportCheck($loaded)
88127 {
88128 $this->loaded = $loaded;
88129 $this->output('Checking '.$this->envAllowXdebug);
88130 }
88131
88132 private function reportError($error)
88133 {
88134 $this->output(sprintf('No restart (%s)', $error), LogLevel::WARNING);
88135 }
88136
88137 private function reportInfo($info)
88138 {
88139 $this->output($info);
88140 }
88141
88142 private function reportNoRestart()
88143 {
88144 $this->output($this->getLoadedMessage());
88145
88146 if ($this->loaded) {
88147 $text = sprintf('No restart (%s)', $this->getEnvAllow());
88148 if (!getenv($this->envAllowXdebug)) {
88149 $text .= ' Allowed by application';
88150 }
88151 $this->output($text);
88152 }
88153 }
88154
88155 private function reportRestart()
88156 {
88157 $this->output($this->getLoadedMessage());
88158 Process::setEnv(self::ENV_RESTART, (string) microtime(true));
88159 }
88160
88161 private function reportRestarted()
88162 {
88163 $loaded = $this->getLoadedMessage();
88164 $text = sprintf('Restarted (%d ms). %s', $this->time, $loaded);
88165 $level = $this->loaded ? LogLevel::WARNING : null;
88166 $this->output($text, $level);
88167 }
88168
88169 private function reportRestarting($command)
88170 {
88171 $text = sprintf('Process restarting (%s)', $this->getEnvAllow());
88172 $this->output($text);
88173 $text = 'Running '.$command;
88174 $this->output($text);
88175 }
88176
88177
88178
88179
88180
88181
88182 private function getEnvAllow()
88183 {
88184 return $this->envAllowXdebug.'='.getenv($this->envAllowXdebug);
88185 }
88186
88187
88188
88189
88190
88191
88192 private function getLoadedMessage()
88193 {
88194 $loaded = $this->loaded ? sprintf('loaded (%s)', $this->loaded) : 'not loaded';
88195 return 'The Xdebug extension is '.$loaded;
88196 }
88197 }
88198 <?php
88199
88200
88201
88202
88203
88204
88205
88206
88207
88208
88209 namespace Composer\XdebugHandler;
88210
88211 use Psr\Log\LoggerInterface;
88212
88213
88214
88215
88216 class XdebugHandler
88217 {
88218 const SUFFIX_ALLOW = '_ALLOW_XDEBUG';
88219 const SUFFIX_INIS = '_ORIGINAL_INIS';
88220 const RESTART_ID = 'internal';
88221 const RESTART_SETTINGS = 'XDEBUG_HANDLER_SETTINGS';
88222 const DEBUG = 'XDEBUG_HANDLER_DEBUG';
88223
88224
88225 protected $tmpIni;
88226
88227 private static $inRestart;
88228 private static $name;
88229 private static $skipped;
88230
88231 private $cli;
88232 private $colorOption;
88233 private $debug;
88234 private $envAllowXdebug;
88235 private $envOriginalInis;
88236 private $loaded;
88237 private $persistent;
88238 private $script;
88239
88240 private $statusWriter;
88241
88242
88243
88244
88245
88246
88247
88248
88249
88250
88251
88252
88253 public function __construct($envPrefix, $colorOption = '')
88254 {
88255 if (!is_string($envPrefix) || empty($envPrefix) || !is_string($colorOption)) {
88256 throw new \RuntimeException('Invalid constructor parameter');
88257 }
88258
88259 self::$name = strtoupper($envPrefix);
88260 $this->envAllowXdebug = self::$name.self::SUFFIX_ALLOW;
88261 $this->envOriginalInis = self::$name.self::SUFFIX_INIS;
88262
88263 $this->colorOption = $colorOption;
88264
88265 if (extension_loaded('xdebug')) {
88266 $ext = new \ReflectionExtension('xdebug');
88267 $this->loaded = $ext->getVersion() ?: 'unknown';
88268 }
88269
88270 if ($this->cli = PHP_SAPI === 'cli') {
88271 $this->debug = getenv(self::DEBUG);
88272 }
88273
88274 $this->statusWriter = new Status($this->envAllowXdebug, (bool) $this->debug);
88275 }
88276
88277
88278
88279
88280
88281
88282
88283
88284 public function setLogger(LoggerInterface $logger)
88285 {
88286 $this->statusWriter->setLogger($logger);
88287 return $this;
88288 }
88289
88290
88291
88292
88293
88294
88295
88296
88297 public function setMainScript($script)
88298 {
88299 $this->script = $script;
88300 return $this;
88301 }
88302
88303
88304
88305
88306
88307
88308 public function setPersistent()
88309 {
88310 $this->persistent = true;
88311 return $this;
88312 }
88313
88314
88315
88316
88317
88318
88319
88320
88321 public function check()
88322 {
88323 $this->notify(Status::CHECK, $this->loaded);
88324 $envArgs = explode('|', (string) getenv($this->envAllowXdebug));
88325
88326 if (empty($envArgs[0]) && $this->requiresRestart((bool) $this->loaded)) {
88327
88328 $this->notify(Status::RESTART);
88329
88330 if ($this->prepareRestart()) {
88331 $command = $this->getCommand();
88332 $this->restart($command);
88333 }
88334 return;
88335 }
88336
88337 if (self::RESTART_ID === $envArgs[0] && count($envArgs) === 5) {
88338
88339 $this->notify(Status::RESTARTED);
88340
88341 Process::setEnv($this->envAllowXdebug);
88342 self::$inRestart = true;
88343
88344 if (!$this->loaded) {
88345
88346 self::$skipped = $envArgs[1];
88347 }
88348
88349 $this->tryEnableSignals();
88350
88351
88352 $this->setEnvRestartSettings($envArgs);
88353 return;
88354 }
88355
88356 $this->notify(Status::NORESTART);
88357
88358 if ($settings = self::getRestartSettings()) {
88359
88360 $this->syncSettings($settings);
88361 }
88362 }
88363
88364
88365
88366
88367
88368
88369
88370
88371
88372 public static function getAllIniFiles()
88373 {
88374 if (!empty(self::$name)) {
88375 $env = getenv(self::$name.self::SUFFIX_INIS);
88376
88377 if (false !== $env) {
88378 return explode(PATH_SEPARATOR, $env);
88379 }
88380 }
88381
88382 $paths = array((string) php_ini_loaded_file());
88383
88384 if ($scanned = php_ini_scanned_files()) {
88385 $paths = array_merge($paths, array_map('trim', explode(',', $scanned)));
88386 }
88387
88388 return $paths;
88389 }
88390
88391
88392
88393
88394
88395
88396
88397
88398
88399 public static function getRestartSettings()
88400 {
88401 $envArgs = explode('|', (string) getenv(self::RESTART_SETTINGS));
88402
88403 if (count($envArgs) !== 6
88404 || (!self::$inRestart && php_ini_loaded_file() !== $envArgs[0])) {
88405 return;
88406 }
88407
88408 return array(
88409 'tmpIni' => $envArgs[0],
88410 'scannedInis' => (bool) $envArgs[1],
88411 'scanDir' => '*' === $envArgs[2] ? false : $envArgs[2],
88412 'phprc' => '*' === $envArgs[3] ? false : $envArgs[3],
88413 'inis' => explode(PATH_SEPARATOR, $envArgs[4]),
88414 'skipped' => $envArgs[5],
88415 );
88416 }
88417
88418
88419
88420
88421
88422
88423 public static function getSkippedVersion()
88424 {
88425 return (string) self::$skipped;
88426 }
88427
88428
88429
88430
88431
88432
88433
88434
88435 protected function requiresRestart($isLoaded)
88436 {
88437 return $isLoaded;
88438 }
88439
88440
88441
88442
88443
88444
88445 protected function restart($command)
88446 {
88447 $this->doRestart($command);
88448 }
88449
88450
88451
88452
88453
88454
88455 private function doRestart($command)
88456 {
88457 $this->tryEnableSignals();
88458 $this->notify(Status::RESTARTING, $command);
88459
88460
88461 if (function_exists('proc_open')) {
88462 if (defined('PHP_WINDOWS_VERSION_BUILD') && PHP_VERSION_ID < 80000) {
88463 $command = '"'.$command.'"';
88464 }
88465 $process = proc_open($command, array(), $pipes);
88466 if (is_resource($process)) {
88467 $exitCode = proc_close($process);
88468 }
88469 } else {
88470 passthru($command, $exitCode);
88471 }
88472
88473 if (!isset($exitCode)) {
88474
88475 $this->notify(Status::ERROR, 'Unable to restart process');
88476 $exitCode = -1;
88477 } else {
88478 $this->notify(Status::INFO, 'Restarted process exited '.$exitCode);
88479 }
88480
88481 if ($this->debug === '2') {
88482 $this->notify(Status::INFO, 'Temp ini saved: '.$this->tmpIni);
88483 } else {
88484 @unlink($this->tmpIni);
88485 }
88486
88487 exit($exitCode);
88488 }
88489
88490
88491
88492
88493
88494
88495
88496
88497
88498
88499
88500 private function prepareRestart()
88501 {
88502 $error = '';
88503 $iniFiles = self::getAllIniFiles();
88504 $scannedInis = count($iniFiles) > 1;
88505 $tmpDir = sys_get_temp_dir();
88506
88507 if (!$this->cli) {
88508 $error = 'Unsupported SAPI: '.PHP_SAPI;
88509 } elseif (!defined('PHP_BINARY')) {
88510 $error = 'PHP version is too old: '.PHP_VERSION;
88511 } elseif (!$this->checkConfiguration($info)) {
88512 $error = $info;
88513 } elseif (!$this->checkScanDirConfig()) {
88514 $error = 'PHP version does not report scanned inis: '.PHP_VERSION;
88515 } elseif (!$this->checkMainScript()) {
88516 $error = 'Unable to access main script: '.$this->script;
88517 } elseif (!$this->writeTmpIni($iniFiles, $tmpDir, $error)) {
88518 $error = $error ?: 'Unable to create temp ini file at: '.$tmpDir;
88519 } elseif (!$this->setEnvironment($scannedInis, $iniFiles)) {
88520 $error = 'Unable to set environment variables';
88521 }
88522
88523 if ($error) {
88524 $this->notify(Status::ERROR, $error);
88525 }
88526
88527 return empty($error);
88528 }
88529
88530
88531
88532
88533
88534
88535
88536
88537
88538
88539 private function writeTmpIni(array $iniFiles, $tmpDir, &$error)
88540 {
88541 if (!$this->tmpIni = @tempnam($tmpDir, '')) {
88542 return false;
88543 }
88544
88545
88546 if (empty($iniFiles[0])) {
88547 array_shift($iniFiles);
88548 }
88549
88550 $content = '';
88551 $regex = '/^\s*(zend_extension\s*=.*xdebug.*)$/mi';
88552
88553 foreach ($iniFiles as $file) {
88554
88555 if (($data = @file_get_contents($file)) === false) {
88556 $error = 'Unable to read ini: '.$file;
88557 return false;
88558 }
88559 $content .= preg_replace($regex, ';$1', $data).PHP_EOL;
88560 }
88561
88562
88563 if ($config = parse_ini_string($content)) {
88564 $loaded = ini_get_all(null, false);
88565 $content .= $this->mergeLoadedConfig($loaded, $config);
88566 }
88567
88568
88569 $content .= 'opcache.enable_cli=0'.PHP_EOL;
88570
88571 return @file_put_contents($this->tmpIni, $content);
88572 }
88573
88574
88575
88576
88577
88578
88579 private function getCommand()
88580 {
88581 $php = array(PHP_BINARY);
88582 $args = array_slice($_SERVER['argv'], 1);
88583
88584 if (!$this->persistent) {
88585
88586 array_push($php, '-n', '-c', $this->tmpIni);
88587 }
88588
88589 if (defined('STDOUT') && Process::supportsColor(STDOUT)) {
88590 $args = Process::addColorOption($args, $this->colorOption);
88591 }
88592
88593 $args = array_merge($php, array($this->script), $args);
88594
88595 $cmd = Process::escape(array_shift($args), true, true);
88596 foreach ($args as $arg) {
88597 $cmd .= ' '.Process::escape($arg);
88598 }
88599
88600 return $cmd;
88601 }
88602
88603
88604
88605
88606
88607
88608
88609
88610
88611
88612
88613 private function setEnvironment($scannedInis, array $iniFiles)
88614 {
88615 $scanDir = getenv('PHP_INI_SCAN_DIR');
88616 $phprc = getenv('PHPRC');
88617
88618
88619 if (!putenv($this->envOriginalInis.'='.implode(PATH_SEPARATOR, $iniFiles))) {
88620 return false;
88621 }
88622
88623 if ($this->persistent) {
88624
88625 if (!putenv('PHP_INI_SCAN_DIR=') || !putenv('PHPRC='.$this->tmpIni)) {
88626 return false;
88627 }
88628 }
88629
88630
88631 $envArgs = array(
88632 self::RESTART_ID,
88633 $this->loaded,
88634 (int) $scannedInis,
88635 false === $scanDir ? '*' : $scanDir,
88636 false === $phprc ? '*' : $phprc,
88637 );
88638
88639 return putenv($this->envAllowXdebug.'='.implode('|', $envArgs));
88640 }
88641
88642
88643
88644
88645
88646
88647
88648 private function notify($op, $data = null)
88649 {
88650 $this->statusWriter->report($op, $data);
88651 }
88652
88653
88654
88655
88656
88657
88658
88659
88660
88661 private function mergeLoadedConfig(array $loadedConfig, array $iniConfig)
88662 {
88663 $content = '';
88664
88665 foreach ($loadedConfig as $name => $value) {
88666
88667 if (!is_string($value)
88668 || strpos($name, 'xdebug') === 0
88669 || $name === 'apc.mmap_file_mask') {
88670 continue;
88671 }
88672
88673 if (!isset($iniConfig[$name]) || $iniConfig[$name] !== $value) {
88674
88675 $content .= $name.'="'.addcslashes($value, '\\"').'"'.PHP_EOL;
88676 }
88677 }
88678
88679 return $content;
88680 }
88681
88682
88683
88684
88685
88686
88687 private function checkMainScript()
88688 {
88689 if (null !== $this->script) {
88690
88691 return file_exists($this->script) || '--' === $this->script;
88692 }
88693
88694 if (file_exists($this->script = $_SERVER['argv'][0])) {
88695 return true;
88696 }
88697
88698
88699 $options = PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : false;
88700 $trace = debug_backtrace($options);
88701
88702 if (($main = end($trace)) && isset($main['file'])) {
88703 return file_exists($this->script = $main['file']);
88704 }
88705
88706 return false;
88707 }
88708
88709
88710
88711
88712
88713
88714 private function setEnvRestartSettings($envArgs)
88715 {
88716 $settings = array(
88717 php_ini_loaded_file(),
88718 $envArgs[2],
88719 $envArgs[3],
88720 $envArgs[4],
88721 getenv($this->envOriginalInis),
88722 self::$skipped,
88723 );
88724
88725 Process::setEnv(self::RESTART_SETTINGS, implode('|', $settings));
88726 }
88727
88728
88729
88730
88731
88732
88733 private function syncSettings(array $settings)
88734 {
88735 if (false === getenv($this->envOriginalInis)) {
88736
88737 Process::setEnv($this->envOriginalInis, implode(PATH_SEPARATOR, $settings['inis']));
88738 }
88739
88740 self::$skipped = $settings['skipped'];
88741 $this->notify(Status::INFO, 'Process called with existing restart settings');
88742 }
88743
88744
88745
88746
88747
88748
88749
88750
88751
88752 private function checkScanDirConfig()
88753 {
88754 return !(getenv('PHP_INI_SCAN_DIR')
88755 && !PHP_CONFIG_FILE_SCAN_DIR
88756 && (PHP_VERSION_ID < 70113
88757 || PHP_VERSION_ID === 70200));
88758 }
88759
88760
88761
88762
88763
88764
88765 private function checkConfiguration(&$info)
88766 {
88767 if (false !== strpos(ini_get('disable_functions'), 'passthru')) {
88768 $info = 'passthru function is disabled';
88769 return false;
88770 }
88771
88772 if (extension_loaded('uopz') && !ini_get('uopz.disable')) {
88773
88774 if (function_exists('uopz_allow_exit')) {
88775 @uopz_allow_exit(true);
88776 } else {
88777 $info = 'uopz extension is not compatible';
88778 return false;
88779 }
88780 }
88781
88782 return true;
88783 }
88784
88785
88786
88787
88788
88789
88790
88791 private function tryEnableSignals()
88792 {
88793 if (!function_exists('pcntl_async_signals') || !function_exists('pcntl_signal')) {
88794 return;
88795 }
88796
88797 pcntl_async_signals(true);
88798 $message = 'Async signals enabled';
88799
88800 if (!self::$inRestart) {
88801
88802 pcntl_signal(SIGINT, SIG_IGN);
88803 $message .= ' (SIGINT = SIG_IGN)';
88804 } elseif (is_int(pcntl_signal_get_handler(SIGINT))) {
88805
88806 pcntl_signal(SIGINT, SIG_DFL);
88807 $message .= ' (SIGINT = SIG_DFL)';
88808 }
88809
88810 $this->notify(Status::INFO, $message);
88811 }
88812 }
88813 Copyright (c) 2012 PHP Framework Interoperability Group
88814
88815 Permission is hereby granted, free of charge, to any person obtaining a copy 
88816 of this software and associated documentation files (the "Software"), to deal
88817 in the Software without restriction, including without limitation the rights 
88818 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
88819 copies of the Software, and to permit persons to whom the Software is 
88820 furnished to do so, subject to the following conditions:
88821
88822 The above copyright notice and this permission notice shall be included in 
88823 all copies or substantial portions of the Software.
88824
88825 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
88826 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
88827 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
88828 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
88829 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
88830 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
88831 THE SOFTWARE.
88832 <?php
88833
88834 namespace Psr\Log;
88835
88836
88837
88838
88839
88840
88841
88842
88843 abstract class AbstractLogger implements LoggerInterface
88844 {
88845
88846
88847
88848
88849
88850
88851
88852
88853 public function emergency($message, array $context = array())
88854 {
88855 $this->log(LogLevel::EMERGENCY, $message, $context);
88856 }
88857
88858
88859
88860
88861
88862
88863
88864
88865
88866
88867
88868
88869 public function alert($message, array $context = array())
88870 {
88871 $this->log(LogLevel::ALERT, $message, $context);
88872 }
88873
88874
88875
88876
88877
88878
88879
88880
88881
88882
88883
88884 public function critical($message, array $context = array())
88885 {
88886 $this->log(LogLevel::CRITICAL, $message, $context);
88887 }
88888
88889
88890
88891
88892
88893
88894
88895
88896
88897
88898 public function error($message, array $context = array())
88899 {
88900 $this->log(LogLevel::ERROR, $message, $context);
88901 }
88902
88903
88904
88905
88906
88907
88908
88909
88910
88911
88912
88913
88914 public function warning($message, array $context = array())
88915 {
88916 $this->log(LogLevel::WARNING, $message, $context);
88917 }
88918
88919
88920
88921
88922
88923
88924
88925
88926
88927 public function notice($message, array $context = array())
88928 {
88929 $this->log(LogLevel::NOTICE, $message, $context);
88930 }
88931
88932
88933
88934
88935
88936
88937
88938
88939
88940
88941
88942 public function info($message, array $context = array())
88943 {
88944 $this->log(LogLevel::INFO, $message, $context);
88945 }
88946
88947
88948
88949
88950
88951
88952
88953
88954
88955 public function debug($message, array $context = array())
88956 {
88957 $this->log(LogLevel::DEBUG, $message, $context);
88958 }
88959 }
88960 <?php
88961
88962 namespace Psr\Log;
88963
88964 class InvalidArgumentException extends \InvalidArgumentException
88965 {
88966 }
88967 <?php
88968
88969 namespace Psr\Log;
88970
88971
88972
88973
88974 class LogLevel
88975 {
88976 const EMERGENCY = 'emergency';
88977 const ALERT = 'alert';
88978 const CRITICAL = 'critical';
88979 const ERROR = 'error';
88980 const WARNING = 'warning';
88981 const NOTICE = 'notice';
88982 const INFO = 'info';
88983 const DEBUG = 'debug';
88984 }
88985 <?php
88986
88987 namespace Psr\Log;
88988
88989
88990
88991
88992 interface LoggerAwareInterface
88993 {
88994
88995
88996
88997
88998
88999
89000
89001 public function setLogger(LoggerInterface $logger);
89002 }
89003 <?php
89004
89005 namespace Psr\Log;
89006
89007
89008
89009
89010 trait LoggerAwareTrait
89011 {
89012
89013
89014
89015
89016
89017 protected $logger;
89018
89019
89020
89021
89022
89023
89024 public function setLogger(LoggerInterface $logger)
89025 {
89026 $this->logger = $logger;
89027 }
89028 }
89029 <?php
89030
89031 namespace Psr\Log;
89032
89033
89034
89035
89036
89037
89038
89039
89040
89041
89042
89043
89044
89045
89046
89047
89048 interface LoggerInterface
89049 {
89050
89051
89052
89053
89054
89055
89056
89057
89058 public function emergency($message, array $context = array());
89059
89060
89061
89062
89063
89064
89065
89066
89067
89068
89069
89070
89071 public function alert($message, array $context = array());
89072
89073
89074
89075
89076
89077
89078
89079
89080
89081
89082
89083 public function critical($message, array $context = array());
89084
89085
89086
89087
89088
89089
89090
89091
89092
89093
89094 public function error($message, array $context = array());
89095
89096
89097
89098
89099
89100
89101
89102
89103
89104
89105
89106
89107 public function warning($message, array $context = array());
89108
89109
89110
89111
89112
89113
89114
89115
89116
89117 public function notice($message, array $context = array());
89118
89119
89120
89121
89122
89123
89124
89125
89126
89127
89128
89129 public function info($message, array $context = array());
89130
89131
89132
89133
89134
89135
89136
89137
89138
89139 public function debug($message, array $context = array());
89140
89141
89142
89143
89144
89145
89146
89147
89148
89149
89150
89151
89152 public function log($level, $message, array $context = array());
89153 }
89154 <?php
89155
89156 namespace Psr\Log;
89157
89158
89159
89160
89161
89162
89163
89164
89165
89166 trait LoggerTrait
89167 {
89168
89169
89170
89171
89172
89173
89174
89175
89176 public function emergency($message, array $context = array())
89177 {
89178 $this->log(LogLevel::EMERGENCY, $message, $context);
89179 }
89180
89181
89182
89183
89184
89185
89186
89187
89188
89189
89190
89191
89192 public function alert($message, array $context = array())
89193 {
89194 $this->log(LogLevel::ALERT, $message, $context);
89195 }
89196
89197
89198
89199
89200
89201
89202
89203
89204
89205
89206
89207 public function critical($message, array $context = array())
89208 {
89209 $this->log(LogLevel::CRITICAL, $message, $context);
89210 }
89211
89212
89213
89214
89215
89216
89217
89218
89219
89220
89221 public function error($message, array $context = array())
89222 {
89223 $this->log(LogLevel::ERROR, $message, $context);
89224 }
89225
89226
89227
89228
89229
89230
89231
89232
89233
89234
89235
89236
89237 public function warning($message, array $context = array())
89238 {
89239 $this->log(LogLevel::WARNING, $message, $context);
89240 }
89241
89242
89243
89244
89245
89246
89247
89248
89249
89250 public function notice($message, array $context = array())
89251 {
89252 $this->log(LogLevel::NOTICE, $message, $context);
89253 }
89254
89255
89256
89257
89258
89259
89260
89261
89262
89263
89264
89265 public function info($message, array $context = array())
89266 {
89267 $this->log(LogLevel::INFO, $message, $context);
89268 }
89269
89270
89271
89272
89273
89274
89275
89276
89277
89278 public function debug($message, array $context = array())
89279 {
89280 $this->log(LogLevel::DEBUG, $message, $context);
89281 }
89282
89283
89284
89285
89286
89287
89288
89289
89290
89291
89292
89293
89294 abstract public function log($level, $message, array $context = array());
89295 }
89296 <?php
89297
89298 namespace Psr\Log;
89299
89300
89301
89302
89303
89304
89305
89306
89307
89308 class NullLogger extends AbstractLogger
89309 {
89310
89311
89312
89313
89314
89315
89316
89317
89318
89319
89320
89321 public function log($level, $message, array $context = array())
89322 {
89323
89324 }
89325 }
89326 <?php
89327
89328 namespace Psr\Log\Test;
89329
89330
89331
89332
89333
89334
89335
89336
89337 class DummyTest
89338 {
89339 public function __toString()
89340 {
89341 return 'DummyTest';
89342 }
89343 }
89344 <?php
89345
89346 namespace Psr\Log\Test;
89347
89348 use Psr\Log\LoggerInterface;
89349 use Psr\Log\LogLevel;
89350 use PHPUnit\Framework\TestCase;
89351
89352
89353
89354
89355
89356
89357
89358 abstract class LoggerInterfaceTest extends TestCase
89359 {
89360
89361
89362
89363 abstract public function getLogger();
89364
89365
89366
89367
89368
89369
89370
89371
89372
89373
89374 abstract public function getLogs();
89375
89376 public function testImplements()
89377 {
89378 $this->assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger());
89379 }
89380
89381
89382
89383
89384 public function testLogsAtAllLevels($level, $message)
89385 {
89386 $logger = $this->getLogger();
89387 $logger->{$level}($message, array('user' => 'Bob'));
89388 $logger->log($level, $message, array('user' => 'Bob'));
89389
89390 $expected = array(
89391 $level.' message of level '.$level.' with context: Bob',
89392 $level.' message of level '.$level.' with context: Bob',
89393 );
89394 $this->assertEquals($expected, $this->getLogs());
89395 }
89396
89397 public function provideLevelsAndMessages()
89398 {
89399 return array(
89400 LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'),
89401 LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'),
89402 LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'),
89403 LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'),
89404 LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'),
89405 LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'),
89406 LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'),
89407 LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}'),
89408 );
89409 }
89410
89411
89412
89413
89414 public function testThrowsOnInvalidLevel()
89415 {
89416 $logger = $this->getLogger();
89417 $logger->log('invalid level', 'Foo');
89418 }
89419
89420 public function testContextReplacement()
89421 {
89422 $logger = $this->getLogger();
89423 $logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar'));
89424
89425 $expected = array('info {Message {nothing} Bob Bar a}');
89426 $this->assertEquals($expected, $this->getLogs());
89427 }
89428
89429 public function testObjectCastToString()
89430 {
89431 if (method_exists($this, 'createPartialMock')) {
89432 $dummy = $this->createPartialMock('Psr\Log\Test\DummyTest', array('__toString'));
89433 } else {
89434 $dummy = $this->getMock('Psr\Log\Test\DummyTest', array('__toString'));
89435 }
89436 $dummy->expects($this->once())
89437 ->method('__toString')
89438 ->will($this->returnValue('DUMMY'));
89439
89440 $this->getLogger()->warning($dummy);
89441
89442 $expected = array('warning DUMMY');
89443 $this->assertEquals($expected, $this->getLogs());
89444 }
89445
89446 public function testContextCanContainAnything()
89447 {
89448 $closed = fopen('php://memory', 'r');
89449 fclose($closed);
89450
89451 $context = array(
89452 'bool' => true,
89453 'null' => null,
89454 'string' => 'Foo',
89455 'int' => 0,
89456 'float' => 0.5,
89457 'nested' => array('with object' => new DummyTest),
89458 'object' => new \DateTime,
89459 'resource' => fopen('php://memory', 'r'),
89460 'closed' => $closed,
89461 );
89462
89463 $this->getLogger()->warning('Crazy context data', $context);
89464
89465 $expected = array('warning Crazy context data');
89466 $this->assertEquals($expected, $this->getLogs());
89467 }
89468
89469 public function testContextExceptionKeyCanBeExceptionOrOtherValues()
89470 {
89471 $logger = $this->getLogger();
89472 $logger->warning('Random message', array('exception' => 'oops'));
89473 $logger->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail')));
89474
89475 $expected = array(
89476 'warning Random message',
89477 'critical Uncaught Exception!'
89478 );
89479 $this->assertEquals($expected, $this->getLogs());
89480 }
89481 }
89482 <?php
89483
89484 namespace Psr\Log\Test;
89485
89486 use Psr\Log\AbstractLogger;
89487
89488
89489
89490
89491
89492
89493
89494
89495
89496
89497
89498
89499
89500
89501
89502
89503
89504
89505
89506
89507
89508
89509
89510
89511
89512
89513
89514
89515
89516
89517
89518
89519
89520
89521
89522
89523
89524
89525
89526
89527
89528
89529
89530
89531
89532
89533
89534
89535
89536
89537
89538 class TestLogger extends AbstractLogger
89539 {
89540
89541
89542
89543 public $records = [];
89544
89545 public $recordsByLevel = [];
89546
89547
89548
89549
89550 public function log($level, $message, array $context = [])
89551 {
89552 $record = [
89553 'level' => $level,
89554 'message' => $message,
89555 'context' => $context,
89556 ];
89557
89558 $this->recordsByLevel[$record['level']][] = $record;
89559 $this->records[] = $record;
89560 }
89561
89562 public function hasRecords($level)
89563 {
89564 return isset($this->recordsByLevel[$level]);
89565 }
89566
89567 public function hasRecord($record, $level)
89568 {
89569 if (is_string($record)) {
89570 $record = ['message' => $record];
89571 }
89572 return $this->hasRecordThatPasses(function ($rec) use ($record) {
89573 if ($rec['message'] !== $record['message']) {
89574 return false;
89575 }
89576 if (isset($record['context']) && $rec['context'] !== $record['context']) {
89577 return false;
89578 }
89579 return true;
89580 }, $level);
89581 }
89582
89583 public function hasRecordThatContains($message, $level)
89584 {
89585 return $this->hasRecordThatPasses(function ($rec) use ($message) {
89586 return strpos($rec['message'], $message) !== false;
89587 }, $level);
89588 }
89589
89590 public function hasRecordThatMatches($regex, $level)
89591 {
89592 return $this->hasRecordThatPasses(function ($rec) use ($regex) {
89593 return preg_match($regex, $rec['message']) > 0;
89594 }, $level);
89595 }
89596
89597 public function hasRecordThatPasses(callable $predicate, $level)
89598 {
89599 if (!isset($this->recordsByLevel[$level])) {
89600 return false;
89601 }
89602 foreach ($this->recordsByLevel[$level] as $i => $rec) {
89603 if (call_user_func($predicate, $rec, $i)) {
89604 return true;
89605 }
89606 }
89607 return false;
89608 }
89609
89610 public function __call($method, $args)
89611 {
89612 if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) {
89613 $genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3];
89614 $level = strtolower($matches[2]);
89615 if (method_exists($this, $genericMethod)) {
89616 $args[] = $level;
89617 return call_user_func_array([$this, $genericMethod], $args);
89618 }
89619 }
89620 throw new \BadMethodCallException('Call to undefined method ' . get_class($this) . '::' . $method . '()');
89621 }
89622
89623 public function reset()
89624 {
89625 $this->records = [];
89626 $this->recordsByLevel = [];
89627 }
89628 }
89629 <?php
89630
89631
89632
89633 require_once __DIR__ . '/composer/autoload_real.php';
89634
89635 return ComposerAutoloaderInitComposerPhar1611758466::getLoader();
89636 <?php
89637
89638
89639
89640 $vendorDir = dirname(dirname(__FILE__));
89641 $baseDir = dirname($vendorDir);
89642
89643 return array(
89644 );
89645 <?php
89646
89647
89648
89649 $vendorDir = dirname(dirname(__FILE__));
89650 $baseDir = dirname($vendorDir);
89651
89652 return array(
89653 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
89654 'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
89655 'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'),
89656 'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
89657 'Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'),
89658 'Symfony\\Component\\Debug\\' => array($vendorDir . '/symfony/debug'),
89659 'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'),
89660 'Seld\\PharUtils\\' => array($vendorDir . '/seld/phar-utils/src'),
89661 'Seld\\JsonLint\\' => array($vendorDir . '/seld/jsonlint/src/Seld/JsonLint'),
89662 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
89663 'JsonSchema\\' => array($vendorDir . '/justinrainbow/json-schema/src/JsonSchema'),
89664 'Composer\\XdebugHandler\\' => array($vendorDir . '/composer/xdebug-handler/src'),
89665 'Composer\\Spdx\\' => array($vendorDir . '/composer/spdx-licenses/src'),
89666 'Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'),
89667 'Composer\\CaBundle\\' => array($vendorDir . '/composer/ca-bundle/src'),
89668 'Composer\\' => array($baseDir . '/src/Composer'),
89669 );
89670 <?php
89671
89672
89673
89674 $vendorDir = dirname(dirname(__FILE__));
89675 $baseDir = dirname($vendorDir);
89676
89677 return array(
89678 );
89679 <?php
89680
89681
89682
89683 $vendorDir = dirname(dirname(__FILE__));
89684 $baseDir = dirname($vendorDir);
89685
89686 return array(
89687 '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
89688 '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
89689 );
89690 <?php
89691
89692
89693
89694 class ComposerAutoloaderInitComposerPhar1611758466
89695 {
89696 private static $loader;
89697
89698 public static function loadClassLoader($class)
89699 {
89700 if ('Composer\Autoload\ClassLoader' === $class) {
89701 require __DIR__ . '/ClassLoader.php';
89702 }
89703 }
89704
89705
89706
89707
89708 public static function getLoader()
89709 {
89710 if (null !== self::$loader) {
89711 return self::$loader;
89712 }
89713
89714 spl_autoload_register(array('ComposerAutoloaderInitComposerPhar1611758466', 'loadClassLoader'), true, true);
89715 self::$loader = $loader = new \Composer\Autoload\ClassLoader();
89716 spl_autoload_unregister(array('ComposerAutoloaderInitComposerPhar1611758466', 'loadClassLoader'));
89717
89718 $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
89719 if ($useStaticLoader) {
89720 require_once __DIR__ . '/autoload_static.php';
89721
89722 call_user_func(\Composer\Autoload\ComposerStaticInitComposerPhar1611758466::getInitializer($loader));
89723 } else {
89724 $map = require __DIR__ . '/autoload_namespaces.php';
89725 foreach ($map as $namespace => $path) {
89726 $loader->set($namespace, $path);
89727 }
89728
89729 $map = require __DIR__ . '/autoload_psr4.php';
89730 foreach ($map as $namespace => $path) {
89731 $loader->setPsr4($namespace, $path);
89732 }
89733
89734 $classMap = require __DIR__ . '/autoload_classmap.php';
89735 if ($classMap) {
89736 $loader->addClassMap($classMap);
89737 }
89738 }
89739
89740 $loader->register(true);
89741
89742 if ($useStaticLoader) {
89743 $includeFiles = Composer\Autoload\ComposerStaticInitComposerPhar1611758466::$files;
89744 } else {
89745 $includeFiles = require __DIR__ . '/autoload_files.php';
89746 }
89747 foreach ($includeFiles as $fileIdentifier => $file) {
89748 composerRequireComposerPhar1611758466($fileIdentifier, $file);
89749 }
89750
89751 return $loader;
89752 }
89753 }
89754
89755 function composerRequireComposerPhar1611758466($fileIdentifier, $file)
89756 {
89757 if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
89758 require $file;
89759
89760 $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
89761 }
89762 }
89763 <?php
89764
89765
89766
89767 namespace Composer\Autoload;
89768
89769 class ComposerStaticInitComposerPhar1611758466
89770 {
89771 public static $files = array (
89772 '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
89773 '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
89774 );
89775
89776 public static $prefixLengthsPsr4 = array (
89777 'S' => 
89778 array (
89779 'Symfony\\Polyfill\\Mbstring\\' => 26,
89780 'Symfony\\Polyfill\\Ctype\\' => 23,
89781 'Symfony\\Component\\Process\\' => 26,
89782 'Symfony\\Component\\Finder\\' => 25,
89783 'Symfony\\Component\\Filesystem\\' => 29,
89784 'Symfony\\Component\\Debug\\' => 24,
89785 'Symfony\\Component\\Console\\' => 26,
89786 'Seld\\PharUtils\\' => 15,
89787 'Seld\\JsonLint\\' => 14,
89788 ),
89789 'P' => 
89790 array (
89791 'Psr\\Log\\' => 8,
89792 ),
89793 'J' => 
89794 array (
89795 'JsonSchema\\' => 11,
89796 ),
89797 'C' => 
89798 array (
89799 'Composer\\XdebugHandler\\' => 23,
89800 'Composer\\Spdx\\' => 14,
89801 'Composer\\Semver\\' => 16,
89802 'Composer\\CaBundle\\' => 18,
89803 'Composer\\' => 9,
89804 ),
89805 );
89806
89807 public static $prefixDirsPsr4 = array (
89808 'Symfony\\Polyfill\\Mbstring\\' => 
89809 array (
89810 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
89811 ),
89812 'Symfony\\Polyfill\\Ctype\\' => 
89813 array (
89814 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
89815 ),
89816 'Symfony\\Component\\Process\\' => 
89817 array (
89818 0 => __DIR__ . '/..' . '/symfony/process',
89819 ),
89820 'Symfony\\Component\\Finder\\' => 
89821 array (
89822 0 => __DIR__ . '/..' . '/symfony/finder',
89823 ),
89824 'Symfony\\Component\\Filesystem\\' => 
89825 array (
89826 0 => __DIR__ . '/..' . '/symfony/filesystem',
89827 ),
89828 'Symfony\\Component\\Debug\\' => 
89829 array (
89830 0 => __DIR__ . '/..' . '/symfony/debug',
89831 ),
89832 'Symfony\\Component\\Console\\' => 
89833 array (
89834 0 => __DIR__ . '/..' . '/symfony/console',
89835 ),
89836 'Seld\\PharUtils\\' => 
89837 array (
89838 0 => __DIR__ . '/..' . '/seld/phar-utils/src',
89839 ),
89840 'Seld\\JsonLint\\' => 
89841 array (
89842 0 => __DIR__ . '/..' . '/seld/jsonlint/src/Seld/JsonLint',
89843 ),
89844 'Psr\\Log\\' => 
89845 array (
89846 0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
89847 ),
89848 'JsonSchema\\' => 
89849 array (
89850 0 => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema',
89851 ),
89852 'Composer\\XdebugHandler\\' => 
89853 array (
89854 0 => __DIR__ . '/..' . '/composer/xdebug-handler/src',
89855 ),
89856 'Composer\\Spdx\\' => 
89857 array (
89858 0 => __DIR__ . '/..' . '/composer/spdx-licenses/src',
89859 ),
89860 'Composer\\Semver\\' => 
89861 array (
89862 0 => __DIR__ . '/..' . '/composer/semver/src',
89863 ),
89864 'Composer\\CaBundle\\' => 
89865 array (
89866 0 => __DIR__ . '/..' . '/composer/ca-bundle/src',
89867 ),
89868 'Composer\\' => 
89869 array (
89870 0 => __DIR__ . '/../..' . '/src/Composer',
89871 ),
89872 );
89873
89874 public static function getInitializer(ClassLoader $loader)
89875 {
89876 return \Closure::bind(function () use ($loader) {
89877 $loader->prefixLengthsPsr4 = ComposerStaticInitComposerPhar1611758466::$prefixLengthsPsr4;
89878 $loader->prefixDirsPsr4 = ComposerStaticInitComposerPhar1611758466::$prefixDirsPsr4;
89879
89880 }, null, ClassLoader::class);
89881 }
89882 }
89883 <?php
89884
89885
89886
89887
89888
89889
89890
89891
89892
89893
89894
89895 namespace Composer\Autoload;
89896
89897
89898
89899
89900
89901
89902
89903
89904
89905
89906
89907
89908
89909
89910
89911
89912
89913
89914
89915
89916
89917
89918
89919
89920
89921
89922
89923
89924
89925 class ClassLoader
89926 {
89927
89928 private $prefixLengthsPsr4 = array();
89929 private $prefixDirsPsr4 = array();
89930 private $fallbackDirsPsr4 = array();
89931
89932
89933 private $prefixesPsr0 = array();
89934 private $fallbackDirsPsr0 = array();
89935
89936 private $useIncludePath = false;
89937 private $classMap = array();
89938 private $classMapAuthoritative = false;
89939 private $missingClasses = array();
89940 private $apcuPrefix;
89941
89942 public function getPrefixes()
89943 {
89944 if (!empty($this->prefixesPsr0)) {
89945 return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
89946 }
89947
89948 return array();
89949 }
89950
89951 public function getPrefixesPsr4()
89952 {
89953 return $this->prefixDirsPsr4;
89954 }
89955
89956 public function getFallbackDirs()
89957 {
89958 return $this->fallbackDirsPsr0;
89959 }
89960
89961 public function getFallbackDirsPsr4()
89962 {
89963 return $this->fallbackDirsPsr4;
89964 }
89965
89966 public function getClassMap()
89967 {
89968 return $this->classMap;
89969 }
89970
89971
89972
89973
89974 public function addClassMap(array $classMap)
89975 {
89976 if ($this->classMap) {
89977 $this->classMap = array_merge($this->classMap, $classMap);
89978 } else {
89979 $this->classMap = $classMap;
89980 }
89981 }
89982
89983
89984
89985
89986
89987
89988
89989
89990
89991 public function add($prefix, $paths, $prepend = false)
89992 {
89993 if (!$prefix) {
89994 if ($prepend) {
89995 $this->fallbackDirsPsr0 = array_merge(
89996 (array) $paths,
89997 $this->fallbackDirsPsr0
89998 );
89999 } else {
90000 $this->fallbackDirsPsr0 = array_merge(
90001 $this->fallbackDirsPsr0,
90002 (array) $paths
90003 );
90004 }
90005
90006 return;
90007 }
90008
90009 $first = $prefix[0];
90010 if (!isset($this->prefixesPsr0[$first][$prefix])) {
90011 $this->prefixesPsr0[$first][$prefix] = (array) $paths;
90012
90013 return;
90014 }
90015 if ($prepend) {
90016 $this->prefixesPsr0[$first][$prefix] = array_merge(
90017 (array) $paths,
90018 $this->prefixesPsr0[$first][$prefix]
90019 );
90020 } else {
90021 $this->prefixesPsr0[$first][$prefix] = array_merge(
90022 $this->prefixesPsr0[$first][$prefix],
90023 (array) $paths
90024 );
90025 }
90026 }
90027
90028
90029
90030
90031
90032
90033
90034
90035
90036
90037
90038 public function addPsr4($prefix, $paths, $prepend = false)
90039 {
90040 if (!$prefix) {
90041
90042 if ($prepend) {
90043 $this->fallbackDirsPsr4 = array_merge(
90044 (array) $paths,
90045 $this->fallbackDirsPsr4
90046 );
90047 } else {
90048 $this->fallbackDirsPsr4 = array_merge(
90049 $this->fallbackDirsPsr4,
90050 (array) $paths
90051 );
90052 }
90053 } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
90054
90055 $length = strlen($prefix);
90056 if ('\\' !== $prefix[$length - 1]) {
90057 throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
90058 }
90059 $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
90060 $this->prefixDirsPsr4[$prefix] = (array) $paths;
90061 } elseif ($prepend) {
90062
90063 $this->prefixDirsPsr4[$prefix] = array_merge(
90064 (array) $paths,
90065 $this->prefixDirsPsr4[$prefix]
90066 );
90067 } else {
90068
90069 $this->prefixDirsPsr4[$prefix] = array_merge(
90070 $this->prefixDirsPsr4[$prefix],
90071 (array) $paths
90072 );
90073 }
90074 }
90075
90076
90077
90078
90079
90080
90081
90082
90083 public function set($prefix, $paths)
90084 {
90085 if (!$prefix) {
90086 $this->fallbackDirsPsr0 = (array) $paths;
90087 } else {
90088 $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
90089 }
90090 }
90091
90092
90093
90094
90095
90096
90097
90098
90099
90100
90101 public function setPsr4($prefix, $paths)
90102 {
90103 if (!$prefix) {
90104 $this->fallbackDirsPsr4 = (array) $paths;
90105 } else {
90106 $length = strlen($prefix);
90107 if ('\\' !== $prefix[$length - 1]) {
90108 throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
90109 }
90110 $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
90111 $this->prefixDirsPsr4[$prefix] = (array) $paths;
90112 }
90113 }
90114
90115
90116
90117
90118
90119
90120 public function setUseIncludePath($useIncludePath)
90121 {
90122 $this->useIncludePath = $useIncludePath;
90123 }
90124
90125
90126
90127
90128
90129
90130
90131 public function getUseIncludePath()
90132 {
90133 return $this->useIncludePath;
90134 }
90135
90136
90137
90138
90139
90140
90141
90142 public function setClassMapAuthoritative($classMapAuthoritative)
90143 {
90144 $this->classMapAuthoritative = $classMapAuthoritative;
90145 }
90146
90147
90148
90149
90150
90151
90152 public function isClassMapAuthoritative()
90153 {
90154 return $this->classMapAuthoritative;
90155 }
90156
90157
90158
90159
90160
90161
90162 public function setApcuPrefix($apcuPrefix)
90163 {
90164 $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
90165 }
90166
90167
90168
90169
90170
90171
90172 public function getApcuPrefix()
90173 {
90174 return $this->apcuPrefix;
90175 }
90176
90177
90178
90179
90180
90181
90182 public function register($prepend = false)
90183 {
90184 spl_autoload_register(array($this, 'loadClass'), true, $prepend);
90185 }
90186
90187
90188
90189
90190 public function unregister()
90191 {
90192 spl_autoload_unregister(array($this, 'loadClass'));
90193 }
90194
90195
90196
90197
90198
90199
90200
90201 public function loadClass($class)
90202 {
90203 if ($file = $this->findFile($class)) {
90204 includeFile($file);
90205
90206 return true;
90207 }
90208 }
90209
90210
90211
90212
90213
90214
90215
90216
90217 public function findFile($class)
90218 {
90219
90220 if (isset($this->classMap[$class])) {
90221 return $this->classMap[$class];
90222 }
90223 if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
90224 return false;
90225 }
90226 if (null !== $this->apcuPrefix) {
90227 $file = apcu_fetch($this->apcuPrefix.$class, $hit);
90228 if ($hit) {
90229 return $file;
90230 }
90231 }
90232
90233 $file = $this->findFileWithExtension($class, '.php');
90234
90235
90236 if (false === $file && defined('HHVM_VERSION')) {
90237 $file = $this->findFileWithExtension($class, '.hh');
90238 }
90239
90240 if (null !== $this->apcuPrefix) {
90241 apcu_add($this->apcuPrefix.$class, $file);
90242 }
90243
90244 if (false === $file) {
90245
90246 $this->missingClasses[$class] = true;
90247 }
90248
90249 return $file;
90250 }
90251
90252 private function findFileWithExtension($class, $ext)
90253 {
90254
90255 $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
90256
90257 $first = $class[0];
90258 if (isset($this->prefixLengthsPsr4[$first])) {
90259 $subPath = $class;
90260 while (false !== $lastPos = strrpos($subPath, '\\')) {
90261 $subPath = substr($subPath, 0, $lastPos);
90262 $search = $subPath . '\\';
90263 if (isset($this->prefixDirsPsr4[$search])) {
90264 $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
90265 foreach ($this->prefixDirsPsr4[$search] as $dir) {
90266 if (file_exists($file = $dir . $pathEnd)) {
90267 return $file;
90268 }
90269 }
90270 }
90271 }
90272 }
90273
90274
90275 foreach ($this->fallbackDirsPsr4 as $dir) {
90276 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
90277 return $file;
90278 }
90279 }
90280
90281
90282 if (false !== $pos = strrpos($class, '\\')) {
90283
90284 $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
90285 . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
90286 } else {
90287
90288 $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
90289 }
90290
90291 if (isset($this->prefixesPsr0[$first])) {
90292 foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
90293 if (0 === strpos($class, $prefix)) {
90294 foreach ($dirs as $dir) {
90295 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
90296 return $file;
90297 }
90298 }
90299 }
90300 }
90301 }
90302
90303
90304 foreach ($this->fallbackDirsPsr0 as $dir) {
90305 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
90306 return $file;
90307 }
90308 }
90309
90310
90311 if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
90312 return $file;
90313 }
90314
90315 return false;
90316 }
90317 }
90318
90319
90320
90321
90322
90323
90324 function includeFile($file)
90325 {
90326 include $file;
90327 }
90328 ##
90329 ## Bundle of CA Root Certificates
90330 ##
90331 ## Certificate data from Mozilla as of: Tue Dec  8 04:12:05 2020 GMT
90332 ##
90333 ## This is a bundle of X.509 certificates of public Certificate Authorities
90334 ## (CA). These were automatically extracted from Mozilla's root certificates
90335 ## file (certdata.txt).  This file can be found in the mozilla source tree:
90336 ## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt
90337 ##
90338 ## It contains the certificates in PEM format and therefore
90339 ## can be directly used with curl / libcurl / php_curl, or with
90340 ## an Apache+mod_ssl webserver for SSL client authentication.
90341 ## Just configure this file as the SSLCACertificateFile.
90342 ##
90343 ## Conversion done with mk-ca-bundle.pl version 1.28.
90344 ## SHA256: d820b8696d8ffe42064a1384a56a8981cdc7e7e198036bbb5fa04a6c282dd9a2
90345 ##
90346
90347
90348 GlobalSign Root CA
90349 ==================
90350 -----BEGIN CERTIFICATE-----
90351 MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx
90352 GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds
90353 b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV
90354 BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD
90355 VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa
90356 DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc
90357 THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb
90358 Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP
90359 c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX
90360 gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
90361 HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF
90362 AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj
90363 Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG
90364 j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH
90365 hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC
90366 X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
90367 -----END CERTIFICATE-----
90368
90369 GlobalSign Root CA - R2
90370 =======================
90371 -----BEGIN CERTIFICATE-----
90372 MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv
90373 YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
90374 bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
90375 aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
90376 bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6
90377 ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp
90378 s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN
90379 S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL
90380 TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C
90381 ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
90382 FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i
90383 YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN
90384 BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp
90385 9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu
90386 01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7
90387 9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
90388 TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
90389 -----END CERTIFICATE-----
90390
90391 Entrust.net Premium 2048 Secure Server CA
90392 =========================================
90393 -----BEGIN CERTIFICATE-----
90394 MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u
90395 ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp
90396 bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV
90397 BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx
90398 NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3
90399 d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl
90400 MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u
90401 ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
90402 MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL
90403 Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr
90404 hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW
90405 nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi
90406 VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E
90407 BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ
90408 KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy
90409 T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf
90410 zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT
90411 J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e
90412 nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE=
90413 -----END CERTIFICATE-----
90414
90415 Baltimore CyberTrust Root
90416 =========================
90417 -----BEGIN CERTIFICATE-----
90418 MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE
90419 ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li
90420 ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC
90421 SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs
90422 dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME
90423 uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB
90424 UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C
90425 G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9
90426 XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr
90427 l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI
90428 VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB
90429 BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh
90430 cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5
90431 hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa
90432 Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H
90433 RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
90434 -----END CERTIFICATE-----
90435
90436 Entrust Root Certification Authority
90437 ====================================
90438 -----BEGIN CERTIFICATE-----
90439 MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV
90440 BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw
90441 b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG
90442 A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0
90443 MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu
90444 MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu
90445 Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v
90446 dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
90447 ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz
90448 A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww
90449 Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68
90450 j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN
90451 rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw
90452 DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1
90453 MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH
90454 hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
90455 A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM
90456 Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa
90457 v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS
90458 W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0
90459 tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8
90460 -----END CERTIFICATE-----
90461
90462 GeoTrust Global CA
90463 ==================
90464 -----BEGIN CERTIFICATE-----
90465 MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
90466 Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw
90467 MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j
90468 LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
90469 CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo
90470 BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet
90471 8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc
90472 T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU
90473 vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD
90474 AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk
90475 DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q
90476 zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4
90477 d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2
90478 mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p
90479 XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm
90480 Mw==
90481 -----END CERTIFICATE-----
90482
90483 GeoTrust Universal CA
90484 =====================
90485 -----BEGIN CERTIFICATE-----
90486 MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
90487 R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1
90488 MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu
90489 Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
90490 ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t
90491 JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e
90492 RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs
90493 7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d
90494 8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V
90495 qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga
90496 Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB
90497 Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu
90498 KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08
90499 ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0
90500 XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB
90501 hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
90502 aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2
90503 qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL
90504 oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK
90505 xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF
90506 KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2
90507 DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK
90508 xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU
90509 p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI
90510 P/rmMuGNG2+k5o7Y+SlIis5z/iw=
90511 -----END CERTIFICATE-----
90512
90513 GeoTrust Universal CA 2
90514 =======================
90515 -----BEGIN CERTIFICATE-----
90516 MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
90517 R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0
90518 MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg
90519 SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA
90520 A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0
90521 DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17
90522 j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q
90523 JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a
90524 QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2
90525 WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP
90526 20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn
90527 ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC
90528 SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG
90529 8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2
90530 +/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E
90531 BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
90532 dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ
90533 4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+
90534 mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq
90535 A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg
90536 Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP
90537 pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d
90538 FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp
90539 gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm
90540 X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
90541 -----END CERTIFICATE-----
90542
90543 Comodo AAA Services root
90544 ========================
90545 -----BEGIN CERTIFICATE-----
90546 MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
90547 R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
90548 TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw
90549 MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl
90550 c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
90551 BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
90552 ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG
90553 C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs
90554 i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW
90555 Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH
90556 Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK
90557 Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f
90558 BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl
90559 cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz
90560 LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm
90561 7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
90562 Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z
90563 8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C
90564 12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
90565 -----END CERTIFICATE-----
90566
90567 QuoVadis Root CA
90568 ================
90569 -----BEGIN CERTIFICATE-----
90570 MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE
90571 ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
90572 eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz
90573 MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp
90574 cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD
90575 EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
90576 AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk
90577 J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL
90578 F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL
90579 YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen
90580 AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w
90581 PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y
90582 ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7
90583 MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj
90584 YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs
90585 ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh
90586 Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW
90587 Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu
90588 BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw
90589 FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0
90590 aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6
90591 tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo
90592 fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul
90593 LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x
90594 gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi
90595 5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi
90596 5nrQNiOKSnQ2+Q==
90597 -----END CERTIFICATE-----
90598
90599 QuoVadis Root CA 2
90600 ==================
90601 -----BEGIN CERTIFICATE-----
90602 MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT
90603 EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx
90604 ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
90605 aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC
90606 DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6
90607 XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk
90608 lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB
90609 lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy
90610 lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt
90611 66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn
90612 wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh
90613 D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy
90614 BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie
90615 J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud
90616 DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU
90617 a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT
90618 ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv
90619 Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3
90620 UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm
90621 VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK
90622 +JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW
90623 IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1
90624 WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X
90625 f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II
90626 4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8
90627 VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
90628 -----END CERTIFICATE-----
90629
90630 QuoVadis Root CA 3
90631 ==================
90632 -----BEGIN CERTIFICATE-----
90633 MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT
90634 EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx
90635 OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
90636 aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
90637 DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg
90638 DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij
90639 KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K
90640 DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv
90641 BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp
90642 p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8
90643 nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX
90644 MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM
90645 Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz
90646 uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT
90647 BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj
90648 YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0
90649 aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB
90650 BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD
90651 VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4
90652 ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE
90653 AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV
90654 qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s
90655 hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z
90656 POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2
90657 Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp
90658 8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC
90659 bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu
90660 g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p
90661 vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr
90662 qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=
90663 -----END CERTIFICATE-----
90664
90665 Security Communication Root CA
90666 ==============================
90667 -----BEGIN CERTIFICATE-----
90668 MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
90669 U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
90670 HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
90671 U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
90672 ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw
90673 8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM
90674 DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX
90675 5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd
90676 DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2
90677 JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw
90678 DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g
90679 0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a
90680 mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ
90681 s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ
90682 6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi
90683 FL39vmwLAw==
90684 -----END CERTIFICATE-----
90685
90686 Sonera Class 2 Root CA
90687 ======================
90688 -----BEGIN CERTIFICATE-----
90689 MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG
90690 U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw
90691 NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh
90692 IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3
90693 /Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT
90694 dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG
90695 f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P
90696 tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH
90697 nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT
90698 XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt
90699 0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI
90700 cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph
90701 Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx
90702 EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH
90703 llpwrN9M
90704 -----END CERTIFICATE-----
90705
90706 XRamp Global CA Root
90707 ====================
90708 -----BEGIN CERTIFICATE-----
90709 MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE
90710 BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj
90711 dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
90712 dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx
90713 HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg
90714 U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
90715 dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu
90716 IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx
90717 foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE
90718 zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs
90719 AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry
90720 xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
90721 EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap
90722 oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC
90723 AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc
90724 /Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
90725 qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n
90726 nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz
90727 8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw=
90728 -----END CERTIFICATE-----
90729
90730 Go Daddy Class 2 CA
90731 ===================
90732 -----BEGIN CERTIFICATE-----
90733 MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY
90734 VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp
90735 ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG
90736 A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g
90737 RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD
90738 ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv
90739 2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32
90740 qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j
90741 YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY
90742 vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O
90743 BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o
90744 atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu
90745 MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG
90746 A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim
90747 PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt
90748 I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
90749 HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI
90750 Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b
90751 vZ8=
90752 -----END CERTIFICATE-----
90753
90754 Starfield Class 2 CA
90755 ====================
90756 -----BEGIN CERTIFICATE-----
90757 MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc
90758 U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg
90759 Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo
90760 MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG
90761 A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG
90762 SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY
90763 bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ
90764 JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm
90765 epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN
90766 F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF
90767 MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f
90768 hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo
90769 bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g
90770 QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs
90771 afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM
90772 PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
90773 xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD
90774 KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3
90775 QBFGmh95DmK/D5fs4C8fF5Q=
90776 -----END CERTIFICATE-----
90777
90778 DigiCert Assured ID Root CA
90779 ===========================
90780 -----BEGIN CERTIFICATE-----
90781 MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG
90782 EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
90783 IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx
90784 MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
90785 ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew
90786 ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO
90787 9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy
90788 UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW
90789 /lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy
90790 oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf
90791 GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF
90792 66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq
90793 hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc
90794 EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn
90795 SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i
90796 8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
90797 +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
90798 -----END CERTIFICATE-----
90799
90800 DigiCert Global Root CA
90801 =======================
90802 -----BEGIN CERTIFICATE-----
90803 MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG
90804 EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
90805 HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw
90806 MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
90807 dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq
90808 hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn
90809 TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5
90810 BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H
90811 4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y
90812 7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB
90813 o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm
90814 8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF
90815 BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr
90816 EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt
90817 tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886
90818 UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
90819 CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
90820 -----END CERTIFICATE-----
90821
90822 DigiCert High Assurance EV Root CA
90823 ==================================
90824 -----BEGIN CERTIFICATE-----
90825 MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG
90826 EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw
90827 KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw
90828 MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
90829 MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu
90830 Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t
90831 Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS
90832 OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3
90833 MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ
90834 NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe
90835 h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB
90836 Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY
90837 JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ
90838 V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp
90839 myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK
90840 mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
90841 vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K
90842 -----END CERTIFICATE-----
90843
90844 DST Root CA X3
90845 ==============
90846 -----BEGIN CERTIFICATE-----
90847 MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK
90848 ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X
90849 DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1
90850 cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD
90851 ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT
90852 rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9
90853 UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy
90854 xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d
90855 utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T
90856 AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ
90857 MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug
90858 dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE
90859 GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw
90860 RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS
90861 fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
90862 -----END CERTIFICATE-----
90863
90864 SwissSign Gold CA - G2
90865 ======================
90866 -----BEGIN CERTIFICATE-----
90867 MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw
90868 EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN
90869 MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp
90870 c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B
90871 AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq
90872 t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C
90873 jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg
90874 vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF
90875 ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR
90876 AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend
90877 jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO
90878 peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR
90879 7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi
90880 GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw
90881 AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64
90882 OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov
90883 L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm
90884 5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr
90885 44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf
90886 Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m
90887 Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp
90888 mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk
90889 vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf
90890 KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br
90891 NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj
90892 viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
90893 -----END CERTIFICATE-----
90894
90895 SwissSign Silver CA - G2
90896 ========================
90897 -----BEGIN CERTIFICATE-----
90898 MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT
90899 BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X
90900 DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3
90901 aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG
90902 9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644
90903 N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm
90904 +/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH
90905 6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu
90906 MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h
90907 qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5
90908 FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs
90909 ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc
90910 celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X
90911 CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
90912 BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB
90913 tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0
90914 cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P
90915 4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F
90916 kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L
90917 3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx
90918 /uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa
90919 DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP
90920 e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu
90921 WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ
90922 DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub
90923 DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
90924 -----END CERTIFICATE-----
90925
90926 GeoTrust Primary Certification Authority
90927 ========================================
90928 -----BEGIN CERTIFICATE-----
90929 MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG
90930 EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD
90931 ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx
90932 CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ
90933 cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
90934 CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN
90935 b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9
90936 nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge
90937 RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt
90938 tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
90939 AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI
90940 hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K
90941 Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN
90942 NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa
90943 Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG
90944 1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
90945 -----END CERTIFICATE-----
90946
90947 thawte Primary Root CA
90948 ======================
90949 -----BEGIN CERTIFICATE-----
90950 MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE
90951 BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2
90952 aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv
90953 cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3
90954 MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg
90955 SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv
90956 KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT
90957 FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs
90958 oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ
90959 1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc
90960 q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K
90961 aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p
90962 afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD
90963 VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF
90964 AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE
90965 uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
90966 xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89
90967 jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH
90968 z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA==
90969 -----END CERTIFICATE-----
90970
90971 VeriSign Class 3 Public Primary Certification Authority - G5
90972 ============================================================
90973 -----BEGIN CERTIFICATE-----
90974 MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
90975 BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
90976 ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
90977 IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp
90978 ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB
90979 yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln
90980 biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh
90981 dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt
90982 YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
90983 ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz
90984 j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD
90985 Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/
90986 Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r
90987 fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/
90988 BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv
90989 Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
90990 aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG
90991 SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+
90992 X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE
90993 KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC
90994 Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE
90995 ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
90996 -----END CERTIFICATE-----
90997
90998 SecureTrust CA
90999 ==============
91000 -----BEGIN CERTIFICATE-----
91001 MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG
91002 EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy
91003 dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe
91004 BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC
91005 ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX
91006 OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t
91007 DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH
91008 GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b
91009 01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH
91010 ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/
91011 BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj
91012 aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ
91013 KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu
91014 SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf
91015 mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ
91016 nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
91017 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
91018 -----END CERTIFICATE-----
91019
91020 Secure Global CA
91021 ================
91022 -----BEGIN CERTIFICATE-----
91023 MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG
91024 EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH
91025 bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg
91026 MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg
91027 Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx
91028 YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ
91029 bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g
91030 8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV
91031 HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi
91032 0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
91033 EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn
91034 oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA
91035 MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+
91036 OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn
91037 CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5
91038 3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc
91039 f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW
91040 -----END CERTIFICATE-----
91041
91042 COMODO Certification Authority
91043 ==============================
91044 -----BEGIN CERTIFICATE-----
91045 MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE
91046 BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG
91047 A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1
91048 dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb
91049 MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD
91050 T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
91051 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH
91052 +7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww
91053 xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV
91054 4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA
91055 1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI
91056 rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E
91057 BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k
91058 b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC
91059 AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP
91060 OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
91061 RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc
91062 IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN
91063 +8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ==
91064 -----END CERTIFICATE-----
91065
91066 Network Solutions Certificate Authority
91067 =======================================
91068 -----BEGIN CERTIFICATE-----
91069 MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG
91070 EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr
91071 IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx
91072 MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu
91073 MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G
91074 CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx
91075 jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT
91076 aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT
91077 crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc
91078 /Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB
91079 AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP
91080 BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv
91081 bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA
91082 A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q
91083 4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/
91084 GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv
91085 wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD
91086 ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
91087 -----END CERTIFICATE-----
91088
91089 COMODO ECC Certification Authority
91090 ==================================
91091 -----BEGIN CERTIFICATE-----
91092 MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC
91093 R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
91094 ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB
91095 dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix
91096 GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
91097 Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo
91098 b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X
91099 4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni
91100 wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E
91101 BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG
91102 FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA
91103 U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
91104 -----END CERTIFICATE-----
91105
91106 Certigna
91107 ========
91108 -----BEGIN CERTIFICATE-----
91109 MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw
91110 EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3
91111 MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI
91112 Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q
91113 XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH
91114 GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p
91115 ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg
91116 DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf
91117 Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ
91118 tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ
91119 BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J
91120 SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA
91121 hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+
91122 ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu
91123 PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY
91124 1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw
91125 WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
91126 -----END CERTIFICATE-----
91127
91128 Cybertrust Global Root
91129 ======================
91130 -----BEGIN CERTIFICATE-----
91131 MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li
91132 ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4
91133 MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD
91134 ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
91135 +Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW
91136 0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL
91137 AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin
91138 89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT
91139 8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP
91140 BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2
91141 MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G
91142 A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO
91143 lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi
91144 5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2
91145 hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T
91146 X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW
91147 WL1WMRJOEcgh4LMRkWXbtKaIOM5V
91148 -----END CERTIFICATE-----
91149
91150 ePKI Root Certification Authority
91151 =================================
91152 -----BEGIN CERTIFICATE-----
91153 MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG
91154 EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg
91155 Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx
91156 MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq
91157 MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B
91158 AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs
91159 IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi
91160 lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv
91161 qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX
91162 12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O
91163 WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+
91164 ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao
91165 lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/
91166 vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi
91167 Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi
91168 MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH
91169 ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0
91170 1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq
91171 KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV
91172 xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP
91173 NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r
91174 GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE
91175 xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx
91176 gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy
91177 sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD
91178 BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw=
91179 -----END CERTIFICATE-----
91180
91181 certSIGN ROOT CA
91182 ================
91183 -----BEGIN CERTIFICATE-----
91184 MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD
91185 VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa
91186 Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE
91187 CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I
91188 JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH
91189 rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2
91190 ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD
91191 0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943
91192 AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
91193 Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB
91194 AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8
91195 SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0
91196 x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt
91197 vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz
91198 TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD
91199 -----END CERTIFICATE-----
91200
91201 GeoTrust Primary Certification Authority - G3
91202 =============================================
91203 -----BEGIN CERTIFICATE-----
91204 MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE
91205 BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0
91206 IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy
91207 eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz
91208 NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo
91209 YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT
91210 LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI
91211 hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j
91212 K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE
91213 c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C
91214 IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu
91215 dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC
91216 MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr
91217 2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9
91218 cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE
91219 Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
91220 AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s
91221 t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt
91222 -----END CERTIFICATE-----
91223
91224 thawte Primary Root CA - G2
91225 ===========================
91226 -----BEGIN CERTIFICATE-----
91227 MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC
91228 VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu
91229 IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg
91230 Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV
91231 MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG
91232 b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt
91233 IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS
91234 LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5
91235 8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU
91236 mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN
91237 G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K
91238 rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
91239 -----END CERTIFICATE-----
91240
91241 thawte Primary Root CA - G3
91242 ===========================
91243 -----BEGIN CERTIFICATE-----
91244 MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE
91245 BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2
91246 aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv
91247 cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w
91248 ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
91249 d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD
91250 VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG
91251 A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
91252 MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At
91253 P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC
91254 +BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY
91255 7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW
91256 vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E
91257 BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ
91258 KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK
91259 A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
91260 t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC
91261 8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm
91262 er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A=
91263 -----END CERTIFICATE-----
91264
91265 GeoTrust Primary Certification Authority - G2
91266 =============================================
91267 -----BEGIN CERTIFICATE-----
91268 MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC
91269 VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu
91270 Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD
91271 ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1
91272 OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg
91273 MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl
91274 b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG
91275 BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc
91276 KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD
91277 VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+
91278 EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m
91279 ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2
91280 npaqBA+K
91281 -----END CERTIFICATE-----
91282
91283 VeriSign Universal Root Certification Authority
91284 ===============================================
91285 -----BEGIN CERTIFICATE-----
91286 MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE
91287 BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
91288 ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
91289 IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u
91290 IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV
91291 UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
91292 cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
91293 IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0
91294 aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj
91295 1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP
91296 MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72
91297 9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I
91298 AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR
91299 tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G
91300 CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O
91301 a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
91302 DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3
91303 Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx
91304 Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx
91305 P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P
91306 wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4
91307 mJO37M2CYfE45k+XmCpajQ==
91308 -----END CERTIFICATE-----
91309
91310 VeriSign Class 3 Public Primary Certification Authority - G4
91311 ============================================================
91312 -----BEGIN CERTIFICATE-----
91313 MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC
91314 VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3
91315 b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz
91316 ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj
91317 YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL
91318 MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU
91319 cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo
91320 b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5
91321 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8
91322 Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz
91323 rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB
91324 /zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw
91325 HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u
91326 Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD
91327 A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx
91328 AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
91329 -----END CERTIFICATE-----
91330
91331 NetLock Arany (Class Gold) Főtanúsítvány
91332 ========================================
91333 -----BEGIN CERTIFICATE-----
91334 MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G
91335 A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610
91336 dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB
91337 cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx
91338 MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO
91339 ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv
91340 biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6
91341 c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu
91342 0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw
91343 /HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk
91344 H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw
91345 fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1
91346 neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB
91347 BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW
91348 qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta
91349 YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC
91350 bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna
91351 NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu
91352 dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
91353 -----END CERTIFICATE-----
91354
91355 Hongkong Post Root CA 1
91356 =======================
91357 -----BEGIN CERTIFICATE-----
91358 MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT
91359 DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx
91360 NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n
91361 IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF
91362 AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1
91363 ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr
91364 auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh
91365 qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY
91366 V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV
91367 HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i
91368 h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio
91369 l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei
91370 IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps
91371 T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT
91372 c4afU9hDDl3WY4JxHYB0yvbiAmvZWg==
91373 -----END CERTIFICATE-----
91374
91375 SecureSign RootCA11
91376 ===================
91377 -----BEGIN CERTIFICATE-----
91378 MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi
91379 SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS
91380 b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw
91381 KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1
91382 cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL
91383 TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO
91384 wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq
91385 g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP
91386 O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA
91387 bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX
91388 t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh
91389 OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r
91390 bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ
91391 Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01
91392 y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061
91393 lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I=
91394 -----END CERTIFICATE-----
91395
91396 Microsec e-Szigno Root CA 2009
91397 ==============================
91398 -----BEGIN CERTIFICATE-----
91399 MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER
91400 MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv
91401 c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o
91402 dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE
91403 BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt
91404 U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw
91405 DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA
91406 fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG
91407 0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA
91408 pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm
91409 1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC
91410 AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf
91411 QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE
91412 FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o
91413 lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX
91414 I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775
91415 tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02
91416 yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi
91417 LXpUq3DDfSJlgnCW
91418 -----END CERTIFICATE-----
91419
91420 GlobalSign Root CA - R3
91421 =======================
91422 -----BEGIN CERTIFICATE-----
91423 MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv
91424 YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
91425 bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
91426 aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
91427 bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt
91428 iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ
91429 0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3
91430 rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl
91431 OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2
91432 xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
91433 FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7
91434 lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8
91435 EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E
91436 bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18
91437 YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r
91438 kpeDMdmztcpHWD9f
91439 -----END CERTIFICATE-----
91440
91441 Autoridad de Certificacion Firmaprofesional CIF A62634068
91442 =========================================================
91443 -----BEGIN CERTIFICATE-----
91444 MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA
91445 BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2
91446 MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw
91447 QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB
91448 NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD
91449 Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P
91450 B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY
91451 7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH
91452 ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI
91453 plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX
91454 MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX
91455 LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK
91456 bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU
91457 vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud
91458 EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH
91459 DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp
91460 cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA
91461 bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx
91462 ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx
91463 51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk
91464 R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP
91465 T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f
91466 Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl
91467 osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR
91468 crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR
91469 saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD
91470 KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi
91471 6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
91472 -----END CERTIFICATE-----
91473
91474 Izenpe.com
91475 ==========
91476 -----BEGIN CERTIFICATE-----
91477 MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG
91478 EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz
91479 MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu
91480 QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ
91481 03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK
91482 ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU
91483 +zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC
91484 PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT
91485 OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK
91486 F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK
91487 0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+
91488 0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB
91489 leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID
91490 AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+
91491 SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG
91492 NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx
91493 MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
91494 BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l
91495 Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga
91496 kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q
91497 hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs
91498 g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5
91499 aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5
91500 nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC
91501 ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo
91502 Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z
91503 WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
91504 -----END CERTIFICATE-----
91505
91506 Chambers of Commerce Root - 2008
91507 ================================
91508 -----BEGIN CERTIFICATE-----
91509 MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD
91510 MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
91511 bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
91512 QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy
91513 Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl
91514 ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF
91515 EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl
91516 cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
91517 AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA
91518 XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj
91519 h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/
91520 ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk
91521 NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g
91522 D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331
91523 lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ
91524 0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj
91525 ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2
91526 EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI
91527 G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ
91528 BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh
91529 bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh
91530 bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC
91531 CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH
91532 AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1
91533 wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH
91534 3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU
91535 RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6
91536 M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1
91537 YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF
91538 9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK
91539 zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG
91540 nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg
91541 OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ
91542 -----END CERTIFICATE-----
91543
91544 Global Chambersign Root - 2008
91545 ==============================
91546 -----BEGIN CERTIFICATE-----
91547 MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD
91548 MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
91549 bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
91550 QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx
91551 NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg
91552 Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ
91553 QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD
91554 aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf
91555 VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf
91556 XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0
91557 ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB
91558 /gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA
91559 TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M
91560 H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe
91561 Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF
91562 HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh
91563 wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB
91564 AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT
91565 BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE
91566 BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm
91567 aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm
91568 aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp
91569 1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0
91570 dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG
91571 /5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6
91572 ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s
91573 dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg
91574 9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH
91575 foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du
91576 qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr
91577 P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq
91578 c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z
91579 09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B
91580 -----END CERTIFICATE-----
91581
91582 Go Daddy Root Certificate Authority - G2
91583 ========================================
91584 -----BEGIN CERTIFICATE-----
91585 MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
91586 B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu
91587 MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
91588 MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
91589 b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G
91590 A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
91591 hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq
91592 9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD
91593 +qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd
91594 fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl
91595 NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC
91596 MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9
91597 BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac
91598 vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r
91599 5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV
91600 N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
91601 LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1
91602 -----END CERTIFICATE-----
91603
91604 Starfield Root Certificate Authority - G2
91605 =========================================
91606 -----BEGIN CERTIFICATE-----
91607 MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
91608 B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
91609 b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0
91610 eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw
91611 DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg
91612 VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB
91613 dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv
91614 W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs
91615 bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk
91616 N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf
91617 ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU
91618 JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
91619 AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol
91620 TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx
91621 4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw
91622 F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
91623 pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ
91624 c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
91625 -----END CERTIFICATE-----
91626
91627 Starfield Services Root Certificate Authority - G2
91628 ==================================================
91629 -----BEGIN CERTIFICATE-----
91630 MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
91631 B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
91632 b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl
91633 IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV
91634 BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT
91635 dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg
91636 Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
91637 AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2
91638 h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa
91639 hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP
91640 LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB
91641 rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw
91642 AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG
91643 SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP
91644 E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy
91645 xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
91646 iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza
91647 YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6
91648 -----END CERTIFICATE-----
91649
91650 AffirmTrust Commercial
91651 ======================
91652 -----BEGIN CERTIFICATE-----
91653 MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS
91654 BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw
91655 MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
91656 bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF
91657 AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb
91658 DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV
91659 C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6
91660 BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww
91661 MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV
91662 HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
91663 AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG
91664 hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi
91665 qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv
91666 0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh
91667 sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
91668 -----END CERTIFICATE-----
91669
91670 AffirmTrust Networking
91671 ======================
91672 -----BEGIN CERTIFICATE-----
91673 MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS
91674 BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw
91675 MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
91676 bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF
91677 AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE
91678 Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI
91679 dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24
91680 /PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb
91681 h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV
91682 HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
91683 AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu
91684 UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6
91685 12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23
91686 WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9
91687 /ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
91688 -----END CERTIFICATE-----
91689
91690 AffirmTrust Premium
91691 ===================
91692 -----BEGIN CERTIFICATE-----
91693 MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS
91694 BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy
91695 OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy
91696 dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
91697 MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn
91698 BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV
91699 5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs
91700 +7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd
91701 GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R
91702 p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI
91703 S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04
91704 6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5
91705 /bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo
91706 +Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB
91707 /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv
91708 MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
91709 Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC
91710 6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S
91711 L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK
91712 +4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV
91713 BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg
91714 IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60
91715 g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb
91716 zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw==
91717 -----END CERTIFICATE-----
91718
91719 AffirmTrust Premium ECC
91720 =======================
91721 -----BEGIN CERTIFICATE-----
91722 MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV
91723 BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx
91724 MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U
91725 cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA
91726 IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ
91727 N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW
91728 BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK
91729 BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X
91730 57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM
91731 eQ==
91732 -----END CERTIFICATE-----
91733
91734 Certum Trusted Network CA
91735 =========================
91736 -----BEGIN CERTIFICATE-----
91737 MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK
91738 ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv
91739 biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy
91740 MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU
91741 ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
91742 MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
91743 AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC
91744 l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J
91745 J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4
91746 fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0
91747 cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB
91748 Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw
91749 DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj
91750 jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1
91751 mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj
91752 Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
91753 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=
91754 -----END CERTIFICATE-----
91755
91756 TWCA Root Certification Authority
91757 =================================
91758 -----BEGIN CERTIFICATE-----
91759 MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ
91760 VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh
91761 dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG
91762 EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB
91763 IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
91764 AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx
91765 QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC
91766 oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP
91767 4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r
91768 y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB
91769 BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG
91770 9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC
91771 mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW
91772 QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY
91773 T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny
91774 Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
91775 -----END CERTIFICATE-----
91776
91777 Security Communication RootCA2
91778 ==============================
91779 -----BEGIN CERTIFICATE-----
91780 MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
91781 U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh
91782 dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC
91783 SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy
91784 aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
91785 ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++
91786 +T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R
91787 3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV
91788 spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K
91789 EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8
91790 QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB
91791 CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj
91792 u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk
91793 3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q
91794 tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29
91795 mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
91796 -----END CERTIFICATE-----
91797
91798 EC-ACC
91799 ======
91800 -----BEGIN CERTIFICATE-----
91801 MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE
91802 BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w
91803 ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD
91804 VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE
91805 CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT
91806 BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7
91807 MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt
91808 SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl
91809 Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh
91810 cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND
91811 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK
91812 w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT
91813 ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4
91814 HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a
91815 E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw
91816 0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E
91817 BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD
91818 VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0
91819 Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l
91820 dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ
91821 lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa
91822 Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe
91823 l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2
91824 E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D
91825 5EI=
91826 -----END CERTIFICATE-----
91827
91828 Hellenic Academic and Research Institutions RootCA 2011
91829 =======================================================
91830 -----BEGIN CERTIFICATE-----
91831 MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT
91832 O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y
91833 aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
91834 IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT
91835 AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
91836 IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo
91837 IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
91838 AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI
91839 1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa
91840 71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u
91841 8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH
91842 3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/
91843 MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8
91844 MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu
91845 b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt
91846 XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8
91847 TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD
91848 /md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N
91849 7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4
91850 -----END CERTIFICATE-----
91851
91852 Actalis Authentication Root CA
91853 ==============================
91854 -----BEGIN CERTIFICATE-----
91855 MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM
91856 BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE
91857 AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky
91858 MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz
91859 IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
91860 IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ
91861 wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa
91862 by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6
91863 zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f
91864 YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2
91865 oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l
91866 EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7
91867 hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8
91868 EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5
91869 jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY
91870 iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt
91871 ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI
91872 WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0
91873 JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx
91874 K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+
91875 Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC
91876 4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo
91877 2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz
91878 lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem
91879 OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9
91880 vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
91881 -----END CERTIFICATE-----
91882
91883 Trustis FPS Root CA
91884 ===================
91885 -----BEGIN CERTIFICATE-----
91886 MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG
91887 EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290
91888 IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV
91889 BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ
91890 KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ
91891 RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk
91892 H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa
91893 cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt
91894 o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA
91895 AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd
91896 BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c
91897 GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC
91898 yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P
91899 8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV
91900 l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl
91901 iB6XzCGcKQENZetX2fNXlrtIzYE=
91902 -----END CERTIFICATE-----
91903
91904 Buypass Class 2 Root CA
91905 =======================
91906 -----BEGIN CERTIFICATE-----
91907 MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
91908 QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X
91909 DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
91910 eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw
91911 DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1
91912 g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn
91913 9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b
91914 /+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU
91915 CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff
91916 awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI
91917 zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn
91918 Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX
91919 Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs
91920 M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
91921 VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
91922 AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s
91923 A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI
91924 osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S
91925 aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd
91926 DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD
91927 LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0
91928 oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC
91929 wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS
91930 CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN
91931 rJgWVqA=
91932 -----END CERTIFICATE-----
91933
91934 Buypass Class 3 Root CA
91935 =======================
91936 -----BEGIN CERTIFICATE-----
91937 MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
91938 QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X
91939 DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
91940 eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw
91941 DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH
91942 sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR
91943 5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh
91944 7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ
91945 ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH
91946 2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV
91947 /afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ
91948 RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA
91949 Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq
91950 j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
91951 VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
91952 AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV
91953 cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G
91954 uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG
91955 Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8
91956 ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2
91957 KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz
91958 6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug
91959 UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe
91960 eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi
91961 Cp/HuZc=
91962 -----END CERTIFICATE-----
91963
91964 T-TeleSec GlobalRoot Class 3
91965 ============================
91966 -----BEGIN CERTIFICATE-----
91967 MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
91968 IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
91969 cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx
91970 MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
91971 dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
91972 ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3
91973 DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK
91974 9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU
91975 NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF
91976 iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W
91977 0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA
91978 MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr
91979 AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb
91980 fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT
91981 ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h
91982 P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml
91983 e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw==
91984 -----END CERTIFICATE-----
91985
91986 D-TRUST Root Class 3 CA 2 2009
91987 ==============================
91988 -----BEGIN CERTIFICATE-----
91989 MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK
91990 DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe
91991 Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE
91992 LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw
91993 DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD
91994 ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA
91995 BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv
91996 KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z
91997 p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC
91998 AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ
91999 4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y
92000 eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw
92001 MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G
92002 PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw
92003 OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm
92004 2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
92005 o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV
92006 dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph
92007 X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I=
92008 -----END CERTIFICATE-----
92009
92010 D-TRUST Root Class 3 CA 2 EV 2009
92011 =================================
92012 -----BEGIN CERTIFICATE-----
92013 MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
92014 DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
92015 OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
92016 DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
92017 OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS
92018 egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh
92019 zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T
92020 7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60
92021 sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35
92022 11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv
92023 cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v
92024 ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El
92025 MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp
92026 b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh
92027 c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+
92028 PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05
92029 nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX
92030 ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA
92031 NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv
92032 w9y4AyHqnxbxLFS1
92033 -----END CERTIFICATE-----
92034
92035 CA Disig Root R2
92036 ================
92037 -----BEGIN CERTIFICATE-----
92038 MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw
92039 EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp
92040 ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx
92041 EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp
92042 c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC
92043 w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia
92044 xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7
92045 A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S
92046 GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV
92047 g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa
92048 5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE
92049 koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A
92050 Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i
92051 Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV
92052 HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u
92053 Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM
92054 tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV
92055 sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je
92056 dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8
92057 1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx
92058 mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01
92059 utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0
92060 sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg
92061 UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV
92062 7+ZtsH8tZ/3zbBt1RqPlShfppNcL
92063 -----END CERTIFICATE-----
92064
92065 ACCVRAIZ1
92066 =========
92067 -----BEGIN CERTIFICATE-----
92068 MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB
92069 SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1
92070 MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH
92071 UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
92072 DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM
92073 jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0
92074 RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD
92075 aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ
92076 0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG
92077 WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7
92078 8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR
92079 5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J
92080 9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK
92081 Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw
92082 Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu
92083 Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2
92084 VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM
92085 Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA
92086 QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh
92087 AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA
92088 YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj
92089 AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA
92090 IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk
92091 aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0
92092 dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2
92093 MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI
92094 hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E
92095 R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN
92096 YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49
92097 nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ
92098 TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3
92099 sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h
92100 I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg
92101 Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd
92102 3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p
92103 EfbRD0tVNEYqi4Y7
92104 -----END CERTIFICATE-----
92105
92106 TWCA Global Root CA
92107 ===================
92108 -----BEGIN CERTIFICATE-----
92109 MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT
92110 CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD
92111 QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK
92112 EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg
92113 Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C
92114 nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV
92115 r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR
92116 Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV
92117 tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W
92118 KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99
92119 sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p
92120 yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn
92121 kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI
92122 zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC
92123 AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g
92124 cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn
92125 LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M
92126 8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg
92127 /eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg
92128 lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP
92129 A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m
92130 i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8
92131 EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3
92132 zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0=
92133 -----END CERTIFICATE-----
92134
92135 TeliaSonera Root CA v1
92136 ======================
92137 -----BEGIN CERTIFICATE-----
92138 MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE
92139 CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4
92140 MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW
92141 VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+
92142 6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA
92143 3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k
92144 B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn
92145 Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH
92146 oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3
92147 F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ
92148 oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7
92149 gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc
92150 TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB
92151 AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW
92152 DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm
92153 zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx
92154 0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW
92155 pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV
92156 G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc
92157 c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT
92158 JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2
92159 qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6
92160 Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems
92161 WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=
92162 -----END CERTIFICATE-----
92163
92164 E-Tugra Certification Authority
92165 ===============================
92166 -----BEGIN CERTIFICATE-----
92167 MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w
92168 DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls
92169 ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN
92170 ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw
92171 NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx
92172 QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl
92173 cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD
92174 DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
92175 MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd
92176 hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K
92177 CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g
92178 ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ
92179 BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0
92180 E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz
92181 rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq
92182 jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn
92183 rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5
92184 dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB
92185 /wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG
92186 MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK
92187 kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO
92188 XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807
92189 VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo
92190 a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc
92191 dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV
92192 KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT
92193 Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0
92194 8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G
92195 C7TbO6Orb1wdtn7os4I07QZcJA==
92196 -----END CERTIFICATE-----
92197
92198 T-TeleSec GlobalRoot Class 2
92199 ============================
92200 -----BEGIN CERTIFICATE-----
92201 MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
92202 IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
92203 cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx
92204 MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
92205 dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
92206 ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3
92207 DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ
92208 SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F
92209 vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970
92210 2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV
92211 WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA
92212 MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy
92213 YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4
92214 r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf
92215 vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR
92216 3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN
92217 9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg==
92218 -----END CERTIFICATE-----
92219
92220 Atos TrustedRoot 2011
92221 =====================
92222 -----BEGIN CERTIFICATE-----
92223 MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU
92224 cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4
92225 MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG
92226 A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV
92227 hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr
92228 54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+
92229 DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320
92230 HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR
92231 z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R
92232 l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ
92233 bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
92234 CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h
92235 k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh
92236 TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9
92237 61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G
92238 3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
92239 -----END CERTIFICATE-----
92240
92241 QuoVadis Root CA 1 G3
92242 =====================
92243 -----BEGIN CERTIFICATE-----
92244 MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG
92245 A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
92246 b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN
92247 MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg
92248 RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE
92249 PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm
92250 PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6
92251 Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN
92252 ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l
92253 g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV
92254 7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX
92255 9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f
92256 iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg
92257 t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
92258 AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI
92259 hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC
92260 MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3
92261 GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct
92262 Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP
92263 +V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh
92264 3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa
92265 wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6
92266 O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0
92267 FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV
92268 hMJKzRwuJIczYOXD
92269 -----END CERTIFICATE-----
92270
92271 QuoVadis Root CA 2 G3
92272 =====================
92273 -----BEGIN CERTIFICATE-----
92274 MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG
92275 A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
92276 b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN
92277 MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg
92278 RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh
92279 ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY
92280 NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t
92281 oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o
92282 MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l
92283 V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo
92284 L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ
92285 sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD
92286 6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh
92287 lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
92288 AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI
92289 hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66
92290 AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K
92291 pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9
92292 x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz
92293 dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X
92294 U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw
92295 mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD
92296 zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN
92297 JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr
92298 O3jtZsSOeWmD3n+M
92299 -----END CERTIFICATE-----
92300
92301 QuoVadis Root CA 3 G3
92302 =====================
92303 -----BEGIN CERTIFICATE-----
92304 MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG
92305 A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
92306 b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN
92307 MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg
92308 RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286
92309 IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL
92310 Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe
92311 6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3
92312 I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U
92313 VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7
92314 5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi
92315 Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM
92316 dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt
92317 rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
92318 AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI
92319 hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px
92320 KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS
92321 t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ
92322 TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du
92323 DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib
92324 Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD
92325 hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX
92326 0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW
92327 dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2
92328 PpxxVJkES/1Y+Zj0
92329 -----END CERTIFICATE-----
92330
92331 DigiCert Assured ID Root G2
92332 ===========================
92333 -----BEGIN CERTIFICATE-----
92334 MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG
92335 EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
92336 IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw
92337 MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
92338 ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw
92339 ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH
92340 35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq
92341 bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw
92342 VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP
92343 YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn
92344 lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO
92345 w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv
92346 0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz
92347 d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW
92348 hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M
92349 jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo
92350 IhNzbM8m9Yop5w==
92351 -----END CERTIFICATE-----
92352
92353 DigiCert Assured ID Root G3
92354 ===========================
92355 -----BEGIN CERTIFICATE-----
92356 MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV
92357 UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD
92358 VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1
92359 MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
92360 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ
92361 BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb
92362 RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs
92363 KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF
92364 UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy
92365 YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy
92366 1vUhZscv6pZjamVFkpUBtA==
92367 -----END CERTIFICATE-----
92368
92369 DigiCert Global Root G2
92370 =======================
92371 -----BEGIN CERTIFICATE-----
92372 MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG
92373 EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
92374 HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx
92375 MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
92376 dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq
92377 hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ
92378 kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO
92379 3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV
92380 BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM
92381 UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB
92382 o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu
92383 5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr
92384 F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U
92385 WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH
92386 QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/
92387 iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
92388 MrY=
92389 -----END CERTIFICATE-----
92390
92391 DigiCert Global Root G3
92392 =======================
92393 -----BEGIN CERTIFICATE-----
92394 MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV
92395 UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD
92396 VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw
92397 MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k
92398 aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C
92399 AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O
92400 YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP
92401 BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp
92402 Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y
92403 3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34
92404 VOKa5Vt8sycX
92405 -----END CERTIFICATE-----
92406
92407 DigiCert Trusted Root G4
92408 ========================
92409 -----BEGIN CERTIFICATE-----
92410 MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG
92411 EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw
92412 HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1
92413 MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
92414 d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G
92415 CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp
92416 pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o
92417 k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa
92418 vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY
92419 QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6
92420 MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm
92421 mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7
92422 f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH
92423 dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8
92424 oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud
92425 DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD
92426 ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY
92427 ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr
92428 yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy
92429 7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah
92430 ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN
92431 5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb
92432 /UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa
92433 5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK
92434 G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP
92435 82Z+
92436 -----END CERTIFICATE-----
92437
92438 COMODO RSA Certification Authority
92439 ==================================
92440 -----BEGIN CERTIFICATE-----
92441 MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE
92442 BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG
92443 A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv
92444 biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC
92445 R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
92446 ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB
92447 dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn
92448 dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ
92449 FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+
92450 5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG
92451 x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX
92452 2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL
92453 OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3
92454 sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C
92455 GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5
92456 WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E
92457 FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
92458 DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt
92459 rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+
92460 nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg
92461 tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW
92462 sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp
92463 pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA
92464 zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq
92465 ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52
92466 7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I
92467 LaZRfyHBNVOFBkpdn627G190
92468 -----END CERTIFICATE-----
92469
92470 USERTrust RSA Certification Authority
92471 =====================================
92472 -----BEGIN CERTIFICATE-----
92473 MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE
92474 BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK
92475 ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh
92476 dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE
92477 BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK
92478 ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh
92479 dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz
92480 0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j
92481 Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn
92482 RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O
92483 +T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq
92484 /nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE
92485 Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM
92486 lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8
92487 yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+
92488 eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
92489 BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
92490 MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW
92491 FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ
92492 7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ
92493 Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM
92494 8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi
92495 FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi
92496 yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c
92497 J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw
92498 sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx
92499 Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9
92500 -----END CERTIFICATE-----
92501
92502 USERTrust ECC Certification Authority
92503 =====================================
92504 -----BEGIN CERTIFICATE-----
92505 MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC
92506 VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
92507 aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
92508 biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC
92509 VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
92510 aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
92511 biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2
92512 0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez
92513 nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV
92514 HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB
92515 HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu
92516 9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=
92517 -----END CERTIFICATE-----
92518
92519 GlobalSign ECC Root CA - R4
92520 ===========================
92521 -----BEGIN CERTIFICATE-----
92522 MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEkMCIGA1UECxMb
92523 R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
92524 EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb
92525 R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
92526 EwpHbG9iYWxTaWduMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprl
92527 OQcJFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAwDgYDVR0P
92528 AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61FuOJAf/sKbvu+M8k8o4TV
92529 MAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGXkPoUVy0D7O48027KqGx2vKLeuwIgJ6iF
92530 JzWbVsaj8kfSt24bAgAXqmemFZHe+pTsewv4n4Q=
92531 -----END CERTIFICATE-----
92532
92533 GlobalSign ECC Root CA - R5
92534 ===========================
92535 -----BEGIN CERTIFICATE-----
92536 MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb
92537 R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
92538 EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb
92539 R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
92540 EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6
92541 SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS
92542 h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd
92543 BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx
92544 uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7
92545 yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3
92546 -----END CERTIFICATE-----
92547
92548 Staat der Nederlanden Root CA - G3
92549 ==================================
92550 -----BEGIN CERTIFICATE-----
92551 MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE
92552 CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g
92553 Um9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloXDTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMC
92554 TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l
92555 ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4y
92556 olQPcPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WWIkYFsO2t
92557 x1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqXxz8ecAgwoNzFs21v0IJy
92558 EavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFyKJLZWyNtZrVtB0LrpjPOktvA9mxjeM3K
92559 Tj215VKb8b475lRgsGYeCasH/lSJEULR9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUur
92560 mkVLoR9BvUhTFXFkC4az5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU5
92561 1nus6+N86U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7Ngzp
92562 07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHPbMk7ccHViLVlvMDo
92563 FxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXtBznaqB16nzaeErAMZRKQFWDZJkBE
92564 41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTtXUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMB
92565 AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleu
92566 yjWcLhL75LpdINyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD
92567 U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwpLiniyMMB8jPq
92568 KqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8Ipf3YF3qKS9Ysr1YvY2WTxB1
92569 v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixpgZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA
92570 8KCWAg8zxXHzniN9lLf9OtMJgwYh/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b
92571 8KKaa8MFSu1BYBQw0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0r
92572 mj1AfsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq4BZ+Extq
92573 1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR1VmiiXTTn74eS9fGbbeI
92574 JG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/QFH1T/U67cjF68IeHRaVesd+QnGTbksV
92575 tzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM94B7IWcnMFk=
92576 -----END CERTIFICATE-----
92577
92578 Staat der Nederlanden EV Root CA
92579 ================================
92580 -----BEGIN CERTIFICATE-----
92581 MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJOTDEeMBwGA1UE
92582 CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFhdCBkZXIgTmVkZXJsYW5kZW4g
92583 RVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0yMjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5M
92584 MR4wHAYDVQQKDBVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRl
92585 cmxhbmRlbiBFViBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkk
92586 SzrSM4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nCUiY4iKTW
92587 O0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3dZ//BYY1jTw+bbRcwJu+r
92588 0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46prfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8
92589 Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13lpJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gV
92590 XJrm0w912fxBmJc+qiXbj5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr
92591 08C+eKxCKFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS/ZbV
92592 0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0XcgOPvZuM5l5Tnrmd
92593 74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH1vI4gnPah1vlPNOePqc7nvQDs/nx
92594 fRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrPpx9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNC
92595 MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwa
92596 ivsnuL8wbqg7MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI
92597 eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u2dfOWBfoqSmu
92598 c0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHSv4ilf0X8rLiltTMMgsT7B/Zq
92599 5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTCwPTxGfARKbalGAKb12NMcIxHowNDXLldRqAN
92600 b/9Zjr7dn3LDWyvfjFvO5QxGbJKyCqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tN
92601 f1zuacpzEPuKqf2evTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi
92602 5Dp6Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIaGl6I6lD4
92603 WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeLeG9QgkRQP2YGiqtDhFZK
92604 DyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGy
92605 eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg==
92606 -----END CERTIFICATE-----
92607
92608 IdenTrust Commercial Root CA 1
92609 ==============================
92610 -----BEGIN CERTIFICATE-----
92611 MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG
92612 EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS
92613 b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES
92614 MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB
92615 IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld
92616 hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/
92617 mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi
92618 1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C
92619 XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl
92620 3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy
92621 NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV
92622 WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg
92623 xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix
92624 uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC
92625 AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI
92626 hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH
92627 6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg
92628 ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt
92629 ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV
92630 YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX
92631 feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro
92632 kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe
92633 2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz
92634 Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R
92635 cGzM7vRX+Bi6hG6H
92636 -----END CERTIFICATE-----
92637
92638 IdenTrust Public Sector Root CA 1
92639 =================================
92640 -----BEGIN CERTIFICATE-----
92641 MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG
92642 EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv
92643 ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV
92644 UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS
92645 b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy
92646 P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6
92647 Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI
92648 rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf
92649 qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS
92650 mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn
92651 ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh
92652 LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v
92653 iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL
92654 4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B
92655 Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw
92656 DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj
92657 t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A
92658 mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt
92659 GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt
92660 m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx
92661 NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4
92662 Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI
92663 ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC
92664 ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ
92665 3Wl9af0AVqW3rLatt8o+Ae+c
92666 -----END CERTIFICATE-----
92667
92668 Entrust Root Certification Authority - G2
92669 =========================================
92670 -----BEGIN CERTIFICATE-----
92671 MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV
92672 BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy
92673 bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug
92674 b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw
92675 HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT
92676 DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx
92677 OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s
92678 eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi
92679 MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP
92680 /vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz
92681 HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU
92682 s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y
92683 TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx
92684 AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6
92685 0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z
92686 iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ
92687 Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi
92688 nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+
92689 vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO
92690 e4pIb4tF9g==
92691 -----END CERTIFICATE-----
92692
92693 Entrust Root Certification Authority - EC1
92694 ==========================================
92695 -----BEGIN CERTIFICATE-----
92696 MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx
92697 FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn
92698 YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl
92699 ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
92700 IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw
92701 FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs
92702 LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg
92703 dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt
92704 IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy
92705 AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef
92706 9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
92707 FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h
92708 vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8
92709 kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G
92710 -----END CERTIFICATE-----
92711
92712 CFCA EV ROOT
92713 ============
92714 -----BEGIN CERTIFICATE-----
92715 MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE
92716 CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB
92717 IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw
92718 MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD
92719 DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV
92720 BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD
92721 7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN
92722 uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW
92723 ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7
92724 xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f
92725 py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K
92726 gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol
92727 hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ
92728 tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf
92729 BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
92730 /wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB
92731 ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q
92732 ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua
92733 4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG
92734 E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX
92735 BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn
92736 aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy
92737 PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX
92738 kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C
92739 ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su
92740 -----END CERTIFICATE-----
92741
92742 OISTE WISeKey Global Root GB CA
92743 ===============================
92744 -----BEGIN CERTIFICATE-----
92745 MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG
92746 EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl
92747 ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw
92748 MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD
92749 VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds
92750 b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX
92751 scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP
92752 rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk
92753 9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o
92754 Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg
92755 GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
92756 /zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI
92757 hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD
92758 dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0
92759 VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui
92760 HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic
92761 Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=
92762 -----END CERTIFICATE-----
92763
92764 SZAFIR ROOT CA2
92765 ===============
92766 -----BEGIN CERTIFICATE-----
92767 MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG
92768 A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV
92769 BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ
92770 BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD
92771 VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q
92772 qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK
92773 DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE
92774 2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ
92775 ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi
92776 ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
92777 AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC
92778 AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5
92779 O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67
92780 oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul
92781 4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6
92782 +/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw==
92783 -----END CERTIFICATE-----
92784
92785 Certum Trusted Network CA 2
92786 ===========================
92787 -----BEGIN CERTIFICATE-----
92788 MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE
92789 BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1
92790 bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y
92791 ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ
92792 TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl
92793 cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB
92794 IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9
92795 7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o
92796 CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b
92797 Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p
92798 uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130
92799 GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ
92800 9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB
92801 Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye
92802 hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM
92803 BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
92804 AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI
92805 hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW
92806 Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA
92807 L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo
92808 clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM
92809 pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb
92810 w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo
92811 J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm
92812 ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX
92813 is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7
92814 zAYspsbiDrW5viSP
92815 -----END CERTIFICATE-----
92816
92817 Hellenic Academic and Research Institutions RootCA 2015
92818 =======================================================
92819 -----BEGIN CERTIFICATE-----
92820 MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT
92821 BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0
92822 aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl
92823 YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx
92824 MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg
92825 QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV
92826 BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw
92827 MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv
92828 bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh
92829 iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+
92830 6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd
92831 FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr
92832 i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F
92833 GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2
92834 fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu
92835 iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc
92836 Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
92837 AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI
92838 hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+
92839 D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM
92840 d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y
92841 d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn
92842 82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb
92843 davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F
92844 Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt
92845 J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa
92846 JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q
92847 p/UsQu0yrbYhnr68
92848 -----END CERTIFICATE-----
92849
92850 Hellenic Academic and Research Institutions ECC RootCA 2015
92851 ===========================================================
92852 -----BEGIN CERTIFICATE-----
92853 MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0
92854 aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u
92855 cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj
92856 aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw
92857 MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj
92858 IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD
92859 VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290
92860 Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP
92861 dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK
92862 Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
92863 BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA
92864 GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn
92865 dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR
92866 -----END CERTIFICATE-----
92867
92868 ISRG Root X1
92869 ============
92870 -----BEGIN CERTIFICATE-----
92871 MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE
92872 BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD
92873 EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG
92874 EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT
92875 DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r
92876 Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1
92877 3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K
92878 b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN
92879 Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ
92880 4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf
92881 1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu
92882 hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH
92883 usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r
92884 OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G
92885 A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY
92886 9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
92887 ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV
92888 0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt
92889 hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw
92890 TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx
92891 e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA
92892 JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD
92893 YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n
92894 JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ
92895 m+kXQ99b21/+jh5Xos1AnX5iItreGCc=
92896 -----END CERTIFICATE-----
92897
92898 AC RAIZ FNMT-RCM
92899 ================
92900 -----BEGIN CERTIFICATE-----
92901 MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT
92902 AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw
92903 MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD
92904 TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
92905 ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf
92906 qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr
92907 btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL
92908 j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou
92909 08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw
92910 WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT
92911 tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ
92912 47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC
92913 ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa
92914 i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
92915 FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o
92916 dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD
92917 nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s
92918 D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ
92919 j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT
92920 Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW
92921 +YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7
92922 Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d
92923 8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm
92924 5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG
92925 rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM=
92926 -----END CERTIFICATE-----
92927
92928 Amazon Root CA 1
92929 ================
92930 -----BEGIN CERTIFICATE-----
92931 MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD
92932 VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1
92933 MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv
92934 bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
92935 ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH
92936 FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ
92937 gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t
92938 dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce
92939 VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB
92940 /zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3
92941 DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM
92942 CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy
92943 8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa
92944 2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2
92945 xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5
92946 -----END CERTIFICATE-----
92947
92948 Amazon Root CA 2
92949 ================
92950 -----BEGIN CERTIFICATE-----
92951 MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD
92952 VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1
92953 MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv
92954 bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
92955 ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4
92956 kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp
92957 N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9
92958 AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd
92959 fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx
92960 kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS
92961 btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0
92962 Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN
92963 c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+
92964 3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw
92965 DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA
92966 A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY
92967 +gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE
92968 YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW
92969 xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ
92970 gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW
92971 aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV
92972 Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3
92973 KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi
92974 JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw=
92975 -----END CERTIFICATE-----
92976
92977 Amazon Root CA 3
92978 ================
92979 -----BEGIN CERTIFICATE-----
92980 MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG
92981 EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy
92982 NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ
92983 MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB
92984 f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr
92985 Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43
92986 rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc
92987 eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw==
92988 -----END CERTIFICATE-----
92989
92990 Amazon Root CA 4
92991 ================
92992 -----BEGIN CERTIFICATE-----
92993 MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG
92994 EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy
92995 NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ
92996 MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN
92997 /sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri
92998 83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
92999 HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA
93000 MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1
93001 AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA==
93002 -----END CERTIFICATE-----
93003
93004 TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1
93005 =============================================
93006 -----BEGIN CERTIFICATE-----
93007 MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT
93008 D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr
93009 IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g
93010 TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp
93011 ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD
93012 VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt
93013 c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth
93014 bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11
93015 IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
93016 MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8
93017 6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc
93018 wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0
93019 3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9
93020 WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU
93021 ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
93022 KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh
93023 AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc
93024 lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R
93025 e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j
93026 q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=
93027 -----END CERTIFICATE-----
93028
93029 GDCA TrustAUTH R5 ROOT
93030 ======================
93031 -----BEGIN CERTIFICATE-----
93032 MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCQ04xMjAw
93033 BgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8wHQYDVQQD
93034 DBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVow
93035 YjELMAkGA1UEBhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ
93036 IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0B
93037 AQEFAAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJjDp6L3TQs
93038 AlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBjTnnEt1u9ol2x8kECK62p
93039 OqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+uKU49tm7srsHwJ5uu4/Ts765/94Y9cnrr
93040 pftZTqfrlYwiOXnhLQiPzLyRuEH3FMEjqcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ
93041 9Cy5WmYqsBebnh52nUpmMUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQ
93042 xXABZG12ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloPzgsM
93043 R6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3GkL30SgLdTMEZeS1SZ
93044 D2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeCjGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4
93045 oR24qoAATILnsn8JuLwwoC8N9VKejveSswoAHQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx
93046 9hoh49pwBiFYFIeFd3mqgnkCAwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlR
93047 MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg
93048 p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZmDRd9FBUb1Ov9
93049 H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5COmSdI31R9KrO9b7eGZONn35
93050 6ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ryL3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd
93051 +PwyvzeG5LuOmCd+uh8W4XAR8gPfJWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQ
93052 HtZa37dG/OaG+svgIHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBD
93053 F8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ
93054 8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQXR4EzzffHqhmsYzmIGrv
93055 /EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrqT8p+ck0LcIymSLumoRT2+1hEmRSuqguT
93056 aaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g==
93057 -----END CERTIFICATE-----
93058
93059 TrustCor RootCert CA-1
93060 ======================
93061 -----BEGIN CERTIFICATE-----
93062 MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYDVQQGEwJQQTEP
93063 MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig
93064 U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp
93065 dHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkx
93066 MjMxMTcyMzE2WjCBpDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFu
93067 YW1hIENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUGA1UECwwe
93068 VHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZUcnVzdENvciBSb290Q2Vy
93069 dCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv463leLCJhJrMxnHQFgKq1mq
93070 jQCj/IDHUHuO1CAmujIS2CNUSSUQIpidRtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4
93071 pQa81QBeCQryJ3pS/C3Vseq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0
93072 JEsq1pme9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CVEY4h
93073 gLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorWhnAbJN7+KIor0Gqw
93074 /Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/DeOxCbeKyKsZn3MzUOcwHwYDVR0j
93075 BBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
93076 AYYwDQYJKoZIhvcNAQELBQADggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5
93077 mDo4Nvu7Zp5I/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf
93078 ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZyonnMlo2HD6C
93079 qFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djtsL1Ac59v2Z3kf9YKVmgenFK+P
93080 3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdNzl/HHk484IkzlQsPpTLWPFp5LBk=
93081 -----END CERTIFICATE-----
93082
93083 TrustCor RootCert CA-2
93084 ======================
93085 -----BEGIN CERTIFICATE-----
93086 MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNVBAYTAlBBMQ8w
93087 DQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQwIgYDVQQKDBtUcnVzdENvciBT
93088 eXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0
93089 eTEfMB0GA1UEAwwWVHJ1c3RDb3IgUm9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEy
93090 MzExNzI2MzlaMIGkMQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5h
93091 bWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U
93092 cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0
93093 IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnIG7CKqJiJJWQdsg4foDSq8Gb
93094 ZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9Nk
93095 RvRUqdw6VC0xK5mC8tkq1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1
93096 oYxOdqHp2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nKDOOb
93097 XUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hapeaz6LMvYHL1cEksr1
93098 /p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF3wP+TfSvPd9cW436cOGlfifHhi5q
93099 jxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQP
93100 eSghYA2FFn3XVDjxklb9tTNMg9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+Ctg
93101 rKAmrhQhJ8Z3mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh
93102 8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAdBgNVHQ4EFgQU
93103 2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6UnrybPZx9mCAZ5YwwYrIwDwYD
93104 VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/h
93105 Osh80QA9z+LqBrWyOrsGS2h60COXdKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnp
93106 kpfbsEZC89NiqpX+MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv
93107 2wnL/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RXCI/hOWB3
93108 S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYaZH9bDTMJBzN7Bj8RpFxw
93109 PIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dv
93110 DDqPys/cA8GiCcjl/YBeyGBCARsaU1q7N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYU
93111 RpFHmygk71dSTlxCnKr3Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANE
93112 xdqtvArBAs8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp5KeX
93113 RKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu1uwJ
93114 -----END CERTIFICATE-----
93115
93116 TrustCor ECA-1
93117 ==============
93118 -----BEGIN CERTIFICATE-----
93119 MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYDVQQGEwJQQTEP
93120 MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig
93121 U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp
93122 dHkxFzAVBgNVBAMMDlRydXN0Q29yIEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3Mjgw
93123 N1owgZwxCzAJBgNVBAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5
93124 MSQwIgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29y
93125 IENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3IgRUNBLTEwggEiMA0GCSqG
93126 SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb3w9U73NjKYKtR8aja+3+XzP4Q1HpGjOR
93127 MRegdMTUpwHmspI+ap3tDvl0mEDTPwOABoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23
93128 xFUfJ3zSCNV2HykVh0A53ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmc
93129 p0yJF4OuowReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/wZ0+
93130 fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZFZtS6mFjBAgMBAAGj
93131 YzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAfBgNVHSMEGDAWgBREnkj1zG1I1KBL
93132 f/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF
93133 AAOCAQEABT41XBVwm8nHc2FvcivUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u
93134 /ukZMjgDfxT2AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F
93135 hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50soIipX1TH0Xs
93136 J5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BIWJZpTdwHjFGTot+fDz2LYLSC
93137 jaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1WitJ/X5g==
93138 -----END CERTIFICATE-----
93139
93140 SSL.com Root Certification Authority RSA
93141 ========================================
93142 -----BEGIN CERTIFICATE-----
93143 MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxDjAM
93144 BgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24x
93145 MTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYw
93146 MjEyMTczOTM5WhcNNDEwMjEyMTczOTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx
93147 EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NM
93148 LmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcNAQEBBQAD
93149 ggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2RxFdHaxh3a3by/ZPkPQ/C
93150 Fp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aXqhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8
93151 P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcCC52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/ge
93152 oeOy3ZExqysdBP+lSgQ36YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkp
93153 k8zruFvh/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrFYD3Z
93154 fBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93EJNyAKoFBbZQ+yODJ
93155 gUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVcUS4cK38acijnALXRdMbX5J+tB5O2
93156 UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi8
93157 1xtZPCvM8hnIk2snYxnP/Okm+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4s
93158 bE6x/c+cCbqiM+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV
93159 HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4GA1UdDwEB/wQE
93160 AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGVcpNxJK1ok1iOMq8bs3AD/CUr
93161 dIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBcHadm47GUBwwyOabqG7B52B2ccETjit3E+ZUf
93162 ijhDPwGFpUenPUayvOUiaPd7nNgsPgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAsl
93163 u1OJD7OAUN5F7kR/q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjq
93164 erQ0cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jra6x+3uxj
93165 MxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90IH37hVZkLId6Tngr75qNJ
93166 vTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/YK9f1JmzJBjSWFupwWRoyeXkLtoh/D1JI
93167 Pb9s2KJELtFOt3JY04kTlf5Eq/jXixtunLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406y
93168 wKBjYZC6VWg3dGq2ktufoYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NI
93169 WuuA8ShYIc2wBlX7Jz9TkHCpBB5XJ7k=
93170 -----END CERTIFICATE-----
93171
93172 SSL.com Root Certification Authority ECC
93173 ========================================
93174 -----BEGIN CERTIFICATE-----
93175 MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCVVMxDjAMBgNV
93176 BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xMTAv
93177 BgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEy
93178 MTgxNDAzWhcNNDEwMjEyMTgxNDAzWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO
93179 BgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv
93180 bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA
93181 BEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI7Z4INcgn64mMU1jrYor+
93182 8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPgCemB+vNH06NjMGEwHQYDVR0OBBYEFILR
93183 hXMw5zUE044CkvvlpNHEIejNMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTT
93184 jgKS++Wk0cQh6M0wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCW
93185 e+0F+S8Tkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+gA0z
93186 5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl
93187 -----END CERTIFICATE-----
93188
93189 SSL.com EV Root Certification Authority RSA R2
93190 ==============================================
93191 -----BEGIN CERTIFICATE-----
93192 MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMQ4w
93193 DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9u
93194 MTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy
93195 MB4XDTE3MDUzMTE4MTQzN1oXDTQyMDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI
93196 DAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYD
93197 VQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMIICIjAN
93198 BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvqM0fNTPl9fb69LT3w23jh
93199 hqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssufOePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7w
93200 cXHswxzpY6IXFJ3vG2fThVUCAtZJycxa4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTO
93201 Zw+oz12WGQvE43LrrdF9HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+
93202 B6KjBSYRaZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcAb9Zh
93203 CBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQGp8hLH94t2S42Oim
93204 9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQVPWKchjgGAGYS5Fl2WlPAApiiECto
93205 RHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMOpgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+Slm
93206 JuwgUHfbSguPvuUCYHBBXtSuUDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48
93207 +qvWBkofZ6aYMBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV
93208 HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa49QaAJadz20Zp
93209 qJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBWs47LCp1Jjr+kxJG7ZhcFUZh1
93210 ++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nx
93211 Y/hoLVUE0fKNsKTPvDxeH3jnpaAgcLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2G
93212 guDKBAdRUNf/ktUM79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDz
93213 OFSz/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXtll9ldDz7
93214 CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEmKf7GUmG6sXP/wwyc5Wxq
93215 lD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKKQbNmC1r7fSOl8hqw/96bg5Qu0T/fkreR
93216 rwU7ZcegbLHNYhLDkBvjJc40vG93drEQw/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1
93217 hlMYegouCRw2n5H9gooiS9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX
93218 9hwJ1C07mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w==
93219 -----END CERTIFICATE-----
93220
93221 SSL.com EV Root Certification Authority ECC
93222 ===========================================
93223 -----BEGIN CERTIFICATE-----
93224 MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMCVVMxDjAMBgNV
93225 BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAy
93226 BgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYw
93227 MjEyMTgxNTIzWhcNNDEwMjEyMTgxNTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx
93228 EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NM
93229 LmNvbSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB
93230 BAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMAVIbc/R/fALhBYlzccBYy
93231 3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1KthkuWnBaBu2+8KGwytAJKaNjMGEwHQYDVR0O
93232 BBYEFFvKXuXe0oGqzagtZFG22XKbl+ZPMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe
93233 5d7SgarNqC1kUbbZcpuX5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJ
93234 N+vp1RPZytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZgh5Mm
93235 m7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg==
93236 -----END CERTIFICATE-----
93237
93238 GlobalSign Root CA - R6
93239 =======================
93240 -----BEGIN CERTIFICATE-----
93241 MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEgMB4GA1UECxMX
93242 R2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds
93243 b2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQxMjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9i
93244 YWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFs
93245 U2lnbjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQss
93246 grRIxutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1kZguSgMpE
93247 3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxDaNc9PIrFsmbVkJq3MQbF
93248 vuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJwLnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqM
93249 PKq0pPbzlUoSB239jLKJz9CgYXfIWHSw1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+
93250 azayOeSsJDa38O+2HBNXk7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05O
93251 WgtH8wY2SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/hbguy
93252 CLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4nWUx2OVvq+aWh2IMP
93253 0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpYrZxCRXluDocZXFSxZba/jJvcE+kN
93254 b7gu3GduyYsRtYQUigAZcIN5kZeR1BonvzceMgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQE
93255 AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNV
93256 HSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN
93257 nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGtIxg93eFyRJa0
93258 lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr6155wsTLxDKZmOMNOsIeDjHfrY
93259 BzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLjvUYAGm0CuiVdjaExUd1URhxN25mW7xocBFym
93260 Fe944Hn+Xds+qkxV/ZoVqW/hpvvfcDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr
93261 3TsTjxKM4kEaSHpzoHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB1
93262 0jZpnOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfspA9MRf/T
93263 uTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+vJJUEeKgDu+6B5dpffItK
93264 oZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+t
93265 JDfLRVpOoERIyNiwmcUVhAn21klJwGW45hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=
93266 -----END CERTIFICATE-----
93267
93268 OISTE WISeKey Global Root GC CA
93269 ===============================
93270 -----BEGIN CERTIFICATE-----
93271 MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQswCQYDVQQGEwJD
93272 SDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEo
93273 MCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRa
93274 Fw00MjA1MDkwOTU4MzNaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQL
93275 ExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh
93276 bCBSb290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4nieUqjFqdr
93277 VCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4Wp2OQ0jnUsYd4XxiWD1Ab
93278 NTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd
93279 BgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7TrYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0E
93280 AwMDaAAwZQIwJsdpW9zV57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtk
93281 AjEA2zQgMgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9
93282 -----END CERTIFICATE-----
93283
93284 GTS Root R1
93285 ===========
93286 -----BEGIN CERTIFICATE-----
93287 MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQG
93288 EwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJv
93289 b3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAG
93290 A1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIi
93291 MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx
93292 9vaMf/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7wCl7r
93293 aKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjwTcLCeoiKu7rPWRnW
93294 r4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0PfyblqAj+lug8aJRT7oM6iCsVlgmy4HqM
93295 LnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly
93296 4cpk9+aCEI3oncKKiPo4Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr
93297 06zqkUspzBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92
93298 wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70paDPvOmbsB4om
93299 3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrNVjzRlwW5y0vtOUucxD/SVRNu
93300 JLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD
93301 VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEM
93302 BQADggIBADiWCu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1
93303 d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6ZXPYfcX3v73sv
93304 fuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZRgyFmxhE+885H7pwoHyXa/6xm
93305 ld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9b
93306 gsiG1eGZbYwE8na6SfZu6W0eX6DvJ4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq
93307 4BjFbkerQUIpm/ZgDdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWEr
93308 tXvM+SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyyF62ARPBo
93309 pY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9SQ98POyDGCBDTtWTurQ0
93310 sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdwsE3PYJ/HQcu51OyLemGhmW/HGY0dVHLql
93311 CFF1pkgl
93312 -----END CERTIFICATE-----
93313
93314 GTS Root R2
93315 ===========
93316 -----BEGIN CERTIFICATE-----
93317 MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQG
93318 EwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJv
93319 b3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAG
93320 A1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIi
93321 MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTuk
93322 k3LvCvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY6Dlo
93323 7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAuMC6C/Pq8tBcKSOWI
93324 m8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7kRXuJVfeKH2JShBKzwkCX44ofR5Gm
93325 dFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbu
93326 ak7MkogwTZq9TwtImoS1mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscsz
93327 cTJGr61K8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW
93328 Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKaG73Vululycsl
93329 aVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCqgc7dGtxRcw1PcOnlthYhGXmy
93330 5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD
93331 VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEM
93332 BQADggIBALZp8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT
93333 vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiTz9D2PGcDFWEJ
93334 +YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiApJiS4wGWAqoC7o87xdFtCjMw
93335 c3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvbpxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3Da
93336 WsYDQvTtN6LwG1BUSw7YhN4ZKJmBR64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5r
93337 n/WkhLx3+WuXrD5RRaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56Gtmwfu
93338 Nmsk0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC5AwiWVIQ
93339 7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiFizoHCBy69Y9Vmhh1fuXs
93340 gWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLnyOd/xCxgXS/Dr55FBcOEArf9LAhST4Ld
93341 o/DUhgkC
93342 -----END CERTIFICATE-----
93343
93344 GTS Root R3
93345 ===========
93346 -----BEGIN CERTIFICATE-----
93347 MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJV
93348 UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg
93349 UjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE
93350 ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcq
93351 hkjOPQIBBgUrgQQAIgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUU
93352 Rout736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL24Cej
93353 QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTB8Sa6oC2uhYHP
93354 0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFukfCPAlaUs3L6JbyO5o91lAFJekazInXJ0
93355 glMLfalAvWhgxeG4VDvBNhcl2MG9AjEAnjWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOa
93356 KaqW04MjyaR7YbPMAuhd
93357 -----END CERTIFICATE-----
93358
93359 GTS Root R4
93360 ===========
93361 -----BEGIN CERTIFICATE-----
93362 MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJV
93363 UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg
93364 UjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE
93365 ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcq
93366 hkjOPQIBBgUrgQQAIgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa
93367 6zzuhXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvRHYqj
93368 QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSATNbrdP9JNqPV
93369 2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0CMRw3J5QdCHojXohw0+WbhXRIjVhLfoI
93370 N+4Zba3bssx9BzT1YBkstTTZbyACMANxsbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11x
93371 zPKwTdb+mciUqXWi4w==
93372 -----END CERTIFICATE-----
93373
93374 UCA Global G2 Root
93375 ==================
93376 -----BEGIN CERTIFICATE-----
93377 MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQG
93378 EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBHbG9iYWwgRzIgUm9vdDAeFw0x
93379 NjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0xCzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlU
93380 cnVzdDEbMBkGA1UEAwwSVUNBIEdsb2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
93381 MIICCgKCAgEAxeYrb3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmT
93382 oni9kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzmVHqUwCoV
93383 8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/RVogvGjqNO7uCEeBHANBS
93384 h6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDcC/Vkw85DvG1xudLeJ1uK6NjGruFZfc8o
93385 LTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIjtm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/
93386 R+zvWr9LesGtOxdQXGLYD0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBe
93387 KW4bHAyvj5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6DlNaBa
93388 4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6iIis7nCs+dwp4wwc
93389 OxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznPO6Q0ibd5Ei9Hxeepl2n8pndntd97
93390 8XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
93391 BBYEFIHEjMz15DD/pQwIX4wVZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo
93392 5sOASD0Ee/ojL3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5
93393 1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl1qnN3e92mI0A
93394 Ds0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oUb3n09tDh05S60FdRvScFDcH9
93395 yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LVPtateJLbXDzz2K36uGt/xDYotgIVilQsnLAX
93396 c47QN6MUPJiVAAwpBVueSUmxX8fjy88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHo
93397 jhJi6IjMtX9Gl8CbEGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZk
93398 bxqgDMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI+Vg7RE+x
93399 ygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGyYiGqhkCyLmTTX8jjfhFn
93400 RR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bXUB+K+wb1whnw0A==
93401 -----END CERTIFICATE-----
93402
93403 UCA Extended Validation Root
93404 ============================
93405 -----BEGIN CERTIFICATE-----
93406 MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQG
93407 EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9u
93408 IFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMxMDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8G
93409 A1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIi
93410 MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrs
93411 iWogD4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvSsPGP2KxF
93412 Rv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aopO2z6+I9tTcg1367r3CTu
93413 eUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dksHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR
93414 59mzLC52LqGj3n5qiAno8geK+LLNEOfic0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH
93415 0mK1lTnj8/FtDw5lhIpjVMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KR
93416 el7sFsLzKuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/TuDv
93417 B0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41Gsx2VYVdWf6/wFlth
93418 WG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs1+lvK9JKBZP8nm9rZ/+I8U6laUpS
93419 NwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQDfwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS
93420 3H5aBZ8eNJr34RQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL
93421 BQADggIBADaNl8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR
93422 ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQVBcZEhrxH9cM
93423 aVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5c6sq1WnIeJEmMX3ixzDx/BR4
93424 dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb
93425 +7lsq+KePRXBOy5nAliRn+/4Qh8st2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOW
93426 F3sGPjLtx7dCvHaj2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwi
93427 GpWOvpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2CxR9GUeOc
93428 GMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmxcmtpzyKEC2IPrNkZAJSi
93429 djzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbMfjKaiJUINlK73nZfdklJrX+9ZSCyycEr
93430 dhh2n1ax
93431 -----END CERTIFICATE-----
93432
93433 Certigna Root CA
93434 ================
93435 -----BEGIN CERTIFICATE-----
93436 MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UE
93437 BhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAwMiA0ODE0NjMwODEwMDAzNjEZ
93438 MBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0xMzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjda
93439 MFoxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYz
93440 MDgxMDAwMzYxGTAXBgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC
93441 DwAwggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sOty3tRQgX
93442 stmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9MCiBtnyN6tMbaLOQdLNyz
93443 KNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPuI9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8
93444 JXrJhFwLrN1CTivngqIkicuQstDuI7pmTLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16
93445 XdG+RCYyKfHx9WzMfgIhC59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq
93446 4NYKpkDfePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3YzIoej
93447 wpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWTCo/1VTp2lc5ZmIoJ
93448 lXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1kJWumIWmbat10TWuXekG9qxf5kBdI
93449 jzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp/
93450 /TBt2dzhauH8XwIDAQABo4IBGjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
93451 HQYDVR0OBBYEFBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of
93452 1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczovL3d3d3cuY2Vy
93453 dGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilodHRwOi8vY3JsLmNlcnRpZ25h
93454 LmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYraHR0cDovL2NybC5kaGlteW90aXMuY29tL2Nl
93455 cnRpZ25hcm9vdGNhLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOIt
93456 OoldaDgvUSILSo3L6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxP
93457 TGRGHVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH60BGM+RFq
93458 7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncBlA2c5uk5jR+mUYyZDDl3
93459 4bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdio2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd
93460 8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS
93461 6Cvu5zHbugRqh5jnxV/vfaci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaY
93462 tlu3zM63Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayhjWZS
93463 aX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw3kAP+HwV96LOPNde
93464 E4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0=
93465 -----END CERTIFICATE-----
93466
93467 emSign Root CA - G1
93468 ===================
93469 -----BEGIN CERTIFICATE-----
93470 MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJJTjET
93471 MBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl
93472 ZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBHMTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgx
93473 ODMwMDBaMGcxCzAJBgNVBAYTAklOMRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVk
93474 aHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIB
93475 IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQzf2N4aLTN
93476 LnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO8oG0x5ZOrRkVUkr+PHB1
93477 cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aqd7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHW
93478 DV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhMtTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ
93479 6DqS0hdW5TUaQBw+jSztOd9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrH
93480 hQIDAQABo0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQDAgEG
93481 MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31xPaOfG1vR2vjTnGs2
93482 vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjMwiI/aTvFthUvozXGaCocV685743Q
93483 NcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6dGNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q
93484 +Mri/Tm3R7nrft8EI6/6nAYH6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeih
93485 U80Bv2noWgbyRQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx
93486 iN66zB+Afko=
93487 -----END CERTIFICATE-----
93488
93489 emSign ECC Root CA - G3
93490 =======================
93491 -----BEGIN CERTIFICATE-----
93492 MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQGEwJJTjETMBEG
93493 A1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg
93494 MB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4
93495 MTgzMDAwWjBrMQswCQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11
93496 ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g
93497 RzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0WXTsuwYc
93498 58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xySfvalY8L1X44uT6EYGQIr
93499 MgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuBzhccLikenEhjQjAOBgNVHQ8BAf8EBAMC
93500 AQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+D
93501 CBeQyh+KTOgNG3qxrdWBCUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7
93502 jHvrZQnD+JbNR6iC8hZVdyR+EhCVBCyj
93503 -----END CERTIFICATE-----
93504
93505 emSign Root CA - C1
93506 ===================
93507 -----BEGIN CERTIFICATE-----
93508 MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCVVMx
93509 EzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNp
93510 Z24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UE
93511 BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQD
93512 ExNlbVNpZ24gUm9vdCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+up
93513 ufGZBczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZHdPIWoU/
93514 Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH3DspVpNqs8FqOp099cGX
93515 OFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvHGPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4V
93516 I5b2P/AgNBbeCsbEBEV5f6f9vtKppa+cxSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleooms
93517 lMuoaJuvimUnzYnu3Yy1aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+
93518 XJGFehiqTbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD
93519 ggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87/kOXSTKZEhVb3xEp
93520 /6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4kqNPEjE2NuLe/gDEo2APJ62gsIq1
93521 NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrGYQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9
93522 wC68AivTxEDkigcxHpvOJpkT+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQ
93523 BmIMMMAVSKeoWXzhriKi4gp6D/piq1JM4fHfyr6DDUI=
93524 -----END CERTIFICATE-----
93525
93526 emSign ECC Root CA - C3
93527 =======================
93528 -----BEGIN CERTIFICATE-----
93529 MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQGEwJVUzETMBEG
93530 A1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxIDAeBgNVBAMTF2VtU2lnbiBF
93531 Q0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UE
93532 BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQD
93533 ExdlbVNpZ24gRUNDIFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd
93534 6bciMK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4OjavtisIGJAnB9
93535 SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0OBBYEFPtaSNCAIEDyqOkA
93536 B2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gA
93537 MGUCMQC02C8Cif22TGK6Q04ThHK1rt0c3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwU
93538 ZOR8loMRnLDRWmFLpg9J0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ==
93539 -----END CERTIFICATE-----
93540
93541 Hongkong Post Root CA 3
93542 =======================
93543 -----BEGIN CERTIFICATE-----
93544 MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQELBQAwbzELMAkG
93545 A1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJSG9uZyBLb25nMRYwFAYDVQQK
93546 Ew1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25na29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2
93547 MDMwMjI5NDZaFw00MjA2MDMwMjI5NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtv
93548 bmcxEjAQBgNVBAcTCUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMX
93549 SG9uZ2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz
93550 iNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFOdem1p+/l6TWZ5Mwc50tf
93551 jTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mIVoBc+L0sPOFMV4i707mV78vH9toxdCim
93552 5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOe
93553 sL4jpNrcyCse2m5FHomY2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj
93554 0mRiikKYvLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+TtbNe/
93555 JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZbx39ri1UbSsUgYT2u
93556 y1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+l2oBlKN8W4UdKjk60FSh0Tlxnf0h
93557 +bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YKTE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsG
93558 xVd7GYYKecsAyVKvQv83j+GjHno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwID
93559 AQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e
93560 i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEwDQYJKoZIhvcN
93561 AQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG7BJ8dNVI0lkUmcDrudHr9Egw
93562 W62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCkMpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWld
93563 y8joRTnU+kLBEUx3XZL7av9YROXrgZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov
93564 +BS5gLNdTaqX4fnkGMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDc
93565 eqFS3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJmOzj/2ZQw
93566 9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+l6mc1X5VTMbeRRAc6uk7
93567 nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6cJfTzPV4e0hz5sy229zdcxsshTrD3mUcY
93568 hcErulWuBurQB7Lcq9CClnXO0lD+mefPL5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB
93569 60PZ2Pierc+xYw5F9KBaLJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fq
93570 dBb9HxEGmpv0
93571 -----END CERTIFICATE-----
93572
93573 Entrust Root Certification Authority - G4
93574 =========================================
93575 -----BEGIN CERTIFICATE-----
93576 MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAwgb4xCzAJBgNV
93577 BAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3Qu
93578 bmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1
93579 dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1
93580 dGhvcml0eSAtIEc0MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYT
93581 AlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0
93582 L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhv
93583 cml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhv
93584 cml0eSAtIEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3D
93585 umSXbcr3DbVZwbPLqGgZ2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV
93586 3imz/f3ET+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j5pds
93587 8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAMC1rlLAHGVK/XqsEQ
93588 e9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73TDtTUXm6Hnmo9RR3RXRv06QqsYJn7
93589 ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNXwbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5X
93590 xNMhIWNlUpEbsZmOeX7m640A2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV
93591 7rtNOzK+mndmnqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8
93592 dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwlN4y6mACXi0mW
93593 Hv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNjc0kCAwEAAaNCMEAwDwYDVR0T
93594 AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9n
93595 MA0GCSqGSIb3DQEBCwUAA4ICAQAS5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4Q
93596 jbRaZIxowLByQzTSGwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht
93597 7LGrhFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/B7NTeLUK
93598 YvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uIAeV8KEsD+UmDfLJ/fOPt
93599 jqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbwH5Lk6rWS02FREAutp9lfx1/cH6NcjKF+
93600 m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKW
93601 RGhXxNUzzxkvFMSUHHuk2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjA
93602 JOgc47OlIQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk5F6G
93603 +TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuYn/PIjhs4ViFqUZPT
93604 kcpG2om3PVODLAgfi49T3f+sHw==
93605 -----END CERTIFICATE-----
93606
93607 Microsoft ECC Root Certificate Authority 2017
93608 =============================================
93609 -----BEGIN CERTIFICATE-----
93610 MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV
93611 UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQgRUND
93612 IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4
93613 MjMxNjA0WjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw
93614 NAYDVQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQ
93615 BgcqhkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZRogPZnZH6
93616 thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYbhGBKia/teQ87zvH2RPUB
93617 eMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIy5lycFIM
93618 +Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlf
93619 Xu5gKcs68tvWMoQZP3zVL8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaR
93620 eNtUjGUBiudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M=
93621 -----END CERTIFICATE-----
93622
93623 Microsoft RSA Root Certificate Authority 2017
93624 =============================================
93625 -----BEGIN CERTIFICATE-----
93626 MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQG
93627 EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQg
93628 UlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIw
93629 NzE4MjMwMDIzWjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u
93630 MTYwNAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcw
93631 ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZNt9GkMml
93632 7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0ZdDMbRnMlfl7rEqUrQ7e
93633 S0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw7
93634 1VdyvD/IybLeS2v4I2wDwAW9lcfNcztmgGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+
93635 dkC0zVJhUXAoP8XFWvLJjEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49F
93636 yGcohJUcaDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaGYaRS
93637 MLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6W6IYZVcSn2i51BVr
93638 lMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4KUGsTuqwPN1q3ErWQgR5WrlcihtnJ
93639 0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJ
93640 ClTUFLkqqNfs+avNJVgyeY+QW5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYw
93641 DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC
93642 NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZCLgLNFgVZJ8og
93643 6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OCgMNPOsduET/m4xaRhPtthH80
93644 dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk
93645 +ONVFT24bcMKpBLBaYVu32TxU5nhSnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex
93646 /2kskZGT4d9Mozd2TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDy
93647 AmH3pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGRxpl/j8nW
93648 ZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiAppGWSZI1b7rCoucL5mxAyE
93649 7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKT
93650 c0QWbej09+CVgI+WXTik9KveCjCHk9hNAHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D
93651 5KbvtwEwXlGjefVwaaZBRA+GsCyRxj3qrg+E
93652 -----END CERTIFICATE-----
93653
93654 e-Szigno Root CA 2017
93655 =====================
93656 -----BEGIN CERTIFICATE-----
93657 MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNVBAYTAkhVMREw
93658 DwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUt
93659 MjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJvb3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZa
93660 Fw00MjA4MjIxMjA3MDZaMHExCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UE
93661 CgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3pp
93662 Z25vIFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtvxie+RJCx
93663 s1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+HWyx7xf58etqjYzBhMA8G
93664 A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSHERUI0arBeAyxr87GyZDv
93665 vzAEwDAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEA
93666 tVfd14pVCzbhhkT61NlojbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxO
93667 svxyqltZ+efcMQ==
93668 -----END CERTIFICATE-----
93669
93670 certSIGN Root CA G2
93671 ===================
93672 -----BEGIN CERTIFICATE-----
93673 MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNVBAYTAlJPMRQw
93674 EgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjAeFw0xNzAy
93675 MDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJBgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lH
93676 TiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
93677 ADCCAgoCggIBAMDFdRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05
93678 N0IwvlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZuIt4Imfk
93679 abBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhpn+Sc8CnTXPnGFiWeI8Mg
93680 wT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKscpc/I1mbySKEwQdPzH/iV8oScLumZfNp
93681 dWO9lfsbl83kqK/20U6o2YpxJM02PbyWxPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91Qqh
93682 ngLjYl/rNUssuHLoPj1PrCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732
93683 jcZZroiFDsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fxDTvf
93684 95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgyLcsUDFDYg2WD7rlc
93685 z8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6CeWRgKRM+o/1Pcmqr4tTluCRVLERL
93686 iohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1Ud
93687 DgQWBBSCIS1mxteg4BXrzkwJd8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOB
93688 ywaK8SJJ6ejqkX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC
93689 b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQlqiCA2ClV9+BB
93690 /AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0OJD7uNGzcgbJceaBxXntC6Z5
93691 8hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+cNywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5
93692 BiKDUyUM/FHE5r7iOZULJK2v0ZXkltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklW
93693 atKcsWMy5WHgUyIOpwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tU
93694 Sxfj03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZkPuXaTH4M
93695 NMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE1LlSVHJ7liXMvGnjSG4N
93696 0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MXQRBdJ3NghVdJIgc=
93697 -----END CERTIFICATE-----
93698
93699 Trustwave Global Certification Authority
93700 ========================================
93701 -----BEGIN CERTIFICATE-----
93702 MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJV
93703 UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2
93704 ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u
93705 IEF1dGhvcml0eTAeFw0xNzA4MjMxOTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJV
93706 UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2
93707 ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u
93708 IEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALldUShLPDeS0YLOvR29
93709 zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0XznswuvCAAJWX/NKSqIk4cXGIDtiLK0thAf
93710 LdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4Bq
93711 stTnoApTAbqOl5F2brz81Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9o
93712 WN0EACyW80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotPJqX+
93713 OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1lRtzuzWniTY+HKE40
93714 Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfwhI0Vcnyh78zyiGG69Gm7DIwLdVcE
93715 uE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm
93716 +9jaJXLE9gCxInm943xZYkqcBW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqj
93717 ifLJS3tBEW1ntwiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud
93718 EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1UdDwEB/wQEAwIB
93719 BjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W0OhUKDtkLSGm+J1WE2pIPU/H
93720 PinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfeuyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0H
93721 ZJDmHvUqoai7PF35owgLEQzxPy0QlG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla
93722 4gt5kNdXElE1GYhBaCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5R
93723 vbbEsLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPTMaCm/zjd
93724 zyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qequ5AvzSxnI9O4fKSTx+O
93725 856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxhVicGaeVyQYHTtgGJoC86cnn+OjC/QezH
93726 Yj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu
93727 3R3y4G5OBVixwJAWKqQ9EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP
93728 29FpHOTKyeC2nOnOcXHebD8WpHk=
93729 -----END CERTIFICATE-----
93730
93731 Trustwave Global ECC P256 Certification Authority
93732 =================================================
93733 -----BEGIN CERTIFICATE-----
93734 MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYDVQQGEwJVUzER
93735 MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI
93736 b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZp
93737 Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYD
93738 VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy
93739 dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1
93740 NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABH77bOYj
93741 43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoNFWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqm
93742 P62jQzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt
93743 0UrrdaVKEJmzsaGLSvcwCgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjz
93744 RM4q3wghDDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7
93745 -----END CERTIFICATE-----
93746
93747 Trustwave Global ECC P384 Certification Authority
93748 =================================================
93749 -----BEGIN CERTIFICATE-----
93750 MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYDVQQGEwJVUzER
93751 MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI
93752 b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZp
93753 Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYD
93754 VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy
93755 dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4
93756 NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuBBAAiA2IABGvaDXU1CDFH
93757 Ba5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJj9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr
93758 /TklZvFe/oyujUF5nQlgziip04pt89ZF1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNV
93759 HQ8BAf8EBQMDBwYAMB0GA1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNn
93760 ADBkAjA3AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsCMGcl
93761 CrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVuSw==
93762 -----END CERTIFICATE-----
93763 <?php
93764
93765 if (PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg') {
93766     echo 'Warning: Composer should be invoked via the CLI version of PHP, not the '.PHP_SAPI.' SAPI'.PHP_EOL;
93767 }
93768
93769 setlocale(LC_ALL, 'C');
93770 require __DIR__.'/../src/bootstrap.php';
93771
93772 use Composer\Console\Application;
93773 use Composer\XdebugHandler\XdebugHandler;
93774
93775 error_reporting(-1);
93776
93777 // Restart without Xdebug
93778 $xdebug = new XdebugHandler('Composer', '--ansi');
93779 $xdebug->check();
93780 unset($xdebug);
93781
93782 if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '4.0', '>=')) {
93783     echo 'HHVM 4.0 has dropped support for Composer, please use PHP instead. Aborting.'.PHP_EOL;
93784     exit(1);
93785 }
93786
93787 if (function_exists('ini_set')) {
93788     @ini_set('display_errors', 1);
93789
93790     $memoryInBytes = function ($value) {
93791         $unit = strtolower(substr($value, -1, 1));
93792         $value = (int) $value;
93793         switch($unit) {
93794             case 'g':
93795                 $value *= 1024;
93796                 // no break (cumulative multiplier)
93797             case 'm':
93798                 $value *= 1024;
93799                 // no break (cumulative multiplier)
93800             case 'k':
93801                 $value *= 1024;
93802         }
93803
93804         return $value;
93805     };
93806
93807     $memoryLimit = trim(ini_get('memory_limit'));
93808     // Increase memory_limit if it is lower than 1.5GB
93809     if ($memoryLimit != -1 && $memoryInBytes($memoryLimit) < 1024 * 1024 * 1536) {
93810         @ini_set('memory_limit', '1536M');
93811     }
93812     // Set user defined memory limit
93813     if ($memoryLimit = getenv('COMPOSER_MEMORY_LIMIT')) {
93814         @ini_set('memory_limit', $memoryLimit);
93815     }
93816     unset($memoryInBytes, $memoryLimit);
93817 }
93818
93819 putenv('COMPOSER_BINARY='.realpath($_SERVER['argv'][0]));
93820
93821 // run the command application
93822 $application = new Application();
93823 $application->run();
93824
93825 Copyright (c) Nils Adermann, Jordi Boggiano
93826
93827 Permission is hereby granted, free of charge, to any person obtaining a copy
93828 of this software and associated documentation files (the "Software"), to deal
93829 in the Software without restriction, including without limitation the rights
93830 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
93831 copies of the Software, and to permit persons to whom the Software is furnished
93832 to do so, subject to the following conditions:
93833
93834 The above copyright notice and this permission notice shall be included in all
93835 copies or substantial portions of the Software.
93836
93837 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
93838 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
93839 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
93840 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
93841 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
93842 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
93843 THE SOFTWARE.
93844
93845 1]®âª°¤\ 2]\83\aÝ\rJ\80;\14P6¢\ 2\0\0\0GBMB