]> git.mxchange.org Git - friendica.git/blob - bin/composer.phar
Show month/halfyear usage
[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\87`3k\0\0y[£\13¤\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Autoload/ClassMapGenerator.phpÖ\1a\0\0\87\1a\0\0ß\f\86\ 1\0\0\0\0\0\0\16\0\0\0src/Composer/Cache.phpä\13\0\0\87\13\0\0xw\0ܤ\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Command/AboutCommand.phpØ\ 2\0\0\87\ 2\0\0ö÷;\87¤\ 1\0\0\0\0\0\0'\0\0\0src/Composer/Command/ArchiveCommand.phpä\14\0\0\87\14\0\0Õ\15­\7f¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Command/BaseCommand.phpÚ\v\0\0\87\v\0\0Ý\10\88ˤ\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Command/BaseDependencyCommand.php\\19\0\0\87`\\19\0\0{\8d9d¤\ 1\0\0\0\0\0\01\0\0\0src/Composer/Command/CheckPlatformReqsCommand.php}\ f\0\0\87`}\ f\0\0\1c0Û¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Command/ClearCacheCommand.php½\ 5\0\0\87\ 5\0\0°\ 2\b\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Command/ConfigCommand.php»Q\0\0\87`»Q\0\0^¼ÿȤ\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Command/CreateProjectCommand.phpe;\0\0\87`e;\0\0'\98À\ 5¤\ 1\0\0\0\0\0\0'\0\0\0src/Composer/Command/DependsCommand.phpø\ 2\0\0\87\ 2\0\0ªe\11á¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Command/DiagnoseCommand.php]P\0\0\87`]P\0\0MTõj¤\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Command/DumpAutoloadCommand.phpã\v\0\0\87\v\0\0© ]\86¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Command/ExecCommand.php\1c \0\0\87`\1c \0\0?ìç\11¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Command/FundCommand.php+
28 \0\0\87`+
29 \0\0ð\19`ó¤\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Command/GlobalCommand.phpÅ       \0\0\87`Å \0\0©O:ü¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Command/HomeCommand.php\ 1\ f\0\0\87`\ 1\ f\0\0\ 4\92\89 ¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Command/InitCommand.php:U\0\0\87`:U\0\0\88\8a»â¤\ 1\0\0\0\0\0\0'\0\0\0src/Composer/Command/InstallCommand.phpT\14\0\0\87`T\14\0\0Þùõ\9b¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Command/LicensesCommand.phpò\ e\0\0\87\ e\0\0´\18È\1c¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Command/OutdatedCommand.php\ f\f\0\0\87`\ f\f\0\0ا\14\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Command/ProhibitsCommand.php\12\ 3\0\0\87`\12\ 3\0\0_¤éS¤\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Command/RemoveCommand.phpß\18\0\0\87\18\0\0ì:/|¤\ 1\0\0\0\0\0\0'\0\0\0src/Composer/Command/RequireCommand.php¨)\0\0\87`¨)\0\0µDàÿ¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Command/RunScriptCommand.php±\ f\0\0\87\ f\0\0\99Ò-Ť\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Command/ScriptAliasCommand.php¯\ 5\0\0\87\ 5\0\0?=\10Ѥ\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Command/SearchCommand.phpT      \0\0\87`T \0\0\7f±¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Command/SelfUpdateCommand.phpðC\0\0\87`ðC\0\0vÕ      <¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Command/ShowCommand.phpp\82\0\0\87`p\82\0\0¼¨ìÛ¤\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Command/StatusCommand.php%\16\0\0\87`%\16\0\0\8e\14ÞÚ¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Command/SuggestsCommand.php
30 \ e\0\0\87`
31 \ e\0\0y\92°ø¤\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Command/UpdateCommand.phpë#\0\0\87`ë#\0\03<&\0¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Command/ValidateCommand.phpe\14\0\0\87`e\14\0\0ï\ 3
32 ²¤\ 1\0\0\0\0\0\0\19\0\0\0src/Composer/Composer.php}\v\0\0\87`}\v\0\0=â=å¤\ 1\0\0\0\0\0\0\17\0\0\0src/Composer/Config.phpø$\0\0\87`ø$\0\0\19öÙú¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Config/ConfigSourceInterface.php\ e\ 2\0\0\87`\ e\ 2\0\0³\f[/¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Config/JsonConfigSource.php²\14\0\0\87\14\0\0Gd=\9e¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Console/Application.phpY8\0\0\87`Y8\0\0Äë檤\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Console/HtmlOutputFormatter.php0\ 6\0\0\87`0\ 6\0\0\9aÒ¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/DependencyResolver/Decisions.php6\10\0\0\87`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\87`\ 5\17\0\0Þ       \b¼¤\ 1\0\0\0\0\0\0/\0\0\0src/Composer/DependencyResolver/GenericRule.php´\ 3\0\0\87\ 3\0\0n±ðã¤\ 1\0\0\0\0\0\0>\0\0\0src/Composer/DependencyResolver/Operation/InstallOperation.phpC\ 2\0\0\87`C\ 2\0\0´\õ*¤\ 1\0\0\0\0\0\0I\0\0\0src/Composer/DependencyResolver/Operation/MarkAliasInstalledOperation.php÷\ 2\0\0\87\ 2\0\0ïÎà÷¤\ 1\0\0\0\0\0\0K\0\0\0src/Composer/DependencyResolver/Operation/MarkAliasUninstalledOperation.phpý\ 2\0\0\87\ 2\0\0\193#\86¤\ 1\0\0\0\0\0\0@\0\0\0src/Composer/DependencyResolver/Operation/OperationInterface.phpÓ\0\0\0\87\0\0\0Ùâ&ä¤\ 1\0\0\0\0\0\0=\0\0\0src/Composer/DependencyResolver/Operation/SolverOperation.php¹\ 1\0\0\87\ 1\0\0&¢e
33 ¤\ 1\0\0\0\0\0\0@\0\0\0src/Composer/DependencyResolver/Operation/UninstallOperation.phpI\ 2\0\0\87`I\ 2\0\0FûÂɤ\ 1\0\0\0\0\0\0=\0\0\0src/Composer/DependencyResolver/Operation/UpdateOperation.php'\ 4\0\0\87`'\ 4\0\0Qúɯ¤\ 1\0\0\0\0\0\03\0\0\0src/Composer/DependencyResolver/PolicyInterface.php­\ 1\0\0\87\ 1\0\0\18\9f\8b\ 1\0\0\0\0\0\0(\0\0\0src/Composer/DependencyResolver/Pool.phpü"\0\0\87`ü"\0\0l\9e\83Ƥ\ 1\0\0\0\0\0\0+\0\0\0src/Composer/DependencyResolver/Problem.php÷\17\0\0\87\17\0\0K\8eX\8b¤\ 1\0\0\0\0\0\0+\0\0\0src/Composer/DependencyResolver/Request.php\83\ 4\0\0\87`\83\ 4\0\0åVP\84¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/DependencyResolver/Rule.php:\19\0\0\87`:\19\0\0=$\19¨¤\ 1\0\0\0\0\0\01\0\0\0src/Composer/DependencyResolver/Rule2Literals.php\17\ 5\0\0\87`\17\ 5\0\0\r\11NS¤\ 1\0\0\0\0\0\0+\0\0\0src/Composer/DependencyResolver/RuleSet.php¨
34 \0\0\87
35 \0\0XÏé¤\ 1\0\0\0\0\0\04\0\0\0src/Composer/DependencyResolver/RuleSetGenerator.php\83\1f\0\0\87`\83\1f\0\0ù\15c\1a¤\ 1\0\0\0\0\0\03\0\0\0src/Composer/DependencyResolver/RuleSetIterator.php\11\ 6\0\0\87`\11\ 6\0\0\9bCü$¤\ 1\0\0\0\0\0\02\0\0\0src/Composer/DependencyResolver/RuleWatchChain.phpi\ 1\0\0\87`i\ 1\0\0\9a\ 1\0\0\0\0\0\02\0\0\0src/Composer/DependencyResolver/RuleWatchGraph.phpÞ\ 6\0\0\87\ 6\0\0ã\983¼¤\ 1\0\0\0\0\0\01\0\0\0src/Composer/DependencyResolver/RuleWatchNode.php\ 4\ 4\0\0\87`\ 4\ 4\0\07§¹!¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/DependencyResolver/Solver.phpF:\0\0\87`F:\0\0\10\93\89¨¤\ 1\0\0\0\0\0\06\0\0\0src/Composer/DependencyResolver/SolverBugException.php\99\ 1\0\0\87`\99\ 1\0\0X\12g6¤\ 1\0\0\0\0\0\0;\0\0\0src/Composer/DependencyResolver/SolverProblemsException.phpô\a\0\0\87\a\0\0×|Ŧ¤\ 1\0\0\0\0\0\0/\0\0\0src/Composer/DependencyResolver/Transaction.phpÔ\13\0\0\87\13\0\0\99\8d^G¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Downloader/ArchiveDownloader.phpÁ      \0\0\87`Á \0\0ÖÞw7¤\ 1\0\0\0\0\0\01\0\0\0src/Composer/Downloader/ChangeReportInterface.phpÌ\0\0\0\87\0\0\0¯à¨¿¤\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Downloader/DownloadManager.php_\15\0\0\87`_\15\0\0\fóøþ¤\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Downloader/DownloaderInterface.phpÊ\ 1\0\0\87\ 1\0\0gs!l¤\ 1\0\0\0\0\0\03\0\0\0src/Composer/Downloader/DvcsDownloaderInterface.phpÑ\0\0\0\87\0\0\0\9c¿¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Downloader/FileDownloader.php>\1c\0\0\87`>\1c\0\0tÀU\98¤\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Downloader/FilesystemException.php
36 \ 1\0\0\87`
37 \ 1\0\0.-\1e\8b¤\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Downloader/FossilDownloader.php\89\v\0\0\87`\89\v\0\0È¢ñç¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Downloader/GitDownloader.php\ 37\0\0\87`\ 37\0\0âh#Ȥ\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Downloader/GzipDownloader.phpó\ 6\0\0\87\ 6\0\0Í\11y\86¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Downloader/HgDownloader.php \b\0\0\87\b\0\0ß`\9aö¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Downloader/PathDownloader.phpJ\15\0\0\87`J\15\0\0)4\ 4פ\ 1\0\0\0\0\0\00\0\0\0src/Composer/Downloader/PearPackageExtractor.phpq\e\0\0\87`q\e\0\0y5+\ 5¤\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Downloader/PerforceDownloader.php\9e\a\0\0\87`\9e\a\0\0Öüñ9¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Downloader/PharDownloader.phpä\0\0\0\87\0\0\0B"2(¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Downloader/RarDownloader.php\9f\a\0\0\87`\9f\a\0\0\19\e\19\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Downloader/SvnDownloader.phpN\14\0\0\87`N\14\0\0 â\97\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Downloader/TarDownloader.phpâ\0\0\0\87\0\0\0\ 4+«r¤\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Downloader/TransportException.php=\ 2\0\0\87`=\ 2\0\0ZÎÈÞ¤\ 1\0\0\0\0\0\09\0\0\0src/Composer/Downloader/VcsCapableDownloaderInterface.phpÔ\0\0\0\87\0\0\0`§ôö¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Downloader/VcsDownloader.php\98\16\0\0\87`\98\16\0\0ö\9f\86\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Downloader/XzDownloader.php§\ 4\0\0\87\ 4\0\0W$;á¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Downloader/ZipDownloader.phpx\15\0\0\87`x\15\0\0\82MÚH¤\ 1\0\0\0\0\0\0&\0\0\0src/Composer/EventDispatcher/Event.php \ 2\0\0\87\ 2\0\0±\99jï¤\ 1\0\0\0\0\0\00\0\0\0src/Composer/EventDispatcher/EventDispatcher.phpL7\0\0\87`L7\0\0+[¸\8c¤\ 1\0\0\0\0\0\09\0\0\0src/Composer/EventDispatcher/EventSubscriberInterface.php©\0\0\0\87\0\0\0\ 1\ 1\0\0\0\0\0\09\0\0\0src/Composer/EventDispatcher/ScriptExecutionException.phpv\0\0\0\87`v\0\0\0wZ8S¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Exception/NoSslException.phpf\0\0\0\87`f\0\0\0ËíM\9d¤\ 1\0\0\0\0\0\0\18\0\0\0src/Composer/Factory.php#>\0\0\87`#>\0\0\ 2^¡4¤\ 1\0\0\0\0\0\0\1a\0\0\0src/Composer/IO/BaseIO.php\99\12\0\0\87`\99\12\0\0Y\85%\f¤\ 1\0\0\0\0\0\0\1c\0\0\0src/Composer/IO/BufferIO.php½\ 6\0\0\87\ 6\0\0*Äx\87¤\ 1\0\0\0\0\0\0\1d\0\0\0src/Composer/IO/ConsoleIO.php\11\19\0\0\87`\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\87\ 5\0\0\0Õ\9d\ e¤\ 1\0\0\0\0\0\0\1a\0\0\0src/Composer/IO/NullIO.phpÀ\ 4\0\0\87\ 4\0\0F`sʤ\ 1\0\0\0\0\0\0\1a\0\0\0src/Composer/Installer.phpD£\0\0\87`D£\0\0\10{¶Ï¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Installer/BinaryInstaller.php\ 1\12\0\0\87`\ 1\12\0\0a·Á\10¤\ 1\0\0\0\0\0\02\0\0\0src/Composer/Installer/BinaryPresenceInterface.phpË\0\0\0\87\0\0\0À5\9a¨¤\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Installer/InstallationManager.php*\17\0\0\87`*\17\0\0Í\96\85ª¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Installer/InstallerEvent.php\ e\ 6\0\0\87`\ e\ 6\0\0lÔzi¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Installer/InstallerEvents.phpÞ\0\0\0\87\0\0\0ì\9f@G¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Installer/InstallerInterface.phpã\ 2\0\0\87\ 2\0\0^\83\93ʤ\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Installer/LibraryInstaller.php"\14\0\0\87`"\14\0\0?¦@¬¤\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Installer/MetapackageInstaller.phpÊ\a\0\0\87\a\0\0Ùti·¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Installer/NoopInstaller.php+\ 5\0\0\87`+\ 5\0\0À·M}¤\ 1\0\0\0\0\0\0'\0\0\0src/Composer/Installer/PackageEvent.phpe\ 3\0\0\87`e\ 3\0\0;° \1a¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Installer/PackageEvents.php¸\ 1\0\0\87\ 1\0\0dbØs¤\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Installer/PearBinaryInstaller.phpø\f\0\0\87\f\0\0\95\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Installer/PearInstaller.php¢\a\0\0\87\a\0\0È\82¶Ñ¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Installer/PluginInstaller.php¡\ 6\0\0\87\ 6\0\0¤õÏܤ\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Installer/ProjectInstaller.php\1d\ 6\0\0\87`\1d\ 6\0\0*0@P¤\ 1\0\0\0\0\0\04\0\0\0src/Composer/Installer/SuggestedPackagesReporter.php:\a\0\0\87`:\a\0\0\82´UV¤\ 1\0\0\0\0\0\0\1e\0\0\0src/Composer/Json/JsonFile.phpJ\15\0\0\87`J\15\0\0\8a\ 1\0\0\0\0\0\0#\0\0\0src/Composer/Json/JsonFormatter.phpW\ 6\0\0\87`W\ 6\0\0uüb\8c¤\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Json/JsonManipulator.phpv4\0\0\87`v4\0\0\18­¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Json/JsonValidationException.php\\ 1\0\0\87`\\ 1\0\0.Xóܤ\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Package/AliasPackage.phpí\17\0\0\87\17\0\0\98J¸X¤\ 1\0\0\0\0\0\07\0\0\0src/Composer/Package/Archiver/ArchivableFilesFilter.php    \ 2\0\0\87\ 2\0\0yY+¦¤\ 1\0\0\0\0\0\07\0\0\0src/Composer/Package/Archiver/ArchivableFilesFinder.phpæ\ 5\0\0\87\ 5\0\0U`\eƤ\ 1\0\0\0\0\0\00\0\0\0src/Composer/Package/Archiver/ArchiveManager.phpÕ\f\0\0\87\f\0\0q^Z\90¤\ 1\0\0\0\0\0\03\0\0\0src/Composer/Package/Archiver/ArchiverInterface.php\a\ 1\0\0\87`\a\ 1\0\0ñ´>\v¤\ 1\0\0\0\0\0\03\0\0\0src/Composer/Package/Archiver/BaseExcludeFilter.php\96\ 6\0\0\87`\96\ 6\0\0v,ÝФ\ 1\0\0\0\0\0\07\0\0\0src/Composer/Package/Archiver/ComposerExcludeFilter.php\1f\ 1\0\0\87`\1f\ 1\0\0\8bSZ0¤\ 1\0\0\0\0\0\02\0\0\0src/Composer/Package/Archiver/GitExcludeFilter.phpr\ 3\0\0\87`r\ 3\0\03\91Mh¤\ 1\0\0\0\0\0\01\0\0\0src/Composer/Package/Archiver/HgExcludeFilter.php
38 \ 5\0\0\87`
39 \ 5\0\0&ðm(¤\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Package/Archiver/PharArchiver.php8\ 6\0\0\87`8\ 6\0\0Fx'M¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Package/Archiver/ZipArchiver.phpX\ 5\0\0\87`X\ 5\0\0¤k\9d\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Package/BasePackage.php\b\ e\0\0\87`\b\ e\0\0r\97F«¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Package/Comparer/Comparer.php½\b\0\0\87\b\0\0¡fK}¤\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Package/CompletePackage.php¦\a\0\0\87\a\0\0p[\ 3Ö¤\ 1\0\0\0\0\0\01\0\0\0src/Composer/Package/CompletePackageInterface.php\e\ 2\0\0\87`\e\ 2\0\0Î\12«>¤\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Package/Dumper/ArrayDumper.phpb\f\0\0\87`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\87`\88\ 5\0\0å¶Y«¤\ 1\0\0\0\0\0\07\0\0\0src/Composer/Package/LinkConstraint/EmptyConstraint.php\82\ 1\0\0\87`\82\ 1\0\0\ eé~\8b¤\ 1\0\0\0\0\0\0?\0\0\0src/Composer/Package/LinkConstraint/LinkConstraintInterface.phpd\ 1\0\0\87`d\ 1\0\0¤ôLn¤\ 1\0\0\0\0\0\07\0\0\0src/Composer/Package/LinkConstraint/MultiConstraint.php\82\ 1\0\0\87`\82\ 1\0\0ób`ý¤\ 1\0\0\0\0\0\0:\0\0\0src/Composer/Package/LinkConstraint/SpecificConstraint.phpi\ 1\0\0\87`i\ 1\0\0Þ\94\9a\ 1\0\0\0\0\0\09\0\0\0src/Composer/Package/LinkConstraint/VersionConstraint.phpX\ 1\0\0\87`X\ 1\0\0\ 2}`y¤\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Package/Loader/ArrayLoader.phpô\1e\0\0\87\1e\0\0\11h°ª¤\ 1\0\0\0\0\0\07\0\0\0src/Composer/Package/Loader/InvalidPackageException.phpE\ 2\0\0\87`E\ 2\0\0xb\13¾¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Package/Loader/JsonLoader.phpù\ 1\0\0\87\ 1\0\0!~\88\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Package/Loader/LoaderInterface.php²\0\0\0\87\0\0\0¦}úΤ\ 1\0\0\0\0\0\01\0\0\0src/Composer/Package/Loader/RootPackageLoader.phpÆ\1a\0\0\87\1a\0\0\99£ã\9b¤\ 1\0\0\0\0\0\05\0\0\0src/Composer/Package/Loader/ValidatingArrayLoader.phpâA\0\0\87`âA\0\0\1c\91É\98¤\ 1\0\0\0\0\0\0\1f\0\0\0src/Composer/Package/Locker.php\11#\0\0\87`\11#\0\0»ÀÎí¤\ 1\0\0\0\0\0\0 \0\0\0src/Composer/Package/Package.phpÉ\1a\0\0\87\1a\0\0\8f\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Package/PackageInterface.php\\b\0\0\87`\\b\0\0xåp¨¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Package/RootAliasPackage.php\1f        \0\0\87`\1f \0\0      _\80ø¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Package/RootPackage.php\11\ 5\0\0\87`\11\ 5\0\0\ 2\8eÎ_¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Package/RootPackageInterface.php¹\ 3\0\0\87\ 3\0\0"maV¤\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Package/Version/VersionGuesser.phpÏ#\0\0\87`Ï#\0\0@»å'¤\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Package/Version/VersionParser.php¥\ 5\0\0\87\ 5\0\0ô´\16à¤\ 1\0\0\0\0\0\00\0\0\0src/Composer/Package/Version/VersionSelector.php\9a\ e\0\0\87`\9a\ e\0\0ô¥×¥¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Plugin/Capability/Capability.phpW\0\0\0\87`W\0\0\0æ_¨1¤\ 1\0\0\0\0\0\02\0\0\0src/Composer/Plugin/Capability/CommandProvider.php\97\0\0\0\87`\97\0\0\0ûOâ>¤\ 1\0\0\0\0\0\0\1f\0\0\0src/Composer/Plugin/Capable.php\7f\0\0\0\87`\7f\0\0\0Æq\15\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Plugin/CommandEvent.phpâ\ 2\0\0\87\ 2\0\0³ÆÇW¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Plugin/PluginEvents.phpö\0\0\0\87\0\0\0á1=z¤\ 1\0\0\0\0\0\0'\0\0\0src/Composer/Plugin/PluginInterface.phpô\0\0\0\87\0\0\0)'*ؤ\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Plugin/PluginManager.php¨$\0\0\87`¨$\0\03 :\90¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Plugin/PreCommandRunEvent.phpõ\ 1\0\0\87\ 1\0\0:ðd\1e¤\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Plugin/PreFileDownloadEvent.php`\ 2\0\0\87``\ 2\0\0\09-Τ\ 1\0\0\0\0\0\04\0\0\0src/Composer/Question/StrictConfirmationQuestion.php\1e\ 5\0\0\87`\1e\ 5\0\0'.³è¤\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Repository/ArrayRepository.php©\ e\0\0\87\ e\0\0Â\92/Ƥ\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Repository/ArtifactRepository.phpí\b\0\0\87\b\0\0q9OS¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Repository/BaseRepository.phpU\10\0\0\87`U\10\0\0{<\9f\16¤\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Repository/ComposerRepository.php5U\0\0\87`5U\0\0¾øU&¤\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Repository/CompositeRepository.php;\b\0\0\87`;\b\0\0¤¯S\1f¤\ 1\0\0\0\0\0\0;\0\0\0src/Composer/Repository/ConfigurableRepositoryInterface.php\85\0\0\0\87`\85\0\0\0±\9f_\1c¤\ 1\0\0\0\0\0\00\0\0\0src/Composer/Repository/FilesystemRepository.phpo\ 5\0\0\87`o\ 5\0\0åè¼\9e¤\ 1\0\0\0\0\0\04\0\0\0src/Composer/Repository/InstalledArrayRepository.php£\0\0\0\87\0\0\0/ö~>¤\ 1\0\0\0\0\0\09\0\0\0src/Composer/Repository/InstalledFilesystemRepository.php£\0\0\0\87\0\0\0V
40 \95\ 1\0\0\0\0\0\08\0\0\0src/Composer/Repository/InstalledRepositoryInterface.php\87\0\0\0\87`\87\0\0\0\18£9p¤\ 1\0\0\0\0\0\06\0\0\0src/Composer/Repository/InvalidRepositoryException.phpn\0\0\0\87`n\0\0\0à\93ë\98¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Repository/PackageRepository.phpi\ 3\0\0\87`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\87\ f\0\0ÐU\91\ 1\0\0\0\0\0\02\0\0\0src/Composer/Repository/Pear/BaseChannelReader.phpH\ 5\0\0\87`H\ 5\0\0\vÁÚ\8b¤\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Repository/Pear/ChannelInfo.phpÄ\ 1\0\0\87\ 1\0\0:T*ɤ\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Repository/Pear/ChannelReader.phpë\ 6\0\0\87\ 6\0\0åÄLi¤\ 1\0\0\0\0\0\04\0\0\0src/Composer/Repository/Pear/ChannelRest10Reader.php®        \0\0\87`® \0\0\99ÖÛú¤\ 1\0\0\0\0\0\04\0\0\0src/Composer/Repository/Pear/ChannelRest11Reader.php& \0\0\87`& \0\0òUb\b¤\ 1\0\0\0\0\0\05\0\0\0src/Composer/Repository/Pear/DependencyConstraint.phpq\ 2\0\0\87`q\ 2\0\09\ e\17\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Repository/Pear/DependencyInfo.phpq\ 1\0\0\87`q\ 1\0\0fºTò¤\ 1\0\0\0\0\0\08\0\0\0src/Composer/Repository/Pear/PackageDependencyParser.php\83\16\0\0\87`\83\16\0\0ð\90\93\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Repository/Pear/PackageInfo.php°\ 3\0\0\87\ 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\87`\92\ 1\0\0o\93\8aä\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Repository/PearRepository.php¥\16\0\0\87\16\0\0ç\ f|5¤\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Repository/PlatformRepository.php)!\0\0\87`)!\0\0À(\87ߤ\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Repository/RepositoryFactory.phpa\13\0\0\87`a\13\0\0lÂéÔ¤\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Repository/RepositoryInterface.phpÛ\ 1\0\0\87\ 1\0\0\92\11âÁ¤\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Repository/RepositoryManager.phpM\v\0\0\87`M\v\0\0<(;\8c¤\ 1\0\0\0\0\0\07\0\0\0src/Composer/Repository/RepositorySecurityException.phpo\0\0\0\87`o\0\0\0pÕ«ª¤\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Repository/Vcs/BitbucketDriver.php~ \0\0\87`~ \0\0Ebºå¤\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Repository/Vcs/FossilDriver.php´\13\0\0\87\13\0\0Å\ 2\86\ 1\0\0\0\0\0\02\0\0\0src/Composer/Repository/Vcs/GitBitbucketDriver.phpë\ 5\0\0\87\ 5\0\0\9c´½X¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Repository/Vcs/GitDriver.phpÉ\13\0\0\87\13\0\0Æ\11\96\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Repository/Vcs/GitHubDriver.php\834\0\0\87`\834\0\0:0G\b¤\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Repository/Vcs/GitLabDriver.php}*\0\0\87`}*\0\0d\8fer¤\ 1\0\0\0\0\0\01\0\0\0src/Composer/Repository/Vcs/HgBitbucketDriver.phpå\ 5\0\0\87\ 5\0\0@)\89\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Repository/Vcs/HgDriver.phpB\12\0\0\87`B\12\0\0\19IO\8c¤\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Repository/Vcs/PerforceDriver.phpù        \0\0\87`ù \0\0&½tÙ¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Repository/Vcs/SvnDriver.php\9e\1c\0\0\87`\9e\1c\0\0â]Ñ\98¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Repository/Vcs/VcsDriver.phpæ
41 \0\0\87
42 \0\0eׯ-¤\ 1\0\0\0\0\0\02\0\0\0src/Composer/Repository/Vcs/VcsDriverInterface.php÷\ 2\0\0\87\ 2\0\0ÇX[\89¤\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Repository/VcsRepository.php\8e-\0\0\87`\8e-\0\0÷ï\rì¤\ 1\0\0\0\0\0\01\0\0\0src/Composer/Repository/VersionCacheInterface.php\94\0\0\0\87`\94\0\0\0A?Rï¤\ 1\0\0\0\0\0\03\0\0\0src/Composer/Repository/WritableArrayRepository.php\r\ 3\0\0\87`\r\ 3\0\0¤3¶¢¤\ 1\0\0\0\0\0\07\0\0\0src/Composer/Repository/WritableRepositoryInterface.php\89\ 1\0\0\87`\89\ 1\0\0\91/sï¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Script/CommandEvent.phpW\0\0\0\87`W\0\0\0£VZt¤\ 1\0\0\0\0\0\0\1d\0\0\0src/Composer/Script/Event.phpº\ 4\0\0\87\ 4\0\0ò\9d»¤¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Script/PackageEvent.php\9c\0\0\0\87`\9c\0\0\0§ÿÉ\r¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Script/ScriptEvents.phpP\ 4\0\0\87`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\87`\9c\ 1\0\0ze\83\8e¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/SelfUpdate/Versions.phpH\a\0\0\87`H\a\0\0c\vlB¤\ 1\0\0\0\0\0\0 \0\0\0src/Composer/Util/AuthHelper.phpË\ 3\0\0\87\ 3\0\0>zx\96¤\ 1\0\0\0\0\0\0\1f\0\0\0src/Composer/Util/Bitbucket.php%\15\0\0\87`%\15\0\0N,vÕ¤\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Util/ComposerMirror.php±\ 4\0\0\87\ 4\0\0­½øؤ\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Util/ConfigValidator.phpà\15\0\0\87\15\0\0¯º`\97¤\ 1\0\0\0\0\0\0"\0\0\0src/Composer/Util/ErrorHandler.phpº\ 4\0\0\87\ 4\0\0\14ª\17\13¤\ 1\0\0\0\0\0\0 \0\0\0src/Composer/Util/Filesystem.php`/\0\0\87``/\0\0ÓJ\89\ 1\0\0\0\0\0\0\19\0\0\0src/Composer/Util/Git.phpø0\0\0\87`ø0\0\0Zð\     ¤\ 1\0\0\0\0\0\0\1c\0\0\0src/Composer/Util/GitHub.phpz\r\0\0\87`z\r\0\0\13\f!Ò¤\ 1\0\0\0\0\0\0\1c\0\0\0src/Composer/Util/GitLab.phpó\ e\0\0\87\ e\0\0^\1e  '¤\ 1\0\0\0\0\0\0\18\0\0\0src/Composer/Util/Hg.php¼\a\0\0\87\a\0\0\83]\18\ 1\0\0\0\0\0\0\1f\0\0\0src/Composer/Util/IniHelper.phph\ 2\0\0\87`h\ 2\0\0;F\b\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Util/NoProxyPattern.phpr\14\0\0\87`r\14\0\0\e\9c´R¤\ 1\0\0\0\0\0\0#\0\0\0src/Composer/Util/PackageSorter.phpÜ\ 5\0\0\87\ 5\0\0w\88Ôâ¤\ 1\0\0\0\0\0\0\1e\0\0\0src/Composer/Util/Perforce.php¶2\0\0\87`¶2\0\0ßÑvT¤\ 1\0\0\0\0\0\0\1e\0\0\0src/Composer/Util/Platform.phpû\ 4\0\0\87\ 4\0\0ñ®\8f\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Util/ProcessExecutor.php±\r\0\0\87\r\0\0\e\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Util/RemoteFilesystem.phpRr\0\0\87`Rr\0\0à¹\96\10¤\ 1\0\0\0\0\0\0\1e\0\0\0src/Composer/Util/Silencer.phpè\ 2\0\0\87\ 2\0\0¿5ѳ¤\ 1\0\0\0\0\0\0!\0\0\0src/Composer/Util/SpdxLicense.php\ 3\ 1\0\0\87`\ 3\ 1\0\0¾7
43 ñ¤\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Util/StreamContextFactory.phpú\ f\0\0\87\ f\0\00K\9a\ 1\0\0\0\0\0\0\19\0\0\0src/Composer/Util/Svn.php'\14\0\0\87`'\14\0\0ôS,,¤\ 1\0\0\0\0\0\0\1f\0\0\0src/Composer/Util/TlsHelper.phpH
44 \0\0\87`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\87`\9e\a\0\0qµkQ¤\ 1\0\0\0\0\0\0\19\0\0\0src/Composer/Util/Zip.php¯\ 5\0\0\87\ 5\0\0ti¸Î¤\ 1\0\0\0\0\0\0\1e\0\0\0src/Composer/XdebugHandler.phpð\ 1\0\0\87\ 1\0\0zÓf~¤\ 1\0\0\0\0\0\0\11\0\0\0src/bootstrap.php¹\ 1\0\0\87\ 1\0\0\15I}\9c¤\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Autoload/ClassLoader.php¡4\0\0\87`¡4\0\0Þs\85\ 1\0\0\0\0\0\0#\0\0\0res/composer-repository-schema.jsonð\ f\0\0\87\ f\0\0\81GÐà¤\ 1\0\0\0\0\0\0\18\0\0\0res/composer-schema.jsonM\9d\0\0\87`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\87\v\0\0Â4DC¤\ 1\0\0\0\0\0\04\0\0\0vendor/composer/spdx-licenses/res/spdx-licenses.jsonu°\0\0\87`u°\0\0\9bý\85\ 1\0\0\0\0\0\04\0\0\0vendor/symfony/console/Resources/bin/hiddeninput.exe\0$\0\0\87`\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\87`?\ 3\0\0ò\16ï ¤\ 1\0\0\0\0\0\0&\0\0\0vendor/symfony/console/Application.php+X\0\0\87`+X\0\0«­yX¤\ 1\0\0\0\0\0\0*\0\0\0vendor/symfony/console/Command/Command.phpä"\0\0\87`ä"\0\0\90¤Ê¤\ 1\0\0\0\0\0\0.\0\0\0vendor/symfony/console/Command/HelpCommand.phpØ\a\0\0\87\a\0\0¦Ú-:¤\ 1\0\0\0\0\0\0.\0\0\0vendor/symfony/console/Command/ListCommand.phpZ\b\0\0\87`Z\b\0\0»w\ 4\ 1\0\0\0\0\0\0(\0\0\0vendor/symfony/console/ConsoleEvents.phpé\0\0\0\87\0\0\0RÛÔe¤\ 1\0\0\0\0\0\0<\0\0\0vendor/symfony/console/Descriptor/ApplicationDescription.phpÏ\b\0\0\87\b\0\0<\8eUî¤\ 1\0\0\0\0\0\00\0\0\0vendor/symfony/console/Descriptor/Descriptor.php\8f\a\0\0\87`\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\87\0\0\0±Q\aµ¤\ 1\0\0\0\0\0\04\0\0\0vendor/symfony/console/Descriptor/JsonDescriptor.phpÜ\r\0\0\87\r\0\0\9dɤ\ 1\0\0\0\0\0\08\0\0\0vendor/symfony/console/Descriptor/MarkdownDescriptor.php¶\ e\0\0\87\ e\0\0·Ô;ݤ\ 1\0\0\0\0\0\04\0\0\0vendor/symfony/console/Descriptor/TextDescriptor.php·\1e\0\0\87\1e\0\0c\93q\80¤\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/console/Descriptor/XmlDescriptor.php\ 1\1c\0\0\87`\ 1\1c\0\0\7fb{<¤\ 1\0\0\0\0\0\04\0\0\0vendor/symfony/console/Event/ConsoleCommandEvent.php°\ 1\0\0\87\ 1\0\0\a!\0Ȥ\ 1\0\0\0\0\0\0-\0\0\0vendor/symfony/console/Event/ConsoleEvent.phpÅ\ 2\0\0\87\ 2\0\0ÒxÛ\¤\ 1\0\0\0\0\0\06\0\0\0vendor/symfony/console/Event/ConsoleExceptionEvent.php\12\ 3\0\0\87`\12\ 3\0\0á\162é¤\ 1\0\0\0\0\0\06\0\0\0vendor/symfony/console/Event/ConsoleTerminateEvent.phpz\ 2\0\0\87`z\ 2\0\0³,îL¤\ 1\0\0\0\0\0\0=\0\0\0vendor/symfony/console/Exception/CommandNotFoundException.phpÔ\ 1\0\0\87\ 1\0\0È÷ L¤\ 1\0\0\0\0\0\07\0\0\0vendor/symfony/console/Exception/ExceptionInterface.phpf\0\0\0\87`f\0\0\0¡ABª¤\ 1\0\0\0\0\0\0=\0\0\0vendor/symfony/console/Exception/InvalidArgumentException.php¦\0\0\0\87\0\0\0Ö̽Z¤\ 1\0\0\0\0\0\0;\0\0\0vendor/symfony/console/Exception/InvalidOptionException.php¦\0\0\0\87\0\0\0\13Ë×H¤\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/console/Exception/LogicException.php\92\0\0\0\87`\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\87`\96\0\0\0Ùí,6¤\ 1\0\0\0\0\0\04\0\0\0vendor/symfony/console/Formatter/OutputFormatter.php3\ e\0\0\87`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\87`\8c\ 1\0\0òññÀ¤\ 1\0\0\0\0\0\09\0\0\0vendor/symfony/console/Formatter/OutputFormatterStyle.phpF\10\0\0\87`F\10\0\0\1d𦴤\ 1\0\0\0\0\0\0B\0\0\0vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php\84\ 1\0\0\87`\84\ 1\0\0÷½\10\ 1\0\0\0\0\0\0>\0\0\0vendor/symfony/console/Formatter/OutputFormatterStyleStack.php@\ 5\0\0\87`@\ 5\0\0G¨ýU¤\ 1\0\0\0\0\0\06\0\0\0vendor/symfony/console/Helper/DebugFormatterHelper.phpy\b\0\0\87`y\b\0\0Ì8ÆФ\ 1\0\0\0\0\0\02\0\0\0vendor/symfony/console/Helper/DescriptorHelper.phpw\ 5\0\0\87`w\ 5\0\0\ 1\ 1\0\0\0\0\0\0.\0\0\0vendor/symfony/console/Helper/DialogHelper.phpð\1e\0\0\87\1e\0\0ÔÈ\16\ 1\0\0\0\0\0\01\0\0\0vendor/symfony/console/Helper/FormatterHelper.phpd\ 4\0\0\87`d\ 4\0\0§×,¸¤\ 1\0\0\0\0\0\0(\0\0\0vendor/symfony/console/Helper/Helper.php©\a\0\0\87\a\0\0Õ'\83±¤\ 1\0\0\0\0\0\01\0\0\0vendor/symfony/console/Helper/HelperInterface.phpå\0\0\0\87\0\0\0\1f\8a \18¤\ 1\0\0\0\0\0\0+\0\0\0vendor/symfony/console/Helper/HelperSet.phpÊ\a\0\0\87\a\0\0áÏW"¤\ 1\0\0\0\0\0\02\0\0\0vendor/symfony/console/Helper/InputAwareHelper.phpc\ 1\0\0\87`c\ 1\0\0\ 6Ìø\83¤\ 1\0\0\0\0\0\0/\0\0\0vendor/symfony/console/Helper/ProcessHelper.phpÓ       \0\0\87`Ó \0\0©w\82\ 1\0\0\0\0\0\0-\0\0\0vendor/symfony/console/Helper/ProgressBar.phpc%\0\0\87`c%\0\0C\e&w¤\ 1\0\0\0\0\0\00\0\0\0vendor/symfony/console/Helper/ProgressHelper.phpY\e\0\0\87`Y\e\0\0R!\8f\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/console/Helper/ProgressIndicator.phpM\14\0\0\87`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\87`[\1d\0\0¯6}ñ¤\ 1\0\0\0\0\0\07\0\0\0vendor/symfony/console/Helper/SymfonyQuestionHelper.php\95
46 \0\0\87`\95
47 \0\0\0]~R¤\ 1\0\0\0\0\0\0'\0\0\0vendor/symfony/console/Helper/Table.php¼*\0\0\87`¼*\0\0fêý!¤\ 1\0\0\0\0\0\0+\0\0\0vendor/symfony/console/Helper/TableCell.php\80\ 3\0\0\87`\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\87`\ e\f\0\0\9b\99¤\ 1\0\0\0\0\0\00\0\0\0vendor/symfony/console/Helper/TableSeparator.phpÊ\0\0\0\87\0\0\0az\1f\1c¤\ 1\0\0\0\0\0\0,\0\0\0vendor/symfony/console/Helper/TableStyle.php 
48 \0\0\87
49 \0\0_ÍI"¤\ 1\0\0\0\0\0\0*\0\0\0vendor/symfony/console/Input/ArgvInput.php\ 1\16\0\0\87`\ 1\16\0\0ªèB-¤\ 1\0\0\0\0\0\0+\0\0\0vendor/symfony/console/Input/ArrayInput.php)\v\0\0\87`)\v\0\0¥Ñ\ 6\ 1\0\0\0\0\0\0&\0\0\0vendor/symfony/console/Input/Input.php£\v\0\0\87\v\0\0\13f¡?¤\ 1\0\0\0\0\0\0.\0\0\0vendor/symfony/console/Input/InputArgument.php\12\ 6\0\0\87`\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\87`\98\0\0\0­\ fO°¤\ 1\0\0\0\0\0\00\0\0\0vendor/symfony/console/Input/InputDefinition.php\86\19\0\0\87`\86\19\0\0¤U)¤¤\ 1\0\0\0\0\0\0/\0\0\0vendor/symfony/console/Input/InputInterface.php£\ 3\0\0\87\ 3\0\0ÆB\8c\ 1\0\0\0\0\0\0,\0\0\0vendor/symfony/console/Input/InputOption.php\14\f\0\0\87`\14\f\0\0\¢Ü=¤\ 1\0\0\0\0\0\0,\0\0\0vendor/symfony/console/Input/StringInput.php\99\ 6\0\0\87`\99\ 6\0\0{\8a\9cþ¤\ 1\0\0\0\0\0\0\1e\0\0\0vendor/symfony/console/LICENSE)\ 4\0\0\87`)\ 4\0\0NUN½¤\ 1\0\0\0\0\0\0/\0\0\0vendor/symfony/console/Logger/ConsoleLogger.php-    \0\0\87`- \0\0ghT\9b¤\ 1\0\0\0\0\0\00\0\0\0vendor/symfony/console/Output/BufferedOutput.php_\ 1\0\0\87`_\ 1\0\0\8b >P¤\ 1\0\0\0\0\0\0/\0\0\0vendor/symfony/console/Output/ConsoleOutput.php±\a\0\0\87\a\0\0nì!f¤\ 1\0\0\0\0\0\08\0\0\0vendor/symfony/console/Output/ConsoleOutputInterface.phpà\0\0\0\87\0\0\0\87\86Æʤ\ 1\0\0\0\0\0\0,\0\0\0vendor/symfony/console/Output/NullOutput.phpÉ\ 3\0\0\87\ 3\0\0\990ïf¤\ 1\0\0\0\0\0\0(\0\0\0vendor/symfony/console/Output/Output.php\98  \0\0\87`\98 \0\00p\ 4\b¤\ 1\0\0\0\0\0\01\0\0\0vendor/symfony/console/Output/OutputInterface.php\17\ 3\0\0\87`\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\87`\9b\ 6\0\0.¡îî¤\ 1\0\0\0\0\0\02\0\0\0vendor/symfony/console/Question/ChoiceQuestion.phpv
50 \0\0\87`v
51 \0\0\8b²WP¤\ 1\0\0\0\0\0\08\0\0\0vendor/symfony/console/Question/ConfirmationQuestion.phpè\ 2\0\0\87\ 2\0\0/\1dÔ\8f¤\ 1\0\0\0\0\0\0,\0\0\0vendor/symfony/console/Question/Question.phpΠ    \0\0\87`Π\0\0lF\ f\10¤\ 1\0\0\0\0\0\0 \0\0\0vendor/symfony/console/Shell.phpã\ f\0\0\87\ f\0\0\89Á\8eå¤\ 1\0\0\0\0\0\0,\0\0\0vendor/symfony/console/Style/OutputStyle.php\\ 5\0\0\87`\\ 5\0\0wפ\ 4¤\ 1\0\0\0\0\0\0/\0\0\0vendor/symfony/console/Style/StyleInterface.phpÏ\ 3\0\0\87\ 3\0\0&nÅѤ\ 1\0\0\0\0\0\0-\0\0\0vendor/symfony/console/Style/SymfonyStyle.phpÛ\1f\0\0\87\1f\0\0§ðcä¤\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/console/Tester/ApplicationTester.phpÏ\ 5\0\0\87\ 5\0\0s\9e9i¤\ 1\0\0\0\0\0\0/\0\0\0vendor/symfony/console/Tester/CommandTester.php¨\ 6\0\0\87\ 6\0\0\7f<\9c\95¤\ 1\0\0\0\0\0\0(\0\0\0vendor/symfony/debug/BufferingLogger.phpt\ 1\0\0\87`t\ 1\0\0=\0hܤ\ 1\0\0\0\0\0\0\1e\0\0\0vendor/symfony/debug/Debug.php+\ 3\0\0\87`+\ 3\0\0.À=©¤\ 1\0\0\0\0\0\0)\0\0\0vendor/symfony/debug/DebugClassLoader.php°\1d\0\0\87\1d\0\0^æ*ñ¤\ 1\0\0\0\0\0\0%\0\0\0vendor/symfony/debug/ErrorHandler.phpýG\0\0\87`ýG\0\0¿zL\1d¤\ 1\0\0\0\0\0\09\0\0\0vendor/symfony/debug/Exception/ClassNotFoundException.php\96\ 1\0\0\87`\96\ 1\0\0i\89æô¤\ 1\0\0\0\0\0\08\0\0\0vendor/symfony/debug/Exception/ContextErrorException.php\98\ 1\0\0\87`\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\87`\ 2\ 1\0\0®+Ãê¤\ 1\0\0\0\0\0\06\0\0\0vendor/symfony/debug/Exception/FatalErrorException.php\f\a\0\0\87`\f\a\0\04ç$¤¤\ 1\0\0\0\0\0\06\0\0\0vendor/symfony/debug/Exception/FatalThrowableError.phpW\ 2\0\0\87`W\ 2\0\0?àèK¤\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/debug/Exception/FlattenException.php»\16\0\0\87\16\0\0+a&\11¤\ 1\0\0\0\0\0\07\0\0\0vendor/symfony/debug/Exception/OutOfMemoryException.php~\0\0\0\87`~\0\0\0ë¨oâ¤\ 1\0\0\0\0\0\0=\0\0\0vendor/symfony/debug/Exception/UndefinedFunctionException.php\9a\ 1\0\0\87`\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\87`\98\ 1\0\0nöêؤ\ 1\0\0\0\0\0\0)\0\0\0vendor/symfony/debug/ExceptionHandler.php$3\0\0\87`$3\0\0Eë×£¤\ 1\0\0\0\0\0\0I\0\0\0vendor/symfony/debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php5\12\0\0\87`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\87`\ 3\ 1\0\0ĹBV¤\ 1\0\0\0\0\0\0M\0\0\0vendor/symfony/debug/FatalErrorHandler/UndefinedFunctionFatalErrorHandler.phpx\b\0\0\87`x\b\0\0~ò"\7f¤\ 1\0\0\0\0\0\0K\0\0\0vendor/symfony/debug/FatalErrorHandler/UndefinedMethodFatalErrorHandler.phpN\ 5\0\0\87`N\ 5\0\0'\80³\88¤\ 1\0\0\0\0\0\0\1c\0\0\0vendor/symfony/debug/LICENSE)\ 4\0\0\87`)\ 4\0\0NUN½¤\ 1\0\0\0\0\0\0:\0\0\0vendor/symfony/filesystem/Exception/ExceptionInterface.phpi\0\0\0\87`i\0\0\0$ ÿ\9b¤\ 1\0\0\0\0\0\0=\0\0\0vendor/symfony/filesystem/Exception/FileNotFoundException.php¼\ 1\0\0\87\ 1\0\0pí\¶¤\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/filesystem/Exception/IOException.php\87\ 1\0\0\87`\87\ 1\0\0\80ü#Ѥ\ 1\0\0\0\0\0\0<\0\0\0vendor/symfony/filesystem/Exception/IOExceptionInterface.php¦\0\0\0\87\0\0\0jÙwM¤\ 1\0\0\0\0\0\0(\0\0\0vendor/symfony/filesystem/Filesystem.phpM4\0\0\87`M4\0\0ãz_\a¤\ 1\0\0\0\0\0\0!\0\0\0vendor/symfony/filesystem/LICENSE)\ 4\0\0\87`)\ 4\0\0NUN½¤\ 1\0\0\0\0\0\0)\0\0\0vendor/symfony/filesystem/LockHandler.phpò\ 5\0\0\87\ 5\0\0~3\9f\ 1\0\0\0\0\0\01\0\0\0vendor/symfony/finder/Adapter/AbstractAdapter.php\\v\0\0\87`\\v\0\0h\19\88\ 1\0\0\0\0\0\05\0\0\0vendor/symfony/finder/Adapter/AbstractFindAdapter.php\83\19\0\0\87`\83\19\0\0kM Þ¤\ 1\0\0\0\0\0\02\0\0\0vendor/symfony/finder/Adapter/AdapterInterface.php\9b\ 3\0\0\87`\9b\ 3\0\0M\aþ\e¤\ 1\0\0\0\0\0\00\0\0\0vendor/symfony/finder/Adapter/BsdFindAdapter.php2\a\0\0\87`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\87`\14\a\0\0¦äàO¤\ 1\0\0\0\0\0\0,\0\0\0vendor/symfony/finder/Adapter/PhpAdapter.phpô\a\0\0\87\a\0\0Þdè;¤\ 1\0\0\0\0\0\0/\0\0\0vendor/symfony/finder/Comparator/Comparator.php\8d\ 3\0\0\87`\8d\ 3\0\0¾ü\9cµ¤\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/finder/Comparator/DateComparator.php#\ 3\0\0\87`#\ 3\0\0\16°\1fΤ\ 1\0\0\0\0\0\05\0\0\0vendor/symfony/finder/Comparator/NumberComparator.php{\ 3\0\0\87`{\ 3\0\0\80ÚùY¤\ 1\0\0\0\0\0\09\0\0\0vendor/symfony/finder/Exception/AccessDeniedException.php\84\0\0\0\87`\84\0\0\0½¾s\9c¤\ 1\0\0\0\0\0\0;\0\0\0vendor/symfony/finder/Exception/AdapterFailureException.php¬\ 2\0\0\87\ 2\0\0w\1e\18\ 1\0\0\0\0\0\06\0\0\0vendor/symfony/finder/Exception/ExceptionInterface.php\84\0\0\0\87`\84\0\0\0\1cGz-¤\ 1\0\0\0\0\0\0A\0\0\0vendor/symfony/finder/Exception/OperationNotPermitedException.php)\ 1\0\0\87`)\ 1\0\0x\1f§e¤\ 1\0\0\0\0\0\0@\0\0\0vendor/symfony/finder/Exception/ShellCommandFailureException.phpº\ 2\0\0\87\ 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\87`\a\ 6\0\0i¥:Ť\ 1\0\0\0\0\0\0)\0\0\0vendor/symfony/finder/Expression/Glob.phpf\ 4\0\0\87`f\ 4\0\0DÞcj¤\ 1\0\0\0\0\0\0*\0\0\0vendor/symfony/finder/Expression/Regex.php\ 3\ f\0\0\87`\ 3\ f\0\0§;M)¤\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/finder/Expression/ValueInterface.phpÍ\ 1\0\0\87\ 1\0\0\p4\86¤\ 1\0\0\0\0\0\0 \0\0\0vendor/symfony/finder/Finder.phpc.\0\0\87`c.\0\0:\885g¤\ 1\0\0\0\0\0\0\1e\0\0\0vendor/symfony/finder/Glob.phpL\ 5\0\0\87`L\ 5\0\0jÍ9פ\ 1\0\0\0\0\0\07\0\0\0vendor/symfony/finder/Iterator/CustomFilterIterator.php]\ 2\0\0\87`]\ 2\0\0ÎoÅƤ\ 1\0\0\0\0\0\0:\0\0\0vendor/symfony/finder/Iterator/DateRangeFilterIterator.phpx\ 2\0\0\87`x\ 2\0\0\ fô\ 3\ 1\0\0\0\0\0\0;\0\0\0vendor/symfony/finder/Iterator/DepthRangeFilterIterator.phpî\ 1\0\0\87\ 1\0\0üÍ\9d\ 1\0\0\0\0\0\0A\0\0\0vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.phpí\ 5\0\0\87\ 5\0\0n\ 5õH¤\ 1\0\0\0\0\0\04\0\0\0vendor/symfony/finder/Iterator/FilePathsIterator.php#\ 6\0\0\87`#\ 6\0\0G?T½¤\ 1\0\0\0\0\0\09\0\0\0vendor/symfony/finder/Iterator/FileTypeFilterIterator.phpZ\ 2\0\0\87`Z\ 2\0\0(\1a&ø¤\ 1\0\0\0\0\0\0<\0\0\0vendor/symfony/finder/Iterator/FilecontentFilterIterator.php5\ 2\0\0\87`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\87`r\ 1\0\0t\b\1a\ 1\0\0\0\0\0\01\0\0\0vendor/symfony/finder/Iterator/FilterIterator.phpÂ\ 2\0\0\87\ 2\0\0\1c\8f㯤\ 1\0\0\0\0\0\0=\0\0\0vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php*\ 5\0\0\87`*\ 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\87\ 1\0\0\12\82\b\ 1\0\0\0\0\0\0=\0\0\0vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php\ f   \0\0\87`\ f \0\0O}Cä¤\ 1\0\0\0\0\0\0:\0\0\0vendor/symfony/finder/Iterator/SizeRangeFilterIterator.phpe\ 2\0\0\87`e\ 2\0\0\9f\92áé¤\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/finder/Iterator/SortableIterator.php+\ 6\0\0\87`+\ 6\0\0õÝË ¤\ 1\0\0\0\0\0\0\1d\0\0\0vendor/symfony/finder/LICENSE)\ 4\0\0\87`)\ 4\0\0NUN½¤\ 1\0\0\0\0\0\0'\0\0\0vendor/symfony/finder/Shell/Command.php>\v\0\0\87`>\v\0\0_~u\f¤\ 1\0\0\0\0\0\0%\0\0\0vendor/symfony/finder/Shell/Shell.phpq\ 4\0\0\87`q\ 4\0\0·Ó\8a\ 1\0\0\0\0\0\0%\0\0\0vendor/symfony/finder/SplFileInfo.php\ 6\ 3\0\0\87`\ 6\ 3\0\0þ\0íù¤\ 1\0\0\0\0\0\0'\0\0\0vendor/symfony/polyfill-ctype/Ctype.phpH   \0\0\87`H \0\0³\9dÕݤ\ 1\0\0\0\0\0\0%\0\0\0vendor/symfony/polyfill-ctype/LICENSE)\ 4\0\0\87`)\ 4\0\0´`e0¤\ 1\0\0\0\0\0\0+\0\0\0vendor/symfony/polyfill-ctype/bootstrap.phpú\ 4\0\0\87\ 4\0\0\15|p:¤\ 1\0\0\0\0\0\0(\0\0\0vendor/symfony/polyfill-mbstring/LICENSE)\ 4\0\0\87`)\ 4\0\0\1f\93\ª¤\ 1\0\0\0\0\0\0-\0\0\0vendor/symfony/polyfill-mbstring/Mbstring.php~G\0\0\87`~G\0\0úì¡T¤\ 1\0\0\0\0\0\0@\0\0\0vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php÷T\0\0\87`÷T\0\0ß2ª?¤\ 1\0\0\0\0\0\0F\0\0\0vendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.phpã\17\0\0\87\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\87`îU\0\0`þ8Q¤\ 1\0\0\0\0\0\0.\0\0\0vendor/symfony/polyfill-mbstring/bootstrap.php\ 3\e\0\0\87`\ 3\e\0\0\11þJ¾¤\ 1\0\0\0\0\0\07\0\0\0vendor/symfony/process/Exception/ExceptionInterface.phpf\0\0\0\87`f\0\0\0]ö>T¤\ 1\0\0\0\0\0\0=\0\0\0vendor/symfony/process/Exception/InvalidArgumentException.php¨\0\0\0\87\0\0\0ÐÀ+_¤\ 1\0\0\0\0\0\03\0\0\0vendor/symfony/process/Exception/LogicException.php\94\0\0\0\87`\94\0\0\0 ³ãñ¤\ 1\0\0\0\0\0\0;\0\0\0vendor/symfony/process/Exception/ProcessFailedException.phpx\ 3\0\0\87`x\ 3\0\0¨Ìzy¤\ 1\0\0\0\0\0\0=\0\0\0vendor/symfony/process/Exception/ProcessTimedOutException.php\1f\ 4\0\0\87`\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\87`\98\0\0\0¢\eØ:¤\ 1\0\0\0\0\0\0+\0\0\0vendor/symfony/process/ExecutableFinder.php\9c\ 4\0\0\87`\9c\ 4\0\0\1eçÁ̤\ 1\0\0\0\0\0\0\1e\0\0\0vendor/symfony/process/LICENSE)\ 4\0\0\87`)\ 4\0\0NUN½¤\ 1\0\0\0\0\0\0.\0\0\0vendor/symfony/process/PhpExecutableFinder.phpÍ\ 4\0\0\87\ 4\0\0í\ 50ã¤\ 1\0\0\0\0\0\0%\0\0\0vendor/symfony/process/PhpProcess.phpù\ 3\0\0\87\ 3\0\0c¶ßĤ\ 1\0\0\0\0\0\0.\0\0\0vendor/symfony/process/Pipes/AbstractPipes.php¸\a\0\0\87\a\0\0xÓ,§¤\ 1\0\0\0\0\0\0/\0\0\0vendor/symfony/process/Pipes/PipesInterface.phpD\ 1\0\0\87`D\ 1\0\0vØ\ 1\0\0\0\0\0\0*\0\0\0vendor/symfony/process/Pipes/UnixPipes.php7\b\0\0\87`7\b\0\0bÜp\84¤\ 1\0\0\0\0\0\0-\0\0\0vendor/symfony/process/Pipes/WindowsPipes.phpi\f\0\0\87`i\f\0\0Ó
53  Ä¤\ 1\0\0\0\0\0\0"\0\0\0vendor/symfony/process/Process.php R\0\0\87` R\0\0×Ó¥¹¤\ 1\0\0\0\0\0\0)\0\0\0vendor/symfony/process/ProcessBuilder.phpá
54 \0\0\87
55 \0\0ñ6I\95¤\ 1\0\0\0\0\0\0'\0\0\0vendor/symfony/process/ProcessUtils.phpJ\ 6\0\0\87`J\ 6\0\0\ 6{ñC¤\ 1\0\0\0\0\0\0\1c\0\0\0vendor/seld/jsonlint/LICENSE"\ 4\0\0\87`"\ 4\0\0a\83sy¤\ 1\0\0\0\0\0\0@\0\0\0vendor/seld/jsonlint/src/Seld/JsonLint/DuplicateKeyException.phpk\ 1\0\0\87`k\ 1\0\0Zù¶Ã¤\ 1\0\0\0\0\0\05\0\0\0vendor/seld/jsonlint/src/Seld/JsonLint/JsonParser.php62\0\0\87`62\0\0\1128ˤ\ 1\0\0\0\0\0\00\0\0\0vendor/seld/jsonlint/src/Seld/JsonLint/Lexer.php#\11\0\0\87`#\11\0\0Úá@,¤\ 1\0\0\0\0\0\0;\0\0\0vendor/seld/jsonlint/src/Seld/JsonLint/ParsingException.php%\ 1\0\0\87`%\ 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\87`>\0\0\0ÿq\9f\9f¤\ 1\0\0\0\0\0\0(\0\0\0vendor/justinrainbow/json-schema/LICENSE \ 4\0\0\87\ 4\0\0ºç\ 6©¤\ 1\0\0\0\0\0\0.\0\0\0vendor/justinrainbow/json-schema/demo/demo.phpñ\ 1\0\0\87\ 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\87`¡ \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\87`\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\87\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\87\ 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\87`\\ 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\87\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\87`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\87`\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\87\11\0\0%l¬ö¤\ 1\0\0\0\0\0\0P\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/SchemaConstraint.php& \0\0\87`& \0\078÷¬¤\ 1\0\0\0\0\0\0P\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/StringConstraint.phpz\ 4\0\0\87`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\87`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\87`\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\87`\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\87`\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\87`,"\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\87\ 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\87`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\87`\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\87`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\87`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\87`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\87`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\87\ 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\87`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\87`\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\87`\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\87`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\87`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\87\ 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\87\ 2\0\0f4÷³¤\ 1\0\0\0\0\0\0A\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/SchemaStorage.php\93\r\0\0\87`\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\87`\ 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\87\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\87\ 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\87\ 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\87`,\ 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\87\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\87`\ 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\87`@\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\87`\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\87`\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\87`s\ 5\0\0ßÁ\91\ 1\0\0\0\0\0\0%\0\0\0vendor/composer/spdx-licenses/LICENSE\1c\ 4\0\0\87`\1c\ 4\0\0\ 6Bhí¤\ 1\0\0\0\0\0\02\0\0\0vendor/composer/spdx-licenses/src/SpdxLicenses.phpH\14\0\0\87`H\14\0\0Í\89T\ 4¤\ 1\0\0\0\0\0\0\1e\0\0\0vendor/composer/semver/LICENSE\1c\ 4\0\0\87`\1c\ 4\0\0\ 6Bhí¤\ 1\0\0\0\0\0\0)\0\0\0vendor/composer/semver/src/Comparator.php\ 2\ 4\0\0\87`\ 2\ 4\0\0wl\83ï¤\ 1\0\0\0\0\0\0<\0\0\0vendor/composer/semver/src/Constraint/AbstractConstraint.phpê\ 2\0\0\87\ 2\0\0M äˤ\ 1\0\0\0\0\0\04\0\0\0vendor/composer/semver/src/Constraint/Constraint.php\8a\f\0\0\87`\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\87\0\0\00C,\87¤\ 1\0\0\0\0\0\09\0\0\0vendor/composer/semver/src/Constraint/EmptyConstraint.phpä\ 1\0\0\87\ 1\0\0ïõ\82³¤\ 1\0\0\0\0\0\09\0\0\0vendor/composer/semver/src/Constraint/MultiConstraint.php,\ 5\0\0\87`,\ 5\0\0\ 2\ 1\0\0\0\0\0\0%\0\0\0vendor/composer/semver/src/Semver.php\7f\ 6\0\0\87`\7f\ 6\0\0 YûÀ¤\ 1\0\0\0\0\0\0,\0\0\0vendor/composer/semver/src/VersionParser.phpw-\0\0\87`w-\0\0Î=ð­¤\ 1\0\0\0\0\0\0!\0\0\0vendor/composer/ca-bundle/LICENSE\1c\ 4\0\0\87`\1c\ 4\0\0*!^`¤\ 1\0\0\0\0\0\0*\0\0\0vendor/composer/ca-bundle/src/CaBundle.phpg\1f\0\0\87`g\1f\0\0Axð\90¤\ 1\0\0\0\0\0\0&\0\0\0vendor/composer/xdebug-handler/LICENSE)\ 4\0\0\87`)\ 4\0\0#Ô;^¤\ 1\0\0\0\0\0\00\0\0\0vendor/composer/xdebug-handler/src/PhpConfig.php´\ 2\0\0\87\ 2\0\0*D\92\0¤\ 1\0\0\0\0\0\0.\0\0\0vendor/composer/xdebug-handler/src/Process.phpk        \0\0\87`k \0\0\8eUÿߤ\ 1\0\0\0\0\0\0-\0\0\0vendor/composer/xdebug-handler/src/Status.php\ f
60 \0\0\87`\ f
61 \0\0$\9fv-¤\ 1\0\0\0\0\0\04\0\0\0vendor/composer/xdebug-handler/src/XdebugHandler.php\87%\0\0\87`\87%\0\0¾L3\ 4¤\ 1\0\0\0\0\0\0\16\0\0\0vendor/psr/log/LICENSE=\ 4\0\0\87`=\ 4\0\0\8e\ 1\0\0\0\0\0\0)\0\0\0vendor/psr/log/Psr/Log/AbstractLogger.php;\ 4\0\0\87`;\ 4\0\0ñ>3[¤\ 1\0\0\0\0\0\03\0\0\0vendor/psr/log/Psr/Log/InvalidArgumentException.php`\0\0\0\87``\0\0\0 \88X1¤\ 1\0\0\0\0\0\0#\0\0\0vendor/psr/log/Psr/Log/LogLevel.phpû\0\0\0\87\0\0\0jðñ8¤\ 1\0\0\0\0\0\0/\0\0\0vendor/psr/log/Psr/Log/LoggerAwareInterface.php|\0\0\0\87`|\0\0\0$\13£\88¤\ 1\0\0\0\0\0\0+\0\0\0vendor/psr/log/Psr/Log/LoggerAwareTrait.php§\0\0\0\87\0\0\0T½úB¤\ 1\0\0\0\0\0\0*\0\0\0vendor/psr/log/Psr/Log/LoggerInterface.phpÈ\ 2\0\0\87\ 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\87`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\87`\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\87`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\87\r\0\0\1d$/Ò¤\ 1\0\0\0\0\0\0*\0\0\0vendor/psr/log/Psr/Log/Test/TestLogger.php<\b\0\0\87`<\b\0\0þ(åI¤\ 1\0\0\0\0\0\0\13\0\0\0vendor/autoload.php\82\0\0\0\87`\82\0\0\0·þùã¤\ 1\0\0\0\0\0\0'\0\0\0vendor/composer/autoload_namespaces.phpd\0\0\0\87`d\0\0\0Z¡¦H¤\ 1\0\0\0\0\0\0!\0\0\0vendor/composer/autoload_psr4.php÷\ 4\0\0\87\ 4\0\0Å*\9a\16¤\ 1\0\0\0\0\0\0%\0\0\0vendor/composer/autoload_classmap.phpd\0\0\0\87`d\0\0\0Z¡¦H¤\ 1\0\0\0\0\0\0"\0\0\0vendor/composer/autoload_files.php\1f\ 1\0\0\87`\1f\ 1\0\0¥\0 ®¤\ 1\0\0\0\0\0\0!\0\0\0vendor/composer/autoload_real.phpL\a\0\0\87`L\a\0\0p/ %¤\ 1\0\0\0\0\0\0#\0\0\0vendor/composer/autoload_static.php§
62 \0\0\87
63 \0\05³2h¤\ 1\0\0\0\0\0\0\1f\0\0\0vendor/composer/ClassLoader.php¦\18\0\0\87\18\0\0MI\0\8c¤\ 1\0\0\0\0\0\0(\0\0\0vendor/composer/ca-bundle/res/cacert.pemê`\ 3\0\87`ê`\ 3\0­3\ 6\f¤\ 1\0\0\0\0\0\0\f\0\0\0bin/composerÊ\ 6\0\0\87\ 6\0\0\a\8f4K¤\ 1\0\0\0\0\0\0\a\0\0\0LICENSE.\ 4\0\0\87`.\ 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.22';
9921 const BRANCH_ALIAS_VERSION = '';
9922 const RELEASE_DATE = '2021-04-27 13:10:45';
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 --nested -- %s', 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
20958
20959 if (!preg_match('{^[.A-Za-z0-9_]+$}', $token)) {
20960 throw new \UnexpectedValueException('Your github oauth token for '.$domain.' contains invalid characters: "'.$token.'"');
20961 }
20962 $this->checkAndSetAuthentication($domain, $token, 'x-oauth-basic');
20963 }
20964
20965 foreach ($gitlabOauth as $domain => $token) {
20966 $this->checkAndSetAuthentication($domain, $token, 'oauth2');
20967 }
20968
20969 foreach ($gitlabToken as $domain => $token) {
20970 $this->checkAndSetAuthentication($domain, $token, 'private-token');
20971 }
20972
20973
20974 foreach ($httpBasic as $domain => $cred) {
20975 $this->checkAndSetAuthentication($domain, $cred['username'], $cred['password']);
20976 }
20977
20978 foreach ($bearerToken as $domain => $token) {
20979 $this->checkAndSetAuthentication($domain, $token, 'bearer');
20980 }
20981
20982
20983 ProcessExecutor::setTimeout((int) $config->get('process-timeout'));
20984 }
20985
20986
20987
20988
20989
20990
20991
20992
20993 public function emergency($message, array $context = array())
20994 {
20995 return $this->log(LogLevel::EMERGENCY, $message, $context);
20996 }
20997
20998
20999
21000
21001
21002
21003
21004
21005
21006
21007
21008 public function alert($message, array $context = array())
21009 {
21010 return $this->log(LogLevel::ALERT, $message, $context);
21011 }
21012
21013
21014
21015
21016
21017
21018
21019
21020
21021
21022 public function critical($message, array $context = array())
21023 {
21024 return $this->log(LogLevel::CRITICAL, $message, $context);
21025 }
21026
21027
21028
21029
21030
21031
21032
21033
21034
21035 public function error($message, array $context = array())
21036 {
21037 return $this->log(LogLevel::ERROR, $message, $context);
21038 }
21039
21040
21041
21042
21043
21044
21045
21046
21047
21048
21049
21050 public function warning($message, array $context = array())
21051 {
21052 return $this->log(LogLevel::WARNING, $message, $context);
21053 }
21054
21055
21056
21057
21058
21059
21060
21061
21062 public function notice($message, array $context = array())
21063 {
21064 return $this->log(LogLevel::NOTICE, $message, $context);
21065 }
21066
21067
21068
21069
21070
21071
21072
21073
21074
21075
21076 public function info($message, array $context = array())
21077 {
21078 return $this->log(LogLevel::INFO, $message, $context);
21079 }
21080
21081
21082
21083
21084
21085
21086
21087
21088 public function debug($message, array $context = array())
21089 {
21090 return $this->log(LogLevel::DEBUG, $message, $context);
21091 }
21092
21093
21094
21095
21096
21097
21098
21099
21100
21101 public function log($level, $message, array $context = array())
21102 {
21103 if (in_array($level, array(LogLevel::EMERGENCY, LogLevel::ALERT, LogLevel::CRITICAL, LogLevel::ERROR))) {
21104 $this->writeError('<error>'.$message.'</error>', true, self::NORMAL);
21105 } elseif ($level === LogLevel::WARNING) {
21106 $this->writeError('<warning>'.$message.'</warning>', true, self::NORMAL);
21107 } elseif ($level === LogLevel::NOTICE) {
21108 $this->writeError('<info>'.$message.'</info>', true, self::VERBOSE);
21109 } elseif ($level === LogLevel::INFO) {
21110 $this->writeError('<info>'.$message.'</info>', true, self::VERY_VERBOSE);
21111 } else {
21112 $this->writeError($message, true, self::DEBUG);
21113 }
21114 }
21115 }
21116 <?php
21117
21118
21119
21120
21121
21122
21123
21124
21125
21126
21127
21128 namespace Composer\IO;
21129
21130 use Symfony\Component\Console\Helper\QuestionHelper;
21131 use Symfony\Component\Console\Output\StreamOutput;
21132 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
21133 use Symfony\Component\Console\Input\StreamableInputInterface;
21134 use Symfony\Component\Console\Input\StringInput;
21135 use Symfony\Component\Console\Helper\HelperSet;
21136
21137
21138
21139
21140 class BufferIO extends ConsoleIO
21141 {
21142
21143
21144
21145
21146
21147 public function __construct($input = '', $verbosity = StreamOutput::VERBOSITY_NORMAL, OutputFormatterInterface $formatter = null)
21148 {
21149 $input = new StringInput($input);
21150 $input->setInteractive(false);
21151
21152 $output = new StreamOutput(fopen('php://memory', 'rw'), $verbosity, $formatter ? $formatter->isDecorated() : false, $formatter);
21153
21154 parent::__construct($input, $output, new HelperSet(array(
21155 new QuestionHelper(),
21156 )));
21157 }
21158
21159 public function getOutput()
21160 {
21161 fseek($this->output->getStream(), 0);
21162
21163 $output = stream_get_contents($this->output->getStream());
21164
21165 $output = preg_replace_callback("{(?<=^|\n|\x08)(.+?)(\x08+)}", function ($matches) {
21166 $pre = strip_tags($matches[1]);
21167
21168 if (strlen($pre) === strlen($matches[2])) {
21169 return '';
21170 }
21171
21172
21173 return rtrim($matches[1])."\n";
21174 }, $output);
21175
21176 return $output;
21177 }
21178
21179 public function setUserInputs(array $inputs)
21180 {
21181 if (!$this->input instanceof StreamableInputInterface) {
21182 throw new \RuntimeException('Setting the user inputs requires at least the version 3.2 of the symfony/console component.');
21183 }
21184
21185 $this->input->setStream($this->createStream($inputs));
21186 $this->input->setInteractive(true);
21187 }
21188
21189 private function createStream(array $inputs)
21190 {
21191 $stream = fopen('php://memory', 'r+', false);
21192
21193 foreach ($inputs as $input) {
21194 fwrite($stream, $input.PHP_EOL);
21195 }
21196
21197 rewind($stream);
21198
21199 return $stream;
21200 }
21201 }
21202 <?php
21203
21204
21205
21206
21207
21208
21209
21210
21211
21212
21213
21214 namespace Composer\IO;
21215
21216 use Composer\Question\StrictConfirmationQuestion;
21217 use Symfony\Component\Console\Helper\HelperSet;
21218 use Symfony\Component\Console\Input\InputInterface;
21219 use Symfony\Component\Console\Output\ConsoleOutputInterface;
21220 use Symfony\Component\Console\Output\OutputInterface;
21221 use Symfony\Component\Console\Question\ChoiceQuestion;
21222 use Symfony\Component\Console\Question\Question;
21223
21224
21225
21226
21227
21228
21229
21230 class ConsoleIO extends BaseIO
21231 {
21232
21233 protected $input;
21234
21235 protected $output;
21236
21237 protected $helperSet;
21238
21239 protected $lastMessage;
21240
21241 protected $lastMessageErr;
21242
21243
21244 private $startTime;
21245
21246 private $verbosityMap;
21247
21248
21249
21250
21251
21252
21253
21254
21255 public function __construct(InputInterface $input, OutputInterface $output, HelperSet $helperSet)
21256 {
21257 $this->input = $input;
21258 $this->output = $output;
21259 $this->helperSet = $helperSet;
21260 $this->verbosityMap = array(
21261 self::QUIET => OutputInterface::VERBOSITY_QUIET,
21262 self::NORMAL => OutputInterface::VERBOSITY_NORMAL,
21263 self::VERBOSE => OutputInterface::VERBOSITY_VERBOSE,
21264 self::VERY_VERBOSE => OutputInterface::VERBOSITY_VERY_VERBOSE,
21265 self::DEBUG => OutputInterface::VERBOSITY_DEBUG,
21266 );
21267 }
21268
21269
21270
21271
21272 public function enableDebugging($startTime)
21273 {
21274 $this->startTime = $startTime;
21275 }
21276
21277
21278
21279
21280 public function isInteractive()
21281 {
21282 return $this->input->isInteractive();
21283 }
21284
21285
21286
21287
21288 public function isDecorated()
21289 {
21290 return $this->output->isDecorated();
21291 }
21292
21293
21294
21295
21296 public function isVerbose()
21297 {
21298 return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE;
21299 }
21300
21301
21302
21303
21304 public function isVeryVerbose()
21305 {
21306 return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE;
21307 }
21308
21309
21310
21311
21312 public function isDebug()
21313 {
21314 return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_DEBUG;
21315 }
21316
21317
21318
21319
21320 public function write($messages, $newline = true, $verbosity = self::NORMAL)
21321 {
21322 $this->doWrite($messages, $newline, false, $verbosity);
21323 }
21324
21325
21326
21327
21328 public function writeError($messages, $newline = true, $verbosity = self::NORMAL)
21329 {
21330 $this->doWrite($messages, $newline, true, $verbosity);
21331 }
21332
21333
21334
21335
21336 public function writeRaw($messages, $newline = true, $verbosity = self::NORMAL)
21337 {
21338 $this->doWrite($messages, $newline, false, $verbosity, true);
21339 }
21340
21341
21342
21343
21344 public function writeErrorRaw($messages, $newline = true, $verbosity = self::NORMAL)
21345 {
21346 $this->doWrite($messages, $newline, true, $verbosity, true);
21347 }
21348
21349
21350
21351
21352
21353
21354
21355 private function doWrite($messages, $newline, $stderr, $verbosity, $raw = false)
21356 {
21357 $sfVerbosity = $this->verbosityMap[$verbosity];
21358 if ($sfVerbosity > $this->output->getVerbosity()) {
21359 return;
21360 }
21361
21362
21363
21364
21365 if (OutputInterface::VERBOSITY_QUIET === 0) {
21366 $sfVerbosity = OutputInterface::OUTPUT_NORMAL;
21367 }
21368
21369 if ($raw) {
21370 if ($sfVerbosity === OutputInterface::OUTPUT_NORMAL) {
21371 $sfVerbosity = OutputInterface::OUTPUT_RAW;
21372 } else {
21373 $sfVerbosity |= OutputInterface::OUTPUT_RAW;
21374 }
21375 }
21376
21377 if (null !== $this->startTime) {
21378 $memoryUsage = memory_get_usage() / 1024 / 1024;
21379 $timeSpent = microtime(true) - $this->startTime;
21380 $messages = array_map(function ($message) use ($memoryUsage, $timeSpent) {
21381 return sprintf('[%.1fMiB/%.2fs] %s', $memoryUsage, $timeSpent, $message);
21382 }, (array) $messages);
21383 }
21384
21385 if (true === $stderr && $this->output instanceof ConsoleOutputInterface) {
21386 $this->output->getErrorOutput()->write($messages, $newline, $sfVerbosity);
21387 $this->lastMessageErr = implode($newline ? "\n" : '', (array) $messages);
21388
21389 return;
21390 }
21391
21392 $this->output->write($messages, $newline, $sfVerbosity);
21393 $this->lastMessage = implode($newline ? "\n" : '', (array) $messages);
21394 }
21395
21396
21397
21398
21399 public function overwrite($messages, $newline = true, $size = null, $verbosity = self::NORMAL)
21400 {
21401 $this->doOverwrite($messages, $newline, $size, false, $verbosity);
21402 }
21403
21404
21405
21406
21407 public function overwriteError($messages, $newline = true, $size = null, $verbosity = self::NORMAL)
21408 {
21409 $this->doOverwrite($messages, $newline, $size, true, $verbosity);
21410 }
21411
21412
21413
21414
21415
21416
21417
21418
21419 private function doOverwrite($messages, $newline, $size, $stderr, $verbosity)
21420 {
21421
21422 $messages = implode($newline ? "\n" : '', (array) $messages);
21423
21424
21425 if (!isset($size)) {
21426
21427 $size = strlen(strip_tags($stderr ? $this->lastMessageErr : $this->lastMessage));
21428 }
21429
21430 $this->doWrite(str_repeat("\x08", $size), false, $stderr, $verbosity);
21431
21432
21433 $this->doWrite($messages, false, $stderr, $verbosity);
21434
21435
21436
21437
21438 $fill = $size - strlen(strip_tags($messages));
21439 if ($fill > 0) {
21440
21441 $this->doWrite(str_repeat(' ', $fill), false, $stderr, $verbosity);
21442
21443 $this->doWrite(str_repeat("\x08", $fill), false, $stderr, $verbosity);
21444 }
21445
21446 if ($newline) {
21447 $this->doWrite('', true, $stderr, $verbosity);
21448 }
21449
21450 if ($stderr) {
21451 $this->lastMessageErr = $messages;
21452 } else {
21453 $this->lastMessage = $messages;
21454 }
21455 }
21456
21457
21458
21459
21460 public function ask($question, $default = null)
21461 {
21462
21463 $helper = $this->helperSet->get('question');
21464 $question = new Question($question, $default);
21465
21466 return $helper->ask($this->input, $this->getErrorOutput(), $question);
21467 }
21468
21469
21470
21471
21472 public function askConfirmation($question, $default = true)
21473 {
21474
21475 $helper = $this->helperSet->get('question');
21476 $question = new StrictConfirmationQuestion($question, $default);
21477
21478 return $helper->ask($this->input, $this->getErrorOutput(), $question);
21479 }
21480
21481
21482
21483
21484 public function askAndValidate($question, $validator, $attempts = null, $default = null)
21485 {
21486
21487 $helper = $this->helperSet->get('question');
21488 $question = new Question($question, $default);
21489 $question->setValidator($validator);
21490 $question->setMaxAttempts($attempts);
21491
21492 return $helper->ask($this->input, $this->getErrorOutput(), $question);
21493 }
21494
21495
21496
21497
21498 public function askAndHideAnswer($question)
21499 {
21500
21501 $helper = $this->helperSet->get('question');
21502 $question = new Question($question);
21503 $question->setHidden(true);
21504
21505 return $helper->ask($this->input, $this->getErrorOutput(), $question);
21506 }
21507
21508
21509
21510
21511 public function select($question, $choices, $default, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false)
21512 {
21513
21514 $helper = $this->helperSet->get('question');
21515 $question = new ChoiceQuestion($question, $choices, $default);
21516 $question->setMaxAttempts($attempts ?: null); 
21517 $question->setErrorMessage($errorMessage);
21518 $question->setMultiselect($multiselect);
21519
21520 $result = $helper->ask($this->input, $this->getErrorOutput(), $question);
21521
21522 if (!is_array($result)) {
21523 return (string) array_search($result, $choices, true);
21524 }
21525
21526 $results = array();
21527 foreach ($choices as $index => $choice) {
21528 if (in_array($choice, $result, true)) {
21529 $results[] = (string) $index;
21530 }
21531 }
21532
21533 return $results;
21534 }
21535
21536
21537
21538
21539 private function getErrorOutput()
21540 {
21541 if ($this->output instanceof ConsoleOutputInterface) {
21542 return $this->output->getErrorOutput();
21543 }
21544
21545 return $this->output;
21546 }
21547 }
21548 <?php
21549
21550
21551
21552
21553
21554
21555
21556
21557
21558
21559
21560 namespace Composer\IO;
21561
21562 use Composer\Config;
21563
21564
21565
21566
21567
21568
21569 interface IOInterface
21570 {
21571 const QUIET = 1;
21572 const NORMAL = 2;
21573 const VERBOSE = 4;
21574 const VERY_VERBOSE = 8;
21575 const DEBUG = 16;
21576
21577
21578
21579
21580
21581
21582 public function isInteractive();
21583
21584
21585
21586
21587
21588
21589 public function isVerbose();
21590
21591
21592
21593
21594
21595
21596 public function isVeryVerbose();
21597
21598
21599
21600
21601
21602
21603 public function isDebug();
21604
21605
21606
21607
21608
21609
21610 public function isDecorated();
21611
21612
21613
21614
21615
21616
21617
21618
21619 public function write($messages, $newline = true, $verbosity = self::NORMAL);
21620
21621
21622
21623
21624
21625
21626
21627
21628 public function writeError($messages, $newline = true, $verbosity = self::NORMAL);
21629
21630
21631
21632
21633
21634
21635
21636
21637
21638 public function overwrite($messages, $newline = true, $size = null, $verbosity = self::NORMAL);
21639
21640
21641
21642
21643
21644
21645
21646
21647
21648 public function overwriteError($messages, $newline = true, $size = null, $verbosity = self::NORMAL);
21649
21650
21651
21652
21653
21654
21655
21656
21657
21658
21659 public function ask($question, $default = null);
21660
21661
21662
21663
21664
21665
21666
21667
21668
21669
21670
21671 public function askConfirmation($question, $default = true);
21672
21673
21674
21675
21676
21677
21678
21679
21680
21681
21682
21683
21684
21685
21686
21687
21688 public function askAndValidate($question, $validator, $attempts = null, $default = null);
21689
21690
21691
21692
21693
21694
21695
21696
21697 public function askAndHideAnswer($question);
21698
21699
21700
21701
21702
21703
21704
21705
21706
21707
21708
21709
21710
21711
21712 public function select($question, $choices, $default, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false);
21713
21714
21715
21716
21717
21718
21719 public function getAuthentications();
21720
21721
21722
21723
21724
21725
21726
21727
21728 public function hasAuthentication($repositoryName);
21729
21730
21731
21732
21733
21734
21735
21736
21737 public function getAuthentication($repositoryName);
21738
21739
21740
21741
21742
21743
21744
21745
21746 public function setAuthentication($repositoryName, $username, $password = null);
21747
21748
21749
21750
21751
21752
21753 public function loadConfiguration(Config $config);
21754 }
21755 <?php
21756
21757
21758
21759
21760
21761
21762
21763
21764
21765
21766
21767 namespace Composer\IO;
21768
21769
21770
21771
21772
21773
21774 class NullIO extends BaseIO
21775 {
21776
21777
21778
21779 public function isInteractive()
21780 {
21781 return false;
21782 }
21783
21784
21785
21786
21787 public function isVerbose()
21788 {
21789 return false;
21790 }
21791
21792
21793
21794
21795 public function isVeryVerbose()
21796 {
21797 return false;
21798 }
21799
21800
21801
21802
21803 public function isDebug()
21804 {
21805 return false;
21806 }
21807
21808
21809
21810
21811 public function isDecorated()
21812 {
21813 return false;
21814 }
21815
21816
21817
21818
21819 public function write($messages, $newline = true, $verbosity = self::NORMAL)
21820 {
21821 }
21822
21823
21824
21825
21826 public function writeError($messages, $newline = true, $verbosity = self::NORMAL)
21827 {
21828 }
21829
21830
21831
21832
21833 public function overwrite($messages, $newline = true, $size = 80, $verbosity = self::NORMAL)
21834 {
21835 }
21836
21837
21838
21839
21840 public function overwriteError($messages, $newline = true, $size = 80, $verbosity = self::NORMAL)
21841 {
21842 }
21843
21844
21845
21846
21847 public function ask($question, $default = null)
21848 {
21849 return $default;
21850 }
21851
21852
21853
21854
21855 public function askConfirmation($question, $default = true)
21856 {
21857 return $default;
21858 }
21859
21860
21861
21862
21863 public function askAndValidate($question, $validator, $attempts = false, $default = null)
21864 {
21865 return $default;
21866 }
21867
21868
21869
21870
21871 public function askAndHideAnswer($question)
21872 {
21873 return null;
21874 }
21875
21876
21877
21878
21879 public function select($question, $choices, $default, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false)
21880 {
21881 return $default;
21882 }
21883 }
21884 <?php
21885
21886
21887
21888
21889
21890
21891
21892
21893
21894
21895
21896 namespace Composer;
21897
21898 use Composer\Autoload\AutoloadGenerator;
21899 use Composer\DependencyResolver\DefaultPolicy;
21900 use Composer\DependencyResolver\Operation\UpdateOperation;
21901 use Composer\DependencyResolver\Operation\InstallOperation;
21902 use Composer\DependencyResolver\Operation\UninstallOperation;
21903 use Composer\DependencyResolver\Operation\MarkAliasUninstalledOperation;
21904 use Composer\DependencyResolver\Operation\OperationInterface;
21905 use Composer\DependencyResolver\PolicyInterface;
21906 use Composer\DependencyResolver\Pool;
21907 use Composer\DependencyResolver\Request;
21908 use Composer\DependencyResolver\Rule;
21909 use Composer\DependencyResolver\Solver;
21910 use Composer\DependencyResolver\SolverProblemsException;
21911 use Composer\Downloader\DownloadManager;
21912 use Composer\EventDispatcher\EventDispatcher;
21913 use Composer\Installer\InstallationManager;
21914 use Composer\Installer\InstallerEvents;
21915 use Composer\Installer\NoopInstaller;
21916 use Composer\Installer\SuggestedPackagesReporter;
21917 use Composer\IO\IOInterface;
21918 use Composer\Package\AliasPackage;
21919 use Composer\Package\BasePackage;
21920 use Composer\Package\CompletePackage;
21921 use Composer\Package\CompletePackageInterface;
21922 use Composer\Package\Link;
21923 use Composer\Package\Loader\ArrayLoader;
21924 use Composer\Package\Dumper\ArrayDumper;
21925 use Composer\Semver\Constraint\Constraint;
21926 use Composer\Package\Locker;
21927 use Composer\Package\PackageInterface;
21928 use Composer\Package\RootPackageInterface;
21929 use Composer\Repository\CompositeRepository;
21930 use Composer\Repository\InstalledArrayRepository;
21931 use Composer\Repository\PlatformRepository;
21932 use Composer\Repository\RepositoryInterface;
21933 use Composer\Repository\RepositoryManager;
21934 use Composer\Repository\WritableRepositoryInterface;
21935 use Composer\Script\ScriptEvents;
21936
21937
21938
21939
21940
21941
21942
21943 class Installer
21944 {
21945
21946
21947
21948 protected $io;
21949
21950
21951
21952
21953 protected $config;
21954
21955
21956
21957
21958 protected $package;
21959
21960
21961
21962
21963 protected $downloadManager;
21964
21965
21966
21967
21968 protected $repositoryManager;
21969
21970
21971
21972
21973 protected $locker;
21974
21975
21976
21977
21978 protected $installationManager;
21979
21980
21981
21982
21983 protected $eventDispatcher;
21984
21985
21986
21987
21988 protected $autoloadGenerator;
21989
21990 protected $preferSource = false;
21991 protected $preferDist = false;
21992 protected $optimizeAutoloader = false;
21993 protected $classMapAuthoritative = false;
21994 protected $apcuAutoloader = false;
21995 protected $devMode = false;
21996 protected $dryRun = false;
21997 protected $verbose = false;
21998 protected $update = false;
21999 protected $dumpAutoloader = true;
22000 protected $runScripts = true;
22001 protected $ignorePlatformReqs = false;
22002 protected $preferStable = false;
22003 protected $preferLowest = false;
22004 protected $skipSuggest = false;
22005 protected $writeLock;
22006 protected $executeOperations = true;
22007
22008
22009
22010
22011
22012
22013 protected $updateWhitelist = null; 
22014 protected $whitelistDependencies = false; 
22015 protected $whitelistAllDependencies = false; 
22016
22017
22018
22019
22020 protected $suggestedPackagesReporter;
22021
22022
22023
22024
22025 protected $additionalInstalledRepository;
22026
22027
22028
22029
22030
22031
22032
22033
22034
22035
22036
22037
22038
22039
22040 public function __construct(IOInterface $io, Config $config, RootPackageInterface $package, DownloadManager $downloadManager, RepositoryManager $repositoryManager, Locker $locker, InstallationManager $installationManager, EventDispatcher $eventDispatcher, AutoloadGenerator $autoloadGenerator)
22041 {
22042 $this->io = $io;
22043 $this->config = $config;
22044 $this->package = $package;
22045 $this->downloadManager = $downloadManager;
22046 $this->repositoryManager = $repositoryManager;
22047 $this->locker = $locker;
22048 $this->installationManager = $installationManager;
22049 $this->eventDispatcher = $eventDispatcher;
22050 $this->autoloadGenerator = $autoloadGenerator;
22051
22052 $this->writeLock = $config->get('lock');
22053 }
22054
22055
22056
22057
22058
22059
22060
22061 public function run()
22062 {
22063
22064
22065
22066
22067 gc_collect_cycles();
22068 gc_disable();
22069
22070
22071 if (!$this->update && !$this->locker->isLocked()) {
22072 $this->update = true;
22073 }
22074
22075 if ($this->dryRun) {
22076 $this->verbose = true;
22077 $this->runScripts = false;
22078 $this->executeOperations = false;
22079 $this->writeLock = false;
22080 $this->dumpAutoloader = false;
22081 $this->installationManager->addInstaller(new NoopInstaller);
22082 $this->mockLocalRepositories($this->repositoryManager);
22083 }
22084
22085 if ($this->runScripts) {
22086 $_SERVER['COMPOSER_DEV_MODE'] = $this->devMode ? '1' : '0';
22087 putenv('COMPOSER_DEV_MODE='.$_SERVER['COMPOSER_DEV_MODE']);
22088
22089
22090 $eventName = $this->update ? ScriptEvents::PRE_UPDATE_CMD : ScriptEvents::PRE_INSTALL_CMD;
22091 $this->eventDispatcher->dispatchScript($eventName, $this->devMode);
22092 }
22093
22094 $this->downloadManager->setPreferSource($this->preferSource);
22095 $this->downloadManager->setPreferDist($this->preferDist);
22096
22097
22098 $localRepo = $this->repositoryManager->getLocalRepository();
22099 if ($this->update) {
22100 $platformOverrides = $this->config->get('platform') ?: array();
22101 } else {
22102 $platformOverrides = $this->locker->getPlatformOverrides();
22103 }
22104 $platformRepo = new PlatformRepository(array(), $platformOverrides);
22105 $installedRepo = $this->createInstalledRepo($localRepo, $platformRepo);
22106
22107 $aliases = $this->getRootAliases();
22108 $this->aliasPlatformPackages($platformRepo, $aliases);
22109
22110 if (!$this->suggestedPackagesReporter) {
22111 $this->suggestedPackagesReporter = new SuggestedPackagesReporter($this->io);
22112 }
22113
22114 try {
22115 list($res, $devPackages) = $this->doInstall($localRepo, $installedRepo, $platformRepo, $aliases);
22116 if ($res !== 0) {
22117 return $res;
22118 }
22119 } catch (\Exception $e) {
22120 if ($this->executeOperations && $this->config->get('notify-on-install')) {
22121 $this->installationManager->notifyInstalls($this->io);
22122 }
22123
22124 throw $e;
22125 }
22126 if ($this->executeOperations && $this->config->get('notify-on-install')) {
22127 $this->installationManager->notifyInstalls($this->io);
22128 }
22129
22130
22131 if ($this->devMode && !$this->skipSuggest) {
22132 $this->suggestedPackagesReporter->output($installedRepo);
22133 }
22134
22135
22136 foreach ($localRepo->getPackages() as $package) {
22137 if (!$package instanceof CompletePackage || !$package->isAbandoned()) {
22138 continue;
22139 }
22140
22141 $replacement = is_string($package->getReplacementPackage())
22142 ? 'Use ' . $package->getReplacementPackage() . ' instead'
22143 : 'No replacement was suggested';
22144
22145 $this->io->writeError(
22146 sprintf(
22147 "<warning>Package %s is abandoned, you should avoid using it. %s.</warning>",
22148 $package->getPrettyName(),
22149 $replacement
22150 )
22151 );
22152 }
22153
22154
22155 if ($this->update && $this->writeLock) {
22156 $localRepo->reload();
22157
22158 $platformReqs = $this->extractPlatformRequirements($this->package->getRequires());
22159 $platformDevReqs = $this->extractPlatformRequirements($this->package->getDevRequires());
22160
22161 $updatedLock = $this->locker->setLockData(
22162 array_diff($localRepo->getCanonicalPackages(), $devPackages),
22163 $devPackages,
22164 $platformReqs,
22165 $platformDevReqs,
22166 $aliases,
22167 $this->package->getMinimumStability(),
22168 $this->package->getStabilityFlags(),
22169 $this->preferStable || $this->package->getPreferStable(),
22170 $this->preferLowest,
22171 $this->config->get('platform') ?: array()
22172 );
22173 if ($updatedLock) {
22174 $this->io->writeError('<info>Writing lock file</info>');
22175 }
22176 }
22177
22178 if ($this->dumpAutoloader) {
22179
22180 if ($this->optimizeAutoloader) {
22181 $this->io->writeError('<info>Generating optimized autoload files</info>');
22182 } else {
22183 $this->io->writeError('<info>Generating autoload files</info>');
22184 }
22185
22186 $this->autoloadGenerator->setDevMode($this->devMode);
22187 $this->autoloadGenerator->setClassMapAuthoritative($this->classMapAuthoritative);
22188 $this->autoloadGenerator->setApcu($this->apcuAutoloader);
22189 $this->autoloadGenerator->setRunScripts($this->runScripts);
22190 $this->autoloadGenerator->dump($this->config, $localRepo, $this->package, $this->installationManager, 'composer', $this->optimizeAutoloader);
22191 }
22192
22193 if ($this->executeOperations) {
22194
22195 foreach ($localRepo->getPackages() as $package) {
22196 $this->installationManager->ensureBinariesPresence($package);
22197 }
22198 }
22199
22200 $fundingCount = 0;
22201 foreach ($localRepo->getPackages() as $package) {
22202 if ($package instanceof CompletePackageInterface && !$package instanceof AliasPackage && $package->getFunding()) {
22203 $fundingCount++;
22204 }
22205 }
22206 if ($fundingCount) {
22207 $this->io->writeError(array(
22208 sprintf(
22209 "<info>%d package%s you are using %s looking for funding.</info>",
22210 $fundingCount,
22211 1 === $fundingCount ? '' : 's',
22212 1 === $fundingCount ? 'is' : 'are'
22213 ),
22214 '<info>Use the `composer fund` command to find out more!</info>',
22215 ));
22216 }
22217
22218 if ($this->runScripts) {
22219
22220 $eventName = $this->update ? ScriptEvents::POST_UPDATE_CMD : ScriptEvents::POST_INSTALL_CMD;
22221 $this->eventDispatcher->dispatchScript($eventName, $this->devMode);
22222 }
22223
22224
22225 if (!defined('HHVM_VERSION')) {
22226 gc_enable();
22227 }
22228
22229 return 0;
22230 }
22231
22232
22233
22234
22235
22236
22237
22238
22239 protected function doInstall($localRepo, $installedRepo, $platformRepo, $aliases)
22240 {
22241
22242 $lockedRepository = null;
22243 $repositories = null;
22244
22245
22246
22247
22248 if (!$this->update || (!empty($this->updateWhitelist) && $this->locker->isLocked())) {
22249 try {
22250 $lockedRepository = $this->locker->getLockedRepository($this->devMode);
22251 } catch (\RuntimeException $e) {
22252
22253 if ($this->package->getDevRequires()) {
22254 throw $e;
22255 }
22256
22257 $lockedRepository = $this->locker->getLockedRepository();
22258 }
22259 }
22260
22261 $this->allowListUpdateDependencies(
22262 $lockedRepository ?: $localRepo,
22263 $this->package->getRequires(),
22264 $this->package->getDevRequires()
22265 );
22266
22267 $this->io->writeError('<info>Loading composer repositories with package information</info>');
22268
22269
22270 $policy = $this->createPolicy();
22271 $pool = $this->createPool($this->update ? null : $lockedRepository);
22272 $pool->addRepository($installedRepo, $aliases);
22273 if ($this->update) {
22274 $repositories = $this->repositoryManager->getRepositories();
22275 foreach ($repositories as $repository) {
22276 $pool->addRepository($repository, $aliases);
22277 }
22278 }
22279
22280
22281
22282 if ($lockedRepository) {
22283 $pool->addRepository($lockedRepository, $aliases);
22284 }
22285
22286
22287 $request = $this->createRequest($this->package, $platformRepo);
22288
22289 if ($this->update) {
22290
22291 $removedUnstablePackages = array();
22292 foreach ($localRepo->getPackages() as $package) {
22293 if (
22294 !$pool->isPackageAcceptable($package->getNames(), $package->getStability())
22295 && $this->installationManager->isPackageInstalled($localRepo, $package)
22296 ) {
22297 $removedUnstablePackages[$package->getName()] = true;
22298 $request->remove($package->getName(), new Constraint('=', $package->getVersion()));
22299 }
22300 }
22301
22302 $this->io->writeError('<info>Updating dependencies'.($this->devMode ? ' (including require-dev)' : '').'</info>');
22303
22304 $request->updateAll();
22305
22306 $links = array_merge($this->package->getRequires(), $this->package->getDevRequires());
22307
22308 foreach ($links as $link) {
22309 $request->install($link->getTarget(), $link->getConstraint());
22310 }
22311
22312
22313
22314 if ($this->updateWhitelist) {
22315 $currentPackages = $this->getCurrentPackages($installedRepo);
22316
22317
22318 $candidates = array();
22319 foreach ($links as $link) {
22320 $candidates[$link->getTarget()] = true;
22321 $rootRequires[$link->getTarget()] = $link;
22322 }
22323 foreach ($currentPackages as $package) {
22324 $candidates[$package->getName()] = true;
22325 }
22326
22327
22328 foreach ($candidates as $candidate => $dummy) {
22329 foreach ($currentPackages as $curPackage) {
22330 if ($curPackage->getName() === $candidate) {
22331 if (!$this->isUpdateable($curPackage) && !isset($removedUnstablePackages[$curPackage->getName()])) {
22332 $constraint = new Constraint('=', $curPackage->getVersion());
22333 $description = $this->locker->isLocked() ? '(locked at' : '(installed at';
22334 $requiredAt = isset($rootRequires[$candidate]) ? ', required as ' . $rootRequires[$candidate]->getPrettyConstraint() : '';
22335 $constraint->setPrettyString($description . ' ' . $curPackage->getPrettyVersion() . $requiredAt . ')');
22336 $request->install($curPackage->getName(), $constraint);
22337 }
22338 break;
22339 }
22340 }
22341 }
22342 }
22343 } else {
22344 $this->io->writeError('<info>Installing dependencies'.($this->devMode ? ' (including require-dev)' : '').' from lock file</info>');
22345
22346 if (!$this->locker->isFresh()) {
22347 $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);
22348 }
22349
22350 foreach ($lockedRepository->getPackages() as $package) {
22351 $version = $package->getVersion();
22352 if (isset($aliases[$package->getName()][$version])) {
22353 $version = $aliases[$package->getName()][$version]['alias_normalized'];
22354 }
22355 $constraint = new Constraint('=', $version);
22356 $constraint->setPrettyString($package->getPrettyVersion());
22357 $request->install($package->getName(), $constraint);
22358 }
22359
22360 foreach ($this->locker->getPlatformRequirements($this->devMode) as $link) {
22361 $request->install($link->getTarget(), $link->getConstraint());
22362 }
22363 }
22364
22365
22366 $this->processDevPackages($localRepo, $pool, $policy, $repositories, $installedRepo, $lockedRepository, 'force-links');
22367
22368
22369 $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, $this->devMode, $policy, $pool, $installedRepo, $request);
22370 $solver = new Solver($policy, $pool, $installedRepo, $this->io);
22371 try {
22372 $operations = $solver->solve($request, $this->ignorePlatformReqs);
22373 $ruleSetSize = $solver->getRuleSetSize();
22374 $solver = null;
22375 } catch (SolverProblemsException $e) {
22376 $this->io->writeError('<error>Your requirements could not be resolved to an installable set of packages.</error>', true, IOInterface::QUIET);
22377 $this->io->writeError($e->getMessage());
22378 if ($this->update && !$this->devMode) {
22379 $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);
22380 }
22381
22382 return array(max(1, $e->getCode()), array());
22383 }
22384
22385
22386 $operations = $this->processDevPackages($localRepo, $pool, $policy, $repositories, $installedRepo, $lockedRepository, 'force-updates', $operations);
22387
22388 $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $this->devMode, $policy, $pool, $installedRepo, $request, $operations);
22389
22390 $this->io->writeError("Analyzed ".count($pool)." packages to resolve dependencies", true, IOInterface::VERBOSE);
22391 $this->io->writeError("Analyzed ".$ruleSetSize." rules to resolve dependencies", true, IOInterface::VERBOSE);
22392
22393
22394 if (!$operations) {
22395 $this->io->writeError('Nothing to install or update');
22396 }
22397
22398 $operations = $this->movePluginsToFront($operations);
22399 $operations = $this->moveUninstallsToFront($operations);
22400
22401
22402
22403 if ($this->update) {
22404 $devPackages = $this->extractDevPackages($operations, $localRepo, $platformRepo, $aliases);
22405 if (!$this->devMode) {
22406 $operations = $this->filterDevPackageOperations($devPackages, $operations, $localRepo);
22407 }
22408 } else {
22409 $devPackages = null;
22410 }
22411
22412 if ($operations) {
22413 $installs = $updates = $uninstalls = array();
22414 foreach ($operations as $operation) {
22415 if ($operation instanceof InstallOperation) {
22416 $installs[] = $operation->getPackage()->getPrettyName().':'.$operation->getPackage()->getFullPrettyVersion();
22417 } elseif ($operation instanceof UpdateOperation) {
22418 $updates[] = $operation->getTargetPackage()->getPrettyName().':'.$operation->getTargetPackage()->getFullPrettyVersion();
22419 } elseif ($operation instanceof UninstallOperation) {
22420 $uninstalls[] = $operation->getPackage()->getPrettyName();
22421 }
22422 }
22423
22424 $this->io->writeError(sprintf(
22425 "<info>Package operations: %d install%s, %d update%s, %d removal%s</info>",
22426 count($installs),
22427 1 === count($installs) ? '' : 's',
22428 count($updates),
22429 1 === count($updates) ? '' : 's',
22430 count($uninstalls),
22431 1 === count($uninstalls) ? '' : 's'
22432 ));
22433 if ($installs) {
22434 $this->io->writeError("Installs: ".implode(', ', $installs), true, IOInterface::VERBOSE);
22435 }
22436 if ($updates) {
22437 $this->io->writeError("Updates: ".implode(', ', $updates), true, IOInterface::VERBOSE);
22438 }
22439 if ($uninstalls) {
22440 $this->io->writeError("Removals: ".implode(', ', $uninstalls), true, IOInterface::VERBOSE);
22441 }
22442 }
22443
22444 foreach ($operations as $operation) {
22445
22446 $jobType = $operation->getJobType();
22447 if ('install' === $jobType) {
22448 $this->suggestedPackagesReporter->addSuggestionsFromPackage($operation->getPackage());
22449 }
22450
22451
22452 if ($this->update) {
22453 $package = null;
22454 if ('update' === $jobType) {
22455 $package = $operation->getTargetPackage();
22456 } elseif ('install' === $jobType) {
22457 $package = $operation->getPackage();
22458 }
22459 if ($package && $package->isDev()) {
22460 $references = $this->package->getReferences();
22461 if (isset($references[$package->getName()])) {
22462 $this->updateInstallReferences($package, $references[$package->getName()]);
22463 }
22464 }
22465 if ('update' === $jobType) {
22466 $targetPackage = $operation->getTargetPackage();
22467 if ($targetPackage->isDev()) {
22468 $initialPackage = $operation->getInitialPackage();
22469 if ($targetPackage->getVersion() === $initialPackage->getVersion()
22470 && (!$targetPackage->getSourceReference() || $targetPackage->getSourceReference() === $initialPackage->getSourceReference())
22471 && (!$targetPackage->getDistReference() || $targetPackage->getDistReference() === $initialPackage->getDistReference())
22472 ) {
22473 $this->io->writeError('  - Skipping update of ' . $targetPackage->getPrettyName() . ' to the same reference-locked version', true, IOInterface::DEBUG);
22474 $this->io->writeError('', true, IOInterface::DEBUG);
22475
22476 continue;
22477 }
22478 }
22479 }
22480 }
22481
22482 $event = 'Composer\Installer\PackageEvents::PRE_PACKAGE_'.strtoupper($jobType);
22483 if (defined($event) && $this->runScripts) {
22484 $this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $policy, $pool, $installedRepo, $request, $operations, $operation);
22485 }
22486
22487
22488 if (!$this->executeOperations && false === strpos($operation->getJobType(), 'Alias')) {
22489 $this->io->writeError('  - ' . $operation);
22490 } elseif ($this->io->isDebug() && false !== strpos($operation->getJobType(), 'Alias')) {
22491 $this->io->writeError('  - ' . $operation);
22492 }
22493
22494 $this->installationManager->execute($localRepo, $operation);
22495
22496
22497 if ($this->verbose && $this->io->isVeryVerbose() && in_array($jobType, array('install', 'update'))) {
22498 $reason = $operation->getReason();
22499 if ($reason instanceof Rule) {
22500 switch ($reason->getReason()) {
22501 case Rule::RULE_JOB_INSTALL:
22502 $this->io->writeError('    REASON: Required by the root package: '.$reason->getPrettyString($pool));
22503 $this->io->writeError('');
22504 break;
22505 case Rule::RULE_PACKAGE_REQUIRES:
22506 $this->io->writeError('    REASON: '.$reason->getPrettyString($pool));
22507 $this->io->writeError('');
22508 break;
22509 }
22510 }
22511 }
22512
22513 if ($this->executeOperations || $this->writeLock) {
22514 $localRepo->write();
22515 }
22516
22517 $event = 'Composer\Installer\PackageEvents::POST_PACKAGE_'.strtoupper($jobType);
22518 if (defined($event) && $this->runScripts) {
22519 $this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $policy, $pool, $installedRepo, $request, $operations, $operation);
22520 }
22521 }
22522
22523 if ($this->executeOperations) {
22524
22525 $this->processPackageUrls($pool, $policy, $localRepo, $repositories);
22526 $localRepo->write();
22527 }
22528
22529
22530 if ($operations) {
22531 $vendorDir = $this->config->get('vendor-dir');
22532 if (is_dir($vendorDir)) {
22533
22534
22535 @touch($vendorDir);
22536 }
22537 }
22538
22539 return array(0, $devPackages);
22540 }
22541
22542
22543
22544
22545
22546
22547
22548
22549
22550
22551
22552 private function extractDevPackages(array $operations, RepositoryInterface $localRepo, PlatformRepository $platformRepo, array $aliases)
22553 {
22554 if (!$this->package->getDevRequires()) {
22555 return array();
22556 }
22557
22558
22559 $tempLocalRepo = clone $localRepo;
22560 foreach ($operations as $operation) {
22561 switch ($operation->getJobType()) {
22562 case 'install':
22563 case 'markAliasInstalled':
22564 if (!$tempLocalRepo->hasPackage($operation->getPackage())) {
22565 $tempLocalRepo->addPackage(clone $operation->getPackage());
22566 }
22567 break;
22568
22569 case 'uninstall':
22570 case 'markAliasUninstalled':
22571 $tempLocalRepo->removePackage($operation->getPackage());
22572 break;
22573
22574 case 'update':
22575 $tempLocalRepo->removePackage($operation->getInitialPackage());
22576 if (!$tempLocalRepo->hasPackage($operation->getTargetPackage())) {
22577 $tempLocalRepo->addPackage(clone $operation->getTargetPackage());
22578 }
22579 break;
22580
22581 default:
22582 throw new \LogicException('Unknown type: '.$operation->getJobType());
22583 }
22584 }
22585
22586
22587
22588
22589 $localRepo = new InstalledArrayRepository(array());
22590 $loader = new ArrayLoader(null, true);
22591 $dumper = new ArrayDumper();
22592 foreach ($tempLocalRepo->getCanonicalPackages() as $pkg) {
22593 $localRepo->addPackage($loader->load($dumper->dump($pkg)));
22594 }
22595 unset($tempLocalRepo, $loader, $dumper);
22596
22597 $policy = $this->createPolicy();
22598 $pool = $this->createPool();
22599 $installedRepo = $this->createInstalledRepo($localRepo, $platformRepo);
22600 $pool->addRepository($installedRepo, $aliases);
22601
22602
22603 $request = $this->createRequest($this->package, $platformRepo);
22604 $request->updateAll();
22605 foreach ($this->package->getRequires() as $link) {
22606 $request->install($link->getTarget(), $link->getConstraint());
22607 }
22608
22609
22610 $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, false, $policy, $pool, $installedRepo, $request);
22611 $solver = new Solver($policy, $pool, $installedRepo, $this->io);
22612 $ops = $solver->solve($request, $this->ignorePlatformReqs);
22613 $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, false, $policy, $pool, $installedRepo, $request, $ops);
22614
22615 $devPackages = array();
22616 foreach ($ops as $op) {
22617 if ($op->getJobType() === 'uninstall') {
22618 $devPackages[] = $op->getPackage();
22619 }
22620 }
22621
22622 return $devPackages;
22623 }
22624
22625
22626
22627
22628 private function filterDevPackageOperations(array $devPackages, array $operations, RepositoryInterface $localRepo)
22629 {
22630 $finalOps = array();
22631 $packagesToSkip = array();
22632 foreach ($devPackages as $pkg) {
22633 $packagesToSkip[$pkg->getName()] = true;
22634 if ($installedDevPkg = $localRepo->findPackage($pkg->getName(), '*')) {
22635 if ($installedDevPkg instanceof AliasPackage) {
22636 $finalOps[] = new MarkAliasUninstalledOperation($installedDevPkg, 'non-dev install removing it');
22637 $installedDevPkg = $installedDevPkg->getAliasOf();
22638 }
22639 $finalOps[] = new UninstallOperation($installedDevPkg, 'non-dev install removing it');
22640 }
22641 }
22642
22643
22644 foreach ($operations as $op) {
22645 $package = $op->getJobType() === 'update' ? $op->getTargetPackage() : $op->getPackage();
22646 if (isset($packagesToSkip[$package->getName()])) {
22647 continue;
22648 }
22649
22650 $finalOps[] = $op;
22651 }
22652
22653 return $finalOps;
22654 }
22655
22656
22657
22658
22659
22660
22661
22662
22663
22664
22665
22666
22667
22668
22669 private function movePluginsToFront(array $operations)
22670 {
22671 $pluginsNoDeps = array();
22672 $pluginsWithDeps = array();
22673 $pluginRequires = array();
22674
22675 foreach (array_reverse($operations, true) as $idx => $op) {
22676 if ($op instanceof InstallOperation) {
22677 $package = $op->getPackage();
22678 } elseif ($op instanceof UpdateOperation) {
22679 $package = $op->getTargetPackage();
22680 } else {
22681 continue;
22682 }
22683
22684
22685 $isPlugin = $package->getType() === 'composer-plugin' || $package->getType() === 'composer-installer';
22686
22687
22688 if ($isPlugin || count(array_intersect($package->getNames(), $pluginRequires))) {
22689
22690 $requires = array_filter(array_keys($package->getRequires()), function ($req) {
22691 return $req !== 'composer-plugin-api' && !preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $req);
22692 });
22693
22694
22695 if ($isPlugin && !count($requires)) {
22696
22697 array_unshift($pluginsNoDeps, $op);
22698 } else {
22699
22700 $pluginRequires = array_merge($pluginRequires, $requires);
22701
22702 array_unshift($pluginsWithDeps, $op);
22703 }
22704
22705 unset($operations[$idx]);
22706 }
22707 }
22708
22709 return array_merge($pluginsNoDeps, $pluginsWithDeps, $operations);
22710 }
22711
22712
22713
22714
22715
22716
22717
22718
22719 private function moveUninstallsToFront(array $operations)
22720 {
22721 $uninstOps = array();
22722 foreach ($operations as $idx => $op) {
22723 if ($op instanceof UninstallOperation) {
22724 $uninstOps[] = $op;
22725 unset($operations[$idx]);
22726 }
22727 }
22728
22729 return array_merge($uninstOps, $operations);
22730 }
22731
22732
22733
22734
22735 private function createInstalledRepo(RepositoryInterface $localRepo, PlatformRepository $platformRepo)
22736 {
22737
22738
22739
22740 $installedRootPackage = clone $this->package;
22741 $installedRootPackage->setRequires(array());
22742 $installedRootPackage->setDevRequires(array());
22743
22744 $repos = array(
22745 $localRepo,
22746 new InstalledArrayRepository(array($installedRootPackage)),
22747 $platformRepo,
22748 );
22749 $installedRepo = new CompositeRepository($repos);
22750 if ($this->additionalInstalledRepository) {
22751 $installedRepo->addRepository($this->additionalInstalledRepository);
22752 }
22753
22754 return $installedRepo;
22755 }
22756
22757
22758
22759
22760
22761 private function createPool(RepositoryInterface $lockedRepository = null)
22762 {
22763 if ($this->update) {
22764 $minimumStability = $this->package->getMinimumStability();
22765 $stabilityFlags = $this->package->getStabilityFlags();
22766
22767 $requires = array_merge($this->package->getRequires(), $this->package->getDevRequires());
22768 } else {
22769 $minimumStability = $this->locker->getMinimumStability();
22770 $stabilityFlags = $this->locker->getStabilityFlags();
22771
22772 $requires = array();
22773 foreach ($lockedRepository->getPackages() as $package) {
22774 $constraint = new Constraint('=', $package->getVersion());
22775 $constraint->setPrettyString($package->getPrettyVersion());
22776 $requires[$package->getName()] = $constraint;
22777 }
22778 }
22779
22780 $rootConstraints = array();
22781 foreach ($requires as $req => $constraint) {
22782
22783 if ($this->ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $req)) {
22784 continue;
22785 }
22786 if ($constraint instanceof Link) {
22787 $rootConstraints[$req] = $constraint->getConstraint();
22788 } else {
22789 $rootConstraints[$req] = $constraint;
22790 }
22791 }
22792
22793 return new Pool($minimumStability, $stabilityFlags, $rootConstraints);
22794 }
22795
22796
22797
22798
22799 private function createPolicy()
22800 {
22801 $preferStable = null;
22802 $preferLowest = null;
22803 if (!$this->update) {
22804 $preferStable = $this->locker->getPreferStable();
22805 $preferLowest = $this->locker->getPreferLowest();
22806 }
22807
22808
22809 if (null === $preferStable) {
22810 $preferStable = $this->preferStable || $this->package->getPreferStable();
22811 }
22812 if (null === $preferLowest) {
22813 $preferLowest = $this->preferLowest;
22814 }
22815
22816 return new DefaultPolicy($preferStable, $preferLowest);
22817 }
22818
22819
22820
22821
22822
22823
22824 private function createRequest(RootPackageInterface $rootPackage, PlatformRepository $platformRepo)
22825 {
22826 $request = new Request();
22827
22828 $constraint = new Constraint('=', $rootPackage->getVersion());
22829 $constraint->setPrettyString($rootPackage->getPrettyVersion());
22830 $request->install($rootPackage->getName(), $constraint);
22831
22832 $fixedPackages = $platformRepo->getPackages();
22833 if ($this->additionalInstalledRepository) {
22834 $additionalFixedPackages = $this->additionalInstalledRepository->getPackages();
22835 $fixedPackages = array_merge($fixedPackages, $additionalFixedPackages);
22836 }
22837
22838
22839
22840 $provided = $rootPackage->getProvides();
22841 foreach ($fixedPackages as $package) {
22842 $constraint = new Constraint('=', $package->getVersion());
22843 $constraint->setPrettyString($package->getPrettyVersion());
22844
22845
22846 if ($package->getRepository() !== $platformRepo
22847 || !isset($provided[$package->getName()])
22848 || !$provided[$package->getName()]->getConstraint()->matches($constraint)
22849 ) {
22850 $request->fix($package->getName(), $constraint);
22851 }
22852 }
22853
22854 return $request;
22855 }
22856
22857
22858
22859
22860
22861
22862
22863
22864
22865
22866
22867
22868 private function processDevPackages($localRepo, $pool, $policy, $repositories, $installedRepo, $lockedRepository, $task, array $operations = null)
22869 {
22870 if ($task === 'force-updates' && null === $operations) {
22871 throw new \InvalidArgumentException('Missing operations argument');
22872 }
22873 if ($task === 'force-links') {
22874 $operations = array();
22875 }
22876
22877 if ($this->update && $this->updateWhitelist) {
22878 $currentPackages = $this->getCurrentPackages($installedRepo);
22879 }
22880
22881 foreach ($localRepo->getCanonicalPackages() as $package) {
22882
22883 if (!$package->isDev()) {
22884 continue;
22885 }
22886
22887
22888 foreach ($operations as $operation) {
22889 if (('update' === $operation->getJobType() && $operation->getInitialPackage()->equals($package))
22890 || ('uninstall' === $operation->getJobType() && $operation->getPackage()->equals($package))
22891 ) {
22892 continue 2;
22893 }
22894 }
22895
22896 if ($this->update) {
22897
22898 if ($this->updateWhitelist && !$this->isUpdateable($package)) {
22899
22900 foreach ($currentPackages as $curPackage) {
22901 if ($curPackage->isDev() && $curPackage->getName() === $package->getName() && $curPackage->getVersion() === $package->getVersion()) {
22902 if ($task === 'force-links') {
22903 $package->setRequires($curPackage->getRequires());
22904 $package->setConflicts($curPackage->getConflicts());
22905 $package->setProvides($curPackage->getProvides());
22906 $package->setReplaces($curPackage->getReplaces());
22907 } elseif ($task === 'force-updates') {
22908 if (($curPackage->getSourceReference() && $curPackage->getSourceReference() !== $package->getSourceReference())
22909 || ($curPackage->getDistReference() && $curPackage->getDistReference() !== $package->getDistReference())
22910 ) {
22911 $operations[] = new UpdateOperation($package, $curPackage);
22912 }
22913 }
22914
22915 break;
22916 }
22917 }
22918
22919 continue;
22920 }
22921
22922
22923 $matches = $pool->whatProvides($package->getName(), new Constraint('=', $package->getVersion()));
22924 foreach ($matches as $index => $match) {
22925
22926 if (!in_array($match->getRepository(), $repositories, true)) {
22927 unset($matches[$index]);
22928 continue;
22929 }
22930
22931
22932 if ($match->getName() !== $package->getName()) {
22933 unset($matches[$index]);
22934 continue;
22935 }
22936
22937 $matches[$index] = $match->getId();
22938 }
22939
22940
22941 if ($matches && $matches = $policy->selectPreferredPackages($pool, array(), $matches)) {
22942 $newPackage = $pool->literalToPackage($matches[0]);
22943
22944 if ($task === 'force-links' && $newPackage) {
22945 $package->setRequires($newPackage->getRequires());
22946 $package->setConflicts($newPackage->getConflicts());
22947 $package->setProvides($newPackage->getProvides());
22948 $package->setReplaces($newPackage->getReplaces());
22949 }
22950
22951 if (
22952 $task === 'force-updates'
22953 && $newPackage
22954 && (
22955 ($newPackage->getSourceReference() && $newPackage->getSourceReference() !== $package->getSourceReference())
22956 || ($newPackage->getDistReference() && $newPackage->getDistReference() !== $package->getDistReference())
22957 )
22958 ) {
22959 $operations[] = new UpdateOperation($package, $newPackage);
22960
22961 continue;
22962 }
22963 }
22964
22965 if ($task === 'force-updates') {
22966
22967 $references = $this->package->getReferences();
22968
22969 if (isset($references[$package->getName()]) && $references[$package->getName()] !== $package->getSourceReference()) {
22970
22971 $operations[] = new UpdateOperation($package, clone $package);
22972 }
22973 }
22974 } else {
22975
22976 foreach ($lockedRepository->findPackages($package->getName()) as $lockedPackage) {
22977 if ($lockedPackage->isDev() && $lockedPackage->getVersion() === $package->getVersion()) {
22978 if ($task === 'force-links') {
22979 $package->setRequires($lockedPackage->getRequires());
22980 $package->setConflicts($lockedPackage->getConflicts());
22981 $package->setProvides($lockedPackage->getProvides());
22982 $package->setReplaces($lockedPackage->getReplaces());
22983 } elseif ($task === 'force-updates') {
22984 if (($lockedPackage->getSourceReference() && $lockedPackage->getSourceReference() !== $package->getSourceReference())
22985 || ($lockedPackage->getDistReference() && $lockedPackage->getDistReference() !== $package->getDistReference())
22986 ) {
22987 $operations[] = new UpdateOperation($package, $lockedPackage);
22988 }
22989 }
22990
22991 break;
22992 }
22993 }
22994 }
22995 }
22996
22997 return $operations;
22998 }
22999
23000
23001
23002
23003
23004
23005 private function getCurrentPackages($installedRepo)
23006 {
23007 if ($this->locker->isLocked()) {
23008 try {
23009 return $this->locker->getLockedRepository(true)->getPackages();
23010 } catch (\RuntimeException $e) {
23011
23012 return $this->locker->getLockedRepository()->getPackages();
23013 }
23014 }
23015
23016 return $installedRepo->getPackages();
23017 }
23018
23019
23020
23021
23022 private function getRootAliases()
23023 {
23024 if ($this->update) {
23025 $aliases = $this->package->getAliases();
23026 } else {
23027 $aliases = $this->locker->getAliases();
23028 }
23029
23030 $normalizedAliases = array();
23031
23032 foreach ($aliases as $alias) {
23033 $normalizedAliases[$alias['package']][$alias['version']] = array(
23034 'alias' => $alias['alias'],
23035 'alias_normalized' => $alias['alias_normalized'],
23036 );
23037 }
23038
23039 return $normalizedAliases;
23040 }
23041
23042
23043
23044
23045
23046
23047
23048 private function processPackageUrls($pool, $policy, $localRepo, $repositories)
23049 {
23050 if (!$this->update) {
23051 return;
23052 }
23053
23054 $rootRefs = $this->package->getReferences();
23055
23056 foreach ($localRepo->getCanonicalPackages() as $package) {
23057
23058 $matches = $pool->whatProvides($package->getName(), new Constraint('=', $package->getVersion()));
23059 foreach ($matches as $index => $match) {
23060
23061 if (!in_array($match->getRepository(), $repositories, true)) {
23062 unset($matches[$index]);
23063 continue;
23064 }
23065
23066
23067 if ($match->getName() !== $package->getName()) {
23068 unset($matches[$index]);
23069 continue;
23070 }
23071
23072 $matches[$index] = $match->getId();
23073 }
23074
23075
23076 if ($matches && $matches = $policy->selectPreferredPackages($pool, array(), $matches)) {
23077 $newPackage = $pool->literalToPackage($matches[0]);
23078
23079
23080 $sourceUrl = $package->getSourceUrl();
23081 $newSourceUrl = $newPackage->getSourceUrl();
23082 $newReference = $newPackage->getSourceReference();
23083
23084 if ($package->isDev() && isset($rootRefs[$package->getName()]) && $package->getSourceReference() === $rootRefs[$package->getName()]) {
23085 $newReference = $rootRefs[$package->getName()];
23086 }
23087
23088 $this->updatePackageUrl($package, $newSourceUrl, $newPackage->getSourceType(), $newReference, $newPackage->getDistUrl(), $newPackage->getDistType(), $newPackage->getDistSha1Checksum());
23089
23090 if ($package instanceof CompletePackage && $newPackage instanceof CompletePackage) {
23091 $package->setAbandoned($newPackage->getReplacementPackage() ?: $newPackage->isAbandoned());
23092 }
23093
23094 $package->setDistMirrors($newPackage->getDistMirrors());
23095 $package->setSourceMirrors($newPackage->getSourceMirrors());
23096 $package->setTransportOptions($newPackage->getTransportOptions());
23097 }
23098 }
23099 }
23100
23101 private function updatePackageUrl(PackageInterface $package, $sourceUrl, $sourceType, $sourceReference, $distUrl, $distType, $distShaSum)
23102 {
23103 $oldSourceRef = $package->getSourceReference();
23104
23105 if ($package->getSourceUrl() !== $sourceUrl) {
23106 $package->setSourceType($sourceType);
23107 $package->setSourceUrl($sourceUrl);
23108 $package->setSourceReference($sourceReference);
23109 }
23110
23111
23112
23113 if (preg_match('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com|(?:www\.)?gitlab\.com)/}i', $distUrl)) {
23114 $package->setDistUrl($distUrl);
23115 $package->setDistType($distType);
23116 $package->setDistSha1Checksum($distShaSum);
23117 $this->updateInstallReferences($package, $sourceReference);
23118 }
23119
23120 if ($this->updateWhitelist && !$this->isUpdateable($package)) {
23121 $this->updateInstallReferences($package, $oldSourceRef);
23122 }
23123 }
23124
23125 private function updateInstallReferences(PackageInterface $package, $reference)
23126 {
23127 if (!$reference) {
23128 return;
23129 }
23130
23131 $package->setSourceReference($reference);
23132
23133 if (preg_match('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com|(?:www\.)?gitlab\.com)/}i', $package->getDistUrl())) {
23134 $package->setDistReference($reference);
23135 $package->setDistUrl(preg_replace('{(?<=/|sha=)[a-f0-9]{40}(?=/|$)}i', $reference, $package->getDistUrl()));
23136 } elseif ($package->getDistReference()) { 
23137 $package->setDistReference($reference);
23138 }
23139 }
23140
23141
23142
23143
23144
23145 private function aliasPlatformPackages(PlatformRepository $platformRepo, $aliases)
23146 {
23147 foreach ($aliases as $package => $versions) {
23148 foreach ($versions as $version => $alias) {
23149 $packages = $platformRepo->findPackages($package, $version);
23150 foreach ($packages as $package) {
23151 $aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias']);
23152 $aliasPackage->setRootPackageAlias(true);
23153 $platformRepo->addPackage($aliasPackage);
23154 }
23155 }
23156 }
23157 }
23158
23159
23160
23161
23162
23163 private function isUpdateable(PackageInterface $package)
23164 {
23165 if (!$this->updateWhitelist) {
23166 throw new \LogicException('isUpdateable should only be called when an allow list is present');
23167 }
23168
23169 foreach ($this->updateWhitelist as $pattern => $void) {
23170 $patternRegexp = BasePackage::packageNameToRegexp($pattern);
23171 if (preg_match($patternRegexp, $package->getName())) {
23172 return true;
23173 }
23174 }
23175
23176 return false;
23177 }
23178
23179
23180
23181
23182
23183 private function extractPlatformRequirements($links)
23184 {
23185 $platformReqs = array();
23186 foreach ($links as $link) {
23187 if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $link->getTarget())) {
23188 $platformReqs[$link->getTarget()] = $link->getPrettyConstraint();
23189 }
23190 }
23191
23192 return $platformReqs;
23193 }
23194
23195
23196
23197
23198
23199
23200
23201
23202
23203
23204
23205
23206
23207
23208 private function allowListUpdateDependencies($localOrLockRepo, array $rootRequires, array $rootDevRequires)
23209 {
23210 if (!$this->updateWhitelist) {
23211 return;
23212 }
23213
23214 $rootRequires = array_merge($rootRequires, $rootDevRequires);
23215
23216 $skipPackages = array();
23217 if (!$this->whitelistAllDependencies) {
23218 foreach ($rootRequires as $require) {
23219 $skipPackages[$require->getTarget()] = true;
23220 }
23221 }
23222
23223 $pool = new Pool('dev');
23224 $pool->addRepository($localOrLockRepo);
23225
23226 $seen = array();
23227
23228 $rootRequiredPackageNames = array_keys($rootRequires);
23229
23230 foreach ($this->updateWhitelist as $packageName => $void) {
23231 $packageQueue = new \SplQueue;
23232 $nameMatchesRequiredPackage = false;
23233
23234 $depPackages = $pool->whatProvides($packageName);
23235 $matchesByPattern = array();
23236
23237 if (empty($depPackages)) {
23238
23239 $allowListPatternSearchRegexp = BasePackage::packageNameToRegexp($packageName, '^%s$');
23240 foreach ($localOrLockRepo->search($allowListPatternSearchRegexp) as $installedPackage) {
23241 $matchesByPattern[] = $pool->whatProvides($installedPackage['name']);
23242 }
23243
23244
23245 $allowListPatternRegexp = BasePackage::packageNameToRegexp($packageName);
23246 foreach ($rootRequiredPackageNames as $rootRequiredPackageName) {
23247 if (preg_match($allowListPatternRegexp, $rootRequiredPackageName)) {
23248 $nameMatchesRequiredPackage = true;
23249 break;
23250 }
23251 }
23252 }
23253
23254 if (!empty($matchesByPattern)) {
23255 $depPackages = array_merge($depPackages, call_user_func_array('array_merge', $matchesByPattern));
23256 }
23257
23258 if (count($depPackages) == 0 && !$nameMatchesRequiredPackage && !in_array($packageName, array('nothing', 'lock', 'mirrors'))) {
23259 $this->io->writeError('<warning>Package "' . $packageName . '" listed for update is not installed. Ignoring.</warning>');
23260 }
23261
23262 foreach ($depPackages as $depPackage) {
23263 $packageQueue->enqueue($depPackage);
23264 }
23265
23266 while (!$packageQueue->isEmpty()) {
23267 $package = $packageQueue->dequeue();
23268 if (isset($seen[$package->getId()])) {
23269 continue;
23270 }
23271
23272 $seen[$package->getId()] = true;
23273 $this->updateWhitelist[$package->getName()] = true;
23274
23275 if (!$this->whitelistDependencies && !$this->whitelistAllDependencies) {
23276 continue;
23277 }
23278
23279 $requires = $package->getRequires();
23280
23281 foreach ($requires as $require) {
23282 $requirePackages = $pool->whatProvides($require->getTarget());
23283
23284 foreach ($requirePackages as $requirePackage) {
23285 if (isset($this->updateWhitelist[$requirePackage->getName()])) {
23286 continue;
23287 }
23288
23289 if (isset($skipPackages[$requirePackage->getName()]) && !preg_match(BasePackage::packageNameToRegexp($packageName), $requirePackage->getName())) {
23290 $this->io->writeError('<warning>Dependency "' . $requirePackage->getName() . '" is also a root requirement, but is not explicitly allowed. Ignoring.</warning>');
23291 continue;
23292 }
23293
23294 $packageQueue->enqueue($requirePackage);
23295 }
23296 }
23297 }
23298 }
23299 }
23300
23301
23302
23303
23304
23305
23306
23307
23308 private function mockLocalRepositories(RepositoryManager $rm)
23309 {
23310 $packages = array();
23311 foreach ($rm->getLocalRepository()->getPackages() as $package) {
23312 $packages[(string) $package] = clone $package;
23313 }
23314 foreach ($packages as $key => $package) {
23315 if ($package instanceof AliasPackage) {
23316 $alias = (string) $package->getAliasOf();
23317 $packages[$key] = new AliasPackage($packages[$alias], $package->getVersion(), $package->getPrettyVersion());
23318 }
23319 }
23320 $rm->setLocalRepository(
23321 new InstalledArrayRepository($packages)
23322 );
23323 }
23324
23325
23326
23327
23328
23329
23330
23331
23332 public static function create(IOInterface $io, Composer $composer)
23333 {
23334 return new static(
23335 $io,
23336 $composer->getConfig(),
23337 $composer->getPackage(),
23338 $composer->getDownloadManager(),
23339 $composer->getRepositoryManager(),
23340 $composer->getLocker(),
23341 $composer->getInstallationManager(),
23342 $composer->getEventDispatcher(),
23343 $composer->getAutoloadGenerator()
23344 );
23345 }
23346
23347
23348
23349
23350
23351 public function setAdditionalInstalledRepository(RepositoryInterface $additionalInstalledRepository)
23352 {
23353 $this->additionalInstalledRepository = $additionalInstalledRepository;
23354
23355 return $this;
23356 }
23357
23358
23359
23360
23361
23362
23363
23364 public function setDryRun($dryRun = true)
23365 {
23366 $this->dryRun = (bool) $dryRun;
23367
23368 return $this;
23369 }
23370
23371
23372
23373
23374
23375
23376 public function isDryRun()
23377 {
23378 return $this->dryRun;
23379 }
23380
23381
23382
23383
23384
23385
23386
23387 public function setPreferSource($preferSource = true)
23388 {
23389 $this->preferSource = (bool) $preferSource;
23390
23391 return $this;
23392 }
23393
23394
23395
23396
23397
23398
23399
23400 public function setPreferDist($preferDist = true)
23401 {
23402 $this->preferDist = (bool) $preferDist;
23403
23404 return $this;
23405 }
23406
23407
23408
23409
23410
23411
23412
23413 public function setOptimizeAutoloader($optimizeAutoloader = false)
23414 {
23415 $this->optimizeAutoloader = (bool) $optimizeAutoloader;
23416 if (!$this->optimizeAutoloader) {
23417
23418
23419 $this->setClassMapAuthoritative(false);
23420 }
23421
23422 return $this;
23423 }
23424
23425
23426
23427
23428
23429
23430
23431
23432 public function setClassMapAuthoritative($classMapAuthoritative = false)
23433 {
23434 $this->classMapAuthoritative = (bool) $classMapAuthoritative;
23435 if ($this->classMapAuthoritative) {
23436
23437 $this->setOptimizeAutoloader(true);
23438 }
23439
23440 return $this;
23441 }
23442
23443
23444
23445
23446
23447
23448
23449 public function setApcuAutoloader($apcuAutoloader = false)
23450 {
23451 $this->apcuAutoloader = (bool) $apcuAutoloader;
23452
23453 return $this;
23454 }
23455
23456
23457
23458
23459
23460
23461
23462 public function setUpdate($update = true)
23463 {
23464 $this->update = (bool) $update;
23465
23466 return $this;
23467 }
23468
23469
23470
23471
23472
23473
23474
23475 public function setDevMode($devMode = true)
23476 {
23477 $this->devMode = (bool) $devMode;
23478
23479 return $this;
23480 }
23481
23482
23483
23484
23485
23486
23487
23488
23489
23490 public function setDumpAutoloader($dumpAutoloader = true)
23491 {
23492 $this->dumpAutoloader = (bool) $dumpAutoloader;
23493
23494 return $this;
23495 }
23496
23497
23498
23499
23500
23501
23502
23503
23504
23505 public function setRunScripts($runScripts = true)
23506 {
23507 $this->runScripts = (bool) $runScripts;
23508
23509 return $this;
23510 }
23511
23512
23513
23514
23515
23516
23517
23518 public function setConfig(Config $config)
23519 {
23520 $this->config = $config;
23521
23522 return $this;
23523 }
23524
23525
23526
23527
23528
23529
23530
23531 public function setVerbose($verbose = true)
23532 {
23533 $this->verbose = (bool) $verbose;
23534
23535 return $this;
23536 }
23537
23538
23539
23540
23541
23542
23543 public function isVerbose()
23544 {
23545 return $this->verbose;
23546 }
23547
23548
23549
23550
23551
23552
23553
23554 public function setIgnorePlatformRequirements($ignorePlatformReqs = false)
23555 {
23556 $this->ignorePlatformReqs = (bool) $ignorePlatformReqs;
23557
23558 return $this;
23559 }
23560
23561
23562
23563
23564
23565
23566
23567
23568
23569
23570 public function setUpdateWhitelist(array $packages)
23571 {
23572 $this->updateWhitelist = array_flip(array_map('strtolower', $packages));
23573
23574 return $this;
23575 }
23576
23577
23578
23579
23580
23581
23582
23583
23584 public function setUpdateAllowList(array $packages)
23585 {
23586
23587 return $this->setUpdateWhitelist($packages);
23588 }
23589
23590
23591
23592
23593 public function setWhitelistDependencies($updateDependencies = true)
23594 {
23595 return $this->setWhitelistTransitiveDependencies($updateDependencies);
23596 }
23597
23598
23599
23600
23601
23602
23603
23604
23605
23606
23607
23608
23609 public function setWhitelistTransitiveDependencies($updateTransitiveDependencies = true)
23610 {
23611 $this->whitelistDependencies = (bool) $updateTransitiveDependencies;
23612
23613 return $this;
23614 }
23615
23616
23617
23618
23619
23620
23621
23622
23623
23624
23625 public function setAllowListTransitiveDependencies($updateTransitiveDependencies = true)
23626 {
23627
23628 return $this->setWhitelistTransitiveDependencies($updateTransitiveDependencies);
23629 }
23630
23631
23632
23633
23634
23635
23636
23637
23638
23639
23640
23641
23642 public function setWhitelistAllDependencies($updateAllDependencies = true)
23643 {
23644 $this->whitelistAllDependencies = (bool) $updateAllDependencies;
23645
23646 return $this;
23647 }
23648
23649
23650
23651
23652
23653
23654
23655
23656
23657
23658 public function setAllowListAllDependencies($updateAllDependencies = true)
23659 {
23660
23661 return $this->setWhitelistAllDependencies($updateAllDependencies);
23662 }
23663
23664
23665
23666
23667
23668
23669
23670 public function setPreferStable($preferStable = true)
23671 {
23672 $this->preferStable = (bool) $preferStable;
23673
23674 return $this;
23675 }
23676
23677
23678
23679
23680
23681
23682
23683 public function setPreferLowest($preferLowest = true)
23684 {
23685 $this->preferLowest = (bool) $preferLowest;
23686
23687 return $this;
23688 }
23689
23690
23691
23692
23693
23694
23695
23696
23697
23698 public function setWriteLock($writeLock = true)
23699 {
23700 $this->writeLock = (bool) $writeLock;
23701
23702 return $this;
23703 }
23704
23705
23706
23707
23708
23709
23710
23711
23712
23713 public function setExecuteOperations($executeOperations = true)
23714 {
23715 $this->executeOperations = (bool) $executeOperations;
23716
23717 return $this;
23718 }
23719
23720
23721
23722
23723
23724
23725
23726 public function setSkipSuggest($skipSuggest = true)
23727 {
23728 $this->skipSuggest = (bool) $skipSuggest;
23729
23730 return $this;
23731 }
23732
23733
23734
23735
23736
23737
23738
23739
23740
23741
23742 public function disablePlugins()
23743 {
23744 $this->installationManager->disablePlugins();
23745
23746 return $this;
23747 }
23748
23749
23750
23751
23752
23753 public function setSuggestedPackagesReporter(SuggestedPackagesReporter $suggestedPackagesReporter)
23754 {
23755 $this->suggestedPackagesReporter = $suggestedPackagesReporter;
23756
23757 return $this;
23758 }
23759 }
23760 <?php
23761
23762
23763
23764
23765
23766
23767
23768
23769
23770
23771
23772 namespace Composer\Installer;
23773
23774 use Composer\IO\IOInterface;
23775 use Composer\Package\PackageInterface;
23776 use Composer\Util\Filesystem;
23777 use Composer\Util\Platform;
23778 use Composer\Util\ProcessExecutor;
23779 use Composer\Util\Silencer;
23780
23781
23782
23783
23784
23785
23786
23787
23788 class BinaryInstaller
23789 {
23790 protected $binDir;
23791 protected $binCompat;
23792 protected $io;
23793 protected $filesystem;
23794
23795
23796
23797
23798
23799
23800
23801 public function __construct(IOInterface $io, $binDir, $binCompat, Filesystem $filesystem = null)
23802 {
23803 $this->binDir = $binDir;
23804 $this->binCompat = $binCompat;
23805 $this->io = $io;
23806 $this->filesystem = $filesystem ?: new Filesystem();
23807 }
23808
23809 public function installBinaries(PackageInterface $package, $installPath, $warnOnOverwrite = true)
23810 {
23811 $binaries = $this->getBinaries($package);
23812 if (!$binaries) {
23813 return;
23814 }
23815 foreach ($binaries as $bin) {
23816 $binPath = $installPath.'/'.$bin;
23817 if (!file_exists($binPath)) {
23818 $this->io->writeError('    <warning>Skipped installation of bin '.$bin.' for package '.$package->getName().': file not found in package</warning>');
23819 continue;
23820 }
23821
23822
23823
23824
23825
23826 $binPath = realpath($binPath);
23827
23828 $this->initializeBinDir();
23829 $link = $this->binDir.'/'.basename($bin);
23830 if (file_exists($link)) {
23831 if (is_link($link)) {
23832
23833
23834
23835 Silencer::call('chmod', $link, 0777 & ~umask());
23836 }
23837 if ($warnOnOverwrite) {
23838 $this->io->writeError('    Skipped installation of bin '.$bin.' for package '.$package->getName().': name conflicts with an existing file');
23839 }
23840 continue;
23841 }
23842
23843 if ($this->binCompat === "auto") {
23844 if (Platform::isWindows()) {
23845 $this->installFullBinaries($binPath, $link, $bin, $package);
23846 } else {
23847 $this->installSymlinkBinaries($binPath, $link);
23848 }
23849 } elseif ($this->binCompat === "full") {
23850 $this->installFullBinaries($binPath, $link, $bin, $package);
23851 }
23852 Silencer::call('chmod', $link, 0777 & ~umask());
23853 }
23854 }
23855
23856 public function removeBinaries(PackageInterface $package)
23857 {
23858 $this->initializeBinDir();
23859
23860 $binaries = $this->getBinaries($package);
23861 if (!$binaries) {
23862 return;
23863 }
23864 foreach ($binaries as $bin) {
23865 $link = $this->binDir.'/'.basename($bin);
23866 if (is_link($link) || file_exists($link)) {
23867 $this->filesystem->unlink($link);
23868 }
23869 if (file_exists($link.'.bat')) {
23870 $this->filesystem->unlink($link.'.bat');
23871 }
23872 }
23873
23874
23875 if (is_dir($this->binDir) && $this->filesystem->isDirEmpty($this->binDir)) {
23876 Silencer::call('rmdir', $this->binDir);
23877 }
23878 }
23879
23880 public static function determineBinaryCaller($bin)
23881 {
23882 if ('.bat' === substr($bin, -4) || '.exe' === substr($bin, -4)) {
23883 return 'call';
23884 }
23885
23886 $handle = fopen($bin, 'r');
23887 $line = fgets($handle);
23888 fclose($handle);
23889 if (preg_match('{^#!/(?:usr/bin/env )?(?:[^/]+/)*(.+)$}m', $line, $match)) {
23890 return trim($match[1]);
23891 }
23892
23893 return 'php';
23894 }
23895
23896 protected function getBinaries(PackageInterface $package)
23897 {
23898 return $package->getBinaries();
23899 }
23900
23901 protected function installFullBinaries($binPath, $link, $bin, PackageInterface $package)
23902 {
23903
23904 if ('.bat' !== substr($binPath, -4)) {
23905 $this->installUnixyProxyBinaries($binPath, $link);
23906 @chmod($link, 0777 & ~umask());
23907 $link .= '.bat';
23908 if (file_exists($link)) {
23909 $this->io->writeError('    Skipped installation of bin '.$bin.'.bat proxy for package '.$package->getName().': a .bat proxy was already installed');
23910 }
23911 }
23912 if (!file_exists($link)) {
23913 file_put_contents($link, $this->generateWindowsProxyCode($binPath, $link));
23914 }
23915 }
23916
23917 protected function installSymlinkBinaries($binPath, $link)
23918 {
23919 if (!$this->filesystem->relativeSymlink($binPath, $link)) {
23920 $this->installUnixyProxyBinaries($binPath, $link);
23921 }
23922 }
23923
23924 protected function installUnixyProxyBinaries($binPath, $link)
23925 {
23926 file_put_contents($link, $this->generateUnixyProxyCode($binPath, $link));
23927 }
23928
23929 protected function initializeBinDir()
23930 {
23931 $this->filesystem->ensureDirectoryExists($this->binDir);
23932 $this->binDir = realpath($this->binDir);
23933 }
23934
23935 protected function generateWindowsProxyCode($bin, $link)
23936 {
23937 $binPath = $this->filesystem->findShortestPath($link, $bin);
23938 $caller = self::determineBinaryCaller($bin);
23939
23940 return "@ECHO OFF\r\n".
23941 "setlocal DISABLEDELAYEDEXPANSION\r\n".
23942 "SET BIN_TARGET=%~dp0/".trim(ProcessExecutor::escape($binPath), '"\'')."\r\n".
23943 "{$caller} \"%BIN_TARGET%\" %*\r\n";
23944 }
23945
23946 protected function generateUnixyProxyCode($bin, $link)
23947 {
23948 $binPath = $this->filesystem->findShortestPath($link, $bin);
23949
23950 $binDir = ProcessExecutor::escape(dirname($binPath));
23951 $binFile = basename($binPath);
23952
23953 $proxyCode = <<<PROXY
23954 #!/usr/bin/env sh
23955
23956 dir=\$(cd "\${0%[/\\\\]*}" > /dev/null; cd $binDir && pwd)
23957
23958 if [ -d /proc/cygdrive ]; then
23959     case \$(which php) in
23960         \$(readlink -n /proc/cygdrive)/*)
23961             # We are in Cygwin using Windows php, so the path must be translated
23962             dir=\$(cygpath -m "\$dir");
23963             ;;
23964     esac
23965 fi
23966
23967 "\${dir}/$binFile" "\$@"
23968
23969 PROXY;
23970
23971 return $proxyCode;
23972 }
23973 }
23974 <?php
23975
23976
23977
23978
23979
23980
23981
23982
23983
23984
23985
23986 namespace Composer\Installer;
23987
23988 use Composer\Package\PackageInterface;
23989
23990
23991
23992
23993
23994
23995 interface BinaryPresenceInterface
23996 {
23997
23998
23999
24000
24001
24002 public function ensureBinariesPresence(PackageInterface $package);
24003 }
24004 <?php
24005
24006
24007
24008
24009
24010
24011
24012
24013
24014
24015
24016 namespace Composer\Installer;
24017
24018 use Composer\IO\IOInterface;
24019 use Composer\Package\PackageInterface;
24020 use Composer\Package\AliasPackage;
24021 use Composer\Repository\RepositoryInterface;
24022 use Composer\Repository\InstalledRepositoryInterface;
24023 use Composer\DependencyResolver\Operation\OperationInterface;
24024 use Composer\DependencyResolver\Operation\InstallOperation;
24025 use Composer\DependencyResolver\Operation\UpdateOperation;
24026 use Composer\DependencyResolver\Operation\UninstallOperation;
24027 use Composer\DependencyResolver\Operation\MarkAliasInstalledOperation;
24028 use Composer\DependencyResolver\Operation\MarkAliasUninstalledOperation;
24029 use Composer\Util\StreamContextFactory;
24030
24031
24032
24033
24034
24035
24036
24037
24038 class InstallationManager
24039 {
24040 private $installers = array();
24041 private $cache = array();
24042 private $notifiablePackages = array();
24043
24044 public function reset()
24045 {
24046 $this->notifiablePackages = array();
24047 }
24048
24049
24050
24051
24052
24053
24054 public function addInstaller(InstallerInterface $installer)
24055 {
24056 array_unshift($this->installers, $installer);
24057 $this->cache = array();
24058 }
24059
24060
24061
24062
24063
24064
24065 public function removeInstaller(InstallerInterface $installer)
24066 {
24067 if (false !== ($key = array_search($installer, $this->installers, true))) {
24068 array_splice($this->installers, $key, 1);
24069 $this->cache = array();
24070 }
24071 }
24072
24073
24074
24075
24076
24077
24078
24079
24080 public function disablePlugins()
24081 {
24082 foreach ($this->installers as $i => $installer) {
24083 if (!$installer instanceof PluginInstaller) {
24084 continue;
24085 }
24086
24087 unset($this->installers[$i]);
24088 }
24089 }
24090
24091
24092
24093
24094
24095
24096
24097
24098
24099 public function getInstaller($type)
24100 {
24101 $type = strtolower($type);
24102
24103 if (isset($this->cache[$type])) {
24104 return $this->cache[$type];
24105 }
24106
24107 foreach ($this->installers as $installer) {
24108 if ($installer->supports($type)) {
24109 return $this->cache[$type] = $installer;
24110 }
24111 }
24112
24113 throw new \InvalidArgumentException('Unknown installer type: '.$type);
24114 }
24115
24116
24117
24118
24119
24120
24121
24122
24123
24124 public function isPackageInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
24125 {
24126 if ($package instanceof AliasPackage) {
24127 return $repo->hasPackage($package) && $this->isPackageInstalled($repo, $package->getAliasOf());
24128 }
24129
24130 return $this->getInstaller($package->getType())->isInstalled($repo, $package);
24131 }
24132
24133
24134
24135
24136
24137
24138
24139 public function ensureBinariesPresence(PackageInterface $package)
24140 {
24141 try {
24142 $installer = $this->getInstaller($package->getType());
24143 } catch (\InvalidArgumentException $e) {
24144
24145 return;
24146 }
24147
24148
24149 if ($installer instanceof BinaryPresenceInterface) {
24150 $installer->ensureBinariesPresence($package);
24151 }
24152 }
24153
24154
24155
24156
24157
24158
24159
24160 public function execute(RepositoryInterface $repo, OperationInterface $operation)
24161 {
24162 $method = $operation->getJobType();
24163 $this->$method($repo, $operation);
24164 }
24165
24166
24167
24168
24169
24170
24171
24172 public function install(RepositoryInterface $repo, InstallOperation $operation)
24173 {
24174 $package = $operation->getPackage();
24175 $installer = $this->getInstaller($package->getType());
24176 $installer->install($repo, $package);
24177 $this->markForNotification($package);
24178 }
24179
24180
24181
24182
24183
24184
24185
24186 public function update(RepositoryInterface $repo, UpdateOperation $operation)
24187 {
24188 $initial = $operation->getInitialPackage();
24189 $target = $operation->getTargetPackage();
24190
24191 $initialType = $initial->getType();
24192 $targetType = $target->getType();
24193
24194 if ($initialType === $targetType) {
24195 $installer = $this->getInstaller($initialType);
24196 $installer->update($repo, $initial, $target);
24197 $this->markForNotification($target);
24198 } else {
24199 $this->getInstaller($initialType)->uninstall($repo, $initial);
24200 $this->getInstaller($targetType)->install($repo, $target);
24201 }
24202 }
24203
24204
24205
24206
24207
24208
24209
24210 public function uninstall(RepositoryInterface $repo, UninstallOperation $operation)
24211 {
24212 $package = $operation->getPackage();
24213 $installer = $this->getInstaller($package->getType());
24214 $installer->uninstall($repo, $package);
24215 }
24216
24217
24218
24219
24220
24221
24222
24223 public function markAliasInstalled(RepositoryInterface $repo, MarkAliasInstalledOperation $operation)
24224 {
24225 $package = $operation->getPackage();
24226
24227 if (!$repo->hasPackage($package)) {
24228 $repo->addPackage(clone $package);
24229 }
24230 }
24231
24232
24233
24234
24235
24236
24237
24238 public function markAliasUninstalled(RepositoryInterface $repo, MarkAliasUninstalledOperation $operation)
24239 {
24240 $package = $operation->getPackage();
24241
24242 $repo->removePackage($package);
24243 }
24244
24245
24246
24247
24248
24249
24250
24251 public function getInstallPath(PackageInterface $package)
24252 {
24253 $installer = $this->getInstaller($package->getType());
24254
24255 return $installer->getInstallPath($package);
24256 }
24257
24258 public function notifyInstalls(IOInterface $io)
24259 {
24260 foreach ($this->notifiablePackages as $repoUrl => $packages) {
24261 $repositoryName = parse_url($repoUrl, PHP_URL_HOST);
24262 if ($io->hasAuthentication($repositoryName)) {
24263 $auth = $io->getAuthentication($repositoryName);
24264 $authStr = base64_encode($auth['username'] . ':' . $auth['password']);
24265 $authHeader = 'Authorization: Basic '.$authStr;
24266 }
24267
24268
24269 if (strpos($repoUrl, '%package%')) {
24270 foreach ($packages as $package) {
24271 $url = str_replace('%package%', $package->getPrettyName(), $repoUrl);
24272
24273 $params = array(
24274 'version' => $package->getPrettyVersion(),
24275 'version_normalized' => $package->getVersion(),
24276 );
24277 $opts = array('http' =>
24278 array(
24279 'method' => 'POST',
24280 'header' => array('Content-type: application/x-www-form-urlencoded'),
24281 'content' => http_build_query($params, '', '&'),
24282 'timeout' => 3,
24283 ),
24284 );
24285 if (isset($authHeader)) {
24286 $opts['http']['header'][] = $authHeader;
24287 }
24288
24289 $context = StreamContextFactory::getContext($url, $opts);
24290 @file_get_contents($url, false, $context);
24291 }
24292
24293 continue;
24294 }
24295
24296 $postData = array('downloads' => array());
24297 foreach ($packages as $package) {
24298 $postData['downloads'][] = array(
24299 'name' => $package->getPrettyName(),
24300 'version' => $package->getVersion(),
24301 );
24302 }
24303
24304 $opts = array('http' =>
24305 array(
24306 'method' => 'POST',
24307 'header' => array('Content-Type: application/json'),
24308 'content' => json_encode($postData),
24309 'timeout' => 6,
24310 ),
24311 );
24312 if (isset($authHeader)) {
24313 $opts['http']['header'][] = $authHeader;
24314 }
24315
24316 $context = StreamContextFactory::getContext($repoUrl, $opts);
24317 @file_get_contents($repoUrl, false, $context);
24318 }
24319
24320 $this->reset();
24321 }
24322
24323 private function markForNotification(PackageInterface $package)
24324 {
24325 if ($package->getNotificationUrl()) {
24326 $this->notifiablePackages[$package->getNotificationUrl()][$package->getName()] = $package;
24327 }
24328 }
24329 }
24330 <?php
24331
24332
24333
24334
24335
24336
24337
24338
24339
24340
24341
24342 namespace Composer\Installer;
24343
24344 use Composer\Composer;
24345 use Composer\DependencyResolver\PolicyInterface;
24346 use Composer\DependencyResolver\Operation\OperationInterface;
24347 use Composer\DependencyResolver\Pool;
24348 use Composer\DependencyResolver\Request;
24349 use Composer\EventDispatcher\Event;
24350 use Composer\IO\IOInterface;
24351 use Composer\Repository\CompositeRepository;
24352
24353
24354
24355
24356
24357
24358 class InstallerEvent extends Event
24359 {
24360
24361
24362
24363 private $composer;
24364
24365
24366
24367
24368 private $io;
24369
24370
24371
24372
24373 private $devMode;
24374
24375
24376
24377
24378 private $policy;
24379
24380
24381
24382
24383 private $pool;
24384
24385
24386
24387
24388 private $installedRepo;
24389
24390
24391
24392
24393 private $request;
24394
24395
24396
24397
24398 private $operations;
24399
24400
24401
24402
24403
24404
24405
24406
24407
24408
24409
24410
24411
24412
24413 public function __construct($eventName, Composer $composer, IOInterface $io, $devMode, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations = array())
24414 {
24415 parent::__construct($eventName);
24416
24417 $this->composer = $composer;
24418 $this->io = $io;
24419 $this->devMode = $devMode;
24420 $this->policy = $policy;
24421 $this->pool = $pool;
24422 $this->installedRepo = $installedRepo;
24423 $this->request = $request;
24424 $this->operations = $operations;
24425 }
24426
24427
24428
24429
24430 public function getComposer()
24431 {
24432 return $this->composer;
24433 }
24434
24435
24436
24437
24438 public function getIO()
24439 {
24440 return $this->io;
24441 }
24442
24443
24444
24445
24446 public function isDevMode()
24447 {
24448 return $this->devMode;
24449 }
24450
24451
24452
24453
24454 public function getPolicy()
24455 {
24456 return $this->policy;
24457 }
24458
24459
24460
24461
24462 public function getPool()
24463 {
24464 return $this->pool;
24465 }
24466
24467
24468
24469
24470 public function getInstalledRepo()
24471 {
24472 return $this->installedRepo;
24473 }
24474
24475
24476
24477
24478 public function getRequest()
24479 {
24480 return $this->request;
24481 }
24482
24483
24484
24485
24486 public function getOperations()
24487 {
24488 return $this->operations;
24489 }
24490 }
24491 <?php
24492
24493
24494
24495
24496
24497
24498
24499
24500
24501
24502
24503 namespace Composer\Installer;
24504
24505
24506
24507
24508
24509
24510 class InstallerEvents
24511 {
24512
24513
24514
24515
24516
24517
24518
24519
24520
24521 const PRE_DEPENDENCIES_SOLVING = 'pre-dependencies-solving';
24522
24523
24524
24525
24526
24527
24528
24529
24530
24531
24532 const POST_DEPENDENCIES_SOLVING = 'post-dependencies-solving';
24533 }
24534 <?php
24535
24536
24537
24538
24539
24540
24541
24542
24543
24544
24545
24546 namespace Composer\Installer;
24547
24548 use Composer\Package\PackageInterface;
24549 use Composer\Repository\InstalledRepositoryInterface;
24550 use InvalidArgumentException;
24551
24552
24553
24554
24555
24556
24557
24558 interface InstallerInterface
24559 {
24560
24561
24562
24563
24564
24565
24566 public function supports($packageType);
24567
24568
24569
24570
24571
24572
24573
24574
24575
24576 public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package);
24577
24578
24579
24580
24581
24582
24583
24584 public function install(InstalledRepositoryInterface $repo, PackageInterface $package);
24585
24586
24587
24588
24589
24590
24591
24592
24593
24594
24595 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target);
24596
24597
24598
24599
24600
24601
24602
24603 public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package);
24604
24605
24606
24607
24608
24609
24610
24611 public function getInstallPath(PackageInterface $package);
24612 }
24613 <?php
24614
24615
24616
24617
24618
24619
24620
24621
24622
24623
24624
24625 namespace Composer\Installer;
24626
24627 use Composer\Composer;
24628 use Composer\IO\IOInterface;
24629 use Composer\Repository\InstalledRepositoryInterface;
24630 use Composer\Package\PackageInterface;
24631 use Composer\Util\Filesystem;
24632 use Composer\Util\Silencer;
24633 use Composer\Util\Platform;
24634
24635
24636
24637
24638
24639
24640
24641 class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
24642 {
24643 protected $composer;
24644 protected $vendorDir;
24645 protected $binDir;
24646 protected $downloadManager;
24647 protected $io;
24648 protected $type;
24649 protected $filesystem;
24650 protected $binCompat;
24651 protected $binaryInstaller;
24652
24653
24654
24655
24656
24657
24658
24659
24660
24661
24662 public function __construct(IOInterface $io, Composer $composer, $type = 'library', Filesystem $filesystem = null, BinaryInstaller $binaryInstaller = null)
24663 {
24664 $this->composer = $composer;
24665 $this->downloadManager = $composer->getDownloadManager();
24666 $this->io = $io;
24667 $this->type = $type;
24668
24669 $this->filesystem = $filesystem ?: new Filesystem();
24670 $this->vendorDir = rtrim($composer->getConfig()->get('vendor-dir'), '/');
24671 $this->binaryInstaller = $binaryInstaller ?: new BinaryInstaller($this->io, rtrim($composer->getConfig()->get('bin-dir'), '/'), $composer->getConfig()->get('bin-compat'), $this->filesystem);
24672 }
24673
24674
24675
24676
24677 public function supports($packageType)
24678 {
24679 return $packageType === $this->type || null === $this->type;
24680 }
24681
24682
24683
24684
24685 public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
24686 {
24687 if (!$repo->hasPackage($package)) {
24688 return false;
24689 }
24690
24691 $installPath = $this->getInstallPath($package);
24692
24693 if (is_readable($installPath)) {
24694 return true;
24695 }
24696
24697 return (Platform::isWindows() && $this->filesystem->isJunction($installPath)) || is_link($installPath);
24698 }
24699
24700
24701
24702
24703 public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
24704 {
24705 $this->initializeVendorDir();
24706 $downloadPath = $this->getInstallPath($package);
24707
24708
24709 if (!is_readable($downloadPath) && $repo->hasPackage($package)) {
24710 $this->binaryInstaller->removeBinaries($package);
24711 }
24712
24713 $this->installCode($package);
24714 $this->binaryInstaller->installBinaries($package, $this->getInstallPath($package));
24715 if (!$repo->hasPackage($package)) {
24716 $repo->addPackage(clone $package);
24717 }
24718 }
24719
24720
24721
24722
24723 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
24724 {
24725 if (!$repo->hasPackage($initial)) {
24726 throw new \InvalidArgumentException('Package is not installed: '.$initial);
24727 }
24728
24729 $this->initializeVendorDir();
24730
24731 $this->binaryInstaller->removeBinaries($initial);
24732 $this->updateCode($initial, $target);
24733 $this->binaryInstaller->installBinaries($target, $this->getInstallPath($target));
24734 $repo->removePackage($initial);
24735 if (!$repo->hasPackage($target)) {
24736 $repo->addPackage(clone $target);
24737 }
24738 }
24739
24740
24741
24742
24743 public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
24744 {
24745 if (!$repo->hasPackage($package)) {
24746 throw new \InvalidArgumentException('Package is not installed: '.$package);
24747 }
24748
24749 $this->removeCode($package);
24750 $this->binaryInstaller->removeBinaries($package);
24751 $repo->removePackage($package);
24752
24753 $downloadPath = $this->getPackageBasePath($package);
24754 if (strpos($package->getName(), '/')) {
24755 $packageVendorDir = dirname($downloadPath);
24756 if (is_dir($packageVendorDir) && $this->filesystem->isDirEmpty($packageVendorDir)) {
24757 Silencer::call('rmdir', $packageVendorDir);
24758 }
24759 }
24760 }
24761
24762
24763
24764
24765 public function getInstallPath(PackageInterface $package)
24766 {
24767 $this->initializeVendorDir();
24768
24769 $basePath = ($this->vendorDir ? $this->vendorDir.'/' : '') . $package->getPrettyName();
24770 $targetDir = $package->getTargetDir();
24771
24772 return $basePath . ($targetDir ? '/'.$targetDir : '');
24773 }
24774
24775
24776
24777
24778
24779
24780 public function ensureBinariesPresence(PackageInterface $package)
24781 {
24782 $this->binaryInstaller->installBinaries($package, $this->getInstallPath($package), false);
24783 }
24784
24785
24786
24787
24788
24789
24790
24791
24792
24793
24794 protected function getPackageBasePath(PackageInterface $package)
24795 {
24796 $installPath = $this->getInstallPath($package);
24797 $targetDir = $package->getTargetDir();
24798
24799 if ($targetDir) {
24800 return preg_replace('{/*'.str_replace('/', '/+', preg_quote($targetDir)).'/?$}', '', $installPath);
24801 }
24802
24803 return $installPath;
24804 }
24805
24806 protected function installCode(PackageInterface $package)
24807 {
24808 $downloadPath = $this->getInstallPath($package);
24809 $this->downloadManager->download($package, $downloadPath);
24810 }
24811
24812 protected function updateCode(PackageInterface $initial, PackageInterface $target)
24813 {
24814 $initialDownloadPath = $this->getInstallPath($initial);
24815 $targetDownloadPath = $this->getInstallPath($target);
24816 if ($targetDownloadPath !== $initialDownloadPath) {
24817
24818
24819 if (substr($initialDownloadPath, 0, strlen($targetDownloadPath)) === $targetDownloadPath
24820 || substr($targetDownloadPath, 0, strlen($initialDownloadPath)) === $initialDownloadPath
24821 ) {
24822 $this->removeCode($initial);
24823 $this->installCode($target);
24824
24825 return;
24826 }
24827
24828 $this->filesystem->rename($initialDownloadPath, $targetDownloadPath);
24829 }
24830 $this->downloadManager->update($initial, $target, $targetDownloadPath);
24831 }
24832
24833 protected function removeCode(PackageInterface $package)
24834 {
24835 $downloadPath = $this->getPackageBasePath($package);
24836 $this->downloadManager->remove($package, $downloadPath);
24837 }
24838
24839 protected function initializeVendorDir()
24840 {
24841 $this->filesystem->ensureDirectoryExists($this->vendorDir);
24842 $this->vendorDir = realpath($this->vendorDir);
24843 }
24844 }
24845 <?php
24846
24847
24848
24849
24850
24851
24852
24853
24854
24855
24856
24857 namespace Composer\Installer;
24858
24859 use Composer\Repository\InstalledRepositoryInterface;
24860 use Composer\Package\PackageInterface;
24861 use Composer\Package\Version\VersionParser;
24862 use Composer\IO\IOInterface;
24863
24864
24865
24866
24867
24868
24869 class MetapackageInstaller implements InstallerInterface
24870 {
24871 private $io;
24872
24873 public function __construct(IOInterface $io)
24874 {
24875 $this->io = $io;
24876 }
24877
24878
24879
24880
24881 public function supports($packageType)
24882 {
24883 return $packageType === 'metapackage';
24884 }
24885
24886
24887
24888
24889 public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
24890 {
24891 return $repo->hasPackage($package);
24892 }
24893
24894
24895
24896
24897 public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
24898 {
24899 $this->io->writeError("  - Installing <info>" . $package->getName() . "</info> (<comment>" . $package->getFullPrettyVersion() . "</comment>)");
24900
24901 $repo->addPackage(clone $package);
24902 }
24903
24904
24905
24906
24907 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
24908 {
24909 if (!$repo->hasPackage($initial)) {
24910 throw new \InvalidArgumentException('Package is not installed: '.$initial);
24911 }
24912
24913 $name = $target->getName();
24914 $from = $initial->getFullPrettyVersion();
24915 $to = $target->getFullPrettyVersion();
24916 $actionName = VersionParser::isUpgrade($initial->getVersion(), $target->getVersion()) ? 'Updating' : 'Downgrading';
24917 $this->io->writeError("  - " . $actionName . " <info>" . $name . "</info> (<comment>" . $from . "</comment> => <comment>" . $to . "</comment>)");
24918
24919 $repo->removePackage($initial);
24920 $repo->addPackage(clone $target);
24921 }
24922
24923
24924
24925
24926 public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
24927 {
24928 if (!$repo->hasPackage($package)) {
24929 throw new \InvalidArgumentException('Package is not installed: '.$package);
24930 }
24931
24932 $this->io->writeError("  - Removing <info>" . $package->getName() . "</info> (<comment>" . $package->getFullPrettyVersion() . "</comment>)");
24933
24934 $repo->removePackage($package);
24935 }
24936
24937
24938
24939
24940 public function getInstallPath(PackageInterface $package)
24941 {
24942 return '';
24943 }
24944 }
24945 <?php
24946
24947
24948
24949
24950
24951
24952
24953
24954
24955
24956
24957 namespace Composer\Installer;
24958
24959 use Composer\Repository\InstalledRepositoryInterface;
24960 use Composer\Package\PackageInterface;
24961
24962
24963
24964
24965
24966
24967
24968
24969 class NoopInstaller implements InstallerInterface
24970 {
24971
24972
24973
24974 public function supports($packageType)
24975 {
24976 return true;
24977 }
24978
24979
24980
24981
24982 public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
24983 {
24984 return $repo->hasPackage($package);
24985 }
24986
24987
24988
24989
24990 public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
24991 {
24992 if (!$repo->hasPackage($package)) {
24993 $repo->addPackage(clone $package);
24994 }
24995 }
24996
24997
24998
24999
25000 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
25001 {
25002 if (!$repo->hasPackage($initial)) {
25003 throw new \InvalidArgumentException('Package is not installed: '.$initial);
25004 }
25005
25006 $repo->removePackage($initial);
25007 if (!$repo->hasPackage($target)) {
25008 $repo->addPackage(clone $target);
25009 }
25010 }
25011
25012
25013
25014
25015 public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
25016 {
25017 if (!$repo->hasPackage($package)) {
25018 throw new \InvalidArgumentException('Package is not installed: '.$package);
25019 }
25020 $repo->removePackage($package);
25021 }
25022
25023
25024
25025
25026 public function getInstallPath(PackageInterface $package)
25027 {
25028 $targetDir = $package->getTargetDir();
25029
25030 return $package->getPrettyName() . ($targetDir ? '/'.$targetDir : '');
25031 }
25032 }
25033 <?php
25034
25035
25036
25037
25038
25039
25040
25041
25042
25043
25044
25045 namespace Composer\Installer;
25046
25047 use Composer\Composer;
25048 use Composer\IO\IOInterface;
25049 use Composer\DependencyResolver\Operation\OperationInterface;
25050 use Composer\DependencyResolver\PolicyInterface;
25051 use Composer\DependencyResolver\Pool;
25052 use Composer\DependencyResolver\Request;
25053 use Composer\Repository\CompositeRepository;
25054
25055
25056
25057
25058
25059
25060 class PackageEvent extends InstallerEvent
25061 {
25062
25063
25064
25065 private $operation;
25066
25067
25068
25069
25070
25071
25072
25073
25074
25075
25076
25077
25078
25079
25080
25081 public function __construct($eventName, Composer $composer, IOInterface $io, $devMode, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations, OperationInterface $operation)
25082 {
25083 parent::__construct($eventName, $composer, $io, $devMode, $policy, $pool, $installedRepo, $request, $operations);
25084
25085 $this->operation = $operation;
25086 }
25087
25088
25089
25090
25091
25092
25093 public function getOperation()
25094 {
25095 return $this->operation;
25096 }
25097 }
25098 <?php
25099
25100
25101
25102
25103
25104
25105
25106
25107
25108
25109
25110 namespace Composer\Installer;
25111
25112
25113
25114
25115
25116
25117 class PackageEvents
25118 {
25119
25120
25121
25122
25123
25124
25125
25126 const PRE_PACKAGE_INSTALL = 'pre-package-install';
25127
25128
25129
25130
25131
25132
25133
25134
25135 const POST_PACKAGE_INSTALL = 'post-package-install';
25136
25137
25138
25139
25140
25141
25142
25143
25144 const PRE_PACKAGE_UPDATE = 'pre-package-update';
25145
25146
25147
25148
25149
25150
25151
25152
25153 const POST_PACKAGE_UPDATE = 'post-package-update';
25154
25155
25156
25157
25158
25159
25160
25161
25162 const PRE_PACKAGE_UNINSTALL = 'pre-package-uninstall';
25163
25164
25165
25166
25167
25168
25169
25170
25171 const POST_PACKAGE_UNINSTALL = 'post-package-uninstall';
25172 }
25173 <?php
25174
25175
25176
25177
25178
25179
25180
25181
25182
25183
25184
25185 namespace Composer\Installer;
25186
25187 use Composer\IO\IOInterface;
25188 use Composer\Package\PackageInterface;
25189 use Composer\Util\Filesystem;
25190 use Composer\Util\ProcessExecutor;
25191
25192
25193
25194
25195
25196
25197 class PearBinaryInstaller extends BinaryInstaller
25198 {
25199 private $installer;
25200 private $vendorDir;
25201
25202
25203
25204
25205
25206
25207
25208
25209
25210 public function __construct(IOInterface $io, $binDir, $vendorDir, $binCompat, Filesystem $filesystem, PearInstaller $installer)
25211 {
25212 parent::__construct($io, $binDir, $binCompat, $filesystem);
25213 $this->installer = $installer;
25214 $this->vendorDir = $vendorDir;
25215 }
25216
25217 protected function getBinaries(PackageInterface $package)
25218 {
25219 $binariesPath = $this->installer->getInstallPath($package) . '/bin/';
25220 $binaries = array();
25221 if (file_exists($binariesPath)) {
25222 foreach (new \FilesystemIterator($binariesPath, \FilesystemIterator::KEY_AS_FILENAME | \FilesystemIterator::CURRENT_AS_FILEINFO) as $fileName => $value) {
25223 if (!$value->isDir()) {
25224 $binaries[] = 'bin/'.$fileName;
25225 }
25226 }
25227 }
25228
25229 return $binaries;
25230 }
25231
25232 protected function initializeBinDir()
25233 {
25234 parent::initializeBinDir();
25235 file_put_contents($this->binDir.'/composer-php', $this->generateUnixyPhpProxyCode());
25236 @chmod($this->binDir.'/composer-php', 0777 & ~umask());
25237 file_put_contents($this->binDir.'/composer-php.bat', $this->generateWindowsPhpProxyCode());
25238 @chmod($this->binDir.'/composer-php.bat', 0777 & ~umask());
25239 }
25240
25241 protected function generateWindowsProxyCode($bin, $link)
25242 {
25243 $binPath = $this->filesystem->findShortestPath($link, $bin);
25244 if ('.bat' === substr($bin, -4)) {
25245 $caller = 'call';
25246 } else {
25247 $handle = fopen($bin, 'r');
25248 $line = fgets($handle);
25249 fclose($handle);
25250 if (preg_match('{^#!/(?:usr/bin/env )?(?:[^/]+/)*(.+)$}m', $line, $match)) {
25251 $caller = trim($match[1]);
25252 } else {
25253 $caller = 'php';
25254 }
25255
25256 if ($caller === 'php') {
25257 return "@echo off\r\n".
25258 "pushd .\r\n".
25259 "cd %~dp0\r\n".
25260 "set PHP_PROXY=%CD%\\composer-php.bat\r\n".
25261 "cd ".ProcessExecutor::escape(dirname($binPath))."\r\n".
25262 "set BIN_TARGET=%CD%\\".basename($binPath)."\r\n".
25263 "popd\r\n".
25264 "%PHP_PROXY% \"%BIN_TARGET%\" %*\r\n";
25265 }
25266 }
25267
25268 return "@echo off\r\n".
25269 "pushd .\r\n".
25270 "cd %~dp0\r\n".
25271 "cd ".ProcessExecutor::escape(dirname($binPath))."\r\n".
25272 "set BIN_TARGET=%CD%\\".basename($binPath)."\r\n".
25273 "popd\r\n".
25274 $caller." \"%BIN_TARGET%\" %*\r\n";
25275 }
25276
25277 private function generateWindowsPhpProxyCode()
25278 {
25279 $binToVendor = $this->filesystem->findShortestPath($this->binDir, $this->vendorDir, true);
25280
25281 return
25282 "@echo off\r\n" .
25283 "setlocal enabledelayedexpansion\r\n" .
25284 "set BIN_DIR=%~dp0\r\n" .
25285 "set VENDOR_DIR=%BIN_DIR%\\".$binToVendor."\r\n" .
25286 "set DIRS=.\r\n" .
25287 "FOR /D %%V IN (%VENDOR_DIR%\\*) DO (\r\n" .
25288 "    FOR /D %%P IN (%%V\\*) DO (\r\n" .
25289 "        set DIRS=!DIRS!;%%~fP\r\n" .
25290 "    )\r\n" .
25291 ")\r\n" .
25292 "php.exe -d include_path=!DIRS! %*\r\n";
25293 }
25294
25295 private function generateUnixyPhpProxyCode()
25296 {
25297 $binToVendor = $this->filesystem->findShortestPath($this->binDir, $this->vendorDir, true);
25298
25299 return
25300 "#!/usr/bin/env sh\n".
25301 "SRC_DIR=`pwd`\n".
25302 "BIN_DIR=`dirname $0`\n".
25303 "VENDOR_DIR=\$BIN_DIR/".escapeshellarg($binToVendor)."\n".
25304 "DIRS=\"\"\n".
25305 "for vendor in \$VENDOR_DIR/*; do\n".
25306 "    if [ -d \"\$vendor\" ]; then\n".
25307 "        for package in \$vendor/*; do\n".
25308 "            if [ -d \"\$package\" ]; then\n".
25309 "                DIRS=\"\${DIRS}:\${package}\"\n".
25310 "            fi\n".
25311 "        done\n".
25312 "    fi\n".
25313 "done\n".
25314 "php -d include_path=\".\$DIRS\" $@\n";
25315 }
25316 }
25317 <?php
25318
25319
25320
25321
25322
25323
25324
25325
25326
25327
25328
25329 namespace Composer\Installer;
25330
25331 use Composer\IO\IOInterface;
25332 use Composer\Composer;
25333 use Composer\Downloader\PearPackageExtractor;
25334 use Composer\Repository\InstalledRepositoryInterface;
25335 use Composer\Package\PackageInterface;
25336 use Composer\Util\Platform;
25337 use Composer\Util\Filesystem;
25338
25339
25340
25341
25342
25343
25344
25345 class PearInstaller extends LibraryInstaller
25346 {
25347
25348
25349
25350
25351
25352
25353
25354 public function __construct(IOInterface $io, Composer $composer, $type = 'pear-library')
25355 {
25356 $filesystem = new Filesystem();
25357 $binaryInstaller = new PearBinaryInstaller($io, rtrim($composer->getConfig()->get('bin-dir'), '/'), rtrim($composer->getConfig()->get('vendor-dir'), '/'), $composer->getConfig()->get('bin-compat'), $filesystem, $this);
25358
25359 parent::__construct($io, $composer, $type, $filesystem, $binaryInstaller);
25360 }
25361
25362
25363
25364
25365 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
25366 {
25367 $this->uninstall($repo, $initial);
25368 $this->install($repo, $target);
25369 }
25370
25371 protected function installCode(PackageInterface $package)
25372 {
25373 parent::installCode($package);
25374
25375 $isWindows = Platform::isWindows();
25376 $php_bin = $this->binDir . ($isWindows ? '/composer-php.bat' : '/composer-php');
25377
25378 if (!$isWindows) {
25379 $php_bin = '/usr/bin/env ' . $php_bin;
25380 }
25381
25382 $installPath = $this->getInstallPath($package);
25383 $vars = array(
25384 'os' => $isWindows ? 'windows' : 'linux',
25385 'php_bin' => $php_bin,
25386 'pear_php' => $installPath,
25387 'php_dir' => $installPath,
25388 'bin_dir' => $installPath . '/bin',
25389 'data_dir' => $installPath . '/data',
25390 'version' => $package->getPrettyVersion(),
25391 );
25392
25393 $packageArchive = $this->getInstallPath($package).'/'.pathinfo($package->getDistUrl(), PATHINFO_BASENAME);
25394 $pearExtractor = new PearPackageExtractor($packageArchive);
25395 $pearExtractor->extractTo($this->getInstallPath($package), array('php' => '/', 'script' => '/bin', 'data' => '/data'), $vars);
25396
25397 $this->io->writeError('    Cleaning up', true, IOInterface::VERBOSE);
25398 $this->filesystem->unlink($packageArchive);
25399 }
25400 }
25401 <?php
25402
25403
25404
25405
25406
25407
25408
25409
25410
25411
25412
25413 namespace Composer\Installer;
25414
25415 use Composer\Composer;
25416 use Composer\IO\IOInterface;
25417 use Composer\Repository\InstalledRepositoryInterface;
25418 use Composer\Package\PackageInterface;
25419
25420
25421
25422
25423
25424
25425
25426 class PluginInstaller extends LibraryInstaller
25427 {
25428 private $installationManager;
25429
25430
25431
25432
25433
25434
25435
25436 public function __construct(IOInterface $io, Composer $composer)
25437 {
25438 parent::__construct($io, $composer, 'composer-plugin');
25439 $this->installationManager = $composer->getInstallationManager();
25440 }
25441
25442
25443
25444
25445 public function supports($packageType)
25446 {
25447 return $packageType === 'composer-plugin' || $packageType === 'composer-installer';
25448 }
25449
25450
25451
25452
25453 public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
25454 {
25455 $extra = $package->getExtra();
25456 if (empty($extra['class'])) {
25457 throw new \UnexpectedValueException('Error while installing '.$package->getPrettyName().', composer-plugin packages should have a class defined in their extra key to be usable.');
25458 }
25459
25460 parent::install($repo, $package);
25461 try {
25462 $this->composer->getPluginManager()->registerPackage($package, true);
25463 } catch (\Exception $e) {
25464
25465 $this->io->writeError('Plugin installation failed ('.$e->getMessage().'), rolling back');
25466 parent::uninstall($repo, $package);
25467 throw $e;
25468 }
25469 }
25470
25471
25472
25473
25474 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
25475 {
25476 $extra = $target->getExtra();
25477 if (empty($extra['class'])) {
25478 throw new \UnexpectedValueException('Error while installing '.$target->getPrettyName().', composer-plugin packages should have a class defined in their extra key to be usable.');
25479 }
25480
25481 parent::update($repo, $initial, $target);
25482 $this->composer->getPluginManager()->registerPackage($target, true);
25483 }
25484 }
25485 <?php
25486
25487
25488
25489
25490
25491
25492
25493
25494
25495
25496
25497 namespace Composer\Installer;
25498
25499 use Composer\Package\PackageInterface;
25500 use Composer\Downloader\DownloadManager;
25501 use Composer\Repository\InstalledRepositoryInterface;
25502 use Composer\Util\Filesystem;
25503
25504
25505
25506
25507
25508
25509
25510 class ProjectInstaller implements InstallerInterface
25511 {
25512 private $installPath;
25513 private $downloadManager;
25514 private $filesystem;
25515
25516 public function __construct($installPath, DownloadManager $dm)
25517 {
25518 $this->installPath = rtrim(strtr($installPath, '\\', '/'), '/').'/';
25519 $this->downloadManager = $dm;
25520 $this->filesystem = new Filesystem;
25521 }
25522
25523
25524
25525
25526
25527
25528
25529 public function supports($packageType)
25530 {
25531 return true;
25532 }
25533
25534
25535
25536
25537 public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
25538 {
25539 return false;
25540 }
25541
25542
25543
25544
25545 public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
25546 {
25547 $installPath = $this->installPath;
25548 if (file_exists($installPath) && !$this->filesystem->isDirEmpty($installPath)) {
25549 throw new \InvalidArgumentException("Project directory $installPath is not empty.");
25550 }
25551 if (!is_dir($installPath)) {
25552 mkdir($installPath, 0777, true);
25553 }
25554 $this->downloadManager->download($package, $installPath);
25555 }
25556
25557
25558
25559
25560 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
25561 {
25562 throw new \InvalidArgumentException("not supported");
25563 }
25564
25565
25566
25567
25568 public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
25569 {
25570 throw new \InvalidArgumentException("not supported");
25571 }
25572
25573
25574
25575
25576
25577
25578
25579 public function getInstallPath(PackageInterface $package)
25580 {
25581 return $this->installPath;
25582 }
25583 }
25584 <?php
25585
25586
25587
25588
25589
25590
25591
25592
25593
25594
25595
25596 namespace Composer\Installer;
25597
25598 use Composer\IO\IOInterface;
25599 use Composer\Package\PackageInterface;
25600 use Composer\Repository\RepositoryInterface;
25601 use Symfony\Component\Console\Formatter\OutputFormatter;
25602
25603
25604
25605
25606
25607
25608 class SuggestedPackagesReporter
25609 {
25610
25611
25612
25613 protected $suggestedPackages = array();
25614
25615
25616
25617
25618 private $io;
25619
25620 public function __construct(IOInterface $io)
25621 {
25622 $this->io = $io;
25623 }
25624
25625
25626
25627
25628 public function getPackages()
25629 {
25630 return $this->suggestedPackages;
25631 }
25632
25633
25634
25635
25636
25637
25638
25639
25640
25641
25642
25643
25644 public function addPackage($source, $target, $reason)
25645 {
25646 $this->suggestedPackages[] = array(
25647 'source' => $source,
25648 'target' => $target,
25649 'reason' => $reason,
25650 );
25651
25652 return $this;
25653 }
25654
25655
25656
25657
25658
25659
25660
25661 public function addSuggestionsFromPackage(PackageInterface $package)
25662 {
25663 $source = $package->getPrettyName();
25664 foreach ($package->getSuggests() as $target => $reason) {
25665 $this->addPackage(
25666 $source,
25667 $target,
25668 $reason
25669 );
25670 }
25671
25672 return $this;
25673 }
25674
25675
25676
25677
25678
25679
25680
25681
25682 public function output(RepositoryInterface $installedRepo = null)
25683 {
25684 $suggestedPackages = $this->getPackages();
25685 $installedPackages = array();
25686 if (null !== $installedRepo && ! empty($suggestedPackages)) {
25687 foreach ($installedRepo->getPackages() as $package) {
25688 $installedPackages = array_merge(
25689 $installedPackages,
25690 $package->getNames()
25691 );
25692 }
25693 }
25694
25695 foreach ($suggestedPackages as $suggestion) {
25696 if (in_array($suggestion['target'], $installedPackages)) {
25697 continue;
25698 }
25699
25700 $this->io->writeError(sprintf(
25701 '%s suggests installing %s%s',
25702 $suggestion['source'],
25703 $this->escapeOutput($suggestion['target']),
25704 $this->escapeOutput('' !== $suggestion['reason'] ? ' ('.$suggestion['reason'].')' : '')
25705 ));
25706 }
25707
25708 return $this;
25709 }
25710
25711
25712
25713
25714
25715 private function escapeOutput($string)
25716 {
25717 return OutputFormatter::escape(
25718 $this->removeControlCharacters($string)
25719 );
25720 }
25721
25722
25723
25724
25725
25726 private function removeControlCharacters($string)
25727 {
25728 return preg_replace(
25729 '/[[:cntrl:]]/',
25730 '',
25731 str_replace("\n", ' ', $string)
25732 );
25733 }
25734 }
25735 <?php
25736
25737
25738
25739
25740
25741
25742
25743
25744
25745
25746
25747 namespace Composer\Json;
25748
25749 use JsonSchema\Validator;
25750 use Seld\JsonLint\JsonParser;
25751 use Seld\JsonLint\ParsingException;
25752 use Composer\Util\RemoteFilesystem;
25753 use Composer\IO\IOInterface;
25754 use Composer\Downloader\TransportException;
25755
25756
25757
25758
25759
25760
25761
25762 class JsonFile
25763 {
25764 const LAX_SCHEMA = 1;
25765 const STRICT_SCHEMA = 2;
25766
25767 const JSON_UNESCAPED_SLASHES = 64;
25768 const JSON_PRETTY_PRINT = 128;
25769 const JSON_UNESCAPED_UNICODE = 256;
25770
25771 const COMPOSER_SCHEMA_PATH = '/../../../res/composer-schema.json';
25772
25773 private $path;
25774 private $rfs;
25775 private $io;
25776
25777
25778
25779
25780
25781
25782
25783
25784
25785 public function __construct($path, RemoteFilesystem $rfs = null, IOInterface $io = null)
25786 {
25787 $this->path = $path;
25788
25789 if (null === $rfs && preg_match('{^https?://}i', $path)) {
25790 throw new \InvalidArgumentException('http urls require a RemoteFilesystem instance to be passed');
25791 }
25792 $this->rfs = $rfs;
25793 $this->io = $io;
25794 }
25795
25796
25797
25798
25799 public function getPath()
25800 {
25801 return $this->path;
25802 }
25803
25804
25805
25806
25807
25808
25809 public function exists()
25810 {
25811 return is_file($this->path);
25812 }
25813
25814
25815
25816
25817
25818
25819
25820 public function read()
25821 {
25822 try {
25823 if ($this->rfs) {
25824 $json = $this->rfs->getContents($this->path, $this->path, false);
25825 } else {
25826 if ($this->io && $this->io->isDebug()) {
25827 $this->io->writeError('Reading ' . $this->path);
25828 }
25829 $json = file_get_contents($this->path);
25830 }
25831 } catch (TransportException $e) {
25832 throw new \RuntimeException($e->getMessage(), 0, $e);
25833 } catch (\Exception $e) {
25834 throw new \RuntimeException('Could not read '.$this->path."\n\n".$e->getMessage());
25835 }
25836
25837 return static::parseJson($json, $this->path);
25838 }
25839
25840
25841
25842
25843
25844
25845
25846
25847 public function write(array $hash, $options = 448)
25848 {
25849 $dir = dirname($this->path);
25850 if (!is_dir($dir)) {
25851 if (file_exists($dir)) {
25852 throw new \UnexpectedValueException(
25853 $dir.' exists and is not a directory.'
25854 );
25855 }
25856 if (!@mkdir($dir, 0777, true)) {
25857 throw new \UnexpectedValueException(
25858 $dir.' does not exist and could not be created.'
25859 );
25860 }
25861 }
25862
25863 $retries = 3;
25864 while ($retries--) {
25865 try {
25866 $this->filePutContentsIfModified($this->path, static::encode($hash, $options). ($options & self::JSON_PRETTY_PRINT ? "\n" : ''));
25867 break;
25868 } catch (\Exception $e) {
25869 if ($retries) {
25870 usleep(500000);
25871 continue;
25872 }
25873
25874 throw $e;
25875 }
25876 }
25877 }
25878
25879
25880
25881
25882 private function filePutContentsIfModified($path, $content)
25883 {
25884 $currentContent = @file_get_contents($path);
25885 if (!$currentContent || ($currentContent != $content)) {
25886 return file_put_contents($path, $content);
25887 }
25888
25889 return 0;
25890 }
25891
25892
25893
25894
25895
25896
25897
25898
25899
25900 public function validateSchema($schema = self::STRICT_SCHEMA, $schemaFile = null)
25901 {
25902 $content = file_get_contents($this->path);
25903 $data = json_decode($content);
25904
25905 if (null === $data && 'null' !== $content) {
25906 self::validateSyntax($content, $this->path);
25907 }
25908
25909 if (null === $schemaFile) {
25910 $schemaFile = __DIR__ . self::COMPOSER_SCHEMA_PATH;
25911 }
25912
25913
25914 if (false === strpos($schemaFile, '://')) {
25915 $schemaFile = 'file://' . $schemaFile;
25916 }
25917
25918 $schemaData = (object) array('$ref' => $schemaFile);
25919
25920 if ($schema === self::LAX_SCHEMA) {
25921 $schemaData->additionalProperties = true;
25922 $schemaData->required = array();
25923 }
25924
25925 $validator = new Validator();
25926 $validator->check($data, $schemaData);
25927
25928
25929
25930 if (!$validator->isValid()) {
25931 $errors = array();
25932 foreach ((array) $validator->getErrors() as $error) {
25933 $errors[] = ($error['property'] ? $error['property'].' : ' : '').$error['message'];
25934 }
25935 throw new JsonValidationException('"'.$this->path.'" does not match the expected JSON schema', $errors);
25936 }
25937
25938 return true;
25939 }
25940
25941
25942
25943
25944
25945
25946
25947
25948 public static function encode($data, $options = 448)
25949 {
25950 if (PHP_VERSION_ID >= 50400) {
25951 $json = json_encode($data, $options);
25952 if (false === $json) {
25953 self::throwEncodeError(json_last_error());
25954 }
25955
25956
25957 if (PHP_VERSION_ID < 50428 || (PHP_VERSION_ID >= 50500 && PHP_VERSION_ID < 50512) || (defined('JSON_C_VERSION') && version_compare(phpversion('json'), '1.3.6', '<'))) {
25958 $json = preg_replace('/\[\s+\]/', '[]', $json);
25959 $json = preg_replace('/\{\s+\}/', '{}', $json);
25960 }
25961
25962 return $json;
25963 }
25964
25965 $json = json_encode($data);
25966 if (false === $json) {
25967 self::throwEncodeError(json_last_error());
25968 }
25969
25970 $prettyPrint = (bool) ($options & self::JSON_PRETTY_PRINT);
25971 $unescapeUnicode = (bool) ($options & self::JSON_UNESCAPED_UNICODE);
25972 $unescapeSlashes = (bool) ($options & self::JSON_UNESCAPED_SLASHES);
25973
25974 if (!$prettyPrint && !$unescapeUnicode && !$unescapeSlashes) {
25975 return $json;
25976 }
25977
25978 return JsonFormatter::format($json, $unescapeUnicode, $unescapeSlashes);
25979 }
25980
25981
25982
25983
25984
25985
25986
25987 private static function throwEncodeError($code)
25988 {
25989 switch ($code) {
25990 case JSON_ERROR_DEPTH:
25991 $msg = 'Maximum stack depth exceeded';
25992 break;
25993 case JSON_ERROR_STATE_MISMATCH:
25994 $msg = 'Underflow or the modes mismatch';
25995 break;
25996 case JSON_ERROR_CTRL_CHAR:
25997 $msg = 'Unexpected control character found';
25998 break;
25999 case JSON_ERROR_UTF8:
26000 $msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
26001 break;
26002 default:
26003 $msg = 'Unknown error';
26004 }
26005
26006 throw new \RuntimeException('JSON encoding failed: '.$msg);
26007 }
26008
26009
26010
26011
26012
26013
26014
26015
26016
26017 public static function parseJson($json, $file = null)
26018 {
26019 if (null === $json) {
26020 return;
26021 }
26022 $data = json_decode($json, true);
26023 if (null === $data && JSON_ERROR_NONE !== json_last_error()) {
26024 self::validateSyntax($json, $file);
26025 }
26026
26027 return $data;
26028 }
26029
26030
26031
26032
26033
26034
26035
26036
26037
26038
26039 protected static function validateSyntax($json, $file = null)
26040 {
26041 $parser = new JsonParser();
26042 $result = $parser->lint($json);
26043 if (null === $result) {
26044 if (defined('JSON_ERROR_UTF8') && JSON_ERROR_UTF8 === json_last_error()) {
26045 throw new \UnexpectedValueException('"'.$file.'" is not UTF-8, could not parse as JSON');
26046 }
26047
26048 return true;
26049 }
26050
26051 throw new ParsingException('"'.$file.'" does not contain valid JSON'."\n".$result->getMessage(), $result->getDetails());
26052 }
26053 }
26054 <?php
26055
26056
26057
26058
26059
26060
26061
26062
26063
26064
26065
26066 namespace Composer\Json;
26067
26068
26069
26070
26071
26072
26073
26074
26075
26076 class JsonFormatter
26077 {
26078
26079
26080
26081
26082
26083
26084
26085
26086
26087
26088
26089
26090 public static function format($json, $unescapeUnicode, $unescapeSlashes)
26091 {
26092 $result = '';
26093 $pos = 0;
26094 $strLen = strlen($json);
26095 $indentStr = '    ';
26096 $newLine = "\n";
26097 $outOfQuotes = true;
26098 $buffer = '';
26099 $noescape = true;
26100
26101 for ($i = 0; $i < $strLen; $i++) {
26102
26103 $char = substr($json, $i, 1);
26104
26105
26106 if ('"' === $char && $noescape) {
26107 $outOfQuotes = !$outOfQuotes;
26108 }
26109
26110 if (!$outOfQuotes) {
26111 $buffer .= $char;
26112 $noescape = '\\' === $char ? !$noescape : true;
26113 continue;
26114 } elseif ('' !== $buffer) {
26115 if ($unescapeSlashes) {
26116 $buffer = str_replace('\\/', '/', $buffer);
26117 }
26118
26119 if ($unescapeUnicode && function_exists('mb_convert_encoding')) {
26120
26121 $buffer = preg_replace_callback('/(\\\\+)u([0-9a-f]{4})/i', function ($match) {
26122 $l = strlen($match[1]);
26123
26124 if ($l % 2) {
26125 $code = hexdec($match[2]);
26126
26127
26128 if (0xD800 <= $code && 0xDFFF >= $code) {
26129 return $match[0];
26130 }
26131
26132 return str_repeat('\\', $l - 1) . mb_convert_encoding(
26133 pack('H*', $match[2]),
26134 'UTF-8',
26135 'UCS-2BE'
26136 );
26137 }
26138
26139 return $match[0];
26140 }, $buffer);
26141 }
26142
26143 $result .= $buffer.$char;
26144 $buffer = '';
26145 continue;
26146 }
26147
26148 if (':' === $char) {
26149
26150 $char .= ' ';
26151 } elseif ('}' === $char || ']' === $char) {
26152 $pos--;
26153 $prevChar = substr($json, $i - 1, 1);
26154
26155 if ('{' !== $prevChar && '[' !== $prevChar) {
26156
26157
26158 $result .= $newLine;
26159 for ($j = 0; $j < $pos; $j++) {
26160 $result .= $indentStr;
26161 }
26162 } else {
26163
26164 $result = rtrim($result);
26165 }
26166 }
26167
26168 $result .= $char;
26169
26170
26171
26172 if (',' === $char || '{' === $char || '[' === $char) {
26173 $result .= $newLine;
26174
26175 if ('{' === $char || '[' === $char) {
26176 $pos++;
26177 }
26178
26179 for ($j = 0; $j < $pos; $j++) {
26180 $result .= $indentStr;
26181 }
26182 }
26183 }
26184
26185 return $result;
26186 }
26187 }
26188 <?php
26189
26190
26191
26192
26193
26194
26195
26196
26197
26198
26199
26200 namespace Composer\Json;
26201
26202 use Composer\Repository\PlatformRepository;
26203
26204
26205
26206
26207 class JsonManipulator
26208 {
26209 private static $DEFINES = '(?(DEFINE)
26210        (?<number>   -? (?= [1-9]|0(?!\d) ) \d+ (\.\d+)? ([eE] [+-]? \d+)? )
26211        (?<boolean>   true | false | null )
26212        (?<string>    " ([^"\\\\]* | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9A-Fa-f]{4} )* " )
26213        (?<array>     \[  (?:  (?&json) \s* (?: , (?&json) \s* )*  )?  \s* \] )
26214        (?<pair>      \s* (?&string) \s* : (?&json) \s* )
26215        (?<object>    \{  (?:  (?&pair)  (?: , (?&pair)  )*  )?  \s* \} )
26216        (?<json>   \s* (?: (?&number) | (?&boolean) | (?&string) | (?&array) | (?&object) ) )
26217     )';
26218
26219 private $contents;
26220 private $newline;
26221 private $indent;
26222
26223 public function __construct($contents)
26224 {
26225 $contents = trim($contents);
26226 if ($contents === '') {
26227 $contents = '{}';
26228 }
26229 if (!$this->pregMatch('#^\{(.*)\}$#s', $contents)) {
26230 throw new \InvalidArgumentException('The json file must be an object ({})');
26231 }
26232 $this->newline = false !== strpos($contents, "\r\n") ? "\r\n" : "\n";
26233 $this->contents = $contents === '{}' ? '{' . $this->newline . '}' : $contents;
26234 $this->detectIndenting();
26235 }
26236
26237 public function getContents()
26238 {
26239 return $this->contents . $this->newline;
26240 }
26241
26242 public function addLink($type, $package, $constraint, $sortPackages = false)
26243 {
26244 $decoded = JsonFile::parseJson($this->contents);
26245
26246
26247 if (!isset($decoded[$type])) {
26248 return $this->addMainKey($type, array($package => $constraint));
26249 }
26250
26251 $regex = '{'.self::$DEFINES.'^(?P<start>\s*\{\s*(?:(?&string)\s*:\s*(?&json)\s*,\s*)*?)'.
26252 '(?P<property>'.preg_quote(JsonFile::encode($type)).'\s*:\s*)(?P<value>(?&json))(?P<end>.*)}sx';
26253 if (!$this->pregMatch($regex, $this->contents, $matches)) {
26254 return false;
26255 }
26256
26257 $links = $matches['value'];
26258
26259
26260 $packageRegex = str_replace('/', '\\\\?/', preg_quote($package));
26261 $regex = '{'.self::$DEFINES.'"(?P<package>'.$packageRegex.')"(\s*:\s*)(?&string)}ix';
26262 if ($this->pregMatch($regex, $links, $packageMatches)) {
26263
26264 $existingPackage = $packageMatches['package'];
26265 $packageRegex = str_replace('/', '\\\\?/', preg_quote($existingPackage));
26266 $links = preg_replace_callback('{'.self::$DEFINES.'"'.$packageRegex.'"(?P<separator>\s*:\s*)(?&string)}ix', function ($m) use ($existingPackage, $constraint) {
26267 return JsonFile::encode(str_replace('\\/', '/', $existingPackage)) . $m['separator'] . '"' . $constraint . '"';
26268 }, $links);
26269 } else {
26270 if ($this->pregMatch('#^\s*\{\s*\S+.*?(\s*\}\s*)$#s', $links, $match)) {
26271
26272 $links = preg_replace(
26273 '{'.preg_quote($match[1]).'$}',
26274
26275 addcslashes(',' . $this->newline . $this->indent . $this->indent . JsonFile::encode($package).': '.JsonFile::encode($constraint) . $match[1], '\\$'),
26276 $links
26277 );
26278 } else {
26279
26280 $links = '{' . $this->newline .
26281 $this->indent . $this->indent . JsonFile::encode($package).': '.JsonFile::encode($constraint) . $this->newline .
26282 $this->indent . '}';
26283 }
26284 }
26285
26286 if (true === $sortPackages) {
26287 $requirements = json_decode($links, true);
26288 $this->sortPackages($requirements);
26289 $links = $this->format($requirements);
26290 }
26291
26292 $this->contents = $matches['start'] . $matches['property'] . $links . $matches['end'];
26293
26294 return true;
26295 }
26296
26297
26298
26299
26300
26301
26302
26303
26304 private function sortPackages(array &$packages = array())
26305 {
26306 $prefix = function ($requirement) {
26307 if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $requirement)) {
26308 return preg_replace(
26309 array(
26310 '/^php/',
26311 '/^hhvm/',
26312 '/^ext/',
26313 '/^lib/',
26314 '/^\D/',
26315 ),
26316 array(
26317 '0-$0',
26318 '1-$0',
26319 '2-$0',
26320 '3-$0',
26321 '4-$0',
26322 ),
26323 $requirement
26324 );
26325 }
26326
26327 return '5-'.$requirement;
26328 };
26329
26330 uksort($packages, function ($a, $b) use ($prefix) {
26331 return strnatcmp($prefix($a), $prefix($b));
26332 });
26333 }
26334
26335 public function addRepository($name, $config)
26336 {
26337 return $this->addSubNode('repositories', $name, $config);
26338 }
26339
26340 public function removeRepository($name)
26341 {
26342 return $this->removeSubNode('repositories', $name);
26343 }
26344
26345 public function addConfigSetting($name, $value)
26346 {
26347 return $this->addSubNode('config', $name, $value);
26348 }
26349
26350 public function removeConfigSetting($name)
26351 {
26352 return $this->removeSubNode('config', $name);
26353 }
26354
26355 public function addProperty($name, $value)
26356 {
26357 if (substr($name, 0, 8) === 'suggest.') {
26358 return $this->addSubNode('suggest', substr($name, 8), $value);
26359 }
26360
26361 if (substr($name, 0, 6) === 'extra.') {
26362 return $this->addSubNode('extra', substr($name, 6), $value);
26363 }
26364
26365 if (substr($name, 0, 8) === 'scripts.') {
26366 return $this->addSubNode('scripts', substr($name, 8), $value);
26367 }
26368
26369 return $this->addMainKey($name, $value);
26370 }
26371
26372 public function removeProperty($name)
26373 {
26374 if (substr($name, 0, 8) === 'suggest.') {
26375 return $this->removeSubNode('suggest', substr($name, 8));
26376 }
26377
26378 if (substr($name, 0, 6) === 'extra.') {
26379 return $this->removeSubNode('extra', substr($name, 6));
26380 }
26381
26382 if (substr($name, 0, 8) === 'scripts.') {
26383 return $this->removeSubNode('scripts', substr($name, 8));
26384 }
26385
26386 return $this->removeMainKey($name);
26387 }
26388
26389 public function addSubNode($mainNode, $name, $value)
26390 {
26391 $decoded = JsonFile::parseJson($this->contents);
26392
26393 $subName = null;
26394 if (in_array($mainNode, array('config', 'extra', 'scripts')) && false !== strpos($name, '.')) {
26395 list($name, $subName) = explode('.', $name, 2);
26396 }
26397
26398
26399 if (!isset($decoded[$mainNode])) {
26400 if ($subName !== null) {
26401 $this->addMainKey($mainNode, array($name => array($subName => $value)));
26402 } else {
26403 $this->addMainKey($mainNode, array($name => $value));
26404 }
26405
26406 return true;
26407 }
26408
26409
26410 $nodeRegex = '{'.self::$DEFINES.'^(?P<start> \s* \{ \s* (?: (?&string) \s* : (?&json) \s* , \s* )*?'.
26411 preg_quote(JsonFile::encode($mainNode)).'\s*:\s*)(?P<content>(?&object))(?P<end>.*)}sx';
26412
26413 try {
26414 if (!$this->pregMatch($nodeRegex, $this->contents, $match)) {
26415 return false;
26416 }
26417 } catch (\RuntimeException $e) {
26418 if ($e->getCode() === PREG_BACKTRACK_LIMIT_ERROR) {
26419 return false;
26420 }
26421 throw $e;
26422 }
26423
26424 $children = $match['content'];
26425
26426 if (!@json_decode($children)) {
26427 return false;
26428 }
26429
26430 $that = $this;
26431
26432
26433 $childRegex = '{'.self::$DEFINES.'(?P<start>"'.preg_quote($name).'"\s*:\s*)(?P<content>(?&json))(?P<end>,?)}x';
26434 if ($this->pregMatch($childRegex, $children, $matches)) {
26435 $children = preg_replace_callback($childRegex, function ($matches) use ($subName, $value, $that) {
26436 if ($subName !== null) {
26437 $curVal = json_decode($matches['content'], true);
26438 if (!is_array($curVal)) {
26439 $curVal = array();
26440 }
26441 $curVal[$subName] = $value;
26442 $value = $curVal;
26443 }
26444
26445 return $matches['start'] . $that->format($value, 1) . $matches['end'];
26446 }, $children);
26447 } else {
26448 $this->pregMatch('#^{ \s*? (?P<content>\S+.*?)? (?P<trailingspace>\s*) }$#sx', $children, $match);
26449
26450 $whitespace = '';
26451 if (!empty($match['trailingspace'])) {
26452 $whitespace = $match['trailingspace'];
26453 }
26454
26455 if (!empty($match['content'])) {
26456 if ($subName !== null) {
26457 $value = array($subName => $value);
26458 }
26459
26460
26461 $children = preg_replace(
26462 '#'.$whitespace.'}$#',
26463 addcslashes(',' . $this->newline . $this->indent . $this->indent . JsonFile::encode($name).': '.$this->format($value, 1) . $whitespace . '}', '\\$'),
26464 $children
26465 );
26466 } else {
26467 if ($subName !== null) {
26468 $value = array($subName => $value);
26469 }
26470
26471
26472 $children = '{' . $this->newline . $this->indent . $this->indent . JsonFile::encode($name).': '.$this->format($value, 1) . $whitespace . '}';
26473 }
26474 }
26475
26476 $this->contents = preg_replace_callback($nodeRegex, function ($m) use ($children) {
26477 return $m['start'] . $children . $m['end'];
26478 }, $this->contents);
26479
26480 return true;
26481 }
26482
26483 public function removeSubNode($mainNode, $name)
26484 {
26485 $decoded = JsonFile::parseJson($this->contents);
26486
26487
26488 if (empty($decoded[$mainNode])) {
26489 return true;
26490 }
26491
26492
26493 $nodeRegex = '{'.self::$DEFINES.'^(?P<start> \s* \{ \s* (?: (?&string) \s* : (?&json) \s* , \s* )*?'.
26494 preg_quote(JsonFile::encode($mainNode)).'\s*:\s*)(?P<content>(?&object))(?P<end>.*)}sx';
26495 try {
26496 if (!$this->pregMatch($nodeRegex, $this->contents, $match)) {
26497 return false;
26498 }
26499 } catch (\RuntimeException $e) {
26500 if ($e->getCode() === PREG_BACKTRACK_LIMIT_ERROR) {
26501 return false;
26502 }
26503 throw $e;
26504 }
26505
26506 $children = $match['content'];
26507
26508
26509 if (!@json_decode($children, true)) {
26510 return false;
26511 }
26512
26513 $subName = null;
26514 if (in_array($mainNode, array('config', 'extra', 'scripts')) && false !== strpos($name, '.')) {
26515 list($name, $subName) = explode('.', $name, 2);
26516 }
26517
26518
26519 if (!isset($decoded[$mainNode][$name]) || ($subName && !isset($decoded[$mainNode][$name][$subName]))) {
26520 return true;
26521 }
26522
26523
26524 $keyRegex = str_replace('/', '\\\\?/', preg_quote($name));
26525 if ($this->pregMatch('{"'.$keyRegex.'"\s*:}i', $children)) {
26526
26527 if (preg_match_all('{'.self::$DEFINES.'"'.$keyRegex.'"\s*:\s*(?:(?&json))}x', $children, $matches)) {
26528 $bestMatch = '';
26529 foreach ($matches[0] as $match) {
26530 if (strlen($bestMatch) < strlen($match)) {
26531 $bestMatch = $match;
26532 }
26533 }
26534 $childrenClean = preg_replace('{,\s*'.preg_quote($bestMatch).'}i', '', $children, -1, $count);
26535 if (1 !== $count) {
26536 $childrenClean = preg_replace('{'.preg_quote($bestMatch).'\s*,?\s*}i', '', $childrenClean, -1, $count);
26537 if (1 !== $count) {
26538 return false;
26539 }
26540 }
26541 }
26542 } else {
26543 $childrenClean = $children;
26544 }
26545
26546
26547 $this->pregMatch('#^{ \s*? (?P<content>\S+.*?)? (?P<trailingspace>\s*) }$#sx', $childrenClean, $match);
26548 if (empty($match['content'])) {
26549 $newline = $this->newline;
26550 $indent = $this->indent;
26551
26552 $this->contents = preg_replace_callback($nodeRegex, function ($matches) use ($indent, $newline) {
26553 return $matches['start'] . '{' . $newline . $indent . '}' . $matches['end'];
26554 }, $this->contents);
26555
26556
26557 if ($subName !== null) {
26558 $curVal = json_decode($children, true);
26559 unset($curVal[$name][$subName]);
26560 $this->addSubNode($mainNode, $name, $curVal[$name]);
26561 }
26562
26563 return true;
26564 }
26565
26566 $that = $this;
26567 $this->contents = preg_replace_callback($nodeRegex, function ($matches) use ($that, $name, $subName, $childrenClean) {
26568 if ($subName !== null) {
26569 $curVal = json_decode($matches['content'], true);
26570 unset($curVal[$name][$subName]);
26571 $childrenClean = $that->format($curVal, 0);
26572 }
26573
26574 return $matches['start'] . $childrenClean . $matches['end'];
26575 }, $this->contents);
26576
26577 return true;
26578 }
26579
26580 public function addMainKey($key, $content)
26581 {
26582 $decoded = JsonFile::parseJson($this->contents);
26583 $content = $this->format($content);
26584
26585
26586 $regex = '{'.self::$DEFINES.'^(?P<start>\s*\{\s*(?:(?&string)\s*:\s*(?&json)\s*,\s*)*?)'.
26587 '(?P<key>'.preg_quote(JsonFile::encode($key)).'\s*:\s*(?&json))(?P<end>.*)}sx';
26588 if (isset($decoded[$key]) && $this->pregMatch($regex, $this->contents, $matches)) {
26589
26590 if (!@json_decode('{'.$matches['key'].'}')) {
26591 return false;
26592 }
26593
26594 $this->contents = $matches['start'] . JsonFile::encode($key).': '.$content . $matches['end'];
26595
26596 return true;
26597 }
26598
26599
26600 if ($this->pregMatch('#[^{\s](\s*)\}$#', $this->contents, $match)) {
26601 $this->contents = preg_replace(
26602 '#'.$match[1].'\}$#',
26603 addcslashes(',' . $this->newline . $this->indent . JsonFile::encode($key). ': '. $content . $this->newline . '}', '\\$'),
26604 $this->contents
26605 );
26606
26607 return true;
26608 }
26609
26610
26611 $this->contents = preg_replace(
26612 '#\}$#',
26613 addcslashes($this->indent . JsonFile::encode($key). ': '.$content . $this->newline . '}', '\\$'),
26614 $this->contents
26615 );
26616
26617 return true;
26618 }
26619
26620 public function removeMainKey($key)
26621 {
26622 $decoded = JsonFile::parseJson($this->contents);
26623
26624 if (!array_key_exists($key, $decoded)) {
26625 return true;
26626 }
26627
26628
26629 $regex = '{'.self::$DEFINES.'^(?P<start>\s*\{\s*(?:(?&string)\s*:\s*(?&json)\s*,\s*)*?)'.
26630 '(?P<removal>'.preg_quote(JsonFile::encode($key)).'\s*:\s*(?&json))\s*,?\s*(?P<end>.*)}sx';
26631 if ($this->pregMatch($regex, $this->contents, $matches)) {
26632
26633 if (!@json_decode('{'.$matches['removal'].'}')) {
26634 return false;
26635 }
26636
26637
26638 if (preg_match('#,\s*$#', $matches['start']) && preg_match('#^\}$#', $matches['end'])) {
26639 $matches['start'] = rtrim(preg_replace('#,(\s*)$#', '$1', $matches['start']), $this->indent);
26640 }
26641
26642 $this->contents = $matches['start'] . $matches['end'];
26643 if (preg_match('#^\{\s*\}\s*$#', $this->contents)) {
26644 $this->contents = "{\n}";
26645 }
26646
26647 return true;
26648 }
26649
26650 return false;
26651 }
26652
26653 public function format($data, $depth = 0)
26654 {
26655 if (is_array($data)) {
26656 reset($data);
26657
26658 if (is_numeric(key($data))) {
26659 foreach ($data as $key => $val) {
26660 $data[$key] = $this->format($val, $depth + 1);
26661 }
26662
26663 return '['.implode(', ', $data).']';
26664 }
26665
26666 $out = '{' . $this->newline;
26667 $elems = array();
26668 foreach ($data as $key => $val) {
26669 $elems[] = str_repeat($this->indent, $depth + 2) . JsonFile::encode($key). ': '.$this->format($val, $depth + 1);
26670 }
26671
26672 return $out . implode(','.$this->newline, $elems) . $this->newline . str_repeat($this->indent, $depth + 1) . '}';
26673 }
26674
26675 return JsonFile::encode($data);
26676 }
26677
26678 protected function detectIndenting()
26679 {
26680 if ($this->pregMatch('{^([ \t]+)"}m', $this->contents, $match)) {
26681 $this->indent = $match[1];
26682 } else {
26683 $this->indent = '    ';
26684 }
26685 }
26686
26687 protected function pregMatch($re, $str, &$matches = array())
26688 {
26689 $count = preg_match($re, $str, $matches);
26690
26691 if ($count === false) {
26692 switch (preg_last_error()) {
26693 case PREG_NO_ERROR:
26694 throw new \RuntimeException('Failed to execute regex: PREG_NO_ERROR', PREG_NO_ERROR);
26695 case PREG_INTERNAL_ERROR:
26696 throw new \RuntimeException('Failed to execute regex: PREG_INTERNAL_ERROR', PREG_INTERNAL_ERROR);
26697 case PREG_BACKTRACK_LIMIT_ERROR:
26698 throw new \RuntimeException('Failed to execute regex: PREG_BACKTRACK_LIMIT_ERROR', PREG_BACKTRACK_LIMIT_ERROR);
26699 case PREG_RECURSION_LIMIT_ERROR:
26700 throw new \RuntimeException('Failed to execute regex: PREG_RECURSION_LIMIT_ERROR', PREG_RECURSION_LIMIT_ERROR);
26701 case PREG_BAD_UTF8_ERROR:
26702 throw new \RuntimeException('Failed to execute regex: PREG_BAD_UTF8_ERROR', PREG_BAD_UTF8_ERROR);
26703 case PREG_BAD_UTF8_OFFSET_ERROR:
26704 throw new \RuntimeException('Failed to execute regex: PREG_BAD_UTF8_OFFSET_ERROR', PREG_BAD_UTF8_OFFSET_ERROR);
26705 case 6: 
26706 if (PHP_VERSION_ID > 70000) {
26707 throw new \RuntimeException('Failed to execute regex: PREG_JIT_STACKLIMIT_ERROR', 6);
26708 }
26709
26710 default:
26711 throw new \RuntimeException('Failed to execute regex: Unknown error');
26712 }
26713 }
26714
26715 return $count;
26716 }
26717 }
26718 <?php
26719
26720
26721
26722
26723
26724
26725
26726
26727
26728
26729
26730 namespace Composer\Json;
26731
26732 use Exception;
26733
26734
26735
26736
26737 class JsonValidationException extends Exception
26738 {
26739 protected $errors;
26740
26741 public function __construct($message, $errors = array(), Exception $previous = null)
26742 {
26743 $this->errors = $errors;
26744 parent::__construct($message, 0, $previous);
26745 }
26746
26747 public function getErrors()
26748 {
26749 return $this->errors;
26750 }
26751 }
26752 <?php
26753
26754
26755
26756
26757
26758
26759
26760
26761
26762
26763
26764 namespace Composer\Package;
26765
26766 use Composer\Semver\Constraint\Constraint;
26767 use Composer\Package\Version\VersionParser;
26768
26769
26770
26771
26772 class AliasPackage extends BasePackage implements CompletePackageInterface
26773 {
26774 protected $version;
26775 protected $prettyVersion;
26776 protected $dev;
26777 protected $rootPackageAlias = false;
26778 protected $stability;
26779
26780
26781 protected $aliasOf;
26782
26783 protected $requires;
26784
26785 protected $devRequires;
26786
26787 protected $conflicts;
26788
26789 protected $provides;
26790
26791 protected $replaces;
26792
26793
26794
26795
26796
26797
26798
26799
26800 public function __construct(PackageInterface $aliasOf, $version, $prettyVersion)
26801 {
26802 parent::__construct($aliasOf->getName());
26803
26804 $this->version = $version;
26805 $this->prettyVersion = $prettyVersion;
26806 $this->aliasOf = $aliasOf;
26807 $this->stability = VersionParser::parseStability($version);
26808 $this->dev = $this->stability === 'dev';
26809
26810 foreach (array('requires', 'devRequires', 'conflicts', 'provides', 'replaces') as $type) {
26811 $links = $aliasOf->{'get' . ucfirst($type)}();
26812 $this->$type = $this->replaceSelfVersionDependencies($links, $type);
26813 }
26814 }
26815
26816
26817
26818
26819 public function getAliasOf()
26820 {
26821 return $this->aliasOf;
26822 }
26823
26824
26825
26826
26827 public function getVersion()
26828 {
26829 return $this->version;
26830 }
26831
26832
26833
26834
26835 public function getStability()
26836 {
26837 return $this->stability;
26838 }
26839
26840
26841
26842
26843 public function getPrettyVersion()
26844 {
26845 return $this->prettyVersion;
26846 }
26847
26848
26849
26850
26851 public function isDev()
26852 {
26853 return $this->dev;
26854 }
26855
26856
26857
26858
26859 public function getRequires()
26860 {
26861 return $this->requires;
26862 }
26863
26864
26865
26866
26867 public function getConflicts()
26868 {
26869 return $this->conflicts;
26870 }
26871
26872
26873
26874
26875 public function getProvides()
26876 {
26877 return $this->provides;
26878 }
26879
26880
26881
26882
26883 public function getReplaces()
26884 {
26885 return $this->replaces;
26886 }
26887
26888
26889
26890
26891 public function getDevRequires()
26892 {
26893 return $this->devRequires;
26894 }
26895
26896
26897
26898
26899
26900
26901
26902
26903
26904
26905 public function setRootPackageAlias($value)
26906 {
26907 return $this->rootPackageAlias = $value;
26908 }
26909
26910
26911
26912
26913
26914 public function isRootPackageAlias()
26915 {
26916 return $this->rootPackageAlias;
26917 }
26918
26919
26920
26921
26922
26923
26924
26925 protected function replaceSelfVersionDependencies(array $links, $linkType)
26926 {
26927 if (in_array($linkType, array('conflicts', 'provides', 'replaces'), true)) {
26928 $newLinks = array();
26929 foreach ($links as $link) {
26930
26931 if ('self.version' === $link->getPrettyConstraint()) {
26932 $newLinks[] = new Link($link->getSource(), $link->getTarget(), new Constraint('=', $this->version), $linkType, $this->prettyVersion);
26933 }
26934 }
26935 $links = array_merge($links, $newLinks);
26936 } else {
26937 foreach ($links as $index => $link) {
26938 if ('self.version' === $link->getPrettyConstraint()) {
26939 $links[$index] = new Link($link->getSource(), $link->getTarget(), new Constraint('=', $this->version), $linkType, $this->prettyVersion);
26940 }
26941 }
26942 }
26943
26944 return $links;
26945 }
26946
26947
26948
26949
26950
26951 public function getType()
26952 {
26953 return $this->aliasOf->getType();
26954 }
26955
26956 public function getTargetDir()
26957 {
26958 return $this->aliasOf->getTargetDir();
26959 }
26960
26961 public function getExtra()
26962 {
26963 return $this->aliasOf->getExtra();
26964 }
26965
26966 public function setInstallationSource($type)
26967 {
26968 $this->aliasOf->setInstallationSource($type);
26969 }
26970
26971 public function getInstallationSource()
26972 {
26973 return $this->aliasOf->getInstallationSource();
26974 }
26975
26976 public function getSourceType()
26977 {
26978 return $this->aliasOf->getSourceType();
26979 }
26980
26981 public function getSourceUrl()
26982 {
26983 return $this->aliasOf->getSourceUrl();
26984 }
26985
26986 public function getSourceUrls()
26987 {
26988 return $this->aliasOf->getSourceUrls();
26989 }
26990
26991 public function getSourceReference()
26992 {
26993 return $this->aliasOf->getSourceReference();
26994 }
26995
26996 public function setSourceReference($reference)
26997 {
26998 return $this->aliasOf->setSourceReference($reference);
26999 }
27000
27001 public function setSourceMirrors($mirrors)
27002 {
27003 return $this->aliasOf->setSourceMirrors($mirrors);
27004 }
27005
27006 public function getSourceMirrors()
27007 {
27008 return $this->aliasOf->getSourceMirrors();
27009 }
27010
27011 public function getDistType()
27012 {
27013 return $this->aliasOf->getDistType();
27014 }
27015
27016 public function getDistUrl()
27017 {
27018 return $this->aliasOf->getDistUrl();
27019 }
27020
27021 public function getDistUrls()
27022 {
27023 return $this->aliasOf->getDistUrls();
27024 }
27025
27026 public function getDistReference()
27027 {
27028 return $this->aliasOf->getDistReference();
27029 }
27030
27031 public function setDistReference($reference)
27032 {
27033 return $this->aliasOf->setDistReference($reference);
27034 }
27035
27036 public function getDistSha1Checksum()
27037 {
27038 return $this->aliasOf->getDistSha1Checksum();
27039 }
27040
27041 public function setTransportOptions(array $options)
27042 {
27043 return $this->aliasOf->setTransportOptions($options);
27044 }
27045
27046 public function getTransportOptions()
27047 {
27048 return $this->aliasOf->getTransportOptions();
27049 }
27050
27051 public function setDistMirrors($mirrors)
27052 {
27053 return $this->aliasOf->setDistMirrors($mirrors);
27054 }
27055
27056 public function getDistMirrors()
27057 {
27058 return $this->aliasOf->getDistMirrors();
27059 }
27060
27061 public function getScripts()
27062 {
27063 return $this->aliasOf->getScripts();
27064 }
27065
27066 public function getLicense()
27067 {
27068 return $this->aliasOf->getLicense();
27069 }
27070
27071 public function getAutoload()
27072 {
27073 return $this->aliasOf->getAutoload();
27074 }
27075
27076 public function getDevAutoload()
27077 {
27078 return $this->aliasOf->getDevAutoload();
27079 }
27080
27081 public function getIncludePaths()
27082 {
27083 return $this->aliasOf->getIncludePaths();
27084 }
27085
27086 public function getRepositories()
27087 {
27088 return $this->aliasOf->getRepositories();
27089 }
27090
27091 public function getReleaseDate()
27092 {
27093 return $this->aliasOf->getReleaseDate();
27094 }
27095
27096 public function getBinaries()
27097 {
27098 return $this->aliasOf->getBinaries();
27099 }
27100
27101 public function getKeywords()
27102 {
27103 return $this->aliasOf->getKeywords();
27104 }
27105
27106 public function getDescription()
27107 {
27108 return $this->aliasOf->getDescription();
27109 }
27110
27111 public function getHomepage()
27112 {
27113 return $this->aliasOf->getHomepage();
27114 }
27115
27116 public function getSuggests()
27117 {
27118 return $this->aliasOf->getSuggests();
27119 }
27120
27121 public function getAuthors()
27122 {
27123 return $this->aliasOf->getAuthors();
27124 }
27125
27126 public function getSupport()
27127 {
27128 return $this->aliasOf->getSupport();
27129 }
27130
27131 public function getFunding()
27132 {
27133 return $this->aliasOf->getFunding();
27134 }
27135
27136 public function getNotificationUrl()
27137 {
27138 return $this->aliasOf->getNotificationUrl();
27139 }
27140
27141 public function getArchiveExcludes()
27142 {
27143 return $this->aliasOf->getArchiveExcludes();
27144 }
27145
27146 public function isAbandoned()
27147 {
27148 return $this->aliasOf->isAbandoned();
27149 }
27150
27151 public function getReplacementPackage()
27152 {
27153 return $this->aliasOf->getReplacementPackage();
27154 }
27155
27156 public function __toString()
27157 {
27158 return parent::__toString().' (alias of '.$this->aliasOf->getVersion().')';
27159 }
27160
27161 public function setDistUrl($url)
27162 {
27163 return $this->aliasOf->setDistUrl($url);
27164 }
27165
27166 public function setDistType($type)
27167 {
27168 return $this->aliasOf->setDistType($type);
27169 }
27170 }
27171 <?php
27172
27173
27174
27175
27176
27177
27178
27179
27180
27181
27182
27183 namespace Composer\Package\Archiver;
27184
27185 use FilterIterator;
27186 use PharData;
27187
27188 class ArchivableFilesFilter extends FilterIterator
27189 {
27190 private $dirs = array();
27191
27192
27193
27194
27195 public function accept()
27196 {
27197 $file = $this->getInnerIterator()->current();
27198 if ($file->isDir()) {
27199 $this->dirs[] = (string) $file;
27200
27201 return false;
27202 }
27203
27204 return true;
27205 }
27206
27207 public function addEmptyDir(PharData $phar, $sources)
27208 {
27209 foreach ($this->dirs as $filepath) {
27210 $localname = str_replace($sources . "/", '', $filepath);
27211 $phar->addEmptyDir($localname);
27212 }
27213 }
27214 }
27215 <?php
27216
27217
27218
27219
27220
27221
27222
27223
27224
27225
27226
27227 namespace Composer\Package\Archiver;
27228
27229 use Composer\Util\Filesystem;
27230 use FilesystemIterator;
27231 use Symfony\Component\Finder\Finder;
27232 use Symfony\Component\Finder\SplFileInfo;
27233
27234
27235
27236
27237
27238
27239
27240
27241
27242 class ArchivableFilesFinder extends \FilterIterator
27243 {
27244
27245
27246
27247 protected $finder;
27248
27249
27250
27251
27252
27253
27254
27255
27256 public function __construct($sources, array $excludes, $ignoreFilters = false)
27257 {
27258 $fs = new Filesystem();
27259
27260 $sources = $fs->normalizePath(realpath($sources));
27261
27262 if ($ignoreFilters) {
27263 $filters = array();
27264 } else {
27265 $filters = array(
27266 new HgExcludeFilter($sources),
27267 new GitExcludeFilter($sources),
27268 new ComposerExcludeFilter($sources, $excludes),
27269 );
27270 }
27271
27272 $this->finder = new Finder();
27273
27274 $filter = function (\SplFileInfo $file) use ($sources, $filters, $fs) {
27275 if ($file->isLink() && strpos($file->getRealPath(), $sources) !== 0) {
27276 return false;
27277 }
27278
27279 $relativePath = preg_replace(
27280 '#^'.preg_quote($sources, '#').'#',
27281 '',
27282 $fs->normalizePath($file->getRealPath())
27283 );
27284
27285 $exclude = false;
27286 foreach ($filters as $filter) {
27287 $exclude = $filter->filter($relativePath, $exclude);
27288 }
27289
27290 return !$exclude;
27291 };
27292
27293 if (method_exists($filter, 'bindTo')) {
27294 $filter = $filter->bindTo(null);
27295 }
27296
27297 $this->finder
27298 ->in($sources)
27299 ->filter($filter)
27300 ->ignoreVCS(true)
27301 ->ignoreDotFiles(false);
27302
27303 parent::__construct($this->finder->getIterator());
27304 }
27305
27306 public function accept()
27307 {
27308
27309 $current = $this->getInnerIterator()->current();
27310
27311 if (!$current->isDir()) {
27312 return true;
27313 }
27314
27315 $iterator = new FilesystemIterator($current, FilesystemIterator::SKIP_DOTS);
27316
27317 return !$iterator->valid();
27318 }
27319 }
27320 <?php
27321
27322
27323
27324
27325
27326
27327
27328
27329
27330
27331
27332 namespace Composer\Package\Archiver;
27333
27334 use Composer\Downloader\DownloadManager;
27335 use Composer\Package\PackageInterface;
27336 use Composer\Package\RootPackageInterface;
27337 use Composer\Util\Filesystem;
27338 use Composer\Json\JsonFile;
27339
27340
27341
27342
27343
27344 class ArchiveManager
27345 {
27346 protected $downloadManager;
27347
27348 protected $archivers = array();
27349
27350
27351
27352
27353 protected $overwriteFiles = true;
27354
27355
27356
27357
27358 public function __construct(DownloadManager $downloadManager)
27359 {
27360 $this->downloadManager = $downloadManager;
27361 }
27362
27363
27364
27365
27366 public function addArchiver(ArchiverInterface $archiver)
27367 {
27368 $this->archivers[] = $archiver;
27369 }
27370
27371
27372
27373
27374
27375
27376
27377
27378 public function setOverwriteFiles($overwriteFiles)
27379 {
27380 $this->overwriteFiles = $overwriteFiles;
27381
27382 return $this;
27383 }
27384
27385
27386
27387
27388
27389
27390
27391
27392 public function getPackageFilename(PackageInterface $package)
27393 {
27394 $nameParts = array(preg_replace('#[^a-z0-9-_]#i', '-', $package->getName()));
27395
27396 if (preg_match('{^[a-f0-9]{40}$}', $package->getDistReference())) {
27397 array_push($nameParts, $package->getDistReference(), $package->getDistType());
27398 } else {
27399 array_push($nameParts, $package->getPrettyVersion(), $package->getDistReference());
27400 }
27401
27402 if ($package->getSourceReference()) {
27403 $nameParts[] = substr(sha1($package->getSourceReference()), 0, 6);
27404 }
27405
27406 $name = implode('-', array_filter($nameParts, function ($p) {
27407 return !empty($p);
27408 }));
27409
27410 return str_replace('/', '-', $name);
27411 }
27412
27413
27414
27415
27416
27417
27418
27419
27420
27421
27422
27423
27424
27425
27426 public function archive(PackageInterface $package, $format, $targetDir, $fileName = null, $ignoreFilters = false)
27427 {
27428 if (empty($format)) {
27429 throw new \InvalidArgumentException('Format must be specified');
27430 }
27431
27432
27433 $usableArchiver = null;
27434 foreach ($this->archivers as $archiver) {
27435 if ($archiver->supports($format, $package->getSourceType())) {
27436 $usableArchiver = $archiver;
27437 break;
27438 }
27439 }
27440
27441
27442 if (null === $usableArchiver) {
27443 throw new \RuntimeException(sprintf('No archiver found to support %s format', $format));
27444 }
27445
27446 $filesystem = new Filesystem();
27447 if (null === $fileName) {
27448 $packageName = $this->getPackageFilename($package);
27449 } else {
27450 $packageName = $fileName;
27451 }
27452
27453
27454 $filesystem->ensureDirectoryExists($targetDir);
27455 $target = realpath($targetDir).'/'.$packageName.'.'.$format;
27456 $filesystem->ensureDirectoryExists(dirname($target));
27457
27458 if (!$this->overwriteFiles && file_exists($target)) {
27459 return $target;
27460 }
27461
27462 if ($package instanceof RootPackageInterface) {
27463 $sourcePath = realpath('.');
27464 } else {
27465
27466 $sourcePath = sys_get_temp_dir().'/composer_archive'.uniqid();
27467 $filesystem->ensureDirectoryExists($sourcePath);
27468
27469 try {
27470
27471 $this->downloadManager->download($package, $sourcePath);
27472 } catch (\Exception $e) {
27473 $filesystem->removeDirectory($sourcePath);
27474 throw $e;
27475 }
27476
27477
27478 if (file_exists($composerJsonPath = $sourcePath.'/composer.json')) {
27479 $jsonFile = new JsonFile($composerJsonPath);
27480 $jsonData = $jsonFile->read();
27481 if (!empty($jsonData['archive']['exclude'])) {
27482 $package->setArchiveExcludes($jsonData['archive']['exclude']);
27483 }
27484 }
27485 }
27486
27487
27488 $tempTarget = sys_get_temp_dir().'/composer_archive'.uniqid().'.'.$format;
27489 $filesystem->ensureDirectoryExists(dirname($tempTarget));
27490
27491 $archivePath = $usableArchiver->archive($sourcePath, $tempTarget, $format, $package->getArchiveExcludes(), $ignoreFilters);
27492 $filesystem->rename($archivePath, $target);
27493
27494
27495 if (!$package instanceof RootPackageInterface) {
27496 $filesystem->removeDirectory($sourcePath);
27497 }
27498 $filesystem->remove($tempTarget);
27499
27500 return $target;
27501 }
27502 }
27503 <?php
27504
27505
27506
27507
27508
27509
27510
27511
27512
27513
27514
27515 namespace Composer\Package\Archiver;
27516
27517
27518
27519
27520
27521
27522 interface ArchiverInterface
27523 {
27524
27525
27526
27527
27528
27529
27530
27531
27532
27533
27534 public function archive($sources, $target, $format, array $excludes = array(), $ignoreFilters = false);
27535
27536
27537
27538
27539
27540
27541
27542
27543
27544 public function supports($format, $sourceType);
27545 }
27546 <?php
27547
27548
27549
27550
27551
27552
27553
27554
27555
27556
27557
27558 namespace Composer\Package\Archiver;
27559
27560 use Symfony\Component\Finder;
27561
27562
27563
27564
27565 abstract class BaseExcludeFilter
27566 {
27567
27568
27569
27570 protected $sourcePath;
27571
27572
27573
27574
27575 protected $excludePatterns;
27576
27577
27578
27579
27580 public function __construct($sourcePath)
27581 {
27582 $this->sourcePath = $sourcePath;
27583 $this->excludePatterns = array();
27584 }
27585
27586
27587
27588
27589
27590
27591
27592
27593
27594
27595
27596 public function filter($relativePath, $exclude)
27597 {
27598 foreach ($this->excludePatterns as $patternData) {
27599 list($pattern, $negate, $stripLeadingSlash) = $patternData;
27600
27601 if ($stripLeadingSlash) {
27602 $path = substr($relativePath, 1);
27603 } else {
27604 $path = $relativePath;
27605 }
27606
27607 if (@preg_match($pattern, $path)) {
27608 $exclude = !$negate;
27609 }
27610 }
27611
27612 return $exclude;
27613 }
27614
27615
27616
27617
27618
27619
27620
27621
27622
27623 protected function parseLines(array $lines, $lineParser)
27624 {
27625 return array_filter(
27626 array_map(
27627 function ($line) use ($lineParser) {
27628 $line = trim($line);
27629
27630 if (!$line || 0 === strpos($line, '#')) {
27631 return null;
27632 }
27633
27634 return call_user_func($lineParser, $line);
27635 },
27636 $lines
27637 ),
27638 function ($pattern) {
27639 return $pattern !== null;
27640 }
27641 );
27642 }
27643
27644
27645
27646
27647
27648
27649
27650
27651 protected function generatePatterns($rules)
27652 {
27653 $patterns = array();
27654 foreach ($rules as $rule) {
27655 $patterns[] = $this->generatePattern($rule);
27656 }
27657
27658 return $patterns;
27659 }
27660
27661
27662
27663
27664
27665
27666
27667
27668 protected function generatePattern($rule)
27669 {
27670 $negate = false;
27671 $pattern = '{';
27672
27673 if (strlen($rule) && $rule[0] === '!') {
27674 $negate = true;
27675 $rule = substr($rule, 1);
27676 }
27677
27678 if (strlen($rule) && $rule[0] === '/') {
27679 $pattern .= '^/';
27680 $rule = substr($rule, 1);
27681 } elseif (strlen($rule) - 1 === strpos($rule, '/')) {
27682 $pattern .= '/';
27683 $rule = substr($rule, 0, -1);
27684 } elseif (false === strpos($rule, '/')) {
27685 $pattern .= '/';
27686 }
27687
27688
27689 $pattern .= substr(Finder\Glob::toRegex($rule), 2, -2) . '(?=$|/)';
27690
27691 return array($pattern . '}', $negate, false);
27692 }
27693 }
27694 <?php
27695
27696
27697
27698
27699
27700
27701
27702
27703
27704
27705
27706 namespace Composer\Package\Archiver;
27707
27708
27709
27710
27711
27712
27713 class ComposerExcludeFilter extends BaseExcludeFilter
27714 {
27715
27716
27717
27718
27719 public function __construct($sourcePath, array $excludeRules)
27720 {
27721 parent::__construct($sourcePath);
27722 $this->excludePatterns = $this->generatePatterns($excludeRules);
27723 }
27724 }
27725 <?php
27726
27727
27728
27729
27730
27731
27732
27733
27734
27735
27736
27737 namespace Composer\Package\Archiver;
27738
27739
27740
27741
27742
27743
27744
27745
27746 class GitExcludeFilter extends BaseExcludeFilter
27747 {
27748
27749
27750
27751
27752
27753 public function __construct($sourcePath)
27754 {
27755 parent::__construct($sourcePath);
27756
27757 if (file_exists($sourcePath.'/.gitignore')) {
27758 $this->excludePatterns = $this->parseLines(
27759 file($sourcePath.'/.gitignore'),
27760 array($this, 'parseGitIgnoreLine')
27761 );
27762 }
27763 if (file_exists($sourcePath.'/.gitattributes')) {
27764 $this->excludePatterns = array_merge(
27765 $this->excludePatterns,
27766 $this->parseLines(
27767 file($sourcePath.'/.gitattributes'),
27768 array($this, 'parseGitAttributesLine')
27769 )
27770 );
27771 }
27772 }
27773
27774
27775
27776
27777
27778
27779
27780
27781 public function parseGitIgnoreLine($line)
27782 {
27783 return $this->generatePattern($line);
27784 }
27785
27786
27787
27788
27789
27790
27791
27792
27793 public function parseGitAttributesLine($line)
27794 {
27795 $parts = preg_split('#\s+#', $line);
27796
27797 if (count($parts) == 2 && $parts[1] === 'export-ignore') {
27798 return $this->generatePattern($parts[0]);
27799 }
27800
27801 return null;
27802 }
27803 }
27804 <?php
27805
27806
27807
27808
27809
27810
27811
27812
27813
27814
27815
27816 namespace Composer\Package\Archiver;
27817
27818 use Symfony\Component\Finder;
27819
27820
27821
27822
27823
27824
27825 class HgExcludeFilter extends BaseExcludeFilter
27826 {
27827 const HG_IGNORE_REGEX = 1;
27828 const HG_IGNORE_GLOB = 2;
27829
27830
27831
27832
27833
27834 protected $patternMode;
27835
27836
27837
27838
27839
27840
27841 public function __construct($sourcePath)
27842 {
27843 parent::__construct($sourcePath);
27844
27845 $this->patternMode = self::HG_IGNORE_REGEX;
27846
27847 if (file_exists($sourcePath.'/.hgignore')) {
27848 $this->excludePatterns = $this->parseLines(
27849 file($sourcePath.'/.hgignore'),
27850 array($this, 'parseHgIgnoreLine')
27851 );
27852 }
27853 }
27854
27855
27856
27857
27858
27859
27860
27861
27862 public function parseHgIgnoreLine($line)
27863 {
27864 if (preg_match('#^syntax\s*:\s*(glob|regexp)$#', $line, $matches)) {
27865 if ($matches[1] === 'glob') {
27866 $this->patternMode = self::HG_IGNORE_GLOB;
27867 } else {
27868 $this->patternMode = self::HG_IGNORE_REGEX;
27869 }
27870
27871 return null;
27872 }
27873
27874 if ($this->patternMode == self::HG_IGNORE_GLOB) {
27875 return $this->patternFromGlob($line);
27876 }
27877
27878 return $this->patternFromRegex($line);
27879 }
27880
27881
27882
27883
27884
27885
27886
27887
27888 protected function patternFromGlob($line)
27889 {
27890 $pattern = '#'.substr(Finder\Glob::toRegex($line), 2, -1).'#';
27891 $pattern = str_replace('[^/]*', '.*', $pattern);
27892
27893 return array($pattern, false, true);
27894 }
27895
27896
27897
27898
27899
27900
27901
27902
27903 public function patternFromRegex($line)
27904 {
27905
27906 $pattern = '#'.preg_replace('/((?:\\\\\\\\)*)(\\\\?)#/', '\1\2\2\\#', $line).'#';
27907
27908 return array($pattern, false, true);
27909 }
27910 }
27911 <?php
27912
27913
27914
27915
27916
27917
27918
27919
27920
27921
27922
27923 namespace Composer\Package\Archiver;
27924
27925
27926
27927
27928
27929
27930 class PharArchiver implements ArchiverInterface
27931 {
27932 protected static $formats = array(
27933 'zip' => \Phar::ZIP,
27934 'tar' => \Phar::TAR,
27935 'tar.gz' => \Phar::TAR,
27936 'tar.bz2' => \Phar::TAR,
27937 );
27938
27939 protected static $compressFormats = array(
27940 'tar.gz' => \Phar::GZ,
27941 'tar.bz2' => \Phar::BZ2,
27942 );
27943
27944
27945
27946
27947 public function archive($sources, $target, $format, array $excludes = array(), $ignoreFilters = false)
27948 {
27949 $sources = realpath($sources);
27950
27951
27952 if (file_exists($target)) {
27953 unlink($target);
27954 }
27955
27956 try {
27957 $filename = substr($target, 0, strrpos($target, $format) - 1);
27958
27959
27960 if (isset(static::$compressFormats[$format])) {
27961
27962 $target = $filename . '.tar';
27963 }
27964
27965 $phar = new \PharData($target, null, null, static::$formats[$format]);
27966 $files = new ArchivableFilesFinder($sources, $excludes, $ignoreFilters);
27967 $filesOnly = new ArchivableFilesFilter($files);
27968 $phar->buildFromIterator($filesOnly, $sources);
27969 $filesOnly->addEmptyDir($phar, $sources);
27970
27971 if (isset(static::$compressFormats[$format])) {
27972
27973 if (!$phar->canCompress(static::$compressFormats[$format])) {
27974 throw new \RuntimeException(sprintf('Can not compress to %s format', $format));
27975 }
27976
27977
27978 unlink($target);
27979
27980
27981 $phar->compress(static::$compressFormats[$format]);
27982
27983
27984 $target = $filename . '.' . $format;
27985 }
27986
27987 return $target;
27988 } catch (\UnexpectedValueException $e) {
27989 $message = sprintf(
27990 "Could not create archive '%s' from '%s': %s",
27991 $target,
27992 $sources,
27993 $e->getMessage()
27994 );
27995
27996 throw new \RuntimeException($message, $e->getCode(), $e);
27997 }
27998 }
27999
28000
28001
28002
28003 public function supports($format, $sourceType)
28004 {
28005 return isset(static::$formats[$format]);
28006 }
28007 }
28008 <?php
28009
28010
28011
28012
28013
28014
28015
28016
28017
28018
28019
28020 namespace Composer\Package\Archiver;
28021
28022 use ZipArchive;
28023 use Composer\Util\Filesystem;
28024
28025
28026
28027
28028 class ZipArchiver implements ArchiverInterface
28029 {
28030 protected static $formats = array(
28031 'zip' => 1,
28032 );
28033
28034
28035
28036
28037 public function archive($sources, $target, $format, array $excludes = array(), $ignoreFilters = false)
28038 {
28039 $fs = new Filesystem();
28040 $sources = $fs->normalizePath($sources);
28041
28042 $zip = new ZipArchive();
28043 $res = $zip->open($target, ZipArchive::CREATE);
28044 if ($res === true) {
28045 $files = new ArchivableFilesFinder($sources, $excludes, $ignoreFilters);
28046 foreach ($files as $file) {
28047
28048 $filepath = strtr($file->getPath()."/".$file->getFilename(), '\\', '/');
28049 $localname = str_replace($sources.'/', '', $filepath);
28050 if ($file->isDir()) {
28051 $zip->addEmptyDir($localname);
28052 } else {
28053 $zip->addFile($filepath, $localname);
28054 }
28055
28056
28057
28058
28059 if (PHP_VERSION_ID >= 50600) {
28060 $perms = fileperms($filepath);
28061
28062
28063
28064
28065 $zip->setExternalAttributesName($localname, ZipArchive::OPSYS_UNIX, $perms << 16);
28066 }
28067 }
28068 if ($zip->close()) {
28069 return $target;
28070 }
28071 }
28072 $message = sprintf(
28073 "Could not create archive '%s' from '%s': %s",
28074 $target,
28075 $sources,
28076 $zip->getStatusString()
28077 );
28078 throw new \RuntimeException($message);
28079 }
28080
28081
28082
28083
28084 public function supports($format, $sourceType)
28085 {
28086 return isset(static::$formats[$format]) && $this->compressionAvailable();
28087 }
28088
28089 private function compressionAvailable()
28090 {
28091 return class_exists('ZipArchive');
28092 }
28093 }
28094 <?php
28095
28096
28097
28098
28099
28100
28101
28102
28103
28104
28105
28106 namespace Composer\Package;
28107
28108 use Composer\Repository\RepositoryInterface;
28109 use Composer\Repository\PlatformRepository;
28110
28111
28112
28113
28114
28115
28116 abstract class BasePackage implements PackageInterface
28117 {
28118 public static $supportedLinkTypes = array(
28119 'require' => array('description' => 'requires', 'method' => 'requires'),
28120 'conflict' => array('description' => 'conflicts', 'method' => 'conflicts'),
28121 'provide' => array('description' => 'provides', 'method' => 'provides'),
28122 'replace' => array('description' => 'replaces', 'method' => 'replaces'),
28123 'require-dev' => array('description' => 'requires (for development)', 'method' => 'devRequires'),
28124 );
28125
28126 const STABILITY_STABLE = 0;
28127 const STABILITY_RC = 5;
28128 const STABILITY_BETA = 10;
28129 const STABILITY_ALPHA = 15;
28130 const STABILITY_DEV = 20;
28131
28132 public static $stabilities = array(
28133 'stable' => self::STABILITY_STABLE,
28134 'RC' => self::STABILITY_RC,
28135 'beta' => self::STABILITY_BETA,
28136 'alpha' => self::STABILITY_ALPHA,
28137 'dev' => self::STABILITY_DEV,
28138 );
28139
28140
28141
28142
28143
28144 public $id;
28145
28146 protected $name;
28147
28148 protected $prettyName;
28149
28150 protected $repository;
28151
28152 protected $transportOptions = array();
28153
28154
28155
28156
28157
28158
28159 public function __construct($name)
28160 {
28161 $this->prettyName = $name;
28162 $this->name = strtolower($name);
28163 $this->id = -1;
28164 }
28165
28166
28167
28168
28169 public function getName()
28170 {
28171 return $this->name;
28172 }
28173
28174
28175
28176
28177 public function getPrettyName()
28178 {
28179 return $this->prettyName;
28180 }
28181
28182
28183
28184
28185 public function getNames()
28186 {
28187 $names = array(
28188 $this->getName() => true,
28189 );
28190
28191 foreach ($this->getProvides() as $link) {
28192 $names[$link->getTarget()] = true;
28193 }
28194
28195 foreach ($this->getReplaces() as $link) {
28196 $names[$link->getTarget()] = true;
28197 }
28198
28199 return array_keys($names);
28200 }
28201
28202
28203
28204
28205 public function setId($id)
28206 {
28207 $this->id = $id;
28208 }
28209
28210
28211
28212
28213 public function getId()
28214 {
28215 return $this->id;
28216 }
28217
28218
28219
28220
28221 public function setRepository(RepositoryInterface $repository)
28222 {
28223 if ($this->repository && $repository !== $this->repository) {
28224 throw new \LogicException('A package can only be added to one repository');
28225 }
28226 $this->repository = $repository;
28227 }
28228
28229
28230
28231
28232 public function getRepository()
28233 {
28234 return $this->repository;
28235 }
28236
28237
28238
28239
28240 public function getTransportOptions()
28241 {
28242 return $this->transportOptions;
28243 }
28244
28245
28246
28247
28248
28249
28250 public function setTransportOptions(array $options)
28251 {
28252 $this->transportOptions = $options;
28253 }
28254
28255
28256
28257
28258
28259
28260 public function isPlatform()
28261 {
28262 return $this->getRepository() instanceof PlatformRepository;
28263 }
28264
28265
28266
28267
28268
28269
28270 public function getUniqueName()
28271 {
28272 return $this->getName().'-'.$this->getVersion();
28273 }
28274
28275 public function equals(PackageInterface $package)
28276 {
28277 $self = $this;
28278 if ($this instanceof AliasPackage) {
28279 $self = $this->getAliasOf();
28280 }
28281 if ($package instanceof AliasPackage) {
28282 $package = $package->getAliasOf();
28283 }
28284
28285 return $package === $self;
28286 }
28287
28288
28289
28290
28291
28292
28293 public function __toString()
28294 {
28295 return $this->getUniqueName();
28296 }
28297
28298 public function getPrettyString()
28299 {
28300 return $this->getPrettyName().' '.$this->getPrettyVersion();
28301 }
28302
28303
28304
28305
28306 public function getFullPrettyVersion($truncate = true)
28307 {
28308 if (!$this->isDev() || !in_array($this->getSourceType(), array('hg', 'git'))) {
28309 return $this->getPrettyVersion();
28310 }
28311
28312
28313 if ($truncate && strlen($this->getSourceReference()) === 40) {
28314 return $this->getPrettyVersion() . ' ' . substr($this->getSourceReference(), 0, 7);
28315 }
28316
28317 return $this->getPrettyVersion() . ' ' . $this->getSourceReference();
28318 }
28319
28320 public function getStabilityPriority()
28321 {
28322 return self::$stabilities[$this->getStability()];
28323 }
28324
28325 public function __clone()
28326 {
28327 $this->repository = null;
28328 $this->id = -1;
28329 }
28330
28331
28332
28333
28334
28335
28336
28337
28338 public static function packageNameToRegexp($allowListPattern, $wrap = '{^%s$}i')
28339 {
28340 $cleanedAllowListPattern = str_replace('\\*', '.*', preg_quote($allowListPattern));
28341
28342 return sprintf($wrap, $cleanedAllowListPattern);
28343 }
28344 }
28345 <?php
28346
28347
28348
28349
28350
28351
28352
28353
28354
28355
28356
28357 namespace Composer\Package\Comparer;
28358
28359
28360
28361
28362
28363
28364 class Comparer
28365 {
28366 private $source;
28367 private $update;
28368 private $changed;
28369
28370 public function setSource($source)
28371 {
28372 $this->source = $source;
28373 }
28374
28375 public function setUpdate($update)
28376 {
28377 $this->update = $update;
28378 }
28379
28380 public function getChanged($toString = false, $explicated = false)
28381 {
28382 $changed = $this->changed;
28383 if (!count($changed)) {
28384 return false;
28385 }
28386 if ($explicated) {
28387 foreach ($changed as $sectionKey => $itemSection) {
28388 foreach ($itemSection as $itemKey => $item) {
28389 $changed[$sectionKey][$itemKey] = $item.' ('.$sectionKey.')';
28390 }
28391 }
28392 }
28393
28394 if ($toString) {
28395 foreach ($changed as $sectionKey => $itemSection) {
28396 foreach ($itemSection as $itemKey => $item) {
28397 $changed['string'][] = $item."\r\n";
28398 }
28399 }
28400 $changed = implode("\r\n", $changed['string']);
28401 }
28402
28403 return $changed;
28404 }
28405
28406 public function doCompare()
28407 {
28408 $source = array();
28409 $destination = array();
28410 $this->changed = array();
28411 $currentDirectory = getcwd();
28412 chdir($this->source);
28413 $source = $this->doTree('.', $source);
28414 if (!is_array($source)) {
28415 return;
28416 }
28417 chdir($currentDirectory);
28418 chdir($this->update);
28419 $destination = $this->doTree('.', $destination);
28420 if (!is_array($destination)) {
28421 exit;
28422 }
28423 chdir($currentDirectory);
28424 foreach ($source as $dir => $value) {
28425 foreach ($value as $file => $hash) {
28426 if (isset($destination[$dir][$file])) {
28427 if ($hash !== $destination[$dir][$file]) {
28428 $this->changed['changed'][] = $dir.'/'.$file;
28429 }
28430 } else {
28431 $this->changed['removed'][] = $dir.'/'.$file;
28432 }
28433 }
28434 }
28435 foreach ($destination as $dir => $value) {
28436 foreach ($value as $file => $hash) {
28437 if (!isset($source[$dir][$file])) {
28438 $this->changed['added'][] = $dir.'/'.$file;
28439 }
28440 }
28441 }
28442 }
28443
28444 private function doTree($dir, &$array)
28445 {
28446 if ($dh = opendir($dir)) {
28447 while ($file = readdir($dh)) {
28448 if ($file !== '.' && $file !== '..') {
28449 if (is_link($dir.'/'.$file)) {
28450 $array[$dir][$file] = readlink($dir.'/'.$file);
28451 } elseif (is_dir($dir.'/'.$file)) {
28452 if (!count($array)) {
28453 $array[0] = 'Temp';
28454 }
28455 if (!$this->doTree($dir.'/'.$file, $array)) {
28456 return false;
28457 }
28458 } elseif (is_file($dir.'/'.$file) && filesize($dir.'/'.$file)) {
28459 set_time_limit(30);
28460 $array[$dir][$file] = md5_file($dir.'/'.$file);
28461 }
28462 }
28463 }
28464 if (count($array) > 1 && isset($array['0'])) {
28465 unset($array['0']);
28466 }
28467
28468 return $array;
28469 }
28470
28471 return false;
28472 }
28473 }
28474 <?php
28475
28476
28477
28478
28479
28480
28481
28482
28483
28484
28485
28486 namespace Composer\Package;
28487
28488
28489
28490
28491
28492
28493 class CompletePackage extends Package implements CompletePackageInterface
28494 {
28495 protected $repositories;
28496 protected $license = array();
28497 protected $keywords;
28498 protected $authors;
28499 protected $description;
28500 protected $homepage;
28501 protected $scripts = array();
28502 protected $support = array();
28503 protected $funding = array();
28504 protected $abandoned = false;
28505
28506
28507
28508
28509 public function setScripts(array $scripts)
28510 {
28511 $this->scripts = $scripts;
28512 }
28513
28514
28515
28516
28517 public function getScripts()
28518 {
28519 return $this->scripts;
28520 }
28521
28522
28523
28524
28525
28526
28527 public function setRepositories($repositories)
28528 {
28529 $this->repositories = $repositories;
28530 }
28531
28532
28533
28534
28535 public function getRepositories()
28536 {
28537 return $this->repositories;
28538 }
28539
28540
28541
28542
28543
28544
28545 public function setLicense(array $license)
28546 {
28547 $this->license = $license;
28548 }
28549
28550
28551
28552
28553 public function getLicense()
28554 {
28555 return $this->license;
28556 }
28557
28558
28559
28560
28561
28562
28563 public function setKeywords(array $keywords)
28564 {
28565 $this->keywords = $keywords;
28566 }
28567
28568
28569
28570
28571 public function getKeywords()
28572 {
28573 return $this->keywords;
28574 }
28575
28576
28577
28578
28579
28580
28581 public function setAuthors(array $authors)
28582 {
28583 $this->authors = $authors;
28584 }
28585
28586
28587
28588
28589 public function getAuthors()
28590 {
28591 return $this->authors;
28592 }
28593
28594
28595
28596
28597
28598
28599 public function setDescription($description)
28600 {
28601 $this->description = $description;
28602 }
28603
28604
28605
28606
28607 public function getDescription()
28608 {
28609 return $this->description;
28610 }
28611
28612
28613
28614
28615
28616
28617 public function setHomepage($homepage)
28618 {
28619 $this->homepage = $homepage;
28620 }
28621
28622
28623
28624
28625 public function getHomepage()
28626 {
28627 return $this->homepage;
28628 }
28629
28630
28631
28632
28633
28634
28635 public function setSupport(array $support)
28636 {
28637 $this->support = $support;
28638 }
28639
28640
28641
28642
28643 public function getSupport()
28644 {
28645 return $this->support;
28646 }
28647
28648
28649
28650
28651
28652
28653 public function setFunding(array $funding)
28654 {
28655 $this->funding = $funding;
28656 }
28657
28658
28659
28660
28661 public function getFunding()
28662 {
28663 return $this->funding;
28664 }
28665
28666
28667
28668
28669 public function isAbandoned()
28670 {
28671 return (bool) $this->abandoned;
28672 }
28673
28674
28675
28676
28677 public function setAbandoned($abandoned)
28678 {
28679 $this->abandoned = $abandoned;
28680 }
28681
28682
28683
28684
28685
28686
28687 public function getReplacementPackage()
28688 {
28689 return is_string($this->abandoned) ? $this->abandoned : null;
28690 }
28691 }
28692 <?php
28693
28694
28695
28696
28697
28698
28699
28700
28701
28702
28703
28704 namespace Composer\Package;
28705
28706
28707
28708
28709
28710
28711 interface CompletePackageInterface extends PackageInterface
28712 {
28713
28714
28715
28716
28717
28718 public function getScripts();
28719
28720
28721
28722
28723
28724
28725
28726
28727 public function getRepositories();
28728
28729
28730
28731
28732
28733
28734 public function getLicense();
28735
28736
28737
28738
28739
28740
28741 public function getKeywords();
28742
28743
28744
28745
28746
28747
28748 public function getDescription();
28749
28750
28751
28752
28753
28754
28755 public function getHomepage();
28756
28757
28758
28759
28760
28761
28762
28763
28764 public function getAuthors();
28765
28766
28767
28768
28769
28770
28771 public function getSupport();
28772
28773
28774
28775
28776
28777
28778
28779
28780 public function getFunding();
28781
28782
28783
28784
28785
28786
28787 public function isAbandoned();
28788
28789
28790
28791
28792
28793
28794 public function getReplacementPackage();
28795 }
28796 <?php
28797
28798
28799
28800
28801
28802
28803
28804
28805
28806
28807
28808 namespace Composer\Package\Dumper;
28809
28810 use Composer\Package\BasePackage;
28811 use Composer\Package\PackageInterface;
28812 use Composer\Package\CompletePackageInterface;
28813 use Composer\Package\RootPackageInterface;
28814
28815
28816
28817
28818
28819 class ArrayDumper
28820 {
28821 public function dump(PackageInterface $package)
28822 {
28823 $keys = array(
28824 'binaries' => 'bin',
28825 'type',
28826 'extra',
28827 'installationSource' => 'installation-source',
28828 'autoload',
28829 'devAutoload' => 'autoload-dev',
28830 'notificationUrl' => 'notification-url',
28831 'includePaths' => 'include-path',
28832 );
28833
28834 $data = array();
28835 $data['name'] = $package->getPrettyName();
28836 $data['version'] = $package->getPrettyVersion();
28837 $data['version_normalized'] = $package->getVersion();
28838
28839 if ($package->getTargetDir()) {
28840 $data['target-dir'] = $package->getTargetDir();
28841 }
28842
28843 if ($package->getSourceType()) {
28844 $data['source']['type'] = $package->getSourceType();
28845 $data['source']['url'] = $package->getSourceUrl();
28846 if (null !== ($value = $package->getSourceReference())) {
28847 $data['source']['reference'] = $value;
28848 }
28849 if ($mirrors = $package->getSourceMirrors()) {
28850 $data['source']['mirrors'] = $mirrors;
28851 }
28852 }
28853
28854 if ($package->getDistType()) {
28855 $data['dist']['type'] = $package->getDistType();
28856 $data['dist']['url'] = $package->getDistUrl();
28857 if (null !== ($value = $package->getDistReference())) {
28858 $data['dist']['reference'] = $value;
28859 }
28860 if (null !== ($value = $package->getDistSha1Checksum())) {
28861 $data['dist']['shasum'] = $value;
28862 }
28863 if ($mirrors = $package->getDistMirrors()) {
28864 $data['dist']['mirrors'] = $mirrors;
28865 }
28866 }
28867
28868 if ($package->getArchiveExcludes()) {
28869 $data['archive']['exclude'] = $package->getArchiveExcludes();
28870 }
28871
28872 foreach (BasePackage::$supportedLinkTypes as $type => $opts) {
28873 if ($links = $package->{'get'.ucfirst($opts['method'])}()) {
28874 foreach ($links as $link) {
28875 $data[$type][$link->getTarget()] = $link->getPrettyConstraint();
28876 }
28877 ksort($data[$type]);
28878 }
28879 }
28880
28881 if ($packages = $package->getSuggests()) {
28882 ksort($packages);
28883 $data['suggest'] = $packages;
28884 }
28885
28886 if ($package->getReleaseDate()) {
28887 $data['time'] = $package->getReleaseDate()->format(DATE_RFC3339);
28888 }
28889
28890 $data = $this->dumpValues($package, $keys, $data);
28891
28892 if ($package instanceof CompletePackageInterface) {
28893 $keys = array(
28894 'scripts',
28895 'license',
28896 'authors',
28897 'description',
28898 'homepage',
28899 'keywords',
28900 'repositories',
28901 'support',
28902 'funding',
28903 );
28904
28905 $data = $this->dumpValues($package, $keys, $data);
28906
28907 if (isset($data['keywords']) && is_array($data['keywords'])) {
28908 sort($data['keywords']);
28909 }
28910
28911 if ($package->isAbandoned()) {
28912 $data['abandoned'] = $package->getReplacementPackage() ?: true;
28913 }
28914 }
28915
28916 if ($package instanceof RootPackageInterface) {
28917 $minimumStability = $package->getMinimumStability();
28918 if ($minimumStability) {
28919 $data['minimum-stability'] = $minimumStability;
28920 }
28921 }
28922
28923 if (count($package->getTransportOptions()) > 0) {
28924 $data['transport-options'] = $package->getTransportOptions();
28925 }
28926
28927 return $data;
28928 }
28929
28930 private function dumpValues(PackageInterface $package, array $keys, array $data)
28931 {
28932 foreach ($keys as $method => $key) {
28933 if (is_numeric($method)) {
28934 $method = $key;
28935 }
28936
28937 $getter = 'get'.ucfirst($method);
28938 $value = $package->$getter();
28939
28940 if (null !== $value && !(is_array($value) && 0 === count($value))) {
28941 $data[$key] = $value;
28942 }
28943 }
28944
28945 return $data;
28946 }
28947 }
28948 <?php
28949
28950
28951
28952
28953
28954
28955
28956
28957
28958
28959
28960 namespace Composer\Package;
28961
28962 use Composer\Semver\Constraint\ConstraintInterface;
28963
28964
28965
28966
28967
28968
28969 class Link
28970 {
28971
28972
28973
28974 protected $source;
28975
28976
28977
28978
28979 protected $target;
28980
28981
28982
28983
28984 protected $constraint;
28985
28986
28987
28988
28989 protected $description;
28990
28991
28992
28993
28994 protected $prettyConstraint;
28995
28996
28997
28998
28999
29000
29001
29002
29003
29004
29005 public function __construct($source, $target, ConstraintInterface $constraint = null, $description = 'relates to', $prettyConstraint = null)
29006 {
29007 $this->source = strtolower($source);
29008 $this->target = strtolower($target);
29009 $this->constraint = $constraint;
29010 $this->description = $description;
29011 $this->prettyConstraint = $prettyConstraint;
29012 }
29013
29014
29015
29016
29017 public function getDescription()
29018 {
29019 return $this->description;
29020 }
29021
29022
29023
29024
29025 public function getSource()
29026 {
29027 return $this->source;
29028 }
29029
29030
29031
29032
29033 public function getTarget()
29034 {
29035 return $this->target;
29036 }
29037
29038
29039
29040
29041 public function getConstraint()
29042 {
29043 return $this->constraint;
29044 }
29045
29046
29047
29048
29049
29050 public function getPrettyConstraint()
29051 {
29052 if (null === $this->prettyConstraint) {
29053 throw new \UnexpectedValueException(sprintf('Link %s has been misconfigured and had no prettyConstraint given.', $this));
29054 }
29055
29056 return $this->prettyConstraint;
29057 }
29058
29059
29060
29061
29062 public function __toString()
29063 {
29064 return $this->source.' '.$this->description.' '.$this->target.' ('.$this->constraint.')';
29065 }
29066
29067
29068
29069
29070
29071 public function getPrettyString(PackageInterface $sourcePackage)
29072 {
29073 return $sourcePackage->getPrettyString().' '.$this->description.' '.$this->target.' '.$this->constraint->getPrettyString().'';
29074 }
29075 }
29076 <?php
29077
29078
29079
29080
29081
29082
29083
29084
29085
29086
29087
29088 namespace Composer\Package\LinkConstraint;
29089
29090 use Composer\Semver\Constraint\EmptyConstraint as SemverEmptyConstraint;
29091
29092 trigger_error('The ' . __NAMESPACE__ . '\EmptyConstraint class is deprecated, use Composer\Semver\Constraint\EmptyConstraint instead.', E_USER_DEPRECATED);
29093
29094
29095
29096
29097 class EmptyConstraint extends SemverEmptyConstraint implements LinkConstraintInterface
29098 {
29099 }
29100 <?php
29101
29102
29103
29104
29105
29106
29107
29108
29109
29110
29111
29112 namespace Composer\Package\LinkConstraint;
29113
29114 use Composer\Semver\Constraint\ConstraintInterface;
29115
29116 trigger_error('The ' . __NAMESPACE__ . '\LinkConstraintInterface interface is deprecated, use Composer\Semver\Constraint\ConstraintInterface instead.', E_USER_DEPRECATED);
29117
29118
29119
29120
29121 interface LinkConstraintInterface extends ConstraintInterface
29122 {
29123 }
29124 <?php
29125
29126
29127
29128
29129
29130
29131
29132
29133
29134
29135
29136 namespace Composer\Package\LinkConstraint;
29137
29138 use Composer\Semver\Constraint\MultiConstraint as SemverMultiConstraint;
29139
29140 trigger_error('The ' . __NAMESPACE__ . '\MultiConstraint class is deprecated, use Composer\Semver\Constraint\MultiConstraint instead.', E_USER_DEPRECATED);
29141
29142
29143
29144
29145 class MultiConstraint extends SemverMultiConstraint implements LinkConstraintInterface
29146 {
29147 }
29148 <?php
29149
29150
29151
29152
29153
29154
29155
29156
29157
29158
29159
29160 namespace Composer\Package\LinkConstraint;
29161
29162 use Composer\Semver\Constraint\AbstractConstraint;
29163
29164 trigger_error('The ' . __NAMESPACE__ . '\SpecificConstraint abstract class is deprecated, there is no replacement for it.', E_USER_DEPRECATED);
29165
29166
29167
29168
29169 abstract class SpecificConstraint extends AbstractConstraint implements LinkConstraintInterface
29170 {
29171 }
29172 <?php
29173
29174
29175
29176
29177
29178
29179
29180
29181
29182
29183
29184 namespace Composer\Package\LinkConstraint;
29185
29186 use Composer\Semver\Constraint\Constraint;
29187
29188 trigger_error('The ' . __NAMESPACE__ . '\VersionConstraint class is deprecated, use Composer\Semver\Constraint\Constraint instead.', E_USER_DEPRECATED);
29189
29190
29191
29192
29193 class VersionConstraint extends Constraint implements LinkConstraintInterface
29194 {
29195 }
29196 <?php
29197
29198
29199
29200
29201
29202
29203
29204
29205
29206
29207
29208 namespace Composer\Package\Loader;
29209
29210 use Composer\Package;
29211 use Composer\Package\AliasPackage;
29212 use Composer\Package\Link;
29213 use Composer\Package\RootAliasPackage;
29214 use Composer\Package\RootPackageInterface;
29215 use Composer\Package\Version\VersionParser;
29216 use Composer\Semver\VersionParser as SemverVersionParser;
29217
29218
29219
29220
29221
29222 class ArrayLoader implements LoaderInterface
29223 {
29224 protected $versionParser;
29225 protected $loadOptions;
29226
29227 public function __construct(SemverVersionParser $parser = null, $loadOptions = false)
29228 {
29229 if (!$parser) {
29230 $parser = new VersionParser;
29231 }
29232 $this->versionParser = $parser;
29233 $this->loadOptions = $loadOptions;
29234 }
29235
29236 public function load(array $config, $class = 'Composer\Package\CompletePackage')
29237 {
29238 if (!isset($config['name'])) {
29239 throw new \UnexpectedValueException('Unknown package has no name defined ('.json_encode($config).').');
29240 }
29241 if (!isset($config['version'])) {
29242 throw new \UnexpectedValueException('Package '.$config['name'].' has no version defined.');
29243 }
29244
29245
29246 if (isset($config['version_normalized'])) {
29247 $version = $config['version_normalized'];
29248 } else {
29249 $version = $this->versionParser->normalize($config['version']);
29250 }
29251 $package = new $class($config['name'], $version, $config['version']);
29252 $package->setType(isset($config['type']) ? strtolower($config['type']) : 'library');
29253
29254 if (isset($config['target-dir'])) {
29255 $package->setTargetDir($config['target-dir']);
29256 }
29257
29258 if (isset($config['extra']) && is_array($config['extra'])) {
29259 $package->setExtra($config['extra']);
29260 }
29261
29262 if (isset($config['bin'])) {
29263 if (!\is_array($config['bin'])) {
29264 $config['bin'] = array($config['bin']);
29265 }
29266 foreach ($config['bin'] as $key => $bin) {
29267 $config['bin'][$key] = ltrim($bin, '/');
29268 }
29269 $package->setBinaries($config['bin']);
29270 }
29271
29272 if (isset($config['installation-source'])) {
29273 $package->setInstallationSource($config['installation-source']);
29274 }
29275
29276 if (isset($config['source'])) {
29277 if (!isset($config['source']['type']) || !isset($config['source']['url']) || !isset($config['source']['reference'])) {
29278 throw new \UnexpectedValueException(sprintf(
29279 "Package %s's source key should be specified as {\"type\": ..., \"url\": ..., \"reference\": ...},\n%s given.",
29280 $config['name'],
29281 json_encode($config['source'])
29282 ));
29283 }
29284 $package->setSourceType($config['source']['type']);
29285 $package->setSourceUrl($config['source']['url']);
29286 $package->setSourceReference(isset($config['source']['reference']) ? $config['source']['reference'] : null);
29287 if (isset($config['source']['mirrors'])) {
29288 $package->setSourceMirrors($config['source']['mirrors']);
29289 }
29290 }
29291
29292 if (isset($config['dist'])) {
29293 if (!isset($config['dist']['type'])
29294 || !isset($config['dist']['url'])) {
29295 throw new \UnexpectedValueException(sprintf(
29296 "Package %s's dist key should be specified as ".
29297 "{\"type\": ..., \"url\": ..., \"reference\": ..., \"shasum\": ...},\n%s given.",
29298 $config['name'],
29299 json_encode($config['dist'])
29300 ));
29301 }
29302 $package->setDistType($config['dist']['type']);
29303 $package->setDistUrl($config['dist']['url']);
29304 $package->setDistReference(isset($config['dist']['reference']) ? $config['dist']['reference'] : null);
29305 $package->setDistSha1Checksum(isset($config['dist']['shasum']) ? $config['dist']['shasum'] : null);
29306 if (isset($config['dist']['mirrors'])) {
29307 $package->setDistMirrors($config['dist']['mirrors']);
29308 }
29309 }
29310
29311 foreach (Package\BasePackage::$supportedLinkTypes as $type => $opts) {
29312 if (isset($config[$type])) {
29313 $method = 'set'.ucfirst($opts['method']);
29314 $package->{$method}(
29315 $this->parseLinks(
29316 $package->getName(),
29317 $package->getPrettyVersion(),
29318 $opts['description'],
29319 $config[$type]
29320 )
29321 );
29322 }
29323 }
29324
29325 if (isset($config['suggest']) && is_array($config['suggest'])) {
29326 foreach ($config['suggest'] as $target => $reason) {
29327 if ('self.version' === trim($reason)) {
29328 $config['suggest'][$target] = $package->getPrettyVersion();
29329 }
29330 }
29331 $package->setSuggests($config['suggest']);
29332 }
29333
29334 if (isset($config['autoload'])) {
29335 $package->setAutoload($config['autoload']);
29336 }
29337
29338 if (isset($config['autoload-dev'])) {
29339 $package->setDevAutoload($config['autoload-dev']);
29340 }
29341
29342 if (isset($config['include-path'])) {
29343 $package->setIncludePaths($config['include-path']);
29344 }
29345
29346 if (!empty($config['time'])) {
29347 $time = preg_match('/^\d++$/D', $config['time']) ? '@'.$config['time'] : $config['time'];
29348
29349 try {
29350 $date = new \DateTime($time, new \DateTimeZone('UTC'));
29351 $package->setReleaseDate($date);
29352 } catch (\Exception $e) {
29353 }
29354 }
29355
29356 if (!empty($config['notification-url'])) {
29357 $package->setNotificationUrl($config['notification-url']);
29358 }
29359
29360 if (!empty($config['archive']['exclude'])) {
29361 $package->setArchiveExcludes($config['archive']['exclude']);
29362 }
29363
29364 if ($package instanceof Package\CompletePackageInterface) {
29365 if (isset($config['scripts']) && is_array($config['scripts'])) {
29366 foreach ($config['scripts'] as $event => $listeners) {
29367 $config['scripts'][$event] = (array) $listeners;
29368 }
29369 if (isset($config['scripts']['composer'])) {
29370 trigger_error('The `composer` script name is reserved for internal use, please avoid defining it', E_USER_DEPRECATED);
29371 }
29372 $package->setScripts($config['scripts']);
29373 }
29374
29375 if (!empty($config['description']) && is_string($config['description'])) {
29376 $package->setDescription($config['description']);
29377 }
29378
29379 if (!empty($config['homepage']) && is_string($config['homepage'])) {
29380 $package->setHomepage($config['homepage']);
29381 }
29382
29383 if (!empty($config['keywords']) && is_array($config['keywords'])) {
29384 $package->setKeywords($config['keywords']);
29385 }
29386
29387 if (!empty($config['license'])) {
29388 $package->setLicense(is_array($config['license']) ? $config['license'] : array($config['license']));
29389 }
29390
29391 if (!empty($config['authors']) && is_array($config['authors'])) {
29392 $package->setAuthors($config['authors']);
29393 }
29394
29395 if (isset($config['support'])) {
29396 $package->setSupport($config['support']);
29397 }
29398
29399 if (!empty($config['funding']) && is_array($config['funding'])) {
29400 $package->setFunding($config['funding']);
29401 }
29402
29403 if (isset($config['abandoned'])) {
29404 $package->setAbandoned($config['abandoned']);
29405 }
29406 }
29407
29408 if ($aliasNormalized = $this->getBranchAlias($config)) {
29409 if ($package instanceof RootPackageInterface) {
29410 $package = new RootAliasPackage($package, $aliasNormalized, preg_replace('{(\.9{7})+}', '.x', $aliasNormalized));
29411 } else {
29412 $package = new AliasPackage($package, $aliasNormalized, preg_replace('{(\.9{7})+}', '.x', $aliasNormalized));
29413 }
29414 }
29415
29416 if ($this->loadOptions && isset($config['transport-options'])) {
29417 $package->setTransportOptions($config['transport-options']);
29418 }
29419
29420 return $package;
29421 }
29422
29423
29424
29425
29426
29427
29428
29429
29430 public function parseLinks($source, $sourceVersion, $description, $links)
29431 {
29432 $res = array();
29433 foreach ($links as $target => $constraint) {
29434 if (!is_string($constraint)) {
29435 throw new \UnexpectedValueException('Link constraint in '.$source.' '.$description.' > '.$target.' should be a string, got '.gettype($constraint) . ' (' . var_export($constraint, true) . ')');
29436 }
29437 if ('self.version' === $constraint) {
29438 $parsedConstraint = $this->versionParser->parseConstraints($sourceVersion);
29439 } else {
29440 $parsedConstraint = $this->versionParser->parseConstraints($constraint);
29441 }
29442
29443 $res[strtolower($target)] = new Link($source, $target, $parsedConstraint, $description, $constraint);
29444 }
29445
29446 return $res;
29447 }
29448
29449
29450
29451
29452
29453
29454
29455 public function getBranchAlias(array $config)
29456 {
29457 if (('dev-' !== substr($config['version'], 0, 4) && '-dev' !== substr($config['version'], -4))
29458 || !isset($config['extra']['branch-alias'])
29459 || !is_array($config['extra']['branch-alias'])
29460 ) {
29461 return;
29462 }
29463
29464 foreach ($config['extra']['branch-alias'] as $sourceBranch => $targetBranch) {
29465
29466 if ('-dev' !== substr($targetBranch, -4)) {
29467 continue;
29468 }
29469
29470
29471 $validatedTargetBranch = $this->versionParser->normalizeBranch(substr($targetBranch, 0, -4));
29472 if ('-dev' !== substr($validatedTargetBranch, -4)) {
29473 continue;
29474 }
29475
29476
29477 if (strtolower($config['version']) !== strtolower($sourceBranch)) {
29478 continue;
29479 }
29480
29481
29482 if (($sourcePrefix = $this->versionParser->parseNumericAliasPrefix($sourceBranch))
29483 && ($targetPrefix = $this->versionParser->parseNumericAliasPrefix($targetBranch))
29484 && (stripos($targetPrefix, $sourcePrefix) !== 0)
29485 ) {
29486 continue;
29487 }
29488
29489 return $validatedTargetBranch;
29490 }
29491 }
29492 }
29493 <?php
29494
29495
29496
29497
29498
29499
29500
29501
29502
29503
29504
29505 namespace Composer\Package\Loader;
29506
29507
29508
29509
29510 class InvalidPackageException extends \Exception
29511 {
29512 private $errors;
29513 private $warnings;
29514 private $data;
29515
29516 public function __construct(array $errors, array $warnings, array $data)
29517 {
29518 $this->errors = $errors;
29519 $this->warnings = $warnings;
29520 $this->data = $data;
29521 parent::__construct("Invalid package information: \n".implode("\n", array_merge($errors, $warnings)));
29522 }
29523
29524 public function getData()
29525 {
29526 return $this->data;
29527 }
29528
29529 public function getErrors()
29530 {
29531 return $this->errors;
29532 }
29533
29534 public function getWarnings()
29535 {
29536 return $this->warnings;
29537 }
29538 }
29539 <?php
29540
29541
29542
29543
29544
29545
29546
29547
29548
29549
29550
29551 namespace Composer\Package\Loader;
29552
29553 use Composer\Json\JsonFile;
29554
29555
29556
29557
29558 class JsonLoader
29559 {
29560 private $loader;
29561
29562 public function __construct(LoaderInterface $loader)
29563 {
29564 $this->loader = $loader;
29565 }
29566
29567
29568
29569
29570
29571 public function load($json)
29572 {
29573 if ($json instanceof JsonFile) {
29574 $config = $json->read();
29575 } elseif (file_exists($json)) {
29576 $config = JsonFile::parseJson(file_get_contents($json), $json);
29577 } elseif (is_string($json)) {
29578 $config = JsonFile::parseJson($json);
29579 }
29580
29581 return $this->loader->load($config);
29582 }
29583 }
29584 <?php
29585
29586
29587
29588
29589
29590
29591
29592
29593
29594
29595
29596 namespace Composer\Package\Loader;
29597
29598
29599
29600
29601
29602
29603 interface LoaderInterface
29604 {
29605
29606
29607
29608
29609
29610
29611
29612 public function load(array $package, $class = 'Composer\Package\CompletePackage');
29613 }
29614 <?php
29615
29616
29617
29618
29619
29620
29621
29622
29623
29624
29625
29626 namespace Composer\Package\Loader;
29627
29628 use Composer\Package\BasePackage;
29629 use Composer\Package\AliasPackage;
29630 use Composer\Config;
29631 use Composer\IO\IOInterface;
29632 use Composer\Package\RootPackageInterface;
29633 use Composer\Repository\RepositoryFactory;
29634 use Composer\Package\Version\VersionGuesser;
29635 use Composer\Package\Version\VersionParser;
29636 use Composer\Repository\RepositoryManager;
29637 use Composer\Util\ProcessExecutor;
29638
29639
29640
29641
29642
29643
29644
29645
29646 class RootPackageLoader extends ArrayLoader
29647 {
29648
29649
29650
29651 private $manager;
29652
29653
29654
29655
29656 private $config;
29657
29658
29659
29660
29661 private $versionGuesser;
29662
29663
29664
29665
29666 private $io;
29667
29668 public function __construct(RepositoryManager $manager, Config $config, VersionParser $parser = null, VersionGuesser $versionGuesser = null, IOInterface $io = null)
29669 {
29670 parent::__construct($parser);
29671
29672 $this->manager = $manager;
29673 $this->config = $config;
29674 $this->versionGuesser = $versionGuesser ?: new VersionGuesser($config, new ProcessExecutor(), $this->versionParser);
29675 $this->io = $io;
29676 }
29677
29678
29679
29680
29681
29682
29683
29684 public function load(array $config, $class = 'Composer\Package\RootPackage', $cwd = null)
29685 {
29686 if (!isset($config['name'])) {
29687 $config['name'] = '__root__';
29688 } elseif ($this->io) {
29689 if ($err = ValidatingArrayLoader::hasPackageNamingError($config['name'])) {
29690 $this->io->writeError('<warning>Deprecation warning: Your package name '.$err.' Make sure you fix this as Composer 2.0 will error.</warning>');
29691 }
29692 }
29693 $autoVersioned = false;
29694 if (!isset($config['version'])) {
29695 $commit = null;
29696
29697
29698 if (getenv('COMPOSER_ROOT_VERSION')) {
29699 $config['version'] = getenv('COMPOSER_ROOT_VERSION');
29700 } else {
29701 $versionData = $this->versionGuesser->guessVersion($config, $cwd ?: getcwd());
29702 if ($versionData) {
29703 $config['version'] = $versionData['pretty_version'];
29704 $config['version_normalized'] = $versionData['version'];
29705 $commit = $versionData['commit'];
29706 }
29707 }
29708
29709 if (!isset($config['version'])) {
29710 $config['version'] = '1.0.0';
29711 $autoVersioned = true;
29712 }
29713
29714 if ($commit) {
29715 $config['source'] = array(
29716 'type' => '',
29717 'url' => '',
29718 'reference' => $commit,
29719 );
29720 $config['dist'] = array(
29721 'type' => '',
29722 'url' => '',
29723 'reference' => $commit,
29724 );
29725 }
29726 }
29727
29728 $realPackage = $package = parent::load($config, $class);
29729 if ($realPackage instanceof AliasPackage) {
29730 $realPackage = $package->getAliasOf();
29731 }
29732
29733 if ($autoVersioned) {
29734 $realPackage->replaceVersion($realPackage->getVersion(), 'No version set (parsed as 1.0.0)');
29735 }
29736
29737 if (isset($config['minimum-stability'])) {
29738 $realPackage->setMinimumStability(VersionParser::normalizeStability($config['minimum-stability']));
29739 }
29740
29741 $aliases = array();
29742 $stabilityFlags = array();
29743 $references = array();
29744 foreach (array('require', 'require-dev') as $linkType) {
29745 if (isset($config[$linkType])) {
29746 $linkInfo = BasePackage::$supportedLinkTypes[$linkType];
29747 $method = 'get'.ucfirst($linkInfo['method']);
29748 $links = array();
29749 foreach ($realPackage->$method() as $link) {
29750 $links[$link->getTarget()] = $link->getConstraint()->getPrettyString();
29751 }
29752 $aliases = $this->extractAliases($links, $aliases);
29753 $stabilityFlags = $this->extractStabilityFlags($links, $stabilityFlags, $realPackage->getMinimumStability());
29754 $references = $this->extractReferences($links, $references);
29755
29756 if (isset($links[$config['name']])) {
29757 throw new \RuntimeException(sprintf('Root package \'%s\' cannot require itself in its composer.json' . PHP_EOL .
29758 'Did you accidentally name your root package after an external package?', $config['name']));
29759 }
29760 }
29761 }
29762
29763 if ($this->io) {
29764 foreach (array_keys(BasePackage::$supportedLinkTypes) as $linkType) {
29765 if (isset($config[$linkType])) {
29766 foreach ($config[$linkType] as $linkName => $constraint) {
29767 if ($err = ValidatingArrayLoader::hasPackageNamingError($linkName, true)) {
29768 $this->io->writeError('<warning>Deprecation warning: '.$linkType.'.'.$err.' Make sure you fix this as Composer 2.0 will error.</warning>');
29769 }
29770 }
29771 }
29772 }
29773 }
29774
29775 $realPackage->setAliases($aliases);
29776 $realPackage->setStabilityFlags($stabilityFlags);
29777 $realPackage->setReferences($references);
29778
29779 if (isset($config['prefer-stable'])) {
29780 $realPackage->setPreferStable((bool) $config['prefer-stable']);
29781 }
29782
29783 if (isset($config['config'])) {
29784 $realPackage->setConfig($config['config']);
29785 }
29786
29787 $repos = RepositoryFactory::defaultRepos(null, $this->config, $this->manager);
29788 foreach ($repos as $repo) {
29789 $this->manager->addRepository($repo);
29790 }
29791 $realPackage->setRepositories($this->config->getRepositories());
29792
29793 return $package;
29794 }
29795
29796 private function extractAliases(array $requires, array $aliases)
29797 {
29798 foreach ($requires as $reqName => $reqVersion) {
29799 if (preg_match('{^([^,\s#]+)(?:#[^ ]+)? +as +([^,\s]+)$}', $reqVersion, $match)) {
29800 $aliases[] = array(
29801 'package' => strtolower($reqName),
29802 'version' => $this->versionParser->normalize($match[1], $reqVersion),
29803 'alias' => $match[2],
29804 'alias_normalized' => $this->versionParser->normalize($match[2], $reqVersion),
29805 );
29806 } elseif (strpos($reqVersion, ' as ') !== false) {
29807 throw new \UnexpectedValueException('Invalid alias definition in "'.$reqName.'": "'.$reqVersion.'". Aliases should be in the form "exact-version as other-exact-version".');
29808 }
29809 }
29810
29811 return $aliases;
29812 }
29813
29814 private function extractStabilityFlags(array $requires, array $stabilityFlags, $minimumStability)
29815 {
29816 $stabilities = BasePackage::$stabilities;
29817 $minimumStability = $stabilities[$minimumStability];
29818 foreach ($requires as $reqName => $reqVersion) {
29819 $constraints = array();
29820
29821
29822 $orSplit = preg_split('{\s*\|\|?\s*}', trim($reqVersion));
29823 foreach ($orSplit as $orConstraint) {
29824 $andSplit = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $orConstraint);
29825 foreach ($andSplit as $andConstraint) {
29826 $constraints[] = $andConstraint;
29827 }
29828 }
29829
29830
29831 $match = false;
29832 foreach ($constraints as $constraint) {
29833 if (preg_match('{^[^@]*?@('.implode('|', array_keys($stabilities)).')$}i', $constraint, $match)) {
29834 $name = strtolower($reqName);
29835 $stability = $stabilities[VersionParser::normalizeStability($match[1])];
29836
29837 if (isset($stabilityFlags[$name]) && $stabilityFlags[$name] > $stability) {
29838 continue;
29839 }
29840 $stabilityFlags[$name] = $stability;
29841 $match = true;
29842 }
29843 }
29844
29845 if ($match) {
29846 continue;
29847 }
29848
29849 foreach ($constraints as $constraint) {
29850
29851
29852 $reqVersion = preg_replace('{^([^,\s@]+) as .+$}', '$1', $constraint);
29853 if (preg_match('{^[^,\s@]+$}', $reqVersion) && 'stable' !== ($stabilityName = VersionParser::parseStability($reqVersion))) {
29854 $name = strtolower($reqName);
29855 $stability = $stabilities[$stabilityName];
29856 if ((isset($stabilityFlags[$name]) && $stabilityFlags[$name] > $stability) || ($minimumStability > $stability)) {
29857 continue;
29858 }
29859 $stabilityFlags[$name] = $stability;
29860 }
29861 }
29862 }
29863
29864 return $stabilityFlags;
29865 }
29866
29867 private function extractReferences(array $requires, array $references)
29868 {
29869 foreach ($requires as $reqName => $reqVersion) {
29870 $reqVersion = preg_replace('{^([^,\s@]+) as .+$}', '$1', $reqVersion);
29871 if (preg_match('{^[^,\s@]+?#([a-f0-9]+)$}', $reqVersion, $match) && 'dev' === VersionParser::parseStability($reqVersion)) {
29872 $name = strtolower($reqName);
29873 $references[$name] = $match[1];
29874 }
29875 }
29876
29877 return $references;
29878 }
29879 }
29880 <?php
29881
29882
29883
29884
29885
29886
29887
29888
29889
29890
29891
29892 namespace Composer\Package\Loader;
29893
29894 use Composer\Package\BasePackage;
29895 use Composer\Semver\Constraint\Constraint;
29896 use Composer\Package\Version\VersionParser;
29897 use Composer\Repository\PlatformRepository;
29898 use Composer\Spdx\SpdxLicenses;
29899
29900
29901
29902
29903 class ValidatingArrayLoader implements LoaderInterface
29904 {
29905 const CHECK_ALL = 3;
29906 const CHECK_UNBOUND_CONSTRAINTS = 1;
29907 const CHECK_STRICT_CONSTRAINTS = 2;
29908
29909 private $loader;
29910 private $versionParser;
29911 private $errors;
29912 private $warnings;
29913 private $config;
29914 private $strictName;
29915 private $flags;
29916
29917 public function __construct(LoaderInterface $loader, $strictName = true, VersionParser $parser = null, $flags = 0)
29918 {
29919 $this->loader = $loader;
29920 $this->versionParser = $parser ?: new VersionParser();
29921 $this->strictName = $strictName;
29922 $this->flags = $flags;
29923 }
29924
29925 public function load(array $config, $class = 'Composer\Package\CompletePackage')
29926 {
29927 $this->errors = array();
29928 $this->warnings = array();
29929 $this->config = $config;
29930
29931 if ($err = self::hasPackageNamingError($config['name'])) {
29932 $this->warnings[] = 'Deprecation warning: Your package name '.$err.' Make sure you fix this as Composer 2.0 will error.';
29933 }
29934
29935 if ($this->strictName) {
29936 $this->validateRegex('name', '[A-Za-z0-9][A-Za-z0-9_.-]*/[A-Za-z0-9][A-Za-z0-9_.-]*', true);
29937 } else {
29938 $this->validateString('name', true);
29939 }
29940
29941 if (!empty($this->config['version'])) {
29942 try {
29943 $this->versionParser->normalize($this->config['version']);
29944 } catch (\Exception $e) {
29945 $this->errors[] = 'version : invalid value ('.$this->config['version'].'): '.$e->getMessage();
29946 unset($this->config['version']);
29947 }
29948 }
29949
29950 if (!empty($this->config['config']['platform'])) {
29951 foreach ((array) $this->config['config']['platform'] as $key => $platform) {
29952 try {
29953 $this->versionParser->normalize($platform);
29954 } catch (\Exception $e) {
29955 $this->errors[] = 'config.platform.' . $key . ' : invalid value ('.$platform.'): '.$e->getMessage();
29956 }
29957 }
29958 }
29959
29960 $this->validateRegex('type', '[A-Za-z0-9-]+');
29961 $this->validateString('target-dir');
29962 $this->validateArray('extra');
29963
29964 if (isset($this->config['bin'])) {
29965 if (is_string($this->config['bin'])) {
29966 $this->validateString('bin');
29967 } else {
29968 $this->validateFlatArray('bin');
29969 }
29970 }
29971
29972 $this->validateArray('scripts'); 
29973 $this->validateString('description');
29974 $this->validateUrl('homepage');
29975 $this->validateFlatArray('keywords', '[\p{N}\p{L} ._-]+');
29976
29977 $releaseDate = null;
29978 $this->validateString('time');
29979 if (!empty($this->config['time'])) {
29980 try {
29981 $releaseDate = new \DateTime($this->config['time'], new \DateTimeZone('UTC'));
29982 } catch (\Exception $e) {
29983 $this->errors[] = 'time : invalid value ('.$this->config['time'].'): '.$e->getMessage();
29984 unset($this->config['time']);
29985 }
29986 }
29987
29988
29989 if (isset($this->config['license']) && (!$releaseDate || $releaseDate->getTimestamp() >= strtotime('-8days'))) {
29990 if (is_array($this->config['license']) || is_string($this->config['license'])) {
29991 $licenses = (array) $this->config['license'];
29992
29993 $licenseValidator = new SpdxLicenses();
29994 foreach ($licenses as $license) {
29995
29996 if ('proprietary' === $license) {
29997 continue;
29998 }
29999 $licenseToValidate = str_replace('proprietary', 'MIT', $license);
30000 if (!$licenseValidator->validate($licenseToValidate)) {
30001 if ($licenseValidator->validate(trim($licenseToValidate))) {
30002 $this->warnings[] = sprintf(
30003 'License %s must not contain extra spaces, make sure to trim it.',
30004 json_encode($license)
30005 );
30006 } else {
30007 $this->warnings[] = sprintf(
30008 'License %s is not a valid SPDX license identifier, see https://spdx.org/licenses/ if you use an open license.' . PHP_EOL .
30009 'If the software is closed-source, you may use "proprietary" as license.',
30010 json_encode($license)
30011 );
30012 }
30013 }
30014 }
30015 }
30016 }
30017
30018 if ($this->validateArray('authors') && !empty($this->config['authors'])) {
30019 foreach ($this->config['authors'] as $key => $author) {
30020 if (!is_array($author)) {
30021 $this->errors[] = 'authors.'.$key.' : should be an array, '.gettype($author).' given';
30022 unset($this->config['authors'][$key]);
30023 continue;
30024 }
30025 foreach (array('homepage', 'email', 'name', 'role') as $authorData) {
30026 if (isset($author[$authorData]) && !is_string($author[$authorData])) {
30027 $this->errors[] = 'authors.'.$key.'.'.$authorData.' : invalid value, must be a string';
30028 unset($this->config['authors'][$key][$authorData]);
30029 }
30030 }
30031 if (isset($author['homepage']) && !$this->filterUrl($author['homepage'])) {
30032 $this->warnings[] = 'authors.'.$key.'.homepage : invalid value ('.$author['homepage'].'), must be an http/https URL';
30033 unset($this->config['authors'][$key]['homepage']);
30034 }
30035 if (isset($author['email']) && !filter_var($author['email'], FILTER_VALIDATE_EMAIL)) {
30036 $this->warnings[] = 'authors.'.$key.'.email : invalid value ('.$author['email'].'), must be a valid email address';
30037 unset($this->config['authors'][$key]['email']);
30038 }
30039 if (empty($this->config['authors'][$key])) {
30040 unset($this->config['authors'][$key]);
30041 }
30042 }
30043 if (empty($this->config['authors'])) {
30044 unset($this->config['authors']);
30045 }
30046 }
30047
30048 if ($this->validateArray('support') && !empty($this->config['support'])) {
30049 foreach (array('issues', 'forum', 'wiki', 'source', 'email', 'irc', 'docs', 'rss', 'chat') as $key) {
30050 if (isset($this->config['support'][$key]) && !is_string($this->config['support'][$key])) {
30051 $this->errors[] = 'support.'.$key.' : invalid value, must be a string';
30052 unset($this->config['support'][$key]);
30053 }
30054 }
30055
30056 if (isset($this->config['support']['email']) && !filter_var($this->config['support']['email'], FILTER_VALIDATE_EMAIL)) {
30057 $this->warnings[] = 'support.email : invalid value ('.$this->config['support']['email'].'), must be a valid email address';
30058 unset($this->config['support']['email']);
30059 }
30060
30061 if (isset($this->config['support']['irc']) && !$this->filterUrl($this->config['support']['irc'], array('irc'))) {
30062 $this->warnings[] = 'support.irc : invalid value ('.$this->config['support']['irc'].'), must be a irc://<server>/<channel> URL';
30063 unset($this->config['support']['irc']);
30064 }
30065
30066 foreach (array('issues', 'forum', 'wiki', 'source', 'docs', 'chat') as $key) {
30067 if (isset($this->config['support'][$key]) && !$this->filterUrl($this->config['support'][$key])) {
30068 $this->warnings[] = 'support.'.$key.' : invalid value ('.$this->config['support'][$key].'), must be an http/https URL';
30069 unset($this->config['support'][$key]);
30070 }
30071 }
30072 if (empty($this->config['support'])) {
30073 unset($this->config['support']);
30074 }
30075 }
30076
30077 if ($this->validateArray('funding') && !empty($this->config['funding'])) {
30078 foreach ($this->config['funding'] as $key => $fundingOption) {
30079 if (!is_array($fundingOption)) {
30080 $this->errors[] = 'funding.'.$key.' : should be an array, '.gettype($fundingOption).' given';
30081 unset($this->config['funding'][$key]);
30082 continue;
30083 }
30084 foreach (array('type', 'url') as $fundingData) {
30085 if (isset($fundingOption[$fundingData]) && !is_string($fundingOption[$fundingData])) {
30086 $this->errors[] = 'funding.'.$key.'.'.$fundingData.' : invalid value, must be a string';
30087 unset($this->config['funding'][$key][$fundingData]);
30088 }
30089 }
30090 if (isset($fundingOption['url']) && !$this->filterUrl($fundingOption['url'])) {
30091 $this->warnings[] = 'funding.'.$key.'.url : invalid value ('.$fundingOption['url'].'), must be an http/https URL';
30092 unset($this->config['funding'][$key]['url']);
30093 }
30094 if (empty($this->config['funding'][$key])) {
30095 unset($this->config['funding'][$key]);
30096 }
30097 }
30098 if (empty($this->config['funding'])) {
30099 unset($this->config['funding']);
30100 }
30101 }
30102
30103 $unboundConstraint = new Constraint('=', $this->versionParser->normalize('dev-master'));
30104 $stableConstraint = new Constraint('=', '1.0.0');
30105
30106 foreach (array_keys(BasePackage::$supportedLinkTypes) as $linkType) {
30107 if ($this->validateArray($linkType) && isset($this->config[$linkType])) {
30108 foreach ($this->config[$linkType] as $package => $constraint) {
30109 if ($err = self::hasPackageNamingError($package, true)) {
30110 $this->warnings[] = 'Deprecation warning: '.$linkType.'.'.$err.' Make sure you fix this as Composer 2.0 will error.';
30111 } elseif (!preg_match('{^[A-Za-z0-9_./-]+$}', $package)) {
30112 $this->warnings[] = $linkType.'.'.$package.' : invalid key, package names must be strings containing only [A-Za-z0-9_./-]';
30113 }
30114 if (!is_string($constraint)) {
30115 $this->errors[] = $linkType.'.'.$package.' : invalid value, must be a string containing a version constraint';
30116 unset($this->config[$linkType][$package]);
30117 } elseif ('self.version' !== $constraint) {
30118 try {
30119 $linkConstraint = $this->versionParser->parseConstraints($constraint);
30120 } catch (\Exception $e) {
30121 $this->errors[] = $linkType.'.'.$package.' : invalid version constraint ('.$e->getMessage().')';
30122 unset($this->config[$linkType][$package]);
30123 continue;
30124 }
30125
30126
30127 if (
30128 ($this->flags & self::CHECK_UNBOUND_CONSTRAINTS)
30129 && 'require' === $linkType
30130 && $linkConstraint->matches($unboundConstraint)
30131 && !preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $package)
30132 ) {
30133 $this->warnings[] = $linkType.'.'.$package.' : unbound version constraints ('.$constraint.') should be avoided';
30134 } elseif (
30135
30136 ($this->flags & self::CHECK_STRICT_CONSTRAINTS)
30137 && 'require' === $linkType
30138 && substr($linkConstraint, 0, 1) === '='
30139 && $stableConstraint->versionCompare($stableConstraint, $linkConstraint, '<=')
30140 ) {
30141 $this->warnings[] = $linkType.'.'.$package.' : exact version constraints ('.$constraint.') should be avoided if the package follows semantic versioning';
30142 }
30143 }
30144 }
30145 }
30146 }
30147
30148 if ($this->validateArray('suggest') && !empty($this->config['suggest'])) {
30149 foreach ($this->config['suggest'] as $package => $description) {
30150 if (!is_string($description)) {
30151 $this->errors[] = 'suggest.'.$package.' : invalid value, must be a string describing why the package is suggested';
30152 unset($this->config['suggest'][$package]);
30153 }
30154 }
30155 }
30156
30157 if ($this->validateString('minimum-stability') && !empty($this->config['minimum-stability'])) {
30158 if (!isset(BasePackage::$stabilities[$this->config['minimum-stability']])) {
30159 $this->errors[] = 'minimum-stability : invalid value ('.$this->config['minimum-stability'].'), must be one of '.implode(', ', array_keys(BasePackage::$stabilities));
30160 unset($this->config['minimum-stability']);
30161 }
30162 }
30163
30164 if ($this->validateArray('autoload') && !empty($this->config['autoload'])) {
30165 $types = array('psr-0', 'psr-4', 'classmap', 'files', 'exclude-from-classmap');
30166 foreach ($this->config['autoload'] as $type => $typeConfig) {
30167 if (!in_array($type, $types)) {
30168 $this->errors[] = 'autoload : invalid value ('.$type.'), must be one of '.implode(', ', $types);
30169 unset($this->config['autoload'][$type]);
30170 }
30171 if ($type === 'psr-4') {
30172 foreach ($typeConfig as $namespace => $dirs) {
30173 if ($namespace !== '' && '\\' !== substr($namespace, -1)) {
30174 $this->errors[] = 'autoload.psr-4 : invalid value ('.$namespace.'), namespaces must end with a namespace separator, should be '.$namespace.'\\\\';
30175 }
30176 }
30177 }
30178 }
30179 }
30180
30181 if (!empty($this->config['autoload']['psr-4']) && !empty($this->config['target-dir'])) {
30182 $this->errors[] = 'target-dir : this can not be used together with the autoload.psr-4 setting, remove target-dir to upgrade to psr-4';
30183
30184
30185 unset($this->config['autoload']['psr-4']);
30186 }
30187
30188
30189
30190
30191
30192
30193
30194 $this->validateFlatArray('include-path');
30195 $this->validateArray('transport-options');
30196
30197
30198 if (isset($this->config['extra']['branch-alias'])) {
30199 if (!is_array($this->config['extra']['branch-alias'])) {
30200 $this->errors[] = 'extra.branch-alias : must be an array of versions => aliases';
30201 } else {
30202 foreach ($this->config['extra']['branch-alias'] as $sourceBranch => $targetBranch) {
30203
30204 if ('-dev' !== substr($targetBranch, -4)) {
30205 $this->warnings[] = 'extra.branch-alias.'.$sourceBranch.' : the target branch ('.$targetBranch.') must end in -dev';
30206 unset($this->config['extra']['branch-alias'][$sourceBranch]);
30207
30208 continue;
30209 }
30210
30211
30212 $validatedTargetBranch = $this->versionParser->normalizeBranch(substr($targetBranch, 0, -4));
30213 if ('-dev' !== substr($validatedTargetBranch, -4)) {
30214 $this->warnings[] = 'extra.branch-alias.'.$sourceBranch.' : the target branch ('.$targetBranch.') must be a parseable number like 2.0-dev';
30215 unset($this->config['extra']['branch-alias'][$sourceBranch]);
30216
30217 continue;
30218 }
30219
30220
30221 if (($sourcePrefix = $this->versionParser->parseNumericAliasPrefix($sourceBranch))
30222 && ($targetPrefix = $this->versionParser->parseNumericAliasPrefix($targetBranch))
30223 && (stripos($targetPrefix, $sourcePrefix) !== 0)
30224 ) {
30225 $this->warnings[] = 'extra.branch-alias.'.$sourceBranch.' : the target branch ('.$targetBranch.') is not a valid numeric alias for this version';
30226 unset($this->config['extra']['branch-alias'][$sourceBranch]);
30227 }
30228 }
30229 }
30230 }
30231
30232 if ($this->errors) {
30233 throw new InvalidPackageException($this->errors, $this->warnings, $config);
30234 }
30235
30236 $package = $this->loader->load($this->config, $class);
30237 $this->config = null;
30238
30239 return $package;
30240 }
30241
30242 public function getWarnings()
30243 {
30244 return $this->warnings;
30245 }
30246
30247 public function getErrors()
30248 {
30249 return $this->errors;
30250 }
30251
30252 public static function hasPackageNamingError($name, $isLink = false)
30253 {
30254 if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name)) {
30255 return;
30256 }
30257
30258 if (!preg_match('{^[a-z0-9](?:[_.-]?[a-z0-9]+)*/[a-z0-9](?:(?:[_.]?|-{0,2})[a-z0-9]+)*$}iD', $name)) {
30259 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]+)*$".';
30260 }
30261
30262 $reservedNames = array('nul', 'con', 'prn', 'aux', 'com1', 'com2', 'com3', 'com4', 'com5', 'com6', 'com7', 'com8', 'com9', 'lpt1', 'lpt2', 'lpt3', 'lpt4', 'lpt5', 'lpt6', 'lpt7', 'lpt8', 'lpt9');
30263 $bits = explode('/', strtolower($name));
30264 if (in_array($bits[0], $reservedNames, true) || in_array($bits[1], $reservedNames, true)) {
30265 return $name.' is reserved, package and vendor names can not match any of: '.implode(', ', $reservedNames).'.';
30266 }
30267
30268 if (preg_match('{\.json$}', $name)) {
30269 return $name.' is invalid, package names can not end in .json, consider renaming it or perhaps using a -json suffix instead.';
30270 }
30271
30272 if (preg_match('{[A-Z]}', $name)) {
30273 if ($isLink) {
30274 return $name.' is invalid, it should not contain uppercase characters. Please use '.strtolower($name).' instead.';
30275 }
30276
30277 $suggestName = preg_replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $name);
30278 $suggestName = strtolower($suggestName);
30279
30280 return $name.' is invalid, it should not contain uppercase characters. We suggest using '.$suggestName.' instead.';
30281 }
30282 }
30283
30284 private function validateRegex($property, $regex, $mandatory = false)
30285 {
30286 if (!$this->validateString($property, $mandatory)) {
30287 return false;
30288 }
30289
30290 if (!preg_match('{^'.$regex.'$}u', $this->config[$property])) {
30291 $message = $property.' : invalid value ('.$this->config[$property].'), must match '.$regex;
30292 if ($mandatory) {
30293 $this->errors[] = $message;
30294 } else {
30295 $this->warnings[] = $message;
30296 }
30297 unset($this->config[$property]);
30298
30299 return false;
30300 }
30301
30302 return true;
30303 }
30304
30305 private function validateString($property, $mandatory = false)
30306 {
30307 if (isset($this->config[$property]) && !is_string($this->config[$property])) {
30308 $this->errors[] = $property.' : should be a string, '.gettype($this->config[$property]).' given';
30309 unset($this->config[$property]);
30310
30311 return false;
30312 }
30313
30314 if (!isset($this->config[$property]) || trim($this->config[$property]) === '') {
30315 if ($mandatory) {
30316 $this->errors[] = $property.' : must be present';
30317 }
30318 unset($this->config[$property]);
30319
30320 return false;
30321 }
30322
30323 return true;
30324 }
30325
30326 private function validateArray($property, $mandatory = false)
30327 {
30328 if (isset($this->config[$property]) && !is_array($this->config[$property])) {
30329 $this->errors[] = $property.' : should be an array, '.gettype($this->config[$property]).' given';
30330 unset($this->config[$property]);
30331
30332 return false;
30333 }
30334
30335 if (!isset($this->config[$property]) || !count($this->config[$property])) {
30336 if ($mandatory) {
30337 $this->errors[] = $property.' : must be present and contain at least one element';
30338 }
30339 unset($this->config[$property]);
30340
30341 return false;
30342 }
30343
30344 return true;
30345 }
30346
30347 private function validateFlatArray($property, $regex = null, $mandatory = false)
30348 {
30349 if (!$this->validateArray($property, $mandatory)) {
30350 return false;
30351 }
30352
30353 $pass = true;
30354 foreach ($this->config[$property] as $key => $value) {
30355 if (!is_string($value) && !is_numeric($value)) {
30356 $this->errors[] = $property.'.'.$key.' : must be a string or int, '.gettype($value).' given';
30357 unset($this->config[$property][$key]);
30358 $pass = false;
30359
30360 continue;
30361 }
30362
30363 if ($regex && !preg_match('{^'.$regex.'$}u', $value)) {
30364 $this->warnings[] = $property.'.'.$key.' : invalid value ('.$value.'), must match '.$regex;
30365 unset($this->config[$property][$key]);
30366 $pass = false;
30367 }
30368 }
30369
30370 return $pass;
30371 }
30372
30373 private function validateUrl($property, $mandatory = false)
30374 {
30375 if (!$this->validateString($property, $mandatory)) {
30376 return false;
30377 }
30378
30379 if (!$this->filterUrl($this->config[$property])) {
30380 $this->warnings[] = $property.' : invalid value ('.$this->config[$property].'), must be an http/https URL';
30381 unset($this->config[$property]);
30382
30383 return false;
30384 }
30385
30386 return true;
30387 }
30388
30389 private function filterUrl($value, array $schemes = array('http', 'https'))
30390 {
30391 if ($value === '') {
30392 return true;
30393 }
30394
30395 $bits = parse_url($value);
30396 if (empty($bits['scheme']) || empty($bits['host'])) {
30397 return false;
30398 }
30399
30400 if (!in_array($bits['scheme'], $schemes, true)) {
30401 return false;
30402 }
30403
30404 return true;
30405 }
30406 }
30407 <?php
30408
30409
30410
30411
30412
30413
30414
30415
30416
30417
30418
30419 namespace Composer\Package;
30420
30421 use Composer\Json\JsonFile;
30422 use Composer\Installer\InstallationManager;
30423 use Composer\Repository\RepositoryManager;
30424 use Composer\Util\ProcessExecutor;
30425 use Composer\Repository\ArrayRepository;
30426 use Composer\Package\Dumper\ArrayDumper;
30427 use Composer\Package\Loader\ArrayLoader;
30428 use Composer\Plugin\PluginInterface;
30429 use Composer\Util\Git as GitUtil;
30430 use Composer\IO\IOInterface;
30431 use Seld\JsonLint\ParsingException;
30432
30433
30434
30435
30436
30437
30438
30439 class Locker
30440 {
30441 private $lockFile;
30442 private $repositoryManager;
30443 private $installationManager;
30444 private $hash;
30445 private $contentHash;
30446 private $loader;
30447 private $dumper;
30448 private $process;
30449 private $lockDataCache;
30450
30451
30452
30453
30454
30455
30456
30457
30458
30459
30460 public function __construct(IOInterface $io, JsonFile $lockFile, RepositoryManager $repositoryManager, InstallationManager $installationManager, $composerFileContents)
30461 {
30462 $this->lockFile = $lockFile;
30463 $this->repositoryManager = $repositoryManager;
30464 $this->installationManager = $installationManager;
30465 $this->hash = md5($composerFileContents);
30466 $this->contentHash = self::getContentHash($composerFileContents);
30467 $this->loader = new ArrayLoader(null, true);
30468 $this->dumper = new ArrayDumper();
30469 $this->process = new ProcessExecutor($io);
30470 }
30471
30472
30473
30474
30475
30476
30477
30478
30479 public static function getContentHash($composerFileContents)
30480 {
30481 $content = json_decode($composerFileContents, true);
30482
30483 $relevantKeys = array(
30484 'name',
30485 'version',
30486 'require',
30487 'require-dev',
30488 'conflict',
30489 'replace',
30490 'provide',
30491 'minimum-stability',
30492 'prefer-stable',
30493 'repositories',
30494 'extra',
30495 );
30496
30497 $relevantContent = array();
30498
30499 foreach (array_intersect($relevantKeys, array_keys($content)) as $key) {
30500 $relevantContent[$key] = $content[$key];
30501 }
30502 if (isset($content['config']['platform'])) {
30503 $relevantContent['config']['platform'] = $content['config']['platform'];
30504 }
30505
30506 ksort($relevantContent);
30507
30508 return md5(json_encode($relevantContent));
30509 }
30510
30511
30512
30513
30514
30515
30516 public function isLocked()
30517 {
30518 if (!$this->lockFile->exists()) {
30519 return false;
30520 }
30521
30522 $data = $this->getLockData();
30523
30524 return isset($data['packages']);
30525 }
30526
30527
30528
30529
30530
30531
30532 public function isFresh()
30533 {
30534 $lock = $this->lockFile->read();
30535
30536 if (!empty($lock['content-hash'])) {
30537
30538 return $this->contentHash === $lock['content-hash'];
30539 }
30540
30541
30542 if (!empty($lock['hash'])) {
30543 return $this->hash === $lock['hash'];
30544 }
30545
30546
30547 return false;
30548 }
30549
30550
30551
30552
30553
30554
30555
30556
30557 public function getLockedRepository($withDevReqs = false)
30558 {
30559 $lockData = $this->getLockData();
30560 $packages = new ArrayRepository();
30561
30562 $lockedPackages = $lockData['packages'];
30563 if ($withDevReqs) {
30564 if (isset($lockData['packages-dev'])) {
30565 $lockedPackages = array_merge($lockedPackages, $lockData['packages-dev']);
30566 } else {
30567 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.');
30568 }
30569 }
30570
30571 if (empty($lockedPackages)) {
30572 return $packages;
30573 }
30574
30575 if (isset($lockedPackages[0]['name'])) {
30576 foreach ($lockedPackages as $info) {
30577 $packages->addPackage($this->loader->load($info));
30578 }
30579
30580 return $packages;
30581 }
30582
30583 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.');
30584 }
30585
30586
30587
30588
30589
30590
30591
30592 public function getPlatformRequirements($withDevReqs = false)
30593 {
30594 $lockData = $this->getLockData();
30595 $requirements = array();
30596
30597 if (!empty($lockData['platform'])) {
30598 $requirements = $this->loader->parseLinks(
30599 '__ROOT__',
30600 '1.0.0',
30601 'requires',
30602 isset($lockData['platform']) ? $lockData['platform'] : array()
30603 );
30604 }
30605
30606 if ($withDevReqs && !empty($lockData['platform-dev'])) {
30607 $devRequirements = $this->loader->parseLinks(
30608 '__ROOT__',
30609 '1.0.0',
30610 'requires',
30611 isset($lockData['platform-dev']) ? $lockData['platform-dev'] : array()
30612 );
30613
30614 $requirements = array_merge($requirements, $devRequirements);
30615 }
30616
30617 return $requirements;
30618 }
30619
30620 public function getMinimumStability()
30621 {
30622 $lockData = $this->getLockData();
30623
30624 return isset($lockData['minimum-stability']) ? $lockData['minimum-stability'] : 'stable';
30625 }
30626
30627 public function getStabilityFlags()
30628 {
30629 $lockData = $this->getLockData();
30630
30631 return isset($lockData['stability-flags']) ? $lockData['stability-flags'] : array();
30632 }
30633
30634 public function getPreferStable()
30635 {
30636 $lockData = $this->getLockData();
30637
30638
30639
30640 return isset($lockData['prefer-stable']) ? $lockData['prefer-stable'] : null;
30641 }
30642
30643 public function getPreferLowest()
30644 {
30645 $lockData = $this->getLockData();
30646
30647
30648
30649 return isset($lockData['prefer-lowest']) ? $lockData['prefer-lowest'] : null;
30650 }
30651
30652 public function getPlatformOverrides()
30653 {
30654 $lockData = $this->getLockData();
30655
30656 return isset($lockData['platform-overrides']) ? $lockData['platform-overrides'] : array();
30657 }
30658
30659 public function getAliases()
30660 {
30661 $lockData = $this->getLockData();
30662
30663 if (!isset($lockData['aliases'])) {
30664 return array();
30665 }
30666
30667
30668
30669 foreach ($lockData['aliases'] as $index => $alias) {
30670 if (in_array($alias['version'], array('dev-master', 'dev-default', 'dev-trunk'), true)) {
30671 $lockData['aliases'][$index]['version'] = '9999999-dev';
30672 }
30673 }
30674
30675 return $lockData['aliases'];
30676 }
30677
30678 public function getLockData()
30679 {
30680 if (null !== $this->lockDataCache) {
30681 return $this->lockDataCache;
30682 }
30683
30684 if (!$this->lockFile->exists()) {
30685 throw new \LogicException('No lockfile found. Unable to read locked packages');
30686 }
30687
30688 return $this->lockDataCache = $this->lockFile->read();
30689 }
30690
30691
30692
30693
30694
30695
30696
30697
30698
30699
30700
30701
30702
30703
30704
30705
30706
30707 public function setLockData(array $packages, $devPackages, array $platformReqs, $platformDevReqs, array $aliases, $minimumStability, array $stabilityFlags, $preferStable, $preferLowest, array $platformOverrides)
30708 {
30709 $lock = array(
30710 '_readme' => array('This file locks the dependencies of your project to a known state',
30711 'Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies',
30712 'This file is @gener'.'ated automatically', ),
30713 'content-hash' => $this->contentHash,
30714 'packages' => null,
30715 'packages-dev' => null,
30716 'aliases' => array(),
30717 'minimum-stability' => $minimumStability,
30718 'stability-flags' => $stabilityFlags,
30719 'prefer-stable' => $preferStable,
30720 'prefer-lowest' => $preferLowest,
30721 );
30722
30723 foreach ($aliases as $package => $versions) {
30724 foreach ($versions as $version => $alias) {
30725 $lock['aliases'][] = array(
30726 'alias' => $alias['alias'],
30727 'alias_normalized' => $alias['alias_normalized'],
30728 'version' => $version,
30729 'package' => $package,
30730 );
30731 }
30732 }
30733
30734 $lock['packages'] = $this->lockPackages($packages);
30735 if (null !== $devPackages) {
30736 $lock['packages-dev'] = $this->lockPackages($devPackages);
30737 }
30738
30739 $lock['platform'] = $platformReqs;
30740 $lock['platform-dev'] = $platformDevReqs;
30741 if ($platformOverrides) {
30742 $lock['platform-overrides'] = $platformOverrides;
30743 }
30744 $lock['plugin-api-version'] = PluginInterface::PLUGIN_API_VERSION;
30745
30746 if (empty($lock['packages']) && empty($lock['packages-dev']) && empty($lock['platform']) && empty($lock['platform-dev'])) {
30747 if ($this->lockFile->exists()) {
30748 unlink($this->lockFile->getPath());
30749 }
30750
30751 return false;
30752 }
30753
30754 try {
30755 $isLocked = $this->isLocked();
30756 } catch (ParsingException $e) {
30757 $isLocked = false;
30758 }
30759 if (!$isLocked || $lock !== $this->getLockData()) {
30760 $this->lockFile->write($lock);
30761 $this->lockDataCache = null;
30762
30763 return true;
30764 }
30765
30766 return false;
30767 }
30768
30769 private function lockPackages(array $packages)
30770 {
30771 $locked = array();
30772
30773 foreach ($packages as $package) {
30774 if ($package instanceof AliasPackage) {
30775 continue;
30776 }
30777
30778 $name = $package->getPrettyName();
30779 $version = $package->getPrettyVersion();
30780
30781 if (!$name || !$version) {
30782 throw new \LogicException(sprintf(
30783 'Package "%s" has no version or name and can not be locked',
30784 $package
30785 ));
30786 }
30787
30788 $spec = $this->dumper->dump($package);
30789 unset($spec['version_normalized']);
30790
30791
30792 $time = isset($spec['time']) ? $spec['time'] : null;
30793 unset($spec['time']);
30794 if ($package->isDev() && $package->getInstallationSource() === 'source') {
30795
30796 $time = $this->getPackageTime($package) ?: $time;
30797 }
30798 if (null !== $time) {
30799 $spec['time'] = $time;
30800 }
30801
30802 unset($spec['installation-source']);
30803
30804 $locked[] = $spec;
30805 }
30806
30807 usort($locked, function ($a, $b) {
30808 $comparison = strcmp($a['name'], $b['name']);
30809
30810 if (0 !== $comparison) {
30811 return $comparison;
30812 }
30813
30814
30815 return strcmp($a['version'], $b['version']);
30816 });
30817
30818 return $locked;
30819 }
30820
30821
30822
30823
30824
30825
30826
30827 private function getPackageTime(PackageInterface $package)
30828 {
30829 if (!function_exists('proc_open')) {
30830 return null;
30831 }
30832
30833 $path = realpath($this->installationManager->getInstallPath($package));
30834 $sourceType = $package->getSourceType();
30835 $datetime = null;
30836
30837 if ($path && in_array($sourceType, array('git', 'hg'))) {
30838 $sourceRef = $package->getSourceReference() ?: $package->getDistReference();
30839 switch ($sourceType) {
30840 case 'git':
30841 GitUtil::cleanEnv();
30842
30843 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)) {
30844 $datetime = new \DateTime('@'.trim($output), new \DateTimeZone('UTC'));
30845 }
30846 break;
30847
30848 case 'hg':
30849 if (0 === $this->process->execute('hg log --template "{date|hgdate}" -r '.ProcessExecutor::escape($sourceRef), $output, $path) && preg_match('{^\s*(\d+)\s*}', $output, $match)) {
30850 $datetime = new \DateTime('@'.$match[1], new \DateTimeZone('UTC'));
30851 }
30852 break;
30853 }
30854 }
30855
30856 return $datetime ? $datetime->format(DATE_RFC3339) : null;
30857 }
30858 }
30859 <?php
30860
30861
30862
30863
30864
30865
30866
30867
30868
30869
30870
30871 namespace Composer\Package;
30872
30873 use Composer\Package\Version\VersionParser;
30874 use Composer\Util\ComposerMirror;
30875
30876
30877
30878
30879
30880
30881 class Package extends BasePackage
30882 {
30883 protected $type;
30884 protected $targetDir;
30885 protected $installationSource;
30886 protected $sourceType;
30887 protected $sourceUrl;
30888 protected $sourceReference;
30889 protected $sourceMirrors;
30890 protected $distType;
30891 protected $distUrl;
30892 protected $distReference;
30893 protected $distSha1Checksum;
30894 protected $distMirrors;
30895 protected $version;
30896 protected $prettyVersion;
30897 protected $releaseDate;
30898 protected $extra = array();
30899 protected $binaries = array();
30900 protected $dev;
30901 protected $stability;
30902 protected $notificationUrl;
30903
30904
30905 protected $requires = array();
30906
30907 protected $conflicts = array();
30908
30909 protected $provides = array();
30910
30911 protected $replaces = array();
30912
30913 protected $devRequires = array();
30914 protected $suggests = array();
30915 protected $autoload = array();
30916 protected $devAutoload = array();
30917 protected $includePaths = array();
30918 protected $archiveExcludes = array();
30919
30920
30921
30922
30923
30924
30925
30926
30927 public function __construct($name, $version, $prettyVersion)
30928 {
30929 parent::__construct($name);
30930
30931 $this->version = $version;
30932 $this->prettyVersion = $prettyVersion;
30933
30934 $this->stability = VersionParser::parseStability($version);
30935 $this->dev = $this->stability === 'dev';
30936 }
30937
30938
30939
30940
30941 public function isDev()
30942 {
30943 return $this->dev;
30944 }
30945
30946
30947
30948
30949 public function setType($type)
30950 {
30951 $this->type = $type;
30952 }
30953
30954
30955
30956
30957 public function getType()
30958 {
30959 return $this->type ?: 'library';
30960 }
30961
30962
30963
30964
30965 public function getStability()
30966 {
30967 return $this->stability;
30968 }
30969
30970
30971
30972
30973 public function setTargetDir($targetDir)
30974 {
30975 $this->targetDir = $targetDir;
30976 }
30977
30978
30979
30980
30981 public function getTargetDir()
30982 {
30983 if (null === $this->targetDir) {
30984 return;
30985 }
30986
30987 return ltrim(preg_replace('{ (?:^|[\\\\/]+) \.\.? (?:[\\\\/]+|$) (?:\.\.? (?:[\\\\/]+|$) )*}x', '/', $this->targetDir), '/');
30988 }
30989
30990
30991
30992
30993 public function setExtra(array $extra)
30994 {
30995 $this->extra = $extra;
30996 }
30997
30998
30999
31000
31001 public function getExtra()
31002 {
31003 return $this->extra;
31004 }
31005
31006
31007
31008
31009 public function setBinaries(array $binaries)
31010 {
31011 $this->binaries = $binaries;
31012 }
31013
31014
31015
31016
31017 public function getBinaries()
31018 {
31019 return $this->binaries;
31020 }
31021
31022
31023
31024
31025 public function setInstallationSource($type)
31026 {
31027 $this->installationSource = $type;
31028 }
31029
31030
31031
31032
31033 public function getInstallationSource()
31034 {
31035 return $this->installationSource;
31036 }
31037
31038
31039
31040
31041 public function setSourceType($type)
31042 {
31043 $this->sourceType = $type;
31044 }
31045
31046
31047
31048
31049 public function getSourceType()
31050 {
31051 return $this->sourceType;
31052 }
31053
31054
31055
31056
31057 public function setSourceUrl($url)
31058 {
31059 $this->sourceUrl = $url;
31060 }
31061
31062
31063
31064
31065 public function getSourceUrl()
31066 {
31067 return $this->sourceUrl;
31068 }
31069
31070
31071
31072
31073 public function setSourceReference($reference)
31074 {
31075 $this->sourceReference = $reference;
31076 }
31077
31078
31079
31080
31081 public function getSourceReference()
31082 {
31083 return $this->sourceReference;
31084 }
31085
31086
31087
31088
31089 public function setSourceMirrors($mirrors)
31090 {
31091 $this->sourceMirrors = $mirrors;
31092 }
31093
31094
31095
31096
31097 public function getSourceMirrors()
31098 {
31099 return $this->sourceMirrors;
31100 }
31101
31102
31103
31104
31105 public function getSourceUrls()
31106 {
31107 return $this->getUrls($this->sourceUrl, $this->sourceMirrors, $this->sourceReference, $this->sourceType, 'source');
31108 }
31109
31110
31111
31112
31113 public function setDistType($type)
31114 {
31115 $this->distType = $type;
31116 }
31117
31118
31119
31120
31121 public function getDistType()
31122 {
31123 return $this->distType;
31124 }
31125
31126
31127
31128
31129 public function setDistUrl($url)
31130 {
31131 $this->distUrl = $url;
31132 }
31133
31134
31135
31136
31137 public function getDistUrl()
31138 {
31139 return $this->distUrl;
31140 }
31141
31142
31143
31144
31145 public function setDistReference($reference)
31146 {
31147 $this->distReference = $reference;
31148 }
31149
31150
31151
31152
31153 public function getDistReference()
31154 {
31155 return $this->distReference;
31156 }
31157
31158
31159
31160
31161 public function setDistSha1Checksum($sha1checksum)
31162 {
31163 $this->distSha1Checksum = $sha1checksum;
31164 }
31165
31166
31167
31168
31169 public function getDistSha1Checksum()
31170 {
31171 return $this->distSha1Checksum;
31172 }
31173
31174
31175
31176
31177 public function setDistMirrors($mirrors)
31178 {
31179 $this->distMirrors = $mirrors;
31180 }
31181
31182
31183
31184
31185 public function getDistMirrors()
31186 {
31187 return $this->distMirrors;
31188 }
31189
31190
31191
31192
31193 public function getDistUrls()
31194 {
31195 return $this->getUrls($this->distUrl, $this->distMirrors, $this->distReference, $this->distType, 'dist');
31196 }
31197
31198
31199
31200
31201 public function getVersion()
31202 {
31203 return $this->version;
31204 }
31205
31206
31207
31208
31209 public function getPrettyVersion()
31210 {
31211 return $this->prettyVersion;
31212 }
31213
31214
31215
31216
31217
31218
31219 public function setReleaseDate(\DateTime $releaseDate)
31220 {
31221 $this->releaseDate = $releaseDate;
31222 }
31223
31224
31225
31226
31227 public function getReleaseDate()
31228 {
31229 return $this->releaseDate;
31230 }
31231
31232
31233
31234
31235
31236
31237 public function setRequires(array $requires)
31238 {
31239 $this->requires = $requires;
31240 }
31241
31242
31243
31244
31245 public function getRequires()
31246 {
31247 return $this->requires;
31248 }
31249
31250
31251
31252
31253
31254
31255 public function setConflicts(array $conflicts)
31256 {
31257 $this->conflicts = $conflicts;
31258 }
31259
31260
31261
31262
31263 public function getConflicts()
31264 {
31265 return $this->conflicts;
31266 }
31267
31268
31269
31270
31271
31272
31273 public function setProvides(array $provides)
31274 {
31275 $this->provides = $provides;
31276 }
31277
31278
31279
31280
31281 public function getProvides()
31282 {
31283 return $this->provides;
31284 }
31285
31286
31287
31288
31289
31290
31291 public function setReplaces(array $replaces)
31292 {
31293 $this->replaces = $replaces;
31294 }
31295
31296
31297
31298
31299 public function getReplaces()
31300 {
31301 return $this->replaces;
31302 }
31303
31304
31305
31306
31307
31308
31309 public function setDevRequires(array $devRequires)
31310 {
31311 $this->devRequires = $devRequires;
31312 }
31313
31314
31315
31316
31317 public function getDevRequires()
31318 {
31319 return $this->devRequires;
31320 }
31321
31322
31323
31324
31325
31326
31327 public function setSuggests(array $suggests)
31328 {
31329 $this->suggests = $suggests;
31330 }
31331
31332
31333
31334
31335 public function getSuggests()
31336 {
31337 return $this->suggests;
31338 }
31339
31340
31341
31342
31343
31344
31345 public function setAutoload(array $autoload)
31346 {
31347 $this->autoload = $autoload;
31348 }
31349
31350
31351
31352
31353 public function getAutoload()
31354 {
31355 return $this->autoload;
31356 }
31357
31358
31359
31360
31361
31362
31363 public function setDevAutoload(array $devAutoload)
31364 {
31365 $this->devAutoload = $devAutoload;
31366 }
31367
31368
31369
31370
31371 public function getDevAutoload()
31372 {
31373 return $this->devAutoload;
31374 }
31375
31376
31377
31378
31379
31380
31381 public function setIncludePaths(array $includePaths)
31382 {
31383 $this->includePaths = $includePaths;
31384 }
31385
31386
31387
31388
31389 public function getIncludePaths()
31390 {
31391 return $this->includePaths;
31392 }
31393
31394
31395
31396
31397
31398
31399 public function setNotificationUrl($notificationUrl)
31400 {
31401 $this->notificationUrl = $notificationUrl;
31402 }
31403
31404
31405
31406
31407 public function getNotificationUrl()
31408 {
31409 return $this->notificationUrl;
31410 }
31411
31412
31413
31414
31415
31416
31417 public function setArchiveExcludes(array $excludes)
31418 {
31419 $this->archiveExcludes = $excludes;
31420 }
31421
31422
31423
31424
31425 public function getArchiveExcludes()
31426 {
31427 return $this->archiveExcludes;
31428 }
31429
31430
31431
31432
31433
31434
31435
31436
31437 public function replaceVersion($version, $prettyVersion)
31438 {
31439 $this->version = $version;
31440 $this->prettyVersion = $prettyVersion;
31441
31442 $this->stability = VersionParser::parseStability($version);
31443 $this->dev = $this->stability === 'dev';
31444 }
31445
31446 protected function getUrls($url, $mirrors, $ref, $type, $urlType)
31447 {
31448 if (!$url) {
31449 return array();
31450 }
31451 $urls = array($url);
31452 if ($mirrors) {
31453 foreach ($mirrors as $mirror) {
31454 if ($urlType === 'dist') {
31455 $mirrorUrl = ComposerMirror::processUrl($mirror['url'], $this->name, $this->version, $ref, $type);
31456 } elseif ($urlType === 'source' && $type === 'git') {
31457 $mirrorUrl = ComposerMirror::processGitUrl($mirror['url'], $this->name, $url, $type);
31458 } elseif ($urlType === 'source' && $type === 'hg') {
31459 $mirrorUrl = ComposerMirror::processHgUrl($mirror['url'], $this->name, $url, $type);
31460 }
31461 if (!in_array($mirrorUrl, $urls)) {
31462 $func = $mirror['preferred'] ? 'array_unshift' : 'array_push';
31463 $func($urls, $mirrorUrl);
31464 }
31465 }
31466 }
31467
31468 return $urls;
31469 }
31470 }
31471 <?php
31472
31473
31474
31475
31476
31477
31478
31479
31480
31481
31482
31483 namespace Composer\Package;
31484
31485 use Composer\Repository\RepositoryInterface;
31486
31487
31488
31489
31490
31491
31492 interface PackageInterface
31493 {
31494
31495
31496
31497
31498
31499 public function getName();
31500
31501
31502
31503
31504
31505
31506 public function getPrettyName();
31507
31508
31509
31510
31511
31512
31513
31514
31515
31516 public function getNames();
31517
31518
31519
31520
31521
31522
31523 public function setId($id);
31524
31525
31526
31527
31528
31529
31530 public function getId();
31531
31532
31533
31534
31535
31536
31537 public function isDev();
31538
31539
31540
31541
31542
31543
31544 public function getType();
31545
31546
31547
31548
31549
31550
31551 public function getTargetDir();
31552
31553
31554
31555
31556
31557
31558 public function getExtra();
31559
31560
31561
31562
31563
31564
31565 public function setInstallationSource($type);
31566
31567
31568
31569
31570
31571
31572 public function getInstallationSource();
31573
31574
31575
31576
31577
31578
31579 public function getSourceType();
31580
31581
31582
31583
31584
31585
31586 public function getSourceUrl();
31587
31588
31589
31590
31591
31592
31593 public function getSourceUrls();
31594
31595
31596
31597
31598
31599
31600 public function getSourceReference();
31601
31602
31603
31604
31605
31606
31607 public function getSourceMirrors();
31608
31609
31610
31611
31612
31613
31614 public function getDistType();
31615
31616
31617
31618
31619
31620
31621 public function getDistUrl();
31622
31623
31624
31625
31626
31627
31628 public function getDistUrls();
31629
31630
31631
31632
31633
31634
31635 public function getDistReference();
31636
31637
31638
31639
31640
31641
31642 public function getDistSha1Checksum();
31643
31644
31645
31646
31647
31648
31649 public function getDistMirrors();
31650
31651
31652
31653
31654
31655
31656 public function getVersion();
31657
31658
31659
31660
31661
31662
31663 public function getPrettyVersion();
31664
31665
31666
31667
31668
31669
31670
31671
31672
31673 public function getFullPrettyVersion($truncate = true);
31674
31675
31676
31677
31678
31679
31680 public function getReleaseDate();
31681
31682
31683
31684
31685
31686
31687 public function getStability();
31688
31689
31690
31691
31692
31693
31694
31695 public function getRequires();
31696
31697
31698
31699
31700
31701
31702
31703 public function getConflicts();
31704
31705
31706
31707
31708
31709
31710
31711 public function getProvides();
31712
31713
31714
31715
31716
31717
31718
31719 public function getReplaces();
31720
31721
31722
31723
31724
31725
31726
31727 public function getDevRequires();
31728
31729
31730
31731
31732
31733
31734
31735 public function getSuggests();
31736
31737
31738
31739
31740
31741
31742
31743
31744
31745
31746
31747 public function getAutoload();
31748
31749
31750
31751
31752
31753
31754
31755
31756
31757
31758
31759 public function getDevAutoload();
31760
31761
31762
31763
31764
31765
31766
31767 public function getIncludePaths();
31768
31769
31770
31771
31772
31773
31774 public function setRepository(RepositoryInterface $repository);
31775
31776
31777
31778
31779
31780
31781 public function getRepository();
31782
31783
31784
31785
31786
31787
31788 public function getBinaries();
31789
31790
31791
31792
31793
31794
31795 public function getUniqueName();
31796
31797
31798
31799
31800
31801
31802 public function getNotificationUrl();
31803
31804
31805
31806
31807
31808
31809 public function __toString();
31810
31811
31812
31813
31814
31815
31816 public function getPrettyString();
31817
31818
31819
31820
31821
31822
31823 public function getArchiveExcludes();
31824
31825
31826
31827
31828
31829
31830 public function getTransportOptions();
31831
31832
31833
31834
31835
31836
31837 public function setSourceReference($reference);
31838
31839
31840
31841
31842
31843
31844 public function setDistUrl($url);
31845
31846
31847
31848
31849
31850
31851 public function setDistType($type);
31852
31853
31854
31855
31856
31857
31858 public function setDistReference($reference);
31859 }
31860 <?php
31861
31862
31863
31864
31865
31866
31867
31868
31869
31870
31871
31872 namespace Composer\Package;
31873
31874
31875
31876
31877 class RootAliasPackage extends AliasPackage implements RootPackageInterface
31878 {
31879 public function __construct(RootPackageInterface $aliasOf, $version, $prettyVersion)
31880 {
31881 parent::__construct($aliasOf, $version, $prettyVersion);
31882 }
31883
31884
31885
31886
31887 public function getAliases()
31888 {
31889 return $this->aliasOf->getAliases();
31890 }
31891
31892
31893
31894
31895 public function getMinimumStability()
31896 {
31897 return $this->aliasOf->getMinimumStability();
31898 }
31899
31900
31901
31902
31903 public function getStabilityFlags()
31904 {
31905 return $this->aliasOf->getStabilityFlags();
31906 }
31907
31908
31909
31910
31911 public function getReferences()
31912 {
31913 return $this->aliasOf->getReferences();
31914 }
31915
31916
31917
31918
31919 public function getPreferStable()
31920 {
31921 return $this->aliasOf->getPreferStable();
31922 }
31923
31924
31925
31926
31927 public function getConfig()
31928 {
31929 return $this->aliasOf->getConfig();
31930 }
31931
31932
31933
31934
31935 public function setRequires(array $require)
31936 {
31937 $this->requires = $this->replaceSelfVersionDependencies($require, 'requires');
31938
31939 $this->aliasOf->setRequires($require);
31940 }
31941
31942
31943
31944
31945 public function setDevRequires(array $devRequire)
31946 {
31947 $this->devRequires = $this->replaceSelfVersionDependencies($devRequire, 'devRequires');
31948
31949 $this->aliasOf->setDevRequires($devRequire);
31950 }
31951
31952
31953
31954
31955 public function setConflicts(array $conflicts)
31956 {
31957 $this->conflicts = $this->replaceSelfVersionDependencies($conflicts, 'conflicts');
31958 $this->aliasOf->setConflicts($conflicts);
31959 }
31960
31961
31962
31963
31964 public function setProvides(array $provides)
31965 {
31966 $this->provides = $this->replaceSelfVersionDependencies($provides, 'provides');
31967 $this->aliasOf->setProvides($provides);
31968 }
31969
31970
31971
31972
31973 public function setReplaces(array $replaces)
31974 {
31975 $this->replaces = $this->replaceSelfVersionDependencies($replaces, 'replaces');
31976 $this->aliasOf->setReplaces($replaces);
31977 }
31978
31979
31980
31981
31982 public function setRepositories($repositories)
31983 {
31984 $this->aliasOf->setRepositories($repositories);
31985 }
31986
31987
31988
31989
31990 public function setAutoload(array $autoload)
31991 {
31992 $this->aliasOf->setAutoload($autoload);
31993 }
31994
31995
31996
31997
31998 public function setDevAutoload(array $devAutoload)
31999 {
32000 $this->aliasOf->setDevAutoload($devAutoload);
32001 }
32002
32003
32004
32005
32006 public function setStabilityFlags(array $stabilityFlags)
32007 {
32008 $this->aliasOf->setStabilityFlags($stabilityFlags);
32009 }
32010
32011
32012
32013
32014 public function setSuggests(array $suggests)
32015 {
32016 $this->aliasOf->setSuggests($suggests);
32017 }
32018
32019
32020
32021
32022 public function setExtra(array $extra)
32023 {
32024 $this->aliasOf->setExtra($extra);
32025 }
32026
32027 public function __clone()
32028 {
32029 parent::__clone();
32030 $this->aliasOf = clone $this->aliasOf;
32031 }
32032 }
32033 <?php
32034
32035
32036
32037
32038
32039
32040
32041
32042
32043
32044
32045 namespace Composer\Package;
32046
32047
32048
32049
32050
32051
32052 class RootPackage extends CompletePackage implements RootPackageInterface
32053 {
32054 protected $minimumStability = 'stable';
32055 protected $preferStable = false;
32056 protected $stabilityFlags = array();
32057 protected $config = array();
32058 protected $references = array();
32059 protected $aliases = array();
32060
32061
32062
32063
32064
32065
32066 public function setMinimumStability($minimumStability)
32067 {
32068 $this->minimumStability = $minimumStability;
32069 }
32070
32071
32072
32073
32074 public function getMinimumStability()
32075 {
32076 return $this->minimumStability;
32077 }
32078
32079
32080
32081
32082
32083
32084 public function setStabilityFlags(array $stabilityFlags)
32085 {
32086 $this->stabilityFlags = $stabilityFlags;
32087 }
32088
32089
32090
32091
32092 public function getStabilityFlags()
32093 {
32094 return $this->stabilityFlags;
32095 }
32096
32097
32098
32099
32100
32101
32102 public function setPreferStable($preferStable)
32103 {
32104 $this->preferStable = $preferStable;
32105 }
32106
32107
32108
32109
32110 public function getPreferStable()
32111 {
32112 return $this->preferStable;
32113 }
32114
32115
32116
32117
32118
32119
32120 public function setConfig(array $config)
32121 {
32122 $this->config = $config;
32123 }
32124
32125
32126
32127
32128 public function getConfig()
32129 {
32130 return $this->config;
32131 }
32132
32133
32134
32135
32136
32137
32138 public function setReferences(array $references)
32139 {
32140 $this->references = $references;
32141 }
32142
32143
32144
32145
32146 public function getReferences()
32147 {
32148 return $this->references;
32149 }
32150
32151
32152
32153
32154
32155
32156 public function setAliases(array $aliases)
32157 {
32158 $this->aliases = $aliases;
32159 }
32160
32161
32162
32163
32164 public function getAliases()
32165 {
32166 return $this->aliases;
32167 }
32168 }
32169 <?php
32170
32171
32172
32173
32174
32175
32176
32177
32178
32179
32180
32181 namespace Composer\Package;
32182
32183
32184
32185
32186
32187
32188 interface RootPackageInterface extends CompletePackageInterface
32189 {
32190
32191
32192
32193
32194
32195 public function getAliases();
32196
32197
32198
32199
32200
32201
32202 public function getMinimumStability();
32203
32204
32205
32206
32207
32208
32209
32210
32211 public function getStabilityFlags();
32212
32213
32214
32215
32216
32217
32218
32219
32220 public function getReferences();
32221
32222
32223
32224
32225
32226
32227 public function getPreferStable();
32228
32229
32230
32231
32232
32233
32234 public function getConfig();
32235
32236
32237
32238
32239
32240
32241 public function setRequires(array $requires);
32242
32243
32244
32245
32246
32247
32248 public function setDevRequires(array $devRequires);
32249
32250
32251
32252
32253
32254
32255 public function setConflicts(array $conflicts);
32256
32257
32258
32259
32260
32261
32262 public function setProvides(array $provides);
32263
32264
32265
32266
32267
32268
32269 public function setReplaces(array $replaces);
32270
32271
32272
32273
32274
32275
32276 public function setRepositories($repositories);
32277
32278
32279
32280
32281
32282
32283 public function setAutoload(array $autoload);
32284
32285
32286
32287
32288
32289
32290 public function setDevAutoload(array $devAutoload);
32291
32292
32293
32294
32295
32296
32297 public function setStabilityFlags(array $stabilityFlags);
32298
32299
32300
32301
32302
32303
32304 public function setSuggests(array $suggests);
32305
32306
32307
32308
32309 public function setExtra(array $extra);
32310 }
32311 <?php
32312
32313
32314
32315
32316
32317
32318
32319
32320
32321
32322
32323 namespace Composer\Package\Version;
32324
32325 use Composer\Config;
32326 use Composer\Repository\Vcs\HgDriver;
32327 use Composer\IO\NullIO;
32328 use Composer\Semver\VersionParser as SemverVersionParser;
32329 use Composer\Util\Git as GitUtil;
32330 use Composer\Util\ProcessExecutor;
32331 use Composer\Util\Svn as SvnUtil;
32332
32333
32334
32335
32336
32337
32338
32339 class VersionGuesser
32340 {
32341
32342
32343
32344 private $config;
32345
32346
32347
32348
32349 private $process;
32350
32351
32352
32353
32354 private $versionParser;
32355
32356
32357
32358
32359
32360
32361 public function __construct(Config $config, ProcessExecutor $process, SemverVersionParser $versionParser)
32362 {
32363 $this->config = $config;
32364 $this->process = $process;
32365 $this->versionParser = $versionParser;
32366 }
32367
32368
32369
32370
32371
32372
32373
32374 public function guessVersion(array $packageConfig, $path)
32375 {
32376 if (!function_exists('proc_open')) {
32377 return null;
32378 }
32379
32380 $versionData = $this->guessGitVersion($packageConfig, $path);
32381 if (null !== $versionData && null !== $versionData['version']) {
32382 return $this->postprocess($versionData);
32383 }
32384
32385 $versionData = $this->guessHgVersion($packageConfig, $path);
32386 if (null !== $versionData && null !== $versionData['version']) {
32387 return $this->postprocess($versionData);
32388 }
32389
32390 $versionData = $this->guessFossilVersion($packageConfig, $path);
32391 if (null !== $versionData && null !== $versionData['version']) {
32392 return $this->postprocess($versionData);
32393 }
32394
32395 $versionData = $this->guessSvnVersion($packageConfig, $path);
32396 if (null !== $versionData && null !== $versionData['version']) {
32397 return $this->postprocess($versionData);
32398 }
32399
32400 return null;
32401 }
32402
32403 private function postprocess(array $versionData)
32404 {
32405 if (!empty($versionData['feature_version']) && $versionData['feature_version'] === $versionData['version'] && $versionData['feature_pretty_version'] === $versionData['feature_pretty_version']) {
32406 unset($versionData['feature_version'], $versionData['feature_pretty_version']);
32407 }
32408
32409 if ('-dev' === substr($versionData['version'], -4) && preg_match('{\.9{7}}', $versionData['version'])) {
32410 $versionData['pretty_version'] = preg_replace('{(\.9{7})+}', '.x', $versionData['version']);
32411 }
32412
32413 if (!empty($versionData['feature_version']) && '-dev' === substr($versionData['feature_version'], -4) && preg_match('{\.9{7}}', $versionData['feature_version'])) {
32414 $versionData['feature_pretty_version'] = preg_replace('{(\.9{7})+}', '.x', $versionData['feature_version']);
32415 }
32416
32417 return $versionData;
32418 }
32419
32420 private function guessGitVersion(array $packageConfig, $path)
32421 {
32422 GitUtil::cleanEnv();
32423 $commit = null;
32424 $version = null;
32425 $prettyVersion = null;
32426 $featureVersion = null;
32427 $featurePrettyVersion = null;
32428 $isDetached = false;
32429
32430
32431 if (0 === $this->process->execute('git branch -a --no-color --no-abbrev -v', $output, $path)) {
32432 $branches = array();
32433 $isFeatureBranch = false;
32434
32435
32436 foreach ($this->process->splitLines($output) as $branch) {
32437 if ($branch && preg_match('{^(?:\* ) *(\(no branch\)|\(detached from \S+\)|\(HEAD detached at \S+\)|\S+) *([a-f0-9]+) .*$}', $branch, $match)) {
32438 if ($match[1] === '(no branch)' || substr($match[1], 0, 10) === '(detached ' || substr($match[1], 0, 17) === '(HEAD detached at') {
32439 $version = 'dev-' . $match[2];
32440 $prettyVersion = $version;
32441 $isFeatureBranch = true;
32442 $isDetached = true;
32443 } else {
32444 $version = $this->versionParser->normalizeBranch($match[1]);
32445 $prettyVersion = 'dev-' . $match[1];
32446 $isFeatureBranch = 0 === strpos($version, 'dev-');
32447 }
32448
32449 if ($match[2]) {
32450 $commit = $match[2];
32451 }
32452 }
32453
32454 if ($branch && !preg_match('{^ *.+/HEAD }', $branch)) {
32455 if (preg_match('{^(?:\* )? *((?:remotes/(?:origin|upstream)/)?[^\s/]+) *([a-f0-9]+) .*$}', $branch, $match)) {
32456 $branches[] = $match[1];
32457 }
32458 }
32459 }
32460
32461 if ($isFeatureBranch) {
32462 $featureVersion = $version;
32463 $featurePrettyVersion = $prettyVersion;
32464
32465 $result = $this->guessFeatureVersion($packageConfig, $version, $branches, 'git rev-list %candidate%..%branch%', $path);
32466 $version = $result['version'];
32467 $prettyVersion = $result['pretty_version'];
32468 }
32469 }
32470
32471 if (!$version || $isDetached) {
32472 $result = $this->versionFromGitTags($path);
32473 if ($result) {
32474 $version = $result['version'];
32475 $prettyVersion = $result['pretty_version'];
32476 $featureVersion = null;
32477 $featurePrettyVersion = null;
32478 }
32479 }
32480
32481 if (!$commit) {
32482 $command = 'git log --pretty="%H" -n1 HEAD'.GitUtil::getNoShowSignatureFlag($this->process);
32483 if (0 === $this->process->execute($command, $output, $path)) {
32484 $commit = trim($output) ?: null;
32485 }
32486 }
32487
32488 if ($featureVersion) {
32489 return array('version' => $version, 'commit' => $commit, 'pretty_version' => $prettyVersion, 'feature_version' => $featureVersion, 'feature_pretty_version' => $featurePrettyVersion);
32490 }
32491
32492 return array('version' => $version, 'commit' => $commit, 'pretty_version' => $prettyVersion);
32493 }
32494
32495 private function versionFromGitTags($path)
32496 {
32497
32498 if (0 === $this->process->execute('git describe --exact-match --tags', $output, $path)) {
32499 try {
32500 $version = $this->versionParser->normalize(trim($output));
32501
32502 return array('version' => $version, 'pretty_version' => trim($output));
32503 } catch (\Exception $e) {
32504 }
32505 }
32506
32507 return null;
32508 }
32509
32510 private function guessHgVersion(array $packageConfig, $path)
32511 {
32512
32513 if (0 === $this->process->execute('hg branch', $output, $path)) {
32514 $branch = trim($output);
32515 $version = $this->versionParser->normalizeBranch($branch);
32516 $isFeatureBranch = 0 === strpos($version, 'dev-');
32517
32518 if ('9999999-dev' === $version) {
32519 return array('version' => $version, 'commit' => null, 'pretty_version' => 'dev-'.$branch);
32520 }
32521
32522 if (!$isFeatureBranch) {
32523 return array('version' => $version, 'commit' => null, 'pretty_version' => $version);
32524 }
32525
32526
32527 $driver = new HgDriver(array('url' => $path), new NullIO(), $this->config, $this->process);
32528 $branches = array_keys($driver->getBranches());
32529
32530
32531 $result = $this->guessFeatureVersion($packageConfig, $version, $branches, 'hg log -r "not ancestors(\'%candidate%\') and ancestors(\'%branch%\')" --template "{node}\\n"', $path);
32532 $result['commit'] = '';
32533 $result['feature_version'] = $version;
32534 $result['feature_pretty_version'] = $version;
32535
32536 return $result;
32537 }
32538 }
32539
32540 private function guessFeatureVersion(array $packageConfig, $version, array $branches, $scmCmdline, $path)
32541 {
32542 $prettyVersion = $version;
32543
32544
32545
32546 if ((isset($packageConfig['extra']['branch-alias']) && !isset($packageConfig['extra']['branch-alias'][$version]))
32547 || strpos(json_encode($packageConfig), '"self.version"')
32548 ) {
32549 $branch = preg_replace('{^dev-}', '', $version);
32550 $length = PHP_INT_MAX;
32551
32552 $nonFeatureBranches = '';
32553 if (!empty($packageConfig['non-feature-branches'])) {
32554 $nonFeatureBranches = implode('|', $packageConfig['non-feature-branches']);
32555 }
32556
32557
32558 if (preg_match('{^(' . $nonFeatureBranches . ')$}', $branch) && in_array($branch, $branches, true)) {
32559 return array('version' => $version, 'pretty_version' => $prettyVersion);
32560 }
32561
32562
32563
32564
32565 usort($branches, function ($a, $b) {
32566 $aRemote = 0 === strpos($a, 'remotes/');
32567 $bRemote = 0 === strpos($b, 'remotes/');
32568
32569 if ($aRemote !== $bRemote) {
32570 return $aRemote ? 1 : -1;
32571 }
32572
32573 return strnatcasecmp($b, $a);
32574 });
32575
32576 foreach ($branches as $candidate) {
32577 $candidateVersion = preg_replace('{^remotes/\S+/}', '', $candidate);
32578
32579
32580 if ($candidate === $branch || !preg_match('{^(' . $nonFeatureBranches . '|master|trunk|default|develop|\d+\..+)$}', $candidateVersion, $match)) {
32581 continue;
32582 }
32583
32584 $cmdLine = str_replace(array('%candidate%', '%branch%'), array($candidate, $branch), $scmCmdline);
32585 if (0 !== $this->process->execute($cmdLine, $output, $path)) {
32586 continue;
32587 }
32588
32589 if (strlen($output) < $length) {
32590 $length = strlen($output);
32591 $version = $this->versionParser->normalizeBranch($candidateVersion);
32592 $prettyVersion = 'dev-' . $candidateVersion;
32593 if ($length === 0) {
32594 break;
32595 }
32596 }
32597 }
32598 }
32599
32600 return array('version' => $version, 'pretty_version' => $prettyVersion);
32601 }
32602
32603 private function guessFossilVersion(array $packageConfig, $path)
32604 {
32605 $version = null;
32606 $prettyVersion = null;
32607
32608
32609 if (0 === $this->process->execute('fossil branch list', $output, $path)) {
32610 $branch = trim($output);
32611 $version = $this->versionParser->normalizeBranch($branch);
32612 $prettyVersion = 'dev-' . $branch;
32613 }
32614
32615
32616 if (0 === $this->process->execute('fossil tag list', $output, $path)) {
32617 try {
32618 $version = $this->versionParser->normalize(trim($output));
32619 $prettyVersion = trim($output);
32620 } catch (\Exception $e) {
32621 }
32622 }
32623
32624 return array('version' => $version, 'commit' => '', 'pretty_version' => $prettyVersion);
32625 }
32626
32627 private function guessSvnVersion(array $packageConfig, $path)
32628 {
32629 SvnUtil::cleanEnv();
32630
32631
32632 if (0 === $this->process->execute('svn info --xml', $output, $path)) {
32633 $trunkPath = isset($packageConfig['trunk-path']) ? preg_quote($packageConfig['trunk-path'], '#') : 'trunk';
32634 $branchesPath = isset($packageConfig['branches-path']) ? preg_quote($packageConfig['branches-path'], '#') : 'branches';
32635 $tagsPath = isset($packageConfig['tags-path']) ? preg_quote($packageConfig['tags-path'], '#') : 'tags';
32636
32637 $urlPattern = '#<url>.*/(' . $trunkPath . '|(' . $branchesPath . '|' . $tagsPath . ')/(.*))</url>#';
32638
32639 if (preg_match($urlPattern, $output, $matches)) {
32640 if (isset($matches[2]) && ($branchesPath === $matches[2] || $tagsPath === $matches[2])) {
32641
32642 $version = $this->versionParser->normalizeBranch($matches[3]);
32643 $prettyVersion = 'dev-' . $matches[3];
32644
32645 return array('version' => $version, 'commit' => '', 'pretty_version' => $prettyVersion);
32646 }
32647
32648 $prettyVersion = trim($matches[1]);
32649 $version = $this->versionParser->normalize($prettyVersion);
32650
32651 return array('version' => $version, 'commit' => '', 'pretty_version' => $prettyVersion);
32652 }
32653 }
32654 }
32655 }
32656 <?php
32657
32658
32659
32660
32661
32662
32663
32664
32665
32666
32667
32668 namespace Composer\Package\Version;
32669
32670 use Composer\Repository\PlatformRepository;
32671 use Composer\Semver\VersionParser as SemverVersionParser;
32672 use Composer\Semver\Semver;
32673
32674 class VersionParser extends SemverVersionParser
32675 {
32676 private static $constraints = array();
32677
32678
32679
32680
32681 public function parseConstraints($constraints)
32682 {
32683 if (!isset(self::$constraints[$constraints])) {
32684 self::$constraints[$constraints] = parent::parseConstraints($constraints);
32685 }
32686
32687 return self::$constraints[$constraints];
32688 }
32689
32690
32691
32692
32693
32694
32695
32696
32697
32698
32699
32700 public function parseNameVersionPairs(array $pairs)
32701 {
32702 $pairs = array_values($pairs);
32703 $result = array();
32704
32705 for ($i = 0, $count = count($pairs); $i < $count; $i++) {
32706 $pair = preg_replace('{^([^=: ]+)[=: ](.*)$}', '$1 $2', trim($pairs[$i]));
32707 if (false === strpos($pair, ' ') && isset($pairs[$i + 1]) && false === strpos($pairs[$i + 1], '/') && !preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $pairs[$i + 1])) {
32708 $pair .= ' '.$pairs[$i + 1];
32709 $i++;
32710 }
32711
32712 if (strpos($pair, ' ')) {
32713 list($name, $version) = explode(' ', $pair, 2);
32714 $result[] = array('name' => $name, 'version' => $version);
32715 } else {
32716 $result[] = array('name' => $pair);
32717 }
32718 }
32719
32720 return $result;
32721 }
32722
32723
32724
32725
32726 public static function isUpgrade($normalizedFrom, $normalizedTo)
32727 {
32728 if (substr($normalizedFrom, 0, 4) === 'dev-' || substr($normalizedTo, 0, 4) === 'dev-') {
32729 return true;
32730 }
32731
32732 $sorted = Semver::sort(array($normalizedTo, $normalizedFrom));
32733
32734 return $sorted[0] === $normalizedFrom;
32735 }
32736 }
32737 <?php
32738
32739
32740
32741
32742
32743
32744
32745
32746
32747
32748
32749 namespace Composer\Package\Version;
32750
32751 use Composer\DependencyResolver\Pool;
32752 use Composer\Package\BasePackage;
32753 use Composer\Package\PackageInterface;
32754 use Composer\Plugin\PluginInterface;
32755 use Composer\Composer;
32756 use Composer\Package\Loader\ArrayLoader;
32757 use Composer\Package\Dumper\ArrayDumper;
32758 use Composer\Semver\Constraint\Constraint;
32759
32760
32761
32762
32763
32764
32765
32766 class VersionSelector
32767 {
32768 private $pool;
32769
32770 private $parser;
32771
32772 public function __construct(Pool $pool)
32773 {
32774 $this->pool = $pool;
32775 }
32776
32777
32778
32779
32780
32781
32782
32783
32784
32785
32786
32787 public function findBestCandidate($packageName, $targetPackageVersion = null, $targetPhpVersion = null, $preferredStability = 'stable')
32788 {
32789 $constraint = $targetPackageVersion ? $this->getParser()->parseConstraints($targetPackageVersion) : null;
32790 $candidates = $this->pool->whatProvides(strtolower($packageName), $constraint, true);
32791
32792 if ($targetPhpVersion) {
32793 $phpConstraint = new Constraint('==', $this->getParser()->normalize($targetPhpVersion));
32794 $composerRuntimeConstraint = new Constraint('==', $this->getParser()->normalize(Composer::RUNTIME_API_VERSION));
32795 $composerPluginConstraint = new Constraint('==', $this->getParser()->normalize(PluginInterface::PLUGIN_API_VERSION));
32796 $candidates = array_filter($candidates, function ($pkg) use ($phpConstraint, $composerPluginConstraint, $composerRuntimeConstraint) {
32797 $reqs = $pkg->getRequires();
32798
32799 return (!isset($reqs['php']) || $reqs['php']->getConstraint()->matches($phpConstraint))
32800 && (!isset($reqs['composer-plugin-api']) || $reqs['composer-plugin-api']->getConstraint()->matches($composerPluginConstraint))
32801 && (!isset($reqs['composer-runtime-api']) || $reqs['composer-runtime-api']->getConstraint()->matches($composerRuntimeConstraint));
32802 });
32803 }
32804
32805 if (!$candidates) {
32806 return false;
32807 }
32808
32809
32810 $package = reset($candidates);
32811 $minPriority = BasePackage::$stabilities[$preferredStability];
32812 foreach ($candidates as $candidate) {
32813 $candidatePriority = $candidate->getStabilityPriority();
32814 $currentPriority = $package->getStabilityPriority();
32815
32816
32817
32818 if ($minPriority < $candidatePriority && $currentPriority < $candidatePriority) {
32819 continue;
32820 }
32821
32822
32823
32824 if ($minPriority < $candidatePriority && $candidatePriority < $currentPriority) {
32825 $package = $candidate;
32826 continue;
32827 }
32828
32829
32830
32831 if ($minPriority >= $candidatePriority && $minPriority < $currentPriority) {
32832 $package = $candidate;
32833 continue;
32834 }
32835
32836
32837 if (version_compare($package->getVersion(), $candidate->getVersion(), '<')) {
32838 $package = $candidate;
32839 }
32840 }
32841
32842 return $package;
32843 }
32844
32845
32846
32847
32848
32849
32850
32851
32852
32853
32854
32855
32856
32857
32858
32859
32860 public function findRecommendedRequireVersion(PackageInterface $package)
32861 {
32862 $version = $package->getVersion();
32863 if (!$package->isDev()) {
32864 return $this->transformVersion($version, $package->getPrettyVersion(), $package->getStability());
32865 }
32866
32867 $loader = new ArrayLoader($this->getParser());
32868 $dumper = new ArrayDumper();
32869 $extra = $loader->getBranchAlias($dumper->dump($package));
32870 if ($extra) {
32871 $extra = preg_replace('{^(\d+\.\d+\.\d+)(\.9999999)-dev$}', '$1.0', $extra, -1, $count);
32872 if ($count) {
32873 $extra = str_replace('.9999999', '.0', $extra);
32874
32875 return $this->transformVersion($extra, $extra, 'dev');
32876 }
32877 }
32878
32879 return $package->getPrettyVersion();
32880 }
32881
32882 private function transformVersion($version, $prettyVersion, $stability)
32883 {
32884
32885
32886 $semanticVersionParts = explode('.', $version);
32887
32888
32889 if (count($semanticVersionParts) == 4 && preg_match('{^0\D?}', $semanticVersionParts[3])) {
32890
32891 if ($semanticVersionParts[0] === '0') {
32892 unset($semanticVersionParts[3]);
32893 } else {
32894 unset($semanticVersionParts[2], $semanticVersionParts[3]);
32895 }
32896 $version = implode('.', $semanticVersionParts);
32897 } else {
32898 return $prettyVersion;
32899 }
32900
32901
32902 if ($stability != 'stable') {
32903 $version .= '@'.$stability;
32904 }
32905
32906
32907 return '^' . $version;
32908 }
32909
32910 private function getParser()
32911 {
32912 if ($this->parser === null) {
32913 $this->parser = new VersionParser();
32914 }
32915
32916 return $this->parser;
32917 }
32918 }
32919 <?php
32920
32921
32922
32923
32924
32925
32926
32927
32928
32929
32930
32931 namespace Composer\Plugin\Capability;
32932
32933
32934
32935
32936
32937
32938
32939 interface Capability
32940 {
32941 }
32942 <?php
32943
32944
32945
32946
32947
32948
32949
32950
32951
32952
32953
32954 namespace Composer\Plugin\Capability;
32955
32956
32957
32958
32959
32960
32961
32962
32963
32964
32965
32966 interface CommandProvider extends Capability
32967 {
32968
32969
32970
32971
32972
32973 public function getCommands();
32974 }
32975 <?php
32976
32977
32978
32979
32980
32981
32982
32983
32984
32985
32986
32987 namespace Composer\Plugin;
32988
32989
32990
32991
32992
32993
32994
32995
32996 interface Capable
32997 {
32998
32999
33000
33001
33002
33003
33004
33005
33006
33007
33008
33009
33010
33011
33012
33013
33014
33015
33016 public function getCapabilities();
33017 }
33018 <?php
33019
33020
33021
33022
33023
33024
33025
33026
33027
33028
33029
33030 namespace Composer\Plugin;
33031
33032 use Composer\EventDispatcher\Event;
33033 use Symfony\Component\Console\Input\InputInterface;
33034 use Symfony\Component\Console\Output\OutputInterface;
33035
33036
33037
33038
33039
33040
33041 class CommandEvent extends Event
33042 {
33043
33044
33045
33046 private $commandName;
33047
33048
33049
33050
33051 private $input;
33052
33053
33054
33055
33056 private $output;
33057
33058
33059
33060
33061
33062
33063
33064
33065
33066
33067
33068 public function __construct($name, $commandName, $input, $output, array $args = array(), array $flags = array())
33069 {
33070 parent::__construct($name, $args, $flags);
33071 $this->commandName = $commandName;
33072 $this->input = $input;
33073 $this->output = $output;
33074 }
33075
33076
33077
33078
33079
33080
33081 public function getInput()
33082 {
33083 return $this->input;
33084 }
33085
33086
33087
33088
33089
33090
33091 public function getOutput()
33092 {
33093 return $this->output;
33094 }
33095
33096
33097
33098
33099
33100
33101 public function getCommandName()
33102 {
33103 return $this->commandName;
33104 }
33105 }
33106 <?php
33107
33108
33109
33110
33111
33112
33113
33114
33115
33116
33117
33118 namespace Composer\Plugin;
33119
33120
33121
33122
33123
33124
33125 class PluginEvents
33126 {
33127
33128
33129
33130
33131
33132
33133
33134
33135 const INIT = 'init';
33136
33137
33138
33139
33140
33141
33142
33143
33144
33145 const COMMAND = 'command';
33146
33147
33148
33149
33150
33151
33152
33153
33154
33155 const PRE_FILE_DOWNLOAD = 'pre-file-download';
33156
33157
33158
33159
33160
33161
33162
33163
33164
33165 const PRE_COMMAND_RUN = 'pre-command-run';
33166 }
33167 <?php
33168
33169
33170
33171
33172
33173
33174
33175
33176
33177
33178
33179 namespace Composer\Plugin;
33180
33181 use Composer\Composer;
33182 use Composer\IO\IOInterface;
33183
33184
33185
33186
33187
33188
33189 interface PluginInterface
33190 {
33191
33192
33193
33194
33195
33196 const PLUGIN_API_VERSION = '1.1.0';
33197
33198
33199
33200
33201
33202
33203
33204 public function activate(Composer $composer, IOInterface $io);
33205 }
33206 <?php
33207
33208
33209
33210
33211
33212
33213
33214
33215
33216
33217
33218 namespace Composer\Plugin;
33219
33220 use Composer\Composer;
33221 use Composer\EventDispatcher\EventSubscriberInterface;
33222 use Composer\IO\IOInterface;
33223 use Composer\Package\CompletePackage;
33224 use Composer\Package\Package;
33225 use Composer\Package\Version\VersionParser;
33226 use Composer\Repository\RepositoryInterface;
33227 use Composer\Package\PackageInterface;
33228 use Composer\Package\Link;
33229 use Composer\Semver\Constraint\Constraint;
33230 use Composer\DependencyResolver\Pool;
33231 use Composer\Plugin\Capability\Capability;
33232 use Composer\Util\PackageSorter;
33233
33234
33235
33236
33237
33238
33239
33240 class PluginManager
33241 {
33242 protected $composer;
33243 protected $io;
33244 protected $globalComposer;
33245 protected $versionParser;
33246 protected $disablePlugins = false;
33247
33248 protected $plugins = array();
33249 protected $registeredPlugins = array();
33250
33251 private static $classCounter = 0;
33252
33253
33254
33255
33256
33257
33258
33259
33260
33261 public function __construct(IOInterface $io, Composer $composer, Composer $globalComposer = null, $disablePlugins = false)
33262 {
33263 $this->io = $io;
33264 $this->composer = $composer;
33265 $this->globalComposer = $globalComposer;
33266 $this->versionParser = new VersionParser();
33267 $this->disablePlugins = $disablePlugins;
33268 }
33269
33270
33271
33272
33273 public function loadInstalledPlugins()
33274 {
33275 if ($this->disablePlugins) {
33276 return;
33277 }
33278
33279 $repo = $this->composer->getRepositoryManager()->getLocalRepository();
33280 $globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null;
33281 if ($repo) {
33282 $this->loadRepository($repo);
33283 }
33284 if ($globalRepo) {
33285 $this->loadRepository($globalRepo);
33286 }
33287 }
33288
33289
33290
33291
33292
33293
33294 public function getPlugins()
33295 {
33296 return $this->plugins;
33297 }
33298
33299
33300
33301
33302
33303
33304 public function getGlobalComposer()
33305 {
33306 return $this->globalComposer;
33307 }
33308
33309
33310
33311
33312
33313
33314
33315
33316
33317
33318
33319
33320 public function registerPackage(PackageInterface $package, $failOnMissingClasses = false)
33321 {
33322 if ($this->disablePlugins) {
33323 return;
33324 }
33325
33326 if ($package->getType() === 'composer-plugin') {
33327 $requiresComposer = null;
33328 foreach ($package->getRequires() as $link) { 
33329 if ('composer-plugin-api' === $link->getTarget()) {
33330 $requiresComposer = $link->getConstraint();
33331 break;
33332 }
33333 }
33334
33335 if (!$requiresComposer) {
33336 throw new \RuntimeException("Plugin ".$package->getName()." is missing a require statement for a version of the composer-plugin-api package.");
33337 }
33338
33339 $currentPluginApiVersion = $this->getPluginApiVersion();
33340 $currentPluginApiConstraint = new Constraint('==', $this->versionParser->normalize($currentPluginApiVersion));
33341
33342 if ($requiresComposer->getPrettyString() === '1.0.0' && $this->getPluginApiVersion() === '1.0.0') {
33343 $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>');
33344 } elseif (!$requiresComposer->matches($currentPluginApiConstraint)) {
33345 $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>');
33346
33347 return;
33348 }
33349 }
33350
33351 $oldInstallerPlugin = ($package->getType() === 'composer-installer');
33352
33353 if (in_array($package->getName(), $this->registeredPlugins)) {
33354 return;
33355 }
33356
33357 $extra = $package->getExtra();
33358 if (empty($extra['class'])) {
33359 throw new \UnexpectedValueException('Error while installing '.$package->getPrettyName().', composer-plugin packages should have a class defined in their extra key to be usable.');
33360 }
33361 $classes = is_array($extra['class']) ? $extra['class'] : array($extra['class']);
33362
33363 $localRepo = $this->composer->getRepositoryManager()->getLocalRepository();
33364 $globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null;
33365
33366 $pool = new Pool('dev');
33367 $pool->addRepository($localRepo);
33368 if ($globalRepo) {
33369 $pool->addRepository($globalRepo);
33370 }
33371
33372 $autoloadPackages = array($package->getName() => $package);
33373 $autoloadPackages = $this->collectDependencies($pool, $autoloadPackages, $package);
33374
33375 $generator = $this->composer->getAutoloadGenerator();
33376 $autoloads = array();
33377 foreach ($autoloadPackages as $autoloadPackage) {
33378 $downloadPath = $this->getInstallPath($autoloadPackage, $globalRepo && $globalRepo->hasPackage($autoloadPackage));
33379 $autoloads[] = array($autoloadPackage, $downloadPath);
33380 }
33381
33382 $map = $generator->parseAutoloads($autoloads, new Package('dummy', '1.0.0.0', '1.0.0'));
33383 $classLoader = $generator->createLoader($map);
33384 $classLoader->register();
33385
33386 foreach ($classes as $class) {
33387 if (class_exists($class, false)) {
33388 $class = trim($class, '\\');
33389 $path = $classLoader->findFile($class);
33390 $code = file_get_contents($path);
33391 $separatorPos = strrpos($class, '\\');
33392 $className = $class;
33393 if ($separatorPos) {
33394 $className = substr($class, $separatorPos + 1);
33395 }
33396 $code = preg_replace('{^((?:final\s+)?(?:\s*))class\s+('.preg_quote($className).')}mi', '$1class $2_composer_tmp'.self::$classCounter, $code, 1);
33397 $code = str_replace('__FILE__', var_export($path, true), $code);
33398 $code = str_replace('__DIR__', var_export(dirname($path), true), $code);
33399 $code = str_replace('__CLASS__', var_export($class, true), $code);
33400 $code = preg_replace('/^\s*<\?(php)?/i', '', $code, 1);
33401 eval($code);
33402 $class .= '_composer_tmp'.self::$classCounter;
33403 self::$classCounter++;
33404 }
33405
33406 if ($oldInstallerPlugin) {
33407 $installer = new $class($this->io, $this->composer);
33408 $this->composer->getInstallationManager()->addInstaller($installer);
33409 } elseif (class_exists($class)) {
33410 $plugin = new $class();
33411 $this->addPlugin($plugin);
33412 $this->registeredPlugins[] = $package->getName();
33413 } elseif ($failOnMissingClasses) {
33414 throw new \UnexpectedValueException('Plugin '.$package->getName().' could not be initialized, class not found: '.$class);
33415 }
33416 }
33417 }
33418
33419
33420
33421
33422
33423
33424 protected function getPluginApiVersion()
33425 {
33426 return PluginInterface::PLUGIN_API_VERSION;
33427 }
33428
33429
33430
33431
33432
33433
33434
33435
33436
33437
33438 public function addPlugin(PluginInterface $plugin)
33439 {
33440 $this->io->writeError('Loading plugin '.get_class($plugin), true, IOInterface::DEBUG);
33441 $this->plugins[] = $plugin;
33442 $plugin->activate($this->composer, $this->io);
33443
33444 if ($plugin instanceof EventSubscriberInterface) {
33445 $this->composer->getEventDispatcher()->addSubscriber($plugin);
33446 }
33447 }
33448
33449
33450
33451
33452
33453
33454
33455
33456
33457
33458
33459
33460 private function loadRepository(RepositoryInterface $repo)
33461 {
33462 $packages = $repo->getPackages();
33463 $sortedPackages = array_reverse(PackageSorter::sortPackages($packages));
33464 foreach ($sortedPackages as $package) {
33465 if (!($package instanceof CompletePackage)) {
33466 continue;
33467 }
33468 if ('composer-plugin' === $package->getType()) {
33469 $this->registerPackage($package);
33470
33471 } elseif ('composer-installer' === $package->getType()) {
33472 $this->registerPackage($package);
33473 }
33474 }
33475 }
33476
33477
33478
33479
33480
33481
33482
33483
33484
33485
33486 private function collectDependencies(Pool $pool, array $collected, PackageInterface $package)
33487 {
33488 $requires = array_merge(
33489 $package->getRequires(),
33490 $package->getDevRequires()
33491 );
33492
33493 foreach ($requires as $requireLink) {
33494 $requiredPackage = $this->lookupInstalledPackage($pool, $requireLink);
33495 if ($requiredPackage && !isset($collected[$requiredPackage->getName()])) {
33496 $collected[$requiredPackage->getName()] = $requiredPackage;
33497 $collected = $this->collectDependencies($pool, $collected, $requiredPackage);
33498 }
33499 }
33500
33501 return $collected;
33502 }
33503
33504
33505
33506
33507
33508
33509
33510
33511
33512
33513
33514 private function lookupInstalledPackage(Pool $pool, Link $link)
33515 {
33516 $packages = $pool->whatProvides($link->getTarget(), $link->getConstraint());
33517
33518 return !empty($packages) ? $packages[0] : null;
33519 }
33520
33521
33522
33523
33524
33525
33526
33527
33528
33529 private function getInstallPath(PackageInterface $package, $global = false)
33530 {
33531 if (!$global) {
33532 return $this->composer->getInstallationManager()->getInstallPath($package);
33533 }
33534
33535 return $this->globalComposer->getInstallationManager()->getInstallPath($package);
33536 }
33537
33538
33539
33540
33541
33542
33543
33544 protected function getCapabilityImplementationClassName(PluginInterface $plugin, $capability)
33545 {
33546 if (!($plugin instanceof Capable)) {
33547 return null;
33548 }
33549
33550 $capabilities = (array) $plugin->getCapabilities();
33551
33552 if (!empty($capabilities[$capability]) && is_string($capabilities[$capability]) && trim($capabilities[$capability])) {
33553 return trim($capabilities[$capability]);
33554 }
33555
33556 if (
33557 array_key_exists($capability, $capabilities)
33558 && (empty($capabilities[$capability]) || !is_string($capabilities[$capability]) || !trim($capabilities[$capability]))
33559 ) {
33560 throw new \UnexpectedValueException('Plugin '.get_class($plugin).' provided invalid capability class name(s), got '.var_export($capabilities[$capability], 1));
33561 }
33562 }
33563
33564
33565
33566
33567
33568
33569
33570
33571
33572 public function getPluginCapability(PluginInterface $plugin, $capabilityClassName, array $ctorArgs = array())
33573 {
33574 if ($capabilityClass = $this->getCapabilityImplementationClassName($plugin, $capabilityClassName)) {
33575 if (!class_exists($capabilityClass)) {
33576 throw new \RuntimeException("Cannot instantiate Capability, as class $capabilityClass from plugin ".get_class($plugin)." does not exist.");
33577 }
33578
33579 $ctorArgs['plugin'] = $plugin;
33580 $capabilityObj = new $capabilityClass($ctorArgs);
33581
33582
33583 if (!$capabilityObj instanceof Capability || !$capabilityObj instanceof $capabilityClassName) {
33584 throw new \RuntimeException(
33585 'Class ' . $capabilityClass . ' must implement both Composer\Plugin\Capability\Capability and '. $capabilityClassName . '.'
33586 );
33587 }
33588
33589 return $capabilityObj;
33590 }
33591 }
33592
33593
33594
33595
33596
33597
33598
33599
33600 public function getPluginCapabilities($capabilityClassName, array $ctorArgs = array())
33601 {
33602 $capabilities = array();
33603 foreach ($this->getPlugins() as $plugin) {
33604 if ($capability = $this->getPluginCapability($plugin, $capabilityClassName, $ctorArgs)) {
33605 $capabilities[] = $capability;
33606 }
33607 }
33608
33609 return $capabilities;
33610 }
33611 }
33612 <?php
33613
33614
33615
33616
33617
33618
33619
33620
33621
33622
33623
33624 namespace Composer\Plugin;
33625
33626 use Composer\EventDispatcher\Event;
33627 use Symfony\Component\Console\Input\InputInterface;
33628
33629
33630
33631
33632
33633
33634 class PreCommandRunEvent extends Event
33635 {
33636
33637
33638
33639 private $input;
33640
33641
33642
33643
33644 private $command;
33645
33646
33647
33648
33649
33650
33651
33652
33653 public function __construct($name, InputInterface $input, $command)
33654 {
33655 parent::__construct($name);
33656 $this->input = $input;
33657 $this->command = $command;
33658 }
33659
33660
33661
33662
33663
33664
33665 public function getInput()
33666 {
33667 return $this->input;
33668 }
33669
33670
33671
33672
33673
33674
33675 public function getCommand()
33676 {
33677 return $this->command;
33678 }
33679 }
33680 <?php
33681
33682
33683
33684
33685
33686
33687
33688
33689
33690
33691
33692 namespace Composer\Plugin;
33693
33694 use Composer\EventDispatcher\Event;
33695 use Composer\Util\RemoteFilesystem;
33696
33697
33698
33699
33700
33701
33702 class PreFileDownloadEvent extends Event
33703 {
33704
33705
33706
33707 private $rfs;
33708
33709
33710
33711
33712 private $processedUrl;
33713
33714
33715
33716
33717
33718
33719
33720
33721 public function __construct($name, RemoteFilesystem $rfs, $processedUrl)
33722 {
33723 parent::__construct($name);
33724 $this->rfs = $rfs;
33725 $this->processedUrl = $processedUrl;
33726 }
33727
33728
33729
33730
33731
33732
33733 public function getRemoteFilesystem()
33734 {
33735 return $this->rfs;
33736 }
33737
33738
33739
33740
33741
33742
33743 public function setRemoteFilesystem(RemoteFilesystem $rfs)
33744 {
33745 $this->rfs = $rfs;
33746 }
33747
33748
33749
33750
33751
33752
33753 public function getProcessedUrl()
33754 {
33755 return $this->processedUrl;
33756 }
33757 }
33758 <?php
33759
33760
33761
33762
33763
33764
33765
33766
33767
33768
33769
33770 namespace Composer\Question;
33771
33772 use Symfony\Component\Console\Exception\InvalidArgumentException;
33773 use Symfony\Component\Console\Question\Question;
33774
33775
33776
33777
33778
33779
33780
33781
33782 class StrictConfirmationQuestion extends Question
33783 {
33784 private $trueAnswerRegex;
33785 private $falseAnswerRegex;
33786
33787
33788
33789
33790
33791
33792
33793
33794
33795 public function __construct($question, $default = true, $trueAnswerRegex = '/^y(?:es)?$/i', $falseAnswerRegex = '/^no?$/i')
33796 {
33797 parent::__construct($question, (bool) $default);
33798
33799 $this->trueAnswerRegex = $trueAnswerRegex;
33800 $this->falseAnswerRegex = $falseAnswerRegex;
33801 $this->setNormalizer($this->getDefaultNormalizer());
33802 $this->setValidator($this->getDefaultValidator());
33803 }
33804
33805
33806
33807
33808
33809
33810 private function getDefaultNormalizer()
33811 {
33812 $default = $this->getDefault();
33813 $trueRegex = $this->trueAnswerRegex;
33814 $falseRegex = $this->falseAnswerRegex;
33815
33816 return function ($answer) use ($default, $trueRegex, $falseRegex) {
33817 if (is_bool($answer)) {
33818 return $answer;
33819 }
33820 if (empty($answer) && !empty($default)) {
33821 return $default;
33822 }
33823
33824 if (preg_match($trueRegex, $answer)) {
33825 return true;
33826 }
33827
33828 if (preg_match($falseRegex, $answer)) {
33829 return false;
33830 }
33831
33832 return null;
33833 };
33834 }
33835
33836
33837
33838
33839
33840
33841 private function getDefaultValidator()
33842 {
33843 return function ($answer) {
33844 if (!is_bool($answer)) {
33845 throw new InvalidArgumentException('Please answer yes, y, no, or n.');
33846 }
33847
33848 return $answer;
33849 };
33850 }
33851 }
33852 <?php
33853
33854
33855
33856
33857
33858
33859
33860
33861
33862
33863
33864 namespace Composer\Repository;
33865
33866 use Composer\Package\AliasPackage;
33867 use Composer\Package\PackageInterface;
33868 use Composer\Package\CompletePackageInterface;
33869 use Composer\Package\Version\VersionParser;
33870 use Composer\Semver\Constraint\ConstraintInterface;
33871 use Composer\Semver\Constraint\Constraint;
33872
33873
33874
33875
33876
33877
33878 class ArrayRepository extends BaseRepository
33879 {
33880
33881 protected $packages;
33882
33883
33884
33885
33886 protected $packageMap;
33887
33888 public function __construct(array $packages = array())
33889 {
33890 foreach ($packages as $package) {
33891 $this->addPackage($package);
33892 }
33893 }
33894
33895
33896
33897
33898 public function findPackage($name, $constraint)
33899 {
33900 $name = strtolower($name);
33901
33902 if (!$constraint instanceof ConstraintInterface) {
33903 $versionParser = new VersionParser();
33904 $constraint = $versionParser->parseConstraints($constraint);
33905 }
33906
33907 foreach ($this->getPackages() as $package) {
33908 if ($name === $package->getName()) {
33909 $pkgConstraint = new Constraint('==', $package->getVersion());
33910 if ($constraint->matches($pkgConstraint)) {
33911 return $package;
33912 }
33913 }
33914 }
33915
33916 return null;
33917 }
33918
33919
33920
33921
33922 public function findPackages($name, $constraint = null)
33923 {
33924
33925 $name = strtolower($name);
33926 $packages = array();
33927
33928 if (null !== $constraint && !$constraint instanceof ConstraintInterface) {
33929 $versionParser = new VersionParser();
33930 $constraint = $versionParser->parseConstraints($constraint);
33931 }
33932
33933 foreach ($this->getPackages() as $package) {
33934 if ($name === $package->getName()) {
33935 $pkgConstraint = new Constraint('==', $package->getVersion());
33936 if (null === $constraint || $constraint->matches($pkgConstraint)) {
33937 $packages[] = $package;
33938 }
33939 }
33940 }
33941
33942 return $packages;
33943 }
33944
33945
33946
33947
33948 public function search($query, $mode = 0, $type = null)
33949 {
33950 $regex = '{(?:'.implode('|', preg_split('{\s+}', $query)).')}i';
33951
33952 $matches = array();
33953 foreach ($this->getPackages() as $package) {
33954 $name = $package->getName();
33955 if (isset($matches[$name])) {
33956 continue;
33957 }
33958 if (preg_match($regex, $name)
33959 || ($mode === self::SEARCH_FULLTEXT && $package instanceof CompletePackageInterface && preg_match($regex, implode(' ', (array) $package->getKeywords()) . ' ' . $package->getDescription()))
33960 ) {
33961 if (null !== $type && $package->getType() !== $type) {
33962 continue;
33963 }
33964
33965 $matches[$name] = array(
33966 'name' => $package->getPrettyName(),
33967 'description' => $package instanceof CompletePackageInterface ? $package->getDescription() : null,
33968 );
33969 }
33970 }
33971
33972 return array_values($matches);
33973 }
33974
33975
33976
33977
33978 public function hasPackage(PackageInterface $package)
33979 {
33980 if ($this->packageMap === null) {
33981 $this->packageMap = array();
33982 foreach ($this->getPackages() as $repoPackage) {
33983 $this->packageMap[$repoPackage->getUniqueName()] = $repoPackage;
33984 }
33985 }
33986
33987 return isset($this->packageMap[$package->getUniqueName()]);
33988 }
33989
33990
33991
33992
33993
33994
33995 public function addPackage(PackageInterface $package)
33996 {
33997 if (null === $this->packages) {
33998 $this->initialize();
33999 }
34000 $package->setRepository($this);
34001 $this->packages[] = $package;
34002
34003 if ($package instanceof AliasPackage) {
34004 $aliasedPackage = $package->getAliasOf();
34005 if (null === $aliasedPackage->getRepository()) {
34006 $this->addPackage($aliasedPackage);
34007 }
34008 }
34009
34010
34011 $this->packageMap = null;
34012 }
34013
34014 protected function createAliasPackage(PackageInterface $package, $alias, $prettyAlias)
34015 {
34016 return new AliasPackage($package instanceof AliasPackage ? $package->getAliasOf() : $package, $alias, $prettyAlias);
34017 }
34018
34019
34020
34021
34022
34023
34024 public function removePackage(PackageInterface $package)
34025 {
34026 $packageId = $package->getUniqueName();
34027
34028 foreach ($this->getPackages() as $key => $repoPackage) {
34029 if ($packageId === $repoPackage->getUniqueName()) {
34030 array_splice($this->packages, $key, 1);
34031
34032
34033 $this->packageMap = null;
34034
34035 return;
34036 }
34037 }
34038 }
34039
34040
34041
34042
34043 public function getPackages()
34044 {
34045 if (null === $this->packages) {
34046 $this->initialize();
34047 }
34048
34049 return $this->packages;
34050 }
34051
34052
34053
34054
34055
34056
34057 public function count()
34058 {
34059 return count($this->packages);
34060 }
34061
34062
34063
34064
34065 protected function initialize()
34066 {
34067 $this->packages = array();
34068 }
34069 }
34070 <?php
34071
34072
34073
34074
34075
34076
34077
34078
34079
34080
34081
34082 namespace Composer\Repository;
34083
34084 use Composer\IO\IOInterface;
34085 use Composer\Json\JsonFile;
34086 use Composer\Package\Loader\ArrayLoader;
34087 use Composer\Package\Loader\LoaderInterface;
34088 use Composer\Util\Zip;
34089
34090
34091
34092
34093 class ArtifactRepository extends ArrayRepository implements ConfigurableRepositoryInterface
34094 {
34095
34096 protected $loader;
34097
34098 protected $lookup;
34099 protected $repoConfig;
34100 private $io;
34101
34102 public function __construct(array $repoConfig, IOInterface $io)
34103 {
34104 parent::__construct();
34105 if (!extension_loaded('zip')) {
34106 throw new \RuntimeException('The artifact repository requires PHP\'s zip extension');
34107 }
34108
34109 $this->loader = new ArrayLoader();
34110 $this->lookup = $repoConfig['url'];
34111 $this->io = $io;
34112 $this->repoConfig = $repoConfig;
34113 }
34114
34115 public function getRepoConfig()
34116 {
34117 return $this->repoConfig;
34118 }
34119
34120 protected function initialize()
34121 {
34122 parent::initialize();
34123
34124 $this->scanDirectory($this->lookup);
34125 }
34126
34127 private function scanDirectory($path)
34128 {
34129 $io = $this->io;
34130
34131 $directory = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::FOLLOW_SYMLINKS);
34132 $iterator = new \RecursiveIteratorIterator($directory);
34133 $regex = new \RegexIterator($iterator, '/^.+\.(zip|phar)$/i');
34134 foreach ($regex as $file) {
34135
34136 if (!$file->isFile()) {
34137 continue;
34138 }
34139
34140 $package = $this->getComposerInformation($file);
34141 if (!$package) {
34142 $io->writeError("File <comment>{$file->getBasename()}</comment> doesn't seem to hold a package", true, IOInterface::VERBOSE);
34143 continue;
34144 }
34145
34146 $template = 'Found package <info>%s</info> (<comment>%s</comment>) in file <info>%s</info>';
34147 $io->writeError(sprintf($template, $package->getName(), $package->getPrettyVersion(), $file->getBasename()), true, IOInterface::VERBOSE);
34148
34149 $this->addPackage($package);
34150 }
34151 }
34152
34153 private function getComposerInformation(\SplFileInfo $file)
34154 {
34155 $json = Zip::getComposerJson($file->getPathname());
34156
34157 if (null === $json) {
34158 return false;
34159 }
34160
34161 $package = JsonFile::parseJson($json, $file->getPathname().'#composer.json');
34162 $package['dist'] = array(
34163 'type' => 'zip',
34164 'url' => strtr($file->getPathname(), '\\', '/'),
34165 'shasum' => sha1_file($file->getRealPath()),
34166 );
34167
34168 try {
34169 $package = $this->loader->load($package);
34170 } catch (\UnexpectedValueException $e) {
34171 throw new \UnexpectedValueException('Failed loading package in '.$file.': '.$e->getMessage(), 0, $e);
34172 }
34173
34174 return $package;
34175 }
34176 }
34177 <?php
34178
34179
34180
34181
34182
34183
34184
34185
34186
34187
34188
34189 namespace Composer\Repository;
34190
34191 use Composer\Package\RootPackageInterface;
34192 use Composer\Semver\Constraint\ConstraintInterface;
34193 use Composer\Semver\Constraint\Constraint;
34194 use Composer\Package\Link;
34195
34196
34197
34198
34199
34200
34201 abstract class BaseRepository implements RepositoryInterface
34202 {
34203
34204
34205
34206
34207
34208
34209
34210
34211
34212
34213
34214
34215
34216 public function getDependents($needle, $constraint = null, $invert = false, $recurse = true, $packagesFound = null)
34217 {
34218 $needles = array_map('strtolower', (array) $needle);
34219 $results = array();
34220
34221
34222 if (null === $packagesFound) {
34223 $packagesFound = $needles;
34224 }
34225
34226
34227 $rootPackage = null;
34228 foreach ($this->getPackages() as $package) {
34229 if ($package instanceof RootPackageInterface) {
34230 $rootPackage = $package;
34231 break;
34232 }
34233 }
34234
34235
34236 foreach ($this->getPackages() as $package) {
34237 $links = $package->getRequires();
34238
34239
34240
34241 $packagesInTree = $packagesFound;
34242
34243
34244 if (!$invert) {
34245 $links += $package->getReplaces();
34246
34247
34248
34249
34250 foreach ($package->getReplaces() as $link) {
34251 foreach ($needles as $needle) {
34252 if ($link->getSource() === $needle) {
34253 if ($constraint === null || ($link->getConstraint()->matches($constraint) === !$invert)) {
34254
34255 if (in_array($link->getTarget(), $packagesInTree)) {
34256 $results[] = array($package, $link, false);
34257 continue;
34258 }
34259 $packagesInTree[] = $link->getTarget();
34260 $dependents = $recurse ? $this->getDependents($link->getTarget(), null, false, true, $packagesInTree) : array();
34261 $results[] = array($package, $link, $dependents);
34262 $needles[] = $link->getTarget();
34263 }
34264 }
34265 }
34266 }
34267 }
34268
34269
34270 if ($package instanceof RootPackageInterface) {
34271 $links += $package->getDevRequires();
34272 }
34273
34274
34275 foreach ($links as $link) {
34276 foreach ($needles as $needle) {
34277 if ($link->getTarget() === $needle) {
34278 if ($constraint === null || ($link->getConstraint()->matches($constraint) === !$invert)) {
34279
34280 if (in_array($link->getSource(), $packagesInTree)) {
34281 $results[] = array($package, $link, false);
34282 continue;
34283 }
34284 $packagesInTree[] = $link->getSource();
34285 $dependents = $recurse ? $this->getDependents($link->getSource(), null, false, true, $packagesInTree) : array();
34286 $results[] = array($package, $link, $dependents);
34287 }
34288 }
34289 }
34290 }
34291
34292
34293 if ($invert && in_array($package->getName(), $needles)) {
34294 foreach ($package->getConflicts() as $link) {
34295 foreach ($this->findPackages($link->getTarget()) as $pkg) {
34296 $version = new Constraint('=', $pkg->getVersion());
34297 if ($link->getConstraint()->matches($version) === $invert) {
34298 $results[] = array($package, $link, false);
34299 }
34300 }
34301 }
34302 }
34303
34304
34305 if ($invert && $constraint && in_array($package->getName(), $needles) && $constraint->matches(new Constraint('=', $package->getVersion()))) {
34306 foreach ($package->getRequires() as $link) {
34307 if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $link->getTarget())) {
34308 if ($this->findPackage($link->getTarget(), $link->getConstraint())) {
34309 continue;
34310 }
34311
34312 $platformPkg = $this->findPackage($link->getTarget(), '*');
34313 $description = $platformPkg ? 'but '.$platformPkg->getPrettyVersion().' is installed' : 'but it is missing';
34314 $results[] = array($package, new Link($package->getName(), $link->getTarget(), null, 'requires', $link->getPrettyConstraint().' '.$description), false);
34315
34316 continue;
34317 }
34318
34319 foreach ($this->getPackages() as $pkg) {
34320 if (!in_array($link->getTarget(), $pkg->getNames())) {
34321 continue;
34322 }
34323
34324 $version = new Constraint('=', $pkg->getVersion());
34325
34326 if ($link->getTarget() !== $pkg->getName()) {
34327 foreach (array_merge($pkg->getReplaces(), $pkg->getProvides()) as $prov) {
34328 if ($link->getTarget() === $prov->getTarget()) {
34329 $version = $prov->getConstraint();
34330 break;
34331 }
34332 }
34333 }
34334
34335 if (!$link->getConstraint()->matches($version)) {
34336
34337
34338 if ($rootPackage) {
34339 foreach (array_merge($rootPackage->getRequires(), $rootPackage->getDevRequires()) as $rootReq) {
34340 if (in_array($rootReq->getTarget(), $pkg->getNames()) && !$rootReq->getConstraint()->matches($link->getConstraint())) {
34341 $results[] = array($package, $link, false);
34342 $results[] = array($rootPackage, $rootReq, false);
34343 continue 3;
34344 }
34345 }
34346
34347 $results[] = array($package, $link, false);
34348 $results[] = array($rootPackage, new Link($rootPackage->getName(), $link->getTarget(), null, 'does not require', 'but ' . $pkg->getPrettyVersion() . ' is installed'), false);
34349 } else {
34350
34351 $results[] = array($package, $link, false);
34352 }
34353 }
34354
34355 continue 2;
34356 }
34357 }
34358 }
34359 }
34360
34361 ksort($results);
34362
34363 return $results;
34364 }
34365 }
34366 <?php
34367
34368
34369
34370
34371
34372
34373
34374
34375
34376
34377
34378 namespace Composer\Repository;
34379
34380 use Composer\Package\Loader\ArrayLoader;
34381 use Composer\Package\PackageInterface;
34382 use Composer\Package\AliasPackage;
34383 use Composer\Package\Version\VersionParser;
34384 use Composer\DependencyResolver\Pool;
34385 use Composer\Json\JsonFile;
34386 use Composer\Cache;
34387 use Composer\Config;
34388 use Composer\Composer;
34389 use Composer\Factory;
34390 use Composer\IO\IOInterface;
34391 use Composer\Util\RemoteFilesystem;
34392 use Composer\Plugin\PluginEvents;
34393 use Composer\Plugin\PreFileDownloadEvent;
34394 use Composer\EventDispatcher\EventDispatcher;
34395 use Composer\Downloader\TransportException;
34396 use Composer\Semver\Constraint\ConstraintInterface;
34397 use Composer\Semver\Constraint\Constraint;
34398
34399
34400
34401
34402 class ComposerRepository extends ArrayRepository implements ConfigurableRepositoryInterface
34403 {
34404 protected $config;
34405 protected $repoConfig;
34406 protected $options;
34407 protected $url;
34408 protected $baseUrl;
34409 protected $io;
34410 protected $rfs;
34411 protected $cache;
34412 protected $notifyUrl;
34413 protected $searchUrl;
34414 protected $hasProviders = false;
34415 protected $providersUrl;
34416 protected $lazyProvidersUrl;
34417 protected $providerListing;
34418 protected $providers = array();
34419 protected $providersByUid = array();
34420 protected $loader;
34421 protected $rootAliases;
34422 protected $allowSslDowngrade = false;
34423 protected $eventDispatcher;
34424 protected $sourceMirrors;
34425 protected $distMirrors;
34426 private $degradedMode = false;
34427 private $rootData;
34428 private $hasPartialPackages;
34429 private $partialPackagesByName;
34430
34431 public function __construct(array $repoConfig, IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, RemoteFilesystem $rfs = null)
34432 {
34433 parent::__construct();
34434 if (!preg_match('{^[\w.]+\??://}', $repoConfig['url'])) {
34435
34436 $repoConfig['url'] = 'http://'.$repoConfig['url'];
34437 }
34438 $repoConfig['url'] = rtrim($repoConfig['url'], '/');
34439
34440 if ('https?' === substr($repoConfig['url'], 0, 6)) {
34441 $repoConfig['url'] = (extension_loaded('openssl') ? 'https' : 'http') . substr($repoConfig['url'], 6);
34442 }
34443
34444 $urlBits = parse_url($repoConfig['url']);
34445 if ($urlBits === false || empty($urlBits['scheme'])) {
34446 throw new \UnexpectedValueException('Invalid url given for Composer repository: '.$repoConfig['url']);
34447 }
34448
34449 if (!isset($repoConfig['options'])) {
34450 $repoConfig['options'] = array();
34451 }
34452 if (isset($repoConfig['allow_ssl_downgrade']) && true === $repoConfig['allow_ssl_downgrade']) {
34453 $this->allowSslDowngrade = true;
34454 }
34455
34456 $this->config = $config;
34457 $this->options = $repoConfig['options'];
34458 $this->url = $repoConfig['url'];
34459
34460
34461 if (preg_match('{^(?P<proto>https?)://packagist\.org/?$}i', $this->url, $match)) {
34462 $this->url = $match['proto'].'://repo.packagist.org';
34463 }
34464
34465 $this->baseUrl = rtrim(preg_replace('{(?:/[^/\\\\]+\.json)?(?:[?#].*)?$}', '', $this->url), '/');
34466 $this->io = $io;
34467 $this->cache = new Cache($io, $config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $this->url), 'a-z0-9.$');
34468 $this->loader = new ArrayLoader();
34469 if ($rfs && $this->options) {
34470 $rfs = clone $rfs;
34471 $rfs->setOptions($this->options);
34472 }
34473 $this->rfs = $rfs ?: Factory::createRemoteFilesystem($this->io, $this->config, $this->options);
34474 $this->eventDispatcher = $eventDispatcher;
34475 $this->repoConfig = $repoConfig;
34476 }
34477
34478 public function getRepoConfig()
34479 {
34480 return $this->repoConfig;
34481 }
34482
34483 public function setRootAliases(array $rootAliases)
34484 {
34485 $this->rootAliases = $rootAliases;
34486 }
34487
34488
34489
34490
34491 public function findPackage($name, $constraint)
34492 {
34493 if (!$this->hasProviders()) {
34494 return parent::findPackage($name, $constraint);
34495 }
34496
34497 $name = strtolower($name);
34498 if (!$constraint instanceof ConstraintInterface) {
34499 $versionParser = new VersionParser();
34500 $constraint = $versionParser->parseConstraints($constraint);
34501 }
34502
34503 foreach ($this->getProviderNames() as $providerName) {
34504 if ($name === $providerName) {
34505 $packages = $this->whatProvides(new Pool('dev'), $providerName);
34506 foreach ($packages as $package) {
34507 if ($name === $package->getName()) {
34508 $pkgConstraint = new Constraint('==', $package->getVersion());
34509 if ($constraint->matches($pkgConstraint)) {
34510 return $package;
34511 }
34512 }
34513 }
34514 break;
34515 }
34516 }
34517 }
34518
34519
34520
34521
34522 public function findPackages($name, $constraint = null)
34523 {
34524 if (!$this->hasProviders()) {
34525 return parent::findPackages($name, $constraint);
34526 }
34527
34528 $name = strtolower($name);
34529
34530 if (null !== $constraint && !$constraint instanceof ConstraintInterface) {
34531 $versionParser = new VersionParser();
34532 $constraint = $versionParser->parseConstraints($constraint);
34533 }
34534
34535 $packages = array();
34536
34537 foreach ($this->getProviderNames() as $providerName) {
34538 if ($name === $providerName) {
34539 $candidates = $this->whatProvides(new Pool('dev'), $providerName);
34540 foreach ($candidates as $package) {
34541 if ($name === $package->getName()) {
34542 $pkgConstraint = new Constraint('==', $package->getVersion());
34543 if (null === $constraint || $constraint->matches($pkgConstraint)) {
34544 $packages[] = $package;
34545 }
34546 }
34547 }
34548 break;
34549 }
34550 }
34551
34552 return $packages;
34553 }
34554
34555 public function getPackages()
34556 {
34557 if ($this->hasProviders()) {
34558 throw new \LogicException('Composer repositories that have providers can not load the complete list of packages, use getProviderNames instead.');
34559 }
34560
34561 return parent::getPackages();
34562 }
34563
34564
34565
34566
34567 public function search($query, $mode = 0, $type = null)
34568 {
34569 $this->loadRootServerFile();
34570
34571 if ($this->searchUrl && $mode === self::SEARCH_FULLTEXT) {
34572 $url = str_replace(array('%query%', '%type%'), array($query, $type), $this->searchUrl);
34573
34574 $origin = RemoteFilesystem::getOrigin($url);
34575 $json = $this->rfs->getContents($origin, $url, false);
34576 $search = JsonFile::parseJson($json, $url);
34577
34578 if (empty($search['results'])) {
34579 return array();
34580 }
34581
34582 $results = array();
34583 foreach ($search['results'] as $result) {
34584
34585 if (empty($result['virtual'])) {
34586 $results[] = $result;
34587 }
34588 }
34589
34590 return $results;
34591 }
34592
34593 if ($this->hasProviders()) {
34594 $results = array();
34595 $regex = '{(?:'.implode('|', preg_split('{\s+}', $query)).')}i';
34596
34597 foreach ($this->getProviderNames() as $name) {
34598 if (preg_match($regex, $name)) {
34599 $results[] = array('name' => $name);
34600 }
34601 }
34602
34603 return $results;
34604 }
34605
34606 return parent::search($query, $mode);
34607 }
34608
34609 public function getProviderNames()
34610 {
34611 $this->loadRootServerFile();
34612
34613 if (null === $this->providerListing) {
34614 $this->loadProviderListings($this->loadRootServerFile());
34615 }
34616
34617 if ($this->hasPartialPackages) {
34618 if (null === $this->partialPackagesByName) {
34619 $this->initializePartialPackages();
34620 }
34621
34622 return array_keys($this->partialPackagesByName);
34623 }
34624
34625 if ($this->lazyProvidersUrl) {
34626
34627 return array();
34628 }
34629
34630 if ($this->providersUrl) {
34631 return array_keys($this->providerListing);
34632 }
34633
34634 return array();
34635 }
34636
34637 protected function configurePackageTransportOptions(PackageInterface $package)
34638 {
34639 foreach ($package->getDistUrls() as $url) {
34640 if (strpos($url, $this->baseUrl) === 0) {
34641 $package->setTransportOptions($this->options);
34642
34643 return;
34644 }
34645 }
34646 }
34647
34648 public function hasProviders()
34649 {
34650 $this->loadRootServerFile();
34651
34652 return $this->hasProviders;
34653 }
34654
34655 public function resetPackageIds()
34656 {
34657 foreach ($this->providersByUid as $package) {
34658 if ($package instanceof AliasPackage) {
34659 $package->getAliasOf()->setId(-1);
34660 }
34661 $package->setId(-1);
34662 }
34663 }
34664
34665
34666
34667
34668
34669
34670
34671 public function whatProvides(Pool $pool, $name, $bypassFilters = false)
34672 {
34673 if (isset($this->providers[$name]) && !$bypassFilters) {
34674 return $this->providers[$name];
34675 }
34676
34677 if ($this->hasPartialPackages && null === $this->partialPackagesByName) {
34678 $this->initializePartialPackages();
34679 }
34680
34681 if (!$this->hasPartialPackages || !isset($this->partialPackagesByName[$name])) {
34682
34683 if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name) || '__root__' === $name || 'composer-plugin-api' === $name) {
34684 return array();
34685 }
34686
34687 if (null === $this->providerListing) {
34688 $this->loadProviderListings($this->loadRootServerFile());
34689 }
34690
34691 $useLastModifiedCheck = false;
34692 if ($this->lazyProvidersUrl && !isset($this->providerListing[$name])) {
34693 $hash = null;
34694 $url = str_replace('%package%', $name, $this->lazyProvidersUrl);
34695 $cacheKey = 'provider-'.strtr($name, '/', '$').'.json';
34696 $useLastModifiedCheck = true;
34697 } elseif ($this->providersUrl) {
34698
34699 if (!isset($this->providerListing[$name])) {
34700 return array();
34701 }
34702
34703 $hash = $this->providerListing[$name]['sha256'];
34704 $url = str_replace(array('%package%', '%hash%'), array($name, $hash), $this->providersUrl);
34705 $cacheKey = 'provider-'.strtr($name, '/', '$').'.json';
34706 } else {
34707 return array();
34708 }
34709
34710 $packages = null;
34711 if ($cacheKey) {
34712 if (!$useLastModifiedCheck && $hash && $this->cache->sha256($cacheKey) === $hash) {
34713 $packages = json_decode($this->cache->read($cacheKey), true);
34714 } elseif ($useLastModifiedCheck) {
34715 if ($contents = $this->cache->read($cacheKey)) {
34716 $contents = json_decode($contents, true);
34717 if (isset($contents['last-modified'])) {
34718 $response = $this->fetchFileIfLastModified($url, $cacheKey, $contents['last-modified']);
34719 if (true === $response) {
34720 $packages = $contents;
34721 } elseif ($response) {
34722 $packages = $response;
34723 }
34724 }
34725 }
34726 }
34727 }
34728
34729 if (!$packages) {
34730 try {
34731 $packages = $this->fetchFile($url, $cacheKey, $hash, $useLastModifiedCheck);
34732 } catch (TransportException $e) {
34733
34734 if ($e->getStatusCode() === 404 && $this->lazyProvidersUrl) {
34735 $packages = array('packages' => array());
34736 } else {
34737 throw $e;
34738 }
34739 }
34740 }
34741
34742 $loadingPartialPackage = false;
34743 } else {
34744 $packages = array('packages' => array('versions' => $this->partialPackagesByName[$name]));
34745 $loadingPartialPackage = true;
34746 }
34747
34748 $this->providers[$name] = array();
34749 foreach ($packages['packages'] as $versions) {
34750 foreach ($versions as $version) {
34751 if (!$loadingPartialPackage && $this->hasPartialPackages && isset($this->partialPackagesByName[$version['name']])) {
34752 continue;
34753 }
34754
34755
34756 if (isset($this->providersByUid[$version['uid']])) {
34757
34758 if (!isset($this->providers[$name][$version['uid']])) {
34759
34760 if ($this->providersByUid[$version['uid']] instanceof AliasPackage) {
34761 $this->providers[$name][$version['uid']] = $this->providersByUid[$version['uid']]->getAliasOf();
34762 $this->providers[$name][$version['uid'].'-alias'] = $this->providersByUid[$version['uid']];
34763 } else {
34764 $this->providers[$name][$version['uid']] = $this->providersByUid[$version['uid']];
34765 }
34766
34767 if (isset($this->providersByUid[$version['uid'].'-root'])) {
34768 $this->providers[$name][$version['uid'].'-root'] = $this->providersByUid[$version['uid'].'-root'];
34769 }
34770 }
34771 } else {
34772 if (!$bypassFilters && !$pool->isPackageAcceptable(strtolower($version['name']), VersionParser::parseStability($version['version']))) {
34773 continue;
34774 }
34775
34776
34777 $package = $this->createPackage($version, 'Composer\Package\CompletePackage');
34778 $package->setRepository($this);
34779
34780 if ($package instanceof AliasPackage) {
34781 $aliased = $package->getAliasOf();
34782 $aliased->setRepository($this);
34783
34784 $this->providers[$name][$version['uid']] = $aliased;
34785 $this->providers[$name][$version['uid'].'-alias'] = $package;
34786
34787
34788 $this->providersByUid[$version['uid']] = $package;
34789 } else {
34790 $this->providers[$name][$version['uid']] = $package;
34791 $this->providersByUid[$version['uid']] = $package;
34792 }
34793
34794
34795 unset($rootAliasData);
34796
34797 if (isset($this->rootAliases[$package->getName()][$package->getVersion()])) {
34798 $rootAliasData = $this->rootAliases[$package->getName()][$package->getVersion()];
34799 } elseif ($package instanceof AliasPackage && isset($this->rootAliases[$package->getName()][$package->getAliasOf()->getVersion()])) {
34800 $rootAliasData = $this->rootAliases[$package->getName()][$package->getAliasOf()->getVersion()];
34801 }
34802
34803 if (isset($rootAliasData)) {
34804 $alias = $this->createAliasPackage($package, $rootAliasData['alias_normalized'], $rootAliasData['alias']);
34805 $alias->setRepository($this);
34806
34807 $this->providers[$name][$version['uid'].'-root'] = $alias;
34808 $this->providersByUid[$version['uid'].'-root'] = $alias;
34809 }
34810 }
34811 }
34812 }
34813
34814 $result = $this->providers[$name];
34815
34816
34817
34818 if ($bypassFilters) {
34819 foreach ($this->providers[$name] as $uid => $provider) {
34820 unset($this->providersByUid[$uid]);
34821 }
34822 unset($this->providers[$name]);
34823 }
34824
34825 return $result;
34826 }
34827
34828
34829
34830
34831 protected function initialize()
34832 {
34833 parent::initialize();
34834
34835 $repoData = $this->loadDataFromServer();
34836
34837 foreach ($repoData as $package) {
34838 $this->addPackage($this->createPackage($package, 'Composer\Package\CompletePackage'));
34839 }
34840 }
34841
34842
34843
34844
34845
34846
34847 public function addPackage(PackageInterface $package)
34848 {
34849 parent::addPackage($package);
34850 $this->configurePackageTransportOptions($package);
34851 }
34852
34853 protected function loadRootServerFile()
34854 {
34855 if (null !== $this->rootData) {
34856 return $this->rootData;
34857 }
34858
34859 if (!extension_loaded('openssl') && 'https' === substr($this->url, 0, 5)) {
34860 throw new \RuntimeException('You must enable the openssl extension in your php.ini to load information from '.$this->url);
34861 }
34862
34863 $jsonUrlParts = parse_url($this->url);
34864
34865 if (isset($jsonUrlParts['path']) && false !== strpos($jsonUrlParts['path'], '.json')) {
34866 $jsonUrl = $this->url;
34867 } else {
34868 $jsonUrl = $this->url . '/packages.json';
34869 }
34870
34871 $data = $this->fetchFile($jsonUrl, 'packages.json');
34872
34873 if (!empty($data['notify-batch'])) {
34874 $this->notifyUrl = $this->canonicalizeUrl($data['notify-batch']);
34875 } elseif (!empty($data['notify'])) {
34876 $this->notifyUrl = $this->canonicalizeUrl($data['notify']);
34877 }
34878
34879 if (!empty($data['search'])) {
34880 $this->searchUrl = $this->canonicalizeUrl($data['search']);
34881 }
34882
34883 if (!empty($data['mirrors'])) {
34884 foreach ($data['mirrors'] as $mirror) {
34885 if (!empty($mirror['git-url'])) {
34886 $this->sourceMirrors['git'][] = array('url' => $mirror['git-url'], 'preferred' => !empty($mirror['preferred']));
34887 }
34888 if (!empty($mirror['hg-url'])) {
34889 $this->sourceMirrors['hg'][] = array('url' => $mirror['hg-url'], 'preferred' => !empty($mirror['preferred']));
34890 }
34891 if (!empty($mirror['dist-url'])) {
34892 $this->distMirrors[] = array(
34893 'url' => $this->canonicalizeUrl($mirror['dist-url']),
34894 'preferred' => !empty($mirror['preferred']),
34895 );
34896 }
34897 }
34898 }
34899
34900 if (!empty($data['providers-lazy-url'])) {
34901 $this->lazyProvidersUrl = $this->canonicalizeUrl($data['providers-lazy-url']);
34902 $this->hasProviders = true;
34903
34904 $this->hasPartialPackages = !empty($data['packages']) && is_array($data['packages']);
34905 }
34906
34907 if ($this->allowSslDowngrade) {
34908 $this->url = str_replace('https://', 'http://', $this->url);
34909 $this->baseUrl = str_replace('https://', 'http://', $this->baseUrl);
34910 }
34911
34912 if (!empty($data['providers-url'])) {
34913 $this->providersUrl = $this->canonicalizeUrl($data['providers-url']);
34914 $this->hasProviders = true;
34915 }
34916
34917 if (!empty($data['providers']) || !empty($data['providers-includes'])) {
34918 $this->hasProviders = true;
34919 }
34920
34921
34922 if (preg_match('{^https?://repo\.packagist\.org/?$}i', $this->url) && !empty($this->repoConfig['force-lazy-providers'])) {
34923 $this->url = 'https://repo.packagist.org';
34924 $this->baseUrl = 'https://repo.packagist.org';
34925 $this->lazyProvidersUrl = $this->canonicalizeUrl('https://repo.packagist.org/p/%package%.json');
34926 $this->providersUrl = null;
34927 } elseif (!empty($this->repoConfig['force-lazy-providers'])) {
34928 $this->lazyProvidersUrl = $this->canonicalizeUrl('/p/%package%.json');
34929 $this->providersUrl = null;
34930 }
34931
34932 return $this->rootData = $data;
34933 }
34934
34935 protected function canonicalizeUrl($url)
34936 {
34937 if ('/' === $url[0]) {
34938 if (preg_match('{^[^:]++://[^/]*+}', $this->url, $matches)) {
34939 return $matches[0] . $url;
34940 }
34941
34942 return $this->url;
34943 }
34944
34945 return $url;
34946 }
34947
34948 protected function loadDataFromServer()
34949 {
34950 $data = $this->loadRootServerFile();
34951
34952 return $this->loadIncludes($data);
34953 }
34954
34955 protected function loadProviderListings($data)
34956 {
34957 if (isset($data['providers'])) {
34958 if (!is_array($this->providerListing)) {
34959 $this->providerListing = array();
34960 }
34961 $this->providerListing = array_merge($this->providerListing, $data['providers']);
34962 }
34963
34964 if ($this->providersUrl && isset($data['provider-includes'])) {
34965 $includes = $data['provider-includes'];
34966 foreach ($includes as $include => $metadata) {
34967 $url = $this->baseUrl . '/' . str_replace('%hash%', $metadata['sha256'], $include);
34968 $cacheKey = str_replace(array('%hash%','$'), '', $include);
34969 if ($this->cache->sha256($cacheKey) === $metadata['sha256']) {
34970 $includedData = json_decode($this->cache->read($cacheKey), true);
34971 } else {
34972 $includedData = $this->fetchFile($url, $cacheKey, $metadata['sha256']);
34973 }
34974
34975 $this->loadProviderListings($includedData);
34976 }
34977 }
34978 }
34979
34980 protected function loadIncludes($data)
34981 {
34982 $packages = array();
34983
34984
34985 if (!isset($data['packages']) && !isset($data['includes'])) {
34986 foreach ($data as $pkg) {
34987 foreach ($pkg['versions'] as $metadata) {
34988 $packages[] = $metadata;
34989 }
34990 }
34991
34992 return $packages;
34993 }
34994
34995 if (isset($data['packages'])) {
34996 foreach ($data['packages'] as $package => $versions) {
34997 foreach ($versions as $version => $metadata) {
34998 $packages[] = $metadata;
34999 }
35000 }
35001 }
35002
35003 if (isset($data['includes'])) {
35004 foreach ($data['includes'] as $include => $metadata) {
35005 if (isset($metadata['sha1']) && $this->cache->sha1($include) === $metadata['sha1']) {
35006 $includedData = json_decode($this->cache->read($include), true);
35007 } else {
35008 $includedData = $this->fetchFile($include);
35009 }
35010 $packages = array_merge($packages, $this->loadIncludes($includedData));
35011 }
35012 }
35013
35014 return $packages;
35015 }
35016
35017 protected function createPackage(array $data, $class = 'Composer\Package\CompletePackage')
35018 {
35019 try {
35020 if (!isset($data['notification-url'])) {
35021 $data['notification-url'] = $this->notifyUrl;
35022 }
35023
35024 $package = $this->loader->load($data, $class);
35025 if (isset($this->sourceMirrors[$package->getSourceType()])) {
35026 $package->setSourceMirrors($this->sourceMirrors[$package->getSourceType()]);
35027 }
35028 $package->setDistMirrors($this->distMirrors);
35029 $this->configurePackageTransportOptions($package);
35030
35031 return $package;
35032 } catch (\Exception $e) {
35033 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);
35034 }
35035 }
35036
35037 protected function fetchFile($filename, $cacheKey = null, $sha256 = null, $storeLastModifiedTime = false)
35038 {
35039 if (null === $cacheKey) {
35040 $cacheKey = $filename;
35041 $filename = $this->baseUrl.'/'.$filename;
35042 }
35043
35044
35045 if (($pos = strpos($filename, '$')) && preg_match('{^https?://.*}i', $filename)) {
35046 $filename = substr($filename, 0, $pos) . '%24' . substr($filename, $pos + 1);
35047 }
35048
35049 $retries = 3;
35050 while ($retries--) {
35051 try {
35052 $preFileDownloadEvent = new PreFileDownloadEvent(PluginEvents::PRE_FILE_DOWNLOAD, $this->rfs, $filename);
35053 if ($this->eventDispatcher) {
35054 $this->eventDispatcher->dispatch($preFileDownloadEvent->getName(), $preFileDownloadEvent);
35055 }
35056
35057 $origin = RemoteFilesystem::getOrigin($filename);
35058 $rfs = $preFileDownloadEvent->getRemoteFilesystem();
35059
35060 $json = $rfs->getContents($origin, $filename, false);
35061 if ($sha256 && $sha256 !== hash('sha256', $json)) {
35062
35063 if ($this->allowSslDowngrade) {
35064 $this->url = str_replace('http://', 'https://', $this->url);
35065 $this->baseUrl = str_replace('http://', 'https://', $this->baseUrl);
35066 $filename = str_replace('http://', 'https://', $filename);
35067 }
35068
35069 if ($retries) {
35070 usleep(100000);
35071
35072 continue;
35073 }
35074
35075
35076 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.');
35077 }
35078
35079 $data = JsonFile::parseJson($json, $filename);
35080 RemoteFilesystem::outputWarnings($this->io, $this->url, $data);
35081
35082 if ($cacheKey) {
35083 if ($storeLastModifiedTime) {
35084 $lastModifiedDate = $rfs->findHeaderValue($rfs->getLastHeaders(), 'last-modified');
35085 if ($lastModifiedDate) {
35086 $data['last-modified'] = $lastModifiedDate;
35087 $json = json_encode($data);
35088 }
35089 }
35090 $this->cache->write($cacheKey, $json);
35091 }
35092
35093 break;
35094 } catch (\Exception $e) {
35095 if ($e instanceof TransportException && $e->getStatusCode() === 404) {
35096 throw $e;
35097 }
35098
35099 if ($retries) {
35100 usleep(100000);
35101 continue;
35102 }
35103
35104 if ($e instanceof RepositorySecurityException) {
35105 throw $e;
35106 }
35107
35108 if ($cacheKey && ($contents = $this->cache->read($cacheKey))) {
35109 if (!$this->degradedMode) {
35110 $this->io->writeError('<warning>'.$e->getMessage().'</warning>');
35111 $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>');
35112 }
35113 $this->degradedMode = true;
35114 $data = JsonFile::parseJson($contents, $this->cache->getRoot().$cacheKey);
35115
35116 break;
35117 }
35118
35119 throw $e;
35120 }
35121 }
35122
35123 return $data;
35124 }
35125
35126 protected function fetchFileIfLastModified($filename, $cacheKey, $lastModifiedTime)
35127 {
35128 $retries = 3;
35129 while ($retries--) {
35130 try {
35131 $preFileDownloadEvent = new PreFileDownloadEvent(PluginEvents::PRE_FILE_DOWNLOAD, $this->rfs, $filename);
35132 if ($this->eventDispatcher) {
35133 $this->eventDispatcher->dispatch($preFileDownloadEvent->getName(), $preFileDownloadEvent);
35134 }
35135
35136 $origin = RemoteFilesystem::getOrigin($filename);
35137 $rfs = $preFileDownloadEvent->getRemoteFilesystem();
35138 $options = array('http' => array('header' => array('If-Modified-Since: '.$lastModifiedTime)));
35139 $json = $rfs->getContents($origin, $filename, false, $options);
35140 if ($json === '' && $rfs->findStatusCode($rfs->getLastHeaders()) === 304) {
35141 return true;
35142 }
35143
35144 $data = JsonFile::parseJson($json, $filename);
35145 RemoteFilesystem::outputWarnings($this->io, $this->url, $data);
35146
35147 $lastModifiedDate = $rfs->findHeaderValue($rfs->getLastHeaders(), 'last-modified');
35148 if ($lastModifiedDate) {
35149 $data['last-modified'] = $lastModifiedDate;
35150 $json = json_encode($data);
35151 }
35152 $this->cache->write($cacheKey, $json);
35153
35154 return $data;
35155 } catch (\Exception $e) {
35156 if ($e instanceof TransportException && $e->getStatusCode() === 404) {
35157 throw $e;
35158 }
35159
35160 if ($retries) {
35161 usleep(100000);
35162 continue;
35163 }
35164
35165 if (!$this->degradedMode) {
35166 $this->io->writeError('<warning>'.$e->getMessage().'</warning>');
35167 $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>');
35168 }
35169 $this->degradedMode = true;
35170
35171 return true;
35172 }
35173 }
35174 }
35175
35176
35177
35178
35179
35180
35181 private function initializePartialPackages()
35182 {
35183 $rootData = $this->loadRootServerFile();
35184
35185 $this->partialPackagesByName = array();
35186 foreach ($rootData['packages'] as $package => $versions) {
35187 $package = strtolower($package);
35188 foreach ($versions as $version) {
35189 $this->partialPackagesByName[$package][] = $version;
35190 if (!empty($version['provide']) && is_array($version['provide'])) {
35191 foreach ($version['provide'] as $provided => $providedVersion) {
35192 $this->partialPackagesByName[strtolower($provided)][] = $version;
35193 }
35194 }
35195 if (!empty($version['replace']) && is_array($version['replace'])) {
35196 foreach ($version['replace'] as $provided => $providedVersion) {
35197 $this->partialPackagesByName[strtolower($provided)][] = $version;
35198 }
35199 }
35200 }
35201 }
35202
35203
35204 $this->rootData = true;
35205 }
35206 }
35207 <?php
35208
35209
35210
35211
35212
35213
35214
35215
35216
35217
35218
35219 namespace Composer\Repository;
35220
35221 use Composer\Package\PackageInterface;
35222
35223
35224
35225
35226
35227
35228 class CompositeRepository extends BaseRepository
35229 {
35230
35231
35232
35233
35234 private $repositories;
35235
35236
35237
35238
35239
35240 public function __construct(array $repositories)
35241 {
35242 $this->repositories = array();
35243 foreach ($repositories as $repo) {
35244 $this->addRepository($repo);
35245 }
35246 }
35247
35248
35249
35250
35251
35252
35253 public function getRepositories()
35254 {
35255 return $this->repositories;
35256 }
35257
35258
35259
35260
35261 public function hasPackage(PackageInterface $package)
35262 {
35263 foreach ($this->repositories as $repository) {
35264
35265 if ($repository->hasPackage($package)) {
35266 return true;
35267 }
35268 }
35269
35270 return false;
35271 }
35272
35273
35274
35275
35276 public function findPackage($name, $constraint)
35277 {
35278 foreach ($this->repositories as $repository) {
35279
35280 $package = $repository->findPackage($name, $constraint);
35281 if (null !== $package) {
35282 return $package;
35283 }
35284 }
35285
35286 return null;
35287 }
35288
35289
35290
35291
35292 public function findPackages($name, $constraint = null)
35293 {
35294 $packages = array();
35295 foreach ($this->repositories as $repository) {
35296
35297 $packages[] = $repository->findPackages($name, $constraint);
35298 }
35299
35300 return $packages ? call_user_func_array('array_merge', $packages) : array();
35301 }
35302
35303
35304
35305
35306 public function search($query, $mode = 0, $type = null)
35307 {
35308 $matches = array();
35309 foreach ($this->repositories as $repository) {
35310
35311 $matches[] = $repository->search($query, $mode, $type);
35312 }
35313
35314 return $matches ? call_user_func_array('array_merge', $matches) : array();
35315 }
35316
35317
35318
35319
35320 public function getPackages()
35321 {
35322 $packages = array();
35323 foreach ($this->repositories as $repository) {
35324
35325 $packages[] = $repository->getPackages();
35326 }
35327
35328 return $packages ? call_user_func_array('array_merge', $packages) : array();
35329 }
35330
35331
35332
35333
35334 public function removePackage(PackageInterface $package)
35335 {
35336 foreach ($this->repositories as $repository) {
35337
35338 $repository->removePackage($package);
35339 }
35340 }
35341
35342
35343
35344
35345 public function count()
35346 {
35347 $total = 0;
35348 foreach ($this->repositories as $repository) {
35349
35350 $total += $repository->count();
35351 }
35352
35353 return $total;
35354 }
35355
35356
35357
35358
35359
35360 public function addRepository(RepositoryInterface $repository)
35361 {
35362 if ($repository instanceof self) {
35363 foreach ($repository->getRepositories() as $repo) {
35364 $this->addRepository($repo);
35365 }
35366 } else {
35367 $this->repositories[] = $repository;
35368 }
35369 }
35370 }
35371 <?php
35372
35373
35374
35375
35376
35377
35378
35379
35380
35381
35382
35383 namespace Composer\Repository;
35384
35385
35386
35387
35388
35389
35390 interface ConfigurableRepositoryInterface
35391 {
35392 public function getRepoConfig();
35393 }
35394 <?php
35395
35396
35397
35398
35399
35400
35401
35402
35403
35404
35405
35406 namespace Composer\Repository;
35407
35408 use Composer\Json\JsonFile;
35409 use Composer\Package\Loader\ArrayLoader;
35410 use Composer\Package\Dumper\ArrayDumper;
35411
35412
35413
35414
35415
35416
35417
35418 class FilesystemRepository extends WritableArrayRepository
35419 {
35420 private $file;
35421
35422
35423
35424
35425
35426
35427 public function __construct(JsonFile $repositoryFile)
35428 {
35429 parent::__construct();
35430 $this->file = $repositoryFile;
35431 }
35432
35433
35434
35435
35436 protected function initialize()
35437 {
35438 parent::initialize();
35439
35440 if (!$this->file->exists()) {
35441 return;
35442 }
35443
35444 try {
35445 $packages = $this->file->read();
35446
35447
35448 if (isset($packages['packages'])) {
35449 $packages = $packages['packages'];
35450 }
35451
35452 if (!is_array($packages)) {
35453 throw new \UnexpectedValueException('Could not parse package list from the repository');
35454 }
35455 } catch (\Exception $e) {
35456 throw new InvalidRepositoryException('Invalid repository data in '.$this->file->getPath().', packages could not be loaded: ['.get_class($e).'] '.$e->getMessage());
35457 }
35458
35459 $loader = new ArrayLoader(null, true);
35460 foreach ($packages as $packageData) {
35461 $package = $loader->load($packageData);
35462 $this->addPackage($package);
35463 }
35464 }
35465
35466 public function reload()
35467 {
35468 $this->packages = null;
35469 $this->initialize();
35470 }
35471
35472
35473
35474
35475 public function write()
35476 {
35477 $data = array();
35478 $dumper = new ArrayDumper();
35479
35480 foreach ($this->getCanonicalPackages() as $package) {
35481 $data[] = $dumper->dump($package);
35482 }
35483
35484 usort($data, function ($a, $b) {
35485 return strcmp($a['name'], $b['name']);
35486 });
35487
35488 $this->file->write($data);
35489 }
35490 }
35491 <?php
35492
35493
35494
35495
35496
35497
35498
35499
35500
35501
35502
35503 namespace Composer\Repository;
35504
35505
35506
35507
35508
35509
35510
35511
35512 class InstalledArrayRepository extends WritableArrayRepository implements InstalledRepositoryInterface
35513 {
35514 }
35515 <?php
35516
35517
35518
35519
35520
35521
35522
35523
35524
35525
35526
35527 namespace Composer\Repository;
35528
35529
35530
35531
35532
35533
35534 class InstalledFilesystemRepository extends FilesystemRepository implements InstalledRepositoryInterface
35535 {
35536 }
35537 <?php
35538
35539
35540
35541
35542
35543
35544
35545
35546
35547
35548
35549 namespace Composer\Repository;
35550
35551
35552
35553
35554
35555
35556
35557
35558 interface InstalledRepositoryInterface extends WritableRepositoryInterface
35559 {
35560 }
35561 <?php
35562
35563
35564
35565
35566
35567
35568
35569
35570
35571
35572
35573 namespace Composer\Repository;
35574
35575
35576
35577
35578
35579
35580 class InvalidRepositoryException extends \Exception
35581 {
35582 }
35583 <?php
35584
35585
35586
35587
35588
35589
35590
35591
35592
35593
35594
35595 namespace Composer\Repository;
35596
35597 use Composer\Package\Loader\ArrayLoader;
35598 use Composer\Package\Loader\ValidatingArrayLoader;
35599
35600
35601
35602
35603
35604
35605 class PackageRepository extends ArrayRepository
35606 {
35607 private $config;
35608
35609
35610
35611
35612
35613
35614 public function __construct(array $config)
35615 {
35616 parent::__construct();
35617 $this->config = $config['package'];
35618
35619
35620 if (!is_numeric(key($this->config))) {
35621 $this->config = array($this->config);
35622 }
35623 }
35624
35625
35626
35627
35628 protected function initialize()
35629 {
35630 parent::initialize();
35631
35632 $loader = new ValidatingArrayLoader(new ArrayLoader(null, true), false);
35633 foreach ($this->config as $package) {
35634 try {
35635 $package = $loader->load($package);
35636 } catch (\Exception $e) {
35637 throw new InvalidRepositoryException('A repository of type "package" contains an invalid package definition: '.$e->getMessage()."\n\nInvalid package definition:\n".json_encode($package));
35638 }
35639
35640 $this->addPackage($package);
35641 }
35642 }
35643 }
35644 <?php
35645
35646
35647
35648
35649
35650
35651
35652
35653
35654
35655
35656 namespace Composer\Repository;
35657
35658 use Composer\Config;
35659 use Composer\IO\IOInterface;
35660 use Composer\Json\JsonFile;
35661 use Composer\Package\Loader\ArrayLoader;
35662 use Composer\Package\Version\VersionGuesser;
35663 use Composer\Package\Version\VersionParser;
35664 use Composer\Util\Platform;
35665 use Composer\Util\ProcessExecutor;
35666 use Composer\Util\Filesystem;
35667 use Composer\Util\Git as GitUtil;
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
35703
35704 class PathRepository extends ArrayRepository implements ConfigurableRepositoryInterface
35705 {
35706
35707
35708
35709 private $loader;
35710
35711
35712
35713
35714 private $versionGuesser;
35715
35716
35717
35718
35719 private $url;
35720
35721
35722
35723
35724 private $repoConfig;
35725
35726
35727
35728
35729 private $process;
35730
35731
35732
35733
35734 private $options;
35735
35736
35737
35738
35739
35740
35741
35742
35743 public function __construct(array $repoConfig, IOInterface $io, Config $config)
35744 {
35745 if (!isset($repoConfig['url'])) {
35746 throw new \RuntimeException('You must specify the `url` configuration for the path repository');
35747 }
35748
35749 $this->loader = new ArrayLoader(null, true);
35750 $this->url = Platform::expandPath($repoConfig['url']);
35751 $this->process = new ProcessExecutor($io);
35752 $this->versionGuesser = new VersionGuesser($config, $this->process, new VersionParser());
35753 $this->repoConfig = $repoConfig;
35754 $this->options = isset($repoConfig['options']) ? $repoConfig['options'] : array();
35755 if (!isset($this->options['relative'])) {
35756 $filesystem = new Filesystem();
35757 $this->options['relative'] = !$filesystem->isAbsolutePath($this->url);
35758 }
35759
35760 parent::__construct();
35761 }
35762
35763 public function getRepoConfig()
35764 {
35765 return $this->repoConfig;
35766 }
35767
35768
35769
35770
35771
35772
35773 protected function initialize()
35774 {
35775 parent::initialize();
35776
35777 $urlMatches = $this->getUrlMatches();
35778
35779 if (empty($urlMatches)) {
35780 if (preg_match('{[*{}]}', $this->url)) {
35781 $url = $this->url;
35782 while (preg_match('{[*{}]}', $url)) {
35783 $url = dirname($url);
35784 }
35785
35786 if (is_dir($url)) {
35787 return;
35788 }
35789 }
35790
35791 throw new \RuntimeException('The `url` supplied for the path (' . $this->url . ') repository does not exist');
35792 }
35793
35794 foreach ($urlMatches as $url) {
35795 $path = realpath($url) . DIRECTORY_SEPARATOR;
35796 $composerFilePath = $path.'composer.json';
35797
35798 if (!file_exists($composerFilePath)) {
35799 continue;
35800 }
35801
35802 $json = file_get_contents($composerFilePath);
35803 $package = JsonFile::parseJson($json, $composerFilePath);
35804 $package['dist'] = array(
35805 'type' => 'path',
35806 'url' => $url,
35807 'reference' => sha1($json . serialize($this->options)),
35808 );
35809 $package['transport-options'] = $this->options;
35810 unset($package['transport-options']['versions']);
35811
35812
35813 if (isset($package['name'], $this->options['versions'][$package['name']])) {
35814 $package['version'] = $this->options['versions'][$package['name']];
35815 }
35816
35817
35818 if (!isset($package['version']) && ($rootVersion = getenv('COMPOSER_ROOT_VERSION'))) {
35819 if (
35820 0 === $this->process->execute('git rev-parse HEAD', $ref1, $path)
35821 && 0 === $this->process->execute('git rev-parse HEAD', $ref2)
35822 && $ref1 === $ref2
35823 ) {
35824 $package['version'] = $rootVersion;
35825 }
35826 }
35827
35828 $output = '';
35829 if (is_dir($path . DIRECTORY_SEPARATOR . '.git') && 0 === $this->process->execute('git log -n1 --pretty=%H'.GitUtil::getNoShowSignatureFlag($this->process), $output, $path)) {
35830 $package['dist']['reference'] = trim($output);
35831 }
35832
35833 if (!isset($package['version'])) {
35834 $versionData = $this->versionGuesser->guessVersion($package, $path);
35835 if (is_array($versionData) && $versionData['pretty_version']) {
35836
35837 if (!empty($versionData['feature_pretty_version'])) {
35838 $package['version'] = $versionData['feature_pretty_version'];
35839 $this->addPackage($this->loader->load($package));
35840 }
35841
35842 $package['version'] = $versionData['pretty_version'];
35843 } else {
35844 $package['version'] = 'dev-master';
35845 }
35846 }
35847
35848 $package = $this->loader->load($package);
35849 $this->addPackage($package);
35850 }
35851 }
35852
35853
35854
35855
35856
35857
35858 private function getUrlMatches()
35859 {
35860 $flags = GLOB_MARK | GLOB_ONLYDIR;
35861
35862 if (defined('GLOB_BRACE')) {
35863 $flags |= GLOB_BRACE;
35864 } elseif (strpos($this->url, '{') !== false || strpos($this->url, '}') !== false) {
35865 throw new \RuntimeException('The operating system does not support GLOB_BRACE which is required for the url '. $this->url);
35866 }
35867
35868
35869 return array_map(function ($val) {
35870 return rtrim(str_replace(DIRECTORY_SEPARATOR, '/', $val), '/');
35871 }, glob($this->url, $flags));
35872 }
35873 }
35874 <?php
35875
35876
35877
35878
35879
35880
35881
35882
35883
35884
35885
35886 namespace Composer\Repository\Pear;
35887
35888 use Composer\Util\RemoteFilesystem;
35889
35890
35891
35892
35893
35894
35895
35896
35897 abstract class BaseChannelReader
35898 {
35899
35900
35901
35902 const CHANNEL_NS = 'http://pear.php.net/channel-1.0';
35903 const ALL_CATEGORIES_NS = 'http://pear.php.net/dtd/rest.allcategories';
35904 const CATEGORY_PACKAGES_INFO_NS = 'http://pear.php.net/dtd/rest.categorypackageinfo';
35905 const ALL_PACKAGES_NS = 'http://pear.php.net/dtd/rest.allpackages';
35906 const ALL_RELEASES_NS = 'http://pear.php.net/dtd/rest.allreleases';
35907 const PACKAGE_INFO_NS = 'http://pear.php.net/dtd/rest.package';
35908
35909
35910 private $rfs;
35911
35912 protected function __construct(RemoteFilesystem $rfs)
35913 {
35914 $this->rfs = $rfs;
35915 }
35916
35917
35918
35919
35920
35921
35922
35923
35924
35925 protected function requestContent($origin, $path)
35926 {
35927 $url = rtrim($origin, '/') . '/' . ltrim($path, '/');
35928 $content = $this->rfs->getContents($origin, $url, false);
35929 if (!$content) {
35930 throw new \UnexpectedValueException('The PEAR channel at ' . $url . ' did not respond.');
35931 }
35932
35933 return str_replace('http://pear.php.net/rest/', 'https://pear.php.net/rest/', $content);
35934 }
35935
35936
35937
35938
35939
35940
35941
35942
35943
35944 protected function requestXml($origin, $path)
35945 {
35946
35947 $xml = simplexml_load_string($this->requestContent($origin, $path), "SimpleXMLElement", LIBXML_NOERROR);
35948
35949 if (false === $xml) {
35950 throw new \UnexpectedValueException(sprintf('The PEAR channel at ' . $origin . ' is broken. (Invalid XML at file `%s`)', $path));
35951 }
35952
35953 return $xml;
35954 }
35955 }
35956 <?php
35957
35958
35959
35960
35961
35962
35963
35964
35965
35966
35967
35968 namespace Composer\Repository\Pear;
35969
35970
35971
35972
35973
35974
35975 class ChannelInfo
35976 {
35977 private $name;
35978 private $alias;
35979 private $packages;
35980
35981
35982
35983
35984
35985
35986 public function __construct($name, $alias, array $packages)
35987 {
35988 $this->name = $name;
35989 $this->alias = $alias;
35990 $this->packages = $packages;
35991 }
35992
35993
35994
35995
35996
35997
35998 public function getName()
35999 {
36000 return $this->name;
36001 }
36002
36003
36004
36005
36006
36007
36008 public function getAlias()
36009 {
36010 return $this->alias;
36011 }
36012
36013
36014
36015
36016
36017
36018 public function getPackages()
36019 {
36020 return $this->packages;
36021 }
36022 }
36023 <?php
36024
36025
36026
36027
36028
36029
36030
36031
36032
36033
36034
36035 namespace Composer\Repository\Pear;
36036
36037 use Composer\Util\RemoteFilesystem;
36038
36039
36040
36041
36042
36043
36044
36045
36046 class ChannelReader extends BaseChannelReader
36047 {
36048
36049 private $readerMap;
36050
36051 public function __construct(RemoteFilesystem $rfs)
36052 {
36053 parent::__construct($rfs);
36054
36055 $rest10reader = new ChannelRest10Reader($rfs);
36056 $rest11reader = new ChannelRest11Reader($rfs);
36057
36058 $this->readerMap = array(
36059 'REST1.3' => $rest11reader,
36060 'REST1.2' => $rest11reader,
36061 'REST1.1' => $rest11reader,
36062 'REST1.0' => $rest10reader,
36063 );
36064 }
36065
36066
36067
36068
36069
36070
36071
36072
36073 public function read($url)
36074 {
36075 $xml = $this->requestXml($url, "/channel.xml");
36076
36077 $channelName = (string) $xml->name;
36078 $channelAlias = (string) $xml->suggestedalias;
36079
36080 $supportedVersions = array_keys($this->readerMap);
36081 $selectedRestVersion = $this->selectRestVersion($xml, $supportedVersions);
36082 if (!$selectedRestVersion) {
36083 throw new \UnexpectedValueException(sprintf('PEAR repository %s does not supports any of %s protocols.', $url, implode(', ', $supportedVersions)));
36084 }
36085
36086 $reader = $this->readerMap[$selectedRestVersion['version']];
36087 $packageDefinitions = $reader->read($selectedRestVersion['baseUrl']);
36088
36089 return new ChannelInfo($channelName, $channelAlias, $packageDefinitions);
36090 }
36091
36092
36093
36094
36095
36096
36097
36098
36099 private function selectRestVersion($channelXml, $supportedVersions)
36100 {
36101 $channelXml->registerXPathNamespace('ns', self::CHANNEL_NS);
36102
36103 foreach ($supportedVersions as $version) {
36104 $xpathTest = "ns:servers/ns:*/ns:rest/ns:baseurl[@type='{$version}']";
36105 $testResult = $channelXml->xpath($xpathTest);
36106
36107 foreach ($testResult as $result) {
36108
36109 $result = (string) $result;
36110 if (preg_match('{^https://}i', $result)) {
36111 return array('version' => $version, 'baseUrl' => $result);
36112 }
36113 }
36114
36115
36116 if (count($testResult) > 0) {
36117 return array('version' => $version, 'baseUrl' => (string) $testResult[0]);
36118 }
36119 }
36120
36121 return null;
36122 }
36123 }
36124 <?php
36125
36126
36127
36128
36129
36130
36131
36132
36133
36134
36135
36136 namespace Composer\Repository\Pear;
36137
36138 use Composer\Downloader\TransportException;
36139
36140
36141
36142
36143
36144
36145
36146
36147
36148
36149
36150
36151 class ChannelRest10Reader extends BaseChannelReader
36152 {
36153 private $dependencyReader;
36154
36155 public function __construct($rfs)
36156 {
36157 parent::__construct($rfs);
36158
36159 $this->dependencyReader = new PackageDependencyParser();
36160 }
36161
36162
36163
36164
36165
36166
36167
36168
36169 public function read($baseUrl)
36170 {
36171 return $this->readPackages($baseUrl);
36172 }
36173
36174
36175
36176
36177
36178
36179
36180
36181 private function readPackages($baseUrl)
36182 {
36183 $result = array();
36184
36185 $xmlPath = '/p/packages.xml';
36186 $xml = $this->requestXml($baseUrl, $xmlPath);
36187 $xml->registerXPathNamespace('ns', self::ALL_PACKAGES_NS);
36188 foreach ($xml->xpath('ns:p') as $node) {
36189 $packageName = (string) $node;
36190 $packageInfo = $this->readPackage($baseUrl, $packageName);
36191 $result[] = $packageInfo;
36192 }
36193
36194 return $result;
36195 }
36196
36197
36198
36199
36200
36201
36202
36203
36204
36205 private function readPackage($baseUrl, $packageName)
36206 {
36207 $xmlPath = '/p/' . strtolower($packageName) . '/info.xml';
36208 $xml = $this->requestXml($baseUrl, $xmlPath);
36209 $xml->registerXPathNamespace('ns', self::PACKAGE_INFO_NS);
36210
36211 $channelName = (string) $xml->c;
36212 $packageName = (string) $xml->n;
36213 $license = (string) $xml->l;
36214 $shortDescription = (string) $xml->s;
36215 $description = (string) $xml->d;
36216
36217 return new PackageInfo(
36218 $channelName,
36219 $packageName,
36220 $license,
36221 $shortDescription,
36222 $description,
36223 $this->readPackageReleases($baseUrl, $packageName)
36224 );
36225 }
36226
36227
36228
36229
36230
36231
36232
36233
36234
36235
36236 private function readPackageReleases($baseUrl, $packageName)
36237 {
36238 $result = array();
36239
36240 try {
36241 $xmlPath = '/r/' . strtolower($packageName) . '/allreleases.xml';
36242 $xml = $this->requestXml($baseUrl, $xmlPath);
36243 $xml->registerXPathNamespace('ns', self::ALL_RELEASES_NS);
36244 foreach ($xml->xpath('ns:r') as $node) {
36245 $releaseVersion = (string) $node->v;
36246 $releaseStability = (string) $node->s;
36247
36248 try {
36249 $result[$releaseVersion] = new ReleaseInfo(
36250 $releaseStability,
36251 $this->readPackageReleaseDependencies($baseUrl, $packageName, $releaseVersion)
36252 );
36253 } catch (TransportException $exception) {
36254 if ($exception->getCode() != 404) {
36255 throw $exception;
36256 }
36257 }
36258 }
36259 } catch (TransportException $exception) {
36260 if ($exception->getCode() != 404) {
36261 throw $exception;
36262 }
36263 }
36264
36265 return $result;
36266 }
36267
36268
36269
36270
36271
36272
36273
36274
36275
36276
36277 private function readPackageReleaseDependencies($baseUrl, $packageName, $version)
36278 {
36279 $dependencyReader = new PackageDependencyParser();
36280
36281 $depthPath = '/r/' . strtolower($packageName) . '/deps.' . $version . '.txt';
36282 $content = $this->requestContent($baseUrl, $depthPath);
36283 $dependencyArray = unserialize($content);
36284
36285 return $dependencyReader->buildDependencyInfo($dependencyArray);
36286 }
36287 }
36288 <?php
36289
36290
36291
36292
36293
36294
36295
36296
36297
36298
36299
36300 namespace Composer\Repository\Pear;
36301
36302
36303
36304
36305
36306
36307
36308
36309
36310
36311 class ChannelRest11Reader extends BaseChannelReader
36312 {
36313 private $dependencyReader;
36314
36315 public function __construct($rfs)
36316 {
36317 parent::__construct($rfs);
36318
36319 $this->dependencyReader = new PackageDependencyParser();
36320 }
36321
36322
36323
36324
36325
36326
36327
36328
36329 public function read($baseUrl)
36330 {
36331 return $this->readChannelPackages($baseUrl);
36332 }
36333
36334
36335
36336
36337
36338
36339
36340
36341 private function readChannelPackages($baseUrl)
36342 {
36343 $result = array();
36344
36345 $xml = $this->requestXml($baseUrl, "/c/categories.xml");
36346 $xml->registerXPathNamespace('ns', self::ALL_CATEGORIES_NS);
36347 foreach ($xml->xpath('ns:c') as $node) {
36348 $categoryName = (string) $node;
36349 $categoryPackages = $this->readCategoryPackages($baseUrl, $categoryName);
36350 $result = array_merge($result, $categoryPackages);
36351 }
36352
36353 return $result;
36354 }
36355
36356
36357
36358
36359
36360
36361
36362
36363
36364 private function readCategoryPackages($baseUrl, $categoryName)
36365 {
36366 $result = array();
36367
36368 $categoryPath = '/c/'.urlencode($categoryName).'/packagesinfo.xml';
36369 $xml = $this->requestXml($baseUrl, $categoryPath);
36370 $xml->registerXPathNamespace('ns', self::CATEGORY_PACKAGES_INFO_NS);
36371 foreach ($xml->xpath('ns:pi') as $node) {
36372 $packageInfo = $this->parsePackage($node);
36373 $result[] = $packageInfo;
36374 }
36375
36376 return $result;
36377 }
36378
36379
36380
36381
36382
36383
36384
36385 private function parsePackage($packageInfo)
36386 {
36387 $packageInfo->registerXPathNamespace('ns', self::CATEGORY_PACKAGES_INFO_NS);
36388 $channelName = (string) $packageInfo->p->c;
36389 $packageName = (string) $packageInfo->p->n;
36390 $license = (string) $packageInfo->p->l;
36391 $shortDescription = (string) $packageInfo->p->s;
36392 $description = (string) $packageInfo->p->d;
36393
36394 $dependencies = array();
36395 foreach ($packageInfo->xpath('ns:deps') as $node) {
36396 $dependencyVersion = (string) $node->v;
36397 $dependencyArray = unserialize((string) $node->d);
36398
36399 $dependencyInfo = $this->dependencyReader->buildDependencyInfo($dependencyArray);
36400
36401 $dependencies[$dependencyVersion] = $dependencyInfo;
36402 }
36403
36404 $releases = array();
36405 $releasesInfo = $packageInfo->xpath('ns:a/ns:r');
36406 if ($releasesInfo) {
36407 foreach ($releasesInfo as $node) {
36408 $releaseVersion = (string) $node->v;
36409 $releaseStability = (string) $node->s;
36410 $releases[$releaseVersion] = new ReleaseInfo(
36411 $releaseStability,
36412 isset($dependencies[$releaseVersion]) ? $dependencies[$releaseVersion] : new DependencyInfo(array(), array())
36413 );
36414 }
36415 }
36416
36417 return new PackageInfo(
36418 $channelName,
36419 $packageName,
36420 $license,
36421 $shortDescription,
36422 $description,
36423 $releases
36424 );
36425 }
36426 }
36427 <?php
36428
36429
36430
36431
36432
36433
36434
36435
36436
36437
36438
36439 namespace Composer\Repository\Pear;
36440
36441
36442
36443
36444
36445
36446 class DependencyConstraint
36447 {
36448 private $type;
36449 private $constraint;
36450 private $channelName;
36451 private $packageName;
36452
36453
36454
36455
36456
36457
36458
36459 public function __construct($type, $constraint, $channelName, $packageName)
36460 {
36461 $this->type = $type;
36462 $this->constraint = $constraint;
36463 $this->channelName = $channelName;
36464 $this->packageName = $packageName;
36465 }
36466
36467 public function getChannelName()
36468 {
36469 return $this->channelName;
36470 }
36471
36472 public function getConstraint()
36473 {
36474 return $this->constraint;
36475 }
36476
36477 public function getPackageName()
36478 {
36479 return $this->packageName;
36480 }
36481
36482 public function getType()
36483 {
36484 return $this->type;
36485 }
36486 }
36487 <?php
36488
36489
36490
36491
36492
36493
36494
36495
36496
36497
36498
36499 namespace Composer\Repository\Pear;
36500
36501
36502
36503
36504
36505
36506 class DependencyInfo
36507 {
36508 private $requires;
36509 private $optionals;
36510
36511
36512
36513
36514
36515 public function __construct($requires, $optionals)
36516 {
36517 $this->requires = $requires;
36518 $this->optionals = $optionals;
36519 }
36520
36521
36522
36523
36524 public function getRequires()
36525 {
36526 return $this->requires;
36527 }
36528
36529
36530
36531
36532 public function getOptionals()
36533 {
36534 return $this->optionals;
36535 }
36536 }
36537 <?php
36538
36539
36540
36541
36542
36543
36544
36545
36546
36547
36548
36549 namespace Composer\Repository\Pear;
36550
36551
36552
36553
36554
36555
36556 class PackageDependencyParser
36557 {
36558
36559
36560
36561
36562
36563
36564 public function buildDependencyInfo($depArray)
36565 {
36566 if (!is_array($depArray)) {
36567 return new DependencyInfo(array(), array());
36568 }
36569 if (!$this->isHash($depArray)) {
36570 return new DependencyInfo($this->buildDependency10Info($depArray), array());
36571 }
36572
36573 return $this->buildDependency20Info($depArray);
36574 }
36575
36576
36577
36578
36579
36580
36581
36582
36583
36584
36585
36586
36587
36588 private function buildDependency10Info($depArray)
36589 {
36590 static $dep10toOperatorMap = array('has' => '==', 'eq' => '==', 'ge' => '>=', 'gt' => '>', 'le' => '<=', 'lt' => '<', 'not' => '!=');
36591
36592 $result = array();
36593
36594 foreach ($depArray as $depItem) {
36595 if (empty($depItem['rel']) || !array_key_exists($depItem['rel'], $dep10toOperatorMap)) {
36596
36597 continue;
36598 }
36599
36600 $depType = !empty($depItem['optional']) && 'yes' == $depItem['optional']
36601 ? 'optional'
36602 : 'required';
36603 $depType = 'not' == $depItem['rel']
36604 ? 'conflicts'
36605 : $depType;
36606
36607 $depVersion = !empty($depItem['version']) ? $this->parseVersion($depItem['version']) : '*';
36608
36609
36610 $depVersionConstraint = ('has' == $depItem['rel'] || 'not' == $depItem['rel']) && '*' == $depVersion
36611 ? '*'
36612 : $dep10toOperatorMap[$depItem['rel']] . $depVersion;
36613
36614 switch ($depItem['type']) {
36615 case 'php':
36616 $depChannelName = 'php';
36617 $depPackageName = '';
36618 break;
36619 case 'pkg':
36620 $depChannelName = !empty($depItem['channel']) ? $depItem['channel'] : 'pear.php.net';
36621 $depPackageName = $depItem['name'];
36622 break;
36623 case 'ext':
36624 $depChannelName = 'ext';
36625 $depPackageName = $depItem['name'];
36626 break;
36627 case 'os':
36628 case 'sapi':
36629 $depChannelName = '';
36630 $depPackageName = '';
36631 break;
36632 default:
36633 $depChannelName = '';
36634 $depPackageName = '';
36635 break;
36636 }
36637
36638 if ('' != $depChannelName) {
36639 $result[] = new DependencyConstraint(
36640 $depType,
36641 $depVersionConstraint,
36642 $depChannelName,
36643 $depPackageName
36644 );
36645 }
36646 }
36647
36648 return $result;
36649 }
36650
36651
36652
36653
36654
36655
36656
36657 private function buildDependency20Info($depArray)
36658 {
36659 $result = array();
36660 $optionals = array();
36661 $defaultOptionals = array();
36662 foreach ($depArray as $depType => $depTypeGroup) {
36663 if (!is_array($depTypeGroup)) {
36664 continue;
36665 }
36666 if ('required' == $depType || 'optional' == $depType) {
36667 foreach ($depTypeGroup as $depItemType => $depItem) {
36668 switch ($depItemType) {
36669 case 'php':
36670 $result[] = new DependencyConstraint(
36671 $depType,
36672 $this->parse20VersionConstraint($depItem),
36673 'php',
36674 ''
36675 );
36676 break;
36677 case 'package':
36678 $deps = $this->buildDepPackageConstraints($depItem, $depType);
36679 $result = array_merge($result, $deps);
36680 break;
36681 case 'extension':
36682 $deps = $this->buildDepExtensionConstraints($depItem, $depType);
36683 $result = array_merge($result, $deps);
36684 break;
36685 case 'subpackage':
36686 $deps = $this->buildDepPackageConstraints($depItem, 'replaces');
36687 $defaultOptionals += $deps;
36688 break;
36689 case 'os':
36690 case 'pearinstaller':
36691 break;
36692 default:
36693 break;
36694 }
36695 }
36696 } elseif ('group' == $depType) {
36697 if ($this->isHash($depTypeGroup)) {
36698 $depTypeGroup = array($depTypeGroup);
36699 }
36700
36701 foreach ($depTypeGroup as $depItem) {
36702 $groupName = $depItem['attribs']['name'];
36703 if (!isset($optionals[$groupName])) {
36704 $optionals[$groupName] = array();
36705 }
36706
36707 if (isset($depItem['subpackage'])) {
36708 $optionals[$groupName] += $this->buildDepPackageConstraints($depItem['subpackage'], 'replaces');
36709 } else {
36710 $result += $this->buildDepPackageConstraints($depItem['package'], 'optional');
36711 }
36712 }
36713 }
36714 }
36715
36716 if (count($defaultOptionals) > 0) {
36717 $optionals['*'] = $defaultOptionals;
36718 }
36719
36720 return new DependencyInfo($result, $optionals);
36721 }
36722
36723
36724
36725
36726
36727
36728
36729
36730 private function buildDepExtensionConstraints($depItem, $depType)
36731 {
36732 if ($this->isHash($depItem)) {
36733 $depItem = array($depItem);
36734 }
36735
36736 $result = array();
36737 foreach ($depItem as $subDepItem) {
36738 $depChannelName = 'ext';
36739 $depPackageName = $subDepItem['name'];
36740 $depVersionConstraint = $this->parse20VersionConstraint($subDepItem);
36741
36742 $result[] = new DependencyConstraint(
36743 $depType,
36744 $depVersionConstraint,
36745 $depChannelName,
36746 $depPackageName
36747 );
36748 }
36749
36750 return $result;
36751 }
36752
36753
36754
36755
36756
36757
36758
36759
36760 private function buildDepPackageConstraints($depItem, $depType)
36761 {
36762 if ($this->isHash($depItem)) {
36763 $depItem = array($depItem);
36764 }
36765
36766 $result = array();
36767 foreach ($depItem as $subDepItem) {
36768 if (!array_key_exists('channel', $subDepItem)) {
36769 $subDepItem['channel'] = $subDepItem['uri'];
36770 }
36771 $depChannelName = $subDepItem['channel'];
36772 $depPackageName = $subDepItem['name'];
36773 $depVersionConstraint = $this->parse20VersionConstraint($subDepItem);
36774 if (isset($subDepItem['conflicts'])) {
36775 $depType = 'conflicts';
36776 }
36777
36778 $result[] = new DependencyConstraint(
36779 $depType,
36780 $depVersionConstraint,
36781 $depChannelName,
36782 $depPackageName
36783 );
36784 }
36785
36786 return $result;
36787 }
36788
36789
36790
36791
36792
36793
36794
36795 private function parse20VersionConstraint(array $data)
36796 {
36797 static $dep20toOperatorMap = array('has' => '==', 'min' => '>=', 'max' => '<=', 'exclude' => '!=');
36798
36799 $versions = array();
36800 $values = array_intersect_key($data, $dep20toOperatorMap);
36801 if (0 == count($values)) {
36802 return '*';
36803 }
36804 if (isset($values['min']) && isset($values['exclude']) && $data['min'] == $data['exclude']) {
36805 $versions[] = '>' . $this->parseVersion($values['min']);
36806 } elseif (isset($values['max']) && isset($values['exclude']) && $data['max'] == $data['exclude']) {
36807 $versions[] = '<' . $this->parseVersion($values['max']);
36808 } else {
36809 foreach ($values as $op => $version) {
36810 if ('exclude' == $op && is_array($version)) {
36811 foreach ($version as $versionPart) {
36812 $versions[] = $dep20toOperatorMap[$op] . $this->parseVersion($versionPart);
36813 }
36814 } else {
36815 $versions[] = $dep20toOperatorMap[$op] . $this->parseVersion($version);
36816 }
36817 }
36818 }
36819
36820 return implode(',', $versions);
36821 }
36822
36823
36824
36825
36826
36827
36828
36829 private function parseVersion($version)
36830 {
36831 if (preg_match('{^v?(\d{1,3})(\.\d+)?(\.\d+)?(\.\d+)?}i', $version, $matches)) {
36832 $version = $matches[1]
36833 .(!empty($matches[2]) ? $matches[2] : '.0')
36834 .(!empty($matches[3]) ? $matches[3] : '.0')
36835 .(!empty($matches[4]) ? $matches[4] : '.0');
36836
36837 return $version;
36838 }
36839
36840 return null;
36841 }
36842
36843
36844
36845
36846
36847
36848
36849 private function isHash(array $array)
36850 {
36851 return !array_key_exists(1, $array) && !array_key_exists(0, $array);
36852 }
36853 }
36854 <?php
36855
36856
36857
36858
36859
36860
36861
36862
36863
36864
36865
36866 namespace Composer\Repository\Pear;
36867
36868
36869
36870
36871
36872
36873 class PackageInfo
36874 {
36875 private $channelName;
36876 private $packageName;
36877 private $license;
36878 private $shortDescription;
36879 private $description;
36880 private $releases;
36881
36882
36883
36884
36885
36886
36887
36888
36889
36890 public function __construct($channelName, $packageName, $license, $shortDescription, $description, $releases)
36891 {
36892 $this->channelName = $channelName;
36893 $this->packageName = $packageName;
36894 $this->license = $license;
36895 $this->shortDescription = $shortDescription;
36896 $this->description = $description;
36897 $this->releases = $releases;
36898 }
36899
36900
36901
36902
36903 public function getChannelName()
36904 {
36905 return $this->channelName;
36906 }
36907
36908
36909
36910
36911 public function getPackageName()
36912 {
36913 return $this->packageName;
36914 }
36915
36916
36917
36918
36919 public function getDescription()
36920 {
36921 return $this->description;
36922 }
36923
36924
36925
36926
36927 public function getShortDescription()
36928 {
36929 return $this->shortDescription;
36930 }
36931
36932
36933
36934
36935 public function getLicense()
36936 {
36937 return $this->license;
36938 }
36939
36940
36941
36942
36943 public function getReleases()
36944 {
36945 return $this->releases;
36946 }
36947 }
36948 <?php
36949
36950
36951
36952
36953
36954
36955
36956
36957
36958
36959
36960 namespace Composer\Repository\Pear;
36961
36962
36963
36964
36965
36966
36967 class ReleaseInfo
36968 {
36969 private $stability;
36970 private $dependencyInfo;
36971
36972
36973
36974
36975
36976 public function __construct($stability, $dependencyInfo)
36977 {
36978 $this->stability = $stability;
36979 $this->dependencyInfo = $dependencyInfo;
36980 }
36981
36982
36983
36984
36985 public function getDependencyInfo()
36986 {
36987 return $this->dependencyInfo;
36988 }
36989
36990
36991
36992
36993 public function getStability()
36994 {
36995 return $this->stability;
36996 }
36997 }
36998 <?php
36999
37000
37001
37002
37003
37004
37005
37006
37007
37008
37009
37010 namespace Composer\Repository;
37011
37012 use Composer\IO\IOInterface;
37013 use Composer\Semver\VersionParser as SemverVersionParser;
37014 use Composer\Package\Version\VersionParser;
37015 use Composer\Repository\Pear\ChannelReader;
37016 use Composer\Package\CompletePackage;
37017 use Composer\Repository\Pear\ChannelInfo;
37018 use Composer\EventDispatcher\EventDispatcher;
37019 use Composer\Package\Link;
37020 use Composer\Semver\Constraint\Constraint;
37021 use Composer\Util\RemoteFilesystem;
37022 use Composer\Config;
37023 use Composer\Factory;
37024
37025
37026
37027
37028
37029
37030
37031
37032
37033
37034 class PearRepository extends ArrayRepository implements ConfigurableRepositoryInterface
37035 {
37036 private $url;
37037 private $io;
37038 private $rfs;
37039 private $versionParser;
37040 private $repoConfig;
37041
37042
37043
37044
37045 private $vendorAlias;
37046
37047 public function __construct(array $repoConfig, IOInterface $io, Config $config, EventDispatcher $dispatcher = null, RemoteFilesystem $rfs = null)
37048 {
37049 parent::__construct();
37050 if (!preg_match('{^https?://}', $repoConfig['url'])) {
37051 $repoConfig['url'] = 'http://'.$repoConfig['url'];
37052 }
37053
37054 $urlBits = parse_url($repoConfig['url']);
37055 if (empty($urlBits['scheme']) || empty($urlBits['host'])) {
37056 throw new \UnexpectedValueException('Invalid url given for PEAR repository: '.$repoConfig['url']);
37057 }
37058
37059 $this->url = rtrim($repoConfig['url'], '/');
37060 $this->io = $io;
37061 $this->rfs = $rfs ?: Factory::createRemoteFilesystem($this->io, $config);
37062 $this->vendorAlias = isset($repoConfig['vendor-alias']) ? $repoConfig['vendor-alias'] : null;
37063 $this->versionParser = new VersionParser();
37064 $this->repoConfig = $repoConfig;
37065 }
37066
37067 public function getRepoConfig()
37068 {
37069 return $this->repoConfig;
37070 }
37071
37072 protected function initialize()
37073 {
37074 parent::initialize();
37075
37076 $this->io->writeError('Initializing PEAR repository '.$this->url);
37077
37078 $reader = new ChannelReader($this->rfs);
37079 try {
37080 $channelInfo = $reader->read($this->url);
37081 } catch (\Exception $e) {
37082 $this->io->writeError('<warning>PEAR repository from '.$this->url.' could not be loaded. '.$e->getMessage().'</warning>');
37083
37084 return;
37085 }
37086 $packages = $this->buildComposerPackages($channelInfo, $this->versionParser);
37087 foreach ($packages as $package) {
37088 $this->addPackage($package);
37089 }
37090 }
37091
37092
37093
37094
37095
37096
37097
37098
37099 private function buildComposerPackages(ChannelInfo $channelInfo, SemverVersionParser $versionParser)
37100 {
37101 $result = array();
37102 foreach ($channelInfo->getPackages() as $packageDefinition) {
37103 foreach ($packageDefinition->getReleases() as $version => $releaseInfo) {
37104 try {
37105 $normalizedVersion = $versionParser->normalize($version);
37106 } catch (\UnexpectedValueException $e) {
37107 $this->io->writeError('Could not load '.$packageDefinition->getPackageName().' '.$version.': '.$e->getMessage(), true, IOInterface::VERBOSE);
37108 continue;
37109 }
37110
37111 $composerPackageName = $this->buildComposerPackageName($packageDefinition->getChannelName(), $packageDefinition->getPackageName());
37112
37113
37114
37115 $urlBits = parse_url($this->url);
37116 $scheme = (isset($urlBits['scheme']) && 'https' === $urlBits['scheme'] && extension_loaded('openssl')) ? 'https' : 'http';
37117 $distUrl = "{$scheme}://{$packageDefinition->getChannelName()}/get/{$packageDefinition->getPackageName()}-{$version}.tgz";
37118
37119 $requires = array();
37120 $suggests = array();
37121 $conflicts = array();
37122 $replaces = array();
37123
37124
37125
37126 if ($channelInfo->getName() == $packageDefinition->getChannelName()) {
37127 $composerPackageAlias = $this->buildComposerPackageName($channelInfo->getAlias(), $packageDefinition->getPackageName());
37128 $aliasConstraint = new Constraint('==', $normalizedVersion);
37129 $replaces[] = new Link($composerPackageName, $composerPackageAlias, $aliasConstraint, 'replaces', (string) $aliasConstraint);
37130 }
37131
37132
37133 if (!empty($this->vendorAlias)
37134 && ($this->vendorAlias != 'pear-'.$channelInfo->getAlias() || $channelInfo->getName() != $packageDefinition->getChannelName())
37135 ) {
37136 $composerPackageAlias = "{$this->vendorAlias}/{$packageDefinition->getPackageName()}";
37137 $aliasConstraint = new Constraint('==', $normalizedVersion);
37138 $replaces[] = new Link($composerPackageName, $composerPackageAlias, $aliasConstraint, 'replaces', (string) $aliasConstraint);
37139 }
37140
37141 foreach ($releaseInfo->getDependencyInfo()->getRequires() as $dependencyConstraint) {
37142 $dependencyPackageName = $this->buildComposerPackageName($dependencyConstraint->getChannelName(), $dependencyConstraint->getPackageName());
37143 $constraint = $versionParser->parseConstraints($dependencyConstraint->getConstraint());
37144 $link = new Link($composerPackageName, $dependencyPackageName, $constraint, $dependencyConstraint->getType(), $dependencyConstraint->getConstraint());
37145 switch ($dependencyConstraint->getType()) {
37146 case 'required':
37147 $requires[] = $link;
37148 break;
37149 case 'conflicts':
37150 $conflicts[] = $link;
37151 break;
37152 case 'replaces':
37153 $replaces[] = $link;
37154 break;
37155 }
37156 }
37157
37158 foreach ($releaseInfo->getDependencyInfo()->getOptionals() as $group => $dependencyConstraints) {
37159 foreach ($dependencyConstraints as $dependencyConstraint) {
37160 $dependencyPackageName = $this->buildComposerPackageName($dependencyConstraint->getChannelName(), $dependencyConstraint->getPackageName());
37161 $suggests[$group.'-'.$dependencyPackageName] = $dependencyConstraint->getConstraint();
37162 }
37163 }
37164
37165 $package = new CompletePackage($composerPackageName, $normalizedVersion, $version);
37166 $package->setType('pear-library');
37167 $package->setDescription($packageDefinition->getDescription());
37168 $package->setLicense(array($packageDefinition->getLicense()));
37169 $package->setDistType('file');
37170 $package->setDistUrl($distUrl);
37171 $package->setAutoload(array('classmap' => array('')));
37172 $package->setIncludePaths(array('/'));
37173 $package->setRequires($requires);
37174 $package->setConflicts($conflicts);
37175 $package->setSuggests($suggests);
37176 $package->setReplaces($replaces);
37177 $result[] = $package;
37178 }
37179 }
37180
37181 return $result;
37182 }
37183
37184 private function buildComposerPackageName($channelName, $packageName)
37185 {
37186 if ('php' === $channelName) {
37187 return "php";
37188 }
37189 if ('ext' === $channelName) {
37190 return "ext-{$packageName}";
37191 }
37192
37193 return "pear-{$channelName}/{$packageName}";
37194 }
37195 }
37196 <?php
37197
37198
37199
37200
37201
37202
37203
37204
37205
37206
37207
37208 namespace Composer\Repository;
37209
37210 use Composer\Composer;
37211 use Composer\Package\CompletePackage;
37212 use Composer\Package\PackageInterface;
37213 use Composer\Package\Version\VersionParser;
37214 use Composer\Plugin\PluginInterface;
37215 use Composer\Util\ProcessExecutor;
37216 use Composer\Util\Silencer;
37217 use Composer\Util\Platform;
37218 use Composer\XdebugHandler\XdebugHandler;
37219 use Symfony\Component\Process\ExecutableFinder;
37220
37221
37222
37223
37224 class PlatformRepository extends ArrayRepository
37225 {
37226 const PLATFORM_PACKAGE_REGEX = '{^(?:php(?:-64bit|-ipv6|-zts|-debug)?|hhvm|(?:ext|lib)-[a-z0-9](?:[_.-]?[a-z0-9]+)*|composer-(?:plugin|runtime)-api)$}iD';
37227
37228 private $versionParser;
37229
37230
37231
37232
37233
37234
37235
37236
37237 private $overrides = array();
37238
37239 private $process;
37240
37241 public function __construct(array $packages = array(), array $overrides = array(), ProcessExecutor $process = null)
37242 {
37243 $this->process = $process === null ? (new ProcessExecutor()) : $process;
37244 foreach ($overrides as $name => $version) {
37245 $this->overrides[strtolower($name)] = array('name' => $name, 'version' => $version);
37246 }
37247 parent::__construct($packages);
37248 }
37249
37250 protected function initialize()
37251 {
37252 parent::initialize();
37253
37254 $this->versionParser = new VersionParser();
37255
37256
37257
37258 foreach ($this->overrides as $override) {
37259
37260 if (!preg_match(self::PLATFORM_PACKAGE_REGEX, $override['name'])) {
37261 throw new \InvalidArgumentException('Invalid platform package name in config.platform: '.$override['name']);
37262 }
37263
37264 $this->addOverriddenPackage($override);
37265 }
37266
37267 $prettyVersion = PluginInterface::PLUGIN_API_VERSION;
37268 $version = $this->versionParser->normalize($prettyVersion);
37269 $composerPluginApi = new CompletePackage('composer-plugin-api', $version, $prettyVersion);
37270 $composerPluginApi->setDescription('The Composer Plugin API');
37271 $this->addPackage($composerPluginApi);
37272
37273 $prettyVersion = Composer::RUNTIME_API_VERSION;
37274 $version = $this->versionParser->normalize($prettyVersion);
37275 $composerRuntimeApi = new CompletePackage('composer-runtime-api', $version, $prettyVersion);
37276 $composerRuntimeApi->setDescription('The Composer Runtime API');
37277 $this->addPackage($composerRuntimeApi);
37278
37279 try {
37280 $prettyVersion = PHP_VERSION;
37281 $version = $this->versionParser->normalize($prettyVersion);
37282 } catch (\UnexpectedValueException $e) {
37283 $prettyVersion = preg_replace('#^([^~+-]+).*$#', '$1', PHP_VERSION);
37284 $version = $this->versionParser->normalize($prettyVersion);
37285 }
37286
37287 $php = new CompletePackage('php', $version, $prettyVersion);
37288 $php->setDescription('The PHP interpreter');
37289 $this->addPackage($php);
37290
37291 if (PHP_DEBUG) {
37292 $phpdebug = new CompletePackage('php-debug', $version, $prettyVersion);
37293 $phpdebug->setDescription('The PHP interpreter, with debugging symbols');
37294 $this->addPackage($phpdebug);
37295 }
37296
37297 if (defined('PHP_ZTS') && PHP_ZTS) {
37298 $phpzts = new CompletePackage('php-zts', $version, $prettyVersion);
37299 $phpzts->setDescription('The PHP interpreter, with Zend Thread Safety');
37300 $this->addPackage($phpzts);
37301 }
37302
37303 if (PHP_INT_SIZE === 8) {
37304 $php64 = new CompletePackage('php-64bit', $version, $prettyVersion);
37305 $php64->setDescription('The PHP interpreter, 64bit');
37306 $this->addPackage($php64);
37307 }
37308
37309
37310
37311 if (defined('AF_INET6') || Silencer::call('inet_pton', '::') !== false) {
37312 $phpIpv6 = new CompletePackage('php-ipv6', $version, $prettyVersion);
37313 $phpIpv6->setDescription('The PHP interpreter, with IPv6 support');
37314 $this->addPackage($phpIpv6);
37315 }
37316
37317 $loadedExtensions = get_loaded_extensions();
37318
37319
37320 foreach ($loadedExtensions as $name) {
37321 if (in_array($name, array('standard', 'Core'))) {
37322 continue;
37323 }
37324
37325 $reflExt = new \ReflectionExtension($name);
37326 $prettyVersion = $reflExt->getVersion();
37327 $this->addExtension($name, $prettyVersion);
37328 }
37329
37330
37331 if (!in_array('xdebug', $loadedExtensions, true) && ($prettyVersion = XdebugHandler::getSkippedVersion())) {
37332 $this->addExtension('xdebug', $prettyVersion);
37333 }
37334
37335
37336
37337
37338 foreach ($loadedExtensions as $name) {
37339 $prettyVersion = null;
37340 $description = 'The '.$name.' PHP library';
37341 switch ($name) {
37342 case 'curl':
37343 $curlVersion = curl_version();
37344 $prettyVersion = $curlVersion['version'];
37345 break;
37346
37347 case 'iconv':
37348 $prettyVersion = ICONV_VERSION;
37349 break;
37350
37351 case 'intl':
37352 $name = 'ICU';
37353 if (defined('INTL_ICU_VERSION')) {
37354 $prettyVersion = INTL_ICU_VERSION;
37355 } else {
37356 $reflector = new \ReflectionExtension('intl');
37357
37358 ob_start();
37359 $reflector->info();
37360 $output = ob_get_clean();
37361
37362 preg_match('/^ICU version => (.*)$/m', $output, $matches);
37363 $prettyVersion = $matches[1];
37364 }
37365
37366 break;
37367
37368 case 'imagick':
37369 $imagick = new \Imagick();
37370 $imageMagickVersion = $imagick->getVersion();
37371
37372
37373 preg_match('/^ImageMagick ([\d.]+)(?:-(\d+))?/', $imageMagickVersion['versionString'], $matches);
37374 if (isset($matches[2])) {
37375 $prettyVersion = "{$matches[1]}.{$matches[2]}";
37376 } else {
37377 $prettyVersion = $matches[1];
37378 }
37379 break;
37380
37381 case 'libxml':
37382 $prettyVersion = LIBXML_DOTTED_VERSION;
37383 break;
37384
37385 case 'openssl':
37386 $prettyVersion = preg_replace_callback('{^(?:OpenSSL|LibreSSL)?\s*([0-9.]+)([a-z]*).*}i', function ($match) {
37387 if (empty($match[2])) {
37388 return $match[1];
37389 }
37390
37391
37392
37393
37394 if (!preg_match('{^z*[a-z]$}', $match[2])) {
37395
37396 return 0;
37397 }
37398
37399 $len = strlen($match[2]);
37400 $patchVersion = ($len - 1) * 26; 
37401 $patchVersion += ord($match[2][$len - 1]) - 96;
37402
37403 return $match[1].'.'.$patchVersion;
37404 }, OPENSSL_VERSION_TEXT);
37405
37406 $description = OPENSSL_VERSION_TEXT;
37407 break;
37408
37409 case 'pcre':
37410 $prettyVersion = preg_replace('{^(\S+).*}', '$1', PCRE_VERSION);
37411 break;
37412
37413 case 'uuid':
37414 $prettyVersion = phpversion('uuid');
37415 break;
37416
37417 case 'xsl':
37418 $prettyVersion = LIBXSLT_DOTTED_VERSION;
37419 break;
37420
37421 default:
37422
37423 continue 2;
37424 }
37425
37426 try {
37427 $version = $this->versionParser->normalize($prettyVersion);
37428 } catch (\UnexpectedValueException $e) {
37429 continue;
37430 }
37431
37432 $lib = new CompletePackage('lib-'.$name, $version, $prettyVersion);
37433 $lib->setDescription($description);
37434 $this->addPackage($lib);
37435 }
37436
37437 $hhvmVersion = defined('HHVM_VERSION') ? HHVM_VERSION : null;
37438 if ($hhvmVersion === null && !Platform::isWindows()) {
37439 $finder = new ExecutableFinder();
37440 $hhvm = $finder->find('hhvm');
37441 if ($hhvm !== null) {
37442 $exitCode = $this->process->execute(
37443 ProcessExecutor::escape($hhvm).
37444 ' --php -d hhvm.jit=0 -r "echo HHVM_VERSION;" 2>/dev/null',
37445 $hhvmVersion
37446 );
37447 if ($exitCode !== 0) {
37448 $hhvmVersion = null;
37449 }
37450 }
37451 }
37452 if ($hhvmVersion) {
37453 try {
37454 $prettyVersion = $hhvmVersion;
37455 $version = $this->versionParser->normalize($prettyVersion);
37456 } catch (\UnexpectedValueException $e) {
37457 $prettyVersion = preg_replace('#^([^~+-]+).*$#', '$1', $hhvmVersion);
37458 $version = $this->versionParser->normalize($prettyVersion);
37459 }
37460
37461 $hhvm = new CompletePackage('hhvm', $version, $prettyVersion);
37462 $hhvm->setDescription('The HHVM Runtime (64bit)');
37463 $this->addPackage($hhvm);
37464 }
37465 }
37466
37467
37468
37469
37470 public function addPackage(PackageInterface $package)
37471 {
37472
37473 if (isset($this->overrides[$package->getName()])) {
37474 $overrider = $this->findPackage($package->getName(), '*');
37475 if ($package->getVersion() === $overrider->getVersion()) {
37476 $actualText = 'same as actual';
37477 } else {
37478 $actualText = 'actual: '.$package->getPrettyVersion();
37479 }
37480 $overrider->setDescription($overrider->getDescription().' ('.$actualText.')');
37481
37482 return;
37483 }
37484
37485
37486 if (isset($this->overrides['php']) && 0 === strpos($package->getName(), 'php-')) {
37487 $overrider = $this->addOverriddenPackage($this->overrides['php'], $package->getPrettyName());
37488 if ($package->getVersion() === $overrider->getVersion()) {
37489 $actualText = 'same as actual';
37490 } else {
37491 $actualText = 'actual: '.$package->getPrettyVersion();
37492 }
37493 $overrider->setDescription($overrider->getDescription().' ('.$actualText.')');
37494
37495 return;
37496 }
37497
37498 parent::addPackage($package);
37499 }
37500
37501 private function addOverriddenPackage(array $override, $name = null)
37502 {
37503 $version = $this->versionParser->normalize($override['version']);
37504 $package = new CompletePackage($name ?: $override['name'], $version, $override['version']);
37505 $package->setDescription('Package overridden via config.platform');
37506 $package->setExtra(array('config.platform' => true));
37507 parent::addPackage($package);
37508
37509 return $package;
37510 }
37511
37512
37513
37514
37515
37516
37517
37518 private function addExtension($name, $prettyVersion)
37519 {
37520 $extraDescription = null;
37521
37522 try {
37523 $version = $this->versionParser->normalize($prettyVersion);
37524 } catch (\UnexpectedValueException $e) {
37525 $extraDescription = ' (actual version: '.$prettyVersion.')';
37526 if (preg_match('{^(\d+\.\d+\.\d+(?:\.\d+)?)}', $prettyVersion, $match)) {
37527 $prettyVersion = $match[1];
37528 } else {
37529 $prettyVersion = '0';
37530 }
37531 $version = $this->versionParser->normalize($prettyVersion);
37532 }
37533
37534 $packageName = $this->buildPackageName($name);
37535 $ext = new CompletePackage($packageName, $version, $prettyVersion);
37536 $ext->setDescription('The '.$name.' PHP extension'.$extraDescription);
37537 $this->addPackage($ext);
37538 }
37539
37540 private function buildPackageName($name)
37541 {
37542 return 'ext-' . str_replace(' ', '-', $name);
37543 }
37544 }
37545 <?php
37546
37547
37548
37549
37550
37551
37552
37553
37554
37555
37556
37557 namespace Composer\Repository;
37558
37559 use Composer\Factory;
37560 use Composer\IO\IOInterface;
37561 use Composer\Config;
37562 use Composer\EventDispatcher\EventDispatcher;
37563 use Composer\Util\RemoteFilesystem;
37564 use Composer\Json\JsonFile;
37565
37566
37567
37568
37569 class RepositoryFactory
37570 {
37571
37572
37573
37574
37575
37576
37577
37578 public static function configFromString(IOInterface $io, Config $config, $repository, $allowFilesystem = false)
37579 {
37580 if (0 === strpos($repository, 'http')) {
37581 $repoConfig = array('type' => 'composer', 'url' => $repository);
37582 } elseif ("json" === pathinfo($repository, PATHINFO_EXTENSION)) {
37583 $json = new JsonFile($repository, Factory::createRemoteFilesystem($io, $config));
37584 $data = $json->read();
37585 if (!empty($data['packages']) || !empty($data['includes']) || !empty($data['provider-includes'])) {
37586 $repoConfig = array('type' => 'composer', 'url' => 'file://' . strtr(realpath($repository), '\\', '/'));
37587 } elseif ($allowFilesystem) {
37588 $repoConfig = array('type' => 'filesystem', 'json' => $json);
37589 } else {
37590 throw new \InvalidArgumentException("Invalid repository URL ($repository) given. This file does not contain a valid composer repository.");
37591 }
37592 } elseif ('{' === substr($repository, 0, 1)) {
37593
37594 $repoConfig = JsonFile::parseJson($repository);
37595 } else {
37596 throw new \InvalidArgumentException("Invalid repository url ($repository) given. Has to be a .json file, an http url or a JSON object.");
37597 }
37598
37599 return $repoConfig;
37600 }
37601
37602
37603
37604
37605
37606
37607
37608
37609 public static function fromString(IOInterface $io, Config $config, $repository, $allowFilesystem = false, RepositoryManager $rm = null)
37610 {
37611 $repoConfig = static::configFromString($io, $config, $repository, $allowFilesystem);
37612
37613 return static::createRepo($io, $config, $repoConfig, $rm);
37614 }
37615
37616
37617
37618
37619
37620
37621
37622 public static function createRepo(IOInterface $io, Config $config, array $repoConfig, RepositoryManager $rm = null)
37623 {
37624 if (!$rm) {
37625 $rm = static::manager($io, $config, null, Factory::createRemoteFilesystem($io, $config));
37626 }
37627 $repos = static::createRepos($rm, array($repoConfig));
37628
37629 return reset($repos);
37630 }
37631
37632
37633
37634
37635
37636
37637
37638 public static function defaultRepos(IOInterface $io = null, Config $config = null, RepositoryManager $rm = null)
37639 {
37640 if (!$config) {
37641 $config = Factory::createConfig($io);
37642 }
37643 if ($io) {
37644 $io->loadConfiguration($config);
37645 }
37646 if (!$rm) {
37647 if (!$io) {
37648 throw new \InvalidArgumentException('This function requires either an IOInterface or a RepositoryManager');
37649 }
37650 $rm = static::manager($io, $config, null, Factory::createRemoteFilesystem($io, $config));
37651 }
37652
37653 return static::createRepos($rm, $config->getRepositories());
37654 }
37655
37656
37657
37658
37659
37660
37661
37662
37663 public static function manager(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, RemoteFilesystem $rfs = null)
37664 {
37665 $rm = new RepositoryManager($io, $config, $eventDispatcher, $rfs);
37666 $rm->setRepositoryClass('composer', 'Composer\Repository\ComposerRepository');
37667 $rm->setRepositoryClass('vcs', 'Composer\Repository\VcsRepository');
37668 $rm->setRepositoryClass('package', 'Composer\Repository\PackageRepository');
37669 $rm->setRepositoryClass('pear', 'Composer\Repository\PearRepository');
37670 $rm->setRepositoryClass('git', 'Composer\Repository\VcsRepository');
37671 $rm->setRepositoryClass('git-bitbucket', 'Composer\Repository\VcsRepository');
37672 $rm->setRepositoryClass('github', 'Composer\Repository\VcsRepository');
37673 $rm->setRepositoryClass('gitlab', 'Composer\Repository\VcsRepository');
37674 $rm->setRepositoryClass('svn', 'Composer\Repository\VcsRepository');
37675 $rm->setRepositoryClass('fossil', 'Composer\Repository\VcsRepository');
37676 $rm->setRepositoryClass('perforce', 'Composer\Repository\VcsRepository');
37677 $rm->setRepositoryClass('hg', 'Composer\Repository\VcsRepository');
37678 $rm->setRepositoryClass('hg-bitbucket', 'Composer\Repository\VcsRepository');
37679 $rm->setRepositoryClass('artifact', 'Composer\Repository\ArtifactRepository');
37680 $rm->setRepositoryClass('path', 'Composer\Repository\PathRepository');
37681
37682 return $rm;
37683 }
37684
37685
37686
37687
37688 private static function createRepos(RepositoryManager $rm, array $repoConfigs)
37689 {
37690 $repos = array();
37691
37692 foreach ($repoConfigs as $index => $repo) {
37693 if (is_string($repo)) {
37694 throw new \UnexpectedValueException('"repositories" should be an array of repository definitions, only a single repository was given');
37695 }
37696 if (!is_array($repo)) {
37697 throw new \UnexpectedValueException('Repository "'.$index.'" ('.json_encode($repo).') should be an array, '.gettype($repo).' given');
37698 }
37699 if (!isset($repo['type'])) {
37700 throw new \UnexpectedValueException('Repository "'.$index.'" ('.json_encode($repo).') must have a type defined');
37701 }
37702
37703 $name = self::generateRepositoryName($index, $repo, $repos);
37704 if ($repo['type'] === 'filesystem') {
37705 $repos[$name] = new FilesystemRepository($repo['json']);
37706 } else {
37707 $repos[$name] = $rm->createRepository($repo['type'], $repo, $index);
37708 }
37709 }
37710
37711 return $repos;
37712 }
37713
37714 public static function generateRepositoryName($index, array $repo, array $existingRepos)
37715 {
37716 $name = is_int($index) && isset($repo['url']) ? preg_replace('{^https?://}i', '', $repo['url']) : $index;
37717 while (isset($existingRepos[$name])) {
37718 $name .= '2';
37719 }
37720
37721 return $name;
37722 }
37723 }
37724 <?php
37725
37726
37727
37728
37729
37730
37731
37732
37733
37734
37735
37736 namespace Composer\Repository;
37737
37738 use Composer\Package\PackageInterface;
37739
37740
37741
37742
37743
37744
37745
37746
37747 interface RepositoryInterface extends \Countable
37748 {
37749 const SEARCH_FULLTEXT = 0;
37750 const SEARCH_NAME = 1;
37751
37752
37753
37754
37755
37756
37757
37758
37759 public function hasPackage(PackageInterface $package);
37760
37761
37762
37763
37764
37765
37766
37767
37768
37769 public function findPackage($name, $constraint);
37770
37771
37772
37773
37774
37775
37776
37777
37778
37779 public function findPackages($name, $constraint = null);
37780
37781
37782
37783
37784
37785
37786 public function getPackages();
37787
37788
37789
37790
37791
37792
37793
37794
37795
37796 public function search($query, $mode = 0);
37797 }
37798 <?php
37799
37800
37801
37802
37803
37804
37805
37806
37807
37808
37809
37810 namespace Composer\Repository;
37811
37812 use Composer\IO\IOInterface;
37813 use Composer\Config;
37814 use Composer\EventDispatcher\EventDispatcher;
37815 use Composer\Package\PackageInterface;
37816 use Composer\Util\RemoteFilesystem;
37817
37818
37819
37820
37821
37822
37823
37824
37825 class RepositoryManager
37826 {
37827 private $localRepository;
37828 private $repositories = array();
37829 private $repositoryClasses = array();
37830 private $io;
37831 private $config;
37832 private $eventDispatcher;
37833 private $rfs;
37834
37835 public function __construct(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, RemoteFilesystem $rfs = null)
37836 {
37837 $this->io = $io;
37838 $this->config = $config;
37839 $this->eventDispatcher = $eventDispatcher;
37840 $this->rfs = $rfs;
37841 }
37842
37843
37844
37845
37846
37847
37848
37849
37850
37851 public function findPackage($name, $constraint)
37852 {
37853 foreach ($this->repositories as $repository) {
37854
37855 if ($package = $repository->findPackage($name, $constraint)) {
37856 return $package;
37857 }
37858 }
37859
37860 return null;
37861 }
37862
37863
37864
37865
37866
37867
37868
37869
37870
37871 public function findPackages($name, $constraint)
37872 {
37873 $packages = array();
37874
37875 foreach ($this->getRepositories() as $repository) {
37876 $packages = array_merge($packages, $repository->findPackages($name, $constraint));
37877 }
37878
37879 return $packages;
37880 }
37881
37882
37883
37884
37885
37886
37887 public function addRepository(RepositoryInterface $repository)
37888 {
37889 $this->repositories[] = $repository;
37890 }
37891
37892
37893
37894
37895
37896
37897
37898
37899 public function prependRepository(RepositoryInterface $repository)
37900 {
37901 array_unshift($this->repositories, $repository);
37902 }
37903
37904
37905
37906
37907
37908
37909
37910
37911
37912
37913 public function createRepository($type, $config, $name = null)
37914 {
37915 if (!isset($this->repositoryClasses[$type])) {
37916 throw new \InvalidArgumentException('Repository type is not registered: '.$type);
37917 }
37918
37919 if (isset($config['packagist']) && false === $config['packagist']) {
37920 $this->io->writeError('<warning>Repository "'.$name.'" ('.json_encode($config).') has a packagist key which should be in its own repository definition</warning>');
37921 }
37922
37923 $class = $this->repositoryClasses[$type];
37924
37925 $reflMethod = new \ReflectionMethod($class, '__construct');
37926 $params = $reflMethod->getParameters();
37927 if (isset($params[4])) {
37928 $paramType = null;
37929 if (\PHP_VERSION_ID >= 70000) {
37930 $reflectionType = $params[4]->getType();
37931 if ($reflectionType) {
37932 $paramType = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : (string)$reflectionType;
37933 }
37934 } else {
37935 $paramType = $params[4]->getClass() ? $params[4]->getClass()->getName() : null;
37936 }
37937
37938 if ($paramType === 'Composer\Util\RemoteFilesystem') {
37939 return new $class($config, $this->io, $this->config, $this->eventDispatcher, $this->rfs);
37940 }
37941 }
37942
37943 return new $class($config, $this->io, $this->config, $this->eventDispatcher);
37944 }
37945
37946
37947
37948
37949
37950
37951
37952 public function setRepositoryClass($type, $class)
37953 {
37954 $this->repositoryClasses[$type] = $class;
37955 }
37956
37957
37958
37959
37960
37961
37962 public function getRepositories()
37963 {
37964 return $this->repositories;
37965 }
37966
37967
37968
37969
37970
37971
37972 public function setLocalRepository(WritableRepositoryInterface $repository)
37973 {
37974 $this->localRepository = $repository;
37975 }
37976
37977
37978
37979
37980
37981
37982 public function getLocalRepository()
37983 {
37984 return $this->localRepository;
37985 }
37986 }
37987 <?php
37988
37989
37990
37991
37992
37993
37994
37995
37996
37997
37998
37999 namespace Composer\Repository;
38000
38001
38002
38003
38004
38005
38006 class RepositorySecurityException extends \Exception
38007 {
38008 }
38009 <?php
38010
38011
38012
38013
38014
38015
38016
38017
38018
38019
38020
38021 namespace Composer\Repository\Vcs;
38022
38023 use Composer\Cache;
38024 use Composer\Downloader\TransportException;
38025 use Composer\Json\JsonFile;
38026 use Composer\Util\Bitbucket;
38027
38028 abstract class BitbucketDriver extends VcsDriver
38029 {
38030
38031 protected $cache;
38032 protected $owner;
38033 protected $repository;
38034 protected $hasIssues;
38035 protected $rootIdentifier;
38036 protected $tags;
38037 protected $branches;
38038 protected $infoCache = array();
38039 protected $branchesUrl = '';
38040 protected $tagsUrl = '';
38041 protected $homeUrl = '';
38042 protected $website = '';
38043 protected $cloneHttpsUrl = '';
38044
38045
38046
38047
38048 protected $fallbackDriver;
38049
38050 protected $vcsType;
38051
38052
38053
38054
38055 public function initialize()
38056 {
38057 preg_match('#^https?://bitbucket\.org/([^/]+)/([^/]+?)(\.git|/?)$#i', $this->url, $match);
38058 $this->owner = $match[1];
38059 $this->repository = $match[2];
38060 $this->originUrl = 'bitbucket.org';
38061 $this->cache = new Cache(
38062 $this->io,
38063 implode('/', array(
38064 $this->config->get('cache-repo-dir'),
38065 $this->originUrl,
38066 $this->owner,
38067 $this->repository,
38068 ))
38069 );
38070 }
38071
38072
38073
38074
38075 public function getUrl()
38076 {
38077 if ($this->fallbackDriver) {
38078 return $this->fallbackDriver->getUrl();
38079 }
38080
38081 return $this->cloneHttpsUrl;
38082 }
38083
38084
38085
38086
38087
38088
38089
38090 protected function getRepoData()
38091 {
38092 $resource = sprintf(
38093 'https://api.bitbucket.org/2.0/repositories/%s/%s?%s',
38094 $this->owner,
38095 $this->repository,
38096 http_build_query(
38097 array('fields' => '-project,-owner'),
38098 null,
38099 '&'
38100 )
38101 );
38102
38103 $repoData = JsonFile::parseJson($this->getContentsWithOAuthCredentials($resource, true), $resource);
38104 if ($this->fallbackDriver) {
38105 return false;
38106 }
38107 $this->parseCloneUrls($repoData['links']['clone']);
38108
38109 $this->hasIssues = !empty($repoData['has_issues']);
38110 $this->branchesUrl = $repoData['links']['branches']['href'];
38111 $this->tagsUrl = $repoData['links']['tags']['href'];
38112 $this->homeUrl = $repoData['links']['html']['href'];
38113 $this->website = $repoData['website'];
38114 $this->vcsType = $repoData['scm'];
38115
38116 return true;
38117 }
38118
38119
38120
38121
38122 public function getComposerInformation($identifier)
38123 {
38124 if ($this->fallbackDriver) {
38125 return $this->fallbackDriver->getComposerInformation($identifier);
38126 }
38127
38128 if (!isset($this->infoCache[$identifier])) {
38129 if ($this->shouldCache($identifier) && $res = $this->cache->read($identifier)) {
38130 $composer = JsonFile::parseJson($res);
38131 } else {
38132 $composer = $this->getBaseComposerInformation($identifier);
38133
38134 if ($this->shouldCache($identifier)) {
38135 $this->cache->write($identifier, json_encode($composer));
38136 }
38137 }
38138
38139 if ($composer) {
38140
38141 if (!isset($composer['support']['source'])) {
38142 $label = array_search(
38143 $identifier,
38144 $this->getTags()
38145 ) ?: array_search(
38146 $identifier,
38147 $this->getBranches()
38148 ) ?: $identifier;
38149
38150 if (array_key_exists($label, $tags = $this->getTags())) {
38151 $hash = $tags[$label];
38152 } elseif (array_key_exists($label, $branches = $this->getBranches())) {
38153 $hash = $branches[$label];
38154 }
38155
38156 if (! isset($hash)) {
38157 $composer['support']['source'] = sprintf(
38158 'https://%s/%s/%s/src',
38159 $this->originUrl,
38160 $this->owner,
38161 $this->repository
38162 );
38163 } else {
38164 $composer['support']['source'] = sprintf(
38165 'https://%s/%s/%s/src/%s/?at=%s',
38166 $this->originUrl,
38167 $this->owner,
38168 $this->repository,
38169 $hash,
38170 $label
38171 );
38172 }
38173 }
38174 if (!isset($composer['support']['issues']) && $this->hasIssues) {
38175 $composer['support']['issues'] = sprintf(
38176 'https://%s/%s/%s/issues',
38177 $this->originUrl,
38178 $this->owner,
38179 $this->repository
38180 );
38181 }
38182 if (!isset($composer['homepage'])) {
38183 $composer['homepage'] = empty($this->website) ? $this->homeUrl : $this->website;
38184 }
38185 }
38186
38187 $this->infoCache[$identifier] = $composer;
38188 }
38189
38190 return $this->infoCache[$identifier];
38191 }
38192
38193
38194
38195
38196 public function getFileContent($file, $identifier)
38197 {
38198 if ($this->fallbackDriver) {
38199 return $this->fallbackDriver->getFileContent($file, $identifier);
38200 }
38201
38202 if (strpos($identifier, '/') !== false) {
38203 $branches = $this->getBranches();
38204 if (isset($branches[$identifier])) {
38205 $identifier = $branches[$identifier];
38206 }
38207 }
38208
38209 $resource = sprintf(
38210 'https://api.bitbucket.org/2.0/repositories/%s/%s/src/%s/%s',
38211 $this->owner,
38212 $this->repository,
38213 $identifier,
38214 $file
38215 );
38216
38217 return $this->getContentsWithOAuthCredentials($resource);
38218 }
38219
38220
38221
38222
38223 public function getChangeDate($identifier)
38224 {
38225 if ($this->fallbackDriver) {
38226 return $this->fallbackDriver->getChangeDate($identifier);
38227 }
38228
38229 if (strpos($identifier, '/') !== false) {
38230 $branches = $this->getBranches();
38231 if (isset($branches[$identifier])) {
38232 $identifier = $branches[$identifier];
38233 }
38234 }
38235
38236 $resource = sprintf(
38237 'https://api.bitbucket.org/2.0/repositories/%s/%s/commit/%s?fields=date',
38238 $this->owner,
38239 $this->repository,
38240 $identifier
38241 );
38242 $commit = JsonFile::parseJson($this->getContentsWithOAuthCredentials($resource), $resource);
38243
38244 return new \DateTime($commit['date']);
38245 }
38246
38247
38248
38249
38250 public function getSource($identifier)
38251 {
38252 if ($this->fallbackDriver) {
38253 return $this->fallbackDriver->getSource($identifier);
38254 }
38255
38256 return array('type' => $this->vcsType, 'url' => $this->getUrl(), 'reference' => $identifier);
38257 }
38258
38259
38260
38261
38262 public function getDist($identifier)
38263 {
38264 if ($this->fallbackDriver) {
38265 return $this->fallbackDriver->getDist($identifier);
38266 }
38267
38268 $url = sprintf(
38269 'https://bitbucket.org/%s/%s/get/%s.zip',
38270 $this->owner,
38271 $this->repository,
38272 $identifier
38273 );
38274
38275 return array('type' => 'zip', 'url' => $url, 'reference' => $identifier, 'shasum' => '');
38276 }
38277
38278
38279
38280
38281 public function getTags()
38282 {
38283 if ($this->fallbackDriver) {
38284 return $this->fallbackDriver->getTags();
38285 }
38286
38287 if (null === $this->tags) {
38288 $this->tags = array();
38289 $resource = sprintf(
38290 '%s?%s',
38291 $this->tagsUrl,
38292 http_build_query(
38293 array(
38294 'pagelen' => 100,
38295 'fields' => 'values.name,values.target.hash,next',
38296 'sort' => '-target.date',
38297 ),
38298 null,
38299 '&'
38300 )
38301 );
38302 $hasNext = true;
38303 while ($hasNext) {
38304 $tagsData = JsonFile::parseJson($this->getContentsWithOAuthCredentials($resource), $resource);
38305 foreach ($tagsData['values'] as $data) {
38306 $this->tags[$data['name']] = $data['target']['hash'];
38307 }
38308 if (empty($tagsData['next'])) {
38309 $hasNext = false;
38310 } else {
38311 $resource = $tagsData['next'];
38312 }
38313 }
38314 if ($this->vcsType === 'hg') {
38315 unset($this->tags['tip']);
38316 }
38317 }
38318
38319 return $this->tags;
38320 }
38321
38322
38323
38324
38325 public function getBranches()
38326 {
38327 if ($this->fallbackDriver) {
38328 return $this->fallbackDriver->getBranches();
38329 }
38330
38331 if (null === $this->branches) {
38332 $this->branches = array();
38333 $resource = sprintf(
38334 '%s?%s',
38335 $this->branchesUrl,
38336 http_build_query(
38337 array(
38338 'pagelen' => 100,
38339 'fields' => 'values.name,values.target.hash,values.heads,next',
38340 'sort' => '-target.date',
38341 ),
38342 null,
38343 '&'
38344 )
38345 );
38346 $hasNext = true;
38347 while ($hasNext) {
38348 $branchData = JsonFile::parseJson($this->getContentsWithOAuthCredentials($resource), $resource);
38349 foreach ($branchData['values'] as $data) {
38350
38351 if ($this->vcsType === 'hg' && empty($data['heads'])) {
38352 continue;
38353 }
38354
38355 $this->branches[$data['name']] = $data['target']['hash'];
38356 }
38357 if (empty($branchData['next'])) {
38358 $hasNext = false;
38359 } else {
38360 $resource = $branchData['next'];
38361 }
38362 }
38363 }
38364
38365 return $this->branches;
38366 }
38367
38368
38369
38370
38371
38372
38373
38374
38375
38376 protected function getContentsWithOAuthCredentials($url, $fetchingRepoData = false)
38377 {
38378 try {
38379 return parent::getContents($url);
38380 } catch (TransportException $e) {
38381 $bitbucketUtil = new Bitbucket($this->io, $this->config, $this->process, $this->remoteFilesystem);
38382
38383 if (403 === $e->getCode() || (401 === $e->getCode() && strpos($e->getMessage(), 'Could not authenticate against') === 0)) {
38384 if (!$this->io->hasAuthentication($this->originUrl)
38385 && $bitbucketUtil->authorizeOAuth($this->originUrl)
38386 ) {
38387 return parent::getContents($url);
38388 }
38389
38390 if (!$this->io->isInteractive() && $fetchingRepoData) {
38391 return $this->attemptCloneFallback();
38392 }
38393 }
38394
38395 throw $e;
38396 }
38397 }
38398
38399
38400
38401
38402
38403
38404 abstract protected function generateSshUrl();
38405
38406 protected function attemptCloneFallback()
38407 {
38408 try {
38409 $this->setupFallbackDriver($this->generateSshUrl());
38410 } catch (\RuntimeException $e) {
38411 $this->fallbackDriver = null;
38412
38413 $this->io->writeError(
38414 '<error>Failed to clone the ' . $this->generateSshUrl() . ' repository, try running in interactive mode'
38415 . ' so that you can enter your Bitbucket OAuth consumer credentials</error>'
38416 );
38417 throw $e;
38418 }
38419 }
38420
38421
38422
38423
38424
38425 abstract protected function setupFallbackDriver($url);
38426
38427
38428
38429
38430
38431 protected function parseCloneUrls(array $cloneLinks)
38432 {
38433 foreach ($cloneLinks as $cloneLink) {
38434 if ($cloneLink['name'] === 'https') {
38435
38436
38437 $this->cloneHttpsUrl = preg_replace('/https:\/\/([^@]+@)?/', 'https://', $cloneLink['href']);
38438 }
38439 }
38440 }
38441
38442
38443
38444
38445 protected function getMainBranchData()
38446 {
38447 $resource = sprintf(
38448 'https://api.bitbucket.org/2.0/repositories/%s/%s?fields=mainbranch',
38449 $this->owner,
38450 $this->repository
38451 );
38452
38453 $data = JsonFile::parseJson($this->getContentsWithOAuthCredentials($resource), $resource);
38454 if (isset($data['mainbranch'])) {
38455 return $data['mainbranch'];
38456 }
38457
38458 return null;
38459 }
38460 }
38461 <?php
38462
38463
38464
38465
38466
38467
38468
38469
38470
38471
38472
38473 namespace Composer\Repository\Vcs;
38474
38475 use Composer\Cache;
38476 use Composer\Config;
38477 use Composer\Util\ProcessExecutor;
38478 use Composer\Util\Filesystem;
38479 use Composer\IO\IOInterface;
38480
38481
38482
38483
38484 class FossilDriver extends VcsDriver
38485 {
38486 protected $tags;
38487 protected $branches;
38488 protected $rootIdentifier;
38489 protected $repoFile;
38490 protected $checkoutDir;
38491 protected $infoCache = array();
38492
38493
38494
38495
38496 public function initialize()
38497 {
38498
38499 $this->checkFossil();
38500
38501
38502 $this->config->prohibitUrlByConfig($this->url, $this->io);
38503
38504
38505
38506 if (Filesystem::isLocalPath($this->url) && is_dir($this->url)) {
38507 $this->checkoutDir = $this->url;
38508 } else {
38509 if (!Cache::isUsable($this->config->get('cache-repo-dir')) || !Cache::isUsable($this->config->get('cache-vcs-dir'))) {
38510 throw new \RuntimeException('FossilDriver requires a usable cache directory, and it looks like you set it to be disabled');
38511 }
38512
38513 $localName = preg_replace('{[^a-z0-9]}i', '-', $this->url);
38514 $this->repoFile = $this->config->get('cache-repo-dir') . '/' . $localName . '.fossil';
38515 $this->checkoutDir = $this->config->get('cache-vcs-dir') . '/' . $localName . '/';
38516
38517 $this->updateLocalRepo();
38518 }
38519
38520 $this->getTags();
38521 $this->getBranches();
38522 }
38523
38524
38525
38526
38527 protected function checkFossil()
38528 {
38529 if (0 !== $this->process->execute('fossil version', $ignoredOutput)) {
38530 throw new \RuntimeException("fossil was not found, check that it is installed and in your PATH env.\n\n" . $this->process->getErrorOutput());
38531 }
38532 }
38533
38534
38535
38536
38537 protected function updateLocalRepo()
38538 {
38539 $fs = new Filesystem();
38540 $fs->ensureDirectoryExists($this->checkoutDir);
38541
38542 if (!is_writable(dirname($this->checkoutDir))) {
38543 throw new \RuntimeException('Can not clone '.$this->url.' to access package information. The "'.$this->checkoutDir.'" directory is not writable by the current user.');
38544 }
38545
38546
38547 if (is_file($this->repoFile) && is_dir($this->checkoutDir) && 0 === $this->process->execute('fossil info', $output, $this->checkoutDir)) {
38548 if (0 !== $this->process->execute('fossil pull', $output, $this->checkoutDir)) {
38549 $this->io->writeError('<error>Failed to update '.$this->url.', package information from this repository may be outdated ('.$this->process->getErrorOutput().')</error>');
38550 }
38551 } else {
38552
38553 $fs->removeDirectory($this->checkoutDir);
38554 $fs->remove($this->repoFile);
38555
38556 $fs->ensureDirectoryExists($this->checkoutDir);
38557
38558 if (0 !== $this->process->execute(sprintf('fossil clone -- %s %s', ProcessExecutor::escape($this->url), ProcessExecutor::escape($this->repoFile)), $output)) {
38559 $output = $this->process->getErrorOutput();
38560
38561 throw new \RuntimeException('Failed to clone '.$this->url.' to repository ' . $this->repoFile . "\n\n" .$output);
38562 }
38563
38564 if (0 !== $this->process->execute(sprintf('fossil open --nested -- %s', ProcessExecutor::escape($this->repoFile)), $output, $this->checkoutDir)) {
38565 $output = $this->process->getErrorOutput();
38566
38567 throw new \RuntimeException('Failed to open repository '.$this->repoFile.' in ' . $this->checkoutDir . "\n\n" .$output);
38568 }
38569 }
38570 }
38571
38572
38573
38574
38575 public function getRootIdentifier()
38576 {
38577 if (null === $this->rootIdentifier) {
38578 $this->rootIdentifier = 'trunk';
38579 }
38580
38581 return $this->rootIdentifier;
38582 }
38583
38584
38585
38586
38587 public function getUrl()
38588 {
38589 return $this->url;
38590 }
38591
38592
38593
38594
38595 public function getSource($identifier)
38596 {
38597 return array('type' => 'fossil', 'url' => $this->getUrl(), 'reference' => $identifier);
38598 }
38599
38600
38601
38602
38603 public function getDist($identifier)
38604 {
38605 return null;
38606 }
38607
38608
38609
38610
38611 public function getFileContent($file, $identifier)
38612 {
38613 $command = sprintf('fossil cat -r %s -- %s', ProcessExecutor::escape($identifier), ProcessExecutor::escape($file));
38614 $this->process->execute($command, $content, $this->checkoutDir);
38615
38616 if (!trim($content)) {
38617 return null;
38618 }
38619
38620 return $content;
38621 }
38622
38623
38624
38625
38626 public function getChangeDate($identifier)
38627 {
38628 $this->process->execute('fossil finfo -b -n 1 composer.json', $output, $this->checkoutDir);
38629 list($ckout, $date, $message) = explode(' ', trim($output), 3);
38630
38631 return new \DateTime($date, new \DateTimeZone('UTC'));
38632 }
38633
38634
38635
38636
38637 public function getTags()
38638 {
38639 if (null === $this->tags) {
38640 $tags = array();
38641
38642 $this->process->execute('fossil tag list', $output, $this->checkoutDir);
38643 foreach ($this->process->splitLines($output) as $tag) {
38644 $tags[$tag] = $tag;
38645 }
38646
38647 $this->tags = $tags;
38648 }
38649
38650 return $this->tags;
38651 }
38652
38653
38654
38655
38656 public function getBranches()
38657 {
38658 if (null === $this->branches) {
38659 $branches = array();
38660 $bookmarks = array();
38661
38662 $this->process->execute('fossil branch list', $output, $this->checkoutDir);
38663 foreach ($this->process->splitLines($output) as $branch) {
38664 $branch = trim(preg_replace('/^\*/', '', trim($branch)));
38665 $branches[$branch] = $branch;
38666 }
38667
38668 $this->branches = $branches;
38669 }
38670
38671 return $this->branches;
38672 }
38673
38674
38675
38676
38677 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
38678 {
38679 if (preg_match('#(^(?:https?|ssh)://(?:[^@]@)?(?:chiselapp\.com|fossil\.))#i', $url)) {
38680 return true;
38681 }
38682
38683 if (preg_match('!/fossil/|\.fossil!', $url)) {
38684 return true;
38685 }
38686
38687
38688 if (Filesystem::isLocalPath($url)) {
38689 $url = Filesystem::getPlatformPath($url);
38690 if (!is_dir($url)) {
38691 return false;
38692 }
38693
38694 $process = new ProcessExecutor($io);
38695
38696 if ($process->execute('fossil info', $output, $url) === 0) {
38697 return true;
38698 }
38699 }
38700
38701 return false;
38702 }
38703 }
38704 <?php
38705
38706
38707
38708
38709
38710
38711
38712
38713
38714
38715
38716 namespace Composer\Repository\Vcs;
38717
38718 use Composer\Config;
38719 use Composer\IO\IOInterface;
38720
38721
38722
38723
38724 class GitBitbucketDriver extends BitbucketDriver
38725 {
38726
38727
38728
38729 public function getRootIdentifier()
38730 {
38731 if ($this->fallbackDriver) {
38732 return $this->fallbackDriver->getRootIdentifier();
38733 }
38734
38735 if (null === $this->rootIdentifier) {
38736 if (! $this->getRepoData()) {
38737 return $this->fallbackDriver->getRootIdentifier();
38738 }
38739
38740 if ($this->vcsType !== 'git') {
38741 throw new \RuntimeException(
38742 $this->url.' does not appear to be a git repository, use '.
38743 $this->cloneHttpsUrl.' if this is a mercurial bitbucket repository'
38744 );
38745 }
38746
38747 $mainBranchData = $this->getMainBranchData();
38748 $this->rootIdentifier = !empty($mainBranchData['name']) ? $mainBranchData['name'] : 'master';
38749 }
38750
38751 return $this->rootIdentifier;
38752 }
38753
38754
38755
38756
38757 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
38758 {
38759 if (!preg_match('#^https?://bitbucket\.org/([^/]+)/(.+?)\.git$#i', $url)) {
38760 return false;
38761 }
38762
38763 if (!extension_loaded('openssl')) {
38764 $io->writeError('Skipping Bitbucket git driver for '.$url.' because the OpenSSL PHP extension is missing.', true, IOInterface::VERBOSE);
38765
38766 return false;
38767 }
38768
38769 return true;
38770 }
38771
38772
38773
38774
38775 protected function setupFallbackDriver($url)
38776 {
38777 $this->fallbackDriver = new GitDriver(
38778 array('url' => $url),
38779 $this->io,
38780 $this->config,
38781 $this->process,
38782 $this->remoteFilesystem
38783 );
38784 $this->fallbackDriver->initialize();
38785 }
38786
38787
38788
38789
38790 protected function generateSshUrl()
38791 {
38792 return 'git@' . $this->originUrl . ':' . $this->owner.'/'.$this->repository.'.git';
38793 }
38794 }
38795 <?php
38796
38797
38798
38799
38800
38801
38802
38803
38804
38805
38806
38807 namespace Composer\Repository\Vcs;
38808
38809 use Composer\Util\ProcessExecutor;
38810 use Composer\Util\Filesystem;
38811 use Composer\Util\Git as GitUtil;
38812 use Composer\IO\IOInterface;
38813 use Composer\Cache;
38814 use Composer\Config;
38815
38816
38817
38818
38819 class GitDriver extends VcsDriver
38820 {
38821 protected $cache;
38822 protected $tags;
38823 protected $branches;
38824 protected $rootIdentifier;
38825 protected $repoDir;
38826 protected $infoCache = array();
38827
38828
38829
38830
38831 public function initialize()
38832 {
38833 if (Filesystem::isLocalPath($this->url)) {
38834 $this->url = preg_replace('{[\\/]\.git/?$}', '', $this->url);
38835 if (!is_dir($this->url)) {
38836 throw new \RuntimeException('Failed to read package information from '.$this->url.' as the path does not exist');
38837 }
38838 $this->repoDir = $this->url;
38839 $cacheUrl = realpath($this->url);
38840 } else {
38841 if (!Cache::isUsable($this->config->get('cache-vcs-dir'))) {
38842 throw new \RuntimeException('GitDriver requires a usable cache directory, and it looks like you set it to be disabled');
38843 }
38844
38845 $this->repoDir = $this->config->get('cache-vcs-dir') . '/' . preg_replace('{[^a-z0-9.]}i', '-', $this->url) . '/';
38846
38847 GitUtil::cleanEnv();
38848
38849 $fs = new Filesystem();
38850 $fs->ensureDirectoryExists(dirname($this->repoDir));
38851
38852 if (!is_writable(dirname($this->repoDir))) {
38853 throw new \RuntimeException('Can not clone '.$this->url.' to access package information. The "'.dirname($this->repoDir).'" directory is not writable by the current user.');
38854 }
38855
38856 if (preg_match('{^ssh://[^@]+@[^:]+:[^0-9]+}', $this->url)) {
38857 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.');
38858 }
38859
38860 $gitUtil = new GitUtil($this->io, $this->config, $this->process, $fs);
38861 if (!$gitUtil->syncMirror($this->url, $this->repoDir)) {
38862 $this->io->writeError('<error>Failed to update '.$this->url.', package information from this repository may be outdated</error>');
38863 }
38864
38865 $cacheUrl = $this->url;
38866 }
38867
38868 $this->getTags();
38869 $this->getBranches();
38870
38871 $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $cacheUrl));
38872 }
38873
38874
38875
38876
38877 public function getRootIdentifier()
38878 {
38879 if (null === $this->rootIdentifier) {
38880 $this->rootIdentifier = 'master';
38881
38882
38883 $this->process->execute('git branch --no-color', $output, $this->repoDir);
38884 $branches = $this->process->splitLines($output);
38885 if (!in_array('* master', $branches)) {
38886 foreach ($branches as $branch) {
38887 if ($branch && preg_match('{^\* +(\S+)}', $branch, $match)) {
38888 $this->rootIdentifier = $match[1];
38889 break;
38890 }
38891 }
38892 }
38893 }
38894
38895 return $this->rootIdentifier;
38896 }
38897
38898
38899
38900
38901 public function getUrl()
38902 {
38903 return $this->url;
38904 }
38905
38906
38907
38908
38909 public function getSource($identifier)
38910 {
38911 return array('type' => 'git', 'url' => $this->getUrl(), 'reference' => $identifier);
38912 }
38913
38914
38915
38916
38917 public function getDist($identifier)
38918 {
38919 return null;
38920 }
38921
38922
38923
38924
38925 public function getFileContent($file, $identifier)
38926 {
38927 $resource = sprintf('%s:%s', ProcessExecutor::escape($identifier), ProcessExecutor::escape($file));
38928 $this->process->execute(sprintf('git show %s', $resource), $content, $this->repoDir);
38929
38930 if (!trim($content)) {
38931 return null;
38932 }
38933
38934 return $content;
38935 }
38936
38937
38938
38939
38940 public function getChangeDate($identifier)
38941 {
38942 $this->process->execute(sprintf(
38943 'git -c log.showSignature=false log -1 --format=%%at %s',
38944 ProcessExecutor::escape($identifier)
38945 ), $output, $this->repoDir);
38946
38947 return new \DateTime('@'.trim($output), new \DateTimeZone('UTC'));
38948 }
38949
38950
38951
38952
38953 public function getTags()
38954 {
38955 if (null === $this->tags) {
38956 $this->tags = array();
38957
38958 $this->process->execute('git show-ref --tags --dereference', $output, $this->repoDir);
38959 foreach ($output = $this->process->splitLines($output) as $tag) {
38960 if ($tag && preg_match('{^([a-f0-9]{40}) refs/tags/(\S+?)(\^\{\})?$}', $tag, $match)) {
38961 $this->tags[$match[2]] = $match[1];
38962 }
38963 }
38964 }
38965
38966 return $this->tags;
38967 }
38968
38969
38970
38971
38972 public function getBranches()
38973 {
38974 if (null === $this->branches) {
38975 $branches = array();
38976
38977 $this->process->execute('git branch --no-color --no-abbrev -v', $output, $this->repoDir);
38978 foreach ($this->process->splitLines($output) as $branch) {
38979 if ($branch && !preg_match('{^ *[^/]+/HEAD }', $branch)) {
38980 if (preg_match('{^(?:\* )? *(\S+) *([a-f0-9]+)(?: .*)?$}', $branch, $match)) {
38981 $branches[$match[1]] = $match[2];
38982 }
38983 }
38984 }
38985
38986 $this->branches = $branches;
38987 }
38988
38989 return $this->branches;
38990 }
38991
38992
38993
38994
38995 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
38996 {
38997 if (preg_match('#(^git://|\.git/?$|git(?:olite)?@|//git\.|//github.com/)#i', $url)) {
38998 return true;
38999 }
39000
39001
39002 if (Filesystem::isLocalPath($url)) {
39003 $url = Filesystem::getPlatformPath($url);
39004 if (!is_dir($url)) {
39005 return false;
39006 }
39007
39008 $process = new ProcessExecutor($io);
39009
39010 if ($process->execute('git tag', $output, $url) === 0) {
39011 return true;
39012 }
39013 }
39014
39015 if (!$deep) {
39016 return false;
39017 }
39018
39019 $gitUtil = new GitUtil($io, $config, new ProcessExecutor($io), new Filesystem());
39020 GitUtil::cleanEnv();
39021
39022 try {
39023 $gitUtil->runCommand(function ($url) {
39024 return 'git ls-remote --heads -- ' . ProcessExecutor::escape($url);
39025 }, $url, sys_get_temp_dir());
39026 } catch (\RuntimeException $e) {
39027 return false;
39028 }
39029
39030 return true;
39031 }
39032 }
39033 <?php
39034
39035
39036
39037
39038
39039
39040
39041
39042
39043
39044
39045 namespace Composer\Repository\Vcs;
39046
39047 use Composer\Config;
39048 use Composer\Downloader\TransportException;
39049 use Composer\Json\JsonFile;
39050 use Composer\Cache;
39051 use Composer\IO\IOInterface;
39052 use Composer\Util\GitHub;
39053
39054
39055
39056
39057 class GitHubDriver extends VcsDriver
39058 {
39059 protected $cache;
39060 protected $owner;
39061 protected $repository;
39062 protected $tags;
39063 protected $branches;
39064 protected $rootIdentifier;
39065 protected $repoData;
39066 protected $hasIssues;
39067 protected $infoCache = array();
39068 protected $isPrivate = false;
39069 private $isArchived = false;
39070 private $fundingInfo;
39071
39072
39073
39074
39075
39076
39077 protected $gitDriver;
39078
39079
39080
39081
39082 public function initialize()
39083 {
39084 preg_match('#^(?:(?:https?|git)://([^/]+)/|git@([^:]+):/?)([^/]+)/(.+?)(?:\.git|/)?$#', $this->url, $match);
39085 $this->owner = $match[3];
39086 $this->repository = $match[4];
39087 $this->originUrl = strtolower(!empty($match[1]) ? $match[1] : $match[2]);
39088 if ($this->originUrl === 'www.github.com') {
39089 $this->originUrl = 'github.com';
39090 }
39091 $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.$this->originUrl.'/'.$this->owner.'/'.$this->repository);
39092
39093 if ( $this->config->get('use-github-api') === false || (isset($this->repoConfig['no-api']) && $this->repoConfig['no-api'] ) ){
39094 $this->setupGitDriver($this->url);
39095
39096 return;
39097 }
39098
39099 $this->fetchRootIdentifier();
39100 }
39101
39102 public function getRepositoryUrl()
39103 {
39104 return 'https://'.$this->originUrl.'/'.$this->owner.'/'.$this->repository;
39105 }
39106
39107
39108
39109
39110 public function getRootIdentifier()
39111 {
39112 if ($this->gitDriver) {
39113 return $this->gitDriver->getRootIdentifier();
39114 }
39115
39116 return $this->rootIdentifier;
39117 }
39118
39119
39120
39121
39122 public function getUrl()
39123 {
39124 if ($this->gitDriver) {
39125 return $this->gitDriver->getUrl();
39126 }
39127
39128 return 'https://' . $this->originUrl . '/'.$this->owner.'/'.$this->repository.'.git';
39129 }
39130
39131
39132
39133
39134 protected function getApiUrl()
39135 {
39136 if ('github.com' === $this->originUrl) {
39137 $apiUrl = 'api.github.com';
39138 } else {
39139 $apiUrl = $this->originUrl . '/api/v3';
39140 }
39141
39142 return 'https://' . $apiUrl;
39143 }
39144
39145
39146
39147
39148 public function getSource($identifier)
39149 {
39150 if ($this->gitDriver) {
39151 return $this->gitDriver->getSource($identifier);
39152 }
39153 if ($this->isPrivate) {
39154
39155
39156 $url = $this->generateSshUrl();
39157 } else {
39158 $url = $this->getUrl();
39159 }
39160
39161 return array('type' => 'git', 'url' => $url, 'reference' => $identifier);
39162 }
39163
39164
39165
39166
39167 public function getDist($identifier)
39168 {
39169 $url = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/zipball/'.$identifier;
39170
39171 return array('type' => 'zip', 'url' => $url, 'reference' => $identifier, 'shasum' => '');
39172 }
39173
39174
39175
39176
39177 public function getComposerInformation($identifier)
39178 {
39179 if ($this->gitDriver) {
39180 return $this->gitDriver->getComposerInformation($identifier);
39181 }
39182
39183 if (!isset($this->infoCache[$identifier])) {
39184 if ($this->shouldCache($identifier) && $res = $this->cache->read($identifier)) {
39185 $composer = JsonFile::parseJson($res);
39186 } else {
39187 $composer = $this->getBaseComposerInformation($identifier);
39188
39189 if ($this->shouldCache($identifier)) {
39190 $this->cache->write($identifier, json_encode($composer));
39191 }
39192 }
39193
39194 if ($composer) {
39195
39196 if (!isset($composer['support']['source'])) {
39197 $label = array_search($identifier, $this->getTags()) ?: array_search($identifier, $this->getBranches()) ?: $identifier;
39198 $composer['support']['source'] = sprintf('https://%s/%s/%s/tree/%s', $this->originUrl, $this->owner, $this->repository, $label);
39199 }
39200 if (!isset($composer['support']['issues']) && $this->hasIssues) {
39201 $composer['support']['issues'] = sprintf('https://%s/%s/%s/issues', $this->originUrl, $this->owner, $this->repository);
39202 }
39203 if (!isset($composer['abandoned']) && $this->isArchived) {
39204 $composer['abandoned'] = true;
39205 }
39206 if (!isset($composer['funding']) && $funding = $this->getFundingInfo()) {
39207 $composer['funding'] = $funding;
39208 }
39209 }
39210
39211 $this->infoCache[$identifier] = $composer;
39212 }
39213
39214 return $this->infoCache[$identifier];
39215 }
39216
39217 private function getFundingInfo()
39218 {
39219 if (null !== $this->fundingInfo) {
39220 return $this->fundingInfo;
39221 }
39222
39223 if ($this->originUrl !== 'github.com') {
39224 return $this->fundingInfo = false;
39225 }
39226
39227 foreach (array($this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/contents/.github/FUNDING.yml', $this->getApiUrl() . '/repos/'.$this->owner.'/.github/contents/FUNDING.yml') as $file) {
39228
39229 try {
39230 $result = $this->remoteFilesystem->getContents($this->originUrl, $file, false, array(
39231 'retry-auth-failure' => false,
39232 ));
39233 $response = json_decode($result, true);
39234 } catch (TransportException $e) {
39235 continue;
39236 }
39237 if (empty($response['content']) || $response['encoding'] !== 'base64' || !($funding = base64_decode($response['content']))) {
39238 continue;
39239 }
39240 break;
39241 }
39242 if (empty($funding)) {
39243 return $this->fundingInfo = false;
39244 }
39245
39246 $result = array();
39247 $key = null;
39248 foreach (preg_split('{\r?\n}', $funding) as $line) {
39249 $line = trim($line);
39250 if (preg_match('{^(\w+)\s*:\s*(.+)$}', $line, $match)) {
39251 if (preg_match('{^\[(.*)\](?:\s*#.*)?$}', $match[2], $match2)) {
39252 foreach (array_map('trim', preg_split('{[\'"]?\s*,\s*[\'"]?}', $match2[1])) as $item) {
39253 $result[] = array('type' => $match[1], 'url' => trim($item, '"\' '));
39254 }
39255 } elseif (preg_match('{^([^#].*?)(\s+#.*)?$}', $match[2], $match2)) {
39256 $result[] = array('type' => $match[1], 'url' => trim($match2[1], '"\' '));
39257 }
39258 $key = null;
39259 } elseif (preg_match('{^(\w+)\s*:\s*#\s*$}', $line, $match)) {
39260 $key = $match[1];
39261 } elseif ($key && preg_match('{^-\s*(.+)(\s+#.*)?$}', $line, $match)) {
39262 $result[] = array('type' => $key, 'url' => trim($match[1], '"\' '));
39263 }
39264 }
39265
39266 foreach ($result as $key => $item) {
39267 switch ($item['type']) {
39268 case 'tidelift':
39269 $result[$key]['url'] = 'https://tidelift.com/funding/github/' . $item['url'];
39270 break;
39271 case 'github':
39272 $result[$key]['url'] = 'https://github.com/' . basename($item['url']);
39273 break;
39274 case 'patreon':
39275 $result[$key]['url'] = 'https://www.patreon.com/' . basename($item['url']);
39276 break;
39277 case 'otechie':
39278 $result[$key]['url'] = 'https://otechie.com/' . basename($item['url']);
39279 break;
39280 case 'open_collective':
39281 $result[$key]['url'] = 'https://opencollective.com/' . basename($item['url']);
39282 break;
39283 case 'liberapay':
39284 $result[$key]['url'] = 'https://liberapay.com/' . basename($item['url']);
39285 break;
39286 case 'ko_fi':
39287 $result[$key]['url'] = 'https://ko-fi.com/' . basename($item['url']);
39288 break;
39289 case 'issuehunt':
39290 $result[$key]['url'] = 'https://issuehunt.io/r/' . $item['url'];
39291 break;
39292 case 'community_bridge':
39293 $result[$key]['url'] = 'https://funding.communitybridge.org/projects/' . basename($item['url']);
39294 break;
39295 }
39296 }
39297
39298 return $this->fundingInfo = $result;
39299 }
39300
39301
39302
39303
39304 public function getFileContent($file, $identifier)
39305 {
39306 if ($this->gitDriver) {
39307 return $this->gitDriver->getFileContent($file, $identifier);
39308 }
39309
39310 $resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/contents/' . $file . '?ref='.urlencode($identifier);
39311 $resource = JsonFile::parseJson($this->getContents($resource));
39312 if (empty($resource['content']) || $resource['encoding'] !== 'base64' || !($content = base64_decode($resource['content']))) {
39313 throw new \RuntimeException('Could not retrieve ' . $file . ' for '.$identifier);
39314 }
39315
39316 return $content;
39317 }
39318
39319
39320
39321
39322 public function getChangeDate($identifier)
39323 {
39324 if ($this->gitDriver) {
39325 return $this->gitDriver->getChangeDate($identifier);
39326 }
39327
39328 $resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/commits/'.urlencode($identifier);
39329 $commit = JsonFile::parseJson($this->getContents($resource), $resource);
39330
39331 return new \DateTime($commit['commit']['committer']['date']);
39332 }
39333
39334
39335
39336
39337 public function getTags()
39338 {
39339 if ($this->gitDriver) {
39340 return $this->gitDriver->getTags();
39341 }
39342 if (null === $this->tags) {
39343 $this->tags = array();
39344 $resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/tags?per_page=100';
39345
39346 do {
39347 $tagsData = JsonFile::parseJson($this->getContents($resource), $resource);
39348 foreach ($tagsData as $tag) {
39349 $this->tags[$tag['name']] = $tag['commit']['sha'];
39350 }
39351
39352 $resource = $this->getNextPage();
39353 } while ($resource);
39354 }
39355
39356 return $this->tags;
39357 }
39358
39359
39360
39361
39362 public function getBranches()
39363 {
39364 if ($this->gitDriver) {
39365 return $this->gitDriver->getBranches();
39366 }
39367 if (null === $this->branches) {
39368 $this->branches = array();
39369 $resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/git/refs/heads?per_page=100';
39370
39371 do {
39372 $branchData = JsonFile::parseJson($this->getContents($resource), $resource);
39373 foreach ($branchData as $branch) {
39374 $name = substr($branch['ref'], 11);
39375 if ($name !== 'gh-pages') {
39376 $this->branches[$name] = $branch['object']['sha'];
39377 }
39378 }
39379
39380 $resource = $this->getNextPage();
39381 } while ($resource);
39382 }
39383
39384 return $this->branches;
39385 }
39386
39387
39388
39389
39390 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
39391 {
39392 if (!preg_match('#^((?:https?|git)://([^/]+)/|git@([^:]+):/?)([^/]+)/(.+?)(?:\.git|/)?$#', $url, $matches)) {
39393 return false;
39394 }
39395
39396 $originUrl = !empty($matches[2]) ? $matches[2] : $matches[3];
39397 if (!in_array(strtolower(preg_replace('{^www\.}i', '', $originUrl)), $config->get('github-domains'))) {
39398 return false;
39399 }
39400
39401 if (!extension_loaded('openssl')) {
39402 $io->writeError('Skipping GitHub driver for '.$url.' because the OpenSSL PHP extension is missing.', true, IOInterface::VERBOSE);
39403
39404 return false;
39405 }
39406
39407 return true;
39408 }
39409
39410
39411
39412
39413
39414
39415 public function getRepoData()
39416 {
39417 $this->fetchRootIdentifier();
39418
39419 return $this->repoData;
39420 }
39421
39422
39423
39424
39425
39426
39427 protected function generateSshUrl()
39428 {
39429 if (false !== strpos($this->originUrl, ':')) {
39430 return 'ssh://git@' . $this->originUrl . '/'.$this->owner.'/'.$this->repository.'.git';
39431 }
39432
39433 return 'git@' . $this->originUrl . ':'.$this->owner.'/'.$this->repository.'.git';
39434 }
39435
39436
39437
39438
39439 protected function getContents($url, $fetchingRepoData = false)
39440 {
39441 try {
39442 return parent::getContents($url);
39443 } catch (TransportException $e) {
39444 $gitHubUtil = new GitHub($this->io, $this->config, $this->process, $this->remoteFilesystem);
39445
39446 switch ($e->getCode()) {
39447 case 401:
39448 case 404:
39449
39450 if (!$fetchingRepoData) {
39451 throw $e;
39452 }
39453
39454 if ($gitHubUtil->authorizeOAuth($this->originUrl)) {
39455 return parent::getContents($url);
39456 }
39457
39458 if (!$this->io->isInteractive()) {
39459 return $this->attemptCloneFallback();
39460 }
39461
39462 $scopesIssued = array();
39463 $scopesNeeded = array();
39464 if ($headers = $e->getHeaders()) {
39465 if ($scopes = $this->remoteFilesystem->findHeaderValue($headers, 'X-OAuth-Scopes')) {
39466 $scopesIssued = explode(' ', $scopes);
39467 }
39468 if ($scopes = $this->remoteFilesystem->findHeaderValue($headers, 'X-Accepted-OAuth-Scopes')) {
39469 $scopesNeeded = explode(' ', $scopes);
39470 }
39471 }
39472 $scopesFailed = array_diff($scopesNeeded, $scopesIssued);
39473
39474
39475 if (!$headers || !count($scopesNeeded) || count($scopesFailed)) {
39476 $gitHubUtil->authorizeOAuthInteractively($this->originUrl, 'Your GitHub credentials are required to fetch private repository metadata (<info>'.$this->url.'</info>)');
39477 }
39478
39479 return parent::getContents($url);
39480
39481 case 403:
39482 if (!$this->io->hasAuthentication($this->originUrl) && $gitHubUtil->authorizeOAuth($this->originUrl)) {
39483 return parent::getContents($url);
39484 }
39485
39486 if (!$this->io->isInteractive() && $fetchingRepoData) {
39487 return $this->attemptCloneFallback();
39488 }
39489
39490 $rateLimited = $gitHubUtil->isRateLimited($e->getHeaders());
39491
39492 if (!$this->io->hasAuthentication($this->originUrl)) {
39493 if (!$this->io->isInteractive()) {
39494 $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>');
39495 throw $e;
39496 }
39497
39498 $gitHubUtil->authorizeOAuthInteractively($this->originUrl, 'API limit exhausted. Enter your GitHub credentials to get a larger API limit (<info>'.$this->url.'</info>)');
39499
39500 return parent::getContents($url);
39501 }
39502
39503 if ($rateLimited) {
39504 $rateLimit = $gitHubUtil->getRateLimit($e->getHeaders());
39505 $this->io->writeError(sprintf(
39506 '<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>',
39507 $rateLimit['limit'],
39508 $rateLimit['reset']
39509 ));
39510 }
39511
39512 throw $e;
39513
39514 default:
39515 throw $e;
39516 }
39517 }
39518 }
39519
39520
39521
39522
39523
39524
39525 protected function fetchRootIdentifier()
39526 {
39527 if ($this->repoData) {
39528 return;
39529 }
39530
39531 $repoDataUrl = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository;
39532
39533 $this->repoData = JsonFile::parseJson($this->getContents($repoDataUrl, true), $repoDataUrl);
39534 if (null === $this->repoData && null !== $this->gitDriver) {
39535 return;
39536 }
39537
39538 $this->owner = $this->repoData['owner']['login'];
39539 $this->repository = $this->repoData['name'];
39540
39541 $this->isPrivate = !empty($this->repoData['private']);
39542 if (isset($this->repoData['default_branch'])) {
39543 $this->rootIdentifier = $this->repoData['default_branch'];
39544 } elseif (isset($this->repoData['master_branch'])) {
39545 $this->rootIdentifier = $this->repoData['master_branch'];
39546 } else {
39547 $this->rootIdentifier = 'master';
39548 }
39549 $this->hasIssues = !empty($this->repoData['has_issues']);
39550 $this->isArchived = !empty($this->repoData['archived']);
39551 }
39552
39553 protected function attemptCloneFallback()
39554 {
39555 $this->isPrivate = true;
39556
39557 try {
39558
39559
39560
39561
39562 $this->setupGitDriver($this->generateSshUrl());
39563
39564 return;
39565 } catch (\RuntimeException $e) {
39566 $this->gitDriver = null;
39567
39568 $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>');
39569 throw $e;
39570 }
39571 }
39572
39573 protected function setupGitDriver($url)
39574 {
39575 $this->gitDriver = new GitDriver(
39576 array('url' => $url),
39577 $this->io,
39578 $this->config,
39579 $this->process,
39580 $this->remoteFilesystem
39581 );
39582 $this->gitDriver->initialize();
39583 }
39584
39585 protected function getNextPage()
39586 {
39587 $headers = $this->remoteFilesystem->getLastHeaders();
39588 foreach ($headers as $header) {
39589 if (preg_match('{^link:\s*(.+?)\s*$}i', $header, $match)) {
39590 $links = explode(',', $match[1]);
39591 foreach ($links as $link) {
39592 if (preg_match('{<(.+?)>; *rel="next"}', $link, $match)) {
39593 return $match[1];
39594 }
39595 }
39596 }
39597 }
39598 }
39599 }
39600 <?php
39601
39602
39603
39604
39605
39606
39607
39608
39609
39610
39611
39612 namespace Composer\Repository\Vcs;
39613
39614 use Composer\Config;
39615 use Composer\Cache;
39616 use Composer\IO\IOInterface;
39617 use Composer\Json\JsonFile;
39618 use Composer\Downloader\TransportException;
39619 use Composer\Util\RemoteFilesystem;
39620 use Composer\Util\GitLab;
39621
39622
39623
39624
39625
39626
39627
39628 class GitLabDriver extends VcsDriver
39629 {
39630 private $scheme;
39631 private $namespace;
39632 private $repository;
39633
39634
39635
39636
39637 private $project;
39638
39639
39640
39641
39642 private $commits = array();
39643
39644
39645
39646
39647 private $tags;
39648
39649
39650
39651
39652 private $branches;
39653
39654
39655
39656
39657
39658
39659 protected $gitDriver;
39660
39661
39662
39663
39664
39665
39666 private $isPrivate = true;
39667
39668
39669
39670
39671 private $hasNonstandardOrigin = false;
39672
39673 const URL_REGEX = '#^(?:(?P<scheme>https?)://(?P<domain>.+?)(?::(?P<port>[0-9]+))?/|git@(?P<domain2>[^:]+):)(?P<parts>.+)/(?P<repo>[^/]+?)(?:\.git|/)?$#';
39674
39675
39676
39677
39678
39679
39680
39681
39682 public function initialize()
39683 {
39684 if (!preg_match(self::URL_REGEX, $this->url, $match)) {
39685 throw new \InvalidArgumentException('The URL provided is invalid. It must be the HTTP URL of a GitLab project.');
39686 }
39687
39688 $guessedDomain = !empty($match['domain']) ? $match['domain'] : $match['domain2'];
39689 $configuredDomains = $this->config->get('gitlab-domains');
39690 $urlParts = explode('/', $match['parts']);
39691
39692 $this->scheme = !empty($match['scheme'])
39693 ? $match['scheme']
39694 : (isset($this->repoConfig['secure-http']) && $this->repoConfig['secure-http'] === false ? 'http' : 'https')
39695 ;
39696 $this->originUrl = $this->determineOrigin($configuredDomains, $guessedDomain, $urlParts, $match['port']);
39697
39698 if (false !== strpos($this->originUrl, ':') || false !== strpos($this->originUrl, '/')) {
39699 $this->hasNonstandardOrigin = true;
39700 }
39701
39702 $this->namespace = implode('/', $urlParts);
39703 $this->repository = preg_replace('#(\.git)$#', '', $match['repo']);
39704
39705 $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.$this->originUrl.'/'.$this->namespace.'/'.$this->repository);
39706
39707 $this->fetchProject();
39708 }
39709
39710
39711
39712
39713
39714
39715
39716 public function setRemoteFilesystem(RemoteFilesystem $remoteFilesystem)
39717 {
39718 $this->remoteFilesystem = $remoteFilesystem;
39719 }
39720
39721
39722
39723
39724 public function getComposerInformation($identifier)
39725 {
39726 if ($this->gitDriver) {
39727 return $this->gitDriver->getComposerInformation($identifier);
39728 }
39729
39730 if (!isset($this->infoCache[$identifier])) {
39731 if ($this->shouldCache($identifier) && $res = $this->cache->read($identifier)) {
39732 $composer = JsonFile::parseJson($res);
39733 } else {
39734 $composer = $this->getBaseComposerInformation($identifier);
39735
39736 if ($this->shouldCache($identifier)) {
39737 $this->cache->write($identifier, json_encode($composer));
39738 }
39739 }
39740
39741 if ($composer) {
39742
39743 if (!isset($composer['support']['issues']) && isset($this->project['_links']['issues'])) {
39744 $composer['support']['issues'] = $this->project['_links']['issues'];
39745 }
39746 if (!isset($composer['abandoned']) && !empty($this->project['archived'])) {
39747 $composer['abandoned'] = true;
39748 }
39749 }
39750
39751 $this->infoCache[$identifier] = $composer;
39752 }
39753
39754 return $this->infoCache[$identifier];
39755 }
39756
39757
39758
39759
39760 public function getFileContent($file, $identifier)
39761 {
39762 if ($this->gitDriver) {
39763 return $this->gitDriver->getFileContent($file, $identifier);
39764 }
39765
39766
39767 if (!preg_match('{[a-f0-9]{40}}i', $identifier)) {
39768 $branches = $this->getBranches();
39769 if (isset($branches[$identifier])) {
39770 $identifier = $branches[$identifier];
39771 }
39772 }
39773
39774 $resource = $this->getApiUrl().'/repository/files/'.$this->urlEncodeAll($file).'/raw?ref='.$identifier;
39775
39776 try {
39777 $content = $this->getContents($resource);
39778 } catch (TransportException $e) {
39779 if ($e->getCode() !== 404) {
39780 throw $e;
39781 }
39782
39783 return null;
39784 }
39785
39786 return $content;
39787 }
39788
39789
39790
39791
39792 public function getChangeDate($identifier)
39793 {
39794 if ($this->gitDriver) {
39795 return $this->gitDriver->getChangeDate($identifier);
39796 }
39797
39798 if (isset($this->commits[$identifier])) {
39799 return new \DateTime($this->commits[$identifier]['committed_date']);
39800 }
39801
39802 return new \DateTime();
39803 }
39804
39805
39806
39807
39808 public function getRepositoryUrl()
39809 {
39810 return $this->isPrivate ? $this->project['ssh_url_to_repo'] : $this->project['http_url_to_repo'];
39811 }
39812
39813
39814
39815
39816 public function getUrl()
39817 {
39818 if ($this->gitDriver) {
39819 return $this->gitDriver->getUrl();
39820 }
39821
39822 return $this->project['web_url'];
39823 }
39824
39825
39826
39827
39828 public function getDist($identifier)
39829 {
39830 $url = $this->getApiUrl().'/repository/archive.zip?sha='.$identifier;
39831
39832 return array('type' => 'zip', 'url' => $url, 'reference' => $identifier, 'shasum' => '');
39833 }
39834
39835
39836
39837
39838 public function getSource($identifier)
39839 {
39840 if ($this->gitDriver) {
39841 return $this->gitDriver->getSource($identifier);
39842 }
39843
39844 return array('type' => 'git', 'url' => $this->getRepositoryUrl(), 'reference' => $identifier);
39845 }
39846
39847
39848
39849
39850 public function getRootIdentifier()
39851 {
39852 if ($this->gitDriver) {
39853 return $this->gitDriver->getRootIdentifier();
39854 }
39855
39856 return $this->project['default_branch'];
39857 }
39858
39859
39860
39861
39862 public function getBranches()
39863 {
39864 if ($this->gitDriver) {
39865 return $this->gitDriver->getBranches();
39866 }
39867
39868 if (!$this->branches) {
39869 $this->branches = $this->getReferences('branches');
39870 }
39871
39872 return $this->branches;
39873 }
39874
39875
39876
39877
39878 public function getTags()
39879 {
39880 if ($this->gitDriver) {
39881 return $this->gitDriver->getTags();
39882 }
39883
39884 if (!$this->tags) {
39885 $this->tags = $this->getReferences('tags');
39886 }
39887
39888 return $this->tags;
39889 }
39890
39891
39892
39893
39894 public function getApiUrl()
39895 {
39896 return $this->scheme.'://'.$this->originUrl.'/api/v4/projects/'.$this->urlEncodeAll($this->namespace).'%2F'.$this->urlEncodeAll($this->repository);
39897 }
39898
39899
39900
39901
39902
39903
39904
39905 private function urlEncodeAll($string)
39906 {
39907 $encoded = '';
39908 for ($i = 0; isset($string[$i]); $i++) {
39909 $character = $string[$i];
39910 if (!ctype_alnum($character) && !in_array($character, array('-', '_'), true)) {
39911 $character = '%' . sprintf('%02X', ord($character));
39912 }
39913 $encoded .= $character;
39914 }
39915
39916 return $encoded;
39917 }
39918
39919
39920
39921
39922
39923
39924 protected function getReferences($type)
39925 {
39926 $perPage = 100;
39927 $resource = $this->getApiUrl().'/repository/'.$type.'?per_page='.$perPage;
39928
39929 $references = array();
39930 do {
39931 $data = JsonFile::parseJson($this->getContents($resource), $resource);
39932
39933 foreach ($data as $datum) {
39934 $references[$datum['name']] = $datum['commit']['id'];
39935
39936
39937
39938 $this->commits[$datum['commit']['id']] = $datum['commit'];
39939 }
39940
39941 if (count($data) >= $perPage) {
39942 $resource = $this->getNextPage();
39943 } else {
39944 $resource = false;
39945 }
39946 } while ($resource);
39947
39948 return $references;
39949 }
39950
39951 protected function fetchProject()
39952 {
39953
39954 $resource = $this->getApiUrl();
39955 $this->project = JsonFile::parseJson($this->getContents($resource, true), $resource);
39956 if (isset($this->project['visibility'])) {
39957 $this->isPrivate = $this->project['visibility'] !== 'public';
39958 } else {
39959
39960 $this->isPrivate = false;
39961 }
39962 }
39963
39964 protected function attemptCloneFallback()
39965 {
39966 try {
39967 if ($this->isPrivate === false) {
39968 $url = $this->generatePublicUrl();
39969 } else {
39970 $url = $this->generateSshUrl();
39971 }
39972
39973
39974
39975
39976 $this->setupGitDriver($url);
39977
39978 return;
39979 } catch (\RuntimeException $e) {
39980 $this->gitDriver = null;
39981
39982 $this->io->writeError('<error>Failed to clone the '.$url.' repository, try running in interactive mode so that you can enter your credentials</error>');
39983 throw $e;
39984 }
39985 }
39986
39987
39988
39989
39990
39991
39992 protected function generateSshUrl()
39993 {
39994 if ($this->hasNonstandardOrigin) {
39995 return 'ssh://git@'.$this->originUrl.'/'.$this->namespace.'/'.$this->repository.'.git';
39996 }
39997
39998 return 'git@' . $this->originUrl . ':'.$this->namespace.'/'.$this->repository.'.git';
39999 }
40000
40001 protected function generatePublicUrl()
40002 {
40003 return $this->scheme . '://' . $this->originUrl . '/'.$this->namespace.'/'.$this->repository.'.git';
40004 }
40005
40006 protected function setupGitDriver($url)
40007 {
40008 $this->gitDriver = new GitDriver(
40009 array('url' => $url),
40010 $this->io,
40011 $this->config,
40012 $this->process,
40013 $this->remoteFilesystem
40014 );
40015 $this->gitDriver->initialize();
40016 }
40017
40018
40019
40020
40021 protected function getContents($url, $fetchingRepoData = false)
40022 {
40023 try {
40024 $res = parent::getContents($url);
40025
40026 if ($fetchingRepoData) {
40027 $json = JsonFile::parseJson($res, $url);
40028
40029
40030
40031
40032 if (!isset($json['default_branch']) && isset($json['permissions'])) {
40033 $this->isPrivate = $json['visibility'] !== 'public';
40034
40035 $moreThanGuestAccess = false;
40036
40037
40038
40039 foreach ($json['permissions'] as $permission) {
40040 if ($permission && $permission['access_level'] > 10) {
40041 $moreThanGuestAccess = true;
40042 }
40043 }
40044
40045 if (!$moreThanGuestAccess) {
40046 $this->io->writeError('<warning>GitLab token with Guest only access detected</warning>');
40047
40048 return $this->attemptCloneFallback();
40049 }
40050 }
40051
40052
40053 if (!isset($json['default_branch'])) {
40054 if (!empty($json['id'])) {
40055 $this->isPrivate = false;
40056 }
40057
40058 throw new TransportException('GitLab API seems to not be authenticated as it did not return a default_branch', 401);
40059 }
40060 }
40061
40062 return $res;
40063 } catch (TransportException $e) {
40064 $gitLabUtil = new GitLab($this->io, $this->config, $this->process, $this->remoteFilesystem);
40065
40066 switch ($e->getCode()) {
40067 case 401:
40068 case 404:
40069
40070 if (!$fetchingRepoData) {
40071 throw $e;
40072 }
40073
40074 if ($gitLabUtil->authorizeOAuth($this->originUrl)) {
40075 return parent::getContents($url);
40076 }
40077
40078 if (!$this->io->isInteractive()) {
40079 return $this->attemptCloneFallback();
40080 }
40081 $this->io->writeError('<warning>Failed to download ' . $this->namespace . '/' . $this->repository . ':' . $e->getMessage() . '</warning>');
40082 $gitLabUtil->authorizeOAuthInteractively($this->scheme, $this->originUrl, 'Your credentials are required to fetch private repository metadata (<info>'.$this->url.'</info>)');
40083
40084 return parent::getContents($url);
40085
40086 case 403:
40087 if (!$this->io->hasAuthentication($this->originUrl) && $gitLabUtil->authorizeOAuth($this->originUrl)) {
40088 return parent::getContents($url);
40089 }
40090
40091 if (!$this->io->isInteractive() && $fetchingRepoData) {
40092 return $this->attemptCloneFallback();
40093 }
40094
40095 throw $e;
40096
40097 default:
40098 throw $e;
40099 }
40100 }
40101 }
40102
40103
40104
40105
40106
40107
40108
40109 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
40110 {
40111 if (!preg_match(self::URL_REGEX, $url, $match)) {
40112 return false;
40113 }
40114
40115 $scheme = !empty($match['scheme']) ? $match['scheme'] : null;
40116 $guessedDomain = !empty($match['domain']) ? $match['domain'] : $match['domain2'];
40117 $urlParts = explode('/', $match['parts']);
40118
40119 if (false === self::determineOrigin((array) $config->get('gitlab-domains'), $guessedDomain, $urlParts, $match['port'])) {
40120 return false;
40121 }
40122
40123 if ('https' === $scheme && !extension_loaded('openssl')) {
40124 $io->writeError('Skipping GitLab driver for '.$url.' because the OpenSSL PHP extension is missing.', true, IOInterface::VERBOSE);
40125
40126 return false;
40127 }
40128
40129 return true;
40130 }
40131
40132 private function getNextPage()
40133 {
40134 $headers = $this->remoteFilesystem->getLastHeaders();
40135 foreach ($headers as $header) {
40136 if (preg_match('{^link:\s*(.+?)\s*$}i', $header, $match)) {
40137 $links = explode(',', $match[1]);
40138 foreach ($links as $link) {
40139 if (preg_match('{<(.+?)>; *rel="next"}', $link, $match)) {
40140 return $match[1];
40141 }
40142 }
40143 }
40144 }
40145 }
40146
40147
40148
40149
40150
40151
40152
40153 private static function determineOrigin(array $configuredDomains, $guessedDomain, array &$urlParts, $portNumber)
40154 {
40155 $guessedDomain = strtolower($guessedDomain);
40156
40157 if (in_array($guessedDomain, $configuredDomains) || ($portNumber && in_array($guessedDomain.':'.$portNumber, $configuredDomains))) {
40158 if ($portNumber) {
40159 return $guessedDomain.':'.$portNumber;
40160 }
40161 return $guessedDomain;
40162 }
40163
40164 if ($portNumber) {
40165 $guessedDomain .= ':'.$portNumber;
40166 }
40167
40168 while (null !== ($part = array_shift($urlParts))) {
40169 $guessedDomain .= '/' . $part;
40170
40171 if (in_array($guessedDomain, $configuredDomains) || ($portNumber && in_array(preg_replace('{:\d+}', '', $guessedDomain), $configuredDomains))) {
40172 return $guessedDomain;
40173 }
40174 }
40175
40176 return false;
40177 }
40178 }
40179 <?php
40180
40181
40182
40183
40184
40185
40186
40187
40188
40189
40190
40191 namespace Composer\Repository\Vcs;
40192
40193 use Composer\Config;
40194 use Composer\IO\IOInterface;
40195
40196
40197
40198
40199 class HgBitbucketDriver extends BitbucketDriver
40200 {
40201
40202
40203
40204 public function getRootIdentifier()
40205 {
40206 if ($this->fallbackDriver) {
40207 return $this->fallbackDriver->getRootIdentifier();
40208 }
40209
40210 if (null === $this->rootIdentifier) {
40211 if (! $this->getRepoData()) {
40212 return $this->fallbackDriver->getRootIdentifier();
40213 }
40214
40215 if ($this->vcsType !== 'hg') {
40216 throw new \RuntimeException(
40217 $this->url.' does not appear to be a mercurial repository, use '.
40218 $this->cloneHttpsUrl.' if this is a git bitbucket repository'
40219 );
40220 }
40221
40222 $mainBranchData = $this->getMainBranchData();
40223 $this->rootIdentifier = !empty($mainBranchData['name']) ? $mainBranchData['name'] : 'default';
40224 }
40225
40226 return $this->rootIdentifier;
40227 }
40228
40229
40230
40231
40232 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
40233 {
40234 if (!preg_match('#^https?://bitbucket\.org/([^/]+)/([^/]+)/?$#i', $url)) {
40235 return false;
40236 }
40237
40238 if (!extension_loaded('openssl')) {
40239 $io->writeError('Skipping Bitbucket hg driver for '.$url.' because the OpenSSL PHP extension is missing.', true, IOInterface::VERBOSE);
40240
40241 return false;
40242 }
40243
40244 return true;
40245 }
40246
40247
40248
40249
40250 protected function setupFallbackDriver($url)
40251 {
40252 $this->fallbackDriver = new HgDriver(
40253 array('url' => $url),
40254 $this->io,
40255 $this->config,
40256 $this->process,
40257 $this->remoteFilesystem
40258 );
40259 $this->fallbackDriver->initialize();
40260 }
40261
40262
40263
40264
40265 protected function generateSshUrl()
40266 {
40267 return 'ssh://hg@' . $this->originUrl . '/' . $this->owner.'/'.$this->repository;
40268 }
40269 }
40270 <?php
40271
40272
40273
40274
40275
40276
40277
40278
40279
40280
40281
40282 namespace Composer\Repository\Vcs;
40283
40284 use Composer\Config;
40285 use Composer\Cache;
40286 use Composer\Util\Hg as HgUtils;
40287 use Composer\Util\ProcessExecutor;
40288 use Composer\Util\Filesystem;
40289 use Composer\IO\IOInterface;
40290
40291
40292
40293
40294 class HgDriver extends VcsDriver
40295 {
40296 protected $tags;
40297 protected $branches;
40298 protected $rootIdentifier;
40299 protected $repoDir;
40300 protected $infoCache = array();
40301
40302
40303
40304
40305 public function initialize()
40306 {
40307 if (Filesystem::isLocalPath($this->url)) {
40308 $this->repoDir = $this->url;
40309 } else {
40310 if (!Cache::isUsable($this->config->get('cache-vcs-dir'))) {
40311 throw new \RuntimeException('HgDriver requires a usable cache directory, and it looks like you set it to be disabled');
40312 }
40313
40314 $cacheDir = $this->config->get('cache-vcs-dir');
40315 $this->repoDir = $cacheDir . '/' . preg_replace('{[^a-z0-9]}i', '-', $this->url) . '/';
40316
40317 $fs = new Filesystem();
40318 $fs->ensureDirectoryExists($cacheDir);
40319
40320 if (!is_writable(dirname($this->repoDir))) {
40321 throw new \RuntimeException('Can not clone '.$this->url.' to access package information. The "'.$cacheDir.'" directory is not writable by the current user.');
40322 }
40323
40324
40325 $this->config->prohibitUrlByConfig($this->url, $this->io);
40326
40327 $hgUtils = new HgUtils($this->io, $this->config, $this->process);
40328
40329
40330 if (is_dir($this->repoDir) && 0 === $this->process->execute('hg summary', $output, $this->repoDir)) {
40331 if (0 !== $this->process->execute('hg pull', $output, $this->repoDir)) {
40332 $this->io->writeError('<error>Failed to update '.$this->url.', package information from this repository may be outdated ('.$this->process->getErrorOutput().')</error>');
40333 }
40334 } else {
40335
40336 $fs->removeDirectory($this->repoDir);
40337
40338 $repoDir = $this->repoDir;
40339 $command = function ($url) use ($repoDir) {
40340 return sprintf('hg clone --noupdate -- %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($repoDir));
40341 };
40342
40343 $hgUtils->runCommand($command, $this->url, null);
40344 }
40345 }
40346
40347 $this->getTags();
40348 $this->getBranches();
40349 }
40350
40351
40352
40353
40354 public function getRootIdentifier()
40355 {
40356 if (null === $this->rootIdentifier) {
40357 $this->process->execute(sprintf('hg tip --template "{node}"'), $output, $this->repoDir);
40358 $output = $this->process->splitLines($output);
40359 $this->rootIdentifier = $output[0];
40360 }
40361
40362 return $this->rootIdentifier;
40363 }
40364
40365
40366
40367
40368 public function getUrl()
40369 {
40370 return $this->url;
40371 }
40372
40373
40374
40375
40376 public function getSource($identifier)
40377 {
40378 return array('type' => 'hg', 'url' => $this->getUrl(), 'reference' => $identifier);
40379 }
40380
40381
40382
40383
40384 public function getDist($identifier)
40385 {
40386 return null;
40387 }
40388
40389
40390
40391
40392 public function getFileContent($file, $identifier)
40393 {
40394 $resource = sprintf('hg cat -r %s %s', ProcessExecutor::escape($identifier), ProcessExecutor::escape($file));
40395 $this->process->execute($resource, $content, $this->repoDir);
40396
40397 if (!trim($content)) {
40398 return;
40399 }
40400
40401 return $content;
40402 }
40403
40404
40405
40406
40407 public function getChangeDate($identifier)
40408 {
40409 $this->process->execute(
40410 sprintf(
40411 'hg log --template "{date|rfc3339date}" -r %s',
40412 ProcessExecutor::escape($identifier)
40413 ),
40414 $output,
40415 $this->repoDir
40416 );
40417
40418 return new \DateTime(trim($output), new \DateTimeZone('UTC'));
40419 }
40420
40421
40422
40423
40424 public function getTags()
40425 {
40426 if (null === $this->tags) {
40427 $tags = array();
40428
40429 $this->process->execute('hg tags', $output, $this->repoDir);
40430 foreach ($this->process->splitLines($output) as $tag) {
40431 if ($tag && preg_match('(^([^\s]+)\s+\d+:(.*)$)', $tag, $match)) {
40432 $tags[$match[1]] = $match[2];
40433 }
40434 }
40435 unset($tags['tip']);
40436
40437 $this->tags = $tags;
40438 }
40439
40440 return $this->tags;
40441 }
40442
40443
40444
40445
40446 public function getBranches()
40447 {
40448 if (null === $this->branches) {
40449 $branches = array();
40450 $bookmarks = array();
40451
40452 $this->process->execute('hg branches', $output, $this->repoDir);
40453 foreach ($this->process->splitLines($output) as $branch) {
40454 if ($branch && preg_match('(^([^\s]+)\s+\d+:([a-f0-9]+))', $branch, $match)) {
40455 $branches[$match[1]] = $match[2];
40456 }
40457 }
40458
40459 $this->process->execute('hg bookmarks', $output, $this->repoDir);
40460 foreach ($this->process->splitLines($output) as $branch) {
40461 if ($branch && preg_match('(^(?:[\s*]*)([^\s]+)\s+\d+:(.*)$)', $branch, $match)) {
40462 $bookmarks[$match[1]] = $match[2];
40463 }
40464 }
40465
40466
40467 $this->branches = array_merge($bookmarks, $branches);
40468 }
40469
40470 return $this->branches;
40471 }
40472
40473
40474
40475
40476 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
40477 {
40478 if (preg_match('#(^(?:https?|ssh)://(?:[^@]+@)?bitbucket.org|https://(?:.*?)\.kilnhg.com)#i', $url)) {
40479 return true;
40480 }
40481
40482
40483 if (Filesystem::isLocalPath($url)) {
40484 $url = Filesystem::getPlatformPath($url);
40485 if (!is_dir($url)) {
40486 return false;
40487 }
40488
40489 $process = new ProcessExecutor($io);
40490
40491 if ($process->execute('hg summary', $output, $url) === 0) {
40492 return true;
40493 }
40494 }
40495
40496 if (!$deep) {
40497 return false;
40498 }
40499
40500 $processExecutor = new ProcessExecutor($io);
40501 $exit = $processExecutor->execute(sprintf('hg identify -- %s', ProcessExecutor::escape($url)), $ignored);
40502
40503 return $exit === 0;
40504 }
40505 }
40506 <?php
40507
40508
40509
40510
40511
40512
40513
40514
40515
40516
40517
40518 namespace Composer\Repository\Vcs;
40519
40520 use Composer\Config;
40521 use Composer\Cache;
40522 use Composer\IO\IOInterface;
40523 use Composer\Util\ProcessExecutor;
40524 use Composer\Util\Perforce;
40525
40526
40527
40528
40529 class PerforceDriver extends VcsDriver
40530 {
40531 protected $depot;
40532 protected $branch;
40533
40534 protected $perforce;
40535
40536
40537
40538
40539 public function initialize()
40540 {
40541 $this->depot = $this->repoConfig['depot'];
40542 $this->branch = '';
40543 if (!empty($this->repoConfig['branch'])) {
40544 $this->branch = $this->repoConfig['branch'];
40545 }
40546
40547 $this->initPerforce($this->repoConfig);
40548 $this->perforce->p4Login();
40549 $this->perforce->checkStream();
40550
40551 $this->perforce->writeP4ClientSpec();
40552 $this->perforce->connectClient();
40553
40554 return true;
40555 }
40556
40557 private function initPerforce($repoConfig)
40558 {
40559 if (!empty($this->perforce)) {
40560 return;
40561 }
40562
40563 if (!Cache::isUsable($this->config->get('cache-vcs-dir'))) {
40564 throw new \RuntimeException('PerforceDriver requires a usable cache directory, and it looks like you set it to be disabled');
40565 }
40566
40567 $repoDir = $this->config->get('cache-vcs-dir') . '/' . $this->depot;
40568 $this->perforce = Perforce::create($repoConfig, $this->getUrl(), $repoDir, $this->process, $this->io);
40569 }
40570
40571
40572
40573
40574 public function getFileContent($file, $identifier)
40575 {
40576 return $this->perforce->getFileContent($file, $identifier);
40577 }
40578
40579
40580
40581
40582 public function getChangeDate($identifier)
40583 {
40584 return null;
40585 }
40586
40587
40588
40589
40590 public function getRootIdentifier()
40591 {
40592 return $this->branch;
40593 }
40594
40595
40596
40597
40598 public function getBranches()
40599 {
40600 return $this->perforce->getBranches();
40601 }
40602
40603
40604
40605
40606 public function getTags()
40607 {
40608 return $this->perforce->getTags();
40609 }
40610
40611
40612
40613
40614 public function getDist($identifier)
40615 {
40616 return null;
40617 }
40618
40619
40620
40621
40622 public function getSource($identifier)
40623 {
40624 $source = array(
40625 'type' => 'perforce',
40626 'url' => $this->repoConfig['url'],
40627 'reference' => $identifier,
40628 'p4user' => $this->perforce->getUser(),
40629 );
40630
40631 return $source;
40632 }
40633
40634
40635
40636
40637 public function getUrl()
40638 {
40639 return $this->url;
40640 }
40641
40642
40643
40644
40645 public function hasComposerFile($identifier)
40646 {
40647 $composerInfo = $this->perforce->getComposerInformation('//' . $this->depot . '/' . $identifier);
40648 $composerInfoIdentifier = $identifier;
40649
40650 return !empty($composerInfo);
40651 }
40652
40653
40654
40655
40656 public function getContents($url)
40657 {
40658 return false;
40659 }
40660
40661
40662
40663
40664 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
40665 {
40666 if ($deep || preg_match('#\b(perforce|p4)\b#i', $url)) {
40667 return Perforce::checkServerExists($url, new ProcessExecutor($io));
40668 }
40669
40670 return false;
40671 }
40672
40673
40674
40675
40676 public function cleanup()
40677 {
40678 $this->perforce->cleanupClientSpec();
40679 $this->perforce = null;
40680 }
40681
40682 public function getDepot()
40683 {
40684 return $this->depot;
40685 }
40686
40687 public function getBranch()
40688 {
40689 return $this->branch;
40690 }
40691 }
40692 <?php
40693
40694
40695
40696
40697
40698
40699
40700
40701
40702
40703
40704 namespace Composer\Repository\Vcs;
40705
40706 use Composer\Cache;
40707 use Composer\Config;
40708 use Composer\Json\JsonFile;
40709 use Composer\Util\ProcessExecutor;
40710 use Composer\Util\Filesystem;
40711 use Composer\Util\Svn as SvnUtil;
40712 use Composer\IO\IOInterface;
40713 use Composer\Downloader\TransportException;
40714
40715
40716
40717
40718
40719 class SvnDriver extends VcsDriver
40720 {
40721
40722
40723
40724 protected $cache;
40725 protected $baseUrl;
40726 protected $tags;
40727 protected $branches;
40728 protected $rootIdentifier;
40729 protected $infoCache = array();
40730
40731 protected $trunkPath = 'trunk';
40732 protected $branchesPath = 'branches';
40733 protected $tagsPath = 'tags';
40734 protected $packagePath = '';
40735 protected $cacheCredentials = true;
40736
40737
40738
40739
40740 private $util;
40741
40742
40743
40744
40745 public function initialize()
40746 {
40747 $this->url = $this->baseUrl = rtrim(self::normalizeUrl($this->url), '/');
40748
40749 SvnUtil::cleanEnv();
40750
40751 if (isset($this->repoConfig['trunk-path'])) {
40752 $this->trunkPath = $this->repoConfig['trunk-path'];
40753 }
40754 if (isset($this->repoConfig['branches-path'])) {
40755 $this->branchesPath = $this->repoConfig['branches-path'];
40756 }
40757 if (isset($this->repoConfig['tags-path'])) {
40758 $this->tagsPath = $this->repoConfig['tags-path'];
40759 }
40760 if (array_key_exists('svn-cache-credentials', $this->repoConfig)) {
40761 $this->cacheCredentials = (bool) $this->repoConfig['svn-cache-credentials'];
40762 }
40763 if (isset($this->repoConfig['package-path'])) {
40764 $this->packagePath = '/' . trim($this->repoConfig['package-path'], '/');
40765 }
40766
40767 if (false !== ($pos = strrpos($this->url, '/' . $this->trunkPath))) {
40768 $this->baseUrl = substr($this->url, 0, $pos);
40769 }
40770
40771 $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $this->baseUrl));
40772
40773 $this->getBranches();
40774 $this->getTags();
40775 }
40776
40777
40778
40779
40780 public function getRootIdentifier()
40781 {
40782 return $this->rootIdentifier ?: $this->trunkPath;
40783 }
40784
40785
40786
40787
40788 public function getUrl()
40789 {
40790 return $this->url;
40791 }
40792
40793
40794
40795
40796 public function getSource($identifier)
40797 {
40798 return array('type' => 'svn', 'url' => $this->baseUrl, 'reference' => $identifier);
40799 }
40800
40801
40802
40803
40804 public function getDist($identifier)
40805 {
40806 return null;
40807 }
40808
40809
40810
40811
40812 protected function shouldCache($identifier)
40813 {
40814 return $this->cache && preg_match('{@\d+$}', $identifier);
40815 }
40816
40817
40818
40819
40820 public function getComposerInformation($identifier)
40821 {
40822 if (!isset($this->infoCache[$identifier])) {
40823 if ($this->shouldCache($identifier) && $res = $this->cache->read($identifier.'.json')) {
40824 return $this->infoCache[$identifier] = JsonFile::parseJson($res);
40825 }
40826
40827 try {
40828 $composer = $this->getBaseComposerInformation($identifier);
40829 } catch (TransportException $e) {
40830 $message = $e->getMessage();
40831 if (stripos($message, 'path not found') === false && stripos($message, 'svn: warning: W160013') === false) {
40832 throw $e;
40833 }
40834
40835 $composer = '';
40836 }
40837
40838 if ($this->shouldCache($identifier)) {
40839 $this->cache->write($identifier.'.json', json_encode($composer));
40840 }
40841
40842 $this->infoCache[$identifier] = $composer;
40843 }
40844
40845 return $this->infoCache[$identifier];
40846 }
40847
40848
40849
40850
40851
40852 public function getFileContent($file, $identifier)
40853 {
40854 $identifier = '/' . trim($identifier, '/') . '/';
40855
40856 preg_match('{^(.+?)(@\d+)?/$}', $identifier, $match);
40857 if (!empty($match[2])) {
40858 $path = $match[1];
40859 $rev = $match[2];
40860 } else {
40861 $path = $identifier;
40862 $rev = '';
40863 }
40864
40865 try {
40866 $resource = $path.$file;
40867 $output = $this->execute('svn cat', $this->baseUrl . $resource . $rev);
40868 if (!trim($output)) {
40869 return null;
40870 }
40871 } catch (\RuntimeException $e) {
40872 throw new TransportException($e->getMessage());
40873 }
40874
40875 return $output;
40876 }
40877
40878
40879
40880
40881 public function getChangeDate($identifier)
40882 {
40883 $identifier = '/' . trim($identifier, '/') . '/';
40884
40885 preg_match('{^(.+?)(@\d+)?/$}', $identifier, $match);
40886 if (!empty($match[2])) {
40887 $path = $match[1];
40888 $rev = $match[2];
40889 } else {
40890 $path = $identifier;
40891 $rev = '';
40892 }
40893
40894 $output = $this->execute('svn info', $this->baseUrl . $path . $rev);
40895 foreach ($this->process->splitLines($output) as $line) {
40896 if ($line && preg_match('{^Last Changed Date: ([^(]+)}', $line, $match)) {
40897 return new \DateTime($match[1], new \DateTimeZone('UTC'));
40898 }
40899 }
40900
40901 return null;
40902 }
40903
40904
40905
40906
40907 public function getTags()
40908 {
40909 if (null === $this->tags) {
40910 $this->tags = array();
40911
40912 if ($this->tagsPath !== false) {
40913 $output = $this->execute('svn ls --verbose', $this->baseUrl . '/' . $this->tagsPath);
40914 if ($output) {
40915 foreach ($this->process->splitLines($output) as $line) {
40916 $line = trim($line);
40917 if ($line && preg_match('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) {
40918 if (isset($match[1]) && isset($match[2]) && $match[2] !== './') {
40919 $this->tags[rtrim($match[2], '/')] = $this->buildIdentifier(
40920 '/' . $this->tagsPath . '/' . $match[2],
40921 $match[1]
40922 );
40923 }
40924 }
40925 }
40926 }
40927 }
40928 }
40929
40930 return $this->tags;
40931 }
40932
40933
40934
40935
40936 public function getBranches()
40937 {
40938 if (null === $this->branches) {
40939 $this->branches = array();
40940
40941 if (false === $this->trunkPath) {
40942 $trunkParent = $this->baseUrl . '/';
40943 } else {
40944 $trunkParent = $this->baseUrl . '/' . $this->trunkPath;
40945 }
40946
40947 $output = $this->execute('svn ls --verbose', $trunkParent);
40948 if ($output) {
40949 foreach ($this->process->splitLines($output) as $line) {
40950 $line = trim($line);
40951 if ($line && preg_match('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) {
40952 if (isset($match[1]) && isset($match[2]) && $match[2] === './') {
40953 $this->branches['trunk'] = $this->buildIdentifier(
40954 '/' . $this->trunkPath,
40955 $match[1]
40956 );
40957 $this->rootIdentifier = $this->branches['trunk'];
40958 break;
40959 }
40960 }
40961 }
40962 }
40963 unset($output);
40964
40965 if ($this->branchesPath !== false) {
40966 $output = $this->execute('svn ls --verbose', $this->baseUrl . '/' . $this->branchesPath);
40967 if ($output) {
40968 foreach ($this->process->splitLines(trim($output)) as $line) {
40969 $line = trim($line);
40970 if ($line && preg_match('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) {
40971 if (isset($match[1]) && isset($match[2]) && $match[2] !== './') {
40972 $this->branches[rtrim($match[2], '/')] = $this->buildIdentifier(
40973 '/' . $this->branchesPath . '/' . $match[2],
40974 $match[1]
40975 );
40976 }
40977 }
40978 }
40979 }
40980 }
40981 }
40982
40983 return $this->branches;
40984 }
40985
40986
40987
40988
40989 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
40990 {
40991 $url = self::normalizeUrl($url);
40992 if (preg_match('#(^svn://|^svn\+ssh://|svn\.)#i', $url)) {
40993 return true;
40994 }
40995
40996
40997 if (!$deep && !Filesystem::isLocalPath($url)) {
40998 return false;
40999 }
41000
41001 $processExecutor = new ProcessExecutor($io);
41002
41003 $exit = $processExecutor->execute(
41004 "svn info --non-interactive -- ".ProcessExecutor::escape($url),
41005 $ignoredOutput
41006 );
41007
41008 if ($exit === 0) {
41009
41010 return true;
41011 }
41012
41013
41014 if (false !== stripos($processExecutor->getErrorOutput(), 'authorization failed:')) {
41015
41016
41017 return true;
41018 }
41019
41020
41021 if (false !== stripos($processExecutor->getErrorOutput(), 'Authentication failed')) {
41022
41023
41024 return true;
41025 }
41026
41027 return false;
41028 }
41029
41030
41031
41032
41033
41034
41035
41036
41037 protected static function normalizeUrl($url)
41038 {
41039 $fs = new Filesystem();
41040 if ($fs->isAbsolutePath($url)) {
41041 return 'file://' . strtr($url, '\\', '/');
41042 }
41043
41044 return $url;
41045 }
41046
41047
41048
41049
41050
41051
41052
41053
41054
41055
41056 protected function execute($command, $url)
41057 {
41058 if (null === $this->util) {
41059 $this->util = new SvnUtil($this->baseUrl, $this->io, $this->config, $this->process);
41060 $this->util->setCacheCredentials($this->cacheCredentials);
41061 }
41062
41063 try {
41064 return $this->util->execute($command, $url);
41065 } catch (\RuntimeException $e) {
41066 if (null === $this->util->binaryVersion()) {
41067 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());
41068 }
41069
41070 throw new \RuntimeException(
41071 'Repository '.$this->url.' could not be processed, '.$e->getMessage()
41072 );
41073 }
41074 }
41075
41076
41077
41078
41079
41080
41081
41082
41083
41084 protected function buildIdentifier($baseDir, $revision)
41085 {
41086 return rtrim($baseDir, '/') . $this->packagePath . '/@' . $revision;
41087 }
41088 }
41089 <?php
41090
41091
41092
41093
41094
41095
41096
41097
41098
41099
41100
41101 namespace Composer\Repository\Vcs;
41102
41103 use Composer\Cache;
41104 use Composer\Downloader\TransportException;
41105 use Composer\Config;
41106 use Composer\Factory;
41107 use Composer\IO\IOInterface;
41108 use Composer\Json\JsonFile;
41109 use Composer\Util\ProcessExecutor;
41110 use Composer\Util\RemoteFilesystem;
41111 use Composer\Util\Filesystem;
41112
41113
41114
41115
41116
41117
41118 abstract class VcsDriver implements VcsDriverInterface
41119 {
41120
41121 protected $url;
41122
41123 protected $originUrl;
41124
41125 protected $repoConfig;
41126
41127 protected $io;
41128
41129 protected $config;
41130
41131 protected $process;
41132
41133 protected $remoteFilesystem;
41134
41135 protected $infoCache = array();
41136
41137 protected $cache;
41138
41139
41140
41141
41142
41143
41144
41145
41146
41147
41148 final public function __construct(array $repoConfig, IOInterface $io, Config $config, ProcessExecutor $process = null, RemoteFilesystem $remoteFilesystem = null)
41149 {
41150 if (Filesystem::isLocalPath($repoConfig['url'])) {
41151 $repoConfig['url'] = Filesystem::getPlatformPath($repoConfig['url']);
41152 }
41153
41154 $this->url = $repoConfig['url'];
41155 $this->originUrl = $repoConfig['url'];
41156 $this->repoConfig = $repoConfig;
41157 $this->io = $io;
41158 $this->config = $config;
41159 $this->process = $process ?: new ProcessExecutor($io);
41160 $this->remoteFilesystem = $remoteFilesystem ?: Factory::createRemoteFilesystem($this->io, $config);
41161 }
41162
41163
41164
41165
41166
41167
41168
41169 protected function shouldCache($identifier)
41170 {
41171 return $this->cache && preg_match('{[a-f0-9]{40}}i', $identifier);
41172 }
41173
41174
41175
41176
41177 public function getComposerInformation($identifier)
41178 {
41179 if (!isset($this->infoCache[$identifier])) {
41180 if ($this->shouldCache($identifier) && $res = $this->cache->read($identifier)) {
41181 return $this->infoCache[$identifier] = JsonFile::parseJson($res);
41182 }
41183
41184 $composer = $this->getBaseComposerInformation($identifier);
41185
41186 if ($this->shouldCache($identifier)) {
41187 $this->cache->write($identifier, json_encode($composer));
41188 }
41189
41190 $this->infoCache[$identifier] = $composer;
41191 }
41192
41193 return $this->infoCache[$identifier];
41194 }
41195
41196 protected function getBaseComposerInformation($identifier)
41197 {
41198 $composerFileContent = $this->getFileContent('composer.json', $identifier);
41199
41200 if (!$composerFileContent) {
41201 return null;
41202 }
41203
41204 $composer = JsonFile::parseJson($composerFileContent, $identifier . ':composer.json');
41205
41206 if (empty($composer['time']) && $changeDate = $this->getChangeDate($identifier)) {
41207 $composer['time'] = $changeDate->format(DATE_RFC3339);
41208 }
41209
41210 return $composer;
41211 }
41212
41213
41214
41215
41216 public function hasComposerFile($identifier)
41217 {
41218 try {
41219 return (bool) $this->getComposerInformation($identifier);
41220 } catch (TransportException $e) {
41221 }
41222
41223 return false;
41224 }
41225
41226
41227
41228
41229
41230
41231
41232
41233 protected function getScheme()
41234 {
41235 if (extension_loaded('openssl')) {
41236 return 'https';
41237 }
41238
41239 return 'http';
41240 }
41241
41242
41243
41244
41245
41246
41247
41248
41249 protected function getContents($url)
41250 {
41251 $options = isset($this->repoConfig['options']) ? $this->repoConfig['options'] : array();
41252
41253 return $this->remoteFilesystem->getContents($this->originUrl, $url, false, $options);
41254 }
41255
41256
41257
41258
41259 public function cleanup()
41260 {
41261 return;
41262 }
41263 }
41264 <?php
41265
41266
41267
41268
41269
41270
41271
41272
41273
41274
41275
41276 namespace Composer\Repository\Vcs;
41277
41278 use Composer\Config;
41279 use Composer\IO\IOInterface;
41280
41281
41282
41283
41284 interface VcsDriverInterface
41285 {
41286
41287
41288
41289 public function initialize();
41290
41291
41292
41293
41294
41295
41296
41297 public function getComposerInformation($identifier);
41298
41299
41300
41301
41302
41303
41304
41305
41306 public function getFileContent($file, $identifier);
41307
41308
41309
41310
41311
41312
41313
41314 public function getChangeDate($identifier);
41315
41316
41317
41318
41319
41320
41321 public function getRootIdentifier();
41322
41323
41324
41325
41326
41327
41328 public function getBranches();
41329
41330
41331
41332
41333
41334
41335 public function getTags();
41336
41337
41338
41339
41340
41341 public function getDist($identifier);
41342
41343
41344
41345
41346
41347 public function getSource($identifier);
41348
41349
41350
41351
41352
41353
41354 public function getUrl();
41355
41356
41357
41358
41359
41360
41361
41362
41363 public function hasComposerFile($identifier);
41364
41365
41366
41367
41368 public function cleanup();
41369
41370
41371
41372
41373
41374
41375
41376
41377
41378
41379 public static function supports(IOInterface $io, Config $config, $url, $deep = false);
41380 }
41381 <?php
41382
41383
41384
41385
41386
41387
41388
41389
41390
41391
41392
41393 namespace Composer\Repository;
41394
41395 use Composer\Downloader\TransportException;
41396 use Composer\Repository\Vcs\VcsDriverInterface;
41397 use Composer\Package\Version\VersionParser;
41398 use Composer\Package\Loader\ArrayLoader;
41399 use Composer\Package\Loader\ValidatingArrayLoader;
41400 use Composer\Package\Loader\InvalidPackageException;
41401 use Composer\Package\Loader\LoaderInterface;
41402 use Composer\EventDispatcher\EventDispatcher;
41403 use Composer\Semver\Constraint\Constraint;
41404 use Composer\IO\IOInterface;
41405 use Composer\Config;
41406
41407
41408
41409
41410 class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInterface
41411 {
41412 protected $url;
41413 protected $packageName;
41414 protected $isVerbose;
41415 protected $isVeryVerbose;
41416 protected $io;
41417 protected $config;
41418 protected $versionParser;
41419 protected $type;
41420 protected $loader;
41421 protected $repoConfig;
41422 protected $branchErrorOccurred = false;
41423 private $drivers;
41424
41425 private $driver;
41426
41427 private $versionCache;
41428 private $emptyReferences = array();
41429 private $versionTransportExceptions = array();
41430
41431 public function __construct(array $repoConfig, IOInterface $io, Config $config, EventDispatcher $dispatcher = null, array $drivers = null, VersionCacheInterface $versionCache = null)
41432 {
41433 parent::__construct();
41434 $this->drivers = $drivers ?: array(
41435 'github' => 'Composer\Repository\Vcs\GitHubDriver',
41436 'gitlab' => 'Composer\Repository\Vcs\GitLabDriver',
41437 'git-bitbucket' => 'Composer\Repository\Vcs\GitBitbucketDriver',
41438 'git' => 'Composer\Repository\Vcs\GitDriver',
41439 'hg-bitbucket' => 'Composer\Repository\Vcs\HgBitbucketDriver',
41440 'hg' => 'Composer\Repository\Vcs\HgDriver',
41441 'perforce' => 'Composer\Repository\Vcs\PerforceDriver',
41442 'fossil' => 'Composer\Repository\Vcs\FossilDriver',
41443
41444 'svn' => 'Composer\Repository\Vcs\SvnDriver',
41445 );
41446
41447 $this->url = $repoConfig['url'];
41448 $this->io = $io;
41449 $this->type = isset($repoConfig['type']) ? $repoConfig['type'] : 'vcs';
41450 $this->isVerbose = $io->isVerbose();
41451 $this->isVeryVerbose = $io->isVeryVerbose();
41452 $this->config = $config;
41453 $this->repoConfig = $repoConfig;
41454 $this->versionCache = $versionCache;
41455 }
41456
41457 public function getRepoConfig()
41458 {
41459 return $this->repoConfig;
41460 }
41461
41462 public function setLoader(LoaderInterface $loader)
41463 {
41464 $this->loader = $loader;
41465 }
41466
41467 public function getDriver()
41468 {
41469 if ($this->driver) {
41470 return $this->driver;
41471 }
41472
41473 if (isset($this->drivers[$this->type])) {
41474 $class = $this->drivers[$this->type];
41475 $this->driver = new $class($this->repoConfig, $this->io, $this->config);
41476 $this->driver->initialize();
41477
41478 return $this->driver;
41479 }
41480
41481 foreach ($this->drivers as $driver) {
41482 if ($driver::supports($this->io, $this->config, $this->url)) {
41483 $this->driver = new $driver($this->repoConfig, $this->io, $this->config);
41484 $this->driver->initialize();
41485
41486 return $this->driver;
41487 }
41488 }
41489
41490 foreach ($this->drivers as $driver) {
41491 if ($driver::supports($this->io, $this->config, $this->url, true)) {
41492 $this->driver = new $driver($this->repoConfig, $this->io, $this->config);
41493 $this->driver->initialize();
41494
41495 return $this->driver;
41496 }
41497 }
41498 }
41499
41500 public function hadInvalidBranches()
41501 {
41502 return $this->branchErrorOccurred;
41503 }
41504
41505 public function getEmptyReferences()
41506 {
41507 return $this->emptyReferences;
41508 }
41509
41510 public function getVersionTransportExceptions()
41511 {
41512 return $this->versionTransportExceptions;
41513 }
41514
41515 protected function initialize()
41516 {
41517 parent::initialize();
41518
41519 $isVerbose = $this->isVerbose;
41520 $isVeryVerbose = $this->isVeryVerbose;
41521
41522 $driver = $this->getDriver();
41523 if (!$driver) {
41524 throw new \InvalidArgumentException('No driver found to handle VCS repository '.$this->url);
41525 }
41526
41527 $this->versionParser = new VersionParser;
41528 if (!$this->loader) {
41529 $this->loader = new ArrayLoader($this->versionParser);
41530 }
41531
41532 try {
41533 if ($driver->hasComposerFile($driver->getRootIdentifier())) {
41534 $data = $driver->getComposerInformation($driver->getRootIdentifier());
41535 $this->packageName = !empty($data['name']) ? $data['name'] : null;
41536 }
41537 } catch (\Exception $e) {
41538 if ($isVeryVerbose) {
41539 $this->io->writeError('<error>Skipped parsing '.$driver->getRootIdentifier().', '.$e->getMessage().'</error>');
41540 }
41541 }
41542
41543 foreach ($driver->getTags() as $tag => $identifier) {
41544 $msg = 'Reading composer.json of <info>' . ($this->packageName ?: $this->url) . '</info> (<comment>' . $tag . '</comment>)';
41545 if ($isVeryVerbose) {
41546 $this->io->writeError($msg);
41547 } elseif ($isVerbose) {
41548 $this->io->overwriteError($msg, false);
41549 }
41550
41551
41552 $tag = str_replace('release-', '', $tag);
41553
41554 $cachedPackage = $this->getCachedPackageVersion($tag, $identifier, $isVerbose, $isVeryVerbose);
41555 if ($cachedPackage) {
41556 $this->addPackage($cachedPackage);
41557
41558 continue;
41559 } elseif ($cachedPackage === false) {
41560 $this->emptyReferences[] = $identifier;
41561
41562 continue;
41563 }
41564
41565 if (!$parsedTag = $this->validateTag($tag)) {
41566 if ($isVeryVerbose) {
41567 $this->io->writeError('<warning>Skipped tag '.$tag.', invalid tag name</warning>');
41568 }
41569 continue;
41570 }
41571
41572 try {
41573 if (!$data = $driver->getComposerInformation($identifier)) {
41574 if ($isVeryVerbose) {
41575 $this->io->writeError('<warning>Skipped tag '.$tag.', no composer file</warning>');
41576 }
41577 $this->emptyReferences[] = $identifier;
41578 continue;
41579 }
41580
41581
41582 if (isset($data['version'])) {
41583 $data['version_normalized'] = $this->versionParser->normalize($data['version']);
41584 } else {
41585
41586 $data['version'] = $tag;
41587 $data['version_normalized'] = $parsedTag;
41588 }
41589
41590
41591 $data['version'] = preg_replace('{[.-]?dev$}i', '', $data['version']);
41592 $data['version_normalized'] = preg_replace('{(^dev-|[.-]?dev$)}i', '', $data['version_normalized']);
41593
41594
41595 if ($data['version_normalized'] !== $parsedTag) {
41596 if ($isVeryVerbose) {
41597 if (preg_match('{(^dev-|[.-]?dev$)}i', $parsedTag)) {
41598 $this->io->writeError('<warning>Skipped tag '.$tag.', invalid tag name, tags can not use dev prefixes or suffixes</warning>');
41599 } else {
41600 $this->io->writeError('<warning>Skipped tag '.$tag.', tag ('.$parsedTag.') does not match version ('.$data['version_normalized'].') in composer.json</warning>');
41601 }
41602 }
41603 continue;
41604 }
41605
41606 $tagPackageName = isset($data['name']) ? $data['name'] : $this->packageName;
41607 if ($existingPackage = $this->findPackage($tagPackageName, $data['version_normalized'])) {
41608 if ($isVeryVerbose) {
41609 $this->io->writeError('<warning>Skipped tag '.$tag.', it conflicts with an another tag ('.$existingPackage->getPrettyVersion().') as both resolve to '.$data['version_normalized'].' internally</warning>');
41610 }
41611 continue;
41612 }
41613
41614 if ($isVeryVerbose) {
41615 $this->io->writeError('Importing tag '.$tag.' ('.$data['version_normalized'].')');
41616 }
41617
41618 $this->addPackage($this->loader->load($this->preProcess($driver, $data, $identifier)));
41619 } catch (\Exception $e) {
41620 if ($e instanceof TransportException) {
41621 $this->versionTransportExceptions['tags'][$tag] = $e;
41622 if ($e->getCode() === 404) {
41623 $this->emptyReferences[] = $identifier;
41624 }
41625 }
41626 if ($isVeryVerbose) {
41627 $this->io->writeError('<warning>Skipped tag '.$tag.', '.($e instanceof TransportException ? 'no composer file was found (' . $e->getCode() . ' HTTP status code)' : $e->getMessage()).'</warning>');
41628 }
41629 continue;
41630 }
41631 }
41632
41633 if (!$isVeryVerbose) {
41634 $this->io->overwriteError('', false);
41635 }
41636
41637 $branches = $driver->getBranches();
41638 foreach ($branches as $branch => $identifier) {
41639 $msg = 'Reading composer.json of <info>' . ($this->packageName ?: $this->url) . '</info> (<comment>' . $branch . '</comment>)';
41640 if ($isVeryVerbose) {
41641 $this->io->writeError($msg);
41642 } elseif ($isVerbose) {
41643 $this->io->overwriteError($msg, false);
41644 }
41645
41646 if ($branch === 'trunk' && isset($branches['master'])) {
41647 if ($isVeryVerbose) {
41648 $this->io->writeError('<warning>Skipped branch '.$branch.', can not parse both master and trunk branches as they both resolve to 9999999-dev internally</warning>');
41649 }
41650 continue;
41651 }
41652
41653 if (!$parsedBranch = $this->validateBranch($branch)) {
41654 if ($isVeryVerbose) {
41655 $this->io->writeError('<warning>Skipped branch '.$branch.', invalid name</warning>');
41656 }
41657 continue;
41658 }
41659
41660
41661 if ('dev-' === substr($parsedBranch, 0, 4) || '9999999-dev' === $parsedBranch) {
41662 $version = 'dev-' . $branch;
41663 } else {
41664 $prefix = substr($branch, 0, 1) === 'v' ? 'v' : '';
41665 $version = $prefix . preg_replace('{(\.9{7})+}', '.x', $parsedBranch);
41666 }
41667
41668 $cachedPackage = $this->getCachedPackageVersion($version, $identifier, $isVerbose, $isVeryVerbose);
41669 if ($cachedPackage) {
41670 $this->addPackage($cachedPackage);
41671
41672 continue;
41673 } elseif ($cachedPackage === false) {
41674 $this->emptyReferences[] = $identifier;
41675
41676 continue;
41677 }
41678
41679 try {
41680 if (!$data = $driver->getComposerInformation($identifier)) {
41681 if ($isVeryVerbose) {
41682 $this->io->writeError('<warning>Skipped branch '.$branch.', no composer file</warning>');
41683 }
41684 $this->emptyReferences[] = $identifier;
41685 continue;
41686 }
41687
41688
41689 $data['version'] = $version;
41690 $data['version_normalized'] = $parsedBranch;
41691
41692 if ($isVeryVerbose) {
41693 $this->io->writeError('Importing branch '.$branch.' ('.$data['version'].')');
41694 }
41695
41696 $packageData = $this->preProcess($driver, $data, $identifier);
41697 $package = $this->loader->load($packageData);
41698 if ($this->loader instanceof ValidatingArrayLoader && $this->loader->getWarnings()) {
41699 throw new InvalidPackageException($this->loader->getErrors(), $this->loader->getWarnings(), $packageData);
41700 }
41701 $this->addPackage($package);
41702 } catch (TransportException $e) {
41703 $this->versionTransportExceptions['branches'][$branch] = $e;
41704 if ($e->getCode() === 404) {
41705 $this->emptyReferences[] = $identifier;
41706 }
41707 if ($isVeryVerbose) {
41708 $this->io->writeError('<warning>Skipped branch '.$branch.', no composer file was found (' . $e->getCode() . ' HTTP status code)</warning>');
41709 }
41710 continue;
41711 } catch (\Exception $e) {
41712 if (!$isVeryVerbose) {
41713 $this->io->writeError('');
41714 }
41715 $this->branchErrorOccurred = true;
41716 $this->io->writeError('<error>Skipped branch '.$branch.', '.$e->getMessage().'</error>');
41717 $this->io->writeError('');
41718 continue;
41719 }
41720 }
41721 $driver->cleanup();
41722
41723 if (!$isVeryVerbose) {
41724 $this->io->overwriteError('', false);
41725 }
41726
41727 if (!$this->getPackages()) {
41728 throw new InvalidRepositoryException('No valid composer.json was found in any branch or tag of '.$this->url.', could not load a package from it.');
41729 }
41730 }
41731
41732 protected function preProcess(VcsDriverInterface $driver, array $data, $identifier)
41733 {
41734
41735 $dataPackageName = isset($data['name']) ? $data['name'] : null;
41736 $data['name'] = $this->packageName ?: $dataPackageName;
41737
41738 if (!isset($data['dist'])) {
41739 $data['dist'] = $driver->getDist($identifier);
41740 }
41741 if (!isset($data['source'])) {
41742 $data['source'] = $driver->getSource($identifier);
41743 }
41744
41745 return $data;
41746 }
41747
41748 private function validateBranch($branch)
41749 {
41750 try {
41751 $normalizedBranch = $this->versionParser->normalizeBranch($branch);
41752
41753
41754 $this->versionParser->parseConstraints($normalizedBranch);
41755
41756 return $normalizedBranch;
41757 } catch (\Exception $e) {
41758 }
41759
41760 return false;
41761 }
41762
41763 private function validateTag($version)
41764 {
41765 try {
41766 return $this->versionParser->normalize($version);
41767 } catch (\Exception $e) {
41768 }
41769
41770 return false;
41771 }
41772
41773 private function getCachedPackageVersion($version, $identifier, $isVerbose, $isVeryVerbose)
41774 {
41775 if (!$this->versionCache) {
41776 return;
41777 }
41778
41779 $cachedPackage = $this->versionCache->getVersionPackage($version, $identifier);
41780 if ($cachedPackage === false) {
41781 if ($isVeryVerbose) {
41782 $this->io->writeError('<warning>Skipped '.$version.', no composer file (cached from ref '.$identifier.')</warning>');
41783 }
41784
41785 return false;
41786 }
41787
41788 if ($cachedPackage) {
41789 $msg = 'Found cached composer.json of <info>' . ($this->packageName ?: $this->url) . '</info> (<comment>' . $version . '</comment>)';
41790 if ($isVeryVerbose) {
41791 $this->io->writeError($msg);
41792 } elseif ($isVerbose) {
41793 $this->io->overwriteError($msg, false);
41794 }
41795
41796 if ($existingPackage = $this->findPackage($cachedPackage['name'], new Constraint('=', $cachedPackage['version_normalized']))) {
41797 if ($isVeryVerbose) {
41798 $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>');
41799 }
41800 $cachedPackage = null;
41801 }
41802 }
41803
41804 if ($cachedPackage) {
41805 return $this->loader->load($cachedPackage);
41806 }
41807
41808 return null;
41809 }
41810 }
41811 <?php
41812
41813
41814
41815
41816
41817
41818
41819
41820
41821
41822
41823 namespace Composer\Repository;
41824
41825 interface VersionCacheInterface
41826 {
41827
41828
41829
41830
41831
41832 public function getVersionPackage($version, $identifier);
41833 }
41834 <?php
41835
41836
41837
41838
41839
41840
41841
41842
41843
41844
41845
41846 namespace Composer\Repository;
41847
41848 use Composer\Package\AliasPackage;
41849
41850
41851
41852
41853
41854
41855 class WritableArrayRepository extends ArrayRepository implements WritableRepositoryInterface
41856 {
41857
41858
41859
41860 public function write()
41861 {
41862 }
41863
41864
41865
41866
41867 public function reload()
41868 {
41869 }
41870
41871
41872
41873
41874 public function getCanonicalPackages()
41875 {
41876 $packages = $this->getPackages();
41877
41878
41879 $packagesByName = array();
41880 foreach ($packages as $package) {
41881 if (!isset($packagesByName[$package->getName()]) || $packagesByName[$package->getName()] instanceof AliasPackage) {
41882 $packagesByName[$package->getName()] = $package;
41883 }
41884 }
41885
41886 $canonicalPackages = array();
41887
41888
41889 foreach ($packagesByName as $package) {
41890 while ($package instanceof AliasPackage) {
41891 $package = $package->getAliasOf();
41892 }
41893
41894 $canonicalPackages[] = $package;
41895 }
41896
41897 return $canonicalPackages;
41898 }
41899 }
41900 <?php
41901
41902
41903
41904
41905
41906
41907
41908
41909
41910
41911
41912 namespace Composer\Repository;
41913
41914 use Composer\Package\PackageInterface;
41915
41916
41917
41918
41919
41920
41921 interface WritableRepositoryInterface extends RepositoryInterface
41922 {
41923
41924
41925
41926 public function write();
41927
41928
41929
41930
41931
41932
41933 public function addPackage(PackageInterface $package);
41934
41935
41936
41937
41938
41939
41940 public function removePackage(PackageInterface $package);
41941
41942
41943
41944
41945
41946
41947 public function getCanonicalPackages();
41948
41949
41950
41951
41952 public function reload();
41953 }
41954 <?php
41955
41956
41957
41958
41959
41960
41961
41962
41963
41964
41965
41966 namespace Composer\Script;
41967
41968
41969
41970
41971
41972
41973 class CommandEvent extends Event
41974 {
41975 }
41976 <?php
41977
41978
41979
41980
41981
41982
41983
41984
41985
41986
41987
41988 namespace Composer\Script;
41989
41990 use Composer\Composer;
41991 use Composer\IO\IOInterface;
41992 use Composer\EventDispatcher\Event as BaseEvent;
41993
41994
41995
41996
41997
41998
41999
42000 class Event extends BaseEvent
42001 {
42002
42003
42004
42005 private $composer;
42006
42007
42008
42009
42010 private $io;
42011
42012
42013
42014
42015 private $devMode;
42016
42017
42018
42019
42020 private $originatingEvent;
42021
42022
42023
42024
42025
42026
42027
42028
42029
42030
42031
42032 public function __construct($name, Composer $composer, IOInterface $io, $devMode = false, array $args = array(), array $flags = array())
42033 {
42034 parent::__construct($name, $args, $flags);
42035 $this->composer = $composer;
42036 $this->io = $io;
42037 $this->devMode = $devMode;
42038 $this->originatingEvent = null;
42039 }
42040
42041
42042
42043
42044
42045
42046 public function getComposer()
42047 {
42048 return $this->composer;
42049 }
42050
42051
42052
42053
42054
42055
42056 public function getIO()
42057 {
42058 return $this->io;
42059 }
42060
42061
42062
42063
42064
42065
42066 public function isDevMode()
42067 {
42068 return $this->devMode;
42069 }
42070
42071
42072
42073
42074
42075
42076 public function getOriginatingEvent()
42077 {
42078 return $this->originatingEvent;
42079 }
42080
42081
42082
42083
42084
42085
42086
42087 public function setOriginatingEvent(BaseEvent $event)
42088 {
42089 $this->originatingEvent = $this->calculateOriginatingEvent($event);
42090
42091 return $this;
42092 }
42093
42094
42095
42096
42097
42098
42099
42100 private function calculateOriginatingEvent(BaseEvent $event)
42101 {
42102 if ($event instanceof Event && $event->getOriginatingEvent()) {
42103 return $this->calculateOriginatingEvent($event->getOriginatingEvent());
42104 }
42105
42106 return $event;
42107 }
42108 }
42109 <?php
42110
42111
42112
42113
42114
42115
42116
42117
42118
42119
42120
42121 namespace Composer\Script;
42122
42123 use Composer\Installer\PackageEvent as BasePackageEvent;
42124
42125
42126
42127
42128
42129
42130 class PackageEvent extends BasePackageEvent
42131 {
42132 }
42133 <?php
42134
42135
42136
42137
42138
42139
42140
42141
42142
42143
42144
42145 namespace Composer\Script;
42146
42147
42148
42149
42150
42151
42152
42153 class ScriptEvents
42154 {
42155
42156
42157
42158
42159
42160
42161
42162 const PRE_INSTALL_CMD = 'pre-install-cmd';
42163
42164
42165
42166
42167
42168
42169
42170
42171 const POST_INSTALL_CMD = 'post-install-cmd';
42172
42173
42174
42175
42176
42177
42178
42179
42180 const PRE_UPDATE_CMD = 'pre-update-cmd';
42181
42182
42183
42184
42185
42186
42187
42188
42189 const POST_UPDATE_CMD = 'post-update-cmd';
42190
42191
42192
42193
42194
42195
42196
42197
42198 const PRE_STATUS_CMD = 'pre-status-cmd';
42199
42200
42201
42202
42203
42204
42205
42206
42207 const POST_STATUS_CMD = 'post-status-cmd';
42208
42209
42210
42211
42212
42213
42214
42215
42216 const PRE_AUTOLOAD_DUMP = 'pre-autoload-dump';
42217
42218
42219
42220
42221
42222
42223
42224
42225 const POST_AUTOLOAD_DUMP = 'post-autoload-dump';
42226
42227
42228
42229
42230
42231
42232
42233
42234 const POST_ROOT_PACKAGE_INSTALL = 'post-root-package-install';
42235
42236
42237
42238
42239
42240
42241
42242
42243
42244 const POST_CREATE_PROJECT_CMD = 'post-create-project-cmd';
42245
42246
42247
42248
42249
42250
42251
42252
42253 const PRE_ARCHIVE_CMD = 'pre-archive-cmd';
42254
42255
42256
42257
42258
42259
42260
42261
42262 const POST_ARCHIVE_CMD = 'post-archive-cmd';
42263
42264
42265
42266
42267
42268
42269
42270
42271
42272
42273
42274 const PRE_PACKAGE_INSTALL = 'pre-package-install';
42275
42276
42277
42278
42279
42280
42281
42282
42283
42284 const POST_PACKAGE_INSTALL = 'post-package-install';
42285
42286
42287
42288
42289
42290
42291
42292
42293
42294 const PRE_PACKAGE_UPDATE = 'pre-package-update';
42295
42296
42297
42298
42299
42300
42301
42302
42303
42304 const POST_PACKAGE_UPDATE = 'post-package-update';
42305
42306
42307
42308
42309
42310
42311
42312
42313
42314 const PRE_PACKAGE_UNINSTALL = 'pre-package-uninstall';
42315
42316
42317
42318
42319
42320
42321
42322
42323
42324 const POST_PACKAGE_UNINSTALL = 'post-package-uninstall';
42325 }
42326 <?php
42327
42328
42329
42330
42331
42332
42333
42334
42335
42336
42337
42338 namespace Composer\SelfUpdate;
42339
42340
42341
42342
42343 class Keys
42344 {
42345 public static function fingerprint($path)
42346 {
42347 $hash = strtoupper(hash('sha256', preg_replace('{\s}', '', file_get_contents($path))));
42348
42349 return implode(' ', array(
42350 substr($hash, 0, 8),
42351 substr($hash, 8, 8),
42352 substr($hash, 16, 8),
42353 substr($hash, 24, 8),
42354 '', 
42355 substr($hash, 32, 8),
42356 substr($hash, 40, 8),
42357 substr($hash, 48, 8),
42358 substr($hash, 56, 8),
42359 ));
42360 }
42361 }
42362 <?php
42363
42364
42365
42366
42367
42368
42369
42370
42371
42372
42373
42374 namespace Composer\SelfUpdate;
42375
42376 use Composer\Util\RemoteFilesystem;
42377 use Composer\Config;
42378 use Composer\Json\JsonFile;
42379
42380
42381
42382
42383 class Versions
42384 {
42385 public static $channels = array('stable', 'preview', 'snapshot', '1', '2');
42386
42387 private $rfs;
42388 private $config;
42389 private $channel;
42390 private $versionsData;
42391
42392 public function __construct(Config $config, RemoteFilesystem $rfs)
42393 {
42394 $this->rfs = $rfs;
42395 $this->config = $config;
42396 }
42397
42398 public function getChannel()
42399 {
42400 if ($this->channel) {
42401 return $this->channel;
42402 }
42403
42404 $channelFile = $this->config->get('home').'/update-channel';
42405 if (file_exists($channelFile)) {
42406 $channel = trim(file_get_contents($channelFile));
42407 if (in_array($channel, array('stable', 'preview', 'snapshot'), true)) {
42408 return $this->channel = $channel;
42409 }
42410 }
42411
42412 return $this->channel = 'stable';
42413 }
42414
42415 public function setChannel($channel)
42416 {
42417 if (!in_array($channel, self::$channels, true)) {
42418 throw new \InvalidArgumentException('Invalid channel '.$channel.', must be one of: ' . implode(', ', self::$channels));
42419 }
42420
42421 $channelFile = $this->config->get('home').'/update-channel';
42422 $this->channel = $channel;
42423 file_put_contents($channelFile, (is_numeric($channel) ? 'stable' : $channel).PHP_EOL);
42424 }
42425
42426 public function getLatest($channel = null)
42427 {
42428 $versions = $this->getVersionsData();
42429
42430 foreach ($versions[$channel ?: $this->getChannel()] as $version) {
42431 if ($version['min-php'] <= PHP_VERSION_ID) {
42432 return $version;
42433 }
42434 }
42435
42436 throw new \UnexpectedValueException('There is no version of Composer available for your PHP version ('.PHP_VERSION.')');
42437 }
42438
42439 private function getVersionsData()
42440 {
42441 if (!$this->versionsData) {
42442 if ($this->config->get('disable-tls') === true) {
42443 $protocol = 'http';
42444 } else {
42445 $protocol = 'https';
42446 }
42447
42448 $this->versionsData = JsonFile::parseJson($this->rfs->getContents('getcomposer.org', $protocol . '://getcomposer.org/versions', false));
42449 }
42450
42451 return $this->versionsData;
42452 }
42453 }
42454 <?php
42455
42456
42457
42458
42459
42460
42461
42462
42463
42464
42465
42466 namespace Composer\Util;
42467
42468 use Composer\Config;
42469 use Composer\IO\IOInterface;
42470
42471
42472
42473
42474 class AuthHelper
42475 {
42476 protected $io;
42477 protected $config;
42478
42479 public function __construct(IOInterface $io, Config $config)
42480 {
42481 $this->io = $io;
42482 $this->config = $config;
42483 }
42484
42485 public function storeAuth($originUrl, $storeAuth)
42486 {
42487 $store = false;
42488 $configSource = $this->config->getAuthConfigSource();
42489 if ($storeAuth === true) {
42490 $store = $configSource;
42491 } elseif ($storeAuth === 'prompt') {
42492 $answer = $this->io->askAndValidate(
42493 'Do you want to store credentials for '.$originUrl.' in '.$configSource->getName().' ? [Yn] ',
42494 function ($value) {
42495 $input = strtolower(substr(trim($value), 0, 1));
42496 if (in_array($input, array('y','n'))) {
42497 return $input;
42498 }
42499 throw new \RuntimeException('Please answer (y)es or (n)o');
42500 },
42501 null,
42502 'y'
42503 );
42504
42505 if ($answer === 'y') {
42506 $store = $configSource;
42507 }
42508 }
42509 if ($store) {
42510 $store->addConfigSetting(
42511 'http-basic.'.$originUrl,
42512 $this->io->getAuthentication($originUrl)
42513 );
42514 }
42515 }
42516 }
42517 <?php
42518
42519
42520
42521
42522
42523
42524
42525
42526
42527
42528
42529 namespace Composer\Util;
42530
42531 use Composer\Factory;
42532 use Composer\IO\IOInterface;
42533 use Composer\Config;
42534 use Composer\Downloader\TransportException;
42535
42536
42537
42538
42539 class Bitbucket
42540 {
42541 private $io;
42542 private $config;
42543 private $process;
42544 private $remoteFilesystem;
42545 private $token = array();
42546 private $time;
42547
42548 const OAUTH2_ACCESS_TOKEN_URL = 'https://bitbucket.org/site/oauth2/access_token';
42549
42550
42551
42552
42553
42554
42555
42556
42557
42558
42559 public function __construct(IOInterface $io, Config $config, ProcessExecutor $process = null, RemoteFilesystem $remoteFilesystem = null, $time = null)
42560 {
42561 $this->io = $io;
42562 $this->config = $config;
42563 $this->process = $process ?: new ProcessExecutor($io);
42564 $this->remoteFilesystem = $remoteFilesystem ?: Factory::createRemoteFilesystem($this->io, $config);
42565 $this->time = $time;
42566 }
42567
42568
42569
42570
42571 public function getToken()
42572 {
42573 if (!isset($this->token['access_token'])) {
42574 return '';
42575 }
42576
42577 return $this->token['access_token'];
42578 }
42579
42580
42581
42582
42583
42584
42585
42586 public function authorizeOAuth($originUrl)
42587 {
42588 if ($originUrl !== 'bitbucket.org') {
42589 return false;
42590 }
42591
42592
42593 if (0 === $this->process->execute('git config bitbucket.accesstoken', $output)) {
42594 $this->io->setAuthentication($originUrl, 'x-token-auth', trim($output));
42595
42596 return true;
42597 }
42598
42599 return false;
42600 }
42601
42602
42603
42604
42605
42606 private function requestAccessToken($originUrl)
42607 {
42608 try {
42609 $json = $this->remoteFilesystem->getContents($originUrl, self::OAUTH2_ACCESS_TOKEN_URL, false, array(
42610 'retry-auth-failure' => false,
42611 'http' => array(
42612 'method' => 'POST',
42613 'content' => 'grant_type=client_credentials',
42614 ),
42615 ));
42616
42617 $this->token = json_decode($json, true);
42618 } catch (TransportException $e) {
42619 if ($e->getCode() === 400) {
42620 $this->io->writeError('<error>Invalid OAuth consumer provided.</error>');
42621 $this->io->writeError('This can have two reasons:');
42622 $this->io->writeError('1. You are authenticating with a bitbucket username/password combination');
42623 $this->io->writeError('2. You are using an OAuth consumer, but didn\'t configure a (dummy) callback url');
42624
42625 return false;
42626 } elseif (in_array($e->getCode(), array(403, 401))) {
42627 $this->io->writeError('<error>Invalid OAuth consumer provided.</error>');
42628 $this->io->writeError('You can also add it manually later by using "composer config --global --auth bitbucket-oauth.bitbucket.org <consumer-key> <consumer-secret>"');
42629
42630 return false;
42631 }
42632
42633 throw $e;
42634 }
42635
42636 return true;
42637 }
42638
42639
42640
42641
42642
42643
42644
42645
42646
42647
42648 public function authorizeOAuthInteractively($originUrl, $message = null)
42649 {
42650 if ($message) {
42651 $this->io->writeError($message);
42652 }
42653
42654 $url = 'https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/';
42655 $this->io->writeError(sprintf('Follow the instructions on %s', $url));
42656 $this->io->writeError(sprintf('to create a consumer. It will be stored in "%s" for future use by Composer.', $this->config->getAuthConfigSource()->getName()));
42657 $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)');
42658
42659 $consumerKey = trim($this->io->askAndHideAnswer('Consumer Key (hidden): '));
42660
42661 if (!$consumerKey) {
42662 $this->io->writeError('<warning>No consumer key given, aborting.</warning>');
42663 $this->io->writeError('You can also add it manually later by using "composer config --global --auth bitbucket-oauth.bitbucket.org <consumer-key> <consumer-secret>"');
42664
42665 return false;
42666 }
42667
42668 $consumerSecret = trim($this->io->askAndHideAnswer('Consumer Secret (hidden): '));
42669
42670 if (!$consumerSecret) {
42671 $this->io->writeError('<warning>No consumer secret given, aborting.</warning>');
42672 $this->io->writeError('You can also add it manually later by using "composer config --global --auth bitbucket-oauth.bitbucket.org <consumer-key> <consumer-secret>"');
42673
42674 return false;
42675 }
42676
42677 $this->io->setAuthentication($originUrl, $consumerKey, $consumerSecret);
42678
42679 if (!$this->requestAccessToken($originUrl)) {
42680 return false;
42681 }
42682
42683
42684 $this->storeInAuthConfig($originUrl, $consumerKey, $consumerSecret);
42685
42686
42687 $this->config->getAuthConfigSource()->removeConfigSetting('http-basic.' . $originUrl);
42688
42689 $this->io->writeError('<info>Consumer stored successfully.</info>');
42690
42691 return true;
42692 }
42693
42694
42695
42696
42697
42698
42699
42700
42701
42702 public function requestToken($originUrl, $consumerKey, $consumerSecret)
42703 {
42704 if (!empty($this->token) || $this->getTokenFromConfig($originUrl)) {
42705 return $this->token['access_token'];
42706 }
42707
42708 $this->io->setAuthentication($originUrl, $consumerKey, $consumerSecret);
42709 if (!$this->requestAccessToken($originUrl)) {
42710 return '';
42711 }
42712
42713 $this->storeInAuthConfig($originUrl, $consumerKey, $consumerSecret);
42714
42715 return $this->token['access_token'];
42716 }
42717
42718
42719
42720
42721
42722
42723
42724 private function storeInAuthConfig($originUrl, $consumerKey, $consumerSecret)
42725 {
42726 $this->config->getConfigSource()->removeConfigSetting('bitbucket-oauth.'.$originUrl);
42727
42728 $time = null === $this->time ? time() : $this->time;
42729 $consumer = array(
42730 "consumer-key" => $consumerKey,
42731 "consumer-secret" => $consumerSecret,
42732 "access-token" => $this->token['access_token'],
42733 "access-token-expiration" => $time + $this->token['expires_in'],
42734 );
42735
42736 $this->config->getAuthConfigSource()->addConfigSetting('bitbucket-oauth.'.$originUrl, $consumer);
42737 }
42738
42739
42740
42741
42742
42743 private function getTokenFromConfig($originUrl)
42744 {
42745 $authConfig = $this->config->get('bitbucket-oauth');
42746
42747 if (
42748 !isset($authConfig[$originUrl]['access-token'])
42749 || !isset($authConfig[$originUrl]['access-token-expiration'])
42750 || time() > $authConfig[$originUrl]['access-token-expiration']
42751 ) {
42752 return false;
42753 }
42754
42755 $this->token = array(
42756 'access_token' => $authConfig[$originUrl]['access-token'],
42757 );
42758
42759 return true;
42760 }
42761 }
42762 <?php
42763
42764
42765
42766
42767
42768
42769
42770
42771
42772
42773
42774 namespace Composer\Util;
42775
42776
42777
42778
42779
42780
42781 class ComposerMirror
42782 {
42783 public static function processUrl($mirrorUrl, $packageName, $version, $reference, $type)
42784 {
42785 if ($reference) {
42786 $reference = preg_match('{^([a-f0-9]*|%reference%)$}', $reference) ? $reference : md5($reference);
42787 }
42788 $version = strpos($version, '/') === false ? $version : md5($version);
42789
42790 return str_replace(
42791 array('%package%', '%version%', '%reference%', '%type%'),
42792 array($packageName, $version, $reference, $type),
42793 $mirrorUrl
42794 );
42795 }
42796
42797 public static function processGitUrl($mirrorUrl, $packageName, $url, $type)
42798 {
42799 if (preg_match('#^(?:(?:https?|git)://github\.com/|git@github\.com:)([^/]+)/(.+?)(?:\.git)?$#', $url, $match)) {
42800 $url = 'gh-'.$match[1].'/'.$match[2];
42801 } elseif (preg_match('#^https://bitbucket\.org/([^/]+)/(.+?)(?:\.git)?/?$#', $url, $match)) {
42802 $url = 'bb-'.$match[1].'/'.$match[2];
42803 } else {
42804 $url = preg_replace('{[^a-z0-9_.-]}i', '-', trim($url, '/'));
42805 }
42806
42807 return str_replace(
42808 array('%package%', '%normalizedUrl%', '%type%'),
42809 array($packageName, $url, $type),
42810 $mirrorUrl
42811 );
42812 }
42813
42814 public static function processHgUrl($mirrorUrl, $packageName, $url, $type)
42815 {
42816 return self::processGitUrl($mirrorUrl, $packageName, $url, $type);
42817 }
42818 }
42819 <?php
42820
42821
42822
42823
42824
42825
42826
42827
42828
42829
42830
42831 namespace Composer\Util;
42832
42833 use Composer\Package\Loader\ArrayLoader;
42834 use Composer\Package\Loader\ValidatingArrayLoader;
42835 use Composer\Package\Loader\InvalidPackageException;
42836 use Composer\Json\JsonValidationException;
42837 use Composer\IO\IOInterface;
42838 use Composer\Json\JsonFile;
42839 use Composer\Spdx\SpdxLicenses;
42840
42841
42842
42843
42844
42845
42846
42847 class ConfigValidator
42848 {
42849 private $io;
42850
42851 public function __construct(IOInterface $io)
42852 {
42853 $this->io = $io;
42854 }
42855
42856
42857
42858
42859
42860
42861
42862
42863
42864 public function validate($file, $arrayLoaderValidationFlags = ValidatingArrayLoader::CHECK_ALL)
42865 {
42866 $errors = array();
42867 $publishErrors = array();
42868 $warnings = array();
42869
42870
42871 $laxValid = false;
42872 try {
42873 $json = new JsonFile($file, null, $this->io);
42874 $manifest = $json->read();
42875
42876 $json->validateSchema(JsonFile::LAX_SCHEMA);
42877 $laxValid = true;
42878 $json->validateSchema();
42879 } catch (JsonValidationException $e) {
42880 foreach ($e->getErrors() as $message) {
42881 if ($laxValid) {
42882 $publishErrors[] = $message;
42883 } else {
42884 $errors[] = $message;
42885 }
42886 }
42887 } catch (\Exception $e) {
42888 $errors[] = $e->getMessage();
42889
42890 return array($errors, $publishErrors, $warnings);
42891 }
42892
42893
42894 if (empty($manifest['license'])) {
42895 $warnings[] = 'No license specified, it is recommended to do so. For closed-source software you may use "proprietary" as license.';
42896 } else {
42897 $licenses = (array) $manifest['license'];
42898
42899
42900 foreach ($licenses as $key => $license) {
42901 if ('proprietary' === $license) {
42902 unset($licenses[$key]);
42903 }
42904 }
42905
42906 $licenseValidator = new SpdxLicenses();
42907 foreach ($licenses as $license) {
42908 $spdxLicense = $licenseValidator->getLicenseByIdentifier($license);
42909 if ($spdxLicense && $spdxLicense[3]) {
42910 if (preg_match('{^[AL]?GPL-[123](\.[01])?\+$}i', $license)) {
42911 $warnings[] = sprintf(
42912 'License "%s" is a deprecated SPDX license identifier, use "'.str_replace('+', '', $license).'-or-later" instead',
42913 $license
42914 );
42915 } elseif (preg_match('{^[AL]?GPL-[123](\.[01])?$}i', $license)) {
42916 $warnings[] = sprintf(
42917 'License "%s" is a deprecated SPDX license identifier, use "'.$license.'-only" or "'.$license.'-or-later" instead',
42918 $license
42919 );
42920 } else {
42921 $warnings[] = sprintf(
42922 'License "%s" is a deprecated SPDX license identifier, see https://spdx.org/licenses/',
42923 $license
42924 );
42925 }
42926 }
42927 }
42928 }
42929
42930 if (isset($manifest['version'])) {
42931 $warnings[] = 'The version field is present, it is recommended to leave it out if the package is published on Packagist.';
42932 }
42933
42934 if (!empty($manifest['name']) && preg_match('{[A-Z]}', $manifest['name'])) {
42935 $suggestName = preg_replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $manifest['name']);
42936 $suggestName = strtolower($suggestName);
42937
42938 $publishErrors[] = sprintf(
42939 '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.',
42940 $manifest['name'],
42941 $suggestName
42942 );
42943 }
42944
42945 if (!empty($manifest['type']) && $manifest['type'] == 'composer-installer') {
42946 $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.";
42947 }
42948
42949
42950 if (isset($manifest['require']) && isset($manifest['require-dev'])) {
42951 $requireOverrides = array_intersect_key($manifest['require'], $manifest['require-dev']);
42952
42953 if (!empty($requireOverrides)) {
42954 $plural = (count($requireOverrides) > 1) ? 'are' : 'is';
42955 $warnings[] = implode(', ', array_keys($requireOverrides)). " {$plural} required both in require and require-dev, this can lead to unexpected behavior";
42956 }
42957 }
42958
42959
42960
42961 foreach (array('provide', 'replace') as $linkType) {
42962 if (isset($manifest[$linkType])) {
42963 foreach (array('require', 'require-dev') as $requireType) {
42964 if (isset($manifest[$requireType])) {
42965 foreach ($manifest[$linkType] as $provide => $constraint) {
42966 if (isset($manifest[$requireType][$provide])) {
42967 $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.';
42968 }
42969 }
42970 }
42971 }
42972 }
42973 }
42974
42975
42976 $require = isset($manifest['require']) ? $manifest['require'] : array();
42977 $requireDev = isset($manifest['require-dev']) ? $manifest['require-dev'] : array();
42978 $packages = array_merge($require, $requireDev);
42979 foreach ($packages as $package => $version) {
42980 if (preg_match('/#/', $version) === 1) {
42981 $warnings[] = sprintf(
42982 'The package "%s" is pointing to a commit-ref, this is bad practice and can cause unforeseen issues.',
42983 $package
42984 );
42985 }
42986 }
42987
42988
42989 $scriptsDescriptions = isset($manifest['scripts-descriptions']) ? $manifest['scripts-descriptions'] : array();
42990 $scripts = isset($manifest['scripts']) ? $manifest['scripts'] : array();
42991 foreach ($scriptsDescriptions as $scriptName => $scriptDescription) {
42992 if (!array_key_exists($scriptName, $scripts)) {
42993 $warnings[] = sprintf(
42994 'Description for non-existent script "%s" found in "scripts-descriptions"',
42995 $scriptName
42996 );
42997 }
42998 }
42999
43000
43001 if (isset($manifest['autoload']['psr-0'][''])) {
43002 $warnings[] = "Defining autoload.psr-0 with an empty namespace prefix is a bad idea for performance";
43003 }
43004 if (isset($manifest['autoload']['psr-4'][''])) {
43005 $warnings[] = "Defining autoload.psr-4 with an empty namespace prefix is a bad idea for performance";
43006 }
43007
43008 try {
43009 $loader = new ValidatingArrayLoader(new ArrayLoader(), true, null, $arrayLoaderValidationFlags);
43010 if (!isset($manifest['version'])) {
43011 $manifest['version'] = '1.0.0';
43012 }
43013 if (!isset($manifest['name'])) {
43014 $manifest['name'] = 'dummy/dummy';
43015 }
43016 $loader->load($manifest);
43017 } catch (InvalidPackageException $e) {
43018 $errors = array_merge($errors, $e->getErrors());
43019 }
43020
43021 $warnings = array_merge($warnings, $loader->getWarnings());
43022
43023 return array($errors, $publishErrors, $warnings);
43024 }
43025 }
43026 <?php
43027
43028
43029
43030
43031
43032
43033
43034
43035
43036
43037
43038 namespace Composer\Util;
43039
43040 use Composer\IO\IOInterface;
43041
43042
43043
43044
43045
43046
43047 class ErrorHandler
43048 {
43049 private static $io;
43050
43051
43052
43053
43054
43055
43056
43057
43058
43059
43060
43061
43062
43063 public static function handle($level, $message, $file, $line)
43064 {
43065
43066 if (!(error_reporting() & $level)) {
43067 return;
43068 }
43069
43070 if (filter_var(ini_get('xdebug.scream'), FILTER_VALIDATE_BOOLEAN)) {
43071 $message .= "\n\nWarning: You have xdebug.scream enabled, the warning above may be".
43072 "\na legitimately suppressed error that you were not supposed to see.";
43073 }
43074
43075 if ($level !== E_DEPRECATED && $level !== E_USER_DEPRECATED) {
43076 throw new \ErrorException($message, 0, $level, $file, $line);
43077 }
43078
43079 if (self::$io) {
43080 self::$io->writeError('<warning>Deprecation Notice: '.$message.' in '.$file.':'.$line.'</warning>');
43081 if (self::$io->isVerbose()) {
43082 self::$io->writeError('<warning>Stack trace:</warning>');
43083 self::$io->writeError(array_filter(array_map(function ($a) {
43084 if (isset($a['line'], $a['file'])) {
43085 return '<warning> '.$a['file'].':'.$a['line'].'</warning>';
43086 }
43087
43088 return null;
43089 }, array_slice(debug_backtrace(), 2))));
43090 }
43091 }
43092
43093 return true;
43094 }
43095
43096
43097
43098
43099
43100
43101 public static function register(IOInterface $io = null)
43102 {
43103 set_error_handler(array(__CLASS__, 'handle'));
43104 error_reporting(E_ALL | E_STRICT);
43105 self::$io = $io;
43106 }
43107 }
43108 <?php
43109
43110
43111
43112
43113
43114
43115
43116
43117
43118
43119
43120 namespace Composer\Util;
43121
43122 use RecursiveDirectoryIterator;
43123 use RecursiveIteratorIterator;
43124 use Symfony\Component\Filesystem\Exception\IOException;
43125 use Symfony\Component\Finder\Finder;
43126
43127
43128
43129
43130
43131 class Filesystem
43132 {
43133 private $processExecutor;
43134
43135 public function __construct(ProcessExecutor $executor = null)
43136 {
43137 $this->processExecutor = $executor ?: new ProcessExecutor();
43138 }
43139
43140 public function remove($file)
43141 {
43142 if (is_dir($file)) {
43143 return $this->removeDirectory($file);
43144 }
43145
43146 if (file_exists($file)) {
43147 return $this->unlink($file);
43148 }
43149
43150 return false;
43151 }
43152
43153
43154
43155
43156
43157
43158
43159 public function isDirEmpty($dir)
43160 {
43161 $finder = Finder::create()
43162 ->ignoreVCS(false)
43163 ->ignoreDotFiles(false)
43164 ->depth(0)
43165 ->in($dir);
43166
43167 return count($finder) === 0;
43168 }
43169
43170 public function emptyDirectory($dir, $ensureDirectoryExists = true)
43171 {
43172 if (file_exists($dir) && is_link($dir)) {
43173 $this->unlink($dir);
43174 }
43175
43176 if ($ensureDirectoryExists) {
43177 $this->ensureDirectoryExists($dir);
43178 }
43179
43180 if (is_dir($dir)) {
43181 $finder = Finder::create()
43182 ->ignoreVCS(false)
43183 ->ignoreDotFiles(false)
43184 ->depth(0)
43185 ->in($dir);
43186
43187 foreach ($finder as $path) {
43188 $this->remove((string) $path);
43189 }
43190 }
43191 }
43192
43193
43194
43195
43196
43197
43198
43199
43200
43201
43202
43203 public function removeDirectory($directory)
43204 {
43205 if ($this->isSymlinkedDirectory($directory)) {
43206 return $this->unlinkSymlinkedDirectory($directory);
43207 }
43208
43209 if ($this->isJunction($directory)) {
43210 return $this->removeJunction($directory);
43211 }
43212
43213 if (is_link($directory)) {
43214 return unlink($directory);
43215 }
43216
43217 if (!file_exists($directory) || !is_dir($directory)) {
43218 return true;
43219 }
43220
43221 if (preg_match('{^(?:[a-z]:)?[/\\\\]+$}i', $directory)) {
43222 throw new \RuntimeException('Aborting an attempted deletion of '.$directory.', this was probably not intended, if it is a real use case please report it.');
43223 }
43224
43225 if (!function_exists('proc_open')) {
43226 return $this->removeDirectoryPhp($directory);
43227 }
43228
43229 if (Platform::isWindows()) {
43230 $cmd = sprintf('rmdir /S /Q %s', ProcessExecutor::escape(realpath($directory)));
43231 } else {
43232 $cmd = sprintf('rm -rf %s', ProcessExecutor::escape($directory));
43233 }
43234
43235 $result = $this->getProcess()->execute($cmd, $output) === 0;
43236
43237
43238 clearstatcache();
43239
43240 if ($result && !file_exists($directory)) {
43241 return true;
43242 }
43243
43244 return $this->removeDirectoryPhp($directory);
43245 }
43246
43247
43248
43249
43250
43251
43252
43253
43254
43255
43256
43257 public function removeDirectoryPhp($directory)
43258 {
43259 try {
43260 $it = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS);
43261 } catch (\UnexpectedValueException $e) {
43262
43263
43264 clearstatcache();
43265 usleep(100000);
43266 if (!is_dir($directory)) {
43267 return true;
43268 }
43269 $it = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS);
43270 }
43271 $ri = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
43272
43273 foreach ($ri as $file) {
43274 if ($file->isDir()) {
43275 $this->rmdir($file->getPathname());
43276 } else {
43277 $this->unlink($file->getPathname());
43278 }
43279 }
43280
43281 return $this->rmdir($directory);
43282 }
43283
43284 public function ensureDirectoryExists($directory)
43285 {
43286 if (!is_dir($directory)) {
43287 if (file_exists($directory)) {
43288 throw new \RuntimeException(
43289 $directory.' exists and is not a directory.'
43290 );
43291 }
43292 if (!@mkdir($directory, 0777, true)) {
43293 throw new \RuntimeException(
43294 $directory.' does not exist and could not be created.'
43295 );
43296 }
43297 }
43298 }
43299
43300
43301
43302
43303
43304
43305
43306
43307 public function unlink($path)
43308 {
43309 $unlinked = @$this->unlinkImplementation($path);
43310 if (!$unlinked) {
43311
43312 if (Platform::isWindows()) {
43313 usleep(350000);
43314 $unlinked = @$this->unlinkImplementation($path);
43315 }
43316
43317 if (!$unlinked) {
43318 $error = error_get_last();
43319 $message = 'Could not delete '.$path.': ' . @$error['message'];
43320 if (Platform::isWindows()) {
43321 $message .= "\nThis can be due to an antivirus or the Windows Search Indexer locking the file while they are analyzed";
43322 }
43323
43324 throw new \RuntimeException($message);
43325 }
43326 }
43327
43328 return true;
43329 }
43330
43331
43332
43333
43334
43335
43336
43337
43338 public function rmdir($path)
43339 {
43340 $deleted = @rmdir($path);
43341 if (!$deleted) {
43342
43343 if (Platform::isWindows()) {
43344 usleep(350000);
43345 $deleted = @rmdir($path);
43346 }
43347
43348 if (!$deleted) {
43349 $error = error_get_last();
43350 $message = 'Could not delete '.$path.': ' . @$error['message'];
43351 if (Platform::isWindows()) {
43352 $message .= "\nThis can be due to an antivirus or the Windows Search Indexer locking the file while they are analyzed";
43353 }
43354
43355 throw new \RuntimeException($message);
43356 }
43357 }
43358
43359 return true;
43360 }
43361
43362
43363
43364
43365
43366
43367
43368
43369
43370
43371 public function copyThenRemove($source, $target)
43372 {
43373 $this->copy($source, $target);
43374 if (!is_dir($source)) {
43375 $this->unlink($source);
43376
43377 return;
43378 }
43379
43380 $this->removeDirectoryPhp($source);
43381 }
43382
43383
43384
43385
43386
43387
43388
43389
43390 public function copy($source, $target)
43391 {
43392 if (!is_dir($source)) {
43393 return copy($source, $target);
43394 }
43395
43396 $it = new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS);
43397 $ri = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::SELF_FIRST);
43398 $this->ensureDirectoryExists($target);
43399
43400 $result = true;
43401 foreach ($ri as $file) {
43402 $targetPath = $target . DIRECTORY_SEPARATOR . $ri->getSubPathName();
43403 if ($file->isDir()) {
43404 $this->ensureDirectoryExists($targetPath);
43405 } else {
43406 $result = $result && copy($file->getPathname(), $targetPath);
43407 }
43408 }
43409
43410 return $result;
43411 }
43412
43413 public function rename($source, $target)
43414 {
43415 if (true === @rename($source, $target)) {
43416 return;
43417 }
43418
43419 if (!function_exists('proc_open')) {
43420 $this->copyThenRemove($source, $target);
43421
43422 return;
43423 }
43424
43425 if (Platform::isWindows()) {
43426
43427 $command = sprintf('xcopy %s %s /E /I /Q /Y', ProcessExecutor::escape($source), ProcessExecutor::escape($target));
43428 $result = $this->processExecutor->execute($command, $output);
43429
43430
43431 clearstatcache();
43432
43433 if (0 === $result) {
43434 $this->remove($source);
43435
43436 return;
43437 }
43438 } else {
43439
43440
43441 $command = sprintf('mv %s %s', ProcessExecutor::escape($source), ProcessExecutor::escape($target));
43442 $result = $this->processExecutor->execute($command, $output);
43443
43444
43445 clearstatcache();
43446
43447 if (0 === $result) {
43448 return;
43449 }
43450 }
43451
43452 $this->copyThenRemove($source, $target);
43453 }
43454
43455
43456
43457
43458
43459
43460
43461
43462
43463
43464 public function findShortestPath($from, $to, $directories = false)
43465 {
43466 if (!$this->isAbsolutePath($from) || !$this->isAbsolutePath($to)) {
43467 throw new \InvalidArgumentException(sprintf('$from (%s) and $to (%s) must be absolute paths.', $from, $to));
43468 }
43469
43470 $from = lcfirst($this->normalizePath($from));
43471 $to = lcfirst($this->normalizePath($to));
43472
43473 if ($directories) {
43474 $from = rtrim($from, '/') . '/dummy_file';
43475 }
43476
43477 if (dirname($from) === dirname($to)) {
43478 return './'.basename($to);
43479 }
43480
43481 $commonPath = $to;
43482 while (strpos($from.'/', $commonPath.'/') !== 0 && '/' !== $commonPath && !preg_match('{^[a-z]:/?$}i', $commonPath)) {
43483 $commonPath = strtr(dirname($commonPath), '\\', '/');
43484 }
43485
43486 if (0 !== strpos($from, $commonPath) || '/' === $commonPath) {
43487 return $to;
43488 }
43489
43490 $commonPath = rtrim($commonPath, '/') . '/';
43491 $sourcePathDepth = substr_count(substr($from, strlen($commonPath)), '/');
43492 $commonPathCode = str_repeat('../', $sourcePathDepth);
43493
43494 return ($commonPathCode . substr($to, strlen($commonPath))) ?: './';
43495 }
43496
43497
43498
43499
43500
43501
43502
43503
43504
43505
43506
43507 public function findShortestPathCode($from, $to, $directories = false, $staticCode = false)
43508 {
43509 if (!$this->isAbsolutePath($from) || !$this->isAbsolutePath($to)) {
43510 throw new \InvalidArgumentException(sprintf('$from (%s) and $to (%s) must be absolute paths.', $from, $to));
43511 }
43512
43513 $from = lcfirst($this->normalizePath($from));
43514 $to = lcfirst($this->normalizePath($to));
43515
43516 if ($from === $to) {
43517 return $directories ? '__DIR__' : '__FILE__';
43518 }
43519
43520 $commonPath = $to;
43521 while (strpos($from.'/', $commonPath.'/') !== 0 && '/' !== $commonPath && !preg_match('{^[a-z]:/?$}i', $commonPath) && '.' !== $commonPath) {
43522 $commonPath = strtr(dirname($commonPath), '\\', '/');
43523 }
43524
43525 if (0 !== strpos($from, $commonPath) || '/' === $commonPath || '.' === $commonPath) {
43526 return var_export($to, true);
43527 }
43528
43529 $commonPath = rtrim($commonPath, '/') . '/';
43530 if (strpos($to, $from.'/') === 0) {
43531 return '__DIR__ . '.var_export(substr($to, strlen($from)), true);
43532 }
43533 $sourcePathDepth = substr_count(substr($from, strlen($commonPath)), '/') + $directories;
43534 if ($staticCode) {
43535 $commonPathCode = "__DIR__ . '".str_repeat('/..', $sourcePathDepth)."'";
43536 } else {
43537 $commonPathCode = str_repeat('dirname(', $sourcePathDepth).'__DIR__'.str_repeat(')', $sourcePathDepth);
43538 }
43539 $relTarget = substr($to, strlen($commonPath));
43540
43541 return $commonPathCode . (strlen($relTarget) ? '.' . var_export('/' . $relTarget, true) : '');
43542 }
43543
43544
43545
43546
43547
43548
43549
43550 public function isAbsolutePath($path)
43551 {
43552 return substr($path, 0, 1) === '/' || substr($path, 1, 1) === ':' || substr($path, 0, 2) === '\\\\';
43553 }
43554
43555
43556
43557
43558
43559
43560
43561
43562
43563 public function size($path)
43564 {
43565 if (!file_exists($path)) {
43566 throw new \RuntimeException("$path does not exist.");
43567 }
43568 if (is_dir($path)) {
43569 return $this->directorySize($path);
43570 }
43571
43572 return filesize($path);
43573 }
43574
43575
43576
43577
43578
43579
43580
43581
43582 public function normalizePath($path)
43583 {
43584 $parts = array();
43585 $path = strtr($path, '\\', '/');
43586 $prefix = '';
43587 $absolute = false;
43588
43589
43590 if (preg_match('{^( [0-9a-z]{2,}+: (?: // (?: [a-z]: )? )? | [a-z]: )}ix', $path, $match)) {
43591 $prefix = $match[1];
43592 $path = substr($path, strlen($prefix));
43593 }
43594
43595 if (substr($path, 0, 1) === '/') {
43596 $absolute = true;
43597 $path = substr($path, 1);
43598 }
43599
43600 $up = false;
43601 foreach (explode('/', $path) as $chunk) {
43602 if ('..' === $chunk && ($absolute || $up)) {
43603 array_pop($parts);
43604 $up = !(empty($parts) || '..' === end($parts));
43605 } elseif ('.' !== $chunk && '' !== $chunk) {
43606 $parts[] = $chunk;
43607 $up = '..' !== $chunk;
43608 }
43609 }
43610
43611 return $prefix.($absolute ? '/' : '').implode('/', $parts);
43612 }
43613
43614
43615
43616
43617
43618
43619
43620 public static function isLocalPath($path)
43621 {
43622 return (bool) preg_match('{^(file://(?!//)|/(?!/)|/?[a-z]:[\\\\/]|\.\.[\\\\/]|[a-z0-9_.-]+[\\\\/])}i', $path);
43623 }
43624
43625 public static function getPlatformPath($path)
43626 {
43627 if (Platform::isWindows()) {
43628 $path = preg_replace('{^(?:file:///([a-z]):?/)}i', 'file://$1:/', $path);
43629 }
43630
43631 return preg_replace('{^file://}i', '', $path);
43632 }
43633
43634 protected function directorySize($directory)
43635 {
43636 $it = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS);
43637 $ri = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
43638
43639 $size = 0;
43640 foreach ($ri as $file) {
43641 if ($file->isFile()) {
43642 $size += $file->getSize();
43643 }
43644 }
43645
43646 return $size;
43647 }
43648
43649 protected function getProcess()
43650 {
43651 return $this->processExecutor;
43652 }
43653
43654
43655
43656
43657
43658
43659
43660
43661
43662
43663 private function unlinkImplementation($path)
43664 {
43665 if (Platform::isWindows() && is_dir($path) && is_link($path)) {
43666 return rmdir($path);
43667 }
43668
43669 return unlink($path);
43670 }
43671
43672
43673
43674
43675
43676
43677
43678
43679 public function relativeSymlink($target, $link)
43680 {
43681 $cwd = getcwd();
43682
43683 $relativePath = $this->findShortestPath($link, $target);
43684 chdir(dirname($link));
43685 $result = @symlink($relativePath, $link);
43686
43687 chdir($cwd);
43688
43689 return $result;
43690 }
43691
43692
43693
43694
43695
43696
43697
43698
43699 public function isSymlinkedDirectory($directory)
43700 {
43701 if (!is_dir($directory)) {
43702 return false;
43703 }
43704
43705 $resolved = $this->resolveSymlinkedDirectorySymlink($directory);
43706
43707 return is_link($resolved);
43708 }
43709
43710
43711
43712
43713
43714
43715 private function unlinkSymlinkedDirectory($directory)
43716 {
43717 $resolved = $this->resolveSymlinkedDirectorySymlink($directory);
43718
43719 return $this->unlink($resolved);
43720 }
43721
43722
43723
43724
43725
43726
43727
43728
43729 private function resolveSymlinkedDirectorySymlink($pathname)
43730 {
43731 if (!is_dir($pathname)) {
43732 return $pathname;
43733 }
43734
43735 $resolved = rtrim($pathname, '/');
43736
43737 if (!strlen($resolved)) {
43738 return $pathname;
43739 }
43740
43741 return $resolved;
43742 }
43743
43744
43745
43746
43747
43748
43749
43750 public function junction($target, $junction)
43751 {
43752 if (!Platform::isWindows()) {
43753 throw new \LogicException(sprintf('Function %s is not available on non-Windows platform', __CLASS__));
43754 }
43755 if (!is_dir($target)) {
43756 throw new IOException(sprintf('Cannot junction to "%s" as it is not a directory.', $target), 0, null, $target);
43757 }
43758 $cmd = sprintf(
43759 'mklink /J %s %s',
43760 ProcessExecutor::escape(str_replace('/', DIRECTORY_SEPARATOR, $junction)),
43761 ProcessExecutor::escape(realpath($target))
43762 );
43763 if ($this->getProcess()->execute($cmd, $output) !== 0) {
43764 throw new IOException(sprintf('Failed to create junction to "%s" at "%s".', $target, $junction), 0, null, $target);
43765 }
43766 clearstatcache(true, $junction);
43767 }
43768
43769
43770
43771
43772
43773
43774
43775
43776
43777
43778
43779
43780
43781
43782
43783
43784
43785
43786
43787
43788
43789 public function isJunction($junction)
43790 {
43791 if (!Platform::isWindows()) {
43792 return false;
43793 }
43794
43795
43796 clearstatcache(true, $junction);
43797
43798 if (!is_dir($junction) || is_link($junction)) {
43799 return false;
43800 }
43801
43802 $stat = lstat($junction);
43803
43804
43805 return $stat ? 0x4000 !== ($stat['mode'] & 0xF000) : false;
43806 }
43807
43808
43809
43810
43811
43812
43813
43814 public function removeJunction($junction)
43815 {
43816 if (!Platform::isWindows()) {
43817 return false;
43818 }
43819 $junction = rtrim(str_replace('/', DIRECTORY_SEPARATOR, $junction), DIRECTORY_SEPARATOR);
43820 if (!$this->isJunction($junction)) {
43821 throw new IOException(sprintf('%s is not a junction and thus cannot be removed as one', $junction));
43822 }
43823
43824 return $this->rmdir($junction);
43825 }
43826 }
43827 <?php
43828
43829
43830
43831
43832
43833
43834
43835
43836
43837
43838
43839 namespace Composer\Util;
43840
43841 use Composer\Config;
43842 use Composer\IO\IOInterface;
43843
43844
43845
43846
43847 class Git
43848 {
43849 private static $version = false;
43850
43851
43852 protected $io;
43853
43854 protected $config;
43855
43856 protected $process;
43857
43858 protected $filesystem;
43859
43860 public function __construct(IOInterface $io, Config $config, ProcessExecutor $process, Filesystem $fs)
43861 {
43862 $this->io = $io;
43863 $this->config = $config;
43864 $this->process = $process;
43865 $this->filesystem = $fs;
43866 }
43867
43868 public function runCommand($commandCallable, $url, $cwd, $initialClone = false)
43869 {
43870
43871 $this->config->prohibitUrlByConfig($url, $this->io);
43872
43873 if ($initialClone) {
43874 $origCwd = $cwd;
43875 $cwd = null;
43876 }
43877
43878 if (preg_match('{^ssh://[^@]+@[^:]+:[^0-9]+}', $url)) {
43879 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.');
43880 }
43881
43882 if (!$initialClone) {
43883
43884 $this->process->execute('git remote -v', $output, $cwd);
43885 if (preg_match('{^(?:composer|origin)\s+https?://(.+):(.+)@([^/]+)}im', $output, $match) && !$this->io->hasAuthentication($match[3])) {
43886 $this->io->setAuthentication($match[3], rawurldecode($match[1]), rawurldecode($match[2]));
43887 }
43888 }
43889
43890 $protocols = $this->config->get('github-protocols');
43891 if (!is_array($protocols)) {
43892 throw new \RuntimeException('Config value "github-protocols" must be an array, got ' . gettype($protocols));
43893 }
43894
43895 if (preg_match('{^(?:https?|git)://' . self::getGitHubDomainsRegex($this->config) . '/(.*)}', $url, $match)) {
43896 $messages = array();
43897 foreach ($protocols as $protocol) {
43898 if ('ssh' === $protocol) {
43899 $protoUrl = "git@" . $match[1] . ":" . $match[2];
43900 } else {
43901 $protoUrl = $protocol . "://" . $match[1] . "/" . $match[2];
43902 }
43903
43904 if (0 === $this->process->execute(call_user_func($commandCallable, $protoUrl), $ignoredOutput, $cwd)) {
43905 return;
43906 }
43907 $messages[] = '- ' . $protoUrl . "\n" . preg_replace('#^#m', '  ', $this->process->getErrorOutput());
43908 if ($initialClone) {
43909 $this->filesystem->removeDirectory($origCwd);
43910 }
43911 }
43912
43913
43914 if (!$this->io->hasAuthentication($match[1]) && !$this->io->isInteractive()) {
43915 $this->throwException('Failed to clone ' . $url . ' via ' . implode(', ', $protocols) . ' protocols, aborting.' . "\n\n" . implode("\n", $messages), $url);
43916 }
43917 }
43918
43919
43920 $bypassSshForGitHub = preg_match('{^git@' . self::getGitHubDomainsRegex($this->config) . ':(.+?)\.git$}i', $url) && !in_array('ssh', $protocols, true);
43921
43922 $command = call_user_func($commandCallable, $url);
43923
43924 $auth = null;
43925 if ($bypassSshForGitHub || 0 !== $this->process->execute($command, $ignoredOutput, $cwd)) {
43926 $errorMsg = $this->process->getErrorOutput();
43927
43928 if (preg_match('{^git@' . self::getGitHubDomainsRegex($this->config) . ':(.+?)\.git$}i', $url, $match)
43929 || preg_match('{^https?://' . self::getGitHubDomainsRegex($this->config) . '/(.*)}', $url, $match)
43930 ) {
43931 if (!$this->io->hasAuthentication($match[1])) {
43932 $gitHubUtil = new GitHub($this->io, $this->config, $this->process);
43933 $message = 'Cloning failed using an ssh key for authentication, enter your GitHub credentials to access private repos';
43934
43935 if (!$gitHubUtil->authorizeOAuth($match[1]) && $this->io->isInteractive()) {
43936 $gitHubUtil->authorizeOAuthInteractively($match[1], $message);
43937 }
43938 }
43939
43940 if ($this->io->hasAuthentication($match[1])) {
43941 $auth = $this->io->getAuthentication($match[1]);
43942 $authUrl = 'https://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[1] . '/' . $match[2] . '.git';
43943 $command = call_user_func($commandCallable, $authUrl);
43944 if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
43945 return;
43946 }
43947
43948 $errorMsg = $this->process->getErrorOutput();
43949 }
43950 } elseif (preg_match('{^https://(bitbucket\.org)/(.*)(\.git)?$}U', $url, $match)) { 
43951 $bitbucketUtil = new Bitbucket($this->io, $this->config, $this->process);
43952
43953 if (!$this->io->hasAuthentication($match[1])) {
43954 $message = 'Enter your Bitbucket credentials to access private repos';
43955
43956 if (!$bitbucketUtil->authorizeOAuth($match[1]) && $this->io->isInteractive()) {
43957 $bitbucketUtil->authorizeOAuthInteractively($match[1], $message);
43958 $accessToken = $bitbucketUtil->getToken();
43959 $this->io->setAuthentication($match[1], 'x-token-auth', $accessToken);
43960 }
43961 } else { 
43962 $auth = $this->io->getAuthentication($match[1]);
43963
43964
43965 if ($auth['username'] !== 'x-token-auth') {
43966 $accessToken = $bitbucketUtil->requestToken($match[1], $auth['username'], $auth['password']);
43967 if (! empty($accessToken)) {
43968 $this->io->setAuthentication($match[1], 'x-token-auth', $accessToken);
43969 }
43970 }
43971 }
43972
43973 if ($this->io->hasAuthentication($match[1])) {
43974 $auth = $this->io->getAuthentication($match[1]);
43975 $authUrl = 'https://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[1] . '/' . $match[2] . '.git';
43976
43977 $command = call_user_func($commandCallable, $authUrl);
43978 if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
43979 return;
43980 }
43981
43982 $errorMsg = $this->process->getErrorOutput();
43983 } else { 
43984 $sshUrl = 'git@bitbucket.org:' . $match[2] . '.git';
43985 $this->io->writeError('    No bitbucket authentication configured. Falling back to ssh.');
43986 $command = call_user_func($commandCallable, $sshUrl);
43987 if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
43988 return;
43989 }
43990
43991 $errorMsg = $this->process->getErrorOutput();
43992 }
43993 } elseif (
43994 preg_match('{^(git)@' . self::getGitLabDomainsRegex($this->config) . ':(.+?\.git)$}i', $url, $match)
43995 || preg_match('{^(https?)://' . self::getGitLabDomainsRegex($this->config) . '/(.*)}', $url, $match)
43996 ) {
43997 if ($match[1] === 'git') {
43998 $match[1] = 'https';
43999 }
44000
44001 if (!$this->io->hasAuthentication($match[2])) {
44002 $gitLabUtil = new GitLab($this->io, $this->config, $this->process);
44003 $message = 'Cloning failed, enter your GitLab credentials to access private repos';
44004
44005 if (!$gitLabUtil->authorizeOAuth($match[2]) && $this->io->isInteractive()) {
44006 $gitLabUtil->authorizeOAuthInteractively($match[1], $match[2], $message);
44007 }
44008 }
44009
44010 if ($this->io->hasAuthentication($match[2])) {
44011 $auth = $this->io->getAuthentication($match[2]);
44012 if ($auth['password'] === 'private-token' || $auth['password'] === 'oauth2' || $auth['password'] === 'gitlab-ci-token') {
44013 $authUrl = $match[1] . '://' . rawurlencode($auth['password']) . ':' . rawurlencode($auth['username']) . '@' . $match[2] . '/' . $match[3]; 
44014 } else {
44015 $authUrl = $match[1] . '://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[2] . '/' . $match[3];
44016 }
44017
44018 $command = call_user_func($commandCallable, $authUrl);
44019 if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
44020 return;
44021 }
44022
44023 $errorMsg = $this->process->getErrorOutput();
44024 }
44025 } elseif ($this->isAuthenticationFailure($url, $match)) { 
44026 if (strpos($match[2], '@')) {
44027 list($authParts, $match[2]) = explode('@', $match[2], 2);
44028 }
44029
44030 $storeAuth = false;
44031 if ($this->io->hasAuthentication($match[2])) {
44032 $auth = $this->io->getAuthentication($match[2]);
44033 } elseif ($this->io->isInteractive()) {
44034 $defaultUsername = null;
44035 if (isset($authParts) && $authParts) {
44036 if (false !== strpos($authParts, ':')) {
44037 list($defaultUsername, ) = explode(':', $authParts, 2);
44038 } else {
44039 $defaultUsername = $authParts;
44040 }
44041 }
44042
44043 $this->io->writeError('    Authentication required (<info>' . $match[2] . '</info>):');
44044 $auth = array(
44045 'username' => $this->io->ask('      Username: ', $defaultUsername),
44046 'password' => $this->io->askAndHideAnswer('      Password: '),
44047 );
44048 $storeAuth = $this->config->get('store-auths');
44049 }
44050
44051 if ($auth) {
44052 $authUrl = $match[1] . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[2] . $match[3];
44053
44054 $command = call_user_func($commandCallable, $authUrl);
44055 if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
44056 $this->io->setAuthentication($match[2], $auth['username'], $auth['password']);
44057 $authHelper = new AuthHelper($this->io, $this->config);
44058 $authHelper->storeAuth($match[2], $storeAuth);
44059
44060 return;
44061 }
44062
44063 $errorMsg = $this->process->getErrorOutput();
44064 }
44065 }
44066
44067 if ($initialClone) {
44068 $this->filesystem->removeDirectory($origCwd);
44069 }
44070
44071 $this->throwException('Failed to execute ' . $command . "\n\n" . $errorMsg, $url);
44072 }
44073 }
44074
44075 public function syncMirror($url, $dir)
44076 {
44077
44078 if (is_dir($dir) && 0 === $this->process->execute('git rev-parse --git-dir', $output, $dir) && trim($output) === '.') {
44079 try {
44080 $commandCallable = function ($url) {
44081 $sanitizedUrl = preg_replace('{://([^@]+?):(.+?)@}', '://', $url);
44082
44083 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));
44084 };
44085 $this->runCommand($commandCallable, $url, $dir);
44086 } catch (\Exception $e) {
44087 $this->io->writeError('<error>Sync mirror failed: ' . $e->getMessage() . '</error>', true, IOInterface::DEBUG);
44088
44089 return false;
44090 }
44091
44092 return true;
44093 }
44094
44095
44096 $this->filesystem->removeDirectory($dir);
44097
44098 $commandCallable = function ($url) use ($dir) {
44099 return sprintf('git clone --mirror -- %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($dir));
44100 };
44101
44102 $this->runCommand($commandCallable, $url, $dir, true);
44103
44104 return true;
44105 }
44106
44107 public function fetchRefOrSyncMirror($url, $dir, $ref)
44108 {
44109 if ($this->checkRefIsInMirror($url, $dir, $ref)) {
44110 return true;
44111 }
44112
44113 if ($this->syncMirror($url, $dir)) {
44114 return $this->checkRefIsInMirror($url, $dir, $ref);
44115 }
44116
44117 return false;
44118 }
44119
44120 public static function getNoShowSignatureFlag(ProcessExecutor $process)
44121 {
44122 $gitVersion = self::getVersion($process);
44123 if ($gitVersion && version_compare($gitVersion, '2.10.0-rc0', '>=')) {
44124 return ' --no-show-signature';
44125 }
44126
44127 return '';
44128 }
44129
44130 private function checkRefIsInMirror($url, $dir, $ref)
44131 {
44132 if (is_dir($dir) && 0 === $this->process->execute('git rev-parse --git-dir', $output, $dir) && trim($output) === '.') {
44133 $escapedRef = ProcessExecutor::escape($ref.'^{commit}');
44134 $exitCode = $this->process->execute(sprintf('git rev-parse --quiet --verify %s', $escapedRef), $ignoredOutput, $dir);
44135 if ($exitCode === 0) {
44136 return true;
44137 }
44138 }
44139
44140 return false;
44141 }
44142
44143 private function isAuthenticationFailure($url, &$match)
44144 {
44145 if (!preg_match('{^(https?://)([^/]+)(.*)$}i', $url, $match)) {
44146 return false;
44147 }
44148
44149 $authFailures = array(
44150 'fatal: Authentication failed',
44151 'remote error: Invalid username or password.',
44152 'error: 401 Unauthorized',
44153 'fatal: unable to access',
44154 'fatal: could not read Username',
44155 );
44156
44157 $errorOutput = $this->process->getErrorOutput();
44158 foreach ($authFailures as $authFailure) {
44159 if (strpos($errorOutput, $authFailure) !== false) {
44160 return true;
44161 }
44162 }
44163
44164 return false;
44165 }
44166
44167 public static function cleanEnv()
44168 {
44169 if (PHP_VERSION_ID < 50400 && ini_get('safe_mode') && false === strpos(ini_get('safe_mode_allowed_env_vars'), 'GIT_ASKPASS')) {
44170 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');
44171 }
44172
44173
44174 if (getenv('GIT_ASKPASS') !== 'echo') {
44175 putenv('GIT_ASKPASS=echo');
44176 $_SERVER['GIT_ASKPASS'] = 'echo';
44177 }
44178
44179
44180 if (getenv('GIT_DIR')) {
44181 putenv('GIT_DIR');
44182 unset($_SERVER['GIT_DIR']);
44183 }
44184 if (getenv('GIT_WORK_TREE')) {
44185 putenv('GIT_WORK_TREE');
44186 unset($_SERVER['GIT_WORK_TREE']);
44187 }
44188
44189
44190 if (getenv('LANGUAGE') !== 'C') {
44191 putenv('LANGUAGE=C');
44192 $_SERVER['LANGUAGE'] = 'C';
44193 }
44194
44195
44196 putenv("DYLD_LIBRARY_PATH");
44197 unset($_SERVER['DYLD_LIBRARY_PATH']);
44198 }
44199
44200 public static function getGitHubDomainsRegex(Config $config)
44201 {
44202 return '(' . implode('|', array_map('preg_quote', $config->get('github-domains'))) . ')';
44203 }
44204
44205 public static function getGitLabDomainsRegex(Config $config)
44206 {
44207 return '(' . implode('|', array_map('preg_quote', $config->get('gitlab-domains'))) . ')';
44208 }
44209
44210 public static function sanitizeUrl($message)
44211 {
44212 return preg_replace_callback('{://(?P<user>[^@]+?):(?P<password>.+?)@}', function ($m) {
44213 if (preg_match('{^[a-f0-9]{12,}$}', $m[1])) {
44214 return '://***:***@';
44215 }
44216
44217 return '://' . $m[1] . ':***@';
44218 }, $message);
44219 }
44220
44221 private function throwException($message, $url)
44222 {
44223
44224 clearstatcache();
44225
44226 if (0 !== $this->process->execute('git --version', $ignoredOutput)) {
44227 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()));
44228 }
44229
44230 throw new \RuntimeException(self::sanitizeUrl($message));
44231 }
44232
44233
44234
44235
44236
44237
44238 public static function getVersion(ProcessExecutor $process = null)
44239 {
44240 if (false === self::$version) {
44241 self::$version = null;
44242 if (!$process) {
44243 $process = new ProcessExecutor;
44244 }
44245 if (0 === $process->execute('git --version', $output) && preg_match('/^git version (\d+(?:\.\d+)+)/m', $output, $matches)) {
44246 self::$version = $matches[1];
44247 }
44248 }
44249
44250 return self::$version;
44251 }
44252 }
44253 <?php
44254
44255
44256
44257
44258
44259
44260
44261
44262
44263
44264
44265 namespace Composer\Util;
44266
44267 use Composer\Factory;
44268 use Composer\IO\IOInterface;
44269 use Composer\Config;
44270 use Composer\Downloader\TransportException;
44271
44272
44273
44274
44275 class GitHub
44276 {
44277 protected $io;
44278 protected $config;
44279 protected $process;
44280 protected $remoteFilesystem;
44281
44282
44283
44284
44285
44286
44287
44288
44289
44290 public function __construct(IOInterface $io, Config $config, ProcessExecutor $process = null, RemoteFilesystem $remoteFilesystem = null)
44291 {
44292 $this->io = $io;
44293 $this->config = $config;
44294 $this->process = $process ?: new ProcessExecutor($io);
44295 $this->remoteFilesystem = $remoteFilesystem ?: Factory::createRemoteFilesystem($this->io, $config);
44296 }
44297
44298
44299
44300
44301
44302
44303
44304 public function authorizeOAuth($originUrl)
44305 {
44306 if (!in_array($originUrl, $this->config->get('github-domains'))) {
44307 return false;
44308 }
44309
44310
44311 if (0 === $this->process->execute('git config github.accesstoken', $output)) {
44312 $this->io->setAuthentication($originUrl, trim($output), 'x-oauth-basic');
44313
44314 return true;
44315 }
44316
44317 return false;
44318 }
44319
44320
44321
44322
44323
44324
44325
44326
44327
44328
44329 public function authorizeOAuthInteractively($originUrl, $message = null)
44330 {
44331 if ($message) {
44332 $this->io->writeError($message);
44333 }
44334
44335 $note = 'Composer';
44336 if ($this->config->get('github-expose-hostname') === true && 0 === $this->process->execute('hostname', $output)) {
44337 $note .= ' on ' . trim($output);
44338 }
44339 $note .= ' ' . date('Y-m-d Hi');
44340
44341 $url = 'https://'.$originUrl.'/settings/tokens/new?scopes=repo&description=' . str_replace('%20', '+', rawurlencode($note));
44342 $this->io->writeError(sprintf('Head to %s', $url));
44343 $this->io->writeError(sprintf('to retrieve a token. It will be stored in "%s" for future use by Composer.', $this->config->getAuthConfigSource()->getName()));
44344
44345 $token = trim($this->io->askAndHideAnswer('Token (hidden): '));
44346
44347 if (!$token) {
44348 $this->io->writeError('<warning>No token given, aborting.</warning>');
44349 $this->io->writeError('You can also add it manually later by using "composer config --global --auth github-oauth.github.com <token>"');
44350
44351 return false;
44352 }
44353
44354 $this->io->setAuthentication($originUrl, $token, 'x-oauth-basic');
44355
44356 try {
44357 $apiUrl = ('github.com' === $originUrl) ? 'api.github.com/' : $originUrl . '/api/v3/';
44358
44359 $this->remoteFilesystem->getContents($originUrl, 'https://'. $apiUrl, false, array(
44360 'retry-auth-failure' => false,
44361 ));
44362 } catch (TransportException $e) {
44363 if (in_array($e->getCode(), array(403, 401))) {
44364 $this->io->writeError('<error>Invalid token provided.</error>');
44365 $this->io->writeError('You can also add it manually later by using "composer config --global --auth github-oauth.github.com <token>"');
44366
44367 return false;
44368 }
44369
44370 throw $e;
44371 }
44372
44373
44374 $this->config->getConfigSource()->removeConfigSetting('github-oauth.'.$originUrl);
44375 $this->config->getAuthConfigSource()->addConfigSetting('github-oauth.'.$originUrl, $token);
44376
44377 $this->io->writeError('<info>Token stored successfully.</info>');
44378
44379 return true;
44380 }
44381
44382
44383
44384
44385
44386
44387
44388
44389 public function getRateLimit(array $headers)
44390 {
44391 $rateLimit = array(
44392 'limit' => '?',
44393 'reset' => '?',
44394 );
44395
44396 foreach ($headers as $header) {
44397 $header = trim($header);
44398 if (false === strpos($header, 'X-RateLimit-')) {
44399 continue;
44400 }
44401 list($type, $value) = explode(':', $header, 2);
44402 switch ($type) {
44403 case 'X-RateLimit-Limit':
44404 $rateLimit['limit'] = (int) trim($value);
44405 break;
44406 case 'X-RateLimit-Reset':
44407 $rateLimit['reset'] = date('Y-m-d H:i:s', (int) trim($value));
44408 break;
44409 }
44410 }
44411
44412 return $rateLimit;
44413 }
44414
44415
44416
44417
44418
44419
44420
44421
44422 public function isRateLimited(array $headers)
44423 {
44424 foreach ($headers as $header) {
44425 if (preg_match('{^X-RateLimit-Remaining: *0$}i', trim($header))) {
44426 return true;
44427 }
44428 }
44429
44430 return false;
44431 }
44432 }
44433 <?php
44434
44435
44436
44437
44438
44439
44440
44441
44442
44443
44444
44445 namespace Composer\Util;
44446
44447 use Composer\IO\IOInterface;
44448 use Composer\Config;
44449 use Composer\Factory;
44450 use Composer\Downloader\TransportException;
44451 use Composer\Json\JsonFile;
44452
44453
44454
44455
44456 class GitLab
44457 {
44458 protected $io;
44459 protected $config;
44460 protected $process;
44461 protected $remoteFilesystem;
44462
44463
44464
44465
44466
44467
44468
44469
44470
44471 public function __construct(IOInterface $io, Config $config, ProcessExecutor $process = null, RemoteFilesystem $remoteFilesystem = null)
44472 {
44473 $this->io = $io;
44474 $this->config = $config;
44475 $this->process = $process ?: new ProcessExecutor($io);
44476 $this->remoteFilesystem = $remoteFilesystem ?: Factory::createRemoteFilesystem($this->io, $config);
44477 }
44478
44479
44480
44481
44482
44483
44484
44485
44486 public function authorizeOAuth($originUrl)
44487 {
44488
44489 $bcOriginUrl = preg_replace('{:\d+}', '', $originUrl);
44490
44491 if (!in_array($originUrl, $this->config->get('gitlab-domains'), true) && !in_array($bcOriginUrl, $this->config->get('gitlab-domains'), true)) {
44492 return false;
44493 }
44494
44495
44496 if (0 === $this->process->execute('git config gitlab.accesstoken', $output)) {
44497 $this->io->setAuthentication($originUrl, trim($output), 'oauth2');
44498
44499 return true;
44500 }
44501
44502
44503 $authTokens = $this->config->get('gitlab-token');
44504
44505 if (isset($authTokens[$originUrl])) {
44506 $this->io->setAuthentication($originUrl, $authTokens[$originUrl], 'private-token');
44507
44508 return true;
44509 }
44510
44511 if (isset($authTokens[$bcOriginUrl])) {
44512 $this->io->setAuthentication($originUrl, $authTokens[$bcOriginUrl], 'private-token');
44513
44514 return true;
44515 }
44516
44517 return false;
44518 }
44519
44520
44521
44522
44523
44524
44525
44526
44527
44528
44529
44530
44531
44532 public function authorizeOAuthInteractively($scheme, $originUrl, $message = null)
44533 {
44534 if ($message) {
44535 $this->io->writeError($message);
44536 }
44537
44538 $this->io->writeError(sprintf('A token will be created and stored in "%s", your password will never be stored', $this->config->getAuthConfigSource()->getName()));
44539 $this->io->writeError('To revoke access to this token you can visit '.$scheme.'://'.$originUrl.'/profile/applications');
44540
44541 $attemptCounter = 0;
44542
44543 while ($attemptCounter++ < 5) {
44544 try {
44545 $response = $this->createToken($scheme, $originUrl);
44546 } catch (TransportException $e) {
44547
44548
44549 if (in_array($e->getCode(), array(403, 401))) {
44550 if (401 === $e->getCode()) {
44551 $response = json_decode($e->getResponse(), true);
44552 if (isset($response['error']) && $response['error'] === 'invalid_grant') {
44553 $this->io->writeError('Bad credentials. If you have two factor authentication enabled you will have to manually create a personal access token');
44554 } else {
44555 $this->io->writeError('Bad credentials.');
44556 }
44557 } else {
44558 $this->io->writeError('Maximum number of login attempts exceeded. Please try again later.');
44559 }
44560
44561 $this->io->writeError('You can also manually create a personal access token enabling the "read_api" scope at '.$scheme.'://'.$originUrl.'/profile/personal_access_tokens');
44562 $this->io->writeError('Add it using "composer config --global --auth gitlab-token.'.$originUrl.' <token>"');
44563
44564 continue;
44565 }
44566
44567 throw $e;
44568 }
44569
44570 $this->io->setAuthentication($originUrl, $response['access_token'], 'oauth2');
44571
44572
44573 $this->config->getAuthConfigSource()->addConfigSetting('gitlab-oauth.'.$originUrl, $response['access_token']);
44574
44575 return true;
44576 }
44577
44578 throw new \RuntimeException('Invalid GitLab credentials 5 times in a row, aborting.');
44579 }
44580
44581 private function createToken($scheme, $originUrl)
44582 {
44583 $username = $this->io->ask('Username: ');
44584 $password = $this->io->askAndHideAnswer('Password: ');
44585
44586 $headers = array('Content-Type: application/x-www-form-urlencoded');
44587
44588 $apiUrl = $originUrl;
44589 $data = http_build_query(array(
44590 'username' => $username,
44591 'password' => $password,
44592 'grant_type' => 'password',
44593 ), null, '&');
44594 $options = array(
44595 'retry-auth-failure' => false,
44596 'http' => array(
44597 'method' => 'POST',
44598 'header' => $headers,
44599 'content' => $data,
44600 ),
44601 );
44602
44603 $json = $this->remoteFilesystem->getContents($originUrl, $scheme.'://'.$apiUrl.'/oauth/token', false, $options);
44604
44605 $this->io->writeError('Token successfully created');
44606
44607 return JsonFile::parseJson($json);
44608 }
44609 }
44610 <?php
44611
44612
44613
44614
44615
44616
44617
44618
44619
44620
44621
44622 namespace Composer\Util;
44623
44624 use Composer\Config;
44625 use Composer\IO\IOInterface;
44626
44627
44628
44629
44630 class Hg
44631 {
44632
44633
44634
44635 private $io;
44636
44637
44638
44639
44640 private $config;
44641
44642
44643
44644
44645 private $process;
44646
44647 public function __construct(IOInterface $io, Config $config, ProcessExecutor $process)
44648 {
44649 $this->io = $io;
44650 $this->config = $config;
44651 $this->process = $process;
44652 }
44653
44654 public function runCommand($commandCallable, $url, $cwd)
44655 {
44656 $this->config->prohibitUrlByConfig($url, $this->io);
44657
44658
44659 $command = call_user_func($commandCallable, $url);
44660
44661 if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
44662 return;
44663 }
44664
44665
44666 if (preg_match('{^(https?)://((.+)(?:\:(.+))?@)?([^/]+)(/.*)?}mi', $url, $match) && $this->io->hasAuthentication($match[5])) {
44667 $auth = $this->io->getAuthentication($match[5]);
44668 $authenticatedUrl = $match[1] . '://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[5] . (!empty($match[6]) ? $match[6] : null);
44669
44670 $command = call_user_func($commandCallable, $authenticatedUrl);
44671
44672 if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
44673 return;
44674 }
44675
44676 $error = $this->process->getErrorOutput();
44677 } else {
44678 $error = 'The given URL (' . $url . ') does not match the required format (http(s)://(username:password@)example.com/path-to-repository)';
44679 }
44680
44681 $this->throwException('Failed to clone ' . $url . ', ' . "\n\n" . $error, $url);
44682 }
44683
44684 public static function sanitizeUrl($message)
44685 {
44686 return preg_replace_callback('{://(?P<user>[^@]+?):(?P<password>.+?)@}', function ($m) {
44687 if (preg_match('{^[a-f0-9]{12,}$}', $m[1])) {
44688 return '://***:***@';
44689 }
44690
44691 return '://' . $m[1] . ':***@';
44692 }, $message);
44693 }
44694
44695 private function throwException($message, $url)
44696 {
44697 if (0 !== $this->process->execute('hg --version', $ignoredOutput)) {
44698 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()));
44699 }
44700
44701 throw new \RuntimeException(self::sanitizeUrl($message));
44702 }
44703 }
44704 <?php
44705
44706
44707
44708
44709
44710
44711
44712
44713
44714
44715
44716 namespace Composer\Util;
44717
44718 use Composer\XdebugHandler\XdebugHandler;
44719
44720
44721
44722
44723
44724
44725
44726
44727 class IniHelper
44728 {
44729
44730
44731
44732
44733
44734
44735
44736
44737 public static function getAll()
44738 {
44739 return XdebugHandler::getAllIniFiles();
44740 }
44741
44742
44743
44744
44745
44746
44747 public static function getMessage()
44748 {
44749 $paths = self::getAll();
44750
44751 if (empty($paths[0])) {
44752 array_shift($paths);
44753 }
44754
44755 $ini = array_shift($paths);
44756
44757 if (empty($ini)) {
44758 return 'A php.ini file does not exist. You will have to create one.';
44759 }
44760
44761 if (!empty($paths)) {
44762 return 'Your command-line PHP is using multiple ini files. Run `php --ini` to show them.';
44763 }
44764
44765 return 'The php.ini used by your command-line PHP is: '.$ini;
44766 }
44767 }
44768 <?php
44769
44770
44771
44772
44773
44774
44775
44776
44777
44778
44779
44780 namespace Composer\Util;
44781
44782 use stdClass;
44783
44784
44785
44786
44787 class NoProxyPattern
44788 {
44789
44790
44791
44792 protected $hostNames = array();
44793
44794
44795
44796
44797 protected $rules = array();
44798
44799
44800
44801
44802 protected $noproxy;
44803
44804
44805
44806
44807 public function __construct($pattern)
44808 {
44809 $this->hostNames = preg_split('{[\s,]+}', $pattern, null, PREG_SPLIT_NO_EMPTY);
44810 $this->noproxy = empty($this->hostNames) || '*' === $this->hostNames[0];
44811 }
44812
44813
44814
44815
44816
44817
44818
44819
44820 public function test($url)
44821 {
44822 if ($this->noproxy) {
44823 return true;
44824 }
44825
44826 if (!$urlData = $this->getUrlData($url)) {
44827 return false;
44828 }
44829
44830 foreach ($this->hostNames as $index => $hostName) {
44831 if ($this->match($index, $hostName, $urlData)) {
44832 return true;
44833 }
44834 }
44835
44836 return false;
44837 }
44838
44839
44840
44841
44842
44843
44844
44845
44846 protected function getUrlData($url)
44847 {
44848 if (!$host = parse_url($url, PHP_URL_HOST)) {
44849 return false;
44850 }
44851
44852 $port = parse_url($url, PHP_URL_PORT);
44853
44854 if (empty($port)) {
44855 switch (parse_url($url, PHP_URL_SCHEME)) {
44856 case 'http':
44857 $port = 80;
44858 break;
44859 case 'https':
44860 $port = 443;
44861 break;
44862 }
44863 }
44864
44865 $hostName = $host . ($port ? ':' . $port : '');
44866 list($host, $port, $err) = $this->splitHostPort($hostName);
44867
44868 if ($err || !$this->ipCheckData($host, $ipdata)) {
44869 return false;
44870 }
44871
44872 return $this->makeData($host, $port, $ipdata);
44873 }
44874
44875
44876
44877
44878
44879
44880
44881
44882
44883
44884 protected function match($index, $hostName, $url)
44885 {
44886 if (!$rule = $this->getRule($index, $hostName)) {
44887
44888 return false;
44889 }
44890
44891 if ($rule->ipdata) {
44892
44893 if (!$url->ipdata) {
44894 return false;
44895 }
44896
44897 if ($rule->ipdata->netmask) {
44898 return $this->matchRange($rule->ipdata, $url->ipdata);
44899 }
44900
44901 $match = $rule->ipdata->ip === $url->ipdata->ip;
44902 } else {
44903
44904 $haystack = substr($url->name, - strlen($rule->name));
44905 $match = stripos($haystack, $rule->name) === 0;
44906 }
44907
44908 if ($match && $rule->port) {
44909 $match = $rule->port === $url->port;
44910 }
44911
44912 return $match;
44913 }
44914
44915
44916
44917
44918
44919
44920
44921
44922
44923 protected function matchRange(stdClass $network, stdClass $target)
44924 {
44925 $net = unpack('C*', $network->ip);
44926 $mask = unpack('C*', $network->netmask);
44927 $ip = unpack('C*', $target->ip);
44928
44929 for ($i = 1; $i < 17; ++$i) {
44930 if (($net[$i] & $mask[$i]) !== ($ip[$i] & $mask[$i])) {
44931 return false;
44932 }
44933 }
44934
44935 return true;
44936 }
44937
44938
44939
44940
44941
44942
44943
44944
44945
44946 private function getRule($index, $hostName)
44947 {
44948 if (array_key_exists($index, $this->rules)) {
44949 return $this->rules[$index];
44950 }
44951
44952 $this->rules[$index] = null;
44953 list($host, $port, $err) = $this->splitHostPort($hostName);
44954
44955 if ($err || !$this->ipCheckData($host, $ipdata, true)) {
44956 return null;
44957 }
44958
44959 $this->rules[$index] = $this->makeData($host, $port, $ipdata);
44960
44961 return $this->rules[$index];
44962 }
44963
44964
44965
44966
44967
44968
44969
44970
44971
44972
44973 private function ipCheckData($host, &$ipdata, $allowPrefix = false)
44974 {
44975 $ipdata = null;
44976 $netmask = null;
44977 $prefix = null;
44978 $modified = false;
44979
44980
44981 if (strpos($host, '/') !== false) {
44982 list($host, $prefix) = explode('/', $host);
44983
44984 if (!$allowPrefix || !$this->validateInt($prefix, 0, 128)) {
44985 return false;
44986 }
44987 $prefix = (int) $prefix;
44988 $modified = true;
44989 }
44990
44991
44992 if (!filter_var($host, FILTER_VALIDATE_IP)) {
44993 return !$modified;
44994 }
44995
44996 list($ip, $size) = $this->ipGetAddr($host);
44997
44998 if ($prefix !== null) {
44999
45000 if ($prefix > $size * 8) {
45001 return false;
45002 }
45003
45004 list($ip, $netmask) = $this->ipGetNetwork($ip, $size, $prefix);
45005 }
45006
45007 $ipdata = $this->makeIpData($ip, $size, $netmask);
45008
45009 return true;
45010 }
45011
45012
45013
45014
45015
45016
45017
45018
45019
45020
45021
45022 private function ipGetAddr($host)
45023 {
45024 $ip = inet_pton($host);
45025 $size = strlen($ip);
45026 $mapped = $this->ipMapTo6($ip, $size);
45027
45028 return array($mapped, $size);
45029 }
45030
45031
45032
45033
45034
45035
45036
45037
45038
45039 private function ipGetMask($prefix, $size)
45040 {
45041 $mask = '';
45042
45043 if ($ones = floor($prefix / 8)) {
45044 $mask = str_repeat(chr(255), $ones);
45045 }
45046
45047 if ($remainder = $prefix % 8) {
45048 $mask .= chr(0xff ^ (0xff >> $remainder));
45049 }
45050
45051 $mask = str_pad($mask, $size, chr(0));
45052
45053 return $this->ipMapTo6($mask, $size);
45054 }
45055
45056
45057
45058
45059
45060
45061
45062
45063
45064
45065 private function ipGetNetwork($rangeIp, $size, $prefix)
45066 {
45067 $netmask = $this->ipGetMask($prefix, $size);
45068
45069
45070 $mask = unpack('C*', $netmask);
45071 $ip = unpack('C*', $rangeIp);
45072 $net = '';
45073
45074 for ($i = 1; $i < 17; ++$i) {
45075 $net .= chr($ip[$i] & $mask[$i]);
45076 }
45077
45078 return array($net, $netmask);
45079 }
45080
45081
45082
45083
45084
45085
45086
45087
45088
45089 private function ipMapTo6($binary, $size)
45090 {
45091 if ($size === 4) {
45092 $prefix = str_repeat(chr(0), 10) . str_repeat(chr(255), 2);
45093 $binary = $prefix . $binary;
45094 }
45095
45096 return $binary;
45097 }
45098
45099
45100
45101
45102
45103
45104
45105
45106
45107
45108 private function makeData($host, $port, $ipdata)
45109 {
45110 return (object) array(
45111 'host' => $host,
45112 'name' => '.' . ltrim($host, '.'),
45113 'port' => $port,
45114 'ipdata' => $ipdata,
45115 );
45116 }
45117
45118
45119
45120
45121
45122
45123
45124
45125
45126
45127 private function makeIpData($ip, $size, $netmask)
45128 {
45129 return (object) array(
45130 'ip' => $ip,
45131 'size' => $size,
45132 'netmask' => $netmask,
45133 );
45134 }
45135
45136
45137
45138
45139
45140
45141
45142
45143 private function splitHostPort($hostName)
45144 {
45145
45146 $error = array('', '', true);
45147 $port = 0;
45148 $ip6 = '';
45149
45150
45151 if ($hostName[0] === '[') {
45152 $index = strpos($hostName, ']');
45153
45154
45155 if (false === $index || $index < 3) {
45156 return $error;
45157 }
45158
45159 $ip6 = substr($hostName, 1, $index - 1);
45160 $hostName = substr($hostName, $index + 1);
45161
45162 if (strpbrk($hostName, '[]') !== false
45163 || substr_count($hostName, ':') > 1) {
45164 return $error;
45165 }
45166 }
45167
45168 if (substr_count($hostName, ':') === 1) {
45169 $index = strpos($hostName, ':');
45170 $port = substr($hostName, $index + 1);
45171 $hostName = substr($hostName, 0, $index);
45172
45173 if (!$this->validateInt($port, 1, 65535)) {
45174 return $error;
45175 }
45176
45177 $port = (int) $port;
45178 }
45179
45180 $host = $ip6 . $hostName;
45181
45182 return array($host, $port, false);
45183 }
45184
45185
45186
45187
45188
45189
45190
45191
45192 private function validateInt($int, $min, $max)
45193 {
45194 $options = array(
45195 'options' => array(
45196 'min_range' => $min,
45197 'max_range' => $max)
45198 );
45199
45200 return false !== filter_var($int, FILTER_VALIDATE_INT, $options);
45201 }
45202 }
45203 <?php
45204
45205
45206 namespace Composer\Util;
45207
45208 use Composer\Package\Link;
45209 use Composer\Package\PackageInterface;
45210
45211 class PackageSorter
45212 {
45213
45214
45215
45216
45217
45218
45219
45220
45221 public static function sortPackages(array $packages) {
45222 $usageList = array();
45223
45224 foreach ($packages as $package) { 
45225 foreach (array_merge($package->getRequires(), $package->getDevRequires()) as $link) { 
45226 $target = $link->getTarget();
45227 $usageList[$target][] = $package->getName();
45228 }
45229 }
45230 $computing = array();
45231 $computed = array();
45232 $computeImportance = function ($name) use (&$computeImportance, &$computing, &$computed, $usageList) {
45233
45234 if (isset($computed[$name])) {
45235 return $computed[$name];
45236 }
45237
45238
45239 if (isset($computing[$name])) {
45240 return 0;
45241 }
45242
45243 $computing[$name] = true;
45244 $weight = 0;
45245
45246 if (isset($usageList[$name])) {
45247 foreach ($usageList[$name] as $user) {
45248 $weight -= 1 - $computeImportance($user);
45249 }
45250 }
45251
45252 unset($computing[$name]);
45253 $computed[$name] = $weight;
45254
45255 return $weight;
45256 };
45257
45258 $weightList = array();
45259
45260 foreach ($packages as $name => $package) {
45261 $weight = $computeImportance($name);
45262 $weightList[$name] = $weight;
45263 }
45264
45265 $stable_sort = function (&$array) {
45266 static $transform, $restore;
45267
45268 $i = 0;
45269
45270 if (!$transform) {
45271 $transform = function (&$v, $k) use (&$i) {
45272 $v = array($v, ++$i, $k, $v);
45273 };
45274
45275 $restore = function (&$v) {
45276 $v = $v[3];
45277 };
45278 }
45279
45280 array_walk($array, $transform);
45281 asort($array);
45282 array_walk($array, $restore);
45283 };
45284
45285 $stable_sort($weightList);
45286
45287 $sortedPackages = array();
45288
45289 foreach (array_keys($weightList) as $name) {
45290 $sortedPackages[] = $packages[$name];
45291 }
45292 return $sortedPackages;
45293 }
45294 }
45295 <?php
45296
45297
45298
45299
45300
45301
45302
45303
45304
45305
45306
45307 namespace Composer\Util;
45308
45309 use Composer\IO\IOInterface;
45310 use Symfony\Component\Process\Process;
45311
45312
45313
45314
45315 class Perforce
45316 {
45317 protected $path;
45318 protected $p4Depot;
45319 protected $p4Client;
45320 protected $p4User;
45321 protected $p4Password;
45322 protected $p4Port;
45323 protected $p4Stream;
45324 protected $p4ClientSpec;
45325 protected $p4DepotType;
45326 protected $p4Branch;
45327 protected $process;
45328 protected $uniquePerforceClientName;
45329 protected $windowsFlag;
45330 protected $commandResult;
45331
45332 protected $io;
45333
45334 protected $filesystem;
45335
45336 public function __construct($repoConfig, $port, $path, ProcessExecutor $process, $isWindows, IOInterface $io)
45337 {
45338 $this->windowsFlag = $isWindows;
45339 $this->p4Port = $port;
45340 $this->initializePath($path);
45341 $this->process = $process;
45342 $this->initialize($repoConfig);
45343 $this->io = $io;
45344 }
45345
45346 public static function create($repoConfig, $port, $path, ProcessExecutor $process, IOInterface $io)
45347 {
45348 return new Perforce($repoConfig, $port, $path, $process, Platform::isWindows(), $io);
45349 }
45350
45351 public static function checkServerExists($url, ProcessExecutor $processExecutor)
45352 {
45353 $output = null;
45354
45355 return 0 === $processExecutor->execute('p4 -p ' . ProcessExecutor::escape($url) . ' info -s', $output);
45356 }
45357
45358 public function initialize($repoConfig)
45359 {
45360 $this->uniquePerforceClientName = $this->generateUniquePerforceClientName();
45361 if (!$repoConfig) {
45362 return;
45363 }
45364 if (isset($repoConfig['unique_perforce_client_name'])) {
45365 $this->uniquePerforceClientName = $repoConfig['unique_perforce_client_name'];
45366 }
45367
45368 if (isset($repoConfig['depot'])) {
45369 $this->p4Depot = $repoConfig['depot'];
45370 }
45371 if (isset($repoConfig['branch'])) {
45372 $this->p4Branch = $repoConfig['branch'];
45373 }
45374 if (isset($repoConfig['p4user'])) {
45375 $this->p4User = $repoConfig['p4user'];
45376 } else {
45377 $this->p4User = $this->getP4variable('P4USER');
45378 }
45379 if (isset($repoConfig['p4password'])) {
45380 $this->p4Password = $repoConfig['p4password'];
45381 }
45382 }
45383
45384 public function initializeDepotAndBranch($depot, $branch)
45385 {
45386 if (isset($depot)) {
45387 $this->p4Depot = $depot;
45388 }
45389 if (isset($branch)) {
45390 $this->p4Branch = $branch;
45391 }
45392 }
45393
45394 public function generateUniquePerforceClientName()
45395 {
45396 return gethostname() . "_" . time();
45397 }
45398
45399 public function cleanupClientSpec()
45400 {
45401 $client = $this->getClient();
45402 $task = 'client -d ' . ProcessExecutor::escape($client);
45403 $useP4Client = false;
45404 $command = $this->generateP4Command($task, $useP4Client);
45405 $this->executeCommand($command);
45406 $clientSpec = $this->getP4ClientSpec();
45407 $fileSystem = $this->getFilesystem();
45408 $fileSystem->remove($clientSpec);
45409 }
45410
45411 protected function executeCommand($command)
45412 {
45413 $this->commandResult = '';
45414
45415 return $this->process->execute($command, $this->commandResult);
45416 }
45417
45418 public function getClient()
45419 {
45420 if (!isset($this->p4Client)) {
45421 $cleanStreamName = str_replace(array('//', '/', '@'), array('', '_', ''), $this->getStream());
45422 $this->p4Client = 'composer_perforce_' . $this->uniquePerforceClientName . '_' . $cleanStreamName;
45423 }
45424
45425 return $this->p4Client;
45426 }
45427
45428 protected function getPath()
45429 {
45430 return $this->path;
45431 }
45432
45433 public function initializePath($path)
45434 {
45435 $this->path = $path;
45436 $fs = $this->getFilesystem();
45437 $fs->ensureDirectoryExists($path);
45438 }
45439
45440 protected function getPort()
45441 {
45442 return $this->p4Port;
45443 }
45444
45445 public function setStream($stream)
45446 {
45447 $this->p4Stream = $stream;
45448 $index = strrpos($stream, '/');
45449
45450 if ($index > 2) {
45451 $this->p4DepotType = 'stream';
45452 }
45453 }
45454
45455 public function isStream()
45456 {
45457 return (strcmp($this->p4DepotType, 'stream') === 0);
45458 }
45459
45460 public function getStream()
45461 {
45462 if (!isset($this->p4Stream)) {
45463 if ($this->isStream()) {
45464 $this->p4Stream = '//' . $this->p4Depot . '/' . $this->p4Branch;
45465 } else {
45466 $this->p4Stream = '//' . $this->p4Depot;
45467 }
45468 }
45469
45470 return $this->p4Stream;
45471 }
45472
45473 public function getStreamWithoutLabel($stream)
45474 {
45475 $index = strpos($stream, '@');
45476 if ($index === false) {
45477 return $stream;
45478 }
45479
45480 return substr($stream, 0, $index);
45481 }
45482
45483 public function getP4ClientSpec()
45484 {
45485 return $this->path . '/' . $this->getClient() . '.p4.spec';
45486 }
45487
45488 public function getUser()
45489 {
45490 return $this->p4User;
45491 }
45492
45493 public function setUser($user)
45494 {
45495 $this->p4User = $user;
45496 }
45497
45498 public function queryP4User()
45499 {
45500 $this->getUser();
45501 if (strlen($this->p4User) > 0) {
45502 return;
45503 }
45504 $this->p4User = $this->getP4variable('P4USER');
45505 if (strlen($this->p4User) > 0) {
45506 return;
45507 }
45508 $this->p4User = $this->io->ask('Enter P4 User:');
45509 if ($this->windowsFlag) {
45510 $command = 'p4 set P4USER=' . $this->p4User;
45511 } else {
45512 $command = 'export P4USER=' . $this->p4User;
45513 }
45514 $this->executeCommand($command);
45515 }
45516
45517 protected function getP4variable($name)
45518 {
45519 if ($this->windowsFlag) {
45520 $command = 'p4 set';
45521 $this->executeCommand($command);
45522 $result = trim($this->commandResult);
45523 $resArray = explode(PHP_EOL, $result);
45524 foreach ($resArray as $line) {
45525 $fields = explode('=', $line);
45526 if (strcmp($name, $fields[0]) == 0) {
45527 $index = strpos($fields[1], ' ');
45528 if ($index === false) {
45529 $value = $fields[1];
45530 } else {
45531 $value = substr($fields[1], 0, $index);
45532 }
45533 $value = trim($value);
45534
45535 return $value;
45536 }
45537 }
45538
45539 return null;
45540 }
45541
45542 $command = 'echo $' . $name;
45543 $this->executeCommand($command);
45544 $result = trim($this->commandResult);
45545
45546 return $result;
45547 }
45548
45549 public function queryP4Password()
45550 {
45551 if (isset($this->p4Password)) {
45552 return $this->p4Password;
45553 }
45554 $password = $this->getP4variable('P4PASSWD');
45555 if (strlen($password) <= 0) {
45556 $password = $this->io->askAndHideAnswer('Enter password for Perforce user ' . $this->getUser() . ': ');
45557 }
45558 $this->p4Password = $password;
45559
45560 return $password;
45561 }
45562
45563 public function generateP4Command($command, $useClient = true)
45564 {
45565 $p4Command = 'p4 ';
45566 $p4Command .= '-u ' . $this->getUser() . ' ';
45567 if ($useClient) {
45568 $p4Command .= '-c ' . $this->getClient() . ' ';
45569 }
45570 $p4Command = $p4Command . '-p ' . $this->getPort() . ' ' . $command;
45571
45572 return $p4Command;
45573 }
45574
45575 public function isLoggedIn()
45576 {
45577 $command = $this->generateP4Command('login -s', false);
45578 $exitCode = $this->executeCommand($command);
45579 if ($exitCode) {
45580 $errorOutput = $this->process->getErrorOutput();
45581 $index = strpos($errorOutput, $this->getUser());
45582 if ($index === false) {
45583 $index = strpos($errorOutput, 'p4');
45584 if ($index === false) {
45585 return false;
45586 }
45587 throw new \Exception('p4 command not found in path: ' . $errorOutput);
45588 }
45589 throw new \Exception('Invalid user name: ' . $this->getUser());
45590 }
45591
45592 return true;
45593 }
45594
45595 public function connectClient()
45596 {
45597 $p4CreateClientCommand = $this->generateP4Command(
45598 'client -i < ' . str_replace(" ", "\\ ", $this->getP4ClientSpec())
45599 );
45600 $this->executeCommand($p4CreateClientCommand);
45601 }
45602
45603 public function syncCodeBase($sourceReference)
45604 {
45605 $prevDir = getcwd();
45606 chdir($this->path);
45607 $p4SyncCommand = $this->generateP4Command('sync -f ');
45608 if (null !== $sourceReference) {
45609 $p4SyncCommand .= '@' . $sourceReference;
45610 }
45611 $this->executeCommand($p4SyncCommand);
45612 chdir($prevDir);
45613 }
45614
45615 public function writeClientSpecToFile($spec)
45616 {
45617 fwrite($spec, 'Client: ' . $this->getClient() . PHP_EOL . PHP_EOL);
45618 fwrite($spec, 'Update: ' . date('Y/m/d H:i:s') . PHP_EOL . PHP_EOL);
45619 fwrite($spec, 'Access: ' . date('Y/m/d H:i:s') . PHP_EOL);
45620 fwrite($spec, 'Owner:  ' . $this->getUser() . PHP_EOL . PHP_EOL);
45621 fwrite($spec, 'Description:' . PHP_EOL);
45622 fwrite($spec, '  Created by ' . $this->getUser() . ' from composer.' . PHP_EOL . PHP_EOL);
45623 fwrite($spec, 'Root: ' . $this->getPath() . PHP_EOL . PHP_EOL);
45624 fwrite($spec, 'Options:  noallwrite noclobber nocompress unlocked modtime rmdir' . PHP_EOL . PHP_EOL);
45625 fwrite($spec, 'SubmitOptions:  revertunchanged' . PHP_EOL . PHP_EOL);
45626 fwrite($spec, 'LineEnd:  local' . PHP_EOL . PHP_EOL);
45627 if ($this->isStream()) {
45628 fwrite($spec, 'Stream:' . PHP_EOL);
45629 fwrite($spec, '  ' . $this->getStreamWithoutLabel($this->p4Stream) . PHP_EOL);
45630 } else {
45631 fwrite(
45632 $spec,
45633 'View:  ' . $this->getStream() . '/...  //' . $this->getClient() . '/... ' . PHP_EOL
45634 );
45635 }
45636 }
45637
45638 public function writeP4ClientSpec()
45639 {
45640 $clientSpec = $this->getP4ClientSpec();
45641 $spec = fopen($clientSpec, 'w');
45642 try {
45643 $this->writeClientSpecToFile($spec);
45644 } catch (\Exception $e) {
45645 fclose($spec);
45646 throw $e;
45647 }
45648 fclose($spec);
45649 }
45650
45651 protected function read($pipe, $name)
45652 {
45653 if (feof($pipe)) {
45654 return;
45655 }
45656 $line = fgets($pipe);
45657 while ($line !== false) {
45658 $line = fgets($pipe);
45659 }
45660 }
45661
45662 public function windowsLogin($password)
45663 {
45664 $command = $this->generateP4Command(' login -a');
45665
45666
45667 if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
45668 $process = Process::fromShellCommandline($command, null, null, $password);
45669 } else {
45670 $process = new Process($command, null, null, $password);
45671 }
45672
45673 return $process->run();
45674 }
45675
45676 public function p4Login()
45677 {
45678 $this->queryP4User();
45679 if (!$this->isLoggedIn()) {
45680 $password = $this->queryP4Password();
45681 if ($this->windowsFlag) {
45682 $this->windowsLogin($password);
45683 } else {
45684 $command = 'echo ' . ProcessExecutor::escape($password) . ' | ' . $this->generateP4Command(' login -a', false);
45685 $exitCode = $this->executeCommand($command);
45686 $result = trim($this->commandResult);
45687 if ($exitCode) {
45688 throw new \Exception("Error logging in:" . $this->process->getErrorOutput());
45689 }
45690 }
45691 }
45692 }
45693
45694 public function getComposerInformation($identifier)
45695 {
45696 $composerFileContent = $this->getFileContent('composer.json', $identifier);
45697
45698 if (!$composerFileContent) {
45699 return;
45700 }
45701
45702 return json_decode($composerFileContent, true);
45703 }
45704
45705 public function getFileContent($file, $identifier)
45706 {
45707 $path = $this->getFilePath($file, $identifier);
45708
45709 $command = $this->generateP4Command(' print ' . ProcessExecutor::escape($path));
45710 $this->executeCommand($command);
45711 $result = $this->commandResult;
45712
45713 if (!trim($result)) {
45714 return null;
45715 }
45716
45717 return $result;
45718 }
45719
45720 public function getFilePath($file, $identifier)
45721 {
45722 $index = strpos($identifier, '@');
45723 if ($index === false) {
45724 $path = $identifier. '/' . $file;
45725
45726 return $path;
45727 }
45728
45729 $path = substr($identifier, 0, $index) . '/' . $file . substr($identifier, $index);
45730 $command = $this->generateP4Command(' files ' . ProcessExecutor::escape($path), false);
45731 $this->executeCommand($command);
45732 $result = $this->commandResult;
45733 $index2 = strpos($result, 'no such file(s).');
45734 if ($index2 === false) {
45735 $index3 = strpos($result, 'change');
45736 if ($index3 !== false) {
45737 $phrase = trim(substr($result, $index3));
45738 $fields = explode(' ', $phrase);
45739
45740 return substr($identifier, 0, $index) . '/' . $file . '@' . $fields[1];
45741 }
45742 }
45743
45744 return null;
45745 }
45746
45747 public function getBranches()
45748 {
45749 $possibleBranches = array();
45750 if (!$this->isStream()) {
45751 $possibleBranches[$this->p4Branch] = $this->getStream();
45752 } else {
45753 $command = $this->generateP4Command('streams '.ProcessExecutor::escape('//' . $this->p4Depot . '/...'));
45754 $this->executeCommand($command);
45755 $result = $this->commandResult;
45756 $resArray = explode(PHP_EOL, $result);
45757 foreach ($resArray as $line) {
45758 $resBits = explode(' ', $line);
45759 if (count($resBits) > 4) {
45760 $branch = preg_replace('/[^A-Za-z0-9 ]/', '', $resBits[4]);
45761 $possibleBranches[$branch] = $resBits[1];
45762 }
45763 }
45764 }
45765 $command = $this->generateP4Command('changes '. ProcessExecutor::escape($this->getStream() . '/...'), false);
45766 $this->executeCommand($command);
45767 $result = $this->commandResult;
45768 $resArray = explode(PHP_EOL, $result);
45769 $lastCommit = $resArray[0];
45770 $lastCommitArr = explode(' ', $lastCommit);
45771 $lastCommitNum = $lastCommitArr[1];
45772
45773 $branches = array('master' => $possibleBranches[$this->p4Branch] . '@'. $lastCommitNum);
45774
45775 return $branches;
45776 }
45777
45778 public function getTags()
45779 {
45780 $command = $this->generateP4Command('labels');
45781 $this->executeCommand($command);
45782 $result = $this->commandResult;
45783 $resArray = explode(PHP_EOL, $result);
45784 $tags = array();
45785 foreach ($resArray as $line) {
45786 if (strpos($line, 'Label') !== false) {
45787 $fields = explode(' ', $line);
45788 $tags[$fields[1]] = $this->getStream() . '@' . $fields[1];
45789 }
45790 }
45791
45792 return $tags;
45793 }
45794
45795 public function checkStream()
45796 {
45797 $command = $this->generateP4Command('depots', false);
45798 $this->executeCommand($command);
45799 $result = $this->commandResult;
45800 $resArray = explode(PHP_EOL, $result);
45801 foreach ($resArray as $line) {
45802 if (strpos($line, 'Depot') !== false) {
45803 $fields = explode(' ', $line);
45804 if (strcmp($this->p4Depot, $fields[1]) === 0) {
45805 $this->p4DepotType = $fields[3];
45806
45807 return $this->isStream();
45808 }
45809 }
45810 }
45811
45812 return false;
45813 }
45814
45815
45816
45817
45818
45819 protected function getChangeList($reference)
45820 {
45821 $index = strpos($reference, '@');
45822 if ($index === false) {
45823 return null;
45824 }
45825 $label = substr($reference, $index);
45826 $command = $this->generateP4Command(' changes -m1 ' . ProcessExecutor::escape($label));
45827 $this->executeCommand($command);
45828 $changes = $this->commandResult;
45829 if (strpos($changes, 'Change') !== 0) {
45830 return null;
45831 }
45832 $fields = explode(' ', $changes);
45833
45834 return $fields[1];
45835 }
45836
45837
45838
45839
45840
45841
45842 public function getCommitLogs($fromReference, $toReference)
45843 {
45844 $fromChangeList = $this->getChangeList($fromReference);
45845 if ($fromChangeList === null) {
45846 return null;
45847 }
45848 $toChangeList = $this->getChangeList($toReference);
45849 if ($toChangeList === null) {
45850 return null;
45851 }
45852 $index = strpos($fromReference, '@');
45853 $main = substr($fromReference, 0, $index) . '/...';
45854 $command = $this->generateP4Command('filelog ' . ProcessExecutor::escape($main . '@' . $fromChangeList. ',' . $toChangeList));
45855 $this->executeCommand($command);
45856
45857 return $this->commandResult;
45858 }
45859
45860 public function getFilesystem()
45861 {
45862 if (empty($this->filesystem)) {
45863 $this->filesystem = new Filesystem($this->process);
45864 }
45865
45866 return $this->filesystem;
45867 }
45868
45869 public function setFilesystem(Filesystem $fs)
45870 {
45871 $this->filesystem = $fs;
45872 }
45873 }
45874 <?php
45875
45876
45877
45878
45879
45880
45881
45882
45883
45884
45885
45886 namespace Composer\Util;
45887
45888
45889
45890
45891
45892
45893 class Platform
45894 {
45895
45896
45897
45898
45899
45900
45901 public static function expandPath($path)
45902 {
45903 if (preg_match('#^~[\\/]#', $path)) {
45904 return self::getUserDirectory() . substr($path, 1);
45905 }
45906
45907 return preg_replace_callback('#^(\$|(?P<percent>%))(?P<var>\w++)(?(percent)%)(?P<path>.*)#', function ($matches) {
45908
45909 if (Platform::isWindows() && $matches['var'] == 'HOME') {
45910 return (getenv('HOME') ?: getenv('USERPROFILE')) . $matches['path'];
45911 }
45912
45913 return getenv($matches['var']) . $matches['path'];
45914 }, $path);
45915 }
45916
45917
45918
45919
45920
45921 public static function getUserDirectory()
45922 {
45923 if (false !== ($home = getenv('HOME'))) {
45924 return $home;
45925 }
45926
45927 if (self::isWindows() && false !== ($home = getenv('USERPROFILE'))) {
45928 return $home;
45929 }
45930
45931 if (function_exists('posix_getuid') && function_exists('posix_getpwuid')) {
45932 $info = posix_getpwuid(posix_getuid());
45933
45934 return $info['dir'];
45935 }
45936
45937 throw new \RuntimeException('Could not determine user directory');
45938 }
45939
45940
45941
45942
45943 public static function isWindows()
45944 {
45945 return defined('PHP_WINDOWS_VERSION_BUILD');
45946 }
45947
45948
45949
45950
45951
45952 public static function strlen($str)
45953 {
45954 static $useMbString = null;
45955 if (null === $useMbString) {
45956 $useMbString = function_exists('mb_strlen') && ini_get('mbstring.func_overload');
45957 }
45958
45959 if ($useMbString) {
45960 return mb_strlen($str, '8bit');
45961 }
45962
45963 return strlen($str);
45964 }
45965 }
45966 <?php
45967
45968
45969
45970
45971
45972
45973
45974
45975
45976
45977
45978 namespace Composer\Util;
45979
45980 use Composer\IO\IOInterface;
45981 use Symfony\Component\Process\Process;
45982 use Symfony\Component\Process\ProcessUtils;
45983
45984
45985
45986
45987 class ProcessExecutor
45988 {
45989 protected static $timeout = 300;
45990
45991 protected $captureOutput;
45992 protected $errorOutput;
45993 protected $io;
45994
45995 public function __construct(IOInterface $io = null)
45996 {
45997 $this->io = $io;
45998 }
45999
46000
46001
46002
46003
46004
46005
46006
46007
46008
46009 public function execute($command, &$output = null, $cwd = null)
46010 {
46011 if ($this->io && $this->io->isDebug()) {
46012 $safeCommand = preg_replace_callback('{://(?P<user>[^:/\s]+):(?P<password>[^@\s/]+)@}i', function ($m) {
46013
46014 if (preg_match('{^([a-f0-9]{12,}|gh[a-z]_[a-zA-Z0-9_]+)$}', $m['user'])) {
46015 return '://***:***@';
46016 }
46017
46018 return '://'.$m['user'].':***@';
46019 }, $command);
46020 $safeCommand = preg_replace("{--password (.*[^\\\\]\') }", '--password \'***\' ', $safeCommand);
46021 $this->io->writeError('Executing command ('.($cwd ?: 'CWD').'): '.$safeCommand);
46022 }
46023
46024
46025
46026 if (null === $cwd && Platform::isWindows() && false !== strpos($command, 'git') && getcwd()) {
46027 $cwd = realpath(getcwd());
46028 }
46029
46030 if (null !== $cwd && !is_dir($cwd)) {
46031 throw new \RuntimeException('The given CWD for the process does not exist: '.$cwd);
46032 }
46033
46034 $this->captureOutput = func_num_args() > 1;
46035 $this->errorOutput = null;
46036
46037
46038 if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
46039 $process = Process::fromShellCommandline($command, $cwd, null, null, static::getTimeout());
46040 } else {
46041 $process = new Process($command, $cwd, null, null, static::getTimeout());
46042 }
46043
46044 $callback = is_callable($output) ? $output : array($this, 'outputHandler');
46045 $process->run($callback);
46046
46047 if ($this->captureOutput && !is_callable($output)) {
46048 $output = $process->getOutput();
46049 }
46050
46051 $this->errorOutput = $process->getErrorOutput();
46052
46053 return $process->getExitCode();
46054 }
46055
46056 public function splitLines($output)
46057 {
46058 $output = trim($output);
46059
46060 return ((string) $output === '') ? array() : preg_split('{\r?\n}', $output);
46061 }
46062
46063
46064
46065
46066
46067
46068 public function getErrorOutput()
46069 {
46070 return $this->errorOutput;
46071 }
46072
46073 public function outputHandler($type, $buffer)
46074 {
46075 if ($this->captureOutput) {
46076 return;
46077 }
46078
46079 if (null === $this->io) {
46080 echo $buffer;
46081
46082 return;
46083 }
46084
46085 if (method_exists($this->io, 'writeRaw')) {
46086 if (Process::ERR === $type) {
46087 $this->io->writeErrorRaw($buffer, false);
46088 } else {
46089 $this->io->writeRaw($buffer, false);
46090 }
46091 } else {
46092 if (Process::ERR === $type) {
46093 $this->io->writeError($buffer, false);
46094 } else {
46095 $this->io->write($buffer, false);
46096 }
46097 }
46098 }
46099
46100 public static function getTimeout()
46101 {
46102 return static::$timeout;
46103 }
46104
46105 public static function setTimeout($timeout)
46106 {
46107 static::$timeout = $timeout;
46108 }
46109
46110
46111
46112
46113
46114
46115
46116
46117 public static function escape($argument)
46118 {
46119 return self::escapeArgument($argument);
46120 }
46121
46122
46123
46124
46125
46126
46127
46128
46129 private static function escapeArgument($argument)
46130 {
46131
46132
46133
46134
46135 if ('\\' === DIRECTORY_SEPARATOR) {
46136 if ((string) $argument === '') {
46137 return escapeshellarg($argument);
46138 }
46139
46140 $escapedArgument = '';
46141 $quote = false;
46142 foreach (preg_split('/(")/', $argument, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $part) {
46143 if ('"' === $part) {
46144 $escapedArgument .= '\\"';
46145 } elseif (self::isSurroundedBy($part, '%')) {
46146
46147 $escapedArgument .= '^%"'.substr($part, 1, -1).'"^%';
46148 } else {
46149
46150 if ('\\' === substr($part, -1)) {
46151 $part .= '\\';
46152 }
46153 $quote = true;
46154 $escapedArgument .= $part;
46155 }
46156 }
46157 if ($quote) {
46158 $escapedArgument = '"'.$escapedArgument.'"';
46159 }
46160
46161 return $escapedArgument;
46162 }
46163
46164 return "'".str_replace("'", "'\\''", $argument)."'";
46165 }
46166
46167 private static function isSurroundedBy($arg, $char)
46168 {
46169 return 2 < strlen($arg) && $char === $arg[0] && $char === $arg[strlen($arg) - 1];
46170 }
46171 }
46172 <?php
46173
46174
46175
46176
46177
46178
46179
46180
46181
46182
46183
46184 namespace Composer\Util;
46185
46186 use Composer\Config;
46187 use Composer\Composer;
46188 use Composer\Semver\Constraint\Constraint;
46189 use Composer\Package\Version\VersionParser;
46190 use Composer\IO\IOInterface;
46191 use Composer\Downloader\TransportException;
46192 use Composer\CaBundle\CaBundle;
46193 use Psr\Log\LoggerInterface;
46194
46195
46196
46197
46198
46199
46200 class RemoteFilesystem
46201 {
46202 private $io;
46203 private $config;
46204 private $scheme;
46205 private $bytesMax;
46206 private $originUrl;
46207 private $fileUrl;
46208 private $fileName;
46209 private $retry;
46210 private $progress;
46211 private $lastProgress;
46212 private $options = array();
46213 private $peerCertificateMap = array();
46214 private $disableTls = false;
46215 private $retryAuthFailure;
46216 private $lastHeaders;
46217 private $storeAuth;
46218 private $degradedMode = false;
46219 private $redirects;
46220 private $maxRedirects = 20;
46221 private $displayedOriginAuthentications = array();
46222
46223
46224
46225
46226
46227
46228
46229
46230
46231 public function __construct(IOInterface $io, Config $config = null, array $options = array(), $disableTls = false)
46232 {
46233 $this->io = $io;
46234
46235
46236
46237 if ($disableTls === false) {
46238 $this->options = $this->getTlsDefaults($options);
46239 } else {
46240 $this->disableTls = true;
46241 }
46242
46243
46244 $this->options = array_replace_recursive($this->options, $options);
46245 $this->config = $config;
46246 }
46247
46248
46249
46250
46251
46252
46253
46254
46255
46256
46257
46258
46259 public function copy($originUrl, $fileUrl, $fileName, $progress = true, $options = array())
46260 {
46261 return $this->get($originUrl, $fileUrl, $options, $fileName, $progress);
46262 }
46263
46264
46265
46266
46267
46268
46269
46270
46271
46272
46273
46274 public function getContents($originUrl, $fileUrl, $progress = true, $options = array())
46275 {
46276 return $this->get($originUrl, $fileUrl, $options, null, $progress);
46277 }
46278
46279
46280
46281
46282
46283
46284 public function getOptions()
46285 {
46286 return $this->options;
46287 }
46288
46289
46290
46291
46292
46293
46294 public function setOptions(array $options)
46295 {
46296 $this->options = array_replace_recursive($this->options, $options);
46297 }
46298
46299
46300
46301
46302
46303
46304 public function isTlsDisabled()
46305 {
46306 return $this->disableTls === true;
46307 }
46308
46309
46310
46311
46312
46313
46314 public function getLastHeaders()
46315 {
46316 return $this->lastHeaders;
46317 }
46318
46319
46320
46321
46322
46323
46324 public function findHeaderValue(array $headers, $name)
46325 {
46326 $value = null;
46327 foreach ($headers as $header) {
46328 if (preg_match('{^'.$name.':\s*(.+?)\s*$}i', $header, $match)) {
46329 $value = $match[1];
46330 } elseif (preg_match('{^HTTP/}i', $header)) {
46331
46332
46333 $value = null;
46334 }
46335 }
46336
46337 return $value;
46338 }
46339
46340
46341
46342
46343
46344 public function findStatusCode(array $headers)
46345 {
46346 $value = null;
46347 foreach ($headers as $header) {
46348 if (preg_match('{^HTTP/\S+ (\d+)}i', $header, $match)) {
46349
46350
46351 $value = (int) $match[1];
46352 }
46353 }
46354
46355 return $value;
46356 }
46357
46358
46359
46360
46361
46362 public function findStatusMessage(array $headers)
46363 {
46364 $value = null;
46365 foreach ($headers as $header) {
46366 if (preg_match('{^HTTP/\S+ \d+}i', $header)) {
46367
46368
46369 $value = $header;
46370 }
46371 }
46372
46373 return $value;
46374 }
46375
46376
46377
46378
46379
46380
46381
46382
46383
46384
46385
46386
46387
46388
46389
46390 protected function get($originUrl, $fileUrl, $additionalOptions = array(), $fileName = null, $progress = true)
46391 {
46392 if (strpos($originUrl, '.github.com') === (strlen($originUrl) - 11)) {
46393 $originUrl = 'github.com';
46394 }
46395
46396
46397
46398 if (
46399 $this->config
46400 && is_array($this->config->get('gitlab-domains'))
46401 && false === strpos($originUrl, '/')
46402 && !in_array($originUrl, $this->config->get('gitlab-domains'))
46403 ) {
46404 foreach ($this->config->get('gitlab-domains') as $gitlabDomain) {
46405 if (0 === strpos($gitlabDomain, $originUrl)) {
46406 $originUrl = $gitlabDomain;
46407 break;
46408 }
46409 }
46410 unset($gitlabDomain);
46411 }
46412
46413 $this->scheme = parse_url($fileUrl, PHP_URL_SCHEME);
46414 $this->bytesMax = 0;
46415 $this->originUrl = $originUrl;
46416 $this->fileUrl = $fileUrl;
46417 $this->fileName = $fileName;
46418 $this->progress = $progress;
46419 $this->lastProgress = null;
46420 $this->retryAuthFailure = true;
46421 $this->lastHeaders = array();
46422 $this->redirects = 1; 
46423
46424
46425 if (preg_match('{^https?://([^:/]+):([^@/]+)@([^/]+)}i', $fileUrl, $match)) {
46426 $this->io->setAuthentication($originUrl, rawurldecode($match[1]), rawurldecode($match[2]));
46427 }
46428
46429 $tempAdditionalOptions = $additionalOptions;
46430 if (isset($tempAdditionalOptions['retry-auth-failure'])) {
46431 $this->retryAuthFailure = (bool) $tempAdditionalOptions['retry-auth-failure'];
46432
46433 unset($tempAdditionalOptions['retry-auth-failure']);
46434 }
46435
46436 $isRedirect = false;
46437 if (isset($tempAdditionalOptions['redirects'])) {
46438 $this->redirects = $tempAdditionalOptions['redirects'];
46439 $isRedirect = true;
46440
46441 unset($tempAdditionalOptions['redirects']);
46442 }
46443
46444 $options = $this->getOptionsForUrl($originUrl, $tempAdditionalOptions);
46445 unset($tempAdditionalOptions);
46446
46447 $origFileUrl = $fileUrl;
46448
46449 if (isset($options['github-token'])) {
46450
46451 if (preg_match('{^https?://api\.github\.com/}', $fileUrl)) {
46452 $options['http']['header'][] = 'Authorization: token '.$options['github-token'];
46453 }
46454 unset($options['github-token']);
46455 }
46456
46457 if (isset($options['gitlab-token'])) {
46458 $fileUrl .= (false === strpos($fileUrl, '?') ? '?' : '&') . 'access_token='.$options['gitlab-token'];
46459 unset($options['gitlab-token']);
46460 }
46461
46462 if (isset($options['http'])) {
46463 $options['http']['ignore_errors'] = true;
46464 }
46465
46466 if ($this->degradedMode && substr($fileUrl, 0, 26) === 'http://repo.packagist.org/') {
46467
46468 $fileUrl = 'http://' . gethostbyname('repo.packagist.org') . substr($fileUrl, 20);
46469 $degradedPackagist = true;
46470 }
46471
46472 $ctx = StreamContextFactory::getContext($fileUrl, $options, array('notification' => array($this, 'callbackGet')));
46473
46474 $actualContextOptions = stream_context_get_options($ctx);
46475 $usingProxy = !empty($actualContextOptions['http']['proxy']) ? ' using proxy ' . $actualContextOptions['http']['proxy'] : '';
46476 $this->io->writeError((substr($origFileUrl, 0, 4) === 'http' ? 'Downloading ' : 'Reading ') . $this->stripCredentialsFromUrl($origFileUrl) . $usingProxy, true, IOInterface::DEBUG);
46477 unset($origFileUrl, $actualContextOptions);
46478
46479
46480 if ((!preg_match('{^http://(repo\.)?packagist\.org/p/}', $fileUrl) || (false === strpos($fileUrl, '$') && false === strpos($fileUrl, '%24'))) && empty($degradedPackagist) && $this->config) {
46481 $this->config->prohibitUrlByConfig($fileUrl, $this->io);
46482 }
46483
46484 if ($this->progress && !$isRedirect) {
46485 $this->io->writeError("Downloading (<comment>connecting...</comment>)", false);
46486 }
46487
46488 $errorMessage = '';
46489 $errorCode = 0;
46490 $result = false;
46491 set_error_handler(function ($code, $msg) use (&$errorMessage) {
46492 if ($errorMessage) {
46493 $errorMessage .= "\n";
46494 }
46495 $errorMessage .= preg_replace('{^file_get_contents\(.*?\): }', '', $msg);
46496
46497 return true;
46498 });
46499 try {
46500 $result = $this->getRemoteContents($originUrl, $fileUrl, $ctx, $http_response_header);
46501
46502 if (!empty($http_response_header[0])) {
46503 $statusCode = $this->findStatusCode($http_response_header);
46504 if ($statusCode >= 400 && $this->findHeaderValue($http_response_header, 'content-type') === 'application/json') {
46505 self::outputWarnings($this->io, $originUrl, json_decode($result, true));
46506 }
46507
46508 if (in_array($statusCode, array(401, 403)) && $this->retryAuthFailure) {
46509 $this->promptAuthAndRetry($statusCode, $this->findStatusMessage($http_response_header), null, $http_response_header);
46510 }
46511 }
46512
46513 $contentLength = !empty($http_response_header[0]) ? $this->findHeaderValue($http_response_header, 'content-length') : null;
46514 if ($contentLength && Platform::strlen($result) < $contentLength) {
46515
46516 $e = new TransportException('Content-Length mismatch, received '.Platform::strlen($result).' bytes out of the expected '.$contentLength);
46517 $e->setHeaders($http_response_header);
46518 $e->setStatusCode($this->findStatusCode($http_response_header));
46519 $e->setResponse($result);
46520 $this->io->writeError('Content-Length mismatch, received '.Platform::strlen($result).' out of '.$contentLength.' bytes: (' . base64_encode($result).')', true, IOInterface::DEBUG);
46521
46522 throw $e;
46523 }
46524
46525 if (PHP_VERSION_ID < 50600 && !empty($options['ssl']['peer_fingerprint'])) {
46526
46527 $params = stream_context_get_params($ctx);
46528 $expectedPeerFingerprint = $options['ssl']['peer_fingerprint'];
46529 $peerFingerprint = TlsHelper::getCertificateFingerprint($params['options']['ssl']['peer_certificate']);
46530
46531
46532 if ($expectedPeerFingerprint !== $peerFingerprint) {
46533 throw new TransportException('Peer fingerprint did not match');
46534 }
46535 }
46536 } catch (\Exception $e) {
46537 if ($e instanceof TransportException && !empty($http_response_header[0])) {
46538 $e->setHeaders($http_response_header);
46539 $e->setStatusCode($this->findStatusCode($http_response_header));
46540 }
46541 if ($e instanceof TransportException && $result !== false) {
46542 $e->setResponse($result);
46543 }
46544 $result = false;
46545 }
46546 if ($errorMessage && !filter_var(ini_get('allow_url_fopen'), FILTER_VALIDATE_BOOLEAN)) {
46547 $errorMessage = 'allow_url_fopen must be enabled in php.ini ('.$errorMessage.')';
46548 }
46549 restore_error_handler();
46550 if (isset($e) && !$this->retry) {
46551 if (!$this->degradedMode && false !== strpos($e->getMessage(), 'Operation timed out')) {
46552 $this->degradedMode = true;
46553 $this->io->writeError('');
46554 $this->io->writeError(array(
46555 '<error>'.$e->getMessage().'</error>',
46556 '<error>Retrying with degraded mode, check https://getcomposer.org/doc/articles/troubleshooting.md#degraded-mode for more info</error>',
46557 ));
46558
46559 return $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress);
46560 }
46561
46562 throw $e;
46563 }
46564
46565 $statusCode = null;
46566 $contentType = null;
46567 $locationHeader = null;
46568 if (!empty($http_response_header[0])) {
46569 $statusCode = $this->findStatusCode($http_response_header);
46570 $contentType = $this->findHeaderValue($http_response_header, 'content-type');
46571 $locationHeader = $this->findHeaderValue($http_response_header, 'location');
46572 }
46573
46574
46575 if ($originUrl === 'bitbucket.org'
46576 && !$this->isPublicBitBucketDownload($fileUrl)
46577 && substr($fileUrl, -4) === '.zip'
46578 && (!$locationHeader || substr(parse_url($locationHeader, PHP_URL_PATH), -4) !== '.zip')
46579 && $contentType && preg_match('{^text/html\b}i', $contentType)
46580 ) {
46581 $result = false;
46582 if ($this->retryAuthFailure) {
46583 $this->promptAuthAndRetry(401);
46584 }
46585 }
46586
46587
46588 if ($statusCode === 404
46589 && $this->config && in_array($originUrl, $this->config->get('gitlab-domains'), true)
46590 && false !== strpos($fileUrl, 'archive.zip')
46591 ) {
46592 $result = false;
46593 if ($this->retryAuthFailure) {
46594 $this->promptAuthAndRetry(401);
46595 }
46596 }
46597
46598
46599 $hasFollowedRedirect = false;
46600 if ($statusCode >= 300 && $statusCode <= 399 && $statusCode !== 304 && $this->redirects < $this->maxRedirects) {
46601 $hasFollowedRedirect = true;
46602 $result = $this->handleRedirect($http_response_header, $additionalOptions, $result);
46603 }
46604
46605
46606 if ($statusCode && $statusCode >= 400 && $statusCode <= 599) {
46607 if (!$this->retry) {
46608 if ($this->progress && !$this->retry && !$isRedirect) {
46609 $this->io->overwriteError("Downloading (<error>failed</error>)", false);
46610 }
46611
46612 $e = new TransportException('The "'.$this->fileUrl.'" file could not be downloaded ('.$http_response_header[0].')', $statusCode);
46613 $e->setHeaders($http_response_header);
46614 $e->setResponse($result);
46615 $e->setStatusCode($statusCode);
46616 throw $e;
46617 }
46618 $result = false;
46619 }
46620
46621 if ($this->progress && !$this->retry && !$isRedirect) {
46622 $this->io->overwriteError("Downloading (".($result === false ? '<error>failed</error>' : '<comment>100%</comment>').")", false);
46623 }
46624
46625
46626 if ($result && extension_loaded('zlib') && substr($fileUrl, 0, 4) === 'http' && !$hasFollowedRedirect) {
46627 $contentEncoding = $this->findHeaderValue($http_response_header, 'content-encoding');
46628 $decode = $contentEncoding && 'gzip' === strtolower($contentEncoding);
46629
46630 if ($decode) {
46631 try {
46632 if (PHP_VERSION_ID >= 50400) {
46633 $result = zlib_decode($result);
46634 } else {
46635
46636 $result = file_get_contents('compress.zlib://data:application/octet-stream;base64,'.base64_encode($result));
46637 }
46638
46639 if (!$result) {
46640 throw new TransportException('Failed to decode zlib stream');
46641 }
46642 } catch (\Exception $e) {
46643 if ($this->degradedMode) {
46644 throw $e;
46645 }
46646
46647 $this->degradedMode = true;
46648 $this->io->writeError(array(
46649 '',
46650 '<error>Failed to decode response: '.$e->getMessage().'</error>',
46651 '<error>Retrying with degraded mode, check https://getcomposer.org/doc/articles/troubleshooting.md#degraded-mode for more info</error>',
46652 ));
46653
46654 return $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress);
46655 }
46656 }
46657 }
46658
46659
46660 if (false !== $result && null !== $fileName && !$isRedirect) {
46661 if ('' === $result) {
46662 throw new TransportException('"'.$this->fileUrl.'" appears broken, and returned an empty 200 response');
46663 }
46664
46665 $errorMessage = '';
46666 set_error_handler(function ($code, $msg) use (&$errorMessage) {
46667 if ($errorMessage) {
46668 $errorMessage .= "\n";
46669 }
46670 $errorMessage .= preg_replace('{^file_put_contents\(.*?\): }', '', $msg);
46671
46672 return true;
46673 });
46674 $result = (bool) file_put_contents($fileName, $result);
46675 restore_error_handler();
46676 if (false === $result) {
46677 throw new TransportException('The "'.$this->fileUrl.'" file could not be written to '.$fileName.': '.$errorMessage);
46678 }
46679 }
46680
46681
46682 if (false === $result && false !== strpos($errorMessage, 'Peer certificate') && PHP_VERSION_ID < 50600) {
46683
46684
46685
46686
46687
46688
46689
46690
46691
46692
46693
46694
46695
46696
46697
46698
46699 if (CaBundle::isOpensslParseSafe()) {
46700 $certDetails = $this->getCertificateCnAndFp($this->fileUrl, $options);
46701
46702 if ($certDetails) {
46703 $this->peerCertificateMap[$this->getUrlAuthority($this->fileUrl)] = $certDetails;
46704
46705 $this->retry = true;
46706 }
46707 } else {
46708 $this->io->writeError('');
46709 $this->io->writeError(sprintf(
46710 '<error>Your version of PHP, %s, is affected by CVE-2013-6420 and cannot safely perform certificate validation, we strongly suggest you upgrade.</error>',
46711 PHP_VERSION
46712 ));
46713 }
46714 }
46715
46716 if ($this->retry) {
46717 $this->retry = false;
46718
46719 $result = $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress);
46720
46721 if ($this->storeAuth && $this->config) {
46722 $authHelper = new AuthHelper($this->io, $this->config);
46723 $authHelper->storeAuth($this->originUrl, $this->storeAuth);
46724 $this->storeAuth = false;
46725 }
46726
46727 return $result;
46728 }
46729
46730 if (false === $result) {
46731 $e = new TransportException('The "'.$this->fileUrl.'" file could not be downloaded: '.$errorMessage, $errorCode);
46732 if (!empty($http_response_header[0])) {
46733 $e->setHeaders($http_response_header);
46734 }
46735
46736 if (!$this->degradedMode && false !== strpos($e->getMessage(), 'Operation timed out')) {
46737 $this->degradedMode = true;
46738 $this->io->writeError('');
46739 $this->io->writeError(array(
46740 '<error>'.$e->getMessage().'</error>',
46741 '<error>Retrying with degraded mode, check https://getcomposer.org/doc/articles/troubleshooting.md#degraded-mode for more info</error>',
46742 ));
46743
46744 return $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress);
46745 }
46746
46747 throw $e;
46748 }
46749
46750 if (!empty($http_response_header[0])) {
46751 $this->lastHeaders = $http_response_header;
46752 }
46753
46754 return $result;
46755 }
46756
46757
46758
46759
46760
46761
46762
46763
46764
46765
46766 protected function getRemoteContents($originUrl, $fileUrl, $context, array &$responseHeaders = null)
46767 {
46768 try {
46769 $e = null;
46770 $result = file_get_contents($fileUrl, false, $context);
46771 } catch (\Throwable $e) {
46772 } catch (\Exception $e) {
46773 }
46774
46775 $responseHeaders = isset($http_response_header) ? $http_response_header : array();
46776
46777 if (null !== $e) {
46778 throw $e;
46779 }
46780
46781 return $result;
46782 }
46783
46784
46785
46786
46787
46788
46789
46790
46791
46792
46793
46794
46795 protected function callbackGet($notificationCode, $severity, $message, $messageCode, $bytesTransferred, $bytesMax)
46796 {
46797 switch ($notificationCode) {
46798 case STREAM_NOTIFY_FAILURE:
46799 if (400 === $messageCode) {
46800
46801
46802 throw new TransportException("The '" . $this->fileUrl . "' URL could not be accessed: " . $message, $messageCode);
46803 }
46804 break;
46805
46806 case STREAM_NOTIFY_FILE_SIZE_IS:
46807 $this->bytesMax = $bytesMax;
46808 break;
46809
46810 case STREAM_NOTIFY_PROGRESS:
46811 if ($this->bytesMax > 0 && $this->progress) {
46812 $progression = min(100, round($bytesTransferred / $this->bytesMax * 100));
46813
46814 if ((0 === $progression % 5) && 100 !== $progression && $progression !== $this->lastProgress) {
46815 $this->lastProgress = $progression;
46816 $this->io->overwriteError("Downloading (<comment>$progression%</comment>)", false);
46817 }
46818 }
46819 break;
46820
46821 default:
46822 break;
46823 }
46824 }
46825
46826 protected function promptAuthAndRetry($httpStatus, $reason = null, $warning = null, $headers = array())
46827 {
46828 if ($this->config && in_array($this->originUrl, $this->config->get('github-domains'), true)) {
46829 $gitHubUtil = new GitHub($this->io, $this->config, null);
46830 $message = "\n";
46831
46832 $rateLimited = $gitHubUtil->isRateLimited($headers);
46833 if ($rateLimited) {
46834 $rateLimit = $gitHubUtil->getRateLimit($headers);
46835 if ($this->io->hasAuthentication($this->originUrl)) {
46836 $message = 'Review your configured GitHub OAuth token or enter a new one to go over the API rate limit.';
46837 } else {
46838 $message = 'Create a GitHub OAuth token to go over the API rate limit.';
46839 }
46840
46841 $message = sprintf(
46842 '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.',
46843 $rateLimit['limit'],
46844 $rateLimit['reset']
46845 )."\n";
46846 } else {
46847 $message .= 'Could not fetch '.$this->fileUrl.', please ';
46848 if ($this->io->hasAuthentication($this->originUrl)) {
46849 $message .= 'review your configured GitHub OAuth token or enter a new one to access private repos';
46850 } else {
46851 $message .= 'create a GitHub OAuth token to access private repos';
46852 }
46853 }
46854
46855 if (!$gitHubUtil->authorizeOAuth($this->originUrl)
46856 && (!$this->io->isInteractive() || !$gitHubUtil->authorizeOAuthInteractively($this->originUrl, $message))
46857 ) {
46858 throw new TransportException('Could not authenticate against '.$this->originUrl, 401);
46859 }
46860 } elseif ($this->config && in_array($this->originUrl, $this->config->get('gitlab-domains'), true)) {
46861 $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');
46862 $gitLabUtil = new GitLab($this->io, $this->config, null);
46863
46864 if ($this->io->hasAuthentication($this->originUrl) && ($auth = $this->io->getAuthentication($this->originUrl)) && in_array($auth['password'], array('gitlab-ci-token', 'private-token', 'oauth2'), true)) {
46865 throw new TransportException("Invalid credentials for '" . $this->fileUrl . "', aborting.", $httpStatus);
46866 }
46867
46868 if (!$gitLabUtil->authorizeOAuth($this->originUrl)
46869 && (!$this->io->isInteractive() || !$gitLabUtil->authorizeOAuthInteractively($this->scheme, $this->originUrl, $message))
46870 ) {
46871 throw new TransportException('Could not authenticate against '.$this->originUrl, 401);
46872 }
46873 } elseif ($this->config && ($this->originUrl === 'bitbucket.org' || $this->originUrl === 'api.bitbucket.org')) {
46874 $askForOAuthToken = true;
46875 $this->originUrl = 'bitbucket.org';
46876
46877 if ($this->io->hasAuthentication($this->originUrl)) {
46878 $auth = $this->io->getAuthentication($this->originUrl);
46879 if ($auth['username'] !== 'x-token-auth') {
46880 $bitbucketUtil = new Bitbucket($this->io, $this->config);
46881 $accessToken = $bitbucketUtil->requestToken($this->originUrl, $auth['username'], $auth['password']);
46882 if (!empty($accessToken)) {
46883 $this->io->setAuthentication($this->originUrl, 'x-token-auth', $accessToken);
46884 $askForOAuthToken = false;
46885 }
46886 } else {
46887 throw new TransportException('Could not authenticate against ' . $this->originUrl, 401);
46888 }
46889 }
46890
46891 if ($askForOAuthToken) {
46892 $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');
46893 $bitBucketUtil = new Bitbucket($this->io, $this->config);
46894 if (! $bitBucketUtil->authorizeOAuth($this->originUrl)
46895 && (! $this->io->isInteractive() || !$bitBucketUtil->authorizeOAuthInteractively($this->originUrl, $message))
46896 ) {
46897 throw new TransportException('Could not authenticate against ' . $this->originUrl, 401);
46898 }
46899 }
46900 } else {
46901
46902 if ($httpStatus === 404) {
46903 return;
46904 }
46905
46906
46907 if (!$this->io->isInteractive()) {
46908 if ($httpStatus === 401) {
46909 $message = "The '" . $this->fileUrl . "' URL required authentication.\nYou must be using the interactive console to authenticate";
46910 }
46911 if ($httpStatus === 403) {
46912 $message = "The '" . $this->fileUrl . "' URL could not be accessed: " . $reason;
46913 }
46914
46915 throw new TransportException($message, $httpStatus);
46916 }
46917
46918 if ($this->io->hasAuthentication($this->originUrl)) {
46919 throw new TransportException("Invalid credentials for '" . $this->fileUrl . "', aborting.", $httpStatus);
46920 }
46921
46922 $this->io->writeError('    Authentication required (<info>'.$this->originUrl.'</info>):');
46923 $username = $this->io->ask('      Username: ');
46924 $password = $this->io->askAndHideAnswer('      Password: ');
46925 $this->io->setAuthentication($this->originUrl, $username, $password);
46926 $this->storeAuth = $this->config->get('store-auths');
46927 }
46928
46929 $this->retry = true;
46930 throw new TransportException('RETRY');
46931 }
46932
46933 protected function getOptionsForUrl($originUrl, $additionalOptions)
46934 {
46935 $tlsOptions = array();
46936
46937
46938 if ($this->disableTls === false && PHP_VERSION_ID < 50600 && !stream_is_local($this->fileUrl)) {
46939 $host = parse_url($this->fileUrl, PHP_URL_HOST);
46940
46941 if (PHP_VERSION_ID < 50304) {
46942
46943
46944
46945
46946
46947 if ($host === 'github.com' || $host === 'api.github.com') {
46948 $host = '*.github.com';
46949 }
46950 }
46951
46952 $tlsOptions['ssl']['CN_match'] = $host;
46953 $tlsOptions['ssl']['SNI_server_name'] = $host;
46954
46955 $urlAuthority = $this->getUrlAuthority($this->fileUrl);
46956
46957 if (isset($this->peerCertificateMap[$urlAuthority])) {
46958
46959 $certMap = $this->peerCertificateMap[$urlAuthority];
46960
46961 $this->io->writeError('', true, IOInterface::DEBUG);
46962 $this->io->writeError(sprintf(
46963 'Using <info>%s</info> as CN for subjectAltName enabled host <info>%s</info>',
46964 $certMap['cn'],
46965 $urlAuthority
46966 ), true, IOInterface::DEBUG);
46967
46968 $tlsOptions['ssl']['CN_match'] = $certMap['cn'];
46969 $tlsOptions['ssl']['peer_fingerprint'] = $certMap['fp'];
46970 } elseif (!CaBundle::isOpensslParseSafe() && $host === 'repo.packagist.org') {
46971
46972 $tlsOptions['ssl']['CN_match'] = 'packagist.org';
46973 }
46974 }
46975
46976 $headers = array();
46977
46978 if (extension_loaded('zlib')) {
46979 $headers[] = 'Accept-Encoding: gzip';
46980 }
46981
46982 $options = array_replace_recursive($this->options, $tlsOptions, $additionalOptions);
46983 if (!$this->degradedMode) {
46984
46985
46986 $options['http']['protocol_version'] = 1.1;
46987 $headers[] = 'Connection: close';
46988 }
46989
46990 if ($this->io->hasAuthentication($originUrl)) {
46991 $authenticationDisplayMessage = null;
46992 $auth = $this->io->getAuthentication($originUrl);
46993 if ($auth['password'] === 'bearer') {
46994 $headers[] = 'Authorization: Bearer '.$auth['username'];
46995 } elseif ('github.com' === $originUrl && 'x-oauth-basic' === $auth['password']) {
46996 $options['github-token'] = $auth['username'];
46997 $authenticationDisplayMessage = 'Using GitHub token authentication';
46998 } elseif ($this->config && in_array($originUrl, $this->config->get('gitlab-domains'), true)) {
46999 if ($auth['password'] === 'oauth2') {
47000 $headers[] = 'Authorization: Bearer '.$auth['username'];
47001 $authenticationDisplayMessage = 'Using GitLab OAuth token authentication';
47002 } elseif ($auth['password'] === 'private-token' || $auth['password'] === 'gitlab-ci-token') {
47003 $headers[] = 'PRIVATE-TOKEN: '.$auth['username'];
47004 $authenticationDisplayMessage = 'Using GitLab private token authentication';
47005 }
47006 } elseif ('bitbucket.org' === $originUrl
47007 && $this->fileUrl !== Bitbucket::OAUTH2_ACCESS_TOKEN_URL && 'x-token-auth' === $auth['username']
47008 ) {
47009 if (!$this->isPublicBitBucketDownload($this->fileUrl)) {
47010 $headers[] = 'Authorization: Bearer ' . $auth['password'];
47011 $authenticationDisplayMessage = 'Using Bitbucket OAuth token authentication';
47012 }
47013 } else {
47014 $authStr = base64_encode($auth['username'] . ':' . $auth['password']);
47015 $headers[] = 'Authorization: Basic '.$authStr;
47016 $authenticationDisplayMessage = 'Using HTTP basic authentication with username "' . $auth['username'] . '"';
47017 }
47018
47019 if ($authenticationDisplayMessage && !in_array($originUrl, $this->displayedOriginAuthentications, true)) {
47020 $this->io->writeError($authenticationDisplayMessage, true, IOInterface::DEBUG);
47021 $this->displayedOriginAuthentications[] = $originUrl;
47022 }
47023 }
47024
47025 $options['http']['follow_location'] = 0;
47026
47027 if (isset($options['http']['header']) && !is_array($options['http']['header'])) {
47028 $options['http']['header'] = explode("\r\n", trim($options['http']['header'], "\r\n"));
47029 }
47030 foreach ($headers as $header) {
47031 $options['http']['header'][] = $header;
47032 }
47033
47034 return $options;
47035 }
47036
47037 private function handleRedirect(array $http_response_header, array $additionalOptions, $result)
47038 {
47039 if ($locationHeader = $this->findHeaderValue($http_response_header, 'location')) {
47040 if (parse_url($locationHeader, PHP_URL_SCHEME)) {
47041
47042 $targetUrl = $locationHeader;
47043 } elseif (parse_url($locationHeader, PHP_URL_HOST)) {
47044
47045 $targetUrl = $this->scheme.':'.$locationHeader;
47046 } elseif ('/' === $locationHeader[0]) {
47047
47048 $urlHost = parse_url($this->fileUrl, PHP_URL_HOST);
47049
47050
47051 $targetUrl = preg_replace('{^(.+(?://|@)'.preg_quote($urlHost).'(?::\d+)?)(?:[/\?].*)?$}', '\1'.$locationHeader, $this->fileUrl);
47052 } else {
47053
47054
47055 $targetUrl = preg_replace('{^(.+/)[^/?]*(?:\?.*)?$}', '\1'.$locationHeader, $this->fileUrl);
47056 }
47057 }
47058
47059 if (!empty($targetUrl)) {
47060 $this->redirects++;
47061
47062 $this->io->writeError('', true, IOInterface::DEBUG);
47063 $this->io->writeError(sprintf('Following redirect (%u) %s', $this->redirects, $this->stripCredentialsFromUrl($targetUrl)), true, IOInterface::DEBUG);
47064
47065 $additionalOptions['redirects'] = $this->redirects;
47066
47067 return $this->get(parse_url($targetUrl, PHP_URL_HOST), $targetUrl, $additionalOptions, $this->fileName, $this->progress);
47068 }
47069
47070 if (!$this->retry) {
47071 $e = new TransportException('The "'.$this->fileUrl.'" file could not be downloaded, got redirect without Location ('.$http_response_header[0].')');
47072 $e->setHeaders($http_response_header);
47073 $e->setResponse($result);
47074
47075 throw $e;
47076 }
47077
47078 return false;
47079 }
47080
47081
47082
47083
47084
47085
47086 private function getTlsDefaults(array $options)
47087 {
47088 $ciphers = implode(':', array(
47089 'ECDHE-RSA-AES128-GCM-SHA256',
47090 'ECDHE-ECDSA-AES128-GCM-SHA256',
47091 'ECDHE-RSA-AES256-GCM-SHA384',
47092 'ECDHE-ECDSA-AES256-GCM-SHA384',
47093 'DHE-RSA-AES128-GCM-SHA256',
47094 'DHE-DSS-AES128-GCM-SHA256',
47095 'kEDH+AESGCM',
47096 'ECDHE-RSA-AES128-SHA256',
47097 'ECDHE-ECDSA-AES128-SHA256',
47098 'ECDHE-RSA-AES128-SHA',
47099 'ECDHE-ECDSA-AES128-SHA',
47100 'ECDHE-RSA-AES256-SHA384',
47101 'ECDHE-ECDSA-AES256-SHA384',
47102 'ECDHE-RSA-AES256-SHA',
47103 'ECDHE-ECDSA-AES256-SHA',
47104 'DHE-RSA-AES128-SHA256',
47105 'DHE-RSA-AES128-SHA',
47106 'DHE-DSS-AES128-SHA256',
47107 'DHE-RSA-AES256-SHA256',
47108 'DHE-DSS-AES256-SHA',
47109 'DHE-RSA-AES256-SHA',
47110 'AES128-GCM-SHA256',
47111 'AES256-GCM-SHA384',
47112 'AES128-SHA256',
47113 'AES256-SHA256',
47114 'AES128-SHA',
47115 'AES256-SHA',
47116 'AES',
47117 'CAMELLIA',
47118 'DES-CBC3-SHA',
47119 '!aNULL',
47120 '!eNULL',
47121 '!EXPORT',
47122 '!DES',
47123 '!RC4',
47124 '!MD5',
47125 '!PSK',
47126 '!aECDH',
47127 '!EDH-DSS-DES-CBC3-SHA',
47128 '!EDH-RSA-DES-CBC3-SHA',
47129 '!KRB5-DES-CBC3-SHA',
47130 ));
47131
47132
47133
47134
47135
47136
47137
47138 $defaults = array(
47139 'ssl' => array(
47140 'ciphers' => $ciphers,
47141 'verify_peer' => true,
47142 'verify_depth' => 7,
47143 'SNI_enabled' => true,
47144 'capture_peer_cert' => true,
47145 ),
47146 );
47147
47148 if (isset($options['ssl'])) {
47149 $defaults['ssl'] = array_replace_recursive($defaults['ssl'], $options['ssl']);
47150 }
47151
47152 $caBundleLogger = $this->io instanceof LoggerInterface ? $this->io : null;
47153
47154
47155
47156
47157
47158 if (!isset($defaults['ssl']['cafile']) && !isset($defaults['ssl']['capath'])) {
47159 $result = CaBundle::getSystemCaRootBundlePath($caBundleLogger);
47160
47161 if (is_dir($result)) {
47162 $defaults['ssl']['capath'] = $result;
47163 } else {
47164 $defaults['ssl']['cafile'] = $result;
47165 }
47166 }
47167
47168 if (isset($defaults['ssl']['cafile']) && (!is_readable($defaults['ssl']['cafile']) || !CaBundle::validateCaFile($defaults['ssl']['cafile'], $caBundleLogger))) {
47169 throw new TransportException('The configured cafile was not valid or could not be read.');
47170 }
47171
47172 if (isset($defaults['ssl']['capath']) && (!is_dir($defaults['ssl']['capath']) || !is_readable($defaults['ssl']['capath']))) {
47173 throw new TransportException('The configured capath was not valid or could not be read.');
47174 }
47175
47176
47177
47178
47179 if (PHP_VERSION_ID >= 50413) {
47180 $defaults['ssl']['disable_compression'] = true;
47181 }
47182
47183 return $defaults;
47184 }
47185
47186
47187
47188
47189
47190
47191 private function getCertificateCnAndFp($url, $options)
47192 {
47193 if (PHP_VERSION_ID >= 50600) {
47194 throw new \BadMethodCallException(sprintf(
47195 '%s must not be used on PHP >= 5.6',
47196 __METHOD__
47197 ));
47198 }
47199
47200 $context = StreamContextFactory::getContext($url, $options, array('options' => array(
47201 'ssl' => array(
47202 'capture_peer_cert' => true,
47203 'verify_peer' => false, 
47204 ), ),
47205 ));
47206
47207
47208
47209 if (false === $handle = @fopen($url, 'rb', false, $context)) {
47210 return;
47211 }
47212
47213
47214 fclose($handle);
47215 $handle = null;
47216
47217 $params = stream_context_get_params($context);
47218
47219 if (!empty($params['options']['ssl']['peer_certificate'])) {
47220 $peerCertificate = $params['options']['ssl']['peer_certificate'];
47221
47222 if (TlsHelper::checkCertificateHost($peerCertificate, parse_url($url, PHP_URL_HOST), $commonName)) {
47223 return array(
47224 'cn' => $commonName,
47225 'fp' => TlsHelper::getCertificateFingerprint($peerCertificate),
47226 );
47227 }
47228 }
47229 }
47230
47231 private function getUrlAuthority($url)
47232 {
47233 $defaultPorts = array(
47234 'ftp' => 21,
47235 'http' => 80,
47236 'https' => 443,
47237 'ssh2.sftp' => 22,
47238 'ssh2.scp' => 22,
47239 );
47240
47241 $scheme = parse_url($url, PHP_URL_SCHEME);
47242
47243 if (!isset($defaultPorts[$scheme])) {
47244 throw new \InvalidArgumentException(sprintf(
47245 'Could not get default port for unknown scheme: %s',
47246 $scheme
47247 ));
47248 }
47249
47250 $defaultPort = $defaultPorts[$scheme];
47251 $port = parse_url($url, PHP_URL_PORT) ?: $defaultPort;
47252
47253 return parse_url($url, PHP_URL_HOST).':'.$port;
47254 }
47255
47256
47257
47258
47259
47260
47261
47262
47263 private function isPublicBitBucketDownload($urlToBitBucketFile)
47264 {
47265 $domain = parse_url($urlToBitBucketFile, PHP_URL_HOST);
47266 if (strpos($domain, 'bitbucket.org') === false) {
47267
47268
47269 return true;
47270 }
47271
47272 $path = parse_url($urlToBitBucketFile, PHP_URL_PATH);
47273
47274
47275
47276 $pathParts = explode('/', $path);
47277
47278 return count($pathParts) >= 4 && $pathParts[3] == 'downloads';
47279 }
47280
47281 public static function outputWarnings(IOInterface $io, $url, $data)
47282 {
47283 foreach (array('warning', 'info') as $type) {
47284 if (empty($data[$type])) {
47285 continue;
47286 }
47287
47288 if (!empty($data[$type . '-versions'])) {
47289 $versionParser = new VersionParser();
47290 $constraint = $versionParser->parseConstraints($data[$type . '-versions']);
47291 $composer = new Constraint('==', $versionParser->normalize(Composer::getVersion()));
47292 if (!$constraint->matches($composer)) {
47293 continue;
47294 }
47295 }
47296
47297 $io->writeError('<'.$type.'>'.ucfirst($type).' from '.$url.': '.$data[$type].'</'.$type.'>');
47298 }
47299 }
47300
47301 public static function getOrigin($urlOrPath)
47302 {
47303 $hostPort = parse_url($urlOrPath, PHP_URL_HOST);
47304 if (!$hostPort) {
47305 return $urlOrPath;
47306 }
47307 if (parse_url($urlOrPath, PHP_URL_PORT)) {
47308 $hostPort .= ':'.parse_url($urlOrPath, PHP_URL_PORT);
47309 }
47310
47311 return $hostPort;
47312 }
47313
47314 private function stripCredentialsFromUrl($url)
47315 {
47316
47317
47318 return preg_replace('{([&?]access_token=)[^&]+}', '$1***', $url);
47319 }
47320 }
47321 <?php
47322
47323
47324
47325
47326
47327
47328
47329
47330
47331
47332
47333 namespace Composer\Util;
47334
47335
47336
47337
47338
47339
47340 class Silencer
47341 {
47342
47343
47344
47345 private static $stack = array();
47346
47347
47348
47349
47350
47351
47352
47353 public static function suppress($mask = null)
47354 {
47355 if (!isset($mask)) {
47356 $mask = E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE | E_DEPRECATED | E_USER_DEPRECATED | E_STRICT;
47357 }
47358 $old = error_reporting();
47359 self::$stack[] = $old;
47360 error_reporting($old & ~$mask);
47361
47362 return $old;
47363 }
47364
47365
47366
47367
47368 public static function restore()
47369 {
47370 if (!empty(self::$stack)) {
47371 error_reporting(array_pop(self::$stack));
47372 }
47373 }
47374
47375
47376
47377
47378
47379
47380
47381
47382
47383
47384 public static function call($callable )
47385 {
47386 try {
47387 self::suppress();
47388 $result = call_user_func_array($callable, array_slice(func_get_args(), 1));
47389 self::restore();
47390
47391 return $result;
47392 } catch (\Exception $e) {
47393
47394 self::restore();
47395 throw $e;
47396 }
47397 }
47398 }
47399 <?php
47400
47401
47402
47403
47404
47405
47406
47407
47408
47409
47410
47411 namespace Composer\Util;
47412
47413 use Composer\Spdx\SpdxLicenses;
47414
47415 trigger_error('The ' . __NAMESPACE__ . '\SpdxLicense class is deprecated, use Composer\Spdx\SpdxLicenses instead.', E_USER_DEPRECATED);
47416
47417
47418
47419
47420 class SpdxLicense extends SpdxLicenses
47421 {
47422 }
47423 <?php
47424
47425
47426
47427
47428
47429
47430
47431
47432
47433
47434
47435 namespace Composer\Util;
47436
47437 use Composer\Composer;
47438
47439
47440
47441
47442
47443
47444
47445 final class StreamContextFactory
47446 {
47447
47448
47449
47450
47451
47452
47453
47454
47455
47456 public static function getContext($url, array $defaultOptions = array(), array $defaultParams = array())
47457 {
47458 $options = array('http' => array(
47459
47460 'follow_location' => 1,
47461 'max_redirects' => 20,
47462 ));
47463
47464
47465 if ((PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') && (!empty($_SERVER['HTTP_PROXY']) || !empty($_SERVER['http_proxy']))) {
47466 $proxy = parse_url(!empty($_SERVER['http_proxy']) ? $_SERVER['http_proxy'] : $_SERVER['HTTP_PROXY']);
47467 }
47468
47469
47470 if (!empty($_SERVER['CGI_HTTP_PROXY'])) {
47471 $proxy = parse_url($_SERVER['CGI_HTTP_PROXY']);
47472 }
47473
47474
47475 if (preg_match('{^https://}i', $url) && (!empty($_SERVER['HTTPS_PROXY']) || !empty($_SERVER['https_proxy']))) {
47476 $proxy = parse_url(!empty($_SERVER['https_proxy']) ? $_SERVER['https_proxy'] : $_SERVER['HTTPS_PROXY']);
47477 }
47478
47479
47480 if (!empty($_SERVER['NO_PROXY']) || !empty($_SERVER['no_proxy']) && parse_url($url, PHP_URL_HOST)) {
47481 $pattern = new NoProxyPattern(!empty($_SERVER['no_proxy']) ? $_SERVER['no_proxy'] : $_SERVER['NO_PROXY']);
47482 if ($pattern->test($url)) {
47483 unset($proxy);
47484 }
47485 }
47486
47487 if (!empty($proxy)) {
47488 $proxyURL = isset($proxy['scheme']) ? $proxy['scheme'] . '://' : '';
47489 $proxyURL .= isset($proxy['host']) ? $proxy['host'] : '';
47490
47491 if (isset($proxy['port'])) {
47492 $proxyURL .= ":" . $proxy['port'];
47493 } elseif ('http://' == substr($proxyURL, 0, 7)) {
47494 $proxyURL .= ":80";
47495 } elseif ('https://' == substr($proxyURL, 0, 8)) {
47496 $proxyURL .= ":443";
47497 }
47498
47499
47500 $proxyURL = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $proxyURL);
47501
47502 if (0 === strpos($proxyURL, 'ssl:') && !extension_loaded('openssl')) {
47503 throw new \RuntimeException('You must enable the openssl extension to use a proxy over https');
47504 }
47505
47506 $options['http']['proxy'] = $proxyURL;
47507
47508
47509 switch (parse_url($url, PHP_URL_SCHEME)) {
47510 case 'http': 
47511 $reqFullUriEnv = getenv('HTTP_PROXY_REQUEST_FULLURI');
47512 if ($reqFullUriEnv === false || $reqFullUriEnv === '' || (strtolower($reqFullUriEnv) !== 'false' && (bool) $reqFullUriEnv)) {
47513 $options['http']['request_fulluri'] = true;
47514 }
47515 break;
47516 case 'https': 
47517 $reqFullUriEnv = getenv('HTTPS_PROXY_REQUEST_FULLURI');
47518 if ($reqFullUriEnv === false || $reqFullUriEnv === '' || (strtolower($reqFullUriEnv) !== 'false' && (bool) $reqFullUriEnv)) {
47519 $options['http']['request_fulluri'] = true;
47520 }
47521 break;
47522 }
47523
47524
47525 if ('https' === parse_url($url, PHP_URL_SCHEME)) {
47526 $options['ssl']['SNI_enabled'] = true;
47527 if (PHP_VERSION_ID < 50600) {
47528 $options['ssl']['SNI_server_name'] = parse_url($url, PHP_URL_HOST);
47529 }
47530 }
47531
47532
47533 if (isset($proxy['user'])) {
47534 $auth = rawurldecode($proxy['user']);
47535 if (isset($proxy['pass'])) {
47536 $auth .= ':' . rawurldecode($proxy['pass']);
47537 }
47538 $auth = base64_encode($auth);
47539
47540
47541 if (isset($defaultOptions['http']['header'])) {
47542 if (is_string($defaultOptions['http']['header'])) {
47543 $defaultOptions['http']['header'] = array($defaultOptions['http']['header']);
47544 }
47545 $defaultOptions['http']['header'][] = "Proxy-Authorization: Basic {$auth}";
47546 } else {
47547 $options['http']['header'] = array("Proxy-Authorization: Basic {$auth}");
47548 }
47549 }
47550 }
47551
47552 $options = array_replace_recursive($options, $defaultOptions);
47553
47554 if (isset($options['http']['header'])) {
47555 $options['http']['header'] = self::fixHttpHeaderField($options['http']['header']);
47556 }
47557
47558 if (defined('HHVM_VERSION')) {
47559 $phpVersion = 'HHVM ' . HHVM_VERSION;
47560 } else {
47561 $phpVersion = 'PHP ' . PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION;
47562 }
47563
47564 if (!isset($options['http']['header']) || false === stripos(implode('', $options['http']['header']), 'user-agent')) {
47565 $options['http']['header'][] = sprintf(
47566 'User-Agent: Composer/%s (%s; %s; %s%s)',
47567 Composer::getVersion(),
47568 function_exists('php_uname') ? php_uname('s') : 'Unknown',
47569 function_exists('php_uname') ? php_uname('r') : 'Unknown',
47570 $phpVersion,
47571 getenv('CI') ? '; CI' : ''
47572 );
47573 }
47574
47575 return stream_context_create($options, $defaultParams);
47576 }
47577
47578
47579
47580
47581
47582
47583
47584
47585
47586
47587
47588 private static function fixHttpHeaderField($header)
47589 {
47590 if (!is_array($header)) {
47591 $header = explode("\r\n", $header);
47592 }
47593 uasort($header, function ($el) {
47594 return stripos($el, 'content-type') === 0 ? 1 : -1;
47595 });
47596
47597 return $header;
47598 }
47599 }
47600 <?php
47601
47602
47603
47604
47605
47606
47607
47608
47609
47610
47611
47612 namespace Composer\Util;
47613
47614 use Composer\Config;
47615 use Composer\IO\IOInterface;
47616
47617
47618
47619
47620
47621 class Svn
47622 {
47623 const MAX_QTY_AUTH_TRIES = 5;
47624
47625
47626
47627
47628 protected $credentials;
47629
47630
47631
47632
47633 protected $hasAuth;
47634
47635
47636
47637
47638 protected $io;
47639
47640
47641
47642
47643 protected $url;
47644
47645
47646
47647
47648 protected $cacheCredentials = true;
47649
47650
47651
47652
47653 protected $process;
47654
47655
47656
47657
47658 protected $qtyAuthTries = 0;
47659
47660
47661
47662
47663 protected $config;
47664
47665
47666
47667
47668 private static $version;
47669
47670
47671
47672
47673
47674
47675
47676 public function __construct($url, IOInterface $io, Config $config, ProcessExecutor $process = null)
47677 {
47678 $this->url = $url;
47679 $this->io = $io;
47680 $this->config = $config;
47681 $this->process = $process ?: new ProcessExecutor($io);
47682 }
47683
47684 public static function cleanEnv()
47685 {
47686
47687 putenv("DYLD_LIBRARY_PATH");
47688 unset($_SERVER['DYLD_LIBRARY_PATH']);
47689 }
47690
47691
47692
47693
47694
47695
47696
47697
47698
47699
47700
47701
47702
47703
47704 public function execute($command, $url, $cwd = null, $path = null, $verbose = false)
47705 {
47706
47707 $this->config->prohibitUrlByConfig($url, $this->io);
47708
47709 return $this->executeWithAuthRetry($command, $cwd, $url, $path, $verbose);
47710 }
47711
47712
47713
47714
47715
47716
47717
47718
47719
47720
47721
47722
47723
47724 public function executeLocal($command, $path, $cwd = null, $verbose = false)
47725 {
47726
47727 return $this->executeWithAuthRetry($command, $cwd, '', $path, $verbose);
47728 }
47729
47730 private function executeWithAuthRetry($svnCommand, $cwd, $url, $path, $verbose)
47731 {
47732
47733 $command = $this->getCommand($svnCommand, $url, $path);
47734
47735 $output = null;
47736 $io = $this->io;
47737 $handler = function ($type, $buffer) use (&$output, $io, $verbose) {
47738 if ($type !== 'out') {
47739 return;
47740 }
47741 if ('Redirecting to URL ' === substr($buffer, 0, 19)) {
47742 return;
47743 }
47744 $output .= $buffer;
47745 if ($verbose) {
47746 $io->writeError($buffer, false);
47747 }
47748 };
47749 $status = $this->process->execute($command, $handler, $cwd);
47750 if (0 === $status) {
47751 return $output;
47752 }
47753
47754 $errorOutput = $this->process->getErrorOutput();
47755 $fullOutput = implode("\n", array($output, $errorOutput));
47756
47757
47758 if (false === stripos($fullOutput, 'Could not authenticate to server:')
47759 && false === stripos($fullOutput, 'authorization failed')
47760 && false === stripos($fullOutput, 'svn: E170001:')
47761 && false === stripos($fullOutput, 'svn: E215004:')) {
47762 throw new \RuntimeException($fullOutput);
47763 }
47764
47765 if (!$this->hasAuth()) {
47766 $this->doAuthDance();
47767 }
47768
47769
47770 if ($this->qtyAuthTries++ < self::MAX_QTY_AUTH_TRIES) {
47771
47772 return $this->executeWithAuthRetry($svnCommand, $cwd, $url, $path, $verbose);
47773 }
47774
47775 throw new \RuntimeException(
47776 'wrong credentials provided ('.$fullOutput.')'
47777 );
47778 }
47779
47780
47781
47782
47783 public function setCacheCredentials($cacheCredentials)
47784 {
47785 $this->cacheCredentials = $cacheCredentials;
47786 }
47787
47788
47789
47790
47791
47792
47793
47794 protected function doAuthDance()
47795 {
47796
47797 if (!$this->io->isInteractive()) {
47798 throw new \RuntimeException(
47799 'can not ask for authentication in non interactive mode'
47800 );
47801 }
47802
47803 $this->io->writeError("The Subversion server ({$this->url}) requested credentials:");
47804
47805 $this->hasAuth = true;
47806 $this->credentials['username'] = $this->io->ask("Username: ");
47807 $this->credentials['password'] = $this->io->askAndHideAnswer("Password: ");
47808
47809 $this->cacheCredentials = $this->io->askConfirmation("Should Subversion cache these credentials? (yes/no) ", true);
47810
47811 return $this;
47812 }
47813
47814
47815
47816
47817
47818
47819
47820
47821
47822
47823 protected function getCommand($cmd, $url, $path = null)
47824 {
47825 $cmd = sprintf(
47826 '%s %s%s -- %s',
47827 $cmd,
47828 '--non-interactive ',
47829 $this->getCredentialString(),
47830 ProcessExecutor::escape($url)
47831 );
47832
47833 if ($path) {
47834 $cmd .= ' ' . ProcessExecutor::escape($path);
47835 }
47836
47837 return $cmd;
47838 }
47839
47840
47841
47842
47843
47844
47845
47846
47847 protected function getCredentialString()
47848 {
47849 if (!$this->hasAuth()) {
47850 return '';
47851 }
47852
47853 return sprintf(
47854 ' %s--username %s --password %s ',
47855 $this->getAuthCache(),
47856 ProcessExecutor::escape($this->getUsername()),
47857 ProcessExecutor::escape($this->getPassword())
47858 );
47859 }
47860
47861
47862
47863
47864
47865
47866
47867 protected function getPassword()
47868 {
47869 if ($this->credentials === null) {
47870 throw new \LogicException("No svn auth detected.");
47871 }
47872
47873 return isset($this->credentials['password']) ? $this->credentials['password'] : '';
47874 }
47875
47876
47877
47878
47879
47880
47881
47882 protected function getUsername()
47883 {
47884 if ($this->credentials === null) {
47885 throw new \LogicException("No svn auth detected.");
47886 }
47887
47888 return $this->credentials['username'];
47889 }
47890
47891
47892
47893
47894
47895
47896 protected function hasAuth()
47897 {
47898 if (null !== $this->hasAuth) {
47899 return $this->hasAuth;
47900 }
47901
47902 if (false === $this->createAuthFromConfig()) {
47903 $this->createAuthFromUrl();
47904 }
47905
47906 return $this->hasAuth;
47907 }
47908
47909
47910
47911
47912
47913
47914 protected function getAuthCache()
47915 {
47916 return $this->cacheCredentials ? '' : '--no-auth-cache ';
47917 }
47918
47919
47920
47921
47922
47923
47924 private function createAuthFromConfig()
47925 {
47926 if (!$this->config->has('http-basic')) {
47927 return $this->hasAuth = false;
47928 }
47929
47930 $authConfig = $this->config->get('http-basic');
47931
47932 $host = parse_url($this->url, PHP_URL_HOST);
47933 if (isset($authConfig[$host])) {
47934 $this->credentials['username'] = $authConfig[$host]['username'];
47935 $this->credentials['password'] = $authConfig[$host]['password'];
47936
47937 return $this->hasAuth = true;
47938 }
47939
47940 return $this->hasAuth = false;
47941 }
47942
47943
47944
47945
47946
47947
47948 private function createAuthFromUrl()
47949 {
47950 $uri = parse_url($this->url);
47951 if (empty($uri['user'])) {
47952 return $this->hasAuth = false;
47953 }
47954
47955 $this->credentials['username'] = $uri['user'];
47956 if (!empty($uri['pass'])) {
47957 $this->credentials['password'] = $uri['pass'];
47958 }
47959
47960 return $this->hasAuth = true;
47961 }
47962
47963
47964
47965
47966
47967
47968 public function binaryVersion()
47969 {
47970 if (!self::$version) {
47971 if (0 === $this->process->execute('svn --version', $output)) {
47972 if (preg_match('{(\d+(?:\.\d+)+)}', $output, $match)) {
47973 self::$version = $match[1];
47974 }
47975 }
47976 }
47977
47978 return self::$version;
47979 }
47980 }
47981 <?php
47982
47983
47984
47985
47986
47987
47988
47989
47990
47991
47992
47993 namespace Composer\Util;
47994
47995 use Composer\CaBundle\CaBundle;
47996
47997
47998
47999
48000 final class TlsHelper
48001 {
48002
48003
48004
48005
48006
48007
48008
48009
48010
48011 public static function checkCertificateHost($certificate, $hostname, &$cn = null)
48012 {
48013 $names = self::getCertificateNames($certificate);
48014
48015 if (empty($names)) {
48016 return false;
48017 }
48018
48019 $combinedNames = array_merge($names['san'], array($names['cn']));
48020 $hostname = strtolower($hostname);
48021
48022 foreach ($combinedNames as $certName) {
48023 $matcher = self::certNameMatcher($certName);
48024
48025 if ($matcher && $matcher($hostname)) {
48026 $cn = $names['cn'];
48027
48028 return true;
48029 }
48030 }
48031
48032 return false;
48033 }
48034
48035
48036
48037
48038
48039
48040
48041
48042 public static function getCertificateNames($certificate)
48043 {
48044 if (is_array($certificate)) {
48045 $info = $certificate;
48046 } elseif (CaBundle::isOpensslParseSafe()) {
48047 $info = openssl_x509_parse($certificate, false);
48048 }
48049
48050 if (!isset($info['subject']['commonName'])) {
48051 return null;
48052 }
48053
48054 $commonName = strtolower($info['subject']['commonName']);
48055 $subjectAltNames = array();
48056
48057 if (isset($info['extensions']['subjectAltName'])) {
48058 $subjectAltNames = preg_split('{\s*,\s*}', $info['extensions']['subjectAltName']);
48059 $subjectAltNames = array_filter(array_map(function ($name) {
48060 if (0 === strpos($name, 'DNS:')) {
48061 return strtolower(ltrim(substr($name, 4)));
48062 }
48063
48064 return null;
48065 }, $subjectAltNames));
48066 $subjectAltNames = array_values($subjectAltNames);
48067 }
48068
48069 return array(
48070 'cn' => $commonName,
48071 'san' => $subjectAltNames,
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
48105
48106
48107
48108
48109
48110
48111
48112
48113
48114 public static function getCertificateFingerprint($certificate)
48115 {
48116 $pubkeydetails = openssl_pkey_get_details(openssl_get_publickey($certificate));
48117 $pubkeypem = $pubkeydetails['key'];
48118
48119 $start = '-----BEGIN PUBLIC KEY-----';
48120 $end = '-----END PUBLIC KEY-----';
48121 $pemtrim = substr($pubkeypem, strpos($pubkeypem, $start) + strlen($start), (strlen($pubkeypem) - strpos($pubkeypem, $end)) * (-1));
48122 $der = base64_decode($pemtrim);
48123
48124 return sha1($der);
48125 }
48126
48127
48128
48129
48130
48131
48132
48133
48134
48135 public static function isOpensslParseSafe()
48136 {
48137 return CaBundle::isOpensslParseSafe();
48138 }
48139
48140
48141
48142
48143
48144
48145
48146
48147 private static function certNameMatcher($certName)
48148 {
48149 $wildcards = substr_count($certName, '*');
48150
48151 if (0 === $wildcards) {
48152
48153 return function ($hostname) use ($certName) {
48154 return $hostname === $certName;
48155 };
48156 }
48157
48158 if (1 === $wildcards) {
48159 $components = explode('.', $certName);
48160
48161 if (3 > count($components)) {
48162
48163 return;
48164 }
48165
48166 $firstComponent = $components[0];
48167
48168
48169 if ('*' !== $firstComponent[strlen($firstComponent) - 1]) {
48170 return;
48171 }
48172
48173 $wildcardRegex = preg_quote($certName);
48174 $wildcardRegex = str_replace('\\*', '[a-z0-9-]+', $wildcardRegex);
48175 $wildcardRegex = "{^{$wildcardRegex}$}";
48176
48177 return function ($hostname) use ($wildcardRegex) {
48178 return 1 === preg_match($wildcardRegex, $hostname);
48179 };
48180 }
48181 }
48182 }
48183 <?php
48184
48185
48186
48187
48188
48189
48190
48191
48192
48193
48194
48195 namespace Composer\Util;
48196
48197 use Composer\Config;
48198
48199
48200
48201
48202 class Url
48203 {
48204 public static function updateDistReference(Config $config, $url, $ref)
48205 {
48206 $host = parse_url($url, PHP_URL_HOST);
48207
48208 if ($host === 'api.github.com' || $host === 'github.com' || $host === 'www.github.com') {
48209 if (preg_match('{^https?://(?:www\.)?github\.com/([^/]+)/([^/]+)/(zip|tar)ball/(.+)$}i', $url, $match)) {
48210
48211 $url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $ref;
48212 } elseif (preg_match('{^https?://(?:www\.)?github\.com/([^/]+)/([^/]+)/archive/.+\.(zip|tar)(?:\.gz)?$}i', $url, $match)) {
48213
48214 $url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $ref;
48215 } elseif (preg_match('{^https?://api\.github\.com/repos/([^/]+)/([^/]+)/(zip|tar)ball(?:/.+)?$}i', $url, $match)) {
48216
48217 $url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $ref;
48218 }
48219 } elseif ($host === 'bitbucket.org' || $host === 'www.bitbucket.org') {
48220 if (preg_match('{^https?://(?:www\.)?bitbucket\.org/([^/]+)/([^/]+)/get/(.+)\.(zip|tar\.gz|tar\.bz2)$}i', $url, $match)) {
48221
48222 $url = 'https://bitbucket.org/' . $match[1] . '/'. $match[2] . '/get/' . $ref . '.' . $match[4];
48223 }
48224 } elseif ($host === 'gitlab.com' || $host === 'www.gitlab.com') {
48225 if (preg_match('{^https?://(?:www\.)?gitlab\.com/api/v[34]/projects/([^/]+)/repository/archive\.(zip|tar\.gz|tar\.bz2|tar)\?sha=.+$}i', $url, $match)) {
48226
48227 $url = 'https://gitlab.com/api/v4/projects/' . $match[1] . '/repository/archive.' . $match[2] . '?sha=' . $ref;
48228 }
48229 } elseif (in_array($host, $config->get('github-domains'), true)) {
48230 $url = preg_replace('{(/repos/[^/]+/[^/]+/(zip|tar)ball)(?:/.+)?$}i', '$1/'.$ref, $url);
48231 } elseif (in_array($host, $config->get('gitlab-domains'), true)) {
48232 $url = preg_replace('{(/api/v[34]/projects/[^/]+/repository/archive\.(?:zip|tar\.gz|tar\.bz2|tar)\?sha=).+$}i', '${1}'.$ref, $url);
48233 }
48234
48235 return $url;
48236 }
48237 }
48238 <?php
48239
48240
48241
48242
48243
48244
48245
48246
48247
48248
48249
48250 namespace Composer\Util;
48251
48252
48253
48254
48255 class Zip
48256 {
48257
48258
48259
48260
48261
48262
48263
48264 public static function getComposerJson($pathToZip)
48265 {
48266 if (!extension_loaded('zip')) {
48267 throw new \RuntimeException('The Zip Util requires PHP\'s zip extension');
48268 }
48269
48270 $zip = new \ZipArchive();
48271 if ($zip->open($pathToZip) !== true) {
48272 return null;
48273 }
48274
48275 if (0 == $zip->numFiles) {
48276 $zip->close();
48277
48278 return null;
48279 }
48280
48281 $foundFileIndex = self::locateFile($zip, 'composer.json');
48282 if (false === $foundFileIndex) {
48283 $zip->close();
48284
48285 return null;
48286 }
48287
48288 $content = null;
48289 $configurationFileName = $zip->getNameIndex($foundFileIndex);
48290 $stream = $zip->getStream($configurationFileName);
48291
48292 if (false !== $stream) {
48293 $content = stream_get_contents($stream);
48294 }
48295
48296 $zip->close();
48297
48298 return $content;
48299 }
48300
48301
48302
48303
48304
48305
48306
48307
48308
48309 private static function locateFile(\ZipArchive $zip, $filename)
48310 {
48311 $indexOfShortestMatch = false;
48312 $lengthOfShortestMatch = -1;
48313
48314 for ($i = 0; $i < $zip->numFiles; $i++) {
48315 $stat = $zip->statIndex($i);
48316 if (strcmp(basename($stat['name']), $filename) === 0) {
48317 $directoryName = dirname($stat['name']);
48318 if ($directoryName === '.') {
48319
48320
48321 return $i;
48322 }
48323
48324 if (strpos($directoryName, '\\') !== false ||
48325 strpos($directoryName, '/') !== false) {
48326
48327 continue;
48328 }
48329
48330 $length = strlen($stat['name']);
48331 if ($indexOfShortestMatch === false || $length < $lengthOfShortestMatch) {
48332
48333 $contents = $zip->getFromIndex($i);
48334 if ($contents !== false) {
48335 $indexOfShortestMatch = $i;
48336 $lengthOfShortestMatch = $length;
48337 }
48338 }
48339 }
48340 }
48341
48342 return $indexOfShortestMatch;
48343 }
48344 }
48345 <?php
48346
48347
48348
48349
48350
48351
48352
48353
48354
48355
48356
48357 namespace Composer;
48358
48359 use Symfony\Component\Console\Output\OutputInterface;
48360
48361 trigger_error('The ' . __NAMESPACE__ . '\XdebugHandler class is deprecated, use Composer\XdebugHandler\XdebugHandler instead,', E_USER_DEPRECATED);
48362
48363
48364
48365
48366 class XdebugHandler extends XdebugHandler\XdebugHandler
48367 {
48368 const ENV_ALLOW = 'COMPOSER_ALLOW_XDEBUG';
48369 const ENV_VERSION = 'COMPOSER_XDEBUG_VERSION';
48370
48371 public function __construct(OutputInterface $output)
48372 {
48373 parent::__construct('composer', '--ansi');
48374 }
48375 }
48376 <?php
48377
48378
48379
48380
48381
48382
48383
48384
48385
48386
48387
48388 function includeIfExists($file)
48389 {
48390 return file_exists($file) ? include $file : false;
48391 }
48392
48393 if ((!$loader = includeIfExists(__DIR__.'/../vendor/autoload.php')) && (!$loader = includeIfExists(__DIR__.'/../../../autoload.php'))) {
48394 echo 'You must set up the project dependencies using `composer install`'.PHP_EOL.
48395 'See https://getcomposer.org/download/ for instructions on installing Composer'.PHP_EOL;
48396 exit(1);
48397 }
48398
48399 return $loader;
48400 <?php
48401
48402 /*
48403  * This file is part of Composer.
48404  *
48405  * (c) Nils Adermann <naderman@naderman.de>
48406  *     Jordi Boggiano <j.boggiano@seld.be>
48407  *
48408  * For the full copyright and license information, please view the LICENSE
48409  * file that was distributed with this source code.
48410  */
48411
48412 namespace Composer\Autoload;
48413
48414 /**
48415  * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
48416  *
48417  *     $loader = new \Composer\Autoload\ClassLoader();
48418  *
48419  *     // register classes with namespaces
48420  *     $loader->add('Symfony\Component', __DIR__.'/component');
48421  *     $loader->add('Symfony',           __DIR__.'/framework');
48422  *
48423  *     // activate the autoloader
48424  *     $loader->register();
48425  *
48426  *     // to enable searching the include path (eg. for PEAR packages)
48427  *     $loader->setUseIncludePath(true);
48428  *
48429  * In this example, if you try to use a class in the Symfony\Component
48430  * namespace or one of its children (Symfony\Component\Console for instance),
48431  * the autoloader will first look for the class under the component/
48432  * directory, and it will then fallback to the framework/ directory if not
48433  * found before giving up.
48434  *
48435  * This class is loosely based on the Symfony UniversalClassLoader.
48436  *
48437  * @author Fabien Potencier <fabien@symfony.com>
48438  * @author Jordi Boggiano <j.boggiano@seld.be>
48439  * @see    http://www.php-fig.org/psr/psr-0/
48440  * @see    http://www.php-fig.org/psr/psr-4/
48441  */
48442 class ClassLoader
48443 {
48444     // PSR-4
48445     private $prefixLengthsPsr4 = array();
48446     private $prefixDirsPsr4 = array();
48447     private $fallbackDirsPsr4 = array();
48448
48449     // PSR-0
48450     private $prefixesPsr0 = array();
48451     private $fallbackDirsPsr0 = array();
48452
48453     private $useIncludePath = false;
48454     private $classMap = array();
48455     private $classMapAuthoritative = false;
48456     private $missingClasses = array();
48457     private $apcuPrefix;
48458
48459     public function getPrefixes()
48460     {
48461         if (!empty($this->prefixesPsr0)) {
48462             return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
48463         }
48464
48465         return array();
48466     }
48467
48468     public function getPrefixesPsr4()
48469     {
48470         return $this->prefixDirsPsr4;
48471     }
48472
48473     public function getFallbackDirs()
48474     {
48475         return $this->fallbackDirsPsr0;
48476     }
48477
48478     public function getFallbackDirsPsr4()
48479     {
48480         return $this->fallbackDirsPsr4;
48481     }
48482
48483     public function getClassMap()
48484     {
48485         return $this->classMap;
48486     }
48487
48488     /**
48489      * @param array $classMap Class to filename map
48490      */
48491     public function addClassMap(array $classMap)
48492     {
48493         if ($this->classMap) {
48494             $this->classMap = array_merge($this->classMap, $classMap);
48495         } else {
48496             $this->classMap = $classMap;
48497         }
48498     }
48499
48500     /**
48501      * Registers a set of PSR-0 directories for a given prefix, either
48502      * appending or prepending to the ones previously set for this prefix.
48503      *
48504      * @param string       $prefix  The prefix
48505      * @param array|string $paths   The PSR-0 root directories
48506      * @param bool         $prepend Whether to prepend the directories
48507      */
48508     public function add($prefix, $paths, $prepend = false)
48509     {
48510         if (!$prefix) {
48511             if ($prepend) {
48512                 $this->fallbackDirsPsr0 = array_merge(
48513                     (array) $paths,
48514                     $this->fallbackDirsPsr0
48515                 );
48516             } else {
48517                 $this->fallbackDirsPsr0 = array_merge(
48518                     $this->fallbackDirsPsr0,
48519                     (array) $paths
48520                 );
48521             }
48522
48523             return;
48524         }
48525
48526         $first = $prefix[0];
48527         if (!isset($this->prefixesPsr0[$first][$prefix])) {
48528             $this->prefixesPsr0[$first][$prefix] = (array) $paths;
48529
48530             return;
48531         }
48532         if ($prepend) {
48533             $this->prefixesPsr0[$first][$prefix] = array_merge(
48534                 (array) $paths,
48535                 $this->prefixesPsr0[$first][$prefix]
48536             );
48537         } else {
48538             $this->prefixesPsr0[$first][$prefix] = array_merge(
48539                 $this->prefixesPsr0[$first][$prefix],
48540                 (array) $paths
48541             );
48542         }
48543     }
48544
48545     /**
48546      * Registers a set of PSR-4 directories for a given namespace, either
48547      * appending or prepending to the ones previously set for this namespace.
48548      *
48549      * @param string       $prefix  The prefix/namespace, with trailing '\\'
48550      * @param array|string $paths   The PSR-4 base directories
48551      * @param bool         $prepend Whether to prepend the directories
48552      *
48553      * @throws \InvalidArgumentException
48554      */
48555     public function addPsr4($prefix, $paths, $prepend = false)
48556     {
48557         if (!$prefix) {
48558             // Register directories for the root namespace.
48559             if ($prepend) {
48560                 $this->fallbackDirsPsr4 = array_merge(
48561                     (array) $paths,
48562                     $this->fallbackDirsPsr4
48563                 );
48564             } else {
48565                 $this->fallbackDirsPsr4 = array_merge(
48566                     $this->fallbackDirsPsr4,
48567                     (array) $paths
48568                 );
48569             }
48570         } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
48571             // Register directories for a new namespace.
48572             $length = strlen($prefix);
48573             if ('\\' !== $prefix[$length - 1]) {
48574                 throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
48575             }
48576             $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
48577             $this->prefixDirsPsr4[$prefix] = (array) $paths;
48578         } elseif ($prepend) {
48579             // Prepend directories for an already registered namespace.
48580             $this->prefixDirsPsr4[$prefix] = array_merge(
48581                 (array) $paths,
48582                 $this->prefixDirsPsr4[$prefix]
48583             );
48584         } else {
48585             // Append directories for an already registered namespace.
48586             $this->prefixDirsPsr4[$prefix] = array_merge(
48587                 $this->prefixDirsPsr4[$prefix],
48588                 (array) $paths
48589             );
48590         }
48591     }
48592
48593     /**
48594      * Registers a set of PSR-0 directories for a given prefix,
48595      * replacing any others previously set for this prefix.
48596      *
48597      * @param string       $prefix The prefix
48598      * @param array|string $paths  The PSR-0 base directories
48599      */
48600     public function set($prefix, $paths)
48601     {
48602         if (!$prefix) {
48603             $this->fallbackDirsPsr0 = (array) $paths;
48604         } else {
48605             $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
48606         }
48607     }
48608
48609     /**
48610      * Registers a set of PSR-4 directories for a given namespace,
48611      * replacing any others previously set for this namespace.
48612      *
48613      * @param string       $prefix The prefix/namespace, with trailing '\\'
48614      * @param array|string $paths  The PSR-4 base directories
48615      *
48616      * @throws \InvalidArgumentException
48617      */
48618     public function setPsr4($prefix, $paths)
48619     {
48620         if (!$prefix) {
48621             $this->fallbackDirsPsr4 = (array) $paths;
48622         } else {
48623             $length = strlen($prefix);
48624             if ('\\' !== $prefix[$length - 1]) {
48625                 throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
48626             }
48627             $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
48628             $this->prefixDirsPsr4[$prefix] = (array) $paths;
48629         }
48630     }
48631
48632     /**
48633      * Turns on searching the include path for class files.
48634      *
48635      * @param bool $useIncludePath
48636      */
48637     public function setUseIncludePath($useIncludePath)
48638     {
48639         $this->useIncludePath = $useIncludePath;
48640     }
48641
48642     /**
48643      * Can be used to check if the autoloader uses the include path to check
48644      * for classes.
48645      *
48646      * @return bool
48647      */
48648     public function getUseIncludePath()
48649     {
48650         return $this->useIncludePath;
48651     }
48652
48653     /**
48654      * Turns off searching the prefix and fallback directories for classes
48655      * that have not been registered with the class map.
48656      *
48657      * @param bool $classMapAuthoritative
48658      */
48659     public function setClassMapAuthoritative($classMapAuthoritative)
48660     {
48661         $this->classMapAuthoritative = $classMapAuthoritative;
48662     }
48663
48664     /**
48665      * Should class lookup fail if not found in the current class map?
48666      *
48667      * @return bool
48668      */
48669     public function isClassMapAuthoritative()
48670     {
48671         return $this->classMapAuthoritative;
48672     }
48673
48674     /**
48675      * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
48676      *
48677      * @param string|null $apcuPrefix
48678      */
48679     public function setApcuPrefix($apcuPrefix)
48680     {
48681         $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
48682     }
48683
48684     /**
48685      * The APCu prefix in use, or null if APCu caching is not enabled.
48686      *
48687      * @return string|null
48688      */
48689     public function getApcuPrefix()
48690     {
48691         return $this->apcuPrefix;
48692     }
48693
48694     /**
48695      * Registers this instance as an autoloader.
48696      *
48697      * @param bool $prepend Whether to prepend the autoloader or not
48698      */
48699     public function register($prepend = false)
48700     {
48701         spl_autoload_register(array($this, 'loadClass'), true, $prepend);
48702     }
48703
48704     /**
48705      * Unregisters this instance as an autoloader.
48706      */
48707     public function unregister()
48708     {
48709         spl_autoload_unregister(array($this, 'loadClass'));
48710     }
48711
48712     /**
48713      * Loads the given class or interface.
48714      *
48715      * @param  string    $class The name of the class
48716      * @return bool|null True if loaded, null otherwise
48717      */
48718     public function loadClass($class)
48719     {
48720         if ($file = $this->findFile($class)) {
48721             includeFile($file);
48722
48723             return true;
48724         }
48725     }
48726
48727     /**
48728      * Finds the path to the file where the class is defined.
48729      *
48730      * @param string $class The name of the class
48731      *
48732      * @return string|false The path if found, false otherwise
48733      */
48734     public function findFile($class)
48735     {
48736         // class map lookup
48737         if (isset($this->classMap[$class])) {
48738             return $this->classMap[$class];
48739         }
48740         if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
48741             return false;
48742         }
48743         if (null !== $this->apcuPrefix) {
48744             $file = apcu_fetch($this->apcuPrefix.$class, $hit);
48745             if ($hit) {
48746                 return $file;
48747             }
48748         }
48749
48750         $file = $this->findFileWithExtension($class, '.php');
48751
48752         // Search for Hack files if we are running on HHVM
48753         if (false === $file && defined('HHVM_VERSION')) {
48754             $file = $this->findFileWithExtension($class, '.hh');
48755         }
48756
48757         if (null !== $this->apcuPrefix) {
48758             apcu_add($this->apcuPrefix.$class, $file);
48759         }
48760
48761         if (false === $file) {
48762             // Remember that this class does not exist.
48763             $this->missingClasses[$class] = true;
48764         }
48765
48766         return $file;
48767     }
48768
48769     private function findFileWithExtension($class, $ext)
48770     {
48771         // PSR-4 lookup
48772         $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
48773
48774         $first = $class[0];
48775         if (isset($this->prefixLengthsPsr4[$first])) {
48776             $subPath = $class;
48777             while (false !== $lastPos = strrpos($subPath, '\\')) {
48778                 $subPath = substr($subPath, 0, $lastPos);
48779                 $search = $subPath . '\\';
48780                 if (isset($this->prefixDirsPsr4[$search])) {
48781                     $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
48782                     foreach ($this->prefixDirsPsr4[$search] as $dir) {
48783                         if (file_exists($file = $dir . $pathEnd)) {
48784                             return $file;
48785                         }
48786                     }
48787                 }
48788             }
48789         }
48790
48791         // PSR-4 fallback dirs
48792         foreach ($this->fallbackDirsPsr4 as $dir) {
48793             if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
48794                 return $file;
48795             }
48796         }
48797
48798         // PSR-0 lookup
48799         if (false !== $pos = strrpos($class, '\\')) {
48800             // namespaced class name
48801             $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
48802                 . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
48803         } else {
48804             // PEAR-like class name
48805             $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
48806         }
48807
48808         if (isset($this->prefixesPsr0[$first])) {
48809             foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
48810                 if (0 === strpos($class, $prefix)) {
48811                     foreach ($dirs as $dir) {
48812                         if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
48813                             return $file;
48814                         }
48815                     }
48816                 }
48817             }
48818         }
48819
48820         // PSR-0 fallback dirs
48821         foreach ($this->fallbackDirsPsr0 as $dir) {
48822             if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
48823                 return $file;
48824             }
48825         }
48826
48827         // PSR-0 include paths.
48828         if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
48829             return $file;
48830         }
48831
48832         return false;
48833     }
48834 }
48835
48836 /**
48837  * Scope isolated include.
48838  *
48839  * Prevents access to $this/self from included files.
48840  */
48841 function includeFile($file)
48842 {
48843     include $file;
48844 }
48845 {
48846     "$schema": "http://json-schema.org/draft-04/schema#",
48847     "description": "A representation of packages metadata.",
48848     "type": "object",
48849     "oneOf": [
48850         { "required": [ "packages" ] },
48851         { "required": [ "providers" ] },
48852         { "required": [ "provider-includes", "providers-url" ] }
48853     ],
48854     "properties": {
48855         "packages": {
48856             "type": ["object", "array"],
48857             "description": "A hashmap of package names in the form of <vendor>/<name>.",
48858             "additionalProperties": { "$ref": "#/definitions/versions" }
48859         },
48860         "providers-url": {
48861             "type": "string",
48862             "description": "Endpoint to retrieve provider data from, e.g. '/p/%package%$%hash%.json'."
48863         },
48864         "provider-includes": {
48865             "type": "object",
48866             "description": "A hashmap of provider listings.",
48867             "additionalProperties": { "$ref": "#/definitions/provider" }
48868         },
48869         "providers": {
48870             "type": "object",
48871             "description": "A hashmap of package names in the form of <vendor>/<name>.",
48872             "additionalProperties": { "$ref": "#/definitions/provider" }
48873         },
48874         "notify-batch": {
48875             "type": "string",
48876             "description": "Endpoint to call after multiple packages have been installed, e.g. '/downloads/'."
48877         },
48878         "search": {
48879             "type": "string",
48880             "description": "Endpoint that provides search capabilities, e.g. '/search.json?q=%query%&type=%type%'."
48881         },
48882         "warning": {
48883             "type": "string",
48884             "description": "A message that will be output by Composer as a warning when this source is consulted."
48885         }
48886     },
48887     "definitions": {
48888         "versions": {
48889             "type": "object",
48890             "description": "A hashmap of versions and their metadata.",
48891             "additionalProperties": { "$ref": "#/definitions/version" }
48892         },
48893         "version": {
48894             "type": "object",
48895             "oneOf": [
48896                 { "$ref": "#/definitions/package" },
48897                 { "$ref": "#/definitions/metapackage" }
48898             ]
48899         },
48900         "package-base": {
48901             "properties": {
48902                 "name": { "type": "string" },
48903                 "type": { "type": "string" },
48904                 "version": { "type": "string" },
48905                 "version_normalized": {
48906                     "type": "string",
48907                     "description": "Normalized version, optional but can save computational time on client side."
48908                 },
48909                 "autoload": { "type": "object" },
48910                 "require": { "type": "object" },
48911                 "replace": { "type": "object" },
48912                 "conflict": { "type": "object" },
48913                 "provide": { "type": "object" },
48914                 "time": { "type": "string" }
48915             },
48916             "additionalProperties": true
48917         },
48918         "package": {
48919             "allOf": [
48920                 { "$ref": "#/definitions/package-base" },
48921                 {
48922                     "properties": {
48923                         "dist": { "type": "object" },
48924                         "source": { "type": "object" }
48925                     }
48926                 },
48927                 { "oneOf": [
48928                     { "required": [ "name", "version", "source" ] },
48929                     { "required": [ "name", "version", "dist" ] }
48930                 ] }
48931             ]
48932         },
48933         "metapackage": {
48934             "allOf": [
48935                 { "$ref": "#/definitions/package-base" },
48936                 {
48937                     "properties": {
48938                         "type": { "type": "string", "enum": [ "metapackage" ] }
48939                     },
48940                     "required": [ "name", "version", "type" ]
48941                 }
48942             ]
48943         },
48944         "provider": {
48945             "type": "object",
48946             "properties": {
48947                 "sha256": {
48948                     "type": "string",
48949                     "description": "Hash value that can be used to validate the resource."
48950                 }
48951             }
48952         }
48953     }
48954 }
48955 {
48956     "$schema": "http://json-schema.org/draft-04/schema#",
48957     "name": "Package",
48958     "type": "object",
48959     "additionalProperties": false,
48960     "required": [ "name", "description" ],
48961     "properties": {
48962         "name": {
48963             "type": "string",
48964             "description": "Package name, including 'vendor-name/' prefix."
48965         },
48966         "type": {
48967             "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.",
48968             "type": "string",
48969             "pattern": "^[a-z0-9-]+$"
48970         },
48971         "target-dir": {
48972             "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.",
48973             "type": "string"
48974         },
48975         "description": {
48976             "type": "string",
48977             "description": "Short package description."
48978         },
48979         "keywords": {
48980             "type": "array",
48981             "items": {
48982                 "type": "string",
48983                 "description": "A tag/keyword that this package relates to."
48984             }
48985         },
48986         "homepage": {
48987             "type": "string",
48988             "description": "Homepage URL for the project.",
48989             "format": "uri"
48990         },
48991         "readme": {
48992             "type": "string",
48993             "description": "Relative path to the readme document."
48994         },
48995         "version": {
48996             "type": "string",
48997             "description": "Package version, see https://getcomposer.org/doc/04-schema.md#version for more info on valid schemes.",
48998             "pattern": "^v?\\d+(((\\.\\d+)?\\.\\d+)?\\.\\d+)?|^dev-"
48999         },
49000         "time": {
49001             "type": "string",
49002             "description": "Package release date, in 'YYYY-MM-DD', 'YYYY-MM-DD HH:MM:SS' or 'YYYY-MM-DDTHH:MM:SSZ' format."
49003         },
49004         "license": {
49005             "type": ["string", "array"],
49006             "description": "License name. Or an array of license names."
49007         },
49008         "authors": {
49009             "$ref": "#/definitions/authors"
49010         },
49011         "require": {
49012             "type": "object",
49013             "description": "This is a hash of package name (keys) and version constraints (values) that are required to run this package.",
49014             "additionalProperties": {
49015                 "type": "string"
49016             }
49017         },
49018         "replace": {
49019             "type": "object",
49020             "description": "This is a hash of package name (keys) and version constraints (values) that can be replaced by this package.",
49021             "additionalProperties": {
49022                 "type": "string"
49023             }
49024         },
49025         "conflict": {
49026             "type": "object",
49027             "description": "This is a hash of package name (keys) and version constraints (values) that conflict with this package.",
49028             "additionalProperties": {
49029                 "type": "string"
49030             }
49031         },
49032         "provide": {
49033             "type": "object",
49034             "description": "This is a hash of package name (keys) and version constraints (values) that this package provides in addition to this package's name.",
49035             "additionalProperties": {
49036                 "type": "string"
49037             }
49038         },
49039         "require-dev": {
49040             "type": "object",
49041             "description": "This is a hash of package name (keys) and version constraints (values) that this package requires for developing it (testing tools and such).",
49042             "additionalProperties": {
49043                 "type": "string"
49044             }
49045         },
49046         "suggest": {
49047             "type": "object",
49048             "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).",
49049             "additionalProperties": {
49050                 "type": "string"
49051             }
49052         },
49053         "config": {
49054             "type": "object",
49055             "description": "Composer options.",
49056             "properties": {
49057                 "process-timeout": {
49058                     "type": "integer",
49059                     "description": "The timeout in seconds for process executions, defaults to 300 (5mins)."
49060                 },
49061                 "use-include-path": {
49062                     "type": "boolean",
49063                     "description": "If true, the Composer autoloader will also look for classes in the PHP include path."
49064                 },
49065                 "preferred-install": {
49066                     "type": ["string", "object"],
49067                     "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\"}."
49068                 },
49069                 "notify-on-install": {
49070                     "type": "boolean",
49071                     "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."
49072                 },
49073                 "github-protocols": {
49074                     "type": "array",
49075                     "description": "A list of protocols to use for github.com clones, in priority order, defaults to [\"git\", \"https\", \"http\"].",
49076                     "items": {
49077                         "type": "string"
49078                     }
49079                 },
49080                 "github-oauth": {
49081                     "type": "object",
49082                     "description": "A hash of domain name => github API oauth tokens, typically {\"github.com\":\"<token>\"}.",
49083                     "additionalProperties": {
49084                         "type": "string"
49085                     }
49086                 },
49087                 "gitlab-oauth": {
49088                     "type": "object",
49089                     "description": "A hash of domain name => gitlab API oauth tokens, typically {\"gitlab.com\":\"<token>\"}.",
49090                     "additionalProperties": {
49091                         "type": "string"
49092                     }
49093                 },
49094                 "gitlab-token": {
49095                     "type": "object",
49096                     "description": "A hash of domain name => gitlab private tokens, typically {\"gitlab.com\":\"<token>\"}.",
49097                     "additionalProperties": {
49098                         "type": "string"
49099                     }
49100                 },
49101                 "bearer": {
49102                     "type": "object",
49103                     "description": "A hash of domain name => bearer authentication token, for example {\"example.com\":\"<token>\"}.",
49104                     "additionalProperties": {
49105                         "type": "string"
49106                     }
49107                 },
49108                 "disable-tls": {
49109                     "type": "boolean",
49110                     "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."
49111                 },
49112                 "secure-http": {
49113                     "type": "boolean",
49114                     "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."
49115                 },
49116                 "cafile": {
49117                     "type": "string",
49118                     "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."
49119                 },
49120                 "capath": {
49121                     "type": "string",
49122                     "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."
49123                 },
49124                 "http-basic": {
49125                     "type": "object",
49126                     "description": "A hash of domain name => {\"username\": \"...\", \"password\": \"...\"}.",
49127                     "additionalProperties": {
49128                         "type": "object",
49129                         "required": ["username", "password"],
49130                         "properties": {
49131                             "username": {
49132                                 "type": "string",
49133                                 "description": "The username used for HTTP Basic authentication"
49134                             },
49135                             "password": {
49136                                 "type": "string",
49137                                 "description": "The password used for HTTP Basic authentication"
49138                             }
49139                         }
49140                     }
49141                 },
49142                 "store-auths": {
49143                     "type": ["string", "boolean"],
49144                     "description": "What to do after prompting for authentication, one of: true (store), false (do not store) or \"prompt\" (ask every time), defaults to prompt."
49145                 },
49146                 "platform": {
49147                     "type": "object",
49148                     "description": "This is a hash of package name (keys) and version (values) that will be used to mock the platform packages on this machine.",
49149                     "additionalProperties": {
49150                         "type": "string"
49151                     }
49152                 },
49153                 "vendor-dir": {
49154                     "type": "string",
49155                     "description": "The location where all packages are installed, defaults to \"vendor\"."
49156                 },
49157                 "bin-dir": {
49158                     "type": "string",
49159                     "description": "The location where all binaries are linked, defaults to \"vendor/bin\"."
49160                 },
49161                 "data-dir": {
49162                     "type": "string",
49163                     "description": "The location where old phar files are stored, defaults to \"$home\" except on XDG Base Directory compliant unixes."
49164                 },
49165                 "cache-dir": {
49166                     "type": "string",
49167                     "description": "The location where all caches are located, defaults to \"~/.composer/cache\" on *nix and \"%LOCALAPPDATA%\\Composer\" on windows."
49168                 },
49169                 "cache-files-dir": {
49170                     "type": "string",
49171                     "description": "The location where files (zip downloads) are cached, defaults to \"{$cache-dir}/files\"."
49172                 },
49173                 "cache-repo-dir": {
49174                     "type": "string",
49175                     "description": "The location where repo (git/hg repo clones) are cached, defaults to \"{$cache-dir}/repo\"."
49176                 },
49177                 "cache-vcs-dir": {
49178                     "type": "string",
49179                     "description": "The location where vcs infos (git clones, github api calls, etc. when reading vcs repos) are cached, defaults to \"{$cache-dir}/vcs\"."
49180                 },
49181                 "cache-ttl": {
49182                     "type": "integer",
49183                     "description": "The default cache time-to-live, defaults to 15552000 (6 months)."
49184                 },
49185                 "cache-files-ttl": {
49186                     "type": "integer",
49187                     "description": "The cache time-to-live for files, defaults to the value of cache-ttl."
49188                 },
49189                 "cache-files-maxsize": {
49190                     "type": ["string", "integer"],
49191                     "description": "The cache max size for the files cache, defaults to \"300MiB\"."
49192                 },
49193                 "bin-compat": {
49194                     "enum": ["auto", "full"],
49195                     "description": "The compatibility of the binaries, defaults to \"auto\" (automatically guessed) and can be \"full\" (compatible with both Windows and Unix-based systems)."
49196                 },
49197                 "discard-changes": {
49198                     "type": ["string", "boolean"],
49199                     "description": "The default style of handling dirty updates, defaults to false and can be any of true, false or \"stash\"."
49200                 },
49201                 "autoloader-suffix": {
49202                     "type": "string",
49203                     "description": "Optional string to be used as a suffix for the generated Composer autoloader. When null a random one will be generated."
49204                 },
49205                 "optimize-autoloader": {
49206                     "type": "boolean",
49207                     "description": "Always optimize when dumping the autoloader."
49208                 },
49209                 "prepend-autoloader": {
49210                     "type": "boolean",
49211                     "description": "If false, the composer autoloader will not be prepended to existing autoloaders, defaults to true."
49212                 },
49213                 "classmap-authoritative": {
49214                     "type": "boolean",
49215                     "description": "If true, the composer autoloader will not scan the filesystem for classes that are not found in the class map, defaults to false."
49216                 },
49217                 "apcu-autoloader": {
49218                     "type": "boolean",
49219                     "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."
49220                 },
49221                 "github-domains": {
49222                     "type": "array",
49223                     "description": "A list of domains to use in github mode. This is used for GitHub Enterprise setups, defaults to [\"github.com\"].",
49224                     "items": {
49225                         "type": "string"
49226                     }
49227                 },
49228                 "github-expose-hostname": {
49229                     "type": "boolean",
49230                     "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."
49231                 },
49232                 "gitlab-domains": {
49233                     "type": "array",
49234                     "description": "A list of domains to use in gitlab mode. This is used for custom GitLab setups, defaults to [\"gitlab.com\"].",
49235                     "items": {
49236                         "type": "string"
49237                     }
49238                 },
49239                 "use-github-api": {
49240                     "type": "boolean",
49241                     "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."
49242                 },
49243                 "archive-format": {
49244                     "type": "string",
49245                     "description": "The default archiving format when not provided on cli, defaults to \"tar\"."
49246                 },
49247                 "archive-dir": {
49248                     "type": "string",
49249                     "description": "The default archive path when not provided on cli, defaults to \".\"."
49250                 },
49251                 "htaccess-protect": {
49252                     "type": "boolean",
49253                     "description": "Defaults to true. If set to false, Composer will not create .htaccess files in the composer home, cache, and data directories."
49254                 },
49255                 "sort-packages": {
49256                     "type": "boolean",
49257                     "description": "Defaults to false. If set to true, Composer will sort packages when adding/updating a new dependency."
49258                 },
49259                 "lock": {
49260                     "type": "boolean",
49261                     "description": "Defaults to true. If set to false, Composer will not create a composer.lock file."
49262                 }
49263             }
49264         },
49265         "extra": {
49266             "type": ["object", "array"],
49267             "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.",
49268             "additionalProperties": true
49269         },
49270         "autoload": {
49271             "$ref": "#/definitions/autoload"
49272         },
49273         "autoload-dev": {
49274             "type": "object",
49275             "description": "Description of additional autoload rules for development purpose (eg. a test suite).",
49276             "properties": {
49277                 "psr-0": {
49278                     "type": "object",
49279                     "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.",
49280                     "additionalProperties": {
49281                         "type": ["string", "array"],
49282                         "items": {
49283                             "type": "string"
49284                         }
49285                     }
49286                 },
49287                 "psr-4": {
49288                     "type": "object",
49289                     "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.",
49290                     "additionalProperties": {
49291                         "type": ["string", "array"],
49292                         "items": {
49293                             "type": "string"
49294                         }
49295                     }
49296                 },
49297                 "classmap": {
49298                     "type": "array",
49299                     "description": "This is an array of directories that contain classes to be included in the class-map generation process."
49300                 },
49301                 "files": {
49302                     "type": "array",
49303                     "description": "This is an array of files that are always required on every request."
49304                 }
49305             }
49306         },
49307         "archive": {
49308             "type": ["object"],
49309             "description": "Options for creating package archives for distribution.",
49310             "properties": {
49311                 "exclude": {
49312                     "type": "array",
49313                     "description": "A list of patterns for paths to exclude or include if prefixed with an exclamation mark."
49314                 }
49315             }
49316         },
49317         "repositories": {
49318             "type": ["object", "array"],
49319             "description": "A set of additional repositories where packages can be found.",
49320             "additionalProperties": {
49321                 "anyOf": [
49322                     { "$ref": "#/definitions/repository" },
49323                     { "type": "boolean", "enum": [false] }
49324                 ]
49325             },
49326             "items": {
49327                 "anyOf": [
49328                     { "$ref": "#/definitions/repository" },
49329                     {
49330                         "type": "object",
49331                         "additionalProperties": { "type": "boolean", "enum": [false] },
49332                         "minProperties": 1,
49333                         "maxProperties": 1
49334                     }
49335                 ]
49336             }
49337         },
49338         "minimum-stability": {
49339             "type": ["string"],
49340             "description": "The minimum stability the packages must have to be install-able. Possible values are: dev, alpha, beta, RC, stable.",
49341             "pattern": "^dev|alpha|beta|rc|RC|stable$"
49342         },
49343         "prefer-stable": {
49344             "type": ["boolean"],
49345             "description": "If set to true, stable packages will be preferred to dev packages when possible, even if the minimum-stability allows unstable packages."
49346         },
49347         "bin": {
49348             "type": ["string", "array"],
49349             "description": "A set of files, or a single file, that should be treated as binaries and symlinked into bin-dir (from config).",
49350             "items": {
49351                 "type": "string"
49352             }
49353         },
49354         "include-path": {
49355             "type": ["array"],
49356             "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.",
49357             "items": {
49358                 "type": "string"
49359             }
49360         },
49361         "scripts": {
49362             "type": ["object"],
49363             "description": "Script listeners that will be executed before/after some events.",
49364             "properties": {
49365                 "pre-install-cmd": {
49366                     "type": ["array", "string"],
49367                     "description": "Occurs before the install command is executed, contains one or more Class::method callables or shell commands."
49368                 },
49369                 "post-install-cmd": {
49370                     "type": ["array", "string"],
49371                     "description": "Occurs after the install command is executed, contains one or more Class::method callables or shell commands."
49372                 },
49373                 "pre-update-cmd": {
49374                     "type": ["array", "string"],
49375                     "description": "Occurs before the update command is executed, contains one or more Class::method callables or shell commands."
49376                 },
49377                 "post-update-cmd": {
49378                     "type": ["array", "string"],
49379                     "description": "Occurs after the update command is executed, contains one or more Class::method callables or shell commands."
49380                 },
49381                 "pre-status-cmd": {
49382                     "type": ["array", "string"],
49383                     "description": "Occurs before the status command is executed, contains one or more Class::method callables or shell commands."
49384                 },
49385                 "post-status-cmd": {
49386                     "type": ["array", "string"],
49387                     "description": "Occurs after the status command is executed, contains one or more Class::method callables or shell commands."
49388                 },
49389                 "pre-package-install": {
49390                     "type": ["array", "string"],
49391                     "description": "Occurs before a package is installed, contains one or more Class::method callables or shell commands."
49392                 },
49393                 "post-package-install": {
49394                     "type": ["array", "string"],
49395                     "description": "Occurs after a package is installed, contains one or more Class::method callables or shell commands."
49396                 },
49397                 "pre-package-update": {
49398                     "type": ["array", "string"],
49399                     "description": "Occurs before a package is updated, contains one or more Class::method callables or shell commands."
49400                 },
49401                 "post-package-update": {
49402                     "type": ["array", "string"],
49403                     "description": "Occurs after a package is updated, contains one or more Class::method callables or shell commands."
49404                 },
49405                 "pre-package-uninstall": {
49406                     "type": ["array", "string"],
49407                     "description": "Occurs before a package has been uninstalled, contains one or more Class::method callables or shell commands."
49408                 },
49409                 "post-package-uninstall": {
49410                     "type": ["array", "string"],
49411                     "description": "Occurs after a package has been uninstalled, contains one or more Class::method callables or shell commands."
49412                 },
49413                 "pre-autoload-dump": {
49414                     "type": ["array", "string"],
49415                     "description": "Occurs before the autoloader is dumped, contains one or more Class::method callables or shell commands."
49416                 },
49417                 "post-autoload-dump": {
49418                     "type": ["array", "string"],
49419                     "description": "Occurs after the autoloader is dumped, contains one or more Class::method callables or shell commands."
49420                 },
49421                 "post-root-package-install": {
49422                     "type": ["array", "string"],
49423                     "description": "Occurs after the root-package is installed, contains one or more Class::method callables or shell commands."
49424                 },
49425                 "post-create-project-cmd": {
49426                     "type": ["array", "string"],
49427                     "description": "Occurs after the create-project command is executed, contains one or more Class::method callables or shell commands."
49428                 }
49429             }
49430         },
49431         "scripts-descriptions": {
49432             "type": ["object"],
49433             "description": "Descriptions for custom commands, shown in console help.",
49434             "additionalProperties": {
49435                 "type": "string"
49436             }
49437         },
49438         "support": {
49439             "type": "object",
49440             "properties": {
49441                 "email": {
49442                     "type": "string",
49443                     "description": "Email address for support.",
49444                     "format": "email"
49445                 },
49446                 "issues": {
49447                     "type": "string",
49448                     "description": "URL to the issue tracker.",
49449                     "format": "uri"
49450                 },
49451                 "forum": {
49452                     "type": "string",
49453                     "description": "URL to the forum.",
49454                     "format": "uri"
49455                 },
49456                 "wiki": {
49457                     "type": "string",
49458                     "description": "URL to the wiki.",
49459                     "format": "uri"
49460                 },
49461                 "irc": {
49462                     "type": "string",
49463                     "description": "IRC channel for support, as irc://server/channel.",
49464                     "format": "uri"
49465                 },
49466                 "chat": {
49467                     "type": "string",
49468                     "description": "URL to the support chat.",
49469                     "format": "uri"
49470                 },
49471                 "source": {
49472                     "type": "string",
49473                     "description": "URL to browse or download the sources.",
49474                     "format": "uri"
49475                 },
49476                 "docs": {
49477                     "type": "string",
49478                     "description": "URL to the documentation.",
49479                     "format": "uri"
49480                 },
49481                 "rss": {
49482                     "type": "string",
49483                     "description": "URL to the RSS feed.",
49484                     "format": "uri"
49485                 }
49486             }
49487         },
49488         "funding": {
49489             "type": "array",
49490             "description": "A list of options to fund the development and maintenance of the package.",
49491             "items": {
49492                 "type": "object",
49493                 "properties": {
49494                     "type": {
49495                         "type": "string",
49496                         "description": "Type of funding or platform through which funding is possible."
49497                     },
49498                     "url": {
49499                         "type": "string",
49500                         "description": "URL to a website with details on funding and a way to fund the package.",
49501                         "format": "uri"
49502                     }
49503                 }
49504             }
49505         },
49506         "non-feature-branches": {
49507             "type": ["array"],
49508             "description": "A set of string or regex patterns for non-numeric branch names that will not be handled as feature branches.",
49509             "items": {
49510                 "type": "string"
49511             }
49512         },
49513         "abandoned": {
49514             "type": ["boolean", "string"],
49515             "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."
49516         },
49517         "_comment": {
49518             "type": ["array", "string"],
49519             "description": "A key to store comments in"
49520         }
49521     },
49522     "definitions": {
49523         "authors": {
49524             "type": "array",
49525             "description": "List of authors that contributed to the package. This is typically the main maintainers, not the full list.",
49526             "items": {
49527                 "type": "object",
49528                 "additionalProperties": false,
49529                 "required": [ "name"],
49530                 "properties": {
49531                     "name": {
49532                         "type": "string",
49533                         "description": "Full name of the author."
49534                     },
49535                     "email": {
49536                         "type": "string",
49537                         "description": "Email address of the author.",
49538                         "format": "email"
49539                     },
49540                     "homepage": {
49541                         "type": "string",
49542                         "description": "Homepage URL for the author.",
49543                         "format": "uri"
49544                     },
49545                     "role": {
49546                         "type": "string",
49547                         "description": "Author's role in the project."
49548                     }
49549                 }
49550             }
49551         },
49552         "autoload": {
49553             "type": "object",
49554             "description": "Description of how the package can be autoloaded.",
49555             "properties": {
49556                 "psr-0": {
49557                     "type": "object",
49558                     "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.",
49559                     "additionalProperties": {
49560                         "type": ["string", "array"],
49561                         "items": {
49562                             "type": "string"
49563                         }
49564                     }
49565                 },
49566                 "psr-4": {
49567                     "type": "object",
49568                     "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.",
49569                     "additionalProperties": {
49570                         "type": ["string", "array"],
49571                         "items": {
49572                             "type": "string"
49573                         }
49574                     }
49575                 },
49576                 "classmap": {
49577                     "type": "array",
49578                     "description": "This is an array of directories that contain classes to be included in the class-map generation process."
49579                 },
49580                 "files": {
49581                     "type": "array",
49582                     "description": "This is an array of files that are always required on every request."
49583                 },
49584                 "exclude-from-classmap": {
49585                     "type": "array",
49586                     "description": "This is an array of patterns to exclude from autoload classmap generation. (e.g. \"exclude-from-classmap\": [\"/test/\", \"/tests/\", \"/Tests/\"]"
49587                 }
49588             }
49589         },
49590         "repository": {
49591             "type": "object",
49592             "anyOf": [
49593                 { "$ref": "#/definitions/composer-repository" },
49594                 { "$ref": "#/definitions/vcs-repository" },
49595                 { "$ref": "#/definitions/path-repository" },
49596                 { "$ref": "#/definitions/artifact-repository" },
49597                 { "$ref": "#/definitions/pear-repository" },
49598                 { "$ref": "#/definitions/package-repository" }
49599             ]
49600         },
49601         "composer-repository": {
49602             "type": "object",
49603             "required": ["type", "url"],
49604             "properties": {
49605                 "type": { "type": "string", "enum": ["composer"] },
49606                 "url": { "type": "string" },
49607                 "options": {
49608                     "type": "object",
49609                     "additionalProperties": true
49610                 },
49611                 "allow_ssl_downgrade": { "type": "boolean" },
49612                 "force-lazy-providers": { "type": "boolean" }
49613             }
49614         },
49615         "vcs-repository": {
49616             "type": "object",
49617             "required": ["type", "url"],
49618             "properties": {
49619                 "type": { "type": "string", "enum": ["vcs", "github", "git", "gitlab", "git-bitbucket", "hg", "hg-bitbucket", "fossil", "perforce", "svn"] },
49620                 "url": { "type": "string" },
49621                 "no-api": { "type": "boolean" },
49622                 "secure-http": { "type": "boolean" },
49623                 "svn-cache-credentials": { "type": "boolean" },
49624                 "trunk-path": { "type": ["string", "boolean"] },
49625                 "branches-path": { "type": ["string", "boolean"] },
49626                 "tags-path": { "type": ["string", "boolean"] },
49627                 "package-path": { "type": "string" },
49628                 "depot": { "type": "string" },
49629                 "branch": { "type": "string" },
49630                 "unique_perforce_client_name": { "type": "string" },
49631                 "p4user": { "type": "string" },
49632                 "p4password": { "type": "string" }
49633             }
49634         },
49635         "path-repository": {
49636             "type": "object",
49637             "required": ["type", "url"],
49638             "properties": {
49639                 "type": { "type": "string", "enum": ["path"] },
49640                 "url": { "type": "string" },
49641                 "options": {
49642                     "type": "object",
49643                     "properties": {
49644                         "symlink": { "type": ["boolean", "null"] }
49645                     },
49646                     "additionalProperties": true
49647                 }
49648             }
49649         },
49650         "artifact-repository": {
49651             "type": "object",
49652             "required": ["type", "url"],
49653             "properties": {
49654                 "type": { "type": "string", "enum": ["artifact"] },
49655                 "url": { "type": "string" }
49656             }
49657         },
49658         "pear-repository": {
49659             "type": "object",
49660             "required": ["type", "url"],
49661             "properties": {
49662                 "type": { "type": "string", "enum": ["pear"] },
49663                 "url": { "type": "string" },
49664                 "vendor-alias": { "type": "string" }
49665             }
49666         },
49667         "package-repository": {
49668             "type": "object",
49669             "required": ["type", "package"],
49670             "properties": {
49671                 "type": { "type": "string", "enum": ["package"] },
49672                 "package": {
49673                     "oneOf": [
49674                         { "$ref": "#/definitions/inline-package" },
49675                         {
49676                             "type": "array",
49677                             "items": { "$ref": "#/definitions/inline-package" }
49678                         }
49679                     ]
49680                 }
49681             }
49682         },
49683         "inline-package": {
49684             "type": "object",
49685             "required": ["name", "version"],
49686             "properties": {
49687                 "name": {
49688                     "type": "string",
49689                     "description": "Package name, including 'vendor-name/' prefix."
49690                 },
49691                 "type": {
49692                     "type": "string"
49693                 },
49694                 "target-dir": {
49695                     "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.",
49696                     "type": "string"
49697                 },
49698                 "description": {
49699                     "type": "string"
49700                 },
49701                 "keywords": {
49702                     "type": "array",
49703                     "items": {
49704                         "type": "string"
49705                     }
49706                 },
49707                 "homepage": {
49708                     "type": "string",
49709                     "format": "uri"
49710                 },
49711                 "version": {
49712                     "type": "string"
49713                 },
49714                 "time": {
49715                     "type": "string"
49716                 },
49717                 "license": {
49718                     "type": [
49719                         "string",
49720                         "array"
49721                     ]
49722                 },
49723                 "authors": {
49724                     "$ref": "#/definitions/authors"
49725                 },
49726                 "require": {
49727                     "type": "object",
49728                     "additionalProperties": {
49729                         "type": "string"
49730                     }
49731                 },
49732                 "replace": {
49733                     "type": "object",
49734                     "additionalProperties": {
49735                         "type": "string"
49736                     }
49737                 },
49738                 "conflict": {
49739                     "type": "object",
49740                     "additionalProperties": {
49741                         "type": "string"
49742                     }
49743                 },
49744                 "provide": {
49745                     "type": "object",
49746                     "additionalProperties": {
49747                         "type": "string"
49748                     }
49749                 },
49750                 "require-dev": {
49751                     "type": "object",
49752                     "additionalProperties": {
49753                         "type": "string"
49754                     }
49755                 },
49756                 "suggest": {
49757                     "type": "object",
49758                     "additionalProperties": {
49759                         "type": "string"
49760                     }
49761                 },
49762                 "extra": {
49763                     "type": ["object", "array"],
49764                     "additionalProperties": true
49765                 },
49766                 "autoload": {
49767                     "$ref": "#/definitions/autoload"
49768                 },
49769                 "archive": {
49770                     "type": ["object"],
49771                     "properties": {
49772                         "exclude": {
49773                             "type": "array"
49774                         }
49775                     }
49776                 },
49777                 "bin": {
49778                     "type": ["string", "array"],
49779                     "description": "A set of files, or a single file, that should be treated as binaries and symlinked into bin-dir (from config).",
49780                     "items": {
49781                         "type": "string"
49782                     }
49783                 },
49784                 "include-path": {
49785                     "type": ["array"],
49786                     "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.",
49787                     "items": {
49788                         "type": "string"
49789                     }
49790                 },
49791                 "source": {
49792                     "type": "object",
49793                     "required": ["type", "url", "reference"],
49794                     "properties": {
49795                         "type": {
49796                             "type": "string"
49797                         },
49798                         "url": {
49799                             "type": "string"
49800                         },
49801                         "reference": {
49802                             "type": "string"
49803                         },
49804                         "mirrors": {
49805                             "type": "array"
49806                         }
49807                     }
49808                 },
49809                 "dist": {
49810                     "type": "object",
49811                     "required": ["type", "url"],
49812                     "properties": {
49813                         "type": {
49814                             "type": "string"
49815                         },
49816                         "url": {
49817                             "type": "string"
49818                         },
49819                         "reference": {
49820                             "type": "string"
49821                         },
49822                         "shasum": {
49823                             "type": "string"
49824                         },
49825                         "mirrors": {
49826                             "type": "array"
49827                         }
49828                     }
49829                 }
49830             },
49831             "additionalProperties": true
49832         }
49833     }
49834 }
49835 {
49836     "389-exception": [
49837         "389 Directory Server Exception"
49838     ],
49839     "Autoconf-exception-2.0": [
49840         "Autoconf exception 2.0"
49841     ],
49842     "Autoconf-exception-3.0": [
49843         "Autoconf exception 3.0"
49844     ],
49845     "Bison-exception-2.2": [
49846         "Bison exception 2.2"
49847     ],
49848     "Bootloader-exception": [
49849         "Bootloader Distribution Exception"
49850     ],
49851     "Classpath-exception-2.0": [
49852         "Classpath exception 2.0"
49853     ],
49854     "CLISP-exception-2.0": [
49855         "CLISP exception 2.0"
49856     ],
49857     "DigiRule-FOSS-exception": [
49858         "DigiRule FOSS License Exception"
49859     ],
49860     "eCos-exception-2.0": [
49861         "eCos exception 2.0"
49862     ],
49863     "Fawkes-Runtime-exception": [
49864         "Fawkes Runtime Exception"
49865     ],
49866     "FLTK-exception": [
49867         "FLTK exception"
49868     ],
49869     "Font-exception-2.0": [
49870         "Font exception 2.0"
49871     ],
49872     "freertos-exception-2.0": [
49873         "FreeRTOS Exception 2.0"
49874     ],
49875     "GCC-exception-2.0": [
49876         "GCC Runtime Library exception 2.0"
49877     ],
49878     "GCC-exception-3.1": [
49879         "GCC Runtime Library exception 3.1"
49880     ],
49881     "gnu-javamail-exception": [
49882         "GNU JavaMail exception"
49883     ],
49884     "GPL-3.0-linking-exception": [
49885         "GPL-3.0 Linking Exception"
49886     ],
49887     "GPL-3.0-linking-source-exception": [
49888         "GPL-3.0 Linking Exception (with Corresponding Source)"
49889     ],
49890     "GPL-CC-1.0": [
49891         "GPL Cooperation Commitment 1.0"
49892     ],
49893     "i2p-gpl-java-exception": [
49894         "i2p GPL+Java Exception"
49895     ],
49896     "LGPL-3.0-linking-exception": [
49897         "LGPL-3.0 Linking Exception"
49898     ],
49899     "Libtool-exception": [
49900         "Libtool Exception"
49901     ],
49902     "Linux-syscall-note": [
49903         "Linux Syscall Note"
49904     ],
49905     "LLVM-exception": [
49906         "LLVM Exception"
49907     ],
49908     "LZMA-exception": [
49909         "LZMA exception"
49910     ],
49911     "mif-exception": [
49912         "Macros and Inline Functions Exception"
49913     ],
49914     "Nokia-Qt-exception-1.1": [
49915         "Nokia Qt LGPL exception 1.1"
49916     ],
49917     "OCaml-LGPL-linking-exception": [
49918         "OCaml LGPL Linking Exception"
49919     ],
49920     "OCCT-exception-1.0": [
49921         "Open CASCADE Exception 1.0"
49922     ],
49923     "OpenJDK-assembly-exception-1.0": [
49924         "OpenJDK Assembly exception 1.0"
49925     ],
49926     "openvpn-openssl-exception": [
49927         "OpenVPN OpenSSL Exception"
49928     ],
49929     "PS-or-PDF-font-exception-20170817": [
49930         "PS/PDF font exception (2017-08-17)"
49931     ],
49932     "Qt-GPL-exception-1.0": [
49933         "Qt GPL exception 1.0"
49934     ],
49935     "Qt-LGPL-exception-1.1": [
49936         "Qt LGPL exception 1.1"
49937     ],
49938     "Qwt-exception-1.0": [
49939         "Qwt exception 1.0"
49940     ],
49941     "SHL-2.0": [
49942         "Solderpad Hardware License v2.0"
49943     ],
49944     "SHL-2.1": [
49945         "Solderpad Hardware License v2.1"
49946     ],
49947     "Swift-exception": [
49948         "Swift Exception"
49949     ],
49950     "u-boot-exception-2.0": [
49951         "U-Boot exception 2.0"
49952     ],
49953     "Universal-FOSS-exception-1.0": [
49954         "Universal FOSS Exception, Version 1.0"
49955     ],
49956     "WxWindows-exception-3.1": [
49957         "WxWindows Library Exception 3.1"
49958     ]
49959 }{
49960     "0BSD": [
49961         "BSD Zero Clause License",
49962         true,
49963         false
49964     ],
49965     "AAL": [
49966         "Attribution Assurance License",
49967         true,
49968         false
49969     ],
49970     "Abstyles": [
49971         "Abstyles License",
49972         false,
49973         false
49974     ],
49975     "Adobe-2006": [
49976         "Adobe Systems Incorporated Source Code License Agreement",
49977         false,
49978         false
49979     ],
49980     "Adobe-Glyph": [
49981         "Adobe Glyph List License",
49982         false,
49983         false
49984     ],
49985     "ADSL": [
49986         "Amazon Digital Services License",
49987         false,
49988         false
49989     ],
49990     "AFL-1.1": [
49991         "Academic Free License v1.1",
49992         true,
49993         false
49994     ],
49995     "AFL-1.2": [
49996         "Academic Free License v1.2",
49997         true,
49998         false
49999     ],
50000     "AFL-2.0": [
50001         "Academic Free License v2.0",
50002         true,
50003         false
50004     ],
50005     "AFL-2.1": [
50006         "Academic Free License v2.1",
50007         true,
50008         false
50009     ],
50010     "AFL-3.0": [
50011         "Academic Free License v3.0",
50012         true,
50013         false
50014     ],
50015     "Afmparse": [
50016         "Afmparse License",
50017         false,
50018         false
50019     ],
50020     "AGPL-1.0": [
50021         "Affero General Public License v1.0",
50022         false,
50023         true
50024     ],
50025     "AGPL-1.0-only": [
50026         "Affero General Public License v1.0 only",
50027         false,
50028         false
50029     ],
50030     "AGPL-1.0-or-later": [
50031         "Affero General Public License v1.0 or later",
50032         false,
50033         false
50034     ],
50035     "AGPL-3.0": [
50036         "GNU Affero General Public License v3.0",
50037         true,
50038         true
50039     ],
50040     "AGPL-3.0-only": [
50041         "GNU Affero General Public License v3.0 only",
50042         true,
50043         false
50044     ],
50045     "AGPL-3.0-or-later": [
50046         "GNU Affero General Public License v3.0 or later",
50047         true,
50048         false
50049     ],
50050     "Aladdin": [
50051         "Aladdin Free Public License",
50052         false,
50053         false
50054     ],
50055     "AMDPLPA": [
50056         "AMD's plpa_map.c License",
50057         false,
50058         false
50059     ],
50060     "AML": [
50061         "Apple MIT License",
50062         false,
50063         false
50064     ],
50065     "AMPAS": [
50066         "Academy of Motion Picture Arts and Sciences BSD",
50067         false,
50068         false
50069     ],
50070     "ANTLR-PD": [
50071         "ANTLR Software Rights Notice",
50072         false,
50073         false
50074     ],
50075     "ANTLR-PD-fallback": [
50076         "ANTLR Software Rights Notice with license fallback",
50077         false,
50078         false
50079     ],
50080     "Apache-1.0": [
50081         "Apache License 1.0",
50082         false,
50083         false
50084     ],
50085     "Apache-1.1": [
50086         "Apache License 1.1",
50087         true,
50088         false
50089     ],
50090     "Apache-2.0": [
50091         "Apache License 2.0",
50092         true,
50093         false
50094     ],
50095     "APAFML": [
50096         "Adobe Postscript AFM License",
50097         false,
50098         false
50099     ],
50100     "APL-1.0": [
50101         "Adaptive Public License 1.0",
50102         true,
50103         false
50104     ],
50105     "APSL-1.0": [
50106         "Apple Public Source License 1.0",
50107         true,
50108         false
50109     ],
50110     "APSL-1.1": [
50111         "Apple Public Source License 1.1",
50112         true,
50113         false
50114     ],
50115     "APSL-1.2": [
50116         "Apple Public Source License 1.2",
50117         true,
50118         false
50119     ],
50120     "APSL-2.0": [
50121         "Apple Public Source License 2.0",
50122         true,
50123         false
50124     ],
50125     "Artistic-1.0": [
50126         "Artistic License 1.0",
50127         true,
50128         false
50129     ],
50130     "Artistic-1.0-cl8": [
50131         "Artistic License 1.0 w/clause 8",
50132         true,
50133         false
50134     ],
50135     "Artistic-1.0-Perl": [
50136         "Artistic License 1.0 (Perl)",
50137         true,
50138         false
50139     ],
50140     "Artistic-2.0": [
50141         "Artistic License 2.0",
50142         true,
50143         false
50144     ],
50145     "Bahyph": [
50146         "Bahyph License",
50147         false,
50148         false
50149     ],
50150     "Barr": [
50151         "Barr License",
50152         false,
50153         false
50154     ],
50155     "Beerware": [
50156         "Beerware License",
50157         false,
50158         false
50159     ],
50160     "BitTorrent-1.0": [
50161         "BitTorrent Open Source License v1.0",
50162         false,
50163         false
50164     ],
50165     "BitTorrent-1.1": [
50166         "BitTorrent Open Source License v1.1",
50167         false,
50168         false
50169     ],
50170     "blessing": [
50171         "SQLite Blessing",
50172         false,
50173         false
50174     ],
50175     "BlueOak-1.0.0": [
50176         "Blue Oak Model License 1.0.0",
50177         false,
50178         false
50179     ],
50180     "Borceux": [
50181         "Borceux license",
50182         false,
50183         false
50184     ],
50185     "BSD-1-Clause": [
50186         "BSD 1-Clause License",
50187         true,
50188         false
50189     ],
50190     "BSD-2-Clause": [
50191         "BSD 2-Clause \"Simplified\" License",
50192         true,
50193         false
50194     ],
50195     "BSD-2-Clause-FreeBSD": [
50196         "BSD 2-Clause FreeBSD License",
50197         false,
50198         true
50199     ],
50200     "BSD-2-Clause-NetBSD": [
50201         "BSD 2-Clause NetBSD License",
50202         false,
50203         true
50204     ],
50205     "BSD-2-Clause-Patent": [
50206         "BSD-2-Clause Plus Patent License",
50207         true,
50208         false
50209     ],
50210     "BSD-2-Clause-Views": [
50211         "BSD 2-Clause with views sentence",
50212         false,
50213         false
50214     ],
50215     "BSD-3-Clause": [
50216         "BSD 3-Clause \"New\" or \"Revised\" License",
50217         true,
50218         false
50219     ],
50220     "BSD-3-Clause-Attribution": [
50221         "BSD with attribution",
50222         false,
50223         false
50224     ],
50225     "BSD-3-Clause-Clear": [
50226         "BSD 3-Clause Clear License",
50227         false,
50228         false
50229     ],
50230     "BSD-3-Clause-LBNL": [
50231         "Lawrence Berkeley National Labs BSD variant license",
50232         true,
50233         false
50234     ],
50235     "BSD-3-Clause-No-Nuclear-License": [
50236         "BSD 3-Clause No Nuclear License",
50237         false,
50238         false
50239     ],
50240     "BSD-3-Clause-No-Nuclear-License-2014": [
50241         "BSD 3-Clause No Nuclear License 2014",
50242         false,
50243         false
50244     ],
50245     "BSD-3-Clause-No-Nuclear-Warranty": [
50246         "BSD 3-Clause No Nuclear Warranty",
50247         false,
50248         false
50249     ],
50250     "BSD-3-Clause-Open-MPI": [
50251         "BSD 3-Clause Open MPI variant",
50252         false,
50253         false
50254     ],
50255     "BSD-4-Clause": [
50256         "BSD 4-Clause \"Original\" or \"Old\" License",
50257         false,
50258         false
50259     ],
50260     "BSD-4-Clause-UC": [
50261         "BSD-4-Clause (University of California-Specific)",
50262         false,
50263         false
50264     ],
50265     "BSD-Protection": [
50266         "BSD Protection License",
50267         false,
50268         false
50269     ],
50270     "BSD-Source-Code": [
50271         "BSD Source Code Attribution",
50272         false,
50273         false
50274     ],
50275     "BSL-1.0": [
50276         "Boost Software License 1.0",
50277         true,
50278         false
50279     ],
50280     "BUSL-1.1": [
50281         "Business Source License 1.1",
50282         false,
50283         false
50284     ],
50285     "bzip2-1.0.5": [
50286         "bzip2 and libbzip2 License v1.0.5",
50287         false,
50288         false
50289     ],
50290     "bzip2-1.0.6": [
50291         "bzip2 and libbzip2 License v1.0.6",
50292         false,
50293         false
50294     ],
50295     "CAL-1.0": [
50296         "Cryptographic Autonomy License 1.0",
50297         true,
50298         false
50299     ],
50300     "CAL-1.0-Combined-Work-Exception": [
50301         "Cryptographic Autonomy License 1.0 (Combined Work Exception)",
50302         true,
50303         false
50304     ],
50305     "Caldera": [
50306         "Caldera License",
50307         false,
50308         false
50309     ],
50310     "CATOSL-1.1": [
50311         "Computer Associates Trusted Open Source License 1.1",
50312         true,
50313         false
50314     ],
50315     "CC-BY-1.0": [
50316         "Creative Commons Attribution 1.0 Generic",
50317         false,
50318         false
50319     ],
50320     "CC-BY-2.0": [
50321         "Creative Commons Attribution 2.0 Generic",
50322         false,
50323         false
50324     ],
50325     "CC-BY-2.5": [
50326         "Creative Commons Attribution 2.5 Generic",
50327         false,
50328         false
50329     ],
50330     "CC-BY-3.0": [
50331         "Creative Commons Attribution 3.0 Unported",
50332         false,
50333         false
50334     ],
50335     "CC-BY-3.0-AT": [
50336         "Creative Commons Attribution 3.0 Austria",
50337         false,
50338         false
50339     ],
50340     "CC-BY-3.0-US": [
50341         "Creative Commons Attribution 3.0 United States",
50342         false,
50343         false
50344     ],
50345     "CC-BY-4.0": [
50346         "Creative Commons Attribution 4.0 International",
50347         false,
50348         false
50349     ],
50350     "CC-BY-NC-1.0": [
50351         "Creative Commons Attribution Non Commercial 1.0 Generic",
50352         false,
50353         false
50354     ],
50355     "CC-BY-NC-2.0": [
50356         "Creative Commons Attribution Non Commercial 2.0 Generic",
50357         false,
50358         false
50359     ],
50360     "CC-BY-NC-2.5": [
50361         "Creative Commons Attribution Non Commercial 2.5 Generic",
50362         false,
50363         false
50364     ],
50365     "CC-BY-NC-3.0": [
50366         "Creative Commons Attribution Non Commercial 3.0 Unported",
50367         false,
50368         false
50369     ],
50370     "CC-BY-NC-4.0": [
50371         "Creative Commons Attribution Non Commercial 4.0 International",
50372         false,
50373         false
50374     ],
50375     "CC-BY-NC-ND-1.0": [
50376         "Creative Commons Attribution Non Commercial No Derivatives 1.0 Generic",
50377         false,
50378         false
50379     ],
50380     "CC-BY-NC-ND-2.0": [
50381         "Creative Commons Attribution Non Commercial No Derivatives 2.0 Generic",
50382         false,
50383         false
50384     ],
50385     "CC-BY-NC-ND-2.5": [
50386         "Creative Commons Attribution Non Commercial No Derivatives 2.5 Generic",
50387         false,
50388         false
50389     ],
50390     "CC-BY-NC-ND-3.0": [
50391         "Creative Commons Attribution Non Commercial No Derivatives 3.0 Unported",
50392         false,
50393         false
50394     ],
50395     "CC-BY-NC-ND-3.0-IGO": [
50396         "Creative Commons Attribution Non Commercial No Derivatives 3.0 IGO",
50397         false,
50398         false
50399     ],
50400     "CC-BY-NC-ND-4.0": [
50401         "Creative Commons Attribution Non Commercial No Derivatives 4.0 International",
50402         false,
50403         false
50404     ],
50405     "CC-BY-NC-SA-1.0": [
50406         "Creative Commons Attribution Non Commercial Share Alike 1.0 Generic",
50407         false,
50408         false
50409     ],
50410     "CC-BY-NC-SA-2.0": [
50411         "Creative Commons Attribution Non Commercial Share Alike 2.0 Generic",
50412         false,
50413         false
50414     ],
50415     "CC-BY-NC-SA-2.5": [
50416         "Creative Commons Attribution Non Commercial Share Alike 2.5 Generic",
50417         false,
50418         false
50419     ],
50420     "CC-BY-NC-SA-3.0": [
50421         "Creative Commons Attribution Non Commercial Share Alike 3.0 Unported",
50422         false,
50423         false
50424     ],
50425     "CC-BY-NC-SA-4.0": [
50426         "Creative Commons Attribution Non Commercial Share Alike 4.0 International",
50427         false,
50428         false
50429     ],
50430     "CC-BY-ND-1.0": [
50431         "Creative Commons Attribution No Derivatives 1.0 Generic",
50432         false,
50433         false
50434     ],
50435     "CC-BY-ND-2.0": [
50436         "Creative Commons Attribution No Derivatives 2.0 Generic",
50437         false,
50438         false
50439     ],
50440     "CC-BY-ND-2.5": [
50441         "Creative Commons Attribution No Derivatives 2.5 Generic",
50442         false,
50443         false
50444     ],
50445     "CC-BY-ND-3.0": [
50446         "Creative Commons Attribution No Derivatives 3.0 Unported",
50447         false,
50448         false
50449     ],
50450     "CC-BY-ND-4.0": [
50451         "Creative Commons Attribution No Derivatives 4.0 International",
50452         false,
50453         false
50454     ],
50455     "CC-BY-SA-1.0": [
50456         "Creative Commons Attribution Share Alike 1.0 Generic",
50457         false,
50458         false
50459     ],
50460     "CC-BY-SA-2.0": [
50461         "Creative Commons Attribution Share Alike 2.0 Generic",
50462         false,
50463         false
50464     ],
50465     "CC-BY-SA-2.0-UK": [
50466         "Creative Commons Attribution Share Alike 2.0 England and Wales",
50467         false,
50468         false
50469     ],
50470     "CC-BY-SA-2.5": [
50471         "Creative Commons Attribution Share Alike 2.5 Generic",
50472         false,
50473         false
50474     ],
50475     "CC-BY-SA-3.0": [
50476         "Creative Commons Attribution Share Alike 3.0 Unported",
50477         false,
50478         false
50479     ],
50480     "CC-BY-SA-3.0-AT": [
50481         "Creative Commons Attribution-Share Alike 3.0 Austria",
50482         false,
50483         false
50484     ],
50485     "CC-BY-SA-4.0": [
50486         "Creative Commons Attribution Share Alike 4.0 International",
50487         false,
50488         false
50489     ],
50490     "CC-PDDC": [
50491         "Creative Commons Public Domain Dedication and Certification",
50492         false,
50493         false
50494     ],
50495     "CC0-1.0": [
50496         "Creative Commons Zero v1.0 Universal",
50497         false,
50498         false
50499     ],
50500     "CDDL-1.0": [
50501         "Common Development and Distribution License 1.0",
50502         true,
50503         false
50504     ],
50505     "CDDL-1.1": [
50506         "Common Development and Distribution License 1.1",
50507         false,
50508         false
50509     ],
50510     "CDLA-Permissive-1.0": [
50511         "Community Data License Agreement Permissive 1.0",
50512         false,
50513         false
50514     ],
50515     "CDLA-Sharing-1.0": [
50516         "Community Data License Agreement Sharing 1.0",
50517         false,
50518         false
50519     ],
50520     "CECILL-1.0": [
50521         "CeCILL Free Software License Agreement v1.0",
50522         false,
50523         false
50524     ],
50525     "CECILL-1.1": [
50526         "CeCILL Free Software License Agreement v1.1",
50527         false,
50528         false
50529     ],
50530     "CECILL-2.0": [
50531         "CeCILL Free Software License Agreement v2.0",
50532         false,
50533         false
50534     ],
50535     "CECILL-2.1": [
50536         "CeCILL Free Software License Agreement v2.1",
50537         true,
50538         false
50539     ],
50540     "CECILL-B": [
50541         "CeCILL-B Free Software License Agreement",
50542         false,
50543         false
50544     ],
50545     "CECILL-C": [
50546         "CeCILL-C Free Software License Agreement",
50547         false,
50548         false
50549     ],
50550     "CERN-OHL-1.1": [
50551         "CERN Open Hardware Licence v1.1",
50552         false,
50553         false
50554     ],
50555     "CERN-OHL-1.2": [
50556         "CERN Open Hardware Licence v1.2",
50557         false,
50558         false
50559     ],
50560     "CERN-OHL-P-2.0": [
50561         "CERN Open Hardware Licence Version 2 - Permissive",
50562         false,
50563         false
50564     ],
50565     "CERN-OHL-S-2.0": [
50566         "CERN Open Hardware Licence Version 2 - Strongly Reciprocal",
50567         false,
50568         false
50569     ],
50570     "CERN-OHL-W-2.0": [
50571         "CERN Open Hardware Licence Version 2 - Weakly Reciprocal",
50572         false,
50573         false
50574     ],
50575     "ClArtistic": [
50576         "Clarified Artistic License",
50577         false,
50578         false
50579     ],
50580     "CNRI-Jython": [
50581         "CNRI Jython License",
50582         false,
50583         false
50584     ],
50585     "CNRI-Python": [
50586         "CNRI Python License",
50587         true,
50588         false
50589     ],
50590     "CNRI-Python-GPL-Compatible": [
50591         "CNRI Python Open Source GPL Compatible License Agreement",
50592         false,
50593         false
50594     ],
50595     "Condor-1.1": [
50596         "Condor Public License v1.1",
50597         false,
50598         false
50599     ],
50600     "copyleft-next-0.3.0": [
50601         "copyleft-next 0.3.0",
50602         false,
50603         false
50604     ],
50605     "copyleft-next-0.3.1": [
50606         "copyleft-next 0.3.1",
50607         false,
50608         false
50609     ],
50610     "CPAL-1.0": [
50611         "Common Public Attribution License 1.0",
50612         true,
50613         false
50614     ],
50615     "CPL-1.0": [
50616         "Common Public License 1.0",
50617         true,
50618         false
50619     ],
50620     "CPOL-1.02": [
50621         "Code Project Open License 1.02",
50622         false,
50623         false
50624     ],
50625     "Crossword": [
50626         "Crossword License",
50627         false,
50628         false
50629     ],
50630     "CrystalStacker": [
50631         "CrystalStacker License",
50632         false,
50633         false
50634     ],
50635     "CUA-OPL-1.0": [
50636         "CUA Office Public License v1.0",
50637         true,
50638         false
50639     ],
50640     "Cube": [
50641         "Cube License",
50642         false,
50643         false
50644     ],
50645     "curl": [
50646         "curl License",
50647         false,
50648         false
50649     ],
50650     "D-FSL-1.0": [
50651         "Deutsche Freie Software Lizenz",
50652         false,
50653         false
50654     ],
50655     "diffmark": [
50656         "diffmark license",
50657         false,
50658         false
50659     ],
50660     "DOC": [
50661         "DOC License",
50662         false,
50663         false
50664     ],
50665     "Dotseqn": [
50666         "Dotseqn License",
50667         false,
50668         false
50669     ],
50670     "DSDP": [
50671         "DSDP License",
50672         false,
50673         false
50674     ],
50675     "dvipdfm": [
50676         "dvipdfm License",
50677         false,
50678         false
50679     ],
50680     "ECL-1.0": [
50681         "Educational Community License v1.0",
50682         true,
50683         false
50684     ],
50685     "ECL-2.0": [
50686         "Educational Community License v2.0",
50687         true,
50688         false
50689     ],
50690     "eCos-2.0": [
50691         "eCos license version 2.0",
50692         false,
50693         true
50694     ],
50695     "EFL-1.0": [
50696         "Eiffel Forum License v1.0",
50697         true,
50698         false
50699     ],
50700     "EFL-2.0": [
50701         "Eiffel Forum License v2.0",
50702         true,
50703         false
50704     ],
50705     "eGenix": [
50706         "eGenix.com Public License 1.1.0",
50707         false,
50708         false
50709     ],
50710     "Entessa": [
50711         "Entessa Public License v1.0",
50712         true,
50713         false
50714     ],
50715     "EPICS": [
50716         "EPICS Open License",
50717         false,
50718         false
50719     ],
50720     "EPL-1.0": [
50721         "Eclipse Public License 1.0",
50722         true,
50723         false
50724     ],
50725     "EPL-2.0": [
50726         "Eclipse Public License 2.0",
50727         true,
50728         false
50729     ],
50730     "ErlPL-1.1": [
50731         "Erlang Public License v1.1",
50732         false,
50733         false
50734     ],
50735     "etalab-2.0": [
50736         "Etalab Open License 2.0",
50737         false,
50738         false
50739     ],
50740     "EUDatagrid": [
50741         "EU DataGrid Software License",
50742         true,
50743         false
50744     ],
50745     "EUPL-1.0": [
50746         "European Union Public License 1.0",
50747         false,
50748         false
50749     ],
50750     "EUPL-1.1": [
50751         "European Union Public License 1.1",
50752         true,
50753         false
50754     ],
50755     "EUPL-1.2": [
50756         "European Union Public License 1.2",
50757         true,
50758         false
50759     ],
50760     "Eurosym": [
50761         "Eurosym License",
50762         false,
50763         false
50764     ],
50765     "Fair": [
50766         "Fair License",
50767         true,
50768         false
50769     ],
50770     "Frameworx-1.0": [
50771         "Frameworx Open License 1.0",
50772         true,
50773         false
50774     ],
50775     "FreeImage": [
50776         "FreeImage Public License v1.0",
50777         false,
50778         false
50779     ],
50780     "FSFAP": [
50781         "FSF All Permissive License",
50782         false,
50783         false
50784     ],
50785     "FSFUL": [
50786         "FSF Unlimited License",
50787         false,
50788         false
50789     ],
50790     "FSFULLR": [
50791         "FSF Unlimited License (with License Retention)",
50792         false,
50793         false
50794     ],
50795     "FTL": [
50796         "Freetype Project License",
50797         false,
50798         false
50799     ],
50800     "GFDL-1.1": [
50801         "GNU Free Documentation License v1.1",
50802         false,
50803         true
50804     ],
50805     "GFDL-1.1-invariants-only": [
50806         "GNU Free Documentation License v1.1 only - invariants",
50807         false,
50808         false
50809     ],
50810     "GFDL-1.1-invariants-or-later": [
50811         "GNU Free Documentation License v1.1 or later - invariants",
50812         false,
50813         false
50814     ],
50815     "GFDL-1.1-no-invariants-only": [
50816         "GNU Free Documentation License v1.1 only - no invariants",
50817         false,
50818         false
50819     ],
50820     "GFDL-1.1-no-invariants-or-later": [
50821         "GNU Free Documentation License v1.1 or later - no invariants",
50822         false,
50823         false
50824     ],
50825     "GFDL-1.1-only": [
50826         "GNU Free Documentation License v1.1 only",
50827         false,
50828         false
50829     ],
50830     "GFDL-1.1-or-later": [
50831         "GNU Free Documentation License v1.1 or later",
50832         false,
50833         false
50834     ],
50835     "GFDL-1.2": [
50836         "GNU Free Documentation License v1.2",
50837         false,
50838         true
50839     ],
50840     "GFDL-1.2-invariants-only": [
50841         "GNU Free Documentation License v1.2 only - invariants",
50842         false,
50843         false
50844     ],
50845     "GFDL-1.2-invariants-or-later": [
50846         "GNU Free Documentation License v1.2 or later - invariants",
50847         false,
50848         false
50849     ],
50850     "GFDL-1.2-no-invariants-only": [
50851         "GNU Free Documentation License v1.2 only - no invariants",
50852         false,
50853         false
50854     ],
50855     "GFDL-1.2-no-invariants-or-later": [
50856         "GNU Free Documentation License v1.2 or later - no invariants",
50857         false,
50858         false
50859     ],
50860     "GFDL-1.2-only": [
50861         "GNU Free Documentation License v1.2 only",
50862         false,
50863         false
50864     ],
50865     "GFDL-1.2-or-later": [
50866         "GNU Free Documentation License v1.2 or later",
50867         false,
50868         false
50869     ],
50870     "GFDL-1.3": [
50871         "GNU Free Documentation License v1.3",
50872         false,
50873         true
50874     ],
50875     "GFDL-1.3-invariants-only": [
50876         "GNU Free Documentation License v1.3 only - invariants",
50877         false,
50878         false
50879     ],
50880     "GFDL-1.3-invariants-or-later": [
50881         "GNU Free Documentation License v1.3 or later - invariants",
50882         false,
50883         false
50884     ],
50885     "GFDL-1.3-no-invariants-only": [
50886         "GNU Free Documentation License v1.3 only - no invariants",
50887         false,
50888         false
50889     ],
50890     "GFDL-1.3-no-invariants-or-later": [
50891         "GNU Free Documentation License v1.3 or later - no invariants",
50892         false,
50893         false
50894     ],
50895     "GFDL-1.3-only": [
50896         "GNU Free Documentation License v1.3 only",
50897         false,
50898         false
50899     ],
50900     "GFDL-1.3-or-later": [
50901         "GNU Free Documentation License v1.3 or later",
50902         false,
50903         false
50904     ],
50905     "Giftware": [
50906         "Giftware License",
50907         false,
50908         false
50909     ],
50910     "GL2PS": [
50911         "GL2PS License",
50912         false,
50913         false
50914     ],
50915     "Glide": [
50916         "3dfx Glide License",
50917         false,
50918         false
50919     ],
50920     "Glulxe": [
50921         "Glulxe License",
50922         false,
50923         false
50924     ],
50925     "GLWTPL": [
50926         "Good Luck With That Public License",
50927         false,
50928         false
50929     ],
50930     "gnuplot": [
50931         "gnuplot License",
50932         false,
50933         false
50934     ],
50935     "GPL-1.0": [
50936         "GNU General Public License v1.0 only",
50937         false,
50938         true
50939     ],
50940     "GPL-1.0+": [
50941         "GNU General Public License v1.0 or later",
50942         false,
50943         true
50944     ],
50945     "GPL-1.0-only": [
50946         "GNU General Public License v1.0 only",
50947         false,
50948         false
50949     ],
50950     "GPL-1.0-or-later": [
50951         "GNU General Public License v1.0 or later",
50952         false,
50953         false
50954     ],
50955     "GPL-2.0": [
50956         "GNU General Public License v2.0 only",
50957         true,
50958         true
50959     ],
50960     "GPL-2.0+": [
50961         "GNU General Public License v2.0 or later",
50962         true,
50963         true
50964     ],
50965     "GPL-2.0-only": [
50966         "GNU General Public License v2.0 only",
50967         true,
50968         false
50969     ],
50970     "GPL-2.0-or-later": [
50971         "GNU General Public License v2.0 or later",
50972         true,
50973         false
50974     ],
50975     "GPL-2.0-with-autoconf-exception": [
50976         "GNU General Public License v2.0 w/Autoconf exception",
50977         false,
50978         true
50979     ],
50980     "GPL-2.0-with-bison-exception": [
50981         "GNU General Public License v2.0 w/Bison exception",
50982         false,
50983         true
50984     ],
50985     "GPL-2.0-with-classpath-exception": [
50986         "GNU General Public License v2.0 w/Classpath exception",
50987         false,
50988         true
50989     ],
50990     "GPL-2.0-with-font-exception": [
50991         "GNU General Public License v2.0 w/Font exception",
50992         false,
50993         true
50994     ],
50995     "GPL-2.0-with-GCC-exception": [
50996         "GNU General Public License v2.0 w/GCC Runtime Library exception",
50997         false,
50998         true
50999     ],
51000     "GPL-3.0": [
51001         "GNU General Public License v3.0 only",
51002         true,
51003         true
51004     ],
51005     "GPL-3.0+": [
51006         "GNU General Public License v3.0 or later",
51007         true,
51008         true
51009     ],
51010     "GPL-3.0-only": [
51011         "GNU General Public License v3.0 only",
51012         true,
51013         false
51014     ],
51015     "GPL-3.0-or-later": [
51016         "GNU General Public License v3.0 or later",
51017         true,
51018         false
51019     ],
51020     "GPL-3.0-with-autoconf-exception": [
51021         "GNU General Public License v3.0 w/Autoconf exception",
51022         false,
51023         true
51024     ],
51025     "GPL-3.0-with-GCC-exception": [
51026         "GNU General Public License v3.0 w/GCC Runtime Library exception",
51027         true,
51028         true
51029     ],
51030     "gSOAP-1.3b": [
51031         "gSOAP Public License v1.3b",
51032         false,
51033         false
51034     ],
51035     "HaskellReport": [
51036         "Haskell Language Report License",
51037         false,
51038         false
51039     ],
51040     "Hippocratic-2.1": [
51041         "Hippocratic License 2.1",
51042         false,
51043         false
51044     ],
51045     "HPND": [
51046         "Historical Permission Notice and Disclaimer",
51047         true,
51048         false
51049     ],
51050     "HPND-sell-variant": [
51051         "Historical Permission Notice and Disclaimer - sell variant",
51052         false,
51053         false
51054     ],
51055     "HTMLTIDY": [
51056         "HTML Tidy License",
51057         false,
51058         false
51059     ],
51060     "IBM-pibs": [
51061         "IBM PowerPC Initialization and Boot Software",
51062         false,
51063         false
51064     ],
51065     "ICU": [
51066         "ICU License",
51067         false,
51068         false
51069     ],
51070     "IJG": [
51071         "Independent JPEG Group License",
51072         false,
51073         false
51074     ],
51075     "ImageMagick": [
51076         "ImageMagick License",
51077         false,
51078         false
51079     ],
51080     "iMatix": [
51081         "iMatix Standard Function Library Agreement",
51082         false,
51083         false
51084     ],
51085     "Imlib2": [
51086         "Imlib2 License",
51087         false,
51088         false
51089     ],
51090     "Info-ZIP": [
51091         "Info-ZIP License",
51092         false,
51093         false
51094     ],
51095     "Intel": [
51096         "Intel Open Source License",
51097         true,
51098         false
51099     ],
51100     "Intel-ACPI": [
51101         "Intel ACPI Software License Agreement",
51102         false,
51103         false
51104     ],
51105     "Interbase-1.0": [
51106         "Interbase Public License v1.0",
51107         false,
51108         false
51109     ],
51110     "IPA": [
51111         "IPA Font License",
51112         true,
51113         false
51114     ],
51115     "IPL-1.0": [
51116         "IBM Public License v1.0",
51117         true,
51118         false
51119     ],
51120     "ISC": [
51121         "ISC License",
51122         true,
51123         false
51124     ],
51125     "JasPer-2.0": [
51126         "JasPer License",
51127         false,
51128         false
51129     ],
51130     "JPNIC": [
51131         "Japan Network Information Center License",
51132         false,
51133         false
51134     ],
51135     "JSON": [
51136         "JSON License",
51137         false,
51138         false
51139     ],
51140     "LAL-1.2": [
51141         "Licence Art Libre 1.2",
51142         false,
51143         false
51144     ],
51145     "LAL-1.3": [
51146         "Licence Art Libre 1.3",
51147         false,
51148         false
51149     ],
51150     "Latex2e": [
51151         "Latex2e License",
51152         false,
51153         false
51154     ],
51155     "Leptonica": [
51156         "Leptonica License",
51157         false,
51158         false
51159     ],
51160     "LGPL-2.0": [
51161         "GNU Library General Public License v2 only",
51162         true,
51163         true
51164     ],
51165     "LGPL-2.0+": [
51166         "GNU Library General Public License v2 or later",
51167         true,
51168         true
51169     ],
51170     "LGPL-2.0-only": [
51171         "GNU Library General Public License v2 only",
51172         true,
51173         false
51174     ],
51175     "LGPL-2.0-or-later": [
51176         "GNU Library General Public License v2 or later",
51177         true,
51178         false
51179     ],
51180     "LGPL-2.1": [
51181         "GNU Lesser General Public License v2.1 only",
51182         true,
51183         true
51184     ],
51185     "LGPL-2.1+": [
51186         "GNU Library General Public License v2.1 or later",
51187         true,
51188         true
51189     ],
51190     "LGPL-2.1-only": [
51191         "GNU Lesser General Public License v2.1 only",
51192         true,
51193         false
51194     ],
51195     "LGPL-2.1-or-later": [
51196         "GNU Lesser General Public License v2.1 or later",
51197         true,
51198         false
51199     ],
51200     "LGPL-3.0": [
51201         "GNU Lesser General Public License v3.0 only",
51202         true,
51203         true
51204     ],
51205     "LGPL-3.0+": [
51206         "GNU Lesser General Public License v3.0 or later",
51207         true,
51208         true
51209     ],
51210     "LGPL-3.0-only": [
51211         "GNU Lesser General Public License v3.0 only",
51212         true,
51213         false
51214     ],
51215     "LGPL-3.0-or-later": [
51216         "GNU Lesser General Public License v3.0 or later",
51217         true,
51218         false
51219     ],
51220     "LGPLLR": [
51221         "Lesser General Public License For Linguistic Resources",
51222         false,
51223         false
51224     ],
51225     "Libpng": [
51226         "libpng License",
51227         false,
51228         false
51229     ],
51230     "libpng-2.0": [
51231         "PNG Reference Library version 2",
51232         false,
51233         false
51234     ],
51235     "libselinux-1.0": [
51236         "libselinux public domain notice",
51237         false,
51238         false
51239     ],
51240     "libtiff": [
51241         "libtiff License",
51242         false,
51243         false
51244     ],
51245     "LiLiQ-P-1.1": [
51246         "Licence Libre du Qu\u00e9bec \u2013 Permissive version 1.1",
51247         true,
51248         false
51249     ],
51250     "LiLiQ-R-1.1": [
51251         "Licence Libre du Qu\u00e9bec \u2013 R\u00e9ciprocit\u00e9 version 1.1",
51252         true,
51253         false
51254     ],
51255     "LiLiQ-Rplus-1.1": [
51256         "Licence Libre du Qu\u00e9bec \u2013 R\u00e9ciprocit\u00e9 forte version 1.1",
51257         true,
51258         false
51259     ],
51260     "Linux-OpenIB": [
51261         "Linux Kernel Variant of OpenIB.org license",
51262         false,
51263         false
51264     ],
51265     "LPL-1.0": [
51266         "Lucent Public License Version 1.0",
51267         true,
51268         false
51269     ],
51270     "LPL-1.02": [
51271         "Lucent Public License v1.02",
51272         true,
51273         false
51274     ],
51275     "LPPL-1.0": [
51276         "LaTeX Project Public License v1.0",
51277         false,
51278         false
51279     ],
51280     "LPPL-1.1": [
51281         "LaTeX Project Public License v1.1",
51282         false,
51283         false
51284     ],
51285     "LPPL-1.2": [
51286         "LaTeX Project Public License v1.2",
51287         false,
51288         false
51289     ],
51290     "LPPL-1.3a": [
51291         "LaTeX Project Public License v1.3a",
51292         false,
51293         false
51294     ],
51295     "LPPL-1.3c": [
51296         "LaTeX Project Public License v1.3c",
51297         true,
51298         false
51299     ],
51300     "MakeIndex": [
51301         "MakeIndex License",
51302         false,
51303         false
51304     ],
51305     "MirOS": [
51306         "The MirOS Licence",
51307         true,
51308         false
51309     ],
51310     "MIT": [
51311         "MIT License",
51312         true,
51313         false
51314     ],
51315     "MIT-0": [
51316         "MIT No Attribution",
51317         true,
51318         false
51319     ],
51320     "MIT-advertising": [
51321         "Enlightenment License (e16)",
51322         false,
51323         false
51324     ],
51325     "MIT-CMU": [
51326         "CMU License",
51327         false,
51328         false
51329     ],
51330     "MIT-enna": [
51331         "enna License",
51332         false,
51333         false
51334     ],
51335     "MIT-feh": [
51336         "feh License",
51337         false,
51338         false
51339     ],
51340     "MIT-open-group": [
51341         "MIT Open Group variant",
51342         false,
51343         false
51344     ],
51345     "MITNFA": [
51346         "MIT +no-false-attribs license",
51347         false,
51348         false
51349     ],
51350     "Motosoto": [
51351         "Motosoto License",
51352         true,
51353         false
51354     ],
51355     "mpich2": [
51356         "mpich2 License",
51357         false,
51358         false
51359     ],
51360     "MPL-1.0": [
51361         "Mozilla Public License 1.0",
51362         true,
51363         false
51364     ],
51365     "MPL-1.1": [
51366         "Mozilla Public License 1.1",
51367         true,
51368         false
51369     ],
51370     "MPL-2.0": [
51371         "Mozilla Public License 2.0",
51372         true,
51373         false
51374     ],
51375     "MPL-2.0-no-copyleft-exception": [
51376         "Mozilla Public License 2.0 (no copyleft exception)",
51377         true,
51378         false
51379     ],
51380     "MS-PL": [
51381         "Microsoft Public License",
51382         true,
51383         false
51384     ],
51385     "MS-RL": [
51386         "Microsoft Reciprocal License",
51387         true,
51388         false
51389     ],
51390     "MTLL": [
51391         "Matrix Template Library License",
51392         false,
51393         false
51394     ],
51395     "MulanPSL-1.0": [
51396         "Mulan Permissive Software License, Version 1",
51397         false,
51398         false
51399     ],
51400     "MulanPSL-2.0": [
51401         "Mulan Permissive Software License, Version 2",
51402         true,
51403         false
51404     ],
51405     "Multics": [
51406         "Multics License",
51407         true,
51408         false
51409     ],
51410     "Mup": [
51411         "Mup License",
51412         false,
51413         false
51414     ],
51415     "NASA-1.3": [
51416         "NASA Open Source Agreement 1.3",
51417         true,
51418         false
51419     ],
51420     "Naumen": [
51421         "Naumen Public License",
51422         true,
51423         false
51424     ],
51425     "NBPL-1.0": [
51426         "Net Boolean Public License v1",
51427         false,
51428         false
51429     ],
51430     "NCGL-UK-2.0": [
51431         "Non-Commercial Government Licence",
51432         false,
51433         false
51434     ],
51435     "NCSA": [
51436         "University of Illinois/NCSA Open Source License",
51437         true,
51438         false
51439     ],
51440     "Net-SNMP": [
51441         "Net-SNMP License",
51442         false,
51443         false
51444     ],
51445     "NetCDF": [
51446         "NetCDF license",
51447         false,
51448         false
51449     ],
51450     "Newsletr": [
51451         "Newsletr License",
51452         false,
51453         false
51454     ],
51455     "NGPL": [
51456         "Nethack General Public License",
51457         true,
51458         false
51459     ],
51460     "NIST-PD": [
51461         "NIST Public Domain Notice",
51462         false,
51463         false
51464     ],
51465     "NIST-PD-fallback": [
51466         "NIST Public Domain Notice with license fallback",
51467         false,
51468         false
51469     ],
51470     "NLOD-1.0": [
51471         "Norwegian Licence for Open Government Data",
51472         false,
51473         false
51474     ],
51475     "NLPL": [
51476         "No Limit Public License",
51477         false,
51478         false
51479     ],
51480     "Nokia": [
51481         "Nokia Open Source License",
51482         true,
51483         false
51484     ],
51485     "NOSL": [
51486         "Netizen Open Source License",
51487         false,
51488         false
51489     ],
51490     "Noweb": [
51491         "Noweb License",
51492         false,
51493         false
51494     ],
51495     "NPL-1.0": [
51496         "Netscape Public License v1.0",
51497         false,
51498         false
51499     ],
51500     "NPL-1.1": [
51501         "Netscape Public License v1.1",
51502         false,
51503         false
51504     ],
51505     "NPOSL-3.0": [
51506         "Non-Profit Open Software License 3.0",
51507         true,
51508         false
51509     ],
51510     "NRL": [
51511         "NRL License",
51512         false,
51513         false
51514     ],
51515     "NTP": [
51516         "NTP License",
51517         true,
51518         false
51519     ],
51520     "NTP-0": [
51521         "NTP No Attribution",
51522         false,
51523         false
51524     ],
51525     "Nunit": [
51526         "Nunit License",
51527         false,
51528         true
51529     ],
51530     "O-UDA-1.0": [
51531         "Open Use of Data Agreement v1.0",
51532         false,
51533         false
51534     ],
51535     "OCCT-PL": [
51536         "Open CASCADE Technology Public License",
51537         false,
51538         false
51539     ],
51540     "OCLC-2.0": [
51541         "OCLC Research Public License 2.0",
51542         true,
51543         false
51544     ],
51545     "ODbL-1.0": [
51546         "ODC Open Database License v1.0",
51547         false,
51548         false
51549     ],
51550     "ODC-By-1.0": [
51551         "Open Data Commons Attribution License v1.0",
51552         false,
51553         false
51554     ],
51555     "OFL-1.0": [
51556         "SIL Open Font License 1.0",
51557         false,
51558         false
51559     ],
51560     "OFL-1.0-no-RFN": [
51561         "SIL Open Font License 1.0 with no Reserved Font Name",
51562         false,
51563         false
51564     ],
51565     "OFL-1.0-RFN": [
51566         "SIL Open Font License 1.0 with Reserved Font Name",
51567         false,
51568         false
51569     ],
51570     "OFL-1.1": [
51571         "SIL Open Font License 1.1",
51572         true,
51573         false
51574     ],
51575     "OFL-1.1-no-RFN": [
51576         "SIL Open Font License 1.1 with no Reserved Font Name",
51577         true,
51578         false
51579     ],
51580     "OFL-1.1-RFN": [
51581         "SIL Open Font License 1.1 with Reserved Font Name",
51582         true,
51583         false
51584     ],
51585     "OGC-1.0": [
51586         "OGC Software License, Version 1.0",
51587         false,
51588         false
51589     ],
51590     "OGL-Canada-2.0": [
51591         "Open Government Licence - Canada",
51592         false,
51593         false
51594     ],
51595     "OGL-UK-1.0": [
51596         "Open Government Licence v1.0",
51597         false,
51598         false
51599     ],
51600     "OGL-UK-2.0": [
51601         "Open Government Licence v2.0",
51602         false,
51603         false
51604     ],
51605     "OGL-UK-3.0": [
51606         "Open Government Licence v3.0",
51607         false,
51608         false
51609     ],
51610     "OGTSL": [
51611         "Open Group Test Suite License",
51612         true,
51613         false
51614     ],
51615     "OLDAP-1.1": [
51616         "Open LDAP Public License v1.1",
51617         false,
51618         false
51619     ],
51620     "OLDAP-1.2": [
51621         "Open LDAP Public License v1.2",
51622         false,
51623         false
51624     ],
51625     "OLDAP-1.3": [
51626         "Open LDAP Public License v1.3",
51627         false,
51628         false
51629     ],
51630     "OLDAP-1.4": [
51631         "Open LDAP Public License v1.4",
51632         false,
51633         false
51634     ],
51635     "OLDAP-2.0": [
51636         "Open LDAP Public License v2.0 (or possibly 2.0A and 2.0B)",
51637         false,
51638         false
51639     ],
51640     "OLDAP-2.0.1": [
51641         "Open LDAP Public License v2.0.1",
51642         false,
51643         false
51644     ],
51645     "OLDAP-2.1": [
51646         "Open LDAP Public License v2.1",
51647         false,
51648         false
51649     ],
51650     "OLDAP-2.2": [
51651         "Open LDAP Public License v2.2",
51652         false,
51653         false
51654     ],
51655     "OLDAP-2.2.1": [
51656         "Open LDAP Public License v2.2.1",
51657         false,
51658         false
51659     ],
51660     "OLDAP-2.2.2": [
51661         "Open LDAP Public License 2.2.2",
51662         false,
51663         false
51664     ],
51665     "OLDAP-2.3": [
51666         "Open LDAP Public License v2.3",
51667         false,
51668         false
51669     ],
51670     "OLDAP-2.4": [
51671         "Open LDAP Public License v2.4",
51672         false,
51673         false
51674     ],
51675     "OLDAP-2.5": [
51676         "Open LDAP Public License v2.5",
51677         false,
51678         false
51679     ],
51680     "OLDAP-2.6": [
51681         "Open LDAP Public License v2.6",
51682         false,
51683         false
51684     ],
51685     "OLDAP-2.7": [
51686         "Open LDAP Public License v2.7",
51687         false,
51688         false
51689     ],
51690     "OLDAP-2.8": [
51691         "Open LDAP Public License v2.8",
51692         true,
51693         false
51694     ],
51695     "OML": [
51696         "Open Market License",
51697         false,
51698         false
51699     ],
51700     "OpenSSL": [
51701         "OpenSSL License",
51702         false,
51703         false
51704     ],
51705     "OPL-1.0": [
51706         "Open Public License v1.0",
51707         false,
51708         false
51709     ],
51710     "OSET-PL-2.1": [
51711         "OSET Public License version 2.1",
51712         true,
51713         false
51714     ],
51715     "OSL-1.0": [
51716         "Open Software License 1.0",
51717         true,
51718         false
51719     ],
51720     "OSL-1.1": [
51721         "Open Software License 1.1",
51722         false,
51723         false
51724     ],
51725     "OSL-2.0": [
51726         "Open Software License 2.0",
51727         true,
51728         false
51729     ],
51730     "OSL-2.1": [
51731         "Open Software License 2.1",
51732         true,
51733         false
51734     ],
51735     "OSL-3.0": [
51736         "Open Software License 3.0",
51737         true,
51738         false
51739     ],
51740     "Parity-6.0.0": [
51741         "The Parity Public License 6.0.0",
51742         false,
51743         false
51744     ],
51745     "Parity-7.0.0": [
51746         "The Parity Public License 7.0.0",
51747         false,
51748         false
51749     ],
51750     "PDDL-1.0": [
51751         "ODC Public Domain Dedication & License 1.0",
51752         false,
51753         false
51754     ],
51755     "PHP-3.0": [
51756         "PHP License v3.0",
51757         true,
51758         false
51759     ],
51760     "PHP-3.01": [
51761         "PHP License v3.01",
51762         true,
51763         false
51764     ],
51765     "Plexus": [
51766         "Plexus Classworlds License",
51767         false,
51768         false
51769     ],
51770     "PolyForm-Noncommercial-1.0.0": [
51771         "PolyForm Noncommercial License 1.0.0",
51772         false,
51773         false
51774     ],
51775     "PolyForm-Small-Business-1.0.0": [
51776         "PolyForm Small Business License 1.0.0",
51777         false,
51778         false
51779     ],
51780     "PostgreSQL": [
51781         "PostgreSQL License",
51782         true,
51783         false
51784     ],
51785     "PSF-2.0": [
51786         "Python Software Foundation License 2.0",
51787         false,
51788         false
51789     ],
51790     "psfrag": [
51791         "psfrag License",
51792         false,
51793         false
51794     ],
51795     "psutils": [
51796         "psutils License",
51797         false,
51798         false
51799     ],
51800     "Python-2.0": [
51801         "Python License 2.0",
51802         true,
51803         false
51804     ],
51805     "Qhull": [
51806         "Qhull License",
51807         false,
51808         false
51809     ],
51810     "QPL-1.0": [
51811         "Q Public License 1.0",
51812         true,
51813         false
51814     ],
51815     "Rdisc": [
51816         "Rdisc License",
51817         false,
51818         false
51819     ],
51820     "RHeCos-1.1": [
51821         "Red Hat eCos Public License v1.1",
51822         false,
51823         false
51824     ],
51825     "RPL-1.1": [
51826         "Reciprocal Public License 1.1",
51827         true,
51828         false
51829     ],
51830     "RPL-1.5": [
51831         "Reciprocal Public License 1.5",
51832         true,
51833         false
51834     ],
51835     "RPSL-1.0": [
51836         "RealNetworks Public Source License v1.0",
51837         true,
51838         false
51839     ],
51840     "RSA-MD": [
51841         "RSA Message-Digest License",
51842         false,
51843         false
51844     ],
51845     "RSCPL": [
51846         "Ricoh Source Code Public License",
51847         true,
51848         false
51849     ],
51850     "Ruby": [
51851         "Ruby License",
51852         false,
51853         false
51854     ],
51855     "SAX-PD": [
51856         "Sax Public Domain Notice",
51857         false,
51858         false
51859     ],
51860     "Saxpath": [
51861         "Saxpath License",
51862         false,
51863         false
51864     ],
51865     "SCEA": [
51866         "SCEA Shared Source License",
51867         false,
51868         false
51869     ],
51870     "Sendmail": [
51871         "Sendmail License",
51872         false,
51873         false
51874     ],
51875     "Sendmail-8.23": [
51876         "Sendmail License 8.23",
51877         false,
51878         false
51879     ],
51880     "SGI-B-1.0": [
51881         "SGI Free Software License B v1.0",
51882         false,
51883         false
51884     ],
51885     "SGI-B-1.1": [
51886         "SGI Free Software License B v1.1",
51887         false,
51888         false
51889     ],
51890     "SGI-B-2.0": [
51891         "SGI Free Software License B v2.0",
51892         false,
51893         false
51894     ],
51895     "SHL-0.5": [
51896         "Solderpad Hardware License v0.5",
51897         false,
51898         false
51899     ],
51900     "SHL-0.51": [
51901         "Solderpad Hardware License, Version 0.51",
51902         false,
51903         false
51904     ],
51905     "SimPL-2.0": [
51906         "Simple Public License 2.0",
51907         true,
51908         false
51909     ],
51910     "SISSL": [
51911         "Sun Industry Standards Source License v1.1",
51912         true,
51913         false
51914     ],
51915     "SISSL-1.2": [
51916         "Sun Industry Standards Source License v1.2",
51917         false,
51918         false
51919     ],
51920     "Sleepycat": [
51921         "Sleepycat License",
51922         true,
51923         false
51924     ],
51925     "SMLNJ": [
51926         "Standard ML of New Jersey License",
51927         false,
51928         false
51929     ],
51930     "SMPPL": [
51931         "Secure Messaging Protocol Public License",
51932         false,
51933         false
51934     ],
51935     "SNIA": [
51936         "SNIA Public License 1.1",
51937         false,
51938         false
51939     ],
51940     "Spencer-86": [
51941         "Spencer License 86",
51942         false,
51943         false
51944     ],
51945     "Spencer-94": [
51946         "Spencer License 94",
51947         false,
51948         false
51949     ],
51950     "Spencer-99": [
51951         "Spencer License 99",
51952         false,
51953         false
51954     ],
51955     "SPL-1.0": [
51956         "Sun Public License v1.0",
51957         true,
51958         false
51959     ],
51960     "SSH-OpenSSH": [
51961         "SSH OpenSSH license",
51962         false,
51963         false
51964     ],
51965     "SSH-short": [
51966         "SSH short notice",
51967         false,
51968         false
51969     ],
51970     "SSPL-1.0": [
51971         "Server Side Public License, v 1",
51972         false,
51973         false
51974     ],
51975     "StandardML-NJ": [
51976         "Standard ML of New Jersey License",
51977         false,
51978         true
51979     ],
51980     "SugarCRM-1.1.3": [
51981         "SugarCRM Public License v1.1.3",
51982         false,
51983         false
51984     ],
51985     "SWL": [
51986         "Scheme Widget Library (SWL) Software License Agreement",
51987         false,
51988         false
51989     ],
51990     "TAPR-OHL-1.0": [
51991         "TAPR Open Hardware License v1.0",
51992         false,
51993         false
51994     ],
51995     "TCL": [
51996         "TCL/TK License",
51997         false,
51998         false
51999     ],
52000     "TCP-wrappers": [
52001         "TCP Wrappers License",
52002         false,
52003         false
52004     ],
52005     "TMate": [
52006         "TMate Open Source License",
52007         false,
52008         false
52009     ],
52010     "TORQUE-1.1": [
52011         "TORQUE v2.5+ Software License v1.1",
52012         false,
52013         false
52014     ],
52015     "TOSL": [
52016         "Trusster Open Source License",
52017         false,
52018         false
52019     ],
52020     "TU-Berlin-1.0": [
52021         "Technische Universitaet Berlin License 1.0",
52022         false,
52023         false
52024     ],
52025     "TU-Berlin-2.0": [
52026         "Technische Universitaet Berlin License 2.0",
52027         false,
52028         false
52029     ],
52030     "UCL-1.0": [
52031         "Upstream Compatibility License v1.0",
52032         true,
52033         false
52034     ],
52035     "Unicode-DFS-2015": [
52036         "Unicode License Agreement - Data Files and Software (2015)",
52037         false,
52038         false
52039     ],
52040     "Unicode-DFS-2016": [
52041         "Unicode License Agreement - Data Files and Software (2016)",
52042         true,
52043         false
52044     ],
52045     "Unicode-TOU": [
52046         "Unicode Terms of Use",
52047         false,
52048         false
52049     ],
52050     "Unlicense": [
52051         "The Unlicense",
52052         true,
52053         false
52054     ],
52055     "UPL-1.0": [
52056         "Universal Permissive License v1.0",
52057         true,
52058         false
52059     ],
52060     "Vim": [
52061         "Vim License",
52062         false,
52063         false
52064     ],
52065     "VOSTROM": [
52066         "VOSTROM Public License for Open Source",
52067         false,
52068         false
52069     ],
52070     "VSL-1.0": [
52071         "Vovida Software License v1.0",
52072         true,
52073         false
52074     ],
52075     "W3C": [
52076         "W3C Software Notice and License (2002-12-31)",
52077         true,
52078         false
52079     ],
52080     "W3C-19980720": [
52081         "W3C Software Notice and License (1998-07-20)",
52082         false,
52083         false
52084     ],
52085     "W3C-20150513": [
52086         "W3C Software Notice and Document License (2015-05-13)",
52087         false,
52088         false
52089     ],
52090     "Watcom-1.0": [
52091         "Sybase Open Watcom Public License 1.0",
52092         true,
52093         false
52094     ],
52095     "Wsuipa": [
52096         "Wsuipa License",
52097         false,
52098         false
52099     ],
52100     "WTFPL": [
52101         "Do What The F*ck You Want To Public License",
52102         false,
52103         false
52104     ],
52105     "wxWindows": [
52106         "wxWindows Library License",
52107         false,
52108         true
52109     ],
52110     "X11": [
52111         "X11 License",
52112         false,
52113         false
52114     ],
52115     "Xerox": [
52116         "Xerox License",
52117         false,
52118         false
52119     ],
52120     "XFree86-1.1": [
52121         "XFree86 License 1.1",
52122         false,
52123         false
52124     ],
52125     "xinetd": [
52126         "xinetd License",
52127         false,
52128         false
52129     ],
52130     "Xnet": [
52131         "X.Net License",
52132         true,
52133         false
52134     ],
52135     "xpp": [
52136         "XPP License",
52137         false,
52138         false
52139     ],
52140     "XSkat": [
52141         "XSkat License",
52142         false,
52143         false
52144     ],
52145     "YPL-1.0": [
52146         "Yahoo! Public License v1.0",
52147         false,
52148         false
52149     ],
52150     "YPL-1.1": [
52151         "Yahoo! Public License v1.1",
52152         false,
52153         false
52154     ],
52155     "Zed": [
52156         "Zed License",
52157         false,
52158         false
52159     ],
52160     "Zend-2.0": [
52161         "Zend License v2.0",
52162         false,
52163         false
52164     ],
52165     "Zimbra-1.3": [
52166         "Zimbra Public License v1.3",
52167         false,
52168         false
52169     ],
52170     "Zimbra-1.4": [
52171         "Zimbra Public License v1.4",
52172         false,
52173         false
52174     ],
52175     "Zlib": [
52176         "zlib License",
52177         true,
52178         false
52179     ],
52180     "zlib-acknowledgement": [
52181         "zlib/libpng License with Acknowledgement",
52182         false,
52183         false
52184     ],
52185     "ZPL-1.1": [
52186         "Zope Public License 1.1",
52187         false,
52188         false
52189     ],
52190     "ZPL-2.0": [
52191         "Zope Public License 2.0",
52192         true,
52193         false
52194     ],
52195     "ZPL-2.1": [
52196         "Zope Public License 2.1",
52197         false,
52198         false
52199     ]
52200 }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
52201 $\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
52202 \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
52203 \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
52204 \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
52205 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
52206 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
52207 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
52208   <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">\r
52209     <security>\r
52210       <requestedPrivileges>\r
52211         <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>\r
52212       </requestedPrivileges>\r
52213     </security>\r
52214   </trustInfo>\r
52215   <dependency>\r
52216     <dependentAssembly>\r
52217       <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.21022.8" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>\r
52218     </dependentAssembly>\r
52219   </dependency>\r
52220 </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
52221
52222 /*
52223  * This file is part of the Symfony package.
52224  *
52225  * (c) Fabien Potencier <fabien@symfony.com>
52226  *
52227  * For the full copyright and license information, please view the LICENSE
52228  * file that was distributed with this source code.
52229  */
52230
52231 use Symfony\Polyfill\Mbstring as p;
52232
52233 if (!function_exists('mb_convert_variables')) {
52234     /**
52235      * Convert character code in variable(s)
52236      */
52237     function mb_convert_variables($to_encoding, $from_encoding, &$var, &...$vars)
52238     {
52239         $vars = [&$var, ...$vars];
52240
52241         $ok = true;
52242         array_walk_recursive($vars, function (&$v) use (&$ok, $to_encoding, $from_encoding) {
52243             if (false === $v = p\Mbstring::mb_convert_encoding($v, $to_encoding, $from_encoding)) {
52244                 $ok = false;
52245             }
52246         });
52247
52248         return $ok ? $from_encoding : false;
52249     }
52250 }
52251 <?php
52252
52253
52254
52255
52256
52257
52258
52259
52260
52261
52262 namespace Symfony\Component\Console;
52263
52264 use Symfony\Component\Console\Command\Command;
52265 use Symfony\Component\Console\Command\HelpCommand;
52266 use Symfony\Component\Console\Command\ListCommand;
52267 use Symfony\Component\Console\Descriptor\TextDescriptor;
52268 use Symfony\Component\Console\Descriptor\XmlDescriptor;
52269 use Symfony\Component\Console\Event\ConsoleCommandEvent;
52270 use Symfony\Component\Console\Event\ConsoleExceptionEvent;
52271 use Symfony\Component\Console\Event\ConsoleTerminateEvent;
52272 use Symfony\Component\Console\Exception\CommandNotFoundException;
52273 use Symfony\Component\Console\Exception\ExceptionInterface;
52274 use Symfony\Component\Console\Exception\LogicException;
52275 use Symfony\Component\Console\Formatter\OutputFormatter;
52276 use Symfony\Component\Console\Helper\DebugFormatterHelper;
52277 use Symfony\Component\Console\Helper\DialogHelper;
52278 use Symfony\Component\Console\Helper\FormatterHelper;
52279 use Symfony\Component\Console\Helper\Helper;
52280 use Symfony\Component\Console\Helper\HelperSet;
52281 use Symfony\Component\Console\Helper\ProcessHelper;
52282 use Symfony\Component\Console\Helper\ProgressHelper;
52283 use Symfony\Component\Console\Helper\QuestionHelper;
52284 use Symfony\Component\Console\Helper\TableHelper;
52285 use Symfony\Component\Console\Input\ArgvInput;
52286 use Symfony\Component\Console\Input\ArrayInput;
52287 use Symfony\Component\Console\Input\InputArgument;
52288 use Symfony\Component\Console\Input\InputAwareInterface;
52289 use Symfony\Component\Console\Input\InputDefinition;
52290 use Symfony\Component\Console\Input\InputInterface;
52291 use Symfony\Component\Console\Input\InputOption;
52292 use Symfony\Component\Console\Output\BufferedOutput;
52293 use Symfony\Component\Console\Output\ConsoleOutput;
52294 use Symfony\Component\Console\Output\ConsoleOutputInterface;
52295 use Symfony\Component\Console\Output\OutputInterface;
52296 use Symfony\Component\Debug\Exception\FatalThrowableError;
52297 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
52298
52299
52300
52301
52302
52303
52304
52305
52306
52307
52308
52309
52310
52311
52312
52313
52314 class Application
52315 {
52316 private $commands = array();
52317 private $wantHelps = false;
52318 private $runningCommand;
52319 private $name;
52320 private $version;
52321 private $catchExceptions = true;
52322 private $autoExit = true;
52323 private $definition;
52324 private $helperSet;
52325 private $dispatcher;
52326 private $terminalDimensions;
52327 private $defaultCommand;
52328 private $initialized;
52329
52330
52331
52332
52333
52334 public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
52335 {
52336 $this->name = $name;
52337 $this->version = $version;
52338 $this->defaultCommand = 'list';
52339 }
52340
52341 public function setDispatcher(EventDispatcherInterface $dispatcher)
52342 {
52343 $this->dispatcher = $dispatcher;
52344 }
52345
52346
52347
52348
52349
52350
52351
52352
52353 public function run(InputInterface $input = null, OutputInterface $output = null)
52354 {
52355 if (null === $input) {
52356 $input = new ArgvInput();
52357 }
52358
52359 if (null === $output) {
52360 $output = new ConsoleOutput();
52361 }
52362
52363 $this->configureIO($input, $output);
52364
52365 try {
52366 $e = null;
52367 $exitCode = $this->doRun($input, $output);
52368 } catch (\Exception $e) {
52369 }
52370
52371 if (null !== $e) {
52372 if (!$this->catchExceptions) {
52373 throw $e;
52374 }
52375
52376 if ($output instanceof ConsoleOutputInterface) {
52377 $this->renderException($e, $output->getErrorOutput());
52378 } else {
52379 $this->renderException($e, $output);
52380 }
52381
52382 $exitCode = $this->getExitCodeForThrowable($e);
52383 }
52384
52385 if ($this->autoExit) {
52386 if ($exitCode > 255) {
52387 $exitCode = 255;
52388 }
52389
52390 exit($exitCode);
52391 }
52392
52393 return $exitCode;
52394 }
52395
52396
52397
52398
52399
52400
52401 public function doRun(InputInterface $input, OutputInterface $output)
52402 {
52403 if (true === $input->hasParameterOption(array('--version', '-V'))) {
52404 $output->writeln($this->getLongVersion());
52405
52406 return 0;
52407 }
52408
52409 $name = $this->getCommandName($input);
52410 if (true === $input->hasParameterOption(array('--help', '-h'))) {
52411 if (!$name) {
52412 $name = 'help';
52413 $input = new ArrayInput(array('command' => 'help'));
52414 } else {
52415 $this->wantHelps = true;
52416 }
52417 }
52418
52419 if (!$name) {
52420 $name = $this->defaultCommand;
52421 $definition = $this->getDefinition();
52422 $definition->setArguments(array_merge(
52423 $definition->getArguments(),
52424 array(
52425 'command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name),
52426 )
52427 ));
52428 }
52429
52430 $this->runningCommand = null;
52431
52432 $command = $this->find($name);
52433
52434 $this->runningCommand = $command;
52435 $exitCode = $this->doRunCommand($command, $input, $output);
52436 $this->runningCommand = null;
52437
52438 return $exitCode;
52439 }
52440
52441 public function setHelperSet(HelperSet $helperSet)
52442 {
52443 $this->helperSet = $helperSet;
52444 }
52445
52446
52447
52448
52449
52450
52451 public function getHelperSet()
52452 {
52453 if (!$this->helperSet) {
52454 $this->helperSet = $this->getDefaultHelperSet();
52455 }
52456
52457 return $this->helperSet;
52458 }
52459
52460 public function setDefinition(InputDefinition $definition)
52461 {
52462 $this->definition = $definition;
52463 }
52464
52465
52466
52467
52468
52469
52470 public function getDefinition()
52471 {
52472 if (!$this->definition) {
52473 $this->definition = $this->getDefaultInputDefinition();
52474 }
52475
52476 return $this->definition;
52477 }
52478
52479
52480
52481
52482
52483
52484 public function getHelp()
52485 {
52486 return $this->getLongVersion();
52487 }
52488
52489
52490
52491
52492
52493
52494 public function setCatchExceptions($boolean)
52495 {
52496 $this->catchExceptions = (bool) $boolean;
52497 }
52498
52499
52500
52501
52502
52503
52504 public function setAutoExit($boolean)
52505 {
52506 $this->autoExit = (bool) $boolean;
52507 }
52508
52509
52510
52511
52512
52513
52514 public function getName()
52515 {
52516 return $this->name;
52517 }
52518
52519
52520
52521
52522
52523
52524 public function setName($name)
52525 {
52526 $this->name = $name;
52527 }
52528
52529
52530
52531
52532
52533
52534 public function getVersion()
52535 {
52536 return $this->version;
52537 }
52538
52539
52540
52541
52542
52543
52544 public function setVersion($version)
52545 {
52546 $this->version = $version;
52547 }
52548
52549
52550
52551
52552
52553
52554 public function getLongVersion()
52555 {
52556 if ('UNKNOWN' !== $this->getName()) {
52557 if ('UNKNOWN' !== $this->getVersion()) {
52558 return sprintf('<info>%s</info> version <comment>%s</comment>', $this->getName(), $this->getVersion());
52559 }
52560
52561 return sprintf('<info>%s</info>', $this->getName());
52562 }
52563
52564 return '<info>Console Tool</info>';
52565 }
52566
52567
52568
52569
52570
52571
52572
52573
52574 public function register($name)
52575 {
52576 return $this->add(new Command($name));
52577 }
52578
52579
52580
52581
52582
52583
52584
52585
52586 public function addCommands(array $commands)
52587 {
52588 foreach ($commands as $command) {
52589 $this->add($command);
52590 }
52591 }
52592
52593
52594
52595
52596
52597
52598
52599
52600
52601 public function add(Command $command)
52602 {
52603 $this->init();
52604
52605 $command->setApplication($this);
52606
52607 if (!$command->isEnabled()) {
52608 $command->setApplication(null);
52609
52610 return;
52611 }
52612
52613 if (null === $command->getDefinition()) {
52614 throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', \get_class($command)));
52615 }
52616
52617 $this->commands[$command->getName()] = $command;
52618
52619 foreach ($command->getAliases() as $alias) {
52620 $this->commands[$alias] = $command;
52621 }
52622
52623 return $command;
52624 }
52625
52626
52627
52628
52629
52630
52631
52632
52633
52634
52635 public function get($name)
52636 {
52637 $this->init();
52638
52639 if (!isset($this->commands[$name])) {
52640 throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name));
52641 }
52642
52643 $command = $this->commands[$name];
52644
52645 if ($this->wantHelps) {
52646 $this->wantHelps = false;
52647
52648 $helpCommand = $this->get('help');
52649 $helpCommand->setCommand($command);
52650
52651 return $helpCommand;
52652 }
52653
52654 return $command;
52655 }
52656
52657
52658
52659
52660
52661
52662
52663
52664 public function has($name)
52665 {
52666 $this->init();
52667
52668 return isset($this->commands[$name]);
52669 }
52670
52671
52672
52673
52674
52675
52676
52677
52678 public function getNamespaces()
52679 {
52680 $namespaces = array();
52681 foreach ($this->all() as $command) {
52682 $namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
52683
52684 foreach ($command->getAliases() as $alias) {
52685 $namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias));
52686 }
52687 }
52688
52689 return array_values(array_unique(array_filter($namespaces)));
52690 }
52691
52692
52693
52694
52695
52696
52697
52698
52699
52700
52701 public function findNamespace($namespace)
52702 {
52703 $allNamespaces = $this->getNamespaces();
52704 $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $namespace);
52705 $namespaces = preg_grep('{^'.$expr.'}', $allNamespaces);
52706
52707 if (empty($namespaces)) {
52708 $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace);
52709
52710 if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) {
52711 if (1 == \count($alternatives)) {
52712 $message .= "\n\nDid you mean this?\n    ";
52713 } else {
52714 $message .= "\n\nDid you mean one of these?\n    ";
52715 }
52716
52717 $message .= implode("\n    ", $alternatives);
52718 }
52719
52720 throw new CommandNotFoundException($message, $alternatives);
52721 }
52722
52723 $exact = \in_array($namespace, $namespaces, true);
52724 if (\count($namespaces) > 1 && !$exact) {
52725 throw new CommandNotFoundException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces));
52726 }
52727
52728 return $exact ? $namespace : reset($namespaces);
52729 }
52730
52731
52732
52733
52734
52735
52736
52737
52738
52739
52740
52741
52742
52743 public function find($name)
52744 {
52745 $this->init();
52746 $aliases = array();
52747 $allCommands = array_keys($this->commands);
52748 $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $name);
52749 $commands = preg_grep('{^'.$expr.'}', $allCommands);
52750
52751 if (empty($commands) || \count(preg_grep('{^'.$expr.'$}', $commands)) < 1) {
52752 if (false !== $pos = strrpos($name, ':')) {
52753
52754 $this->findNamespace(substr($name, 0, $pos));
52755 }
52756
52757 $message = sprintf('Command "%s" is not defined.', $name);
52758
52759 if ($alternatives = $this->findAlternatives($name, $allCommands)) {
52760 if (1 == \count($alternatives)) {
52761 $message .= "\n\nDid you mean this?\n    ";
52762 } else {
52763 $message .= "\n\nDid you mean one of these?\n    ";
52764 }
52765 $message .= implode("\n    ", $alternatives);
52766 }
52767
52768 throw new CommandNotFoundException($message, $alternatives);
52769 }
52770
52771
52772 if (\count($commands) > 1) {
52773 $commandList = $this->commands;
52774 $commands = array_filter($commands, function ($nameOrAlias) use ($commandList, $commands, &$aliases) {
52775 $commandName = $commandList[$nameOrAlias]->getName();
52776 $aliases[$nameOrAlias] = $commandName;
52777
52778 return $commandName === $nameOrAlias || !\in_array($commandName, $commands);
52779 });
52780 }
52781
52782 $exact = \in_array($name, $commands, true) || isset($aliases[$name]);
52783 if (!$exact && \count($commands) > 1) {
52784 $suggestions = $this->getAbbreviationSuggestions(array_values($commands));
52785
52786 throw new CommandNotFoundException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions), array_values($commands));
52787 }
52788
52789 return $this->get($exact ? $name : reset($commands));
52790 }
52791
52792
52793
52794
52795
52796
52797
52798
52799
52800
52801 public function all($namespace = null)
52802 {
52803 $this->init();
52804
52805 if (null === $namespace) {
52806 return $this->commands;
52807 }
52808
52809 $commands = array();
52810 foreach ($this->commands as $name => $command) {
52811 if ($namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1)) {
52812 $commands[$name] = $command;
52813 }
52814 }
52815
52816 return $commands;
52817 }
52818
52819
52820
52821
52822
52823
52824
52825
52826 public static function getAbbreviations($names)
52827 {
52828 $abbrevs = array();
52829 foreach ($names as $name) {
52830 for ($len = \strlen($name); $len > 0; --$len) {
52831 $abbrev = substr($name, 0, $len);
52832 $abbrevs[$abbrev][] = $name;
52833 }
52834 }
52835
52836 return $abbrevs;
52837 }
52838
52839
52840
52841
52842
52843
52844
52845
52846
52847
52848
52849 public function asText($namespace = null, $raw = false)
52850 {
52851 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);
52852
52853 $descriptor = new TextDescriptor();
52854 $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, !$raw);
52855 $descriptor->describe($output, $this, array('namespace' => $namespace, 'raw_output' => true));
52856
52857 return $output->fetch();
52858 }
52859
52860
52861
52862
52863
52864
52865
52866
52867
52868
52869
52870 public function asXml($namespace = null, $asDom = false)
52871 {
52872 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);
52873
52874 $descriptor = new XmlDescriptor();
52875
52876 if ($asDom) {
52877 return $descriptor->getApplicationDocument($this, $namespace);
52878 }
52879
52880 $output = new BufferedOutput();
52881 $descriptor->describe($output, $this, array('namespace' => $namespace));
52882
52883 return $output->fetch();
52884 }
52885
52886
52887
52888
52889 public function renderException($e, $output)
52890 {
52891 $output->writeln('', OutputInterface::VERBOSITY_QUIET);
52892
52893 do {
52894 $title = sprintf('  [%s]  ', \get_class($e));
52895
52896 $len = Helper::strlen($title);
52897
52898 $width = $this->getTerminalWidth() ? $this->getTerminalWidth() - 1 : PHP_INT_MAX;
52899
52900 if (\defined('HHVM_VERSION') && $width > 1 << 31) {
52901 $width = 1 << 31;
52902 }
52903 $lines = array();
52904 foreach (preg_split('/\r?\n/', trim($e->getMessage())) as $line) {
52905 foreach ($this->splitStringByWidth($line, $width - 4) as $line) {
52906
52907 $lineLength = Helper::strlen($line) + 4;
52908 $lines[] = array($line, $lineLength);
52909
52910 $len = max($lineLength, $len);
52911 }
52912 }
52913
52914 $messages = array();
52915 $messages[] = $emptyLine = sprintf('<error>%s</error>', str_repeat(' ', $len));
52916 $messages[] = sprintf('<error>%s%s</error>', $title, str_repeat(' ', max(0, $len - Helper::strlen($title))));
52917 foreach ($lines as $line) {
52918 $messages[] = sprintf('<error>  %s  %s</error>', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1]));
52919 }
52920 $messages[] = $emptyLine;
52921 $messages[] = '';
52922
52923 $output->writeln($messages, OutputInterface::VERBOSITY_QUIET);
52924
52925 if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
52926 $output->writeln('<comment>Exception trace:</comment>', OutputInterface::VERBOSITY_QUIET);
52927
52928
52929 $trace = $e->getTrace();
52930 array_unshift($trace, array(
52931 'function' => '',
52932 'file' => null !== $e->getFile() ? $e->getFile() : 'n/a',
52933 'line' => null !== $e->getLine() ? $e->getLine() : 'n/a',
52934 'args' => array(),
52935 ));
52936
52937 for ($i = 0, $count = \count($trace); $i < $count; ++$i) {
52938 $class = isset($trace[$i]['class']) ? $trace[$i]['class'] : '';
52939 $type = isset($trace[$i]['type']) ? $trace[$i]['type'] : '';
52940 $function = $trace[$i]['function'];
52941 $file = isset($trace[$i]['file']) ? $trace[$i]['file'] : 'n/a';
52942 $line = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a';
52943
52944 $output->writeln(sprintf(' %s%s%s() at <info>%s:%s</info>', $class, $type, $function, $file, $line), OutputInterface::VERBOSITY_QUIET);
52945 }
52946
52947 $output->writeln('', OutputInterface::VERBOSITY_QUIET);
52948 }
52949 } while ($e = $e->getPrevious());
52950
52951 if (null !== $this->runningCommand) {
52952 $output->writeln(sprintf('<info>%s</info>', sprintf($this->runningCommand->getSynopsis(), $this->getName())), OutputInterface::VERBOSITY_QUIET);
52953 $output->writeln('', OutputInterface::VERBOSITY_QUIET);
52954 }
52955 }
52956
52957
52958
52959
52960
52961
52962 protected function getTerminalWidth()
52963 {
52964 $dimensions = $this->getTerminalDimensions();
52965
52966 return $dimensions[0];
52967 }
52968
52969
52970
52971
52972
52973
52974 protected function getTerminalHeight()
52975 {
52976 $dimensions = $this->getTerminalDimensions();
52977
52978 return $dimensions[1];
52979 }
52980
52981
52982
52983
52984
52985
52986 public function getTerminalDimensions()
52987 {
52988 if ($this->terminalDimensions) {
52989 return $this->terminalDimensions;
52990 }
52991
52992 if ('\\' === \DIRECTORY_SEPARATOR) {
52993
52994 if (preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim(getenv('ANSICON')), $matches)) {
52995 return array((int) $matches[1], (int) $matches[2]);
52996 }
52997
52998 if (preg_match('/^(\d+)x(\d+)$/', $this->getConsoleMode(), $matches)) {
52999 return array((int) $matches[1], (int) $matches[2]);
53000 }
53001 }
53002
53003 if ($sttyString = $this->getSttyColumns()) {
53004
53005 if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) {
53006 return array((int) $matches[2], (int) $matches[1]);
53007 }
53008
53009 if (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) {
53010 return array((int) $matches[2], (int) $matches[1]);
53011 }
53012 }
53013
53014 return array(null, null);
53015 }
53016
53017
53018
53019
53020
53021
53022
53023
53024
53025
53026
53027 public function setTerminalDimensions($width, $height)
53028 {
53029 $this->terminalDimensions = array($width, $height);
53030
53031 return $this;
53032 }
53033
53034
53035
53036
53037 protected function configureIO(InputInterface $input, OutputInterface $output)
53038 {
53039 if (true === $input->hasParameterOption(array('--ansi'))) {
53040 $output->setDecorated(true);
53041 } elseif (true === $input->hasParameterOption(array('--no-ansi'))) {
53042 $output->setDecorated(false);
53043 }
53044
53045 if (true === $input->hasParameterOption(array('--no-interaction', '-n'))) {
53046 $input->setInteractive(false);
53047 } elseif (\function_exists('posix_isatty') && $this->getHelperSet()->has('question')) {
53048 $inputStream = $this->getHelperSet()->get('question')->getInputStream();
53049 if (!@posix_isatty($inputStream) && false === getenv('SHELL_INTERACTIVE')) {
53050 $input->setInteractive(false);
53051 }
53052 }
53053
53054 if (true === $input->hasParameterOption(array('--quiet', '-q'))) {
53055 $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
53056 $input->setInteractive(false);
53057 } else {
53058 if ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || 3 === $input->getParameterOption('--verbose')) {
53059 $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
53060 } elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2') || 2 === $input->getParameterOption('--verbose')) {
53061 $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
53062 } elseif ($input->hasParameterOption('-v') || $input->hasParameterOption('--verbose=1') || $input->hasParameterOption('--verbose') || $input->getParameterOption('--verbose')) {
53063 $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
53064 }
53065 }
53066 }
53067
53068
53069
53070
53071
53072
53073
53074
53075
53076 protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output)
53077 {
53078 foreach ($command->getHelperSet() as $helper) {
53079 if ($helper instanceof InputAwareInterface) {
53080 $helper->setInput($input);
53081 }
53082 }
53083
53084 if (null === $this->dispatcher) {
53085 return $command->run($input, $output);
53086 }
53087
53088
53089 try {
53090 $command->mergeApplicationDefinition();
53091 $input->bind($command->getDefinition());
53092 } catch (ExceptionInterface $e) {
53093
53094 }
53095
53096 $event = new ConsoleCommandEvent($command, $input, $output);
53097 $e = null;
53098
53099 try {
53100 $this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event);
53101
53102 if ($event->commandShouldRun()) {
53103 $exitCode = $command->run($input, $output);
53104 } else {
53105 $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED;
53106 }
53107 } catch (\Exception $e) {
53108 } catch (\Throwable $e) {
53109 }
53110 if (null !== $e) {
53111 $x = $e instanceof \Exception ? $e : new FatalThrowableError($e);
53112 $event = new ConsoleExceptionEvent($command, $input, $output, $x, $x->getCode());
53113 $this->dispatcher->dispatch(ConsoleEvents::EXCEPTION, $event);
53114
53115 if ($x !== $event->getException()) {
53116 $e = $event->getException();
53117 }
53118
53119 $exitCode = $this->getExitCodeForThrowable($e);
53120 }
53121
53122 $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode);
53123 $this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);
53124
53125 if (null !== $e) {
53126 throw $e;
53127 }
53128
53129 return $event->getExitCode();
53130 }
53131
53132
53133
53134
53135
53136
53137 protected function getCommandName(InputInterface $input)
53138 {
53139 return $input->getFirstArgument();
53140 }
53141
53142
53143
53144
53145
53146
53147 protected function getDefaultInputDefinition()
53148 {
53149 return new InputDefinition(array(
53150 new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
53151
53152 new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message'),
53153 new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'),
53154 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'),
53155 new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'),
53156 new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output'),
53157 new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output'),
53158 new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'),
53159 ));
53160 }
53161
53162
53163
53164
53165
53166
53167 protected function getDefaultCommands()
53168 {
53169 return array(new HelpCommand(), new ListCommand());
53170 }
53171
53172
53173
53174
53175
53176
53177 protected function getDefaultHelperSet()
53178 {
53179 return new HelperSet(array(
53180 new FormatterHelper(),
53181 new DialogHelper(false),
53182 new ProgressHelper(false),
53183 new TableHelper(false),
53184 new DebugFormatterHelper(),
53185 new ProcessHelper(),
53186 new QuestionHelper(),
53187 ));
53188 }
53189
53190
53191
53192
53193
53194
53195 private function getSttyColumns()
53196 {
53197 if (!\function_exists('proc_open')) {
53198 return;
53199 }
53200
53201 $descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
53202 $process = proc_open('stty -a | grep columns', $descriptorspec, $pipes, null, null, array('suppress_errors' => true));
53203 if (\is_resource($process)) {
53204 $info = stream_get_contents($pipes[1]);
53205 fclose($pipes[1]);
53206 fclose($pipes[2]);
53207 proc_close($process);
53208
53209 return $info;
53210 }
53211 }
53212
53213
53214
53215
53216
53217
53218 private function getConsoleMode()
53219 {
53220 if (!\function_exists('proc_open')) {
53221 return;
53222 }
53223
53224 $descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
53225 $process = proc_open('mode CON', $descriptorspec, $pipes, null, null, array('suppress_errors' => true));
53226 if (\is_resource($process)) {
53227 $info = stream_get_contents($pipes[1]);
53228 fclose($pipes[1]);
53229 fclose($pipes[2]);
53230 proc_close($process);
53231
53232 if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
53233 return $matches[2].'x'.$matches[1];
53234 }
53235 }
53236 }
53237
53238
53239
53240
53241
53242
53243
53244
53245 private function getAbbreviationSuggestions($abbrevs)
53246 {
53247 return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], \count($abbrevs) > 2 ? sprintf(' and %d more', \count($abbrevs) - 2) : '');
53248 }
53249
53250
53251
53252
53253
53254
53255
53256
53257
53258
53259
53260 public function extractNamespace($name, $limit = null)
53261 {
53262 $parts = explode(':', $name);
53263 array_pop($parts);
53264
53265 return implode(':', null === $limit ? $parts : \array_slice($parts, 0, $limit));
53266 }
53267
53268
53269
53270
53271
53272
53273
53274
53275
53276
53277 private function findAlternatives($name, $collection)
53278 {
53279 $threshold = 1e3;
53280 $alternatives = array();
53281
53282 $collectionParts = array();
53283 foreach ($collection as $item) {
53284 $collectionParts[$item] = explode(':', $item);
53285 }
53286
53287 foreach (explode(':', $name) as $i => $subname) {
53288 foreach ($collectionParts as $collectionName => $parts) {
53289 $exists = isset($alternatives[$collectionName]);
53290 if (!isset($parts[$i]) && $exists) {
53291 $alternatives[$collectionName] += $threshold;
53292 continue;
53293 } elseif (!isset($parts[$i])) {
53294 continue;
53295 }
53296
53297 $lev = levenshtein($subname, $parts[$i]);
53298 if ($lev <= \strlen($subname) / 3 || '' !== $subname && false !== strpos($parts[$i], $subname)) {
53299 $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;
53300 } elseif ($exists) {
53301 $alternatives[$collectionName] += $threshold;
53302 }
53303 }
53304 }
53305
53306 foreach ($collection as $item) {
53307 $lev = levenshtein($name, $item);
53308 if ($lev <= \strlen($name) / 3 || false !== strpos($item, $name)) {
53309 $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
53310 }
53311 }
53312
53313 $alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; });
53314 asort($alternatives);
53315
53316 return array_keys($alternatives);
53317 }
53318
53319
53320
53321
53322
53323
53324 public function setDefaultCommand($commandName)
53325 {
53326 $this->defaultCommand = $commandName;
53327 }
53328
53329 private function splitStringByWidth($string, $width)
53330 {
53331
53332
53333
53334 if (false === $encoding = mb_detect_encoding($string, null, true)) {
53335 return str_split($string, $width);
53336 }
53337
53338 $utf8String = mb_convert_encoding($string, 'utf8', $encoding);
53339 $lines = array();
53340 $line = '';
53341 foreach (preg_split('//u', $utf8String) as $char) {
53342
53343 if (mb_strwidth($line.$char, 'utf8') <= $width) {
53344 $line .= $char;
53345 continue;
53346 }
53347
53348 $lines[] = str_pad($line, $width);
53349 $line = $char;
53350 }
53351
53352 $lines[] = \count($lines) ? str_pad($line, $width) : $line;
53353
53354 mb_convert_variables($encoding, 'utf8', $lines);
53355
53356 return $lines;
53357 }
53358
53359
53360
53361
53362
53363
53364
53365
53366 private function extractAllNamespaces($name)
53367 {
53368
53369 $parts = explode(':', $name, -1);
53370 $namespaces = array();
53371
53372 foreach ($parts as $part) {
53373 if (\count($namespaces)) {
53374 $namespaces[] = end($namespaces).':'.$part;
53375 } else {
53376 $namespaces[] = $part;
53377 }
53378 }
53379
53380 return $namespaces;
53381 }
53382
53383 private function init()
53384 {
53385 if ($this->initialized) {
53386 return;
53387 }
53388 $this->initialized = true;
53389
53390 foreach ($this->getDefaultCommands() as $command) {
53391 $this->add($command);
53392 }
53393 }
53394
53395
53396
53397
53398
53399
53400 private function getExitCodeForThrowable($throwable)
53401 {
53402 $exitCode = $throwable->getCode();
53403 if (is_numeric($exitCode)) {
53404 $exitCode = (int) $exitCode;
53405 if (0 === $exitCode) {
53406 $exitCode = 1;
53407 }
53408 } else {
53409 $exitCode = 1;
53410 }
53411
53412 return $exitCode;
53413 }
53414 }
53415 <?php
53416
53417
53418
53419
53420
53421
53422
53423
53424
53425
53426 namespace Symfony\Component\Console\Command;
53427
53428 use Symfony\Component\Console\Application;
53429 use Symfony\Component\Console\Descriptor\TextDescriptor;
53430 use Symfony\Component\Console\Descriptor\XmlDescriptor;
53431 use Symfony\Component\Console\Exception\ExceptionInterface;
53432 use Symfony\Component\Console\Exception\InvalidArgumentException;
53433 use Symfony\Component\Console\Exception\LogicException;
53434 use Symfony\Component\Console\Helper\HelperSet;
53435 use Symfony\Component\Console\Input\InputArgument;
53436 use Symfony\Component\Console\Input\InputDefinition;
53437 use Symfony\Component\Console\Input\InputInterface;
53438 use Symfony\Component\Console\Input\InputOption;
53439 use Symfony\Component\Console\Output\BufferedOutput;
53440 use Symfony\Component\Console\Output\OutputInterface;
53441
53442
53443
53444
53445
53446
53447 class Command
53448 {
53449 private $application;
53450 private $name;
53451 private $processTitle;
53452 private $aliases = array();
53453 private $definition;
53454 private $help;
53455 private $description;
53456 private $ignoreValidationErrors = false;
53457 private $applicationDefinitionMerged = false;
53458 private $applicationDefinitionMergedWithArgs = false;
53459 private $code;
53460 private $synopsis = array();
53461 private $usages = array();
53462 private $helperSet;
53463
53464
53465
53466
53467
53468
53469 public function __construct($name = null)
53470 {
53471 $this->definition = new InputDefinition();
53472
53473 if (null !== $name) {
53474 $this->setName($name);
53475 }
53476
53477 $this->configure();
53478
53479 if (!$this->name) {
53480 throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', \get_class($this)));
53481 }
53482 }
53483
53484
53485
53486
53487
53488
53489 public function ignoreValidationErrors()
53490 {
53491 $this->ignoreValidationErrors = true;
53492 }
53493
53494 public function setApplication(Application $application = null)
53495 {
53496 $this->application = $application;
53497 if ($application) {
53498 $this->setHelperSet($application->getHelperSet());
53499 } else {
53500 $this->helperSet = null;
53501 }
53502 }
53503
53504 public function setHelperSet(HelperSet $helperSet)
53505 {
53506 $this->helperSet = $helperSet;
53507 }
53508
53509
53510
53511
53512
53513
53514 public function getHelperSet()
53515 {
53516 return $this->helperSet;
53517 }
53518
53519
53520
53521
53522
53523
53524 public function getApplication()
53525 {
53526 return $this->application;
53527 }
53528
53529
53530
53531
53532
53533
53534
53535
53536
53537 public function isEnabled()
53538 {
53539 return true;
53540 }
53541
53542
53543
53544
53545 protected function configure()
53546 {
53547 }
53548
53549
53550
53551
53552
53553
53554
53555
53556
53557
53558
53559
53560
53561
53562
53563 protected function execute(InputInterface $input, OutputInterface $output)
53564 {
53565 throw new LogicException('You must override the execute() method in the concrete command class.');
53566 }
53567
53568
53569
53570
53571
53572
53573
53574
53575 protected function interact(InputInterface $input, OutputInterface $output)
53576 {
53577 }
53578
53579
53580
53581
53582
53583
53584
53585
53586
53587
53588
53589 protected function initialize(InputInterface $input, OutputInterface $output)
53590 {
53591 }
53592
53593
53594
53595
53596
53597
53598
53599
53600
53601
53602
53603
53604
53605
53606
53607 public function run(InputInterface $input, OutputInterface $output)
53608 {
53609
53610 $this->getSynopsis(true);
53611 $this->getSynopsis(false);
53612
53613
53614 $this->mergeApplicationDefinition();
53615
53616
53617 try {
53618 $input->bind($this->definition);
53619 } catch (ExceptionInterface $e) {
53620 if (!$this->ignoreValidationErrors) {
53621 throw $e;
53622 }
53623 }
53624
53625 $this->initialize($input, $output);
53626
53627 if (null !== $this->processTitle) {
53628 if (\function_exists('cli_set_process_title')) {
53629 if (!@cli_set_process_title($this->processTitle)) {
53630 if ('Darwin' === PHP_OS) {
53631 $output->writeln('<comment>Running "cli_set_process_title" as an unprivileged user is not supported on MacOS.</comment>', OutputInterface::VERBOSITY_VERY_VERBOSE);
53632 } else {
53633 cli_set_process_title($this->processTitle);
53634 }
53635 }
53636 } elseif (\function_exists('setproctitle')) {
53637 setproctitle($this->processTitle);
53638 } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) {
53639 $output->writeln('<comment>Install the proctitle PECL to be able to change the process title.</comment>');
53640 }
53641 }
53642
53643 if ($input->isInteractive()) {
53644 $this->interact($input, $output);
53645 }
53646
53647
53648
53649
53650 if ($input->hasArgument('command') && null === $input->getArgument('command')) {
53651 $input->setArgument('command', $this->getName());
53652 }
53653
53654 $input->validate();
53655
53656 if ($this->code) {
53657 $statusCode = \call_user_func($this->code, $input, $output);
53658 } else {
53659 $statusCode = $this->execute($input, $output);
53660 }
53661
53662 return is_numeric($statusCode) ? (int) $statusCode : 0;
53663 }
53664
53665
53666
53667
53668
53669
53670
53671
53672
53673
53674
53675
53676
53677
53678
53679 public function setCode($code)
53680 {
53681 if (!\is_callable($code)) {
53682 throw new InvalidArgumentException('Invalid callable provided to Command::setCode.');
53683 }
53684
53685 if (\PHP_VERSION_ID >= 50400 && $code instanceof \Closure) {
53686 $r = new \ReflectionFunction($code);
53687 if (null === $r->getClosureThis()) {
53688 if (\PHP_VERSION_ID < 70000) {
53689
53690
53691
53692
53693 $code = @\Closure::bind($code, $this);
53694 } else {
53695 $code = \Closure::bind($code, $this);
53696 }
53697 }
53698 }
53699
53700 $this->code = $code;
53701
53702 return $this;
53703 }
53704
53705
53706
53707
53708
53709
53710
53711
53712 public function mergeApplicationDefinition($mergeArgs = true)
53713 {
53714 if (null === $this->application || (true === $this->applicationDefinitionMerged && ($this->applicationDefinitionMergedWithArgs || !$mergeArgs))) {
53715 return;
53716 }
53717
53718 $this->definition->addOptions($this->application->getDefinition()->getOptions());
53719
53720 $this->applicationDefinitionMerged = true;
53721
53722 if ($mergeArgs) {
53723 $currentArguments = $this->definition->getArguments();
53724 $this->definition->setArguments($this->application->getDefinition()->getArguments());
53725 $this->definition->addArguments($currentArguments);
53726
53727 $this->applicationDefinitionMergedWithArgs = true;
53728 }
53729 }
53730
53731
53732
53733
53734
53735
53736
53737
53738 public function setDefinition($definition)
53739 {
53740 if ($definition instanceof InputDefinition) {
53741 $this->definition = $definition;
53742 } else {
53743 $this->definition->setDefinition($definition);
53744 }
53745
53746 $this->applicationDefinitionMerged = false;
53747
53748 return $this;
53749 }
53750
53751
53752
53753
53754
53755
53756 public function getDefinition()
53757 {
53758 return $this->definition;
53759 }
53760
53761
53762
53763
53764
53765
53766
53767
53768
53769
53770
53771 public function getNativeDefinition()
53772 {
53773 return $this->getDefinition();
53774 }
53775
53776
53777
53778
53779
53780
53781
53782
53783
53784
53785
53786
53787
53788 public function addArgument($name, $mode = null, $description = '', $default = null)
53789 {
53790 $this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
53791
53792 return $this;
53793 }
53794
53795
53796
53797
53798
53799
53800
53801
53802
53803
53804
53805
53806
53807
53808 public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
53809 {
53810 $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
53811
53812 return $this;
53813 }
53814
53815
53816
53817
53818
53819
53820
53821
53822
53823
53824
53825
53826
53827
53828
53829 public function setName($name)
53830 {
53831 $this->validateName($name);
53832
53833 $this->name = $name;
53834
53835 return $this;
53836 }
53837
53838
53839
53840
53841
53842
53843
53844
53845
53846
53847
53848
53849
53850 public function setProcessTitle($title)
53851 {
53852 $this->processTitle = $title;
53853
53854 return $this;
53855 }
53856
53857
53858
53859
53860
53861
53862 public function getName()
53863 {
53864 return $this->name;
53865 }
53866
53867
53868
53869
53870
53871
53872
53873
53874 public function setDescription($description)
53875 {
53876 $this->description = $description;
53877
53878 return $this;
53879 }
53880
53881
53882
53883
53884
53885
53886 public function getDescription()
53887 {
53888 return $this->description;
53889 }
53890
53891
53892
53893
53894
53895
53896
53897
53898 public function setHelp($help)
53899 {
53900 $this->help = $help;
53901
53902 return $this;
53903 }
53904
53905
53906
53907
53908
53909
53910 public function getHelp()
53911 {
53912 return $this->help;
53913 }
53914
53915
53916
53917
53918
53919
53920
53921 public function getProcessedHelp()
53922 {
53923 $name = $this->name;
53924
53925 $placeholders = array(
53926 '%command.name%',
53927 '%command.full_name%',
53928 );
53929 $replacements = array(
53930 $name,
53931 $_SERVER['PHP_SELF'].' '.$name,
53932 );
53933
53934 return str_replace($placeholders, $replacements, $this->getHelp() ?: $this->getDescription());
53935 }
53936
53937
53938
53939
53940
53941
53942
53943
53944
53945
53946 public function setAliases($aliases)
53947 {
53948 if (!\is_array($aliases) && !$aliases instanceof \Traversable) {
53949 throw new InvalidArgumentException('$aliases must be an array or an instance of \Traversable');
53950 }
53951
53952 foreach ($aliases as $alias) {
53953 $this->validateName($alias);
53954 }
53955
53956 $this->aliases = $aliases;
53957
53958 return $this;
53959 }
53960
53961
53962
53963
53964
53965
53966 public function getAliases()
53967 {
53968 return $this->aliases;
53969 }
53970
53971
53972
53973
53974
53975
53976
53977
53978 public function getSynopsis($short = false)
53979 {
53980 $key = $short ? 'short' : 'long';
53981
53982 if (!isset($this->synopsis[$key])) {
53983 $this->synopsis[$key] = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis($short)));
53984 }
53985
53986 return $this->synopsis[$key];
53987 }
53988
53989
53990
53991
53992
53993
53994
53995
53996 public function addUsage($usage)
53997 {
53998 if (0 !== strpos($usage, $this->name)) {
53999 $usage = sprintf('%s %s', $this->name, $usage);
54000 }
54001
54002 $this->usages[] = $usage;
54003
54004 return $this;
54005 }
54006
54007
54008
54009
54010
54011
54012 public function getUsages()
54013 {
54014 return $this->usages;
54015 }
54016
54017
54018
54019
54020
54021
54022
54023
54024
54025
54026
54027 public function getHelper($name)
54028 {
54029 if (null === $this->helperSet) {
54030 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));
54031 }
54032
54033 return $this->helperSet->get($name);
54034 }
54035
54036
54037
54038
54039
54040
54041
54042
54043 public function asText()
54044 {
54045 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);
54046
54047 $descriptor = new TextDescriptor();
54048 $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true);
54049 $descriptor->describe($output, $this, array('raw_output' => true));
54050
54051 return $output->fetch();
54052 }
54053
54054
54055
54056
54057
54058
54059
54060
54061
54062
54063 public function asXml($asDom = false)
54064 {
54065 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);
54066
54067 $descriptor = new XmlDescriptor();
54068
54069 if ($asDom) {
54070 return $descriptor->getCommandDocument($this);
54071 }
54072
54073 $output = new BufferedOutput();
54074 $descriptor->describe($output, $this);
54075
54076 return $output->fetch();
54077 }
54078
54079
54080
54081
54082
54083
54084
54085
54086
54087
54088 private function validateName($name)
54089 {
54090 if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) {
54091 throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
54092 }
54093 }
54094 }
54095 <?php
54096
54097
54098
54099
54100
54101
54102
54103
54104
54105
54106 namespace Symfony\Component\Console\Command;
54107
54108 use Symfony\Component\Console\Helper\DescriptorHelper;
54109 use Symfony\Component\Console\Input\InputArgument;
54110 use Symfony\Component\Console\Input\InputInterface;
54111 use Symfony\Component\Console\Input\InputOption;
54112 use Symfony\Component\Console\Output\OutputInterface;
54113
54114
54115
54116
54117
54118
54119 class HelpCommand extends Command
54120 {
54121 private $command;
54122
54123
54124
54125
54126 protected function configure()
54127 {
54128 $this->ignoreValidationErrors();
54129
54130 $this
54131 ->setName('help')
54132 ->setDefinition(array(
54133 new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),
54134 new InputOption('xml', null, InputOption::VALUE_NONE, 'To output help as XML'),
54135 new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
54136 new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'),
54137 ))
54138 ->setDescription('Displays help for a command')
54139 ->setHelp(<<<'EOF'
54140 The <info>%command.name%</info> command displays help for a given command:
54141
54142   <info>php %command.full_name% list</info>
54143
54144 You can also output the help in other formats by using the <comment>--format</comment> option:
54145
54146   <info>php %command.full_name% --format=xml list</info>
54147
54148 To display the list of available commands, please use the <info>list</info> command.
54149 EOF
54150 )
54151 ;
54152 }
54153
54154 public function setCommand(Command $command)
54155 {
54156 $this->command = $command;
54157 }
54158
54159
54160
54161
54162 protected function execute(InputInterface $input, OutputInterface $output)
54163 {
54164 if (null === $this->command) {
54165 $this->command = $this->getApplication()->find($input->getArgument('command_name'));
54166 }
54167
54168 if ($input->getOption('xml')) {
54169 @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);
54170
54171 $input->setOption('format', 'xml');
54172 }
54173
54174 $helper = new DescriptorHelper();
54175 $helper->describe($output, $this->command, array(
54176 'format' => $input->getOption('format'),
54177 'raw_text' => $input->getOption('raw'),
54178 ));
54179
54180 $this->command = null;
54181 }
54182 }
54183 <?php
54184
54185
54186
54187
54188
54189
54190
54191
54192
54193
54194 namespace Symfony\Component\Console\Command;
54195
54196 use Symfony\Component\Console\Helper\DescriptorHelper;
54197 use Symfony\Component\Console\Input\InputArgument;
54198 use Symfony\Component\Console\Input\InputDefinition;
54199 use Symfony\Component\Console\Input\InputInterface;
54200 use Symfony\Component\Console\Input\InputOption;
54201 use Symfony\Component\Console\Output\OutputInterface;
54202
54203
54204
54205
54206
54207
54208 class ListCommand extends Command
54209 {
54210
54211
54212
54213 protected function configure()
54214 {
54215 $this
54216 ->setName('list')
54217 ->setDefinition($this->createDefinition())
54218 ->setDescription('Lists commands')
54219 ->setHelp(<<<'EOF'
54220 The <info>%command.name%</info> command lists all commands:
54221
54222   <info>php %command.full_name%</info>
54223
54224 You can also display the commands for a specific namespace:
54225
54226   <info>php %command.full_name% test</info>
54227
54228 You can also output the information in other formats by using the <comment>--format</comment> option:
54229
54230   <info>php %command.full_name% --format=xml</info>
54231
54232 It's also possible to get raw list of commands (useful for embedding command runner):
54233
54234   <info>php %command.full_name% --raw</info>
54235 EOF
54236 )
54237 ;
54238 }
54239
54240
54241
54242
54243 public function getNativeDefinition()
54244 {
54245 return $this->createDefinition();
54246 }
54247
54248
54249
54250
54251 protected function execute(InputInterface $input, OutputInterface $output)
54252 {
54253 if ($input->getOption('xml')) {
54254 @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);
54255
54256 $input->setOption('format', 'xml');
54257 }
54258
54259 $helper = new DescriptorHelper();
54260 $helper->describe($output, $this->getApplication(), array(
54261 'format' => $input->getOption('format'),
54262 'raw_text' => $input->getOption('raw'),
54263 'namespace' => $input->getArgument('namespace'),
54264 ));
54265 }
54266
54267
54268
54269
54270 private function createDefinition()
54271 {
54272 return new InputDefinition(array(
54273 new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
54274 new InputOption('xml', null, InputOption::VALUE_NONE, 'To output list as XML'),
54275 new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'),
54276 new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
54277 ));
54278 }
54279 }
54280 <?php
54281
54282
54283
54284
54285
54286
54287
54288
54289
54290
54291 namespace Symfony\Component\Console;
54292
54293
54294
54295
54296
54297
54298 final class ConsoleEvents
54299 {
54300
54301
54302
54303
54304
54305
54306
54307
54308
54309
54310 const COMMAND = 'console.command';
54311
54312
54313
54314
54315
54316
54317
54318
54319
54320
54321 const TERMINATE = 'console.terminate';
54322
54323
54324
54325
54326
54327
54328
54329
54330
54331
54332
54333 const EXCEPTION = 'console.exception';
54334 }
54335 <?php
54336
54337
54338
54339
54340
54341
54342
54343
54344
54345
54346 namespace Symfony\Component\Console\Descriptor;
54347
54348 use Symfony\Component\Console\Application;
54349 use Symfony\Component\Console\Command\Command;
54350 use Symfony\Component\Console\Exception\CommandNotFoundException;
54351
54352
54353
54354
54355
54356
54357 class ApplicationDescription
54358 {
54359 const GLOBAL_NAMESPACE = '_global';
54360
54361 private $application;
54362 private $namespace;
54363
54364
54365
54366
54367 private $namespaces;
54368
54369
54370
54371
54372 private $commands;
54373
54374
54375
54376
54377 private $aliases;
54378
54379 public function __construct(Application $application, $namespace = null)
54380 {
54381 $this->application = $application;
54382 $this->namespace = $namespace;
54383 }
54384
54385
54386
54387
54388 public function getNamespaces()
54389 {
54390 if (null === $this->namespaces) {
54391 $this->inspectApplication();
54392 }
54393
54394 return $this->namespaces;
54395 }
54396
54397
54398
54399
54400 public function getCommands()
54401 {
54402 if (null === $this->commands) {
54403 $this->inspectApplication();
54404 }
54405
54406 return $this->commands;
54407 }
54408
54409
54410
54411
54412
54413
54414
54415
54416 public function getCommand($name)
54417 {
54418 if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) {
54419 throw new CommandNotFoundException(sprintf('Command %s does not exist.', $name));
54420 }
54421
54422 return isset($this->commands[$name]) ? $this->commands[$name] : $this->aliases[$name];
54423 }
54424
54425 private function inspectApplication()
54426 {
54427 $this->commands = array();
54428 $this->namespaces = array();
54429
54430 $all = $this->application->all($this->namespace ? $this->application->findNamespace($this->namespace) : null);
54431 foreach ($this->sortCommands($all) as $namespace => $commands) {
54432 $names = array();
54433
54434
54435 foreach ($commands as $name => $command) {
54436 if (!$command->getName()) {
54437 continue;
54438 }
54439
54440 if ($command->getName() === $name) {
54441 $this->commands[$name] = $command;
54442 } else {
54443 $this->aliases[$name] = $command;
54444 }
54445
54446 $names[] = $name;
54447 }
54448
54449 $this->namespaces[$namespace] = array('id' => $namespace, 'commands' => $names);
54450 }
54451 }
54452
54453
54454
54455
54456 private function sortCommands(array $commands)
54457 {
54458 $namespacedCommands = array();
54459 $globalCommands = array();
54460 foreach ($commands as $name => $command) {
54461 $key = $this->application->extractNamespace($name, 1);
54462 if (!$key) {
54463 $globalCommands['_global'][$name] = $command;
54464 } else {
54465 $namespacedCommands[$key][$name] = $command;
54466 }
54467 }
54468 ksort($namespacedCommands);
54469 $namespacedCommands = array_merge($globalCommands, $namespacedCommands);
54470
54471 foreach ($namespacedCommands as &$commandsSet) {
54472 ksort($commandsSet);
54473 }
54474
54475 unset($commandsSet);
54476
54477 return $namespacedCommands;
54478 }
54479 }
54480 <?php
54481
54482
54483
54484
54485
54486
54487
54488
54489
54490
54491 namespace Symfony\Component\Console\Descriptor;
54492
54493 use Symfony\Component\Console\Application;
54494 use Symfony\Component\Console\Command\Command;
54495 use Symfony\Component\Console\Exception\InvalidArgumentException;
54496 use Symfony\Component\Console\Input\InputArgument;
54497 use Symfony\Component\Console\Input\InputDefinition;
54498 use Symfony\Component\Console\Input\InputOption;
54499 use Symfony\Component\Console\Output\OutputInterface;
54500
54501
54502
54503
54504
54505
54506 abstract class Descriptor implements DescriptorInterface
54507 {
54508
54509
54510
54511 private $output;
54512
54513
54514
54515
54516 public function describe(OutputInterface $output, $object, array $options = array())
54517 {
54518 $this->output = $output;
54519
54520 switch (true) {
54521 case $object instanceof InputArgument:
54522 $this->describeInputArgument($object, $options);
54523 break;
54524 case $object instanceof InputOption:
54525 $this->describeInputOption($object, $options);
54526 break;
54527 case $object instanceof InputDefinition:
54528 $this->describeInputDefinition($object, $options);
54529 break;
54530 case $object instanceof Command:
54531 $this->describeCommand($object, $options);
54532 break;
54533 case $object instanceof Application:
54534 $this->describeApplication($object, $options);
54535 break;
54536 default:
54537 throw new InvalidArgumentException(sprintf('Object of type "%s" is not describable.', \get_class($object)));
54538 }
54539 }
54540
54541
54542
54543
54544
54545
54546
54547 protected function write($content, $decorated = false)
54548 {
54549 $this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW);
54550 }
54551
54552
54553
54554
54555
54556
54557 abstract protected function describeInputArgument(InputArgument $argument, array $options = array());
54558
54559
54560
54561
54562
54563
54564 abstract protected function describeInputOption(InputOption $option, array $options = array());
54565
54566
54567
54568
54569
54570
54571 abstract protected function describeInputDefinition(InputDefinition $definition, array $options = array());
54572
54573
54574
54575
54576
54577
54578 abstract protected function describeCommand(Command $command, array $options = array());
54579
54580
54581
54582
54583
54584
54585 abstract protected function describeApplication(Application $application, array $options = array());
54586 }
54587 <?php
54588
54589
54590
54591
54592
54593
54594
54595
54596
54597
54598 namespace Symfony\Component\Console\Descriptor;
54599
54600 use Symfony\Component\Console\Output\OutputInterface;
54601
54602
54603
54604
54605
54606
54607 interface DescriptorInterface
54608 {
54609
54610
54611
54612
54613
54614
54615
54616 public function describe(OutputInterface $output, $object, array $options = array());
54617 }
54618 <?php
54619
54620
54621
54622
54623
54624
54625
54626
54627
54628
54629 namespace Symfony\Component\Console\Descriptor;
54630
54631 use Symfony\Component\Console\Application;
54632 use Symfony\Component\Console\Command\Command;
54633 use Symfony\Component\Console\Input\InputArgument;
54634 use Symfony\Component\Console\Input\InputDefinition;
54635 use Symfony\Component\Console\Input\InputOption;
54636
54637
54638
54639
54640
54641
54642
54643
54644 class JsonDescriptor extends Descriptor
54645 {
54646
54647
54648
54649 protected function describeInputArgument(InputArgument $argument, array $options = array())
54650 {
54651 $this->writeData($this->getInputArgumentData($argument), $options);
54652 }
54653
54654
54655
54656
54657 protected function describeInputOption(InputOption $option, array $options = array())
54658 {
54659 $this->writeData($this->getInputOptionData($option), $options);
54660 }
54661
54662
54663
54664
54665 protected function describeInputDefinition(InputDefinition $definition, array $options = array())
54666 {
54667 $this->writeData($this->getInputDefinitionData($definition), $options);
54668 }
54669
54670
54671
54672
54673 protected function describeCommand(Command $command, array $options = array())
54674 {
54675 $this->writeData($this->getCommandData($command), $options);
54676 }
54677
54678
54679
54680
54681 protected function describeApplication(Application $application, array $options = array())
54682 {
54683 $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;
54684 $description = new ApplicationDescription($application, $describedNamespace);
54685 $commands = array();
54686
54687 foreach ($description->getCommands() as $command) {
54688 $commands[] = $this->getCommandData($command);
54689 }
54690
54691 $data = $describedNamespace
54692 ? array('commands' => $commands, 'namespace' => $describedNamespace)
54693 : array('commands' => $commands, 'namespaces' => array_values($description->getNamespaces()));
54694
54695 $this->writeData($data, $options);
54696 }
54697
54698
54699
54700
54701
54702
54703 private function writeData(array $data, array $options)
54704 {
54705 $this->write(json_encode($data, isset($options['json_encoding']) ? $options['json_encoding'] : 0));
54706 }
54707
54708
54709
54710
54711 private function getInputArgumentData(InputArgument $argument)
54712 {
54713 return array(
54714 'name' => $argument->getName(),
54715 'is_required' => $argument->isRequired(),
54716 'is_array' => $argument->isArray(),
54717 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $argument->getDescription()),
54718 'default' => INF === $argument->getDefault() ? 'INF' : $argument->getDefault(),
54719 );
54720 }
54721
54722
54723
54724
54725 private function getInputOptionData(InputOption $option)
54726 {
54727 return array(
54728 'name' => '--'.$option->getName(),
54729 'shortcut' => $option->getShortcut() ? '-'.str_replace('|', '|-', $option->getShortcut()) : '',
54730 'accept_value' => $option->acceptValue(),
54731 'is_value_required' => $option->isValueRequired(),
54732 'is_multiple' => $option->isArray(),
54733 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $option->getDescription()),
54734 'default' => INF === $option->getDefault() ? 'INF' : $option->getDefault(),
54735 );
54736 }
54737
54738
54739
54740
54741 private function getInputDefinitionData(InputDefinition $definition)
54742 {
54743 $inputArguments = array();
54744 foreach ($definition->getArguments() as $name => $argument) {
54745 $inputArguments[$name] = $this->getInputArgumentData($argument);
54746 }
54747
54748 $inputOptions = array();
54749 foreach ($definition->getOptions() as $name => $option) {
54750 $inputOptions[$name] = $this->getInputOptionData($option);
54751 }
54752
54753 return array('arguments' => $inputArguments, 'options' => $inputOptions);
54754 }
54755
54756
54757
54758
54759 private function getCommandData(Command $command)
54760 {
54761 $command->getSynopsis();
54762 $command->mergeApplicationDefinition(false);
54763
54764 return array(
54765 'name' => $command->getName(),
54766 'usage' => array_merge(array($command->getSynopsis()), $command->getUsages(), $command->getAliases()),
54767 'description' => $command->getDescription(),
54768 'help' => $command->getProcessedHelp(),
54769 'definition' => $this->getInputDefinitionData($command->getNativeDefinition()),
54770 );
54771 }
54772 }
54773 <?php
54774
54775
54776
54777
54778
54779
54780
54781
54782
54783
54784 namespace Symfony\Component\Console\Descriptor;
54785
54786 use Symfony\Component\Console\Application;
54787 use Symfony\Component\Console\Command\Command;
54788 use Symfony\Component\Console\Helper\Helper;
54789 use Symfony\Component\Console\Input\InputArgument;
54790 use Symfony\Component\Console\Input\InputDefinition;
54791 use Symfony\Component\Console\Input\InputOption;
54792
54793
54794
54795
54796
54797
54798
54799
54800 class MarkdownDescriptor extends Descriptor
54801 {
54802
54803
54804
54805 protected function describeInputArgument(InputArgument $argument, array $options = array())
54806 {
54807 $this->write(
54808 '**'.$argument->getName().':**'."\n\n"
54809 .'* Name: '.($argument->getName() ?: '<none>')."\n"
54810 .'* Is required: '.($argument->isRequired() ? 'yes' : 'no')."\n"
54811 .'* Is array: '.($argument->isArray() ? 'yes' : 'no')."\n"
54812 .'* Description: '.preg_replace('/\s*[\r\n]\s*/', "\n  ", $argument->getDescription() ?: '<none>')."\n"
54813 .'* Default: `'.str_replace("\n", '', var_export($argument->getDefault(), true)).'`'
54814 );
54815 }
54816
54817
54818
54819
54820 protected function describeInputOption(InputOption $option, array $options = array())
54821 {
54822 $this->write(
54823 '**'.$option->getName().':**'."\n\n"
54824 .'* Name: `--'.$option->getName().'`'."\n"
54825 .'* Shortcut: '.($option->getShortcut() ? '`-'.str_replace('|', '|-', $option->getShortcut()).'`' : '<none>')."\n"
54826 .'* Accept value: '.($option->acceptValue() ? 'yes' : 'no')."\n"
54827 .'* Is value required: '.($option->isValueRequired() ? 'yes' : 'no')."\n"
54828 .'* Is multiple: '.($option->isArray() ? 'yes' : 'no')."\n"
54829 .'* Description: '.preg_replace('/\s*[\r\n]\s*/', "\n  ", $option->getDescription() ?: '<none>')."\n"
54830 .'* Default: `'.str_replace("\n", '', var_export($option->getDefault(), true)).'`'
54831 );
54832 }
54833
54834
54835
54836
54837 protected function describeInputDefinition(InputDefinition $definition, array $options = array())
54838 {
54839 if ($showArguments = \count($definition->getArguments()) > 0) {
54840 $this->write('### Arguments:');
54841 foreach ($definition->getArguments() as $argument) {
54842 $this->write("\n\n");
54843 $this->write($this->describeInputArgument($argument));
54844 }
54845 }
54846
54847 if (\count($definition->getOptions()) > 0) {
54848 if ($showArguments) {
54849 $this->write("\n\n");
54850 }
54851
54852 $this->write('### Options:');
54853 foreach ($definition->getOptions() as $option) {
54854 $this->write("\n\n");
54855 $this->write($this->describeInputOption($option));
54856 }
54857 }
54858 }
54859
54860
54861
54862
54863 protected function describeCommand(Command $command, array $options = array())
54864 {
54865 $command->getSynopsis();
54866 $command->mergeApplicationDefinition(false);
54867
54868 $this->write(
54869 $command->getName()."\n"
54870 .str_repeat('-', Helper::strlen($command->getName()))."\n\n"
54871 .'* Description: '.($command->getDescription() ?: '<none>')."\n"
54872 .'* Usage:'."\n\n"
54873 .array_reduce(array_merge(array($command->getSynopsis()), $command->getAliases(), $command->getUsages()), function ($carry, $usage) {
54874 return $carry.'  * `'.$usage.'`'."\n";
54875 })
54876 );
54877
54878 if ($help = $command->getProcessedHelp()) {
54879 $this->write("\n");
54880 $this->write($help);
54881 }
54882
54883 if ($command->getNativeDefinition()) {
54884 $this->write("\n\n");
54885 $this->describeInputDefinition($command->getNativeDefinition());
54886 }
54887 }
54888
54889
54890
54891
54892 protected function describeApplication(Application $application, array $options = array())
54893 {
54894 $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;
54895 $description = new ApplicationDescription($application, $describedNamespace);
54896
54897 $this->write($application->getName()."\n".str_repeat('=', Helper::strlen($application->getName())));
54898
54899 foreach ($description->getNamespaces() as $namespace) {
54900 if (ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
54901 $this->write("\n\n");
54902 $this->write('**'.$namespace['id'].':**');
54903 }
54904
54905 $this->write("\n\n");
54906 $this->write(implode("\n", array_map(function ($commandName) {
54907 return '* '.$commandName;
54908 }, $namespace['commands'])));
54909 }
54910
54911 foreach ($description->getCommands() as $command) {
54912 $this->write("\n\n");
54913 $this->write($this->describeCommand($command));
54914 }
54915 }
54916 }
54917 <?php
54918
54919
54920
54921
54922
54923
54924
54925
54926
54927
54928 namespace Symfony\Component\Console\Descriptor;
54929
54930 use Symfony\Component\Console\Application;
54931 use Symfony\Component\Console\Command\Command;
54932 use Symfony\Component\Console\Formatter\OutputFormatter;
54933 use Symfony\Component\Console\Helper\Helper;
54934 use Symfony\Component\Console\Input\InputArgument;
54935 use Symfony\Component\Console\Input\InputDefinition;
54936 use Symfony\Component\Console\Input\InputOption;
54937
54938
54939
54940
54941
54942
54943
54944
54945 class TextDescriptor extends Descriptor
54946 {
54947
54948
54949
54950 protected function describeInputArgument(InputArgument $argument, array $options = array())
54951 {
54952 if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) {
54953 $default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($argument->getDefault()));
54954 } else {
54955 $default = '';
54956 }
54957
54958 $totalWidth = isset($options['total_width']) ? $options['total_width'] : Helper::strlen($argument->getName());
54959 $spacingWidth = $totalWidth - \strlen($argument->getName());
54960
54961 $this->writeText(sprintf('  <info>%s</info>  %s%s%s',
54962 $argument->getName(),
54963 str_repeat(' ', $spacingWidth),
54964
54965 preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $argument->getDescription()),
54966 $default
54967 ), $options);
54968 }
54969
54970
54971
54972
54973 protected function describeInputOption(InputOption $option, array $options = array())
54974 {
54975 if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) {
54976 $default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($option->getDefault()));
54977 } else {
54978 $default = '';
54979 }
54980
54981 $value = '';
54982 if ($option->acceptValue()) {
54983 $value = '='.strtoupper($option->getName());
54984
54985 if ($option->isValueOptional()) {
54986 $value = '['.$value.']';
54987 }
54988 }
54989
54990 $totalWidth = isset($options['total_width']) ? $options['total_width'] : $this->calculateTotalWidthForOptions(array($option));
54991 $synopsis = sprintf('%s%s',
54992 $option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : '    ',
54993 sprintf('--%s%s', $option->getName(), $value)
54994 );
54995
54996 $spacingWidth = $totalWidth - Helper::strlen($synopsis);
54997
54998 $this->writeText(sprintf('  <info>%s</info>  %s%s%s%s',
54999 $synopsis,
55000 str_repeat(' ', $spacingWidth),
55001
55002 preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $option->getDescription()),
55003 $default,
55004 $option->isArray() ? '<comment> (multiple values allowed)</comment>' : ''
55005 ), $options);
55006 }
55007
55008
55009
55010
55011 protected function describeInputDefinition(InputDefinition $definition, array $options = array())
55012 {
55013 $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions());
55014 foreach ($definition->getArguments() as $argument) {
55015 $totalWidth = max($totalWidth, Helper::strlen($argument->getName()));
55016 }
55017
55018 if ($definition->getArguments()) {
55019 $this->writeText('<comment>Arguments:</comment>', $options);
55020 $this->writeText("\n");
55021 foreach ($definition->getArguments() as $argument) {
55022 $this->describeInputArgument($argument, array_merge($options, array('total_width' => $totalWidth)));
55023 $this->writeText("\n");
55024 }
55025 }
55026
55027 if ($definition->getArguments() && $definition->getOptions()) {
55028 $this->writeText("\n");
55029 }
55030
55031 if ($definition->getOptions()) {
55032 $laterOptions = array();
55033
55034 $this->writeText('<comment>Options:</comment>', $options);
55035 foreach ($definition->getOptions() as $option) {
55036 if (\strlen($option->getShortcut()) > 1) {
55037 $laterOptions[] = $option;
55038 continue;
55039 }
55040 $this->writeText("\n");
55041 $this->describeInputOption($option, array_merge($options, array('total_width' => $totalWidth)));
55042 }
55043 foreach ($laterOptions as $option) {
55044 $this->writeText("\n");
55045 $this->describeInputOption($option, array_merge($options, array('total_width' => $totalWidth)));
55046 }
55047 }
55048 }
55049
55050
55051
55052
55053 protected function describeCommand(Command $command, array $options = array())
55054 {
55055 $command->getSynopsis(true);
55056 $command->getSynopsis(false);
55057 $command->mergeApplicationDefinition(false);
55058
55059 $this->writeText('<comment>Usage:</comment>', $options);
55060 foreach (array_merge(array($command->getSynopsis(true)), $command->getAliases(), $command->getUsages()) as $usage) {
55061 $this->writeText("\n");
55062 $this->writeText('  '.OutputFormatter::escape($usage), $options);
55063 }
55064 $this->writeText("\n");
55065
55066 $definition = $command->getNativeDefinition();
55067 if ($definition->getOptions() || $definition->getArguments()) {
55068 $this->writeText("\n");
55069 $this->describeInputDefinition($definition, $options);
55070 $this->writeText("\n");
55071 }
55072
55073 if ($help = $command->getProcessedHelp()) {
55074 $this->writeText("\n");
55075 $this->writeText('<comment>Help:</comment>', $options);
55076 $this->writeText("\n");
55077 $this->writeText('  '.str_replace("\n", "\n  ", $help), $options);
55078 $this->writeText("\n");
55079 }
55080 }
55081
55082
55083
55084
55085 protected function describeApplication(Application $application, array $options = array())
55086 {
55087 $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;
55088 $description = new ApplicationDescription($application, $describedNamespace);
55089
55090 if (isset($options['raw_text']) && $options['raw_text']) {
55091 $width = $this->getColumnWidth($description->getCommands());
55092
55093 foreach ($description->getCommands() as $command) {
55094 $this->writeText(sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options);
55095 $this->writeText("\n");
55096 }
55097 } else {
55098 if ('' != $help = $application->getHelp()) {
55099 $this->writeText("$help\n\n", $options);
55100 }
55101
55102 $this->writeText("<comment>Usage:</comment>\n", $options);
55103 $this->writeText("  command [options] [arguments]\n\n", $options);
55104
55105 $this->describeInputDefinition(new InputDefinition($application->getDefinition()->getOptions()), $options);
55106
55107 $this->writeText("\n");
55108 $this->writeText("\n");
55109
55110 $width = $this->getColumnWidth($description->getCommands());
55111
55112 if ($describedNamespace) {
55113 $this->writeText(sprintf('<comment>Available commands for the "%s" namespace:</comment>', $describedNamespace), $options);
55114 } else {
55115 $this->writeText('<comment>Available commands:</comment>', $options);
55116 }
55117
55118
55119 foreach ($description->getNamespaces() as $namespace) {
55120 if (!$describedNamespace && ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
55121 $this->writeText("\n");
55122 $this->writeText(' <comment>'.$namespace['id'].'</comment>', $options);
55123 }
55124
55125 foreach ($namespace['commands'] as $name) {
55126 $this->writeText("\n");
55127 $spacingWidth = $width - Helper::strlen($name);
55128 $this->writeText(sprintf('  <info>%s</info>%s%s', $name, str_repeat(' ', $spacingWidth), $description->getCommand($name)->getDescription()), $options);
55129 }
55130 }
55131
55132 $this->writeText("\n");
55133 }
55134 }
55135
55136
55137
55138
55139 private function writeText($content, array $options = array())
55140 {
55141 $this->write(
55142 isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content,
55143 isset($options['raw_output']) ? !$options['raw_output'] : true
55144 );
55145 }
55146
55147
55148
55149
55150
55151
55152
55153
55154 private function formatDefaultValue($default)
55155 {
55156 if (INF === $default) {
55157 return 'INF';
55158 }
55159
55160 if (\is_string($default)) {
55161 $default = OutputFormatter::escape($default);
55162 } elseif (\is_array($default)) {
55163 foreach ($default as $key => $value) {
55164 if (\is_string($value)) {
55165 $default[$key] = OutputFormatter::escape($value);
55166 }
55167 }
55168 }
55169
55170 if (\PHP_VERSION_ID < 50400) {
55171 return str_replace(array('\/', '\\\\'), array('/', '\\'), json_encode($default));
55172 }
55173
55174 return str_replace('\\\\', '\\', json_encode($default, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
55175 }
55176
55177
55178
55179
55180
55181
55182 private function getColumnWidth(array $commands)
55183 {
55184 $widths = array();
55185
55186 foreach ($commands as $command) {
55187 $widths[] = Helper::strlen($command->getName());
55188 foreach ($command->getAliases() as $alias) {
55189 $widths[] = Helper::strlen($alias);
55190 }
55191 }
55192
55193 return max($widths) + 2;
55194 }
55195
55196
55197
55198
55199
55200
55201 private function calculateTotalWidthForOptions(array $options)
55202 {
55203 $totalWidth = 0;
55204 foreach ($options as $option) {
55205
55206 $nameLength = 1 + max(\strlen($option->getShortcut()), 1) + 4 + Helper::strlen($option->getName());
55207
55208 if ($option->acceptValue()) {
55209 $valueLength = 1 + Helper::strlen($option->getName()); 
55210 $valueLength += $option->isValueOptional() ? 2 : 0; 
55211
55212 $nameLength += $valueLength;
55213 }
55214 $totalWidth = max($totalWidth, $nameLength);
55215 }
55216
55217 return $totalWidth;
55218 }
55219 }
55220 <?php
55221
55222
55223
55224
55225
55226
55227
55228
55229
55230
55231 namespace Symfony\Component\Console\Descriptor;
55232
55233 use Symfony\Component\Console\Application;
55234 use Symfony\Component\Console\Command\Command;
55235 use Symfony\Component\Console\Input\InputArgument;
55236 use Symfony\Component\Console\Input\InputDefinition;
55237 use Symfony\Component\Console\Input\InputOption;
55238
55239
55240
55241
55242
55243
55244
55245
55246 class XmlDescriptor extends Descriptor
55247 {
55248
55249
55250
55251 public function getInputDefinitionDocument(InputDefinition $definition)
55252 {
55253 $dom = new \DOMDocument('1.0', 'UTF-8');
55254 $dom->appendChild($definitionXML = $dom->createElement('definition'));
55255
55256 $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments'));
55257 foreach ($definition->getArguments() as $argument) {
55258 $this->appendDocument($argumentsXML, $this->getInputArgumentDocument($argument));
55259 }
55260
55261 $definitionXML->appendChild($optionsXML = $dom->createElement('options'));
55262 foreach ($definition->getOptions() as $option) {
55263 $this->appendDocument($optionsXML, $this->getInputOptionDocument($option));
55264 }
55265
55266 return $dom;
55267 }
55268
55269
55270
55271
55272 public function getCommandDocument(Command $command)
55273 {
55274 $dom = new \DOMDocument('1.0', 'UTF-8');
55275 $dom->appendChild($commandXML = $dom->createElement('command'));
55276
55277 $command->getSynopsis();
55278 $command->mergeApplicationDefinition(false);
55279
55280 $commandXML->setAttribute('id', $command->getName());
55281 $commandXML->setAttribute('name', $command->getName());
55282
55283 $commandXML->appendChild($usagesXML = $dom->createElement('usages'));
55284
55285 foreach (array_merge(array($command->getSynopsis()), $command->getAliases(), $command->getUsages()) as $usage) {
55286 $usagesXML->appendChild($dom->createElement('usage', $usage));
55287 }
55288
55289 $commandXML->appendChild($descriptionXML = $dom->createElement('description'));
55290 $descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getDescription())));
55291
55292 $commandXML->appendChild($helpXML = $dom->createElement('help'));
55293 $helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getProcessedHelp())));
55294
55295 $definitionXML = $this->getInputDefinitionDocument($command->getNativeDefinition());
55296 $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0));
55297
55298 return $dom;
55299 }
55300
55301
55302
55303
55304
55305
55306
55307 public function getApplicationDocument(Application $application, $namespace = null)
55308 {
55309 $dom = new \DOMDocument('1.0', 'UTF-8');
55310 $dom->appendChild($rootXml = $dom->createElement('symfony'));
55311
55312 if ('UNKNOWN' !== $application->getName()) {
55313 $rootXml->setAttribute('name', $application->getName());
55314 if ('UNKNOWN' !== $application->getVersion()) {
55315 $rootXml->setAttribute('version', $application->getVersion());
55316 }
55317 }
55318
55319 $rootXml->appendChild($commandsXML = $dom->createElement('commands'));
55320
55321 $description = new ApplicationDescription($application, $namespace);
55322
55323 if ($namespace) {
55324 $commandsXML->setAttribute('namespace', $namespace);
55325 }
55326
55327 foreach ($description->getCommands() as $command) {
55328 $this->appendDocument($commandsXML, $this->getCommandDocument($command));
55329 }
55330
55331 if (!$namespace) {
55332 $rootXml->appendChild($namespacesXML = $dom->createElement('namespaces'));
55333
55334 foreach ($description->getNamespaces() as $namespaceDescription) {
55335 $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace'));
55336 $namespaceArrayXML->setAttribute('id', $namespaceDescription['id']);
55337
55338 foreach ($namespaceDescription['commands'] as $name) {
55339 $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command'));
55340 $commandXML->appendChild($dom->createTextNode($name));
55341 }
55342 }
55343 }
55344
55345 return $dom;
55346 }
55347
55348
55349
55350
55351 protected function describeInputArgument(InputArgument $argument, array $options = array())
55352 {
55353 $this->writeDocument($this->getInputArgumentDocument($argument));
55354 }
55355
55356
55357
55358
55359 protected function describeInputOption(InputOption $option, array $options = array())
55360 {
55361 $this->writeDocument($this->getInputOptionDocument($option));
55362 }
55363
55364
55365
55366
55367 protected function describeInputDefinition(InputDefinition $definition, array $options = array())
55368 {
55369 $this->writeDocument($this->getInputDefinitionDocument($definition));
55370 }
55371
55372
55373
55374
55375 protected function describeCommand(Command $command, array $options = array())
55376 {
55377 $this->writeDocument($this->getCommandDocument($command));
55378 }
55379
55380
55381
55382
55383 protected function describeApplication(Application $application, array $options = array())
55384 {
55385 $this->writeDocument($this->getApplicationDocument($application, isset($options['namespace']) ? $options['namespace'] : null));
55386 }
55387
55388
55389
55390
55391 private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent)
55392 {
55393 foreach ($importedParent->childNodes as $childNode) {
55394 $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, true));
55395 }
55396 }
55397
55398
55399
55400
55401
55402
55403 private function writeDocument(\DOMDocument $dom)
55404 {
55405 $dom->formatOutput = true;
55406 $this->write($dom->saveXML());
55407 }
55408
55409
55410
55411
55412 private function getInputArgumentDocument(InputArgument $argument)
55413 {
55414 $dom = new \DOMDocument('1.0', 'UTF-8');
55415
55416 $dom->appendChild($objectXML = $dom->createElement('argument'));
55417 $objectXML->setAttribute('name', $argument->getName());
55418 $objectXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0);
55419 $objectXML->setAttribute('is_array', $argument->isArray() ? 1 : 0);
55420 $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
55421 $descriptionXML->appendChild($dom->createTextNode($argument->getDescription()));
55422
55423 $objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));
55424 $defaults = \is_array($argument->getDefault()) ? $argument->getDefault() : (\is_bool($argument->getDefault()) ? array(var_export($argument->getDefault(), true)) : ($argument->getDefault() ? array($argument->getDefault()) : array()));
55425 foreach ($defaults as $default) {
55426 $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
55427 $defaultXML->appendChild($dom->createTextNode($default));
55428 }
55429
55430 return $dom;
55431 }
55432
55433
55434
55435
55436 private function getInputOptionDocument(InputOption $option)
55437 {
55438 $dom = new \DOMDocument('1.0', 'UTF-8');
55439
55440 $dom->appendChild($objectXML = $dom->createElement('option'));
55441 $objectXML->setAttribute('name', '--'.$option->getName());
55442 $pos = strpos($option->getShortcut(), '|');
55443 if (false !== $pos) {
55444 $objectXML->setAttribute('shortcut', '-'.substr($option->getShortcut(), 0, $pos));
55445 $objectXML->setAttribute('shortcuts', '-'.str_replace('|', '|-', $option->getShortcut()));
55446 } else {
55447 $objectXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : '');
55448 }
55449 $objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0);
55450 $objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0);
55451 $objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0);
55452 $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
55453 $descriptionXML->appendChild($dom->createTextNode($option->getDescription()));
55454
55455 if ($option->acceptValue()) {
55456 $defaults = \is_array($option->getDefault()) ? $option->getDefault() : (\is_bool($option->getDefault()) ? array(var_export($option->getDefault(), true)) : ($option->getDefault() ? array($option->getDefault()) : array()));
55457 $objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));
55458
55459 if (!empty($defaults)) {
55460 foreach ($defaults as $default) {
55461 $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
55462 $defaultXML->appendChild($dom->createTextNode($default));
55463 }
55464 }
55465 }
55466
55467 return $dom;
55468 }
55469 }
55470 <?php
55471
55472
55473
55474
55475
55476
55477
55478
55479
55480
55481 namespace Symfony\Component\Console\Event;
55482
55483
55484
55485
55486
55487
55488 class ConsoleCommandEvent extends ConsoleEvent
55489 {
55490
55491
55492
55493 const RETURN_CODE_DISABLED = 113;
55494
55495
55496
55497
55498 private $commandShouldRun = true;
55499
55500
55501
55502
55503
55504
55505 public function disableCommand()
55506 {
55507 return $this->commandShouldRun = false;
55508 }
55509
55510
55511
55512
55513
55514
55515 public function enableCommand()
55516 {
55517 return $this->commandShouldRun = true;
55518 }
55519
55520
55521
55522
55523
55524
55525 public function commandShouldRun()
55526 {
55527 return $this->commandShouldRun;
55528 }
55529 }
55530 <?php
55531
55532
55533
55534
55535
55536
55537
55538
55539
55540
55541 namespace Symfony\Component\Console\Event;
55542
55543 use Symfony\Component\Console\Command\Command;
55544 use Symfony\Component\Console\Input\InputInterface;
55545 use Symfony\Component\Console\Output\OutputInterface;
55546 use Symfony\Component\EventDispatcher\Event;
55547
55548
55549
55550
55551
55552
55553 class ConsoleEvent extends Event
55554 {
55555 protected $command;
55556
55557 private $input;
55558 private $output;
55559
55560 public function __construct(Command $command, InputInterface $input, OutputInterface $output)
55561 {
55562 $this->command = $command;
55563 $this->input = $input;
55564 $this->output = $output;
55565 }
55566
55567
55568
55569
55570
55571
55572 public function getCommand()
55573 {
55574 return $this->command;
55575 }
55576
55577
55578
55579
55580
55581
55582 public function getInput()
55583 {
55584 return $this->input;
55585 }
55586
55587
55588
55589
55590
55591
55592 public function getOutput()
55593 {
55594 return $this->output;
55595 }
55596 }
55597 <?php
55598
55599
55600
55601
55602
55603
55604
55605
55606
55607
55608 namespace Symfony\Component\Console\Event;
55609
55610 use Symfony\Component\Console\Command\Command;
55611 use Symfony\Component\Console\Input\InputInterface;
55612 use Symfony\Component\Console\Output\OutputInterface;
55613
55614
55615
55616
55617
55618
55619 class ConsoleExceptionEvent extends ConsoleEvent
55620 {
55621 private $exception;
55622 private $exitCode;
55623
55624 public function __construct(Command $command, InputInterface $input, OutputInterface $output, \Exception $exception, $exitCode)
55625 {
55626 parent::__construct($command, $input, $output);
55627
55628 $this->setException($exception);
55629 $this->exitCode = (int) $exitCode;
55630 }
55631
55632
55633
55634
55635
55636
55637 public function getException()
55638 {
55639 return $this->exception;
55640 }
55641
55642
55643
55644
55645
55646
55647
55648
55649 public function setException(\Exception $exception)
55650 {
55651 $this->exception = $exception;
55652 }
55653
55654
55655
55656
55657
55658
55659 public function getExitCode()
55660 {
55661 return $this->exitCode;
55662 }
55663 }
55664 <?php
55665
55666
55667
55668
55669
55670
55671
55672
55673
55674
55675 namespace Symfony\Component\Console\Event;
55676
55677 use Symfony\Component\Console\Command\Command;
55678 use Symfony\Component\Console\Input\InputInterface;
55679 use Symfony\Component\Console\Output\OutputInterface;
55680
55681
55682
55683
55684
55685
55686 class ConsoleTerminateEvent extends ConsoleEvent
55687 {
55688
55689
55690
55691
55692
55693 private $exitCode;
55694
55695 public function __construct(Command $command, InputInterface $input, OutputInterface $output, $exitCode)
55696 {
55697 parent::__construct($command, $input, $output);
55698
55699 $this->setExitCode($exitCode);
55700 }
55701
55702
55703
55704
55705
55706
55707 public function setExitCode($exitCode)
55708 {
55709 $this->exitCode = (int) $exitCode;
55710 }
55711
55712
55713
55714
55715
55716
55717 public function getExitCode()
55718 {
55719 return $this->exitCode;
55720 }
55721 }
55722 <?php
55723
55724
55725
55726
55727
55728
55729
55730
55731
55732
55733 namespace Symfony\Component\Console\Exception;
55734
55735
55736
55737
55738
55739
55740 class CommandNotFoundException extends \InvalidArgumentException implements ExceptionInterface
55741 {
55742 private $alternatives;
55743
55744
55745
55746
55747
55748
55749
55750 public function __construct($message, array $alternatives = array(), $code = 0, \Exception $previous = null)
55751 {
55752 parent::__construct($message, $code, $previous);
55753
55754 $this->alternatives = $alternatives;
55755 }
55756
55757
55758
55759
55760 public function getAlternatives()
55761 {
55762 return $this->alternatives;
55763 }
55764 }
55765 <?php
55766
55767
55768
55769
55770
55771
55772
55773
55774
55775
55776 namespace Symfony\Component\Console\Exception;
55777
55778
55779
55780
55781
55782
55783 interface ExceptionInterface
55784 {
55785 }
55786 <?php
55787
55788
55789
55790
55791
55792
55793
55794
55795
55796
55797 namespace Symfony\Component\Console\Exception;
55798
55799
55800
55801
55802 class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
55803 {
55804 }
55805 <?php
55806
55807
55808
55809
55810
55811
55812
55813
55814
55815
55816 namespace Symfony\Component\Console\Exception;
55817
55818
55819
55820
55821
55822
55823 class InvalidOptionException extends \InvalidArgumentException implements ExceptionInterface
55824 {
55825 }
55826 <?php
55827
55828
55829
55830
55831
55832
55833
55834
55835
55836
55837 namespace Symfony\Component\Console\Exception;
55838
55839
55840
55841
55842 class LogicException extends \LogicException implements ExceptionInterface
55843 {
55844 }
55845 <?php
55846
55847
55848
55849
55850
55851
55852
55853
55854
55855
55856 namespace Symfony\Component\Console\Exception;
55857
55858
55859
55860
55861 class RuntimeException extends \RuntimeException implements ExceptionInterface
55862 {
55863 }
55864 <?php
55865
55866
55867
55868
55869
55870
55871
55872
55873
55874
55875 namespace Symfony\Component\Console\Formatter;
55876
55877 use Symfony\Component\Console\Exception\InvalidArgumentException;
55878
55879
55880
55881
55882
55883
55884 class OutputFormatter implements OutputFormatterInterface
55885 {
55886 private $decorated;
55887 private $styles = array();
55888 private $styleStack;
55889
55890
55891
55892
55893
55894
55895
55896
55897 public static function escape($text)
55898 {
55899 $text = preg_replace('/([^\\\\]?)</', '$1\\<', $text);
55900
55901 return self::escapeTrailingBackslash($text);
55902 }
55903
55904
55905
55906
55907
55908
55909
55910
55911
55912
55913 public static function escapeTrailingBackslash($text)
55914 {
55915 if ('\\' === substr($text, -1)) {
55916 $len = \strlen($text);
55917 $text = rtrim($text, '\\');
55918 $text = str_replace("\0", '', $text);
55919 $text .= str_repeat("\0", $len - \strlen($text));
55920 }
55921
55922 return $text;
55923 }
55924
55925
55926
55927
55928
55929
55930
55931 public function __construct($decorated = false, array $styles = array())
55932 {
55933 $this->decorated = (bool) $decorated;
55934
55935 $this->setStyle('error', new OutputFormatterStyle('white', 'red'));
55936 $this->setStyle('info', new OutputFormatterStyle('green'));
55937 $this->setStyle('comment', new OutputFormatterStyle('yellow'));
55938 $this->setStyle('question', new OutputFormatterStyle('black', 'cyan'));
55939
55940 foreach ($styles as $name => $style) {
55941 $this->setStyle($name, $style);
55942 }
55943
55944 $this->styleStack = new OutputFormatterStyleStack();
55945 }
55946
55947
55948
55949
55950 public function setDecorated($decorated)
55951 {
55952 $this->decorated = (bool) $decorated;
55953 }
55954
55955
55956
55957
55958 public function isDecorated()
55959 {
55960 return $this->decorated;
55961 }
55962
55963
55964
55965
55966 public function setStyle($name, OutputFormatterStyleInterface $style)
55967 {
55968 $this->styles[strtolower($name)] = $style;
55969 }
55970
55971
55972
55973
55974 public function hasStyle($name)
55975 {
55976 return isset($this->styles[strtolower($name)]);
55977 }
55978
55979
55980
55981
55982 public function getStyle($name)
55983 {
55984 if (!$this->hasStyle($name)) {
55985 throw new InvalidArgumentException(sprintf('Undefined style: %s', $name));
55986 }
55987
55988 return $this->styles[strtolower($name)];
55989 }
55990
55991
55992
55993
55994 public function format($message)
55995 {
55996 $message = (string) $message;
55997 $offset = 0;
55998 $output = '';
55999 $tagRegex = '[a-z][a-z0-9_=;-]*+';
56000 preg_match_all("#<(($tagRegex) | /($tagRegex)?)>#ix", $message, $matches, PREG_OFFSET_CAPTURE);
56001 foreach ($matches[0] as $i => $match) {
56002 $pos = $match[1];
56003 $text = $match[0];
56004
56005 if (0 != $pos && '\\' == $message[$pos - 1]) {
56006 continue;
56007 }
56008
56009
56010 $output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset));
56011 $offset = $pos + \strlen($text);
56012
56013
56014 if ($open = '/' != $text[1]) {
56015 $tag = $matches[1][$i][0];
56016 } else {
56017 $tag = isset($matches[3][$i][0]) ? $matches[3][$i][0] : '';
56018 }
56019
56020 if (!$open && !$tag) {
56021
56022 $this->styleStack->pop();
56023 } elseif (false === $style = $this->createStyleFromString(strtolower($tag))) {
56024 $output .= $this->applyCurrentStyle($text);
56025 } elseif ($open) {
56026 $this->styleStack->push($style);
56027 } else {
56028 $this->styleStack->pop($style);
56029 }
56030 }
56031
56032 $output .= $this->applyCurrentStyle(substr($message, $offset));
56033
56034 if (false !== strpos($output, "\0")) {
56035 return strtr($output, array("\0" => '\\', '\\<' => '<'));
56036 }
56037
56038 return str_replace('\\<', '<', $output);
56039 }
56040
56041
56042
56043
56044 public function getStyleStack()
56045 {
56046 return $this->styleStack;
56047 }
56048
56049
56050
56051
56052
56053
56054
56055
56056 private function createStyleFromString($string)
56057 {
56058 if (isset($this->styles[$string])) {
56059 return $this->styles[$string];
56060 }
56061
56062 if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', strtolower($string), $matches, PREG_SET_ORDER)) {
56063 return false;
56064 }
56065
56066 $style = new OutputFormatterStyle();
56067 foreach ($matches as $match) {
56068 array_shift($match);
56069
56070 if ('fg' == $match[0]) {
56071 $style->setForeground($match[1]);
56072 } elseif ('bg' == $match[0]) {
56073 $style->setBackground($match[1]);
56074 } else {
56075 try {
56076 $style->setOption($match[1]);
56077 } catch (\InvalidArgumentException $e) {
56078 return false;
56079 }
56080 }
56081 }
56082
56083 return $style;
56084 }
56085
56086
56087
56088
56089
56090
56091
56092
56093 private function applyCurrentStyle($text)
56094 {
56095 return $this->isDecorated() && \strlen($text) > 0 ? $this->styleStack->getCurrent()->apply($text) : $text;
56096 }
56097 }
56098 <?php
56099
56100
56101
56102
56103
56104
56105
56106
56107
56108
56109 namespace Symfony\Component\Console\Formatter;
56110
56111
56112
56113
56114
56115
56116 interface OutputFormatterInterface
56117 {
56118
56119
56120
56121
56122
56123 public function setDecorated($decorated);
56124
56125
56126
56127
56128
56129
56130 public function isDecorated();
56131
56132
56133
56134
56135
56136
56137
56138 public function setStyle($name, OutputFormatterStyleInterface $style);
56139
56140
56141
56142
56143
56144
56145
56146
56147 public function hasStyle($name);
56148
56149
56150
56151
56152
56153
56154
56155
56156
56157
56158 public function getStyle($name);
56159
56160
56161
56162
56163
56164
56165
56166
56167 public function format($message);
56168 }
56169 <?php
56170
56171
56172
56173
56174
56175
56176
56177
56178
56179
56180 namespace Symfony\Component\Console\Formatter;
56181
56182 use Symfony\Component\Console\Exception\InvalidArgumentException;
56183
56184
56185
56186
56187
56188
56189 class OutputFormatterStyle implements OutputFormatterStyleInterface
56190 {
56191 private static $availableForegroundColors = array(
56192 'black' => array('set' => 30, 'unset' => 39),
56193 'red' => array('set' => 31, 'unset' => 39),
56194 'green' => array('set' => 32, 'unset' => 39),
56195 'yellow' => array('set' => 33, 'unset' => 39),
56196 'blue' => array('set' => 34, 'unset' => 39),
56197 'magenta' => array('set' => 35, 'unset' => 39),
56198 'cyan' => array('set' => 36, 'unset' => 39),
56199 'white' => array('set' => 37, 'unset' => 39),
56200 'default' => array('set' => 39, 'unset' => 39),
56201 );
56202 private static $availableBackgroundColors = array(
56203 'black' => array('set' => 40, 'unset' => 49),
56204 'red' => array('set' => 41, 'unset' => 49),
56205 'green' => array('set' => 42, 'unset' => 49),
56206 'yellow' => array('set' => 43, 'unset' => 49),
56207 'blue' => array('set' => 44, 'unset' => 49),
56208 'magenta' => array('set' => 45, 'unset' => 49),
56209 'cyan' => array('set' => 46, 'unset' => 49),
56210 'white' => array('set' => 47, 'unset' => 49),
56211 'default' => array('set' => 49, 'unset' => 49),
56212 );
56213 private static $availableOptions = array(
56214 'bold' => array('set' => 1, 'unset' => 22),
56215 'underscore' => array('set' => 4, 'unset' => 24),
56216 'blink' => array('set' => 5, 'unset' => 25),
56217 'reverse' => array('set' => 7, 'unset' => 27),
56218 'conceal' => array('set' => 8, 'unset' => 28),
56219 );
56220
56221 private $foreground;
56222 private $background;
56223 private $options = array();
56224
56225
56226
56227
56228
56229
56230
56231
56232 public function __construct($foreground = null, $background = null, array $options = array())
56233 {
56234 if (null !== $foreground) {
56235 $this->setForeground($foreground);
56236 }
56237 if (null !== $background) {
56238 $this->setBackground($background);
56239 }
56240 if (\count($options)) {
56241 $this->setOptions($options);
56242 }
56243 }
56244
56245
56246
56247
56248
56249
56250
56251
56252 public function setForeground($color = null)
56253 {
56254 if (null === $color) {
56255 $this->foreground = null;
56256
56257 return;
56258 }
56259
56260 if (!isset(static::$availableForegroundColors[$color])) {
56261 throw new InvalidArgumentException(sprintf('Invalid foreground color specified: "%s". Expected one of (%s)', $color, implode(', ', array_keys(static::$availableForegroundColors))));
56262 }
56263
56264 $this->foreground = static::$availableForegroundColors[$color];
56265 }
56266
56267
56268
56269
56270
56271
56272
56273
56274 public function setBackground($color = null)
56275 {
56276 if (null === $color) {
56277 $this->background = null;
56278
56279 return;
56280 }
56281
56282 if (!isset(static::$availableBackgroundColors[$color])) {
56283 throw new InvalidArgumentException(sprintf('Invalid background color specified: "%s". Expected one of (%s)', $color, implode(', ', array_keys(static::$availableBackgroundColors))));
56284 }
56285
56286 $this->background = static::$availableBackgroundColors[$color];
56287 }
56288
56289
56290
56291
56292
56293
56294
56295
56296 public function setOption($option)
56297 {
56298 if (!isset(static::$availableOptions[$option])) {
56299 throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s)', $option, implode(', ', array_keys(static::$availableOptions))));
56300 }
56301
56302 if (!\in_array(static::$availableOptions[$option], $this->options)) {
56303 $this->options[] = static::$availableOptions[$option];
56304 }
56305 }
56306
56307
56308
56309
56310
56311
56312
56313
56314 public function unsetOption($option)
56315 {
56316 if (!isset(static::$availableOptions[$option])) {
56317 throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s)', $option, implode(', ', array_keys(static::$availableOptions))));
56318 }
56319
56320 $pos = array_search(static::$availableOptions[$option], $this->options);
56321 if (false !== $pos) {
56322 unset($this->options[$pos]);
56323 }
56324 }
56325
56326
56327
56328
56329 public function setOptions(array $options)
56330 {
56331 $this->options = array();
56332
56333 foreach ($options as $option) {
56334 $this->setOption($option);
56335 }
56336 }
56337
56338
56339
56340
56341
56342
56343
56344
56345 public function apply($text)
56346 {
56347 $setCodes = array();
56348 $unsetCodes = array();
56349
56350 if (null !== $this->foreground) {
56351 $setCodes[] = $this->foreground['set'];
56352 $unsetCodes[] = $this->foreground['unset'];
56353 }
56354 if (null !== $this->background) {
56355 $setCodes[] = $this->background['set'];
56356 $unsetCodes[] = $this->background['unset'];
56357 }
56358 if (\count($this->options)) {
56359 foreach ($this->options as $option) {
56360 $setCodes[] = $option['set'];
56361 $unsetCodes[] = $option['unset'];
56362 }
56363 }
56364
56365 if (0 === \count($setCodes)) {
56366 return $text;
56367 }
56368
56369 return sprintf("\033[%sm%s\033[%sm", implode(';', $setCodes), $text, implode(';', $unsetCodes));
56370 }
56371 }
56372 <?php
56373
56374
56375
56376
56377
56378
56379
56380
56381
56382
56383 namespace Symfony\Component\Console\Formatter;
56384
56385
56386
56387
56388
56389
56390 interface OutputFormatterStyleInterface
56391 {
56392
56393
56394
56395
56396
56397 public function setForeground($color = null);
56398
56399
56400
56401
56402
56403
56404 public function setBackground($color = null);
56405
56406
56407
56408
56409
56410
56411 public function setOption($option);
56412
56413
56414
56415
56416
56417
56418 public function unsetOption($option);
56419
56420
56421
56422
56423 public function setOptions(array $options);
56424
56425
56426
56427
56428
56429
56430
56431
56432 public function apply($text);
56433 }
56434 <?php
56435
56436
56437
56438
56439
56440
56441
56442
56443
56444
56445 namespace Symfony\Component\Console\Formatter;
56446
56447 use Symfony\Component\Console\Exception\InvalidArgumentException;
56448
56449
56450
56451
56452 class OutputFormatterStyleStack
56453 {
56454
56455
56456
56457 private $styles;
56458
56459 private $emptyStyle;
56460
56461 public function __construct(OutputFormatterStyleInterface $emptyStyle = null)
56462 {
56463 $this->emptyStyle = $emptyStyle ?: new OutputFormatterStyle();
56464 $this->reset();
56465 }
56466
56467
56468
56469
56470 public function reset()
56471 {
56472 $this->styles = array();
56473 }
56474
56475
56476
56477
56478 public function push(OutputFormatterStyleInterface $style)
56479 {
56480 $this->styles[] = $style;
56481 }
56482
56483
56484
56485
56486
56487
56488
56489
56490 public function pop(OutputFormatterStyleInterface $style = null)
56491 {
56492 if (empty($this->styles)) {
56493 return $this->emptyStyle;
56494 }
56495
56496 if (null === $style) {
56497 return array_pop($this->styles);
56498 }
56499
56500 foreach (array_reverse($this->styles, true) as $index => $stackedStyle) {
56501 if ($style->apply('') === $stackedStyle->apply('')) {
56502 $this->styles = \array_slice($this->styles, 0, $index);
56503
56504 return $stackedStyle;
56505 }
56506 }
56507
56508 throw new InvalidArgumentException('Incorrectly nested style tag found.');
56509 }
56510
56511
56512
56513
56514
56515
56516 public function getCurrent()
56517 {
56518 if (empty($this->styles)) {
56519 return $this->emptyStyle;
56520 }
56521
56522 return $this->styles[\count($this->styles) - 1];
56523 }
56524
56525
56526
56527
56528 public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle)
56529 {
56530 $this->emptyStyle = $emptyStyle;
56531
56532 return $this;
56533 }
56534
56535
56536
56537
56538 public function getEmptyStyle()
56539 {
56540 return $this->emptyStyle;
56541 }
56542 }
56543 <?php
56544
56545
56546
56547
56548
56549
56550
56551
56552
56553
56554 namespace Symfony\Component\Console\Helper;
56555
56556
56557
56558
56559
56560
56561
56562
56563 class DebugFormatterHelper extends Helper
56564 {
56565 private $colors = array('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default');
56566 private $started = array();
56567 private $count = -1;
56568
56569
56570
56571
56572
56573
56574
56575
56576
56577
56578 public function start($id, $message, $prefix = 'RUN')
56579 {
56580 $this->started[$id] = array('border' => ++$this->count % \count($this->colors));
56581
56582 return sprintf("%s<bg=blue;fg=white> %s </> <fg=blue>%s</>\n", $this->getBorder($id), $prefix, $message);
56583 }
56584
56585
56586
56587
56588
56589
56590
56591
56592
56593
56594
56595
56596 public function progress($id, $buffer, $error = false, $prefix = 'OUT', $errorPrefix = 'ERR')
56597 {
56598 $message = '';
56599
56600 if ($error) {
56601 if (isset($this->started[$id]['out'])) {
56602 $message .= "\n";
56603 unset($this->started[$id]['out']);
56604 }
56605 if (!isset($this->started[$id]['err'])) {
56606 $message .= sprintf('%s<bg=red;fg=white> %s </> ', $this->getBorder($id), $errorPrefix);
56607 $this->started[$id]['err'] = true;
56608 }
56609
56610 $message .= str_replace("\n", sprintf("\n%s<bg=red;fg=white> %s </> ", $this->getBorder($id), $errorPrefix), $buffer);
56611 } else {
56612 if (isset($this->started[$id]['err'])) {
56613 $message .= "\n";
56614 unset($this->started[$id]['err']);
56615 }
56616 if (!isset($this->started[$id]['out'])) {
56617 $message .= sprintf('%s<bg=green;fg=white> %s </> ', $this->getBorder($id), $prefix);
56618 $this->started[$id]['out'] = true;
56619 }
56620
56621 $message .= str_replace("\n", sprintf("\n%s<bg=green;fg=white> %s </> ", $this->getBorder($id), $prefix), $buffer);
56622 }
56623
56624 return $message;
56625 }
56626
56627
56628
56629
56630
56631
56632
56633
56634
56635
56636
56637 public function stop($id, $message, $successful, $prefix = 'RES')
56638 {
56639 $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : '';
56640
56641 if ($successful) {
56642 return sprintf("%s%s<bg=green;fg=white> %s </> <fg=green>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
56643 }
56644
56645 $message = sprintf("%s%s<bg=red;fg=white> %s </> <fg=red>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
56646
56647 unset($this->started[$id]['out'], $this->started[$id]['err']);
56648
56649 return $message;
56650 }
56651
56652
56653
56654
56655
56656
56657 private function getBorder($id)
56658 {
56659 return sprintf('<bg=%s> </>', $this->colors[$this->started[$id]['border']]);
56660 }
56661
56662
56663
56664
56665 public function getName()
56666 {
56667 return 'debug_formatter';
56668 }
56669 }
56670 <?php
56671
56672
56673
56674
56675
56676
56677
56678
56679
56680
56681 namespace Symfony\Component\Console\Helper;
56682
56683 use Symfony\Component\Console\Descriptor\DescriptorInterface;
56684 use Symfony\Component\Console\Descriptor\JsonDescriptor;
56685 use Symfony\Component\Console\Descriptor\MarkdownDescriptor;
56686 use Symfony\Component\Console\Descriptor\TextDescriptor;
56687 use Symfony\Component\Console\Descriptor\XmlDescriptor;
56688 use Symfony\Component\Console\Exception\InvalidArgumentException;
56689 use Symfony\Component\Console\Output\OutputInterface;
56690
56691
56692
56693
56694
56695
56696 class DescriptorHelper extends Helper
56697 {
56698
56699
56700
56701 private $descriptors = array();
56702
56703 public function __construct()
56704 {
56705 $this
56706 ->register('txt', new TextDescriptor())
56707 ->register('xml', new XmlDescriptor())
56708 ->register('json', new JsonDescriptor())
56709 ->register('md', new MarkdownDescriptor())
56710 ;
56711 }
56712
56713
56714
56715
56716
56717
56718
56719
56720
56721
56722
56723
56724
56725
56726 public function describe(OutputInterface $output, $object, array $options = array())
56727 {
56728 $options = array_merge(array(
56729 'raw_text' => false,
56730 'format' => 'txt',
56731 ), $options);
56732
56733 if (!isset($this->descriptors[$options['format']])) {
56734 throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $options['format']));
56735 }
56736
56737 $descriptor = $this->descriptors[$options['format']];
56738 $descriptor->describe($output, $object, $options);
56739 }
56740
56741
56742
56743
56744
56745
56746
56747
56748
56749 public function register($format, DescriptorInterface $descriptor)
56750 {
56751 $this->descriptors[$format] = $descriptor;
56752
56753 return $this;
56754 }
56755
56756
56757
56758
56759 public function getName()
56760 {
56761 return 'descriptor';
56762 }
56763 }
56764 <?php
56765
56766
56767
56768
56769
56770
56771
56772
56773
56774
56775 namespace Symfony\Component\Console\Helper;
56776
56777 use Symfony\Component\Console\Exception\InvalidArgumentException;
56778 use Symfony\Component\Console\Exception\RuntimeException;
56779 use Symfony\Component\Console\Formatter\OutputFormatterStyle;
56780 use Symfony\Component\Console\Output\ConsoleOutputInterface;
56781 use Symfony\Component\Console\Output\OutputInterface;
56782
56783
56784
56785
56786
56787
56788
56789
56790
56791 class DialogHelper extends InputAwareHelper
56792 {
56793 private $inputStream;
56794 private static $shell;
56795 private static $stty;
56796
56797 public function __construct($triggerDeprecationError = true)
56798 {
56799 if ($triggerDeprecationError) {
56800 @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);
56801 }
56802 }
56803
56804
56805
56806
56807
56808
56809
56810
56811
56812
56813
56814
56815
56816
56817
56818
56819 public function select(OutputInterface $output, $question, $choices, $default = null, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false)
56820 {
56821 if ($output instanceof ConsoleOutputInterface) {
56822 $output = $output->getErrorOutput();
56823 }
56824
56825 $width = max(array_map('strlen', array_keys($choices)));
56826
56827 $messages = (array) $question;
56828 foreach ($choices as $key => $value) {
56829 $messages[] = sprintf("  [<info>%-{$width}s</info>] %s", $key, $value);
56830 }
56831
56832 $output->writeln($messages);
56833
56834 $result = $this->askAndValidate($output, '> ', function ($picked) use ($choices, $errorMessage, $multiselect) {
56835
56836 $selectedChoices = str_replace(' ', '', $picked);
56837
56838 if ($multiselect) {
56839
56840 if (!preg_match('/^[a-zA-Z0-9_-]+(?:,[a-zA-Z0-9_-]+)*$/', $selectedChoices, $matches)) {
56841 throw new InvalidArgumentException(sprintf($errorMessage, $picked));
56842 }
56843 $selectedChoices = explode(',', $selectedChoices);
56844 } else {
56845 $selectedChoices = array($picked);
56846 }
56847
56848 $multiselectChoices = array();
56849
56850 foreach ($selectedChoices as $value) {
56851 if (empty($choices[$value])) {
56852 throw new InvalidArgumentException(sprintf($errorMessage, $value));
56853 }
56854 $multiselectChoices[] = $value;
56855 }
56856
56857 if ($multiselect) {
56858 return $multiselectChoices;
56859 }
56860
56861 return $picked;
56862 }, $attempts, $default);
56863
56864 return $result;
56865 }
56866
56867
56868
56869
56870
56871
56872
56873
56874
56875
56876
56877
56878
56879 public function ask(OutputInterface $output, $question, $default = null, array $autocomplete = null)
56880 {
56881 if ($this->input && !$this->input->isInteractive()) {
56882 return $default;
56883 }
56884
56885 if ($output instanceof ConsoleOutputInterface) {
56886 $output = $output->getErrorOutput();
56887 }
56888
56889 $output->write($question);
56890
56891 $inputStream = $this->inputStream ?: STDIN;
56892
56893 if (null === $autocomplete || !$this->hasSttyAvailable()) {
56894 $ret = fgets($inputStream, 4096);
56895 if (false === $ret) {
56896 throw new RuntimeException('Aborted');
56897 }
56898 $ret = trim($ret);
56899 } else {
56900 $ret = '';
56901
56902 $i = 0;
56903 $ofs = -1;
56904 $matches = $autocomplete;
56905 $numMatches = \count($matches);
56906
56907 $sttyMode = shell_exec('stty -g');
56908
56909
56910 shell_exec('stty -icanon -echo');
56911
56912
56913 $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white'));
56914
56915
56916 while (!feof($inputStream)) {
56917 $c = fread($inputStream, 1);
56918
56919
56920 if ("\177" === $c) {
56921 if (0 === $numMatches && 0 !== $i) {
56922 --$i;
56923
56924 $output->write("\033[1D");
56925 }
56926
56927 if (0 === $i) {
56928 $ofs = -1;
56929 $matches = $autocomplete;
56930 $numMatches = \count($matches);
56931 } else {
56932 $numMatches = 0;
56933 }
56934
56935
56936 $ret = substr($ret, 0, $i);
56937 } elseif ("\033" === $c) {
56938
56939 $c .= fread($inputStream, 2);
56940
56941
56942 if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) {
56943 if ('A' === $c[2] && -1 === $ofs) {
56944 $ofs = 0;
56945 }
56946
56947 if (0 === $numMatches) {
56948 continue;
56949 }
56950
56951 $ofs += ('A' === $c[2]) ? -1 : 1;
56952 $ofs = ($numMatches + $ofs) % $numMatches;
56953 }
56954 } elseif (\ord($c) < 32) {
56955 if ("\t" === $c || "\n" === $c) {
56956 if ($numMatches > 0 && -1 !== $ofs) {
56957 $ret = $matches[$ofs];
56958
56959 $output->write(substr($ret, $i));
56960 $i = \strlen($ret);
56961 }
56962
56963 if ("\n" === $c) {
56964 $output->write($c);
56965 break;
56966 }
56967
56968 $numMatches = 0;
56969 }
56970
56971 continue;
56972 } else {
56973 $output->write($c);
56974 $ret .= $c;
56975 ++$i;
56976
56977 $numMatches = 0;
56978 $ofs = 0;
56979
56980 foreach ($autocomplete as $value) {
56981
56982 if (0 === strpos($value, $ret) && $i !== \strlen($value)) {
56983 $matches[$numMatches++] = $value;
56984 }
56985 }
56986 }
56987
56988
56989 $output->write("\033[K");
56990
56991 if ($numMatches > 0 && -1 !== $ofs) {
56992
56993 $output->write("\0337");
56994
56995 $output->write('<hl>'.substr($matches[$ofs], $i).'</hl>');
56996
56997 $output->write("\0338");
56998 }
56999 }
57000
57001
57002 shell_exec(sprintf('stty %s', $sttyMode));
57003 }
57004
57005 return \strlen($ret) > 0 ? $ret : $default;
57006 }
57007
57008
57009
57010
57011
57012
57013
57014
57015
57016
57017
57018
57019 public function askConfirmation(OutputInterface $output, $question, $default = true)
57020 {
57021 $answer = 'z';
57022 while ($answer && !\in_array(strtolower($answer[0]), array('y', 'n'))) {
57023 $answer = $this->ask($output, $question);
57024 }
57025
57026 if (false === $default) {
57027 return $answer && 'y' == strtolower($answer[0]);
57028 }
57029
57030 return !$answer || 'y' == strtolower($answer[0]);
57031 }
57032
57033
57034
57035
57036
57037
57038
57039
57040
57041
57042
57043
57044 public function askHiddenResponse(OutputInterface $output, $question, $fallback = true)
57045 {
57046 if ($output instanceof ConsoleOutputInterface) {
57047 $output = $output->getErrorOutput();
57048 }
57049
57050 if ('\\' === \DIRECTORY_SEPARATOR) {
57051 $exe = __DIR__.'/../Resources/bin/hiddeninput.exe';
57052
57053
57054 if ('phar:' === substr(__FILE__, 0, 5)) {
57055 $tmpExe = sys_get_temp_dir().'/hiddeninput.exe';
57056 copy($exe, $tmpExe);
57057 $exe = $tmpExe;
57058 }
57059
57060 $output->write($question);
57061 $value = rtrim(shell_exec($exe));
57062 $output->writeln('');
57063
57064 if (isset($tmpExe)) {
57065 unlink($tmpExe);
57066 }
57067
57068 return $value;
57069 }
57070
57071 if ($this->hasSttyAvailable()) {
57072 $output->write($question);
57073
57074 $sttyMode = shell_exec('stty -g');
57075
57076 shell_exec('stty -echo');
57077 $value = fgets($this->inputStream ?: STDIN, 4096);
57078 shell_exec(sprintf('stty %s', $sttyMode));
57079
57080 if (false === $value) {
57081 throw new RuntimeException('Aborted');
57082 }
57083
57084 $value = trim($value);
57085 $output->writeln('');
57086
57087 return $value;
57088 }
57089
57090 if (false !== $shell = $this->getShell()) {
57091 $output->write($question);
57092 $readCmd = 'csh' === $shell ? 'set mypassword = $<' : 'read -r mypassword';
57093 $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd);
57094 $value = rtrim(shell_exec($command));
57095 $output->writeln('');
57096
57097 return $value;
57098 }
57099
57100 if ($fallback) {
57101 return $this->ask($output, $question);
57102 }
57103
57104 throw new RuntimeException('Unable to hide the response');
57105 }
57106
57107
57108
57109
57110
57111
57112
57113
57114
57115
57116
57117
57118
57119
57120
57121
57122
57123
57124
57125 public function askAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $default = null, array $autocomplete = null)
57126 {
57127 $that = $this;
57128
57129 $interviewer = function () use ($output, $question, $default, $autocomplete, $that) {
57130 return $that->ask($output, $question, $default, $autocomplete);
57131 };
57132
57133 return $this->validateAttempts($interviewer, $output, $validator, $attempts);
57134 }
57135
57136
57137
57138
57139
57140
57141
57142
57143
57144
57145
57146
57147
57148
57149
57150
57151
57152
57153
57154 public function askHiddenResponseAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $fallback = true)
57155 {
57156 $that = $this;
57157
57158 $interviewer = function () use ($output, $question, $fallback, $that) {
57159 return $that->askHiddenResponse($output, $question, $fallback);
57160 };
57161
57162 return $this->validateAttempts($interviewer, $output, $validator, $attempts);
57163 }
57164
57165
57166
57167
57168
57169
57170
57171
57172 public function setInputStream($stream)
57173 {
57174 $this->inputStream = $stream;
57175 }
57176
57177
57178
57179
57180
57181
57182 public function getInputStream()
57183 {
57184 return $this->inputStream;
57185 }
57186
57187
57188
57189
57190 public function getName()
57191 {
57192 return 'dialog';
57193 }
57194
57195
57196
57197
57198
57199
57200 private function getShell()
57201 {
57202 if (null !== self::$shell) {
57203 return self::$shell;
57204 }
57205
57206 self::$shell = false;
57207
57208 if (file_exists('/usr/bin/env')) {
57209
57210 $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null";
57211 foreach (array('bash', 'zsh', 'ksh', 'csh') as $sh) {
57212 if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) {
57213 self::$shell = $sh;
57214 break;
57215 }
57216 }
57217 }
57218
57219 return self::$shell;
57220 }
57221
57222 private function hasSttyAvailable()
57223 {
57224 if (null !== self::$stty) {
57225 return self::$stty;
57226 }
57227
57228 exec('stty 2>&1', $output, $exitcode);
57229
57230 return self::$stty = 0 === $exitcode;
57231 }
57232
57233
57234
57235
57236
57237
57238
57239
57240
57241
57242
57243
57244
57245 private function validateAttempts($interviewer, OutputInterface $output, $validator, $attempts)
57246 {
57247 if ($output instanceof ConsoleOutputInterface) {
57248 $output = $output->getErrorOutput();
57249 }
57250
57251 $e = null;
57252 while (false === $attempts || $attempts--) {
57253 if (null !== $e) {
57254 $output->writeln($this->getHelperSet()->get('formatter')->formatBlock($e->getMessage(), 'error'));
57255 }
57256
57257 try {
57258 return \call_user_func($validator, $interviewer());
57259 } catch (\Exception $e) {
57260 }
57261 }
57262
57263 throw $e;
57264 }
57265 }
57266 <?php
57267
57268
57269
57270
57271
57272
57273
57274
57275
57276
57277 namespace Symfony\Component\Console\Helper;
57278
57279 use Symfony\Component\Console\Formatter\OutputFormatter;
57280
57281
57282
57283
57284
57285
57286 class FormatterHelper extends Helper
57287 {
57288
57289
57290
57291
57292
57293
57294
57295
57296
57297 public function formatSection($section, $message, $style = 'info')
57298 {
57299 return sprintf('<%s>[%s]</%s> %s', $style, $section, $style, $message);
57300 }
57301
57302
57303
57304
57305
57306
57307
57308
57309
57310
57311 public function formatBlock($messages, $style, $large = false)
57312 {
57313 if (!\is_array($messages)) {
57314 $messages = array($messages);
57315 }
57316
57317 $len = 0;
57318 $lines = array();
57319 foreach ($messages as $message) {
57320 $message = OutputFormatter::escape($message);
57321 $lines[] = sprintf($large ? '  %s  ' : ' %s ', $message);
57322 $len = max($this->strlen($message) + ($large ? 4 : 2), $len);
57323 }
57324
57325 $messages = $large ? array(str_repeat(' ', $len)) : array();
57326 for ($i = 0; isset($lines[$i]); ++$i) {
57327 $messages[] = $lines[$i].str_repeat(' ', $len - $this->strlen($lines[$i]));
57328 }
57329 if ($large) {
57330 $messages[] = str_repeat(' ', $len);
57331 }
57332
57333 for ($i = 0; isset($messages[$i]); ++$i) {
57334 $messages[$i] = sprintf('<%s>%s</%s>', $style, $messages[$i], $style);
57335 }
57336
57337 return implode("\n", $messages);
57338 }
57339
57340
57341
57342
57343 public function getName()
57344 {
57345 return 'formatter';
57346 }
57347 }
57348 <?php
57349
57350
57351
57352
57353
57354
57355
57356
57357
57358
57359 namespace Symfony\Component\Console\Helper;
57360
57361 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
57362
57363
57364
57365
57366
57367
57368 abstract class Helper implements HelperInterface
57369 {
57370 protected $helperSet = null;
57371
57372
57373
57374
57375 public function setHelperSet(HelperSet $helperSet = null)
57376 {
57377 $this->helperSet = $helperSet;
57378 }
57379
57380
57381
57382
57383 public function getHelperSet()
57384 {
57385 return $this->helperSet;
57386 }
57387
57388
57389
57390
57391
57392
57393
57394
57395 public static function strlen($string)
57396 {
57397 if (false === $encoding = mb_detect_encoding($string, null, true)) {
57398 return \strlen($string);
57399 }
57400
57401 return mb_strwidth($string, $encoding);
57402 }
57403
57404 public static function formatTime($secs)
57405 {
57406 static $timeFormats = array(
57407 array(0, '< 1 sec'),
57408 array(1, '1 sec'),
57409 array(2, 'secs', 1),
57410 array(60, '1 min'),
57411 array(120, 'mins', 60),
57412 array(3600, '1 hr'),
57413 array(7200, 'hrs', 3600),
57414 array(86400, '1 day'),
57415 array(172800, 'days', 86400),
57416 );
57417
57418 foreach ($timeFormats as $index => $format) {
57419 if ($secs >= $format[0]) {
57420 if ((isset($timeFormats[$index + 1]) && $secs < $timeFormats[$index + 1][0])
57421 || $index == \count($timeFormats) - 1
57422 ) {
57423 if (2 == \count($format)) {
57424 return $format[1];
57425 }
57426
57427 return floor($secs / $format[2]).' '.$format[1];
57428 }
57429 }
57430 }
57431 }
57432
57433 public static function formatMemory($memory)
57434 {
57435 if ($memory >= 1024 * 1024 * 1024) {
57436 return sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024);
57437 }
57438
57439 if ($memory >= 1024 * 1024) {
57440 return sprintf('%.1f MiB', $memory / 1024 / 1024);
57441 }
57442
57443 if ($memory >= 1024) {
57444 return sprintf('%d KiB', $memory / 1024);
57445 }
57446
57447 return sprintf('%d B', $memory);
57448 }
57449
57450 public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, $string)
57451 {
57452 return self::strlen(self::removeDecoration($formatter, $string));
57453 }
57454
57455 public static function removeDecoration(OutputFormatterInterface $formatter, $string)
57456 {
57457 $isDecorated = $formatter->isDecorated();
57458 $formatter->setDecorated(false);
57459
57460 $string = $formatter->format($string);
57461
57462 $string = preg_replace("/\033\[[^m]*m/", '', $string);
57463 $formatter->setDecorated($isDecorated);
57464
57465 return $string;
57466 }
57467 }
57468 <?php
57469
57470
57471
57472
57473
57474
57475
57476
57477
57478
57479 namespace Symfony\Component\Console\Helper;
57480
57481
57482
57483
57484
57485
57486 interface HelperInterface
57487 {
57488
57489
57490
57491 public function setHelperSet(HelperSet $helperSet = null);
57492
57493
57494
57495
57496
57497
57498 public function getHelperSet();
57499
57500
57501
57502
57503
57504
57505 public function getName();
57506 }
57507 <?php
57508
57509
57510
57511
57512
57513
57514
57515
57516
57517
57518 namespace Symfony\Component\Console\Helper;
57519
57520 use Symfony\Component\Console\Command\Command;
57521 use Symfony\Component\Console\Exception\InvalidArgumentException;
57522
57523
57524
57525
57526
57527
57528 class HelperSet implements \IteratorAggregate
57529 {
57530
57531
57532
57533 private $helpers = array();
57534 private $command;
57535
57536
57537
57538
57539 public function __construct(array $helpers = array())
57540 {
57541 foreach ($helpers as $alias => $helper) {
57542 $this->set($helper, \is_int($alias) ? null : $alias);
57543 }
57544 }
57545
57546
57547
57548
57549
57550
57551
57552 public function set(HelperInterface $helper, $alias = null)
57553 {
57554 $this->helpers[$helper->getName()] = $helper;
57555 if (null !== $alias) {
57556 $this->helpers[$alias] = $helper;
57557 }
57558
57559 $helper->setHelperSet($this);
57560 }
57561
57562
57563
57564
57565
57566
57567
57568
57569 public function has($name)
57570 {
57571 return isset($this->helpers[$name]);
57572 }
57573
57574
57575
57576
57577
57578
57579
57580
57581
57582
57583 public function get($name)
57584 {
57585 if (!$this->has($name)) {
57586 throw new InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name));
57587 }
57588
57589 if ('dialog' === $name && $this->helpers[$name] instanceof DialogHelper) {
57590 @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);
57591 } elseif ('progress' === $name && $this->helpers[$name] instanceof ProgressHelper) {
57592 @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);
57593 } elseif ('table' === $name && $this->helpers[$name] instanceof TableHelper) {
57594 @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);
57595 }
57596
57597 return $this->helpers[$name];
57598 }
57599
57600 public function setCommand(Command $command = null)
57601 {
57602 $this->command = $command;
57603 }
57604
57605
57606
57607
57608
57609
57610 public function getCommand()
57611 {
57612 return $this->command;
57613 }
57614
57615
57616
57617
57618 public function getIterator()
57619 {
57620 return new \ArrayIterator($this->helpers);
57621 }
57622 }
57623 <?php
57624
57625
57626
57627
57628
57629
57630
57631
57632
57633
57634 namespace Symfony\Component\Console\Helper;
57635
57636 use Symfony\Component\Console\Input\InputAwareInterface;
57637 use Symfony\Component\Console\Input\InputInterface;
57638
57639
57640
57641
57642
57643
57644 abstract class InputAwareHelper extends Helper implements InputAwareInterface
57645 {
57646 protected $input;
57647
57648
57649
57650
57651 public function setInput(InputInterface $input)
57652 {
57653 $this->input = $input;
57654 }
57655 }
57656 <?php
57657
57658
57659
57660
57661
57662
57663
57664
57665
57666
57667 namespace Symfony\Component\Console\Helper;
57668
57669 use Symfony\Component\Console\Output\ConsoleOutputInterface;
57670 use Symfony\Component\Console\Output\OutputInterface;
57671 use Symfony\Component\Process\Exception\ProcessFailedException;
57672 use Symfony\Component\Process\Process;
57673 use Symfony\Component\Process\ProcessBuilder;
57674
57675
57676
57677
57678
57679
57680 class ProcessHelper extends Helper
57681 {
57682
57683
57684
57685
57686
57687
57688
57689
57690
57691
57692
57693
57694 public function run(OutputInterface $output, $cmd, $error = null, $callback = null, $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE)
57695 {
57696 if ($output instanceof ConsoleOutputInterface) {
57697 $output = $output->getErrorOutput();
57698 }
57699
57700 $formatter = $this->getHelperSet()->get('debug_formatter');
57701
57702 if (\is_array($cmd)) {
57703 $process = ProcessBuilder::create($cmd)->getProcess();
57704 } elseif ($cmd instanceof Process) {
57705 $process = $cmd;
57706 } else {
57707 $process = new Process($cmd);
57708 }
57709
57710 if ($verbosity <= $output->getVerbosity()) {
57711 $output->write($formatter->start(spl_object_hash($process), $this->escapeString($process->getCommandLine())));
57712 }
57713
57714 if ($output->isDebug()) {
57715 $callback = $this->wrapCallback($output, $process, $callback);
57716 }
57717
57718 $process->run($callback);
57719
57720 if ($verbosity <= $output->getVerbosity()) {
57721 $message = $process->isSuccessful() ? 'Command ran successfully' : sprintf('%s Command did not run successfully', $process->getExitCode());
57722 $output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful()));
57723 }
57724
57725 if (!$process->isSuccessful() && null !== $error) {
57726 $output->writeln(sprintf('<error>%s</error>', $this->escapeString($error)));
57727 }
57728
57729 return $process;
57730 }
57731
57732
57733
57734
57735
57736
57737
57738
57739
57740
57741
57742
57743
57744
57745
57746
57747
57748
57749
57750 public function mustRun(OutputInterface $output, $cmd, $error = null, $callback = null)
57751 {
57752 $process = $this->run($output, $cmd, $error, $callback);
57753
57754 if (!$process->isSuccessful()) {
57755 throw new ProcessFailedException($process);
57756 }
57757
57758 return $process;
57759 }
57760
57761
57762
57763
57764
57765
57766
57767
57768
57769
57770 public function wrapCallback(OutputInterface $output, Process $process, $callback = null)
57771 {
57772 if ($output instanceof ConsoleOutputInterface) {
57773 $output = $output->getErrorOutput();
57774 }
57775
57776 $formatter = $this->getHelperSet()->get('debug_formatter');
57777
57778 $that = $this;
57779
57780 return function ($type, $buffer) use ($output, $process, $callback, $formatter, $that) {
57781 $output->write($formatter->progress(spl_object_hash($process), $that->escapeString($buffer), Process::ERR === $type));
57782
57783 if (null !== $callback) {
57784 \call_user_func($callback, $type, $buffer);
57785 }
57786 };
57787 }
57788
57789
57790
57791
57792
57793
57794 public function escapeString($str)
57795 {
57796 return str_replace('<', '\\<', $str);
57797 }
57798
57799
57800
57801
57802 public function getName()
57803 {
57804 return 'process';
57805 }
57806 }
57807 <?php
57808
57809
57810
57811
57812
57813
57814
57815
57816
57817
57818 namespace Symfony\Component\Console\Helper;
57819
57820 use Symfony\Component\Console\Exception\LogicException;
57821 use Symfony\Component\Console\Output\ConsoleOutputInterface;
57822 use Symfony\Component\Console\Output\OutputInterface;
57823
57824
57825
57826
57827
57828
57829
57830 class ProgressBar
57831 {
57832 private $barWidth = 28;
57833 private $barChar;
57834 private $emptyBarChar = '-';
57835 private $progressChar = '>';
57836 private $format;
57837 private $internalFormat;
57838 private $redrawFreq = 1;
57839 private $output;
57840 private $step = 0;
57841 private $max;
57842 private $startTime;
57843 private $stepWidth;
57844 private $percent = 0.0;
57845 private $formatLineCount;
57846 private $messages = array();
57847 private $overwrite = true;
57848 private $firstRun = true;
57849
57850 private static $formatters;
57851 private static $formats;
57852
57853
57854
57855
57856
57857 public function __construct(OutputInterface $output, $max = 0)
57858 {
57859 if ($output instanceof ConsoleOutputInterface) {
57860 $output = $output->getErrorOutput();
57861 }
57862
57863 $this->output = $output;
57864 $this->setMaxSteps($max);
57865
57866 if (!$this->output->isDecorated()) {
57867
57868 $this->overwrite = false;
57869
57870
57871 $this->setRedrawFrequency($max / 10);
57872 }
57873
57874 $this->startTime = time();
57875 }
57876
57877
57878
57879
57880
57881
57882
57883
57884
57885 public static function setPlaceholderFormatterDefinition($name, $callable)
57886 {
57887 if (!self::$formatters) {
57888 self::$formatters = self::initPlaceholderFormatters();
57889 }
57890
57891 self::$formatters[$name] = $callable;
57892 }
57893
57894
57895
57896
57897
57898
57899
57900
57901 public static function getPlaceholderFormatterDefinition($name)
57902 {
57903 if (!self::$formatters) {
57904 self::$formatters = self::initPlaceholderFormatters();
57905 }
57906
57907 return isset(self::$formatters[$name]) ? self::$formatters[$name] : null;
57908 }
57909
57910
57911
57912
57913
57914
57915
57916
57917
57918 public static function setFormatDefinition($name, $format)
57919 {
57920 if (!self::$formats) {
57921 self::$formats = self::initFormats();
57922 }
57923
57924 self::$formats[$name] = $format;
57925 }
57926
57927
57928
57929
57930
57931
57932
57933
57934 public static function getFormatDefinition($name)
57935 {
57936 if (!self::$formats) {
57937 self::$formats = self::initFormats();
57938 }
57939
57940 return isset(self::$formats[$name]) ? self::$formats[$name] : null;
57941 }
57942
57943
57944
57945
57946
57947
57948
57949
57950
57951
57952
57953 public function setMessage($message, $name = 'message')
57954 {
57955 $this->messages[$name] = $message;
57956 }
57957
57958 public function getMessage($name = 'message')
57959 {
57960 return $this->messages[$name];
57961 }
57962
57963
57964
57965
57966
57967
57968 public function getStartTime()
57969 {
57970 return $this->startTime;
57971 }
57972
57973
57974
57975
57976
57977
57978 public function getMaxSteps()
57979 {
57980 return $this->max;
57981 }
57982
57983
57984
57985
57986
57987
57988
57989
57990 public function getStep()
57991 {
57992 @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);
57993
57994 return $this->getProgress();
57995 }
57996
57997
57998
57999
58000
58001
58002 public function getProgress()
58003 {
58004 return $this->step;
58005 }
58006
58007
58008
58009
58010
58011
58012
58013
58014 public function getStepWidth()
58015 {
58016 return $this->stepWidth;
58017 }
58018
58019
58020
58021
58022
58023
58024 public function getProgressPercent()
58025 {
58026 return $this->percent;
58027 }
58028
58029
58030
58031
58032
58033
58034 public function setBarWidth($size)
58035 {
58036 $this->barWidth = (int) $size;
58037 }
58038
58039
58040
58041
58042
58043
58044 public function getBarWidth()
58045 {
58046 return $this->barWidth;
58047 }
58048
58049
58050
58051
58052
58053
58054 public function setBarCharacter($char)
58055 {
58056 $this->barChar = $char;
58057 }
58058
58059
58060
58061
58062
58063
58064 public function getBarCharacter()
58065 {
58066 if (null === $this->barChar) {
58067 return $this->max ? '=' : $this->emptyBarChar;
58068 }
58069
58070 return $this->barChar;
58071 }
58072
58073
58074
58075
58076
58077
58078 public function setEmptyBarCharacter($char)
58079 {
58080 $this->emptyBarChar = $char;
58081 }
58082
58083
58084
58085
58086
58087
58088 public function getEmptyBarCharacter()
58089 {
58090 return $this->emptyBarChar;
58091 }
58092
58093
58094
58095
58096
58097
58098 public function setProgressCharacter($char)
58099 {
58100 $this->progressChar = $char;
58101 }
58102
58103
58104
58105
58106
58107
58108 public function getProgressCharacter()
58109 {
58110 return $this->progressChar;
58111 }
58112
58113
58114
58115
58116
58117
58118 public function setFormat($format)
58119 {
58120 $this->format = null;
58121 $this->internalFormat = $format;
58122 }
58123
58124
58125
58126
58127
58128
58129 public function setRedrawFrequency($freq)
58130 {
58131 $this->redrawFreq = max((int) $freq, 1);
58132 }
58133
58134
58135
58136
58137
58138
58139 public function start($max = null)
58140 {
58141 $this->startTime = time();
58142 $this->step = 0;
58143 $this->percent = 0.0;
58144
58145 if (null !== $max) {
58146 $this->setMaxSteps($max);
58147 }
58148
58149 $this->display();
58150 }
58151
58152
58153
58154
58155
58156
58157
58158
58159 public function advance($step = 1)
58160 {
58161 $this->setProgress($this->step + $step);
58162 }
58163
58164
58165
58166
58167
58168
58169
58170
58171
58172
58173 public function setCurrent($step)
58174 {
58175 @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);
58176
58177 $this->setProgress($step);
58178 }
58179
58180
58181
58182
58183
58184
58185 public function setOverwrite($overwrite)
58186 {
58187 $this->overwrite = (bool) $overwrite;
58188 }
58189
58190
58191
58192
58193
58194
58195
58196
58197 public function setProgress($step)
58198 {
58199 $step = (int) $step;
58200 if ($step < $this->step) {
58201 throw new LogicException('You can\'t regress the progress bar.');
58202 }
58203
58204 if ($this->max && $step > $this->max) {
58205 $this->max = $step;
58206 }
58207
58208 $prevPeriod = (int) ($this->step / $this->redrawFreq);
58209 $currPeriod = (int) ($step / $this->redrawFreq);
58210 $this->step = $step;
58211 $this->percent = $this->max ? (float) $this->step / $this->max : 0;
58212 if ($prevPeriod !== $currPeriod || $this->max === $step) {
58213 $this->display();
58214 }
58215 }
58216
58217
58218
58219
58220 public function finish()
58221 {
58222 if (!$this->max) {
58223 $this->max = $this->step;
58224 }
58225
58226 if ($this->step === $this->max && !$this->overwrite) {
58227
58228 return;
58229 }
58230
58231 $this->setProgress($this->max);
58232 }
58233
58234
58235
58236
58237 public function display()
58238 {
58239 if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
58240 return;
58241 }
58242
58243 if (null === $this->format) {
58244 $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
58245 }
58246
58247
58248 $self = $this;
58249 $output = $this->output;
58250 $messages = $this->messages;
58251 $this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) use ($self, $output, $messages) {
58252 if ($formatter = $self::getPlaceholderFormatterDefinition($matches[1])) {
58253 $text = \call_user_func($formatter, $self, $output);
58254 } elseif (isset($messages[$matches[1]])) {
58255 $text = $messages[$matches[1]];
58256 } else {
58257 return $matches[0];
58258 }
58259
58260 if (isset($matches[2])) {
58261 $text = sprintf('%'.$matches[2], $text);
58262 }
58263
58264 return $text;
58265 }, $this->format));
58266 }
58267
58268
58269
58270
58271
58272
58273
58274
58275 public function clear()
58276 {
58277 if (!$this->overwrite) {
58278 return;
58279 }
58280
58281 if (null === $this->format) {
58282 $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
58283 }
58284
58285 $this->overwrite('');
58286 }
58287
58288
58289
58290
58291
58292
58293 private function setRealFormat($format)
58294 {
58295
58296 if (!$this->max && null !== self::getFormatDefinition($format.'_nomax')) {
58297 $this->format = self::getFormatDefinition($format.'_nomax');
58298 } elseif (null !== self::getFormatDefinition($format)) {
58299 $this->format = self::getFormatDefinition($format);
58300 } else {
58301 $this->format = $format;
58302 }
58303
58304 $this->formatLineCount = substr_count($this->format, "\n");
58305 }
58306
58307
58308
58309
58310
58311
58312 private function setMaxSteps($max)
58313 {
58314 $this->max = max(0, (int) $max);
58315 $this->stepWidth = $this->max ? Helper::strlen($this->max) : 4;
58316 }
58317
58318
58319
58320
58321
58322
58323 private function overwrite($message)
58324 {
58325 if ($this->overwrite) {
58326 if (!$this->firstRun) {
58327
58328 $this->output->write("\x0D");
58329
58330
58331 $this->output->write("\x1B[2K");
58332
58333
58334 if ($this->formatLineCount > 0) {
58335 $this->output->write(str_repeat("\x1B[1A\x1B[2K", $this->formatLineCount));
58336 }
58337 }
58338 } elseif ($this->step > 0) {
58339 $this->output->writeln('');
58340 }
58341
58342 $this->firstRun = false;
58343
58344 $this->output->write($message);
58345 }
58346
58347 private function determineBestFormat()
58348 {
58349 switch ($this->output->getVerbosity()) {
58350
58351 case OutputInterface::VERBOSITY_VERBOSE:
58352 return $this->max ? 'verbose' : 'verbose_nomax';
58353 case OutputInterface::VERBOSITY_VERY_VERBOSE:
58354 return $this->max ? 'very_verbose' : 'very_verbose_nomax';
58355 case OutputInterface::VERBOSITY_DEBUG:
58356 return $this->max ? 'debug' : 'debug_nomax';
58357 default:
58358 return $this->max ? 'normal' : 'normal_nomax';
58359 }
58360 }
58361
58362 private static function initPlaceholderFormatters()
58363 {
58364 return array(
58365 'bar' => function (ProgressBar $bar, OutputInterface $output) {
58366 $completeBars = floor($bar->getMaxSteps() > 0 ? $bar->getProgressPercent() * $bar->getBarWidth() : $bar->getProgress() % $bar->getBarWidth());
58367 $display = str_repeat($bar->getBarCharacter(), $completeBars);
58368 if ($completeBars < $bar->getBarWidth()) {
58369 $emptyBars = $bar->getBarWidth() - $completeBars - Helper::strlenWithoutDecoration($output->getFormatter(), $bar->getProgressCharacter());
58370 $display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars);
58371 }
58372
58373 return $display;
58374 },
58375 'elapsed' => function (ProgressBar $bar) {
58376 return Helper::formatTime(time() - $bar->getStartTime());
58377 },
58378 'remaining' => function (ProgressBar $bar) {
58379 if (!$bar->getMaxSteps()) {
58380 throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.');
58381 }
58382
58383 if (!$bar->getProgress()) {
58384 $remaining = 0;
58385 } else {
58386 $remaining = round((time() - $bar->getStartTime()) / $bar->getProgress() * ($bar->getMaxSteps() - $bar->getProgress()));
58387 }
58388
58389 return Helper::formatTime($remaining);
58390 },
58391 'estimated' => function (ProgressBar $bar) {
58392 if (!$bar->getMaxSteps()) {
58393 throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.');
58394 }
58395
58396 if (!$bar->getProgress()) {
58397 $estimated = 0;
58398 } else {
58399 $estimated = round((time() - $bar->getStartTime()) / $bar->getProgress() * $bar->getMaxSteps());
58400 }
58401
58402 return Helper::formatTime($estimated);
58403 },
58404 'memory' => function (ProgressBar $bar) {
58405 return Helper::formatMemory(memory_get_usage(true));
58406 },
58407 'current' => function (ProgressBar $bar) {
58408 return str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', STR_PAD_LEFT);
58409 },
58410 'max' => function (ProgressBar $bar) {
58411 return $bar->getMaxSteps();
58412 },
58413 'percent' => function (ProgressBar $bar) {
58414 return floor($bar->getProgressPercent() * 100);
58415 },
58416 );
58417 }
58418
58419 private static function initFormats()
58420 {
58421 return array(
58422 'normal' => ' %current%/%max% [%bar%] %percent:3s%%',
58423 'normal_nomax' => ' %current% [%bar%]',
58424
58425 'verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%',
58426 'verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',
58427
58428 'very_verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%',
58429 'very_verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',
58430
58431 'debug' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%',
58432 'debug_nomax' => ' %current% [%bar%] %elapsed:6s% %memory:6s%',
58433 );
58434 }
58435 }
58436 <?php
58437
58438
58439
58440
58441
58442
58443
58444
58445
58446
58447 namespace Symfony\Component\Console\Helper;
58448
58449 use Symfony\Component\Console\Exception\LogicException;
58450 use Symfony\Component\Console\Output\ConsoleOutputInterface;
58451 use Symfony\Component\Console\Output\NullOutput;
58452 use Symfony\Component\Console\Output\OutputInterface;
58453
58454
58455
58456
58457
58458
58459
58460
58461
58462
58463 class ProgressHelper extends Helper
58464 {
58465 const FORMAT_QUIET = ' %percent%%';
58466 const FORMAT_NORMAL = ' %current%/%max% [%bar%] %percent%%';
58467 const FORMAT_VERBOSE = ' %current%/%max% [%bar%] %percent%% Elapsed: %elapsed%';
58468 const FORMAT_QUIET_NOMAX = ' %current%';
58469 const FORMAT_NORMAL_NOMAX = ' %current% [%bar%]';
58470 const FORMAT_VERBOSE_NOMAX = ' %current% [%bar%] Elapsed: %elapsed%';
58471
58472
58473 private $barWidth = 28;
58474 private $barChar = '=';
58475 private $emptyBarChar = '-';
58476 private $progressChar = '>';
58477 private $format = null;
58478 private $redrawFreq = 1;
58479
58480 private $lastMessagesLength;
58481 private $barCharOriginal;
58482
58483
58484
58485
58486 private $output;
58487
58488
58489
58490
58491
58492
58493 private $current;
58494
58495
58496
58497
58498
58499
58500 private $max;
58501
58502
58503
58504
58505
58506
58507 private $startTime;
58508
58509
58510
58511
58512
58513
58514 private $defaultFormatVars = array(
58515 'current',
58516 'max',
58517 'bar',
58518 'percent',
58519 'elapsed',
58520 );
58521
58522
58523
58524
58525
58526
58527 private $formatVars;
58528
58529
58530
58531
58532
58533
58534 private $widths = array(
58535 'current' => 4,
58536 'max' => 4,
58537 'percent' => 3,
58538 'elapsed' => 6,
58539 );
58540
58541
58542
58543
58544
58545
58546 private $timeFormats = array(
58547 array(0, '???'),
58548 array(2, '1 sec'),
58549 array(59, 'secs', 1),
58550 array(60, '1 min'),
58551 array(3600, 'mins', 60),
58552 array(5400, '1 hr'),
58553 array(86400, 'hrs', 3600),
58554 array(129600, '1 day'),
58555 array(604800, 'days', 86400),
58556 );
58557
58558 public function __construct($triggerDeprecationError = true)
58559 {
58560 if ($triggerDeprecationError) {
58561 @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);
58562 }
58563 }
58564
58565
58566
58567
58568
58569
58570 public function setBarWidth($size)
58571 {
58572 $this->barWidth = (int) $size;
58573 }
58574
58575
58576
58577
58578
58579
58580 public function setBarCharacter($char)
58581 {
58582 $this->barChar = $char;
58583 }
58584
58585
58586
58587
58588
58589
58590 public function setEmptyBarCharacter($char)
58591 {
58592 $this->emptyBarChar = $char;
58593 }
58594
58595
58596
58597
58598
58599
58600 public function setProgressCharacter($char)
58601 {
58602 $this->progressChar = $char;
58603 }
58604
58605
58606
58607
58608
58609
58610 public function setFormat($format)
58611 {
58612 $this->format = $format;
58613 }
58614
58615
58616
58617
58618
58619
58620 public function setRedrawFrequency($freq)
58621 {
58622 $this->redrawFreq = (int) $freq;
58623 }
58624
58625
58626
58627
58628
58629
58630
58631 public function start(OutputInterface $output, $max = null)
58632 {
58633 if ($output instanceof ConsoleOutputInterface) {
58634 $output = $output->getErrorOutput();
58635 }
58636
58637 $this->startTime = time();
58638 $this->current = 0;
58639 $this->max = (int) $max;
58640
58641
58642 $this->output = $output->isDecorated() ? $output : new NullOutput();
58643 $this->lastMessagesLength = 0;
58644 $this->barCharOriginal = '';
58645
58646 if (null === $this->format) {
58647 switch ($output->getVerbosity()) {
58648 case OutputInterface::VERBOSITY_QUIET:
58649 $this->format = self::FORMAT_QUIET_NOMAX;
58650 if ($this->max > 0) {
58651 $this->format = self::FORMAT_QUIET;
58652 }
58653 break;
58654 case OutputInterface::VERBOSITY_VERBOSE:
58655 case OutputInterface::VERBOSITY_VERY_VERBOSE:
58656 case OutputInterface::VERBOSITY_DEBUG:
58657 $this->format = self::FORMAT_VERBOSE_NOMAX;
58658 if ($this->max > 0) {
58659 $this->format = self::FORMAT_VERBOSE;
58660 }
58661 break;
58662 default:
58663 $this->format = self::FORMAT_NORMAL_NOMAX;
58664 if ($this->max > 0) {
58665 $this->format = self::FORMAT_NORMAL;
58666 }
58667 break;
58668 }
58669 }
58670
58671 $this->initialize();
58672 }
58673
58674
58675
58676
58677
58678
58679
58680
58681
58682 public function advance($step = 1, $redraw = false)
58683 {
58684 $this->setCurrent($this->current + $step, $redraw);
58685 }
58686
58687
58688
58689
58690
58691
58692
58693
58694
58695 public function setCurrent($current, $redraw = false)
58696 {
58697 if (null === $this->startTime) {
58698 throw new LogicException('You must start the progress bar before calling setCurrent().');
58699 }
58700
58701 $current = (int) $current;
58702
58703 if ($current < $this->current) {
58704 throw new LogicException('You can\'t regress the progress bar');
58705 }
58706
58707 if (0 === $this->current) {
58708 $redraw = true;
58709 }
58710
58711 $prevPeriod = (int) ($this->current / $this->redrawFreq);
58712
58713 $this->current = $current;
58714
58715 $currPeriod = (int) ($this->current / $this->redrawFreq);
58716 if ($redraw || $prevPeriod !== $currPeriod || $this->max === $this->current) {
58717 $this->display();
58718 }
58719 }
58720
58721
58722
58723
58724
58725
58726
58727
58728 public function display($finish = false)
58729 {
58730 if (null === $this->startTime) {
58731 throw new LogicException('You must start the progress bar before calling display().');
58732 }
58733
58734 $message = $this->format;
58735 foreach ($this->generate($finish) as $name => $value) {
58736 $message = str_replace("%{$name}%", $value, $message);
58737 }
58738 $this->overwrite($this->output, $message);
58739 }
58740
58741
58742
58743
58744
58745
58746
58747
58748 public function clear()
58749 {
58750 $this->overwrite($this->output, '');
58751 }
58752
58753
58754
58755
58756 public function finish()
58757 {
58758 if (null === $this->startTime) {
58759 throw new LogicException('You must start the progress bar before calling finish().');
58760 }
58761
58762 if (null !== $this->startTime) {
58763 if (!$this->max) {
58764 $this->barChar = $this->barCharOriginal;
58765 $this->display(true);
58766 }
58767 $this->startTime = null;
58768 $this->output->writeln('');
58769 $this->output = null;
58770 }
58771 }
58772
58773
58774
58775
58776 private function initialize()
58777 {
58778 $this->formatVars = array();
58779 foreach ($this->defaultFormatVars as $var) {
58780 if (false !== strpos($this->format, "%{$var}%")) {
58781 $this->formatVars[$var] = true;
58782 }
58783 }
58784
58785 if ($this->max > 0) {
58786 $this->widths['max'] = $this->strlen($this->max);
58787 $this->widths['current'] = $this->widths['max'];
58788 } else {
58789 $this->barCharOriginal = $this->barChar;
58790 $this->barChar = $this->emptyBarChar;
58791 }
58792 }
58793
58794
58795
58796
58797
58798
58799
58800
58801 private function generate($finish = false)
58802 {
58803 $vars = array();
58804 $percent = 0;
58805 if ($this->max > 0) {
58806 $percent = (float) $this->current / $this->max;
58807 }
58808
58809 if (isset($this->formatVars['bar'])) {
58810 if ($this->max > 0) {
58811 $completeBars = floor($percent * $this->barWidth);
58812 } else {
58813 if (!$finish) {
58814 $completeBars = floor($this->current % $this->barWidth);
58815 } else {
58816 $completeBars = $this->barWidth;
58817 }
58818 }
58819
58820 $emptyBars = $this->barWidth - $completeBars - $this->strlen($this->progressChar);
58821 $bar = str_repeat($this->barChar, $completeBars);
58822 if ($completeBars < $this->barWidth) {
58823 $bar .= $this->progressChar;
58824 $bar .= str_repeat($this->emptyBarChar, $emptyBars);
58825 }
58826
58827 $vars['bar'] = $bar;
58828 }
58829
58830 if (isset($this->formatVars['elapsed'])) {
58831 $elapsed = time() - $this->startTime;
58832 $vars['elapsed'] = str_pad($this->humaneTime($elapsed), $this->widths['elapsed'], ' ', STR_PAD_LEFT);
58833 }
58834
58835 if (isset($this->formatVars['current'])) {
58836 $vars['current'] = str_pad($this->current, $this->widths['current'], ' ', STR_PAD_LEFT);
58837 }
58838
58839 if (isset($this->formatVars['max'])) {
58840 $vars['max'] = $this->max;
58841 }
58842
58843 if (isset($this->formatVars['percent'])) {
58844 $vars['percent'] = str_pad(floor($percent * 100), $this->widths['percent'], ' ', STR_PAD_LEFT);
58845 }
58846
58847 return $vars;
58848 }
58849
58850
58851
58852
58853
58854
58855
58856
58857 private function humaneTime($secs)
58858 {
58859 $text = '';
58860 foreach ($this->timeFormats as $format) {
58861 if ($secs < $format[0]) {
58862 if (2 == \count($format)) {
58863 $text = $format[1];
58864 break;
58865 } else {
58866 $text = ceil($secs / $format[2]).' '.$format[1];
58867 break;
58868 }
58869 }
58870 }
58871
58872 return $text;
58873 }
58874
58875
58876
58877
58878
58879
58880
58881 private function overwrite(OutputInterface $output, $message)
58882 {
58883 $length = $this->strlen($message);
58884
58885
58886 if (null !== $this->lastMessagesLength && $this->lastMessagesLength > $length) {
58887 $message = str_pad($message, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT);
58888 }
58889
58890
58891 $output->write("\x0D");
58892 $output->write($message);
58893
58894 $this->lastMessagesLength = $this->strlen($message);
58895 }
58896
58897
58898
58899
58900 public function getName()
58901 {
58902 return 'progress';
58903 }
58904 }
58905 <?php
58906
58907
58908
58909
58910
58911
58912
58913
58914
58915
58916 namespace Symfony\Component\Console\Helper;
58917
58918 use Symfony\Component\Console\Exception\InvalidArgumentException;
58919 use Symfony\Component\Console\Exception\LogicException;
58920 use Symfony\Component\Console\Output\OutputInterface;
58921
58922
58923
58924
58925 class ProgressIndicator
58926 {
58927 private $output;
58928 private $startTime;
58929 private $format;
58930 private $message;
58931 private $indicatorValues;
58932 private $indicatorCurrent;
58933 private $indicatorChangeInterval;
58934 private $indicatorUpdateTime;
58935 private $started = false;
58936
58937 private static $formatters;
58938 private static $formats;
58939
58940
58941
58942
58943
58944
58945
58946 public function __construct(OutputInterface $output, $format = null, $indicatorChangeInterval = 100, $indicatorValues = null)
58947 {
58948 $this->output = $output;
58949
58950 if (null === $format) {
58951 $format = $this->determineBestFormat();
58952 }
58953
58954 if (null === $indicatorValues) {
58955 $indicatorValues = array('-', '\\', '|', '/');
58956 }
58957
58958 $indicatorValues = array_values($indicatorValues);
58959
58960 if (2 > \count($indicatorValues)) {
58961 throw new InvalidArgumentException('Must have at least 2 indicator value characters.');
58962 }
58963
58964 $this->format = self::getFormatDefinition($format);
58965 $this->indicatorChangeInterval = $indicatorChangeInterval;
58966 $this->indicatorValues = $indicatorValues;
58967 $this->startTime = time();
58968 }
58969
58970
58971
58972
58973
58974
58975 public function setMessage($message)
58976 {
58977 $this->message = $message;
58978
58979 $this->display();
58980 }
58981
58982
58983
58984
58985
58986
58987
58988
58989 public function getMessage()
58990 {
58991 return $this->message;
58992 }
58993
58994
58995
58996
58997
58998
58999
59000
59001 public function getStartTime()
59002 {
59003 return $this->startTime;
59004 }
59005
59006
59007
59008
59009
59010
59011
59012
59013 public function getCurrentValue()
59014 {
59015 return $this->indicatorValues[$this->indicatorCurrent % \count($this->indicatorValues)];
59016 }
59017
59018
59019
59020
59021
59022
59023 public function start($message)
59024 {
59025 if ($this->started) {
59026 throw new LogicException('Progress indicator already started.');
59027 }
59028
59029 $this->message = $message;
59030 $this->started = true;
59031 $this->startTime = time();
59032 $this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval;
59033 $this->indicatorCurrent = 0;
59034
59035 $this->display();
59036 }
59037
59038
59039
59040
59041 public function advance()
59042 {
59043 if (!$this->started) {
59044 throw new LogicException('Progress indicator has not yet been started.');
59045 }
59046
59047 if (!$this->output->isDecorated()) {
59048 return;
59049 }
59050
59051 $currentTime = $this->getCurrentTimeInMilliseconds();
59052
59053 if ($currentTime < $this->indicatorUpdateTime) {
59054 return;
59055 }
59056
59057 $this->indicatorUpdateTime = $currentTime + $this->indicatorChangeInterval;
59058 ++$this->indicatorCurrent;
59059
59060 $this->display();
59061 }
59062
59063
59064
59065
59066
59067
59068 public function finish($message)
59069 {
59070 if (!$this->started) {
59071 throw new LogicException('Progress indicator has not yet been started.');
59072 }
59073
59074 $this->message = $message;
59075 $this->display();
59076 $this->output->writeln('');
59077 $this->started = false;
59078 }
59079
59080
59081
59082
59083
59084
59085
59086
59087 public static function getFormatDefinition($name)
59088 {
59089 if (!self::$formats) {
59090 self::$formats = self::initFormats();
59091 }
59092
59093 return isset(self::$formats[$name]) ? self::$formats[$name] : null;
59094 }
59095
59096
59097
59098
59099
59100
59101
59102
59103
59104 public static function setPlaceholderFormatterDefinition($name, $callable)
59105 {
59106 if (!self::$formatters) {
59107 self::$formatters = self::initPlaceholderFormatters();
59108 }
59109
59110 self::$formatters[$name] = $callable;
59111 }
59112
59113
59114
59115
59116
59117
59118
59119
59120 public static function getPlaceholderFormatterDefinition($name)
59121 {
59122 if (!self::$formatters) {
59123 self::$formatters = self::initPlaceholderFormatters();
59124 }
59125
59126 return isset(self::$formatters[$name]) ? self::$formatters[$name] : null;
59127 }
59128
59129 private function display()
59130 {
59131 if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
59132 return;
59133 }
59134
59135 $self = $this;
59136
59137 $this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) use ($self) {
59138 if ($formatter = $self::getPlaceholderFormatterDefinition($matches[1])) {
59139 return \call_user_func($formatter, $self);
59140 }
59141
59142 return $matches[0];
59143 }, $this->format));
59144 }
59145
59146 private function determineBestFormat()
59147 {
59148 switch ($this->output->getVerbosity()) {
59149
59150 case OutputInterface::VERBOSITY_VERBOSE:
59151 return $this->output->isDecorated() ? 'verbose' : 'verbose_no_ansi';
59152 case OutputInterface::VERBOSITY_VERY_VERBOSE:
59153 case OutputInterface::VERBOSITY_DEBUG:
59154 return $this->output->isDecorated() ? 'very_verbose' : 'very_verbose_no_ansi';
59155 default:
59156 return $this->output->isDecorated() ? 'normal' : 'normal_no_ansi';
59157 }
59158 }
59159
59160
59161
59162
59163
59164
59165 private function overwrite($message)
59166 {
59167 if ($this->output->isDecorated()) {
59168 $this->output->write("\x0D\x1B[2K");
59169 $this->output->write($message);
59170 } else {
59171 $this->output->writeln($message);
59172 }
59173 }
59174
59175 private function getCurrentTimeInMilliseconds()
59176 {
59177 return round(microtime(true) * 1000);
59178 }
59179
59180 private static function initPlaceholderFormatters()
59181 {
59182 return array(
59183 'indicator' => function (ProgressIndicator $indicator) {
59184 return $indicator->getCurrentValue();
59185 },
59186 'message' => function (ProgressIndicator $indicator) {
59187 return $indicator->getMessage();
59188 },
59189 'elapsed' => function (ProgressIndicator $indicator) {
59190 return Helper::formatTime(time() - $indicator->getStartTime());
59191 },
59192 'memory' => function () {
59193 return Helper::formatMemory(memory_get_usage(true));
59194 },
59195 );
59196 }
59197
59198 private static function initFormats()
59199 {
59200 return array(
59201 'normal' => ' %indicator% %message%',
59202 'normal_no_ansi' => ' %message%',
59203
59204 'verbose' => ' %indicator% %message% (%elapsed:6s%)',
59205 'verbose_no_ansi' => ' %message% (%elapsed:6s%)',
59206
59207 'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)',
59208 'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)',
59209 );
59210 }
59211 }
59212 <?php
59213
59214
59215
59216
59217
59218
59219
59220
59221
59222
59223 namespace Symfony\Component\Console\Helper;
59224
59225 use Symfony\Component\Console\Exception\InvalidArgumentException;
59226 use Symfony\Component\Console\Exception\RuntimeException;
59227 use Symfony\Component\Console\Formatter\OutputFormatter;
59228 use Symfony\Component\Console\Formatter\OutputFormatterStyle;
59229 use Symfony\Component\Console\Input\InputInterface;
59230 use Symfony\Component\Console\Output\ConsoleOutputInterface;
59231 use Symfony\Component\Console\Output\OutputInterface;
59232 use Symfony\Component\Console\Question\ChoiceQuestion;
59233 use Symfony\Component\Console\Question\Question;
59234
59235
59236
59237
59238
59239
59240 class QuestionHelper extends Helper
59241 {
59242 private $inputStream;
59243 private static $shell;
59244 private static $stty;
59245
59246
59247
59248
59249
59250
59251
59252
59253 public function ask(InputInterface $input, OutputInterface $output, Question $question)
59254 {
59255 if ($output instanceof ConsoleOutputInterface) {
59256 $output = $output->getErrorOutput();
59257 }
59258
59259 if (!$input->isInteractive()) {
59260 $default = $question->getDefault();
59261
59262 if (null !== $default && $question instanceof ChoiceQuestion) {
59263 $choices = $question->getChoices();
59264
59265 if (!$question->isMultiselect()) {
59266 return isset($choices[$default]) ? $choices[$default] : $default;
59267 }
59268
59269 $default = explode(',', $default);
59270 foreach ($default as $k => $v) {
59271 $v = trim($v);
59272 $default[$k] = isset($choices[$v]) ? $choices[$v] : $v;
59273 }
59274 }
59275
59276 return $default;
59277 }
59278
59279 if (!$question->getValidator()) {
59280 return $this->doAsk($output, $question);
59281 }
59282
59283 $that = $this;
59284
59285 $interviewer = function () use ($output, $question, $that) {
59286 return $that->doAsk($output, $question);
59287 };
59288
59289 return $this->validateAttempts($interviewer, $output, $question);
59290 }
59291
59292
59293
59294
59295
59296
59297
59298
59299
59300
59301 public function setInputStream($stream)
59302 {
59303 if (!\is_resource($stream)) {
59304 throw new InvalidArgumentException('Input stream must be a valid resource.');
59305 }
59306
59307 $this->inputStream = $stream;
59308 }
59309
59310
59311
59312
59313
59314
59315 public function getInputStream()
59316 {
59317 return $this->inputStream;
59318 }
59319
59320
59321
59322
59323 public function getName()
59324 {
59325 return 'question';
59326 }
59327
59328
59329
59330
59331
59332
59333
59334
59335
59336
59337 public function doAsk(OutputInterface $output, Question $question)
59338 {
59339 $this->writePrompt($output, $question);
59340
59341 $inputStream = $this->inputStream ?: STDIN;
59342 $autocomplete = $question->getAutocompleterValues();
59343
59344 if (null === $autocomplete || !$this->hasSttyAvailable()) {
59345 $ret = false;
59346 if ($question->isHidden()) {
59347 try {
59348 $ret = trim($this->getHiddenResponse($output, $inputStream));
59349 } catch (RuntimeException $e) {
59350 if (!$question->isHiddenFallback()) {
59351 throw $e;
59352 }
59353 }
59354 }
59355
59356 if (false === $ret) {
59357 $ret = fgets($inputStream, 4096);
59358 if (false === $ret) {
59359 throw new RuntimeException('Aborted');
59360 }
59361 $ret = trim($ret);
59362 }
59363 } else {
59364 $ret = trim($this->autocomplete($output, $question, $inputStream, \is_array($autocomplete) ? $autocomplete : iterator_to_array($autocomplete, false)));
59365 }
59366
59367 $ret = \strlen($ret) > 0 ? $ret : $question->getDefault();
59368
59369 if ($normalizer = $question->getNormalizer()) {
59370 return $normalizer($ret);
59371 }
59372
59373 return $ret;
59374 }
59375
59376
59377
59378
59379 protected function writePrompt(OutputInterface $output, Question $question)
59380 {
59381 $message = $question->getQuestion();
59382
59383 if ($question instanceof ChoiceQuestion) {
59384 $maxWidth = max(array_map(array($this, 'strlen'), array_keys($question->getChoices())));
59385
59386 $messages = (array) $question->getQuestion();
59387 foreach ($question->getChoices() as $key => $value) {
59388 $width = $maxWidth - $this->strlen($key);
59389 $messages[] = '  [<info>'.$key.str_repeat(' ', $width).'</info>] '.$value;
59390 }
59391
59392 $output->writeln($messages);
59393
59394 $message = $question->getPrompt();
59395 }
59396
59397 $output->write($message);
59398 }
59399
59400
59401
59402
59403 protected function writeError(OutputInterface $output, \Exception $error)
59404 {
59405 if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) {
59406 $message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error');
59407 } else {
59408 $message = '<error>'.$error->getMessage().'</error>';
59409 }
59410
59411 $output->writeln($message);
59412 }
59413
59414
59415
59416
59417
59418
59419
59420
59421
59422
59423
59424 private function autocomplete(OutputInterface $output, Question $question, $inputStream, array $autocomplete)
59425 {
59426 $ret = '';
59427
59428 $i = 0;
59429 $ofs = -1;
59430 $matches = $autocomplete;
59431 $numMatches = \count($matches);
59432
59433 $sttyMode = shell_exec('stty -g');
59434
59435
59436 shell_exec('stty -icanon -echo');
59437
59438
59439 $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white'));
59440
59441
59442 while (!feof($inputStream)) {
59443 $c = fread($inputStream, 1);
59444
59445
59446 if ("\177" === $c) {
59447 if (0 === $numMatches && 0 !== $i) {
59448 --$i;
59449
59450 $output->write("\033[1D");
59451 }
59452
59453 if (0 === $i) {
59454 $ofs = -1;
59455 $matches = $autocomplete;
59456 $numMatches = \count($matches);
59457 } else {
59458 $numMatches = 0;
59459 }
59460
59461
59462 $ret = substr($ret, 0, $i);
59463 } elseif ("\033" === $c) {
59464
59465 $c .= fread($inputStream, 2);
59466
59467
59468 if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) {
59469 if ('A' === $c[2] && -1 === $ofs) {
59470 $ofs = 0;
59471 }
59472
59473 if (0 === $numMatches) {
59474 continue;
59475 }
59476
59477 $ofs += ('A' === $c[2]) ? -1 : 1;
59478 $ofs = ($numMatches + $ofs) % $numMatches;
59479 }
59480 } elseif (\ord($c) < 32) {
59481 if ("\t" === $c || "\n" === $c) {
59482 if ($numMatches > 0 && -1 !== $ofs) {
59483 $ret = $matches[$ofs];
59484
59485 $output->write(substr($ret, $i));
59486 $i = \strlen($ret);
59487 }
59488
59489 if ("\n" === $c) {
59490 $output->write($c);
59491 break;
59492 }
59493
59494 $numMatches = 0;
59495 }
59496
59497 continue;
59498 } else {
59499 $output->write($c);
59500 $ret .= $c;
59501 ++$i;
59502
59503 $numMatches = 0;
59504 $ofs = 0;
59505
59506 foreach ($autocomplete as $value) {
59507
59508 if (0 === strpos($value, $ret)) {
59509 $matches[$numMatches++] = $value;
59510 }
59511 }
59512 }
59513
59514
59515 $output->write("\033[K");
59516
59517 if ($numMatches > 0 && -1 !== $ofs) {
59518
59519 $output->write("\0337");
59520
59521 $output->write('<hl>'.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $i)).'</hl>');
59522
59523 $output->write("\0338");
59524 }
59525 }
59526
59527
59528 shell_exec(sprintf('stty %s', $sttyMode));
59529
59530 return $ret;
59531 }
59532
59533
59534
59535
59536
59537
59538
59539
59540
59541
59542
59543 private function getHiddenResponse(OutputInterface $output, $inputStream)
59544 {
59545 if ('\\' === \DIRECTORY_SEPARATOR) {
59546 $exe = __DIR__.'/../Resources/bin/hiddeninput.exe';
59547
59548
59549 if ('phar:' === substr(__FILE__, 0, 5)) {
59550 $tmpExe = sys_get_temp_dir().'/hiddeninput.exe';
59551 copy($exe, $tmpExe);
59552 $exe = $tmpExe;
59553 }
59554
59555 $value = rtrim(shell_exec($exe));
59556 $output->writeln('');
59557
59558 if (isset($tmpExe)) {
59559 unlink($tmpExe);
59560 }
59561
59562 return $value;
59563 }
59564
59565 if ($this->hasSttyAvailable()) {
59566 $sttyMode = shell_exec('stty -g');
59567
59568 shell_exec('stty -echo');
59569 $value = fgets($inputStream, 4096);
59570 shell_exec(sprintf('stty %s', $sttyMode));
59571
59572 if (false === $value) {
59573 throw new RuntimeException('Aborted');
59574 }
59575
59576 $value = trim($value);
59577 $output->writeln('');
59578
59579 return $value;
59580 }
59581
59582 if (false !== $shell = $this->getShell()) {
59583 $readCmd = 'csh' === $shell ? 'set mypassword = $<' : 'read -r mypassword';
59584 $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd);
59585 $value = rtrim(shell_exec($command));
59586 $output->writeln('');
59587
59588 return $value;
59589 }
59590
59591 throw new RuntimeException('Unable to hide the response.');
59592 }
59593
59594
59595
59596
59597
59598
59599
59600
59601
59602
59603
59604
59605 private function validateAttempts($interviewer, OutputInterface $output, Question $question)
59606 {
59607 $error = null;
59608 $attempts = $question->getMaxAttempts();
59609 while (null === $attempts || $attempts--) {
59610 if (null !== $error) {
59611 $this->writeError($output, $error);
59612 }
59613
59614 try {
59615 return \call_user_func($question->getValidator(), $interviewer());
59616 } catch (RuntimeException $e) {
59617 throw $e;
59618 } catch (\Exception $error) {
59619 }
59620 }
59621
59622 throw $error;
59623 }
59624
59625
59626
59627
59628
59629
59630 private function getShell()
59631 {
59632 if (null !== self::$shell) {
59633 return self::$shell;
59634 }
59635
59636 self::$shell = false;
59637
59638 if (file_exists('/usr/bin/env')) {
59639
59640 $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null";
59641 foreach (array('bash', 'zsh', 'ksh', 'csh') as $sh) {
59642 if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) {
59643 self::$shell = $sh;
59644 break;
59645 }
59646 }
59647 }
59648
59649 return self::$shell;
59650 }
59651
59652
59653
59654
59655
59656
59657 private function hasSttyAvailable()
59658 {
59659 if (null !== self::$stty) {
59660 return self::$stty;
59661 }
59662
59663 exec('stty 2>&1', $output, $exitcode);
59664
59665 return self::$stty = 0 === $exitcode;
59666 }
59667 }
59668 <?php
59669
59670
59671
59672
59673
59674
59675
59676
59677
59678
59679 namespace Symfony\Component\Console\Helper;
59680
59681 use Symfony\Component\Console\Exception\LogicException;
59682 use Symfony\Component\Console\Formatter\OutputFormatter;
59683 use Symfony\Component\Console\Input\InputInterface;
59684 use Symfony\Component\Console\Output\OutputInterface;
59685 use Symfony\Component\Console\Question\ChoiceQuestion;
59686 use Symfony\Component\Console\Question\ConfirmationQuestion;
59687 use Symfony\Component\Console\Question\Question;
59688 use Symfony\Component\Console\Style\SymfonyStyle;
59689
59690
59691
59692
59693
59694
59695 class SymfonyQuestionHelper extends QuestionHelper
59696 {
59697
59698
59699
59700 public function ask(InputInterface $input, OutputInterface $output, Question $question)
59701 {
59702 $validator = $question->getValidator();
59703 $question->setValidator(function ($value) use ($validator) {
59704 if (null !== $validator) {
59705 $value = $validator($value);
59706 } else {
59707
59708 if (!\is_array($value) && !\is_bool($value) && 0 === \strlen($value)) {
59709 throw new LogicException('A value is required.');
59710 }
59711 }
59712
59713 return $value;
59714 });
59715
59716 return parent::ask($input, $output, $question);
59717 }
59718
59719
59720
59721
59722 protected function writePrompt(OutputInterface $output, Question $question)
59723 {
59724 $text = OutputFormatter::escapeTrailingBackslash($question->getQuestion());
59725 $default = $question->getDefault();
59726
59727 switch (true) {
59728 case null === $default:
59729 $text = sprintf(' <info>%s</info>:', $text);
59730
59731 break;
59732
59733 case $question instanceof ConfirmationQuestion:
59734 $text = sprintf(' <info>%s (yes/no)</info> [<comment>%s</comment>]:', $text, $default ? 'yes' : 'no');
59735
59736 break;
59737
59738 case $question instanceof ChoiceQuestion && $question->isMultiselect():
59739 $choices = $question->getChoices();
59740 $default = explode(',', $default);
59741
59742 foreach ($default as $key => $value) {
59743 $default[$key] = $choices[trim($value)];
59744 }
59745
59746 $text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape(implode(', ', $default)));
59747
59748 break;
59749
59750 case $question instanceof ChoiceQuestion:
59751 $choices = $question->getChoices();
59752 $text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape(isset($choices[$default]) ? $choices[$default] : $default));
59753
59754 break;
59755
59756 default:
59757 $text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape($default));
59758 }
59759
59760 $output->writeln($text);
59761
59762 if ($question instanceof ChoiceQuestion) {
59763 $width = max(array_map('strlen', array_keys($question->getChoices())));
59764
59765 foreach ($question->getChoices() as $key => $value) {
59766 $output->writeln(sprintf("  [<comment>%-${width}s</comment>] %s", $key, $value));
59767 }
59768 }
59769
59770 $output->write(' > ');
59771 }
59772
59773
59774
59775
59776 protected function writeError(OutputInterface $output, \Exception $error)
59777 {
59778 if ($output instanceof SymfonyStyle) {
59779 $output->newLine();
59780 $output->error($error->getMessage());
59781
59782 return;
59783 }
59784
59785 parent::writeError($output, $error);
59786 }
59787 }
59788 <?php
59789
59790
59791
59792
59793
59794
59795
59796
59797
59798
59799 namespace Symfony\Component\Console\Helper;
59800
59801 use Symfony\Component\Console\Exception\InvalidArgumentException;
59802 use Symfony\Component\Console\Output\OutputInterface;
59803
59804
59805
59806
59807
59808
59809
59810
59811
59812 class Table
59813 {
59814
59815
59816
59817 private $headers = array();
59818
59819
59820
59821
59822 private $rows = array();
59823
59824
59825
59826
59827 private $columnWidths = array();
59828
59829
59830
59831
59832
59833
59834 private $numberOfColumns;
59835
59836
59837
59838
59839 private $output;
59840
59841
59842
59843
59844 private $style;
59845
59846
59847
59848
59849 private $columnStyles = array();
59850
59851 private static $styles;
59852
59853 public function __construct(OutputInterface $output)
59854 {
59855 $this->output = $output;
59856
59857 if (!self::$styles) {
59858 self::$styles = self::initStyles();
59859 }
59860
59861 $this->setStyle('default');
59862 }
59863
59864
59865
59866
59867
59868
59869
59870 public static function setStyleDefinition($name, TableStyle $style)
59871 {
59872 if (!self::$styles) {
59873 self::$styles = self::initStyles();
59874 }
59875
59876 self::$styles[$name] = $style;
59877 }
59878
59879
59880
59881
59882
59883
59884
59885
59886 public static function getStyleDefinition($name)
59887 {
59888 if (!self::$styles) {
59889 self::$styles = self::initStyles();
59890 }
59891
59892 if (isset(self::$styles[$name])) {
59893 return self::$styles[$name];
59894 }
59895
59896 throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
59897 }
59898
59899
59900
59901
59902
59903
59904
59905
59906 public function setStyle($name)
59907 {
59908 $this->style = $this->resolveStyle($name);
59909
59910 return $this;
59911 }
59912
59913
59914
59915
59916
59917
59918 public function getStyle()
59919 {
59920 return $this->style;
59921 }
59922
59923
59924
59925
59926
59927
59928
59929
59930
59931 public function setColumnStyle($columnIndex, $name)
59932 {
59933 $columnIndex = (int) $columnIndex;
59934
59935 $this->columnStyles[$columnIndex] = $this->resolveStyle($name);
59936
59937 return $this;
59938 }
59939
59940
59941
59942
59943
59944
59945
59946
59947
59948
59949 public function getColumnStyle($columnIndex)
59950 {
59951 if (isset($this->columnStyles[$columnIndex])) {
59952 return $this->columnStyles[$columnIndex];
59953 }
59954
59955 return $this->getStyle();
59956 }
59957
59958 public function setHeaders(array $headers)
59959 {
59960 $headers = array_values($headers);
59961 if (!empty($headers) && !\is_array($headers[0])) {
59962 $headers = array($headers);
59963 }
59964
59965 $this->headers = $headers;
59966
59967 return $this;
59968 }
59969
59970 public function setRows(array $rows)
59971 {
59972 $this->rows = array();
59973
59974 return $this->addRows($rows);
59975 }
59976
59977 public function addRows(array $rows)
59978 {
59979 foreach ($rows as $row) {
59980 $this->addRow($row);
59981 }
59982
59983 return $this;
59984 }
59985
59986 public function addRow($row)
59987 {
59988 if ($row instanceof TableSeparator) {
59989 $this->rows[] = $row;
59990
59991 return $this;
59992 }
59993
59994 if (!\is_array($row)) {
59995 throw new InvalidArgumentException('A row must be an array or a TableSeparator instance.');
59996 }
59997
59998 $this->rows[] = array_values($row);
59999
60000 return $this;
60001 }
60002
60003 public function setRow($column, array $row)
60004 {
60005 $this->rows[$column] = $row;
60006
60007 return $this;
60008 }
60009
60010
60011
60012
60013
60014
60015
60016
60017
60018
60019
60020
60021
60022
60023 public function render()
60024 {
60025 $this->calculateNumberOfColumns();
60026 $rows = $this->buildTableRows($this->rows);
60027 $headers = $this->buildTableRows($this->headers);
60028
60029 $this->calculateColumnsWidth(array_merge($headers, $rows));
60030
60031 $this->renderRowSeparator();
60032 if (!empty($headers)) {
60033 foreach ($headers as $header) {
60034 $this->renderRow($header, $this->style->getCellHeaderFormat());
60035 $this->renderRowSeparator();
60036 }
60037 }
60038 foreach ($rows as $row) {
60039 if ($row instanceof TableSeparator) {
60040 $this->renderRowSeparator();
60041 } else {
60042 $this->renderRow($row, $this->style->getCellRowFormat());
60043 }
60044 }
60045 if (!empty($rows)) {
60046 $this->renderRowSeparator();
60047 }
60048
60049 $this->cleanup();
60050 }
60051
60052
60053
60054
60055
60056
60057
60058
60059 private function renderRowSeparator()
60060 {
60061 if (0 === $count = $this->numberOfColumns) {
60062 return;
60063 }
60064
60065 if (!$this->style->getHorizontalBorderChar() && !$this->style->getCrossingChar()) {
60066 return;
60067 }
60068
60069 $markup = $this->style->getCrossingChar();
60070 for ($column = 0; $column < $count; ++$column) {
60071 $markup .= str_repeat($this->style->getHorizontalBorderChar(), $this->columnWidths[$column]).$this->style->getCrossingChar();
60072 }
60073
60074 $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup));
60075 }
60076
60077
60078
60079
60080 private function renderColumnSeparator()
60081 {
60082 return sprintf($this->style->getBorderFormat(), $this->style->getVerticalBorderChar());
60083 }
60084
60085
60086
60087
60088
60089
60090
60091
60092
60093
60094
60095 private function renderRow(array $row, $cellFormat)
60096 {
60097 if (empty($row)) {
60098 return;
60099 }
60100
60101 $rowContent = $this->renderColumnSeparator();
60102 foreach ($this->getRowColumns($row) as $column) {
60103 $rowContent .= $this->renderCell($row, $column, $cellFormat);
60104 $rowContent .= $this->renderColumnSeparator();
60105 }
60106 $this->output->writeln($rowContent);
60107 }
60108
60109
60110
60111
60112
60113
60114
60115
60116 private function renderCell(array $row, $column, $cellFormat)
60117 {
60118 $cell = isset($row[$column]) ? $row[$column] : '';
60119 $width = $this->columnWidths[$column];
60120 if ($cell instanceof TableCell && $cell->getColspan() > 1) {
60121
60122 foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) {
60123 $width += $this->getColumnSeparatorWidth() + $this->columnWidths[$nextColumn];
60124 }
60125 }
60126
60127
60128 if (false !== $encoding = mb_detect_encoding($cell, null, true)) {
60129 $width += \strlen($cell) - mb_strwidth($cell, $encoding);
60130 }
60131
60132 $style = $this->getColumnStyle($column);
60133
60134 if ($cell instanceof TableSeparator) {
60135 return sprintf($style->getBorderFormat(), str_repeat($style->getHorizontalBorderChar(), $width));
60136 }
60137
60138 $width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
60139 $content = sprintf($style->getCellRowContentFormat(), $cell);
60140
60141 return sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $style->getPadType()));
60142 }
60143
60144
60145
60146
60147 private function calculateNumberOfColumns()
60148 {
60149 if (null !== $this->numberOfColumns) {
60150 return;
60151 }
60152
60153 $columns = array(0);
60154 foreach (array_merge($this->headers, $this->rows) as $row) {
60155 if ($row instanceof TableSeparator) {
60156 continue;
60157 }
60158
60159 $columns[] = $this->getNumberOfColumns($row);
60160 }
60161
60162 $this->numberOfColumns = max($columns);
60163 }
60164
60165 private function buildTableRows($rows)
60166 {
60167 $unmergedRows = array();
60168 for ($rowKey = 0; $rowKey < \count($rows); ++$rowKey) {
60169 $rows = $this->fillNextRows($rows, $rowKey);
60170
60171
60172 foreach ($rows[$rowKey] as $column => $cell) {
60173 if (!strstr($cell, "\n")) {
60174 continue;
60175 }
60176 $lines = explode("\n", str_replace("\n", "<fg=default;bg=default>\n</>", $cell));
60177 foreach ($lines as $lineKey => $line) {
60178 if ($cell instanceof TableCell) {
60179 $line = new TableCell($line, array('colspan' => $cell->getColspan()));
60180 }
60181 if (0 === $lineKey) {
60182 $rows[$rowKey][$column] = $line;
60183 } else {
60184 $unmergedRows[$rowKey][$lineKey][$column] = $line;
60185 }
60186 }
60187 }
60188 }
60189
60190 $tableRows = array();
60191 foreach ($rows as $rowKey => $row) {
60192 $tableRows[] = $this->fillCells($row);
60193 if (isset($unmergedRows[$rowKey])) {
60194 $tableRows = array_merge($tableRows, $unmergedRows[$rowKey]);
60195 }
60196 }
60197
60198 return $tableRows;
60199 }
60200
60201
60202
60203
60204
60205
60206
60207
60208
60209 private function fillNextRows(array $rows, $line)
60210 {
60211 $unmergedRows = array();
60212 foreach ($rows[$line] as $column => $cell) {
60213 if ($cell instanceof TableCell && $cell->getRowspan() > 1) {
60214 $nbLines = $cell->getRowspan() - 1;
60215 $lines = array($cell);
60216 if (strstr($cell, "\n")) {
60217 $lines = explode("\n", str_replace("\n", "<fg=default;bg=default>\n</>", $cell));
60218 $nbLines = \count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines;
60219
60220 $rows[$line][$column] = new TableCell($lines[0], array('colspan' => $cell->getColspan()));
60221 unset($lines[0]);
60222 }
60223
60224
60225 $unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, array()), $unmergedRows);
60226 foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
60227 $value = isset($lines[$unmergedRowKey - $line]) ? $lines[$unmergedRowKey - $line] : '';
60228 $unmergedRows[$unmergedRowKey][$column] = new TableCell($value, array('colspan' => $cell->getColspan()));
60229 if ($nbLines === $unmergedRowKey - $line) {
60230 break;
60231 }
60232 }
60233 }
60234 }
60235
60236 foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
60237
60238 if (isset($rows[$unmergedRowKey]) && \is_array($rows[$unmergedRowKey]) && ($this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns)) {
60239 foreach ($unmergedRow as $cellKey => $cell) {
60240
60241 array_splice($rows[$unmergedRowKey], $cellKey, 0, array($cell));
60242 }
60243 } else {
60244 $row = $this->copyRow($rows, $unmergedRowKey - 1);
60245 foreach ($unmergedRow as $column => $cell) {
60246 if (!empty($cell)) {
60247 $row[$column] = $unmergedRow[$column];
60248 }
60249 }
60250 array_splice($rows, $unmergedRowKey, 0, array($row));
60251 }
60252 }
60253
60254 return $rows;
60255 }
60256
60257
60258
60259
60260
60261
60262 private function fillCells($row)
60263 {
60264 $newRow = array();
60265 foreach ($row as $column => $cell) {
60266 $newRow[] = $cell;
60267 if ($cell instanceof TableCell && $cell->getColspan() > 1) {
60268 foreach (range($column + 1, $column + $cell->getColspan() - 1) as $position) {
60269
60270 $newRow[] = '';
60271 }
60272 }
60273 }
60274
60275 return $newRow ?: $row;
60276 }
60277
60278
60279
60280
60281
60282
60283
60284 private function copyRow(array $rows, $line)
60285 {
60286 $row = $rows[$line];
60287 foreach ($row as $cellKey => $cellValue) {
60288 $row[$cellKey] = '';
60289 if ($cellValue instanceof TableCell) {
60290 $row[$cellKey] = new TableCell('', array('colspan' => $cellValue->getColspan()));
60291 }
60292 }
60293
60294 return $row;
60295 }
60296
60297
60298
60299
60300
60301
60302 private function getNumberOfColumns(array $row)
60303 {
60304 $columns = \count($row);
60305 foreach ($row as $column) {
60306 $columns += $column instanceof TableCell ? ($column->getColspan() - 1) : 0;
60307 }
60308
60309 return $columns;
60310 }
60311
60312
60313
60314
60315
60316
60317 private function getRowColumns(array $row)
60318 {
60319 $columns = range(0, $this->numberOfColumns - 1);
60320 foreach ($row as $cellKey => $cell) {
60321 if ($cell instanceof TableCell && $cell->getColspan() > 1) {
60322
60323 $columns = array_diff($columns, range($cellKey + 1, $cellKey + $cell->getColspan() - 1));
60324 }
60325 }
60326
60327 return $columns;
60328 }
60329
60330
60331
60332
60333
60334
60335 private function calculateColumnsWidth($rows)
60336 {
60337 for ($column = 0; $column < $this->numberOfColumns; ++$column) {
60338 $lengths = array();
60339 foreach ($rows as $row) {
60340 if ($row instanceof TableSeparator) {
60341 continue;
60342 }
60343
60344 foreach ($row as $i => $cell) {
60345 if ($cell instanceof TableCell) {
60346 $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell);
60347 $textLength = Helper::strlen($textContent);
60348 if ($textLength > 0) {
60349 $contentColumns = str_split($textContent, ceil($textLength / $cell->getColspan()));
60350 foreach ($contentColumns as $position => $content) {
60351 $row[$i + $position] = $content;
60352 }
60353 }
60354 }
60355 }
60356
60357 $lengths[] = $this->getCellWidth($row, $column);
60358 }
60359
60360 $this->columnWidths[$column] = max($lengths) + Helper::strlen($this->style->getCellRowContentFormat()) - 2;
60361 }
60362 }
60363
60364
60365
60366
60367
60368
60369 private function getColumnSeparatorWidth()
60370 {
60371 return Helper::strlen(sprintf($this->style->getBorderFormat(), $this->style->getVerticalBorderChar()));
60372 }
60373
60374
60375
60376
60377
60378
60379
60380
60381
60382 private function getCellWidth(array $row, $column)
60383 {
60384 if (isset($row[$column])) {
60385 $cell = $row[$column];
60386 $cellWidth = Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
60387
60388 return $cellWidth;
60389 }
60390
60391 return 0;
60392 }
60393
60394
60395
60396
60397 private function cleanup()
60398 {
60399 $this->columnWidths = array();
60400 $this->numberOfColumns = null;
60401 }
60402
60403 private static function initStyles()
60404 {
60405 $borderless = new TableStyle();
60406 $borderless
60407 ->setHorizontalBorderChar('=')
60408 ->setVerticalBorderChar(' ')
60409 ->setCrossingChar(' ')
60410 ;
60411
60412 $compact = new TableStyle();
60413 $compact
60414 ->setHorizontalBorderChar('')
60415 ->setVerticalBorderChar(' ')
60416 ->setCrossingChar('')
60417 ->setCellRowContentFormat('%s')
60418 ;
60419
60420 $styleGuide = new TableStyle();
60421 $styleGuide
60422 ->setHorizontalBorderChar('-')
60423 ->setVerticalBorderChar(' ')
60424 ->setCrossingChar(' ')
60425 ->setCellHeaderFormat('%s')
60426 ;
60427
60428 return array(
60429 'default' => new TableStyle(),
60430 'borderless' => $borderless,
60431 'compact' => $compact,
60432 'symfony-style-guide' => $styleGuide,
60433 );
60434 }
60435
60436 private function resolveStyle($name)
60437 {
60438 if ($name instanceof TableStyle) {
60439 return $name;
60440 }
60441
60442 if (isset(self::$styles[$name])) {
60443 return self::$styles[$name];
60444 }
60445
60446 throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
60447 }
60448 }
60449 <?php
60450
60451
60452
60453
60454
60455
60456
60457
60458
60459
60460 namespace Symfony\Component\Console\Helper;
60461
60462 use Symfony\Component\Console\Exception\InvalidArgumentException;
60463
60464
60465
60466
60467 class TableCell
60468 {
60469 private $value;
60470 private $options = array(
60471 'rowspan' => 1,
60472 'colspan' => 1,
60473 );
60474
60475
60476
60477
60478
60479 public function __construct($value = '', array $options = array())
60480 {
60481 if (is_numeric($value) && !\is_string($value)) {
60482 $value = (string) $value;
60483 }
60484
60485 $this->value = $value;
60486
60487
60488 if ($diff = array_diff(array_keys($options), array_keys($this->options))) {
60489 throw new InvalidArgumentException(sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff)));
60490 }
60491
60492 $this->options = array_merge($this->options, $options);
60493 }
60494
60495
60496
60497
60498
60499
60500 public function __toString()
60501 {
60502 return $this->value;
60503 }
60504
60505
60506
60507
60508
60509
60510 public function getColspan()
60511 {
60512 return (int) $this->options['colspan'];
60513 }
60514
60515
60516
60517
60518
60519
60520 public function getRowspan()
60521 {
60522 return (int) $this->options['rowspan'];
60523 }
60524 }
60525 <?php
60526
60527
60528
60529
60530
60531
60532
60533
60534
60535
60536 namespace Symfony\Component\Console\Helper;
60537
60538 use Symfony\Component\Console\Exception\InvalidArgumentException;
60539 use Symfony\Component\Console\Output\NullOutput;
60540 use Symfony\Component\Console\Output\OutputInterface;
60541
60542
60543
60544
60545
60546
60547
60548
60549
60550
60551 class TableHelper extends Helper
60552 {
60553 const LAYOUT_DEFAULT = 0;
60554 const LAYOUT_BORDERLESS = 1;
60555 const LAYOUT_COMPACT = 2;
60556
60557 private $table;
60558
60559 public function __construct($triggerDeprecationError = true)
60560 {
60561 if ($triggerDeprecationError) {
60562 @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);
60563 }
60564
60565 $this->table = new Table(new NullOutput());
60566 }
60567
60568
60569
60570
60571
60572
60573
60574
60575
60576
60577 public function setLayout($layout)
60578 {
60579 switch ($layout) {
60580 case self::LAYOUT_BORDERLESS:
60581 $this->table->setStyle('borderless');
60582 break;
60583
60584 case self::LAYOUT_COMPACT:
60585 $this->table->setStyle('compact');
60586 break;
60587
60588 case self::LAYOUT_DEFAULT:
60589 $this->table->setStyle('default');
60590 break;
60591
60592 default:
60593 throw new InvalidArgumentException(sprintf('Invalid table layout "%s".', $layout));
60594 }
60595
60596 return $this;
60597 }
60598
60599 public function setHeaders(array $headers)
60600 {
60601 $this->table->setHeaders($headers);
60602
60603 return $this;
60604 }
60605
60606 public function setRows(array $rows)
60607 {
60608 $this->table->setRows($rows);
60609
60610 return $this;
60611 }
60612
60613 public function addRows(array $rows)
60614 {
60615 $this->table->addRows($rows);
60616
60617 return $this;
60618 }
60619
60620 public function addRow(array $row)
60621 {
60622 $this->table->addRow($row);
60623
60624 return $this;
60625 }
60626
60627 public function setRow($column, array $row)
60628 {
60629 $this->table->setRow($column, $row);
60630
60631 return $this;
60632 }
60633
60634
60635
60636
60637
60638
60639
60640
60641 public function setPaddingChar($paddingChar)
60642 {
60643 $this->table->getStyle()->setPaddingChar($paddingChar);
60644
60645 return $this;
60646 }
60647
60648
60649
60650
60651
60652
60653
60654
60655 public function setHorizontalBorderChar($horizontalBorderChar)
60656 {
60657 $this->table->getStyle()->setHorizontalBorderChar($horizontalBorderChar);
60658
60659 return $this;
60660 }
60661
60662
60663
60664
60665
60666
60667
60668
60669 public function setVerticalBorderChar($verticalBorderChar)
60670 {
60671 $this->table->getStyle()->setVerticalBorderChar($verticalBorderChar);
60672
60673 return $this;
60674 }
60675
60676
60677
60678
60679
60680
60681
60682
60683 public function setCrossingChar($crossingChar)
60684 {
60685 $this->table->getStyle()->setCrossingChar($crossingChar);
60686
60687 return $this;
60688 }
60689
60690
60691
60692
60693
60694
60695
60696
60697 public function setCellHeaderFormat($cellHeaderFormat)
60698 {
60699 $this->table->getStyle()->setCellHeaderFormat($cellHeaderFormat);
60700
60701 return $this;
60702 }
60703
60704
60705
60706
60707
60708
60709
60710
60711 public function setCellRowFormat($cellRowFormat)
60712 {
60713 $this->table->getStyle()->setCellHeaderFormat($cellRowFormat);
60714
60715 return $this;
60716 }
60717
60718
60719
60720
60721
60722
60723
60724
60725 public function setCellRowContentFormat($cellRowContentFormat)
60726 {
60727 $this->table->getStyle()->setCellRowContentFormat($cellRowContentFormat);
60728
60729 return $this;
60730 }
60731
60732
60733
60734
60735
60736
60737
60738
60739 public function setBorderFormat($borderFormat)
60740 {
60741 $this->table->getStyle()->setBorderFormat($borderFormat);
60742
60743 return $this;
60744 }
60745
60746
60747
60748
60749
60750
60751
60752
60753 public function setPadType($padType)
60754 {
60755 $this->table->getStyle()->setPadType($padType);
60756
60757 return $this;
60758 }
60759
60760
60761
60762
60763
60764
60765
60766
60767
60768
60769
60770
60771
60772 public function render(OutputInterface $output)
60773 {
60774 $p = new \ReflectionProperty($this->table, 'output');
60775 $p->setAccessible(true);
60776 $p->setValue($this->table, $output);
60777
60778 $this->table->render();
60779 }
60780
60781
60782
60783
60784 public function getName()
60785 {
60786 return 'table';
60787 }
60788 }
60789 <?php
60790
60791
60792
60793
60794
60795
60796
60797
60798
60799
60800 namespace Symfony\Component\Console\Helper;
60801
60802
60803
60804
60805
60806
60807 class TableSeparator extends TableCell
60808 {
60809 public function __construct(array $options = array())
60810 {
60811 parent::__construct('', $options);
60812 }
60813 }
60814 <?php
60815
60816
60817
60818
60819
60820
60821
60822
60823
60824
60825 namespace Symfony\Component\Console\Helper;
60826
60827 use Symfony\Component\Console\Exception\InvalidArgumentException;
60828 use Symfony\Component\Console\Exception\LogicException;
60829
60830
60831
60832
60833
60834
60835
60836 class TableStyle
60837 {
60838 private $paddingChar = ' ';
60839 private $horizontalBorderChar = '-';
60840 private $verticalBorderChar = '|';
60841 private $crossingChar = '+';
60842 private $cellHeaderFormat = '<info>%s</info>';
60843 private $cellRowFormat = '%s';
60844 private $cellRowContentFormat = ' %s ';
60845 private $borderFormat = '%s';
60846 private $padType = STR_PAD_RIGHT;
60847
60848
60849
60850
60851
60852
60853
60854
60855 public function setPaddingChar($paddingChar)
60856 {
60857 if (!$paddingChar) {
60858 throw new LogicException('The padding char must not be empty');
60859 }
60860
60861 $this->paddingChar = $paddingChar;
60862
60863 return $this;
60864 }
60865
60866
60867
60868
60869
60870
60871 public function getPaddingChar()
60872 {
60873 return $this->paddingChar;
60874 }
60875
60876
60877
60878
60879
60880
60881
60882
60883 public function setHorizontalBorderChar($horizontalBorderChar)
60884 {
60885 $this->horizontalBorderChar = $horizontalBorderChar;
60886
60887 return $this;
60888 }
60889
60890
60891
60892
60893
60894
60895 public function getHorizontalBorderChar()
60896 {
60897 return $this->horizontalBorderChar;
60898 }
60899
60900
60901
60902
60903
60904
60905
60906
60907 public function setVerticalBorderChar($verticalBorderChar)
60908 {
60909 $this->verticalBorderChar = $verticalBorderChar;
60910
60911 return $this;
60912 }
60913
60914
60915
60916
60917
60918
60919 public function getVerticalBorderChar()
60920 {
60921 return $this->verticalBorderChar;
60922 }
60923
60924
60925
60926
60927
60928
60929
60930
60931 public function setCrossingChar($crossingChar)
60932 {
60933 $this->crossingChar = $crossingChar;
60934
60935 return $this;
60936 }
60937
60938
60939
60940
60941
60942
60943 public function getCrossingChar()
60944 {
60945 return $this->crossingChar;
60946 }
60947
60948
60949
60950
60951
60952
60953
60954
60955 public function setCellHeaderFormat($cellHeaderFormat)
60956 {
60957 $this->cellHeaderFormat = $cellHeaderFormat;
60958
60959 return $this;
60960 }
60961
60962
60963
60964
60965
60966
60967 public function getCellHeaderFormat()
60968 {
60969 return $this->cellHeaderFormat;
60970 }
60971
60972
60973
60974
60975
60976
60977
60978
60979 public function setCellRowFormat($cellRowFormat)
60980 {
60981 $this->cellRowFormat = $cellRowFormat;
60982
60983 return $this;
60984 }
60985
60986
60987
60988
60989
60990
60991 public function getCellRowFormat()
60992 {
60993 return $this->cellRowFormat;
60994 }
60995
60996
60997
60998
60999
61000
61001
61002
61003 public function setCellRowContentFormat($cellRowContentFormat)
61004 {
61005 $this->cellRowContentFormat = $cellRowContentFormat;
61006
61007 return $this;
61008 }
61009
61010
61011
61012
61013
61014
61015 public function getCellRowContentFormat()
61016 {
61017 return $this->cellRowContentFormat;
61018 }
61019
61020
61021
61022
61023
61024
61025
61026
61027 public function setBorderFormat($borderFormat)
61028 {
61029 $this->borderFormat = $borderFormat;
61030
61031 return $this;
61032 }
61033
61034
61035
61036
61037
61038
61039 public function getBorderFormat()
61040 {
61041 return $this->borderFormat;
61042 }
61043
61044
61045
61046
61047
61048
61049
61050
61051 public function setPadType($padType)
61052 {
61053 if (!\in_array($padType, array(STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH), true)) {
61054 throw new InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).');
61055 }
61056
61057 $this->padType = $padType;
61058
61059 return $this;
61060 }
61061
61062
61063
61064
61065
61066
61067 public function getPadType()
61068 {
61069 return $this->padType;
61070 }
61071 }
61072 <?php
61073
61074
61075
61076
61077
61078
61079
61080
61081
61082
61083 namespace Symfony\Component\Console\Input;
61084
61085 use Symfony\Component\Console\Exception\RuntimeException;
61086
61087
61088
61089
61090
61091
61092
61093
61094
61095
61096
61097
61098
61099
61100
61101
61102
61103
61104
61105
61106
61107
61108
61109
61110
61111
61112 class ArgvInput extends Input
61113 {
61114 private $tokens;
61115 private $parsed;
61116
61117
61118
61119
61120
61121 public function __construct(array $argv = null, InputDefinition $definition = null)
61122 {
61123 if (null === $argv) {
61124 $argv = $_SERVER['argv'];
61125 }
61126
61127
61128 array_shift($argv);
61129
61130 $this->tokens = $argv;
61131
61132 parent::__construct($definition);
61133 }
61134
61135 protected function setTokens(array $tokens)
61136 {
61137 $this->tokens = $tokens;
61138 }
61139
61140
61141
61142
61143 protected function parse()
61144 {
61145 $parseOptions = true;
61146 $this->parsed = $this->tokens;
61147 while (null !== $token = array_shift($this->parsed)) {
61148 if ($parseOptions && '' == $token) {
61149 $this->parseArgument($token);
61150 } elseif ($parseOptions && '--' == $token) {
61151 $parseOptions = false;
61152 } elseif ($parseOptions && 0 === strpos($token, '--')) {
61153 $this->parseLongOption($token);
61154 } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {
61155 $this->parseShortOption($token);
61156 } else {
61157 $this->parseArgument($token);
61158 }
61159 }
61160 }
61161
61162
61163
61164
61165
61166
61167 private function parseShortOption($token)
61168 {
61169 $name = substr($token, 1);
61170
61171 if (\strlen($name) > 1) {
61172 if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) {
61173
61174 $this->addShortOption($name[0], substr($name, 1));
61175 } else {
61176 $this->parseShortOptionSet($name);
61177 }
61178 } else {
61179 $this->addShortOption($name, null);
61180 }
61181 }
61182
61183
61184
61185
61186
61187
61188
61189
61190 private function parseShortOptionSet($name)
61191 {
61192 $len = \strlen($name);
61193 for ($i = 0; $i < $len; ++$i) {
61194 if (!$this->definition->hasShortcut($name[$i])) {
61195 $encoding = mb_detect_encoding($name, null, true);
61196 throw new RuntimeException(sprintf('The "-%s" option does not exist.', false === $encoding ? $name[$i] : mb_substr($name, $i, 1, $encoding)));
61197 }
61198
61199 $option = $this->definition->getOptionForShortcut($name[$i]);
61200 if ($option->acceptValue()) {
61201 $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));
61202
61203 break;
61204 } else {
61205 $this->addLongOption($option->getName(), null);
61206 }
61207 }
61208 }
61209
61210
61211
61212
61213
61214
61215 private function parseLongOption($token)
61216 {
61217 $name = substr($token, 2);
61218
61219 if (false !== $pos = strpos($name, '=')) {
61220 if (0 === \strlen($value = substr($name, $pos + 1))) {
61221 array_unshift($this->parsed, null);
61222 }
61223 $this->addLongOption(substr($name, 0, $pos), $value);
61224 } else {
61225 $this->addLongOption($name, null);
61226 }
61227 }
61228
61229
61230
61231
61232
61233
61234
61235
61236 private function parseArgument($token)
61237 {
61238 $c = \count($this->arguments);
61239
61240
61241 if ($this->definition->hasArgument($c)) {
61242 $arg = $this->definition->getArgument($c);
61243 $this->arguments[$arg->getName()] = $arg->isArray() ? array($token) : $token;
61244
61245
61246 } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {
61247 $arg = $this->definition->getArgument($c - 1);
61248 $this->arguments[$arg->getName()][] = $token;
61249
61250
61251 } else {
61252 $all = $this->definition->getArguments();
61253 if (\count($all)) {
61254 throw new RuntimeException(sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all))));
61255 }
61256
61257 throw new RuntimeException(sprintf('No arguments expected, got "%s".', $token));
61258 }
61259 }
61260
61261
61262
61263
61264
61265
61266
61267
61268
61269 private function addShortOption($shortcut, $value)
61270 {
61271 if (!$this->definition->hasShortcut($shortcut)) {
61272 throw new RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
61273 }
61274
61275 $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
61276 }
61277
61278
61279
61280
61281
61282
61283
61284
61285
61286 private function addLongOption($name, $value)
61287 {
61288 if (!$this->definition->hasOption($name)) {
61289 throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name));
61290 }
61291
61292 $option = $this->definition->getOption($name);
61293
61294
61295 if (!isset($value[0])) {
61296 $value = null;
61297 }
61298
61299 if (null !== $value && !$option->acceptValue()) {
61300 throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name));
61301 }
61302
61303 if (null === $value && $option->acceptValue() && \count($this->parsed)) {
61304
61305
61306 $next = array_shift($this->parsed);
61307 if (isset($next[0]) && '-' !== $next[0]) {
61308 $value = $next;
61309 } elseif (empty($next)) {
61310 $value = null;
61311 } else {
61312 array_unshift($this->parsed, $next);
61313 }
61314 }
61315
61316 if (null === $value) {
61317 if ($option->isValueRequired()) {
61318 throw new RuntimeException(sprintf('The "--%s" option requires a value.', $name));
61319 }
61320
61321 if (!$option->isArray()) {
61322 $value = $option->isValueOptional() ? $option->getDefault() : true;
61323 }
61324 }
61325
61326 if ($option->isArray()) {
61327 $this->options[$name][] = $value;
61328 } else {
61329 $this->options[$name] = $value;
61330 }
61331 }
61332
61333
61334
61335
61336 public function getFirstArgument()
61337 {
61338 foreach ($this->tokens as $token) {
61339 if ($token && '-' === $token[0]) {
61340 continue;
61341 }
61342
61343 return $token;
61344 }
61345 }
61346
61347
61348
61349
61350 public function hasParameterOption($values)
61351 {
61352 $values = (array) $values;
61353
61354 foreach ($this->tokens as $token) {
61355 foreach ($values as $value) {
61356
61357
61358
61359 $leading = 0 === strpos($value, '--') ? $value.'=' : $value;
61360 if ($token === $value || '' !== $leading && 0 === strpos($token, $leading)) {
61361 return true;
61362 }
61363 }
61364 }
61365
61366 return false;
61367 }
61368
61369
61370
61371
61372 public function getParameterOption($values, $default = false)
61373 {
61374 $values = (array) $values;
61375 $tokens = $this->tokens;
61376
61377 while (0 < \count($tokens)) {
61378 $token = array_shift($tokens);
61379
61380 foreach ($values as $value) {
61381 if ($token === $value) {
61382 return array_shift($tokens);
61383 }
61384
61385
61386
61387 $leading = 0 === strpos($value, '--') ? $value.'=' : $value;
61388 if ('' !== $leading && 0 === strpos($token, $leading)) {
61389 return substr($token, \strlen($leading));
61390 }
61391 }
61392 }
61393
61394 return $default;
61395 }
61396
61397
61398
61399
61400
61401
61402 public function __toString()
61403 {
61404 $self = $this;
61405 $tokens = array_map(function ($token) use ($self) {
61406 if (preg_match('{^(-[^=]+=)(.+)}', $token, $match)) {
61407 return $match[1].$self->escapeToken($match[2]);
61408 }
61409
61410 if ($token && '-' !== $token[0]) {
61411 return $self->escapeToken($token);
61412 }
61413
61414 return $token;
61415 }, $this->tokens);
61416
61417 return implode(' ', $tokens);
61418 }
61419 }
61420 <?php
61421
61422
61423
61424
61425
61426
61427
61428
61429
61430
61431 namespace Symfony\Component\Console\Input;
61432
61433 use Symfony\Component\Console\Exception\InvalidArgumentException;
61434 use Symfony\Component\Console\Exception\InvalidOptionException;
61435
61436
61437
61438
61439
61440
61441
61442
61443
61444
61445 class ArrayInput extends Input
61446 {
61447 private $parameters;
61448
61449 public function __construct(array $parameters, InputDefinition $definition = null)
61450 {
61451 $this->parameters = $parameters;
61452
61453 parent::__construct($definition);
61454 }
61455
61456
61457
61458
61459 public function getFirstArgument()
61460 {
61461 foreach ($this->parameters as $key => $value) {
61462 if ($key && '-' === $key[0]) {
61463 continue;
61464 }
61465
61466 return $value;
61467 }
61468 }
61469
61470
61471
61472
61473 public function hasParameterOption($values)
61474 {
61475 $values = (array) $values;
61476
61477 foreach ($this->parameters as $k => $v) {
61478 if (!\is_int($k)) {
61479 $v = $k;
61480 }
61481
61482 if (\in_array($v, $values)) {
61483 return true;
61484 }
61485 }
61486
61487 return false;
61488 }
61489
61490
61491
61492
61493 public function getParameterOption($values, $default = false)
61494 {
61495 $values = (array) $values;
61496
61497 foreach ($this->parameters as $k => $v) {
61498 if (\is_int($k)) {
61499 if (\in_array($v, $values)) {
61500 return true;
61501 }
61502 } elseif (\in_array($k, $values)) {
61503 return $v;
61504 }
61505 }
61506
61507 return $default;
61508 }
61509
61510
61511
61512
61513
61514
61515 public function __toString()
61516 {
61517 $params = array();
61518 foreach ($this->parameters as $param => $val) {
61519 if ($param && '-' === $param[0]) {
61520 if (\is_array($val)) {
61521 foreach ($val as $v) {
61522 $params[] = $param.('' != $v ? '='.$this->escapeToken($v) : '');
61523 }
61524 } else {
61525 $params[] = $param.('' != $val ? '='.$this->escapeToken($val) : '');
61526 }
61527 } else {
61528 $params[] = \is_array($val) ? implode(' ', array_map(array($this, 'escapeToken'), $val)) : $this->escapeToken($val);
61529 }
61530 }
61531
61532 return implode(' ', $params);
61533 }
61534
61535
61536
61537
61538 protected function parse()
61539 {
61540 foreach ($this->parameters as $key => $value) {
61541 if (0 === strpos($key, '--')) {
61542 $this->addLongOption(substr($key, 2), $value);
61543 } elseif ('-' === $key[0]) {
61544 $this->addShortOption(substr($key, 1), $value);
61545 } else {
61546 $this->addArgument($key, $value);
61547 }
61548 }
61549 }
61550
61551
61552
61553
61554
61555
61556
61557
61558
61559 private function addShortOption($shortcut, $value)
61560 {
61561 if (!$this->definition->hasShortcut($shortcut)) {
61562 throw new InvalidOptionException(sprintf('The "-%s" option does not exist.', $shortcut));
61563 }
61564
61565 $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
61566 }
61567
61568
61569
61570
61571
61572
61573
61574
61575
61576
61577 private function addLongOption($name, $value)
61578 {
61579 if (!$this->definition->hasOption($name)) {
61580 throw new InvalidOptionException(sprintf('The "--%s" option does not exist.', $name));
61581 }
61582
61583 $option = $this->definition->getOption($name);
61584
61585 if (null === $value) {
61586 if ($option->isValueRequired()) {
61587 throw new InvalidOptionException(sprintf('The "--%s" option requires a value.', $name));
61588 }
61589
61590 $value = $option->isValueOptional() ? $option->getDefault() : true;
61591 }
61592
61593 $this->options[$name] = $value;
61594 }
61595
61596
61597
61598
61599
61600
61601
61602
61603
61604 private function addArgument($name, $value)
61605 {
61606 if (!$this->definition->hasArgument($name)) {
61607 throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
61608 }
61609
61610 $this->arguments[$name] = $value;
61611 }
61612 }
61613 <?php
61614
61615
61616
61617
61618
61619
61620
61621
61622
61623
61624 namespace Symfony\Component\Console\Input;
61625
61626 use Symfony\Component\Console\Exception\InvalidArgumentException;
61627 use Symfony\Component\Console\Exception\RuntimeException;
61628
61629
61630
61631
61632
61633
61634
61635
61636
61637
61638
61639
61640 abstract class Input implements InputInterface
61641 {
61642 protected $definition;
61643 protected $options = array();
61644 protected $arguments = array();
61645 protected $interactive = true;
61646
61647 public function __construct(InputDefinition $definition = null)
61648 {
61649 if (null === $definition) {
61650 $this->definition = new InputDefinition();
61651 } else {
61652 $this->bind($definition);
61653 $this->validate();
61654 }
61655 }
61656
61657
61658
61659
61660 public function bind(InputDefinition $definition)
61661 {
61662 $this->arguments = array();
61663 $this->options = array();
61664 $this->definition = $definition;
61665
61666 $this->parse();
61667 }
61668
61669
61670
61671
61672 abstract protected function parse();
61673
61674
61675
61676
61677 public function validate()
61678 {
61679 $definition = $this->definition;
61680 $givenArguments = $this->arguments;
61681
61682 $missingArguments = array_filter(array_keys($definition->getArguments()), function ($argument) use ($definition, $givenArguments) {
61683 return !array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired();
61684 });
61685
61686 if (\count($missingArguments) > 0) {
61687 throw new RuntimeException(sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments)));
61688 }
61689 }
61690
61691
61692
61693
61694 public function isInteractive()
61695 {
61696 return $this->interactive;
61697 }
61698
61699
61700
61701
61702 public function setInteractive($interactive)
61703 {
61704 $this->interactive = (bool) $interactive;
61705 }
61706
61707
61708
61709
61710 public function getArguments()
61711 {
61712 return array_merge($this->definition->getArgumentDefaults(), $this->arguments);
61713 }
61714
61715
61716
61717
61718 public function getArgument($name)
61719 {
61720 if (!$this->definition->hasArgument($name)) {
61721 throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
61722 }
61723
61724 return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name)->getDefault();
61725 }
61726
61727
61728
61729
61730 public function setArgument($name, $value)
61731 {
61732 if (!$this->definition->hasArgument($name)) {
61733 throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
61734 }
61735
61736 $this->arguments[$name] = $value;
61737 }
61738
61739
61740
61741
61742 public function hasArgument($name)
61743 {
61744 return $this->definition->hasArgument($name);
61745 }
61746
61747
61748
61749
61750 public function getOptions()
61751 {
61752 return array_merge($this->definition->getOptionDefaults(), $this->options);
61753 }
61754
61755
61756
61757
61758 public function getOption($name)
61759 {
61760 if (!$this->definition->hasOption($name)) {
61761 throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
61762 }
61763
61764 return isset($this->options[$name]) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
61765 }
61766
61767
61768
61769
61770 public function setOption($name, $value)
61771 {
61772 if (!$this->definition->hasOption($name)) {
61773 throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
61774 }
61775
61776 $this->options[$name] = $value;
61777 }
61778
61779
61780
61781
61782 public function hasOption($name)
61783 {
61784 return $this->definition->hasOption($name);
61785 }
61786
61787
61788
61789
61790
61791
61792
61793
61794 public function escapeToken($token)
61795 {
61796 return preg_match('{^[\w-]+$}', $token) ? $token : escapeshellarg($token);
61797 }
61798 }
61799 <?php
61800
61801
61802
61803
61804
61805
61806
61807
61808
61809
61810 namespace Symfony\Component\Console\Input;
61811
61812 use Symfony\Component\Console\Exception\InvalidArgumentException;
61813 use Symfony\Component\Console\Exception\LogicException;
61814
61815
61816
61817
61818
61819
61820 class InputArgument
61821 {
61822 const REQUIRED = 1;
61823 const OPTIONAL = 2;
61824 const IS_ARRAY = 4;
61825
61826 private $name;
61827 private $mode;
61828 private $default;
61829 private $description;
61830
61831
61832
61833
61834
61835
61836
61837
61838
61839 public function __construct($name, $mode = null, $description = '', $default = null)
61840 {
61841 if (null === $mode) {
61842 $mode = self::OPTIONAL;
61843 } elseif (!\is_int($mode) || $mode > 7 || $mode < 1) {
61844 throw new InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode));
61845 }
61846
61847 $this->name = $name;
61848 $this->mode = $mode;
61849 $this->description = $description;
61850
61851 $this->setDefault($default);
61852 }
61853
61854
61855
61856
61857
61858
61859 public function getName()
61860 {
61861 return $this->name;
61862 }
61863
61864
61865
61866
61867
61868
61869 public function isRequired()
61870 {
61871 return self::REQUIRED === (self::REQUIRED & $this->mode);
61872 }
61873
61874
61875
61876
61877
61878
61879 public function isArray()
61880 {
61881 return self::IS_ARRAY === (self::IS_ARRAY & $this->mode);
61882 }
61883
61884
61885
61886
61887
61888
61889
61890
61891 public function setDefault($default = null)
61892 {
61893 if (self::REQUIRED === $this->mode && null !== $default) {
61894 throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.');
61895 }
61896
61897 if ($this->isArray()) {
61898 if (null === $default) {
61899 $default = array();
61900 } elseif (!\is_array($default)) {
61901 throw new LogicException('A default value for an array argument must be an array.');
61902 }
61903 }
61904
61905 $this->default = $default;
61906 }
61907
61908
61909
61910
61911
61912
61913 public function getDefault()
61914 {
61915 return $this->default;
61916 }
61917
61918
61919
61920
61921
61922
61923 public function getDescription()
61924 {
61925 return $this->description;
61926 }
61927 }
61928 <?php
61929
61930
61931
61932
61933
61934
61935
61936
61937
61938
61939 namespace Symfony\Component\Console\Input;
61940
61941
61942
61943
61944
61945
61946
61947 interface InputAwareInterface
61948 {
61949
61950
61951
61952 public function setInput(InputInterface $input);
61953 }
61954 <?php
61955
61956
61957
61958
61959
61960
61961
61962
61963
61964
61965 namespace Symfony\Component\Console\Input;
61966
61967 use Symfony\Component\Console\Descriptor\TextDescriptor;
61968 use Symfony\Component\Console\Descriptor\XmlDescriptor;
61969 use Symfony\Component\Console\Exception\InvalidArgumentException;
61970 use Symfony\Component\Console\Exception\LogicException;
61971 use Symfony\Component\Console\Output\BufferedOutput;
61972
61973
61974
61975
61976
61977
61978
61979
61980
61981
61982
61983
61984
61985 class InputDefinition
61986 {
61987 private $arguments;
61988 private $requiredCount;
61989 private $hasAnArrayArgument = false;
61990 private $hasOptional;
61991 private $options;
61992 private $shortcuts;
61993
61994
61995
61996
61997 public function __construct(array $definition = array())
61998 {
61999 $this->setDefinition($definition);
62000 }
62001
62002
62003
62004
62005 public function setDefinition(array $definition)
62006 {
62007 $arguments = array();
62008 $options = array();
62009 foreach ($definition as $item) {
62010 if ($item instanceof InputOption) {
62011 $options[] = $item;
62012 } else {
62013 $arguments[] = $item;
62014 }
62015 }
62016
62017 $this->setArguments($arguments);
62018 $this->setOptions($options);
62019 }
62020
62021
62022
62023
62024
62025
62026 public function setArguments($arguments = array())
62027 {
62028 $this->arguments = array();
62029 $this->requiredCount = 0;
62030 $this->hasOptional = false;
62031 $this->hasAnArrayArgument = false;
62032 $this->addArguments($arguments);
62033 }
62034
62035
62036
62037
62038
62039
62040 public function addArguments($arguments = array())
62041 {
62042 if (null !== $arguments) {
62043 foreach ($arguments as $argument) {
62044 $this->addArgument($argument);
62045 }
62046 }
62047 }
62048
62049
62050
62051
62052 public function addArgument(InputArgument $argument)
62053 {
62054 if (isset($this->arguments[$argument->getName()])) {
62055 throw new LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName()));
62056 }
62057
62058 if ($this->hasAnArrayArgument) {
62059 throw new LogicException('Cannot add an argument after an array argument.');
62060 }
62061
62062 if ($argument->isRequired() && $this->hasOptional) {
62063 throw new LogicException('Cannot add a required argument after an optional one.');
62064 }
62065
62066 if ($argument->isArray()) {
62067 $this->hasAnArrayArgument = true;
62068 }
62069
62070 if ($argument->isRequired()) {
62071 ++$this->requiredCount;
62072 } else {
62073 $this->hasOptional = true;
62074 }
62075
62076 $this->arguments[$argument->getName()] = $argument;
62077 }
62078
62079
62080
62081
62082
62083
62084
62085
62086
62087
62088 public function getArgument($name)
62089 {
62090 if (!$this->hasArgument($name)) {
62091 throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
62092 }
62093
62094 $arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments;
62095
62096 return $arguments[$name];
62097 }
62098
62099
62100
62101
62102
62103
62104
62105
62106 public function hasArgument($name)
62107 {
62108 $arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments;
62109
62110 return isset($arguments[$name]);
62111 }
62112
62113
62114
62115
62116
62117
62118 public function getArguments()
62119 {
62120 return $this->arguments;
62121 }
62122
62123
62124
62125
62126
62127
62128 public function getArgumentCount()
62129 {
62130 return $this->hasAnArrayArgument ? PHP_INT_MAX : \count($this->arguments);
62131 }
62132
62133
62134
62135
62136
62137
62138 public function getArgumentRequiredCount()
62139 {
62140 return $this->requiredCount;
62141 }
62142
62143
62144
62145
62146
62147
62148 public function getArgumentDefaults()
62149 {
62150 $values = array();
62151 foreach ($this->arguments as $argument) {
62152 $values[$argument->getName()] = $argument->getDefault();
62153 }
62154
62155 return $values;
62156 }
62157
62158
62159
62160
62161
62162
62163 public function setOptions($options = array())
62164 {
62165 $this->options = array();
62166 $this->shortcuts = array();
62167 $this->addOptions($options);
62168 }
62169
62170
62171
62172
62173
62174
62175 public function addOptions($options = array())
62176 {
62177 foreach ($options as $option) {
62178 $this->addOption($option);
62179 }
62180 }
62181
62182
62183
62184
62185 public function addOption(InputOption $option)
62186 {
62187 if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) {
62188 throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName()));
62189 }
62190
62191 if ($option->getShortcut()) {
62192 foreach (explode('|', $option->getShortcut()) as $shortcut) {
62193 if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) {
62194 throw new LogicException(sprintf('An option with shortcut "%s" already exists.', $shortcut));
62195 }
62196 }
62197 }
62198
62199 $this->options[$option->getName()] = $option;
62200 if ($option->getShortcut()) {
62201 foreach (explode('|', $option->getShortcut()) as $shortcut) {
62202 $this->shortcuts[$shortcut] = $option->getName();
62203 }
62204 }
62205 }
62206
62207
62208
62209
62210
62211
62212
62213
62214
62215
62216 public function getOption($name)
62217 {
62218 if (!$this->hasOption($name)) {
62219 throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
62220 }
62221
62222 return $this->options[$name];
62223 }
62224
62225
62226
62227
62228
62229
62230
62231
62232
62233
62234
62235 public function hasOption($name)
62236 {
62237 return isset($this->options[$name]);
62238 }
62239
62240
62241
62242
62243
62244
62245 public function getOptions()
62246 {
62247 return $this->options;
62248 }
62249
62250
62251
62252
62253
62254
62255
62256
62257 public function hasShortcut($name)
62258 {
62259 return isset($this->shortcuts[$name]);
62260 }
62261
62262
62263
62264
62265
62266
62267
62268
62269 public function getOptionForShortcut($shortcut)
62270 {
62271 return $this->getOption($this->shortcutToName($shortcut));
62272 }
62273
62274
62275
62276
62277
62278
62279 public function getOptionDefaults()
62280 {
62281 $values = array();
62282 foreach ($this->options as $option) {
62283 $values[$option->getName()] = $option->getDefault();
62284 }
62285
62286 return $values;
62287 }
62288
62289
62290
62291
62292
62293
62294
62295
62296
62297
62298 private function shortcutToName($shortcut)
62299 {
62300 if (!isset($this->shortcuts[$shortcut])) {
62301 throw new InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
62302 }
62303
62304 return $this->shortcuts[$shortcut];
62305 }
62306
62307
62308
62309
62310
62311
62312
62313
62314 public function getSynopsis($short = false)
62315 {
62316 $elements = array();
62317
62318 if ($short && $this->getOptions()) {
62319 $elements[] = '[options]';
62320 } elseif (!$short) {
62321 foreach ($this->getOptions() as $option) {
62322 $value = '';
62323 if ($option->acceptValue()) {
62324 $value = sprintf(
62325 ' %s%s%s',
62326 $option->isValueOptional() ? '[' : '',
62327 strtoupper($option->getName()),
62328 $option->isValueOptional() ? ']' : ''
62329 );
62330 }
62331
62332 $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';
62333 $elements[] = sprintf('[%s--%s%s]', $shortcut, $option->getName(), $value);
62334 }
62335 }
62336
62337 if (\count($elements) && $this->getArguments()) {
62338 $elements[] = '[--]';
62339 }
62340
62341 foreach ($this->getArguments() as $argument) {
62342 $element = '<'.$argument->getName().'>';
62343 if (!$argument->isRequired()) {
62344 $element = '['.$element.']';
62345 } elseif ($argument->isArray()) {
62346 $element .= ' ('.$element.')';
62347 }
62348
62349 if ($argument->isArray()) {
62350 $element .= '...';
62351 }
62352
62353 $elements[] = $element;
62354 }
62355
62356 return implode(' ', $elements);
62357 }
62358
62359
62360
62361
62362
62363
62364
62365
62366 public function asText()
62367 {
62368 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);
62369
62370 $descriptor = new TextDescriptor();
62371 $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true);
62372 $descriptor->describe($output, $this, array('raw_output' => true));
62373
62374 return $output->fetch();
62375 }
62376
62377
62378
62379
62380
62381
62382
62383
62384
62385
62386 public function asXml($asDom = false)
62387 {
62388 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);
62389
62390 $descriptor = new XmlDescriptor();
62391
62392 if ($asDom) {
62393 return $descriptor->getInputDefinitionDocument($this);
62394 }
62395
62396 $output = new BufferedOutput();
62397 $descriptor->describe($output, $this);
62398
62399 return $output->fetch();
62400 }
62401 }
62402 <?php
62403
62404
62405
62406
62407
62408
62409
62410
62411
62412
62413 namespace Symfony\Component\Console\Input;
62414
62415 use Symfony\Component\Console\Exception\InvalidArgumentException;
62416 use Symfony\Component\Console\Exception\RuntimeException;
62417
62418
62419
62420
62421
62422
62423 interface InputInterface
62424 {
62425
62426
62427
62428
62429
62430 public function getFirstArgument();
62431
62432
62433
62434
62435
62436
62437
62438
62439
62440
62441
62442
62443
62444 public function hasParameterOption($values);
62445
62446
62447
62448
62449
62450
62451
62452
62453
62454
62455
62456
62457
62458
62459 public function getParameterOption($values, $default = false);
62460
62461
62462
62463
62464
62465
62466 public function bind(InputDefinition $definition);
62467
62468
62469
62470
62471
62472
62473 public function validate();
62474
62475
62476
62477
62478
62479
62480 public function getArguments();
62481
62482
62483
62484
62485
62486
62487
62488
62489
62490
62491 public function getArgument($name);
62492
62493
62494
62495
62496
62497
62498
62499
62500
62501 public function setArgument($name, $value);
62502
62503
62504
62505
62506
62507
62508
62509
62510 public function hasArgument($name);
62511
62512
62513
62514
62515
62516
62517 public function getOptions();
62518
62519
62520
62521
62522
62523
62524
62525
62526
62527
62528 public function getOption($name);
62529
62530
62531
62532
62533
62534
62535
62536
62537
62538 public function setOption($name, $value);
62539
62540
62541
62542
62543
62544
62545
62546
62547 public function hasOption($name);
62548
62549
62550
62551
62552
62553
62554 public function isInteractive();
62555
62556
62557
62558
62559
62560
62561 public function setInteractive($interactive);
62562 }
62563 <?php
62564
62565
62566
62567
62568
62569
62570
62571
62572
62573
62574 namespace Symfony\Component\Console\Input;
62575
62576 use Symfony\Component\Console\Exception\InvalidArgumentException;
62577 use Symfony\Component\Console\Exception\LogicException;
62578
62579
62580
62581
62582
62583
62584 class InputOption
62585 {
62586 const VALUE_NONE = 1;
62587 const VALUE_REQUIRED = 2;
62588 const VALUE_OPTIONAL = 4;
62589 const VALUE_IS_ARRAY = 8;
62590
62591 private $name;
62592 private $shortcut;
62593 private $mode;
62594 private $default;
62595 private $description;
62596
62597
62598
62599
62600
62601
62602
62603
62604
62605
62606 public function __construct($name, $shortcut = null, $mode = null, $description = '', $default = null)
62607 {
62608 if (0 === strpos($name, '--')) {
62609 $name = substr($name, 2);
62610 }
62611
62612 if (empty($name)) {
62613 throw new InvalidArgumentException('An option name cannot be empty.');
62614 }
62615
62616 if (empty($shortcut)) {
62617 $shortcut = null;
62618 }
62619
62620 if (null !== $shortcut) {
62621 if (\is_array($shortcut)) {
62622 $shortcut = implode('|', $shortcut);
62623 }
62624 $shortcuts = preg_split('{(\|)-?}', ltrim($shortcut, '-'));
62625 $shortcuts = array_filter($shortcuts);
62626 $shortcut = implode('|', $shortcuts);
62627
62628 if (empty($shortcut)) {
62629 throw new InvalidArgumentException('An option shortcut cannot be empty.');
62630 }
62631 }
62632
62633 if (null === $mode) {
62634 $mode = self::VALUE_NONE;
62635 } elseif (!\is_int($mode) || $mode > 15 || $mode < 1) {
62636 throw new InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode));
62637 }
62638
62639 $this->name = $name;
62640 $this->shortcut = $shortcut;
62641 $this->mode = $mode;
62642 $this->description = $description;
62643
62644 if ($this->isArray() && !$this->acceptValue()) {
62645 throw new InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.');
62646 }
62647
62648 $this->setDefault($default);
62649 }
62650
62651
62652
62653
62654
62655
62656 public function getShortcut()
62657 {
62658 return $this->shortcut;
62659 }
62660
62661
62662
62663
62664
62665
62666 public function getName()
62667 {
62668 return $this->name;
62669 }
62670
62671
62672
62673
62674
62675
62676 public function acceptValue()
62677 {
62678 return $this->isValueRequired() || $this->isValueOptional();
62679 }
62680
62681
62682
62683
62684
62685
62686 public function isValueRequired()
62687 {
62688 return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode);
62689 }
62690
62691
62692
62693
62694
62695
62696 public function isValueOptional()
62697 {
62698 return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode);
62699 }
62700
62701
62702
62703
62704
62705
62706 public function isArray()
62707 {
62708 return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode);
62709 }
62710
62711
62712
62713
62714
62715
62716
62717
62718 public function setDefault($default = null)
62719 {
62720 if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) {
62721 throw new LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.');
62722 }
62723
62724 if ($this->isArray()) {
62725 if (null === $default) {
62726 $default = array();
62727 } elseif (!\is_array($default)) {
62728 throw new LogicException('A default value for an array option must be an array.');
62729 }
62730 }
62731
62732 $this->default = $this->acceptValue() ? $default : false;
62733 }
62734
62735
62736
62737
62738
62739
62740 public function getDefault()
62741 {
62742 return $this->default;
62743 }
62744
62745
62746
62747
62748
62749
62750 public function getDescription()
62751 {
62752 return $this->description;
62753 }
62754
62755
62756
62757
62758
62759
62760 public function equals(self $option)
62761 {
62762 return $option->getName() === $this->getName()
62763 && $option->getShortcut() === $this->getShortcut()
62764 && $option->getDefault() === $this->getDefault()
62765 && $option->isArray() === $this->isArray()
62766 && $option->isValueRequired() === $this->isValueRequired()
62767 && $option->isValueOptional() === $this->isValueOptional()
62768 ;
62769 }
62770 }
62771 <?php
62772
62773
62774
62775
62776
62777
62778
62779
62780
62781
62782 namespace Symfony\Component\Console\Input;
62783
62784 use Symfony\Component\Console\Exception\InvalidArgumentException;
62785
62786
62787
62788
62789
62790
62791
62792
62793
62794
62795 class StringInput extends ArgvInput
62796 {
62797 const REGEX_STRING = '([^\s]+?)(?:\s|(?<!\\\\)"|(?<!\\\\)\'|$)';
62798 const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';
62799
62800
62801
62802
62803
62804
62805
62806 public function __construct($input, InputDefinition $definition = null)
62807 {
62808 if ($definition) {
62809 @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);
62810 }
62811
62812 parent::__construct(array(), null);
62813
62814 $this->setTokens($this->tokenize($input));
62815
62816 if (null !== $definition) {
62817 $this->bind($definition);
62818 }
62819 }
62820
62821
62822
62823
62824
62825
62826
62827
62828
62829
62830 private function tokenize($input)
62831 {
62832 $tokens = array();
62833 $length = \strlen($input);
62834 $cursor = 0;
62835 while ($cursor < $length) {
62836 if (preg_match('/\s+/A', $input, $match, null, $cursor)) {
62837 } elseif (preg_match('/([^="\'\s]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, null, $cursor)) {
62838 $tokens[] = $match[1].$match[2].stripcslashes(str_replace(array('"\'', '\'"', '\'\'', '""'), '', substr($match[3], 1, \strlen($match[3]) - 2)));
62839 } elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, null, $cursor)) {
62840 $tokens[] = stripcslashes(substr($match[0], 1, \strlen($match[0]) - 2));
62841 } elseif (preg_match('/'.self::REGEX_STRING.'/A', $input, $match, null, $cursor)) {
62842 $tokens[] = stripcslashes($match[1]);
62843 } else {
62844
62845 throw new InvalidArgumentException(sprintf('Unable to parse input near "... %s ..."', substr($input, $cursor, 10)));
62846 }
62847
62848 $cursor += \strlen($match[0]);
62849 }
62850
62851 return $tokens;
62852 }
62853 }
62854 Copyright (c) 2004-2018 Fabien Potencier
62855
62856 Permission is hereby granted, free of charge, to any person obtaining a copy
62857 of this software and associated documentation files (the "Software"), to deal
62858 in the Software without restriction, including without limitation the rights
62859 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
62860 copies of the Software, and to permit persons to whom the Software is furnished
62861 to do so, subject to the following conditions:
62862
62863 The above copyright notice and this permission notice shall be included in all
62864 copies or substantial portions of the Software.
62865
62866 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
62867 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62868 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
62869 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
62870 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
62871 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
62872 THE SOFTWARE.
62873 <?php
62874
62875
62876
62877
62878
62879
62880
62881
62882
62883
62884 namespace Symfony\Component\Console\Logger;
62885
62886 use Psr\Log\AbstractLogger;
62887 use Psr\Log\InvalidArgumentException;
62888 use Psr\Log\LogLevel;
62889 use Symfony\Component\Console\Output\ConsoleOutputInterface;
62890 use Symfony\Component\Console\Output\OutputInterface;
62891
62892
62893
62894
62895
62896
62897
62898
62899 class ConsoleLogger extends AbstractLogger
62900 {
62901 const INFO = 'info';
62902 const ERROR = 'error';
62903
62904 private $output;
62905 private $verbosityLevelMap = array(
62906 LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL,
62907 LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL,
62908 LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL,
62909 LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL,
62910 LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL,
62911 LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE,
62912 LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE,
62913 LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG,
62914 );
62915 private $formatLevelMap = array(
62916 LogLevel::EMERGENCY => self::ERROR,
62917 LogLevel::ALERT => self::ERROR,
62918 LogLevel::CRITICAL => self::ERROR,
62919 LogLevel::ERROR => self::ERROR,
62920 LogLevel::WARNING => self::INFO,
62921 LogLevel::NOTICE => self::INFO,
62922 LogLevel::INFO => self::INFO,
62923 LogLevel::DEBUG => self::INFO,
62924 );
62925
62926 public function __construct(OutputInterface $output, array $verbosityLevelMap = array(), array $formatLevelMap = array())
62927 {
62928 $this->output = $output;
62929 $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap;
62930 $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap;
62931 }
62932
62933
62934
62935
62936 public function log($level, $message, array $context = array())
62937 {
62938 if (!isset($this->verbosityLevelMap[$level])) {
62939 throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level));
62940 }
62941
62942
62943 if (self::ERROR === $this->formatLevelMap[$level] && $this->output instanceof ConsoleOutputInterface) {
62944 $output = $this->output->getErrorOutput();
62945 } else {
62946 $output = $this->output;
62947 }
62948
62949 if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) {
62950 $output->writeln(sprintf('<%1$s>[%2$s] %3$s</%1$s>', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)));
62951 }
62952 }
62953
62954
62955
62956
62957
62958
62959
62960
62961
62962
62963
62964 private function interpolate($message, array $context)
62965 {
62966
62967 $replace = array();
62968 foreach ($context as $key => $val) {
62969 if (!\is_array($val) && (!\is_object($val) || method_exists($val, '__toString'))) {
62970 $replace[sprintf('{%s}', $key)] = $val;
62971 }
62972 }
62973
62974
62975 return strtr($message, $replace);
62976 }
62977 }
62978 <?php
62979
62980
62981
62982
62983
62984
62985
62986
62987
62988
62989 namespace Symfony\Component\Console\Output;
62990
62991
62992
62993
62994 class BufferedOutput extends Output
62995 {
62996 private $buffer = '';
62997
62998
62999
63000
63001
63002
63003 public function fetch()
63004 {
63005 $content = $this->buffer;
63006 $this->buffer = '';
63007
63008 return $content;
63009 }
63010
63011
63012
63013
63014 protected function doWrite($message, $newline)
63015 {
63016 $this->buffer .= $message;
63017
63018 if ($newline) {
63019 $this->buffer .= PHP_EOL;
63020 }
63021 }
63022 }
63023 <?php
63024
63025
63026
63027
63028
63029
63030
63031
63032
63033
63034 namespace Symfony\Component\Console\Output;
63035
63036 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
63037
63038
63039
63040
63041
63042
63043
63044
63045
63046
63047
63048
63049
63050
63051 class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
63052 {
63053 private $stderr;
63054
63055
63056
63057
63058
63059
63060 public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null)
63061 {
63062 parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter);
63063
63064 $actualDecorated = $this->isDecorated();
63065 $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated, $this->getFormatter());
63066
63067 if (null === $decorated) {
63068 $this->setDecorated($actualDecorated && $this->stderr->isDecorated());
63069 }
63070 }
63071
63072
63073
63074
63075 public function setDecorated($decorated)
63076 {
63077 parent::setDecorated($decorated);
63078 $this->stderr->setDecorated($decorated);
63079 }
63080
63081
63082
63083
63084 public function setFormatter(OutputFormatterInterface $formatter)
63085 {
63086 parent::setFormatter($formatter);
63087 $this->stderr->setFormatter($formatter);
63088 }
63089
63090
63091
63092
63093 public function setVerbosity($level)
63094 {
63095 parent::setVerbosity($level);
63096 $this->stderr->setVerbosity($level);
63097 }
63098
63099
63100
63101
63102 public function getErrorOutput()
63103 {
63104 return $this->stderr;
63105 }
63106
63107
63108
63109
63110 public function setErrorOutput(OutputInterface $error)
63111 {
63112 $this->stderr = $error;
63113 }
63114
63115
63116
63117
63118
63119
63120
63121 protected function hasStdoutSupport()
63122 {
63123 return false === $this->isRunningOS400();
63124 }
63125
63126
63127
63128
63129
63130
63131
63132 protected function hasStderrSupport()
63133 {
63134 return false === $this->isRunningOS400();
63135 }
63136
63137
63138
63139
63140
63141
63142
63143 private function isRunningOS400()
63144 {
63145 $checks = array(
63146 \function_exists('php_uname') ? php_uname('s') : '',
63147 getenv('OSTYPE'),
63148 PHP_OS,
63149 );
63150
63151 return false !== stripos(implode(';', $checks), 'OS400');
63152 }
63153
63154
63155
63156
63157 private function openOutputStream()
63158 {
63159 $outputStream = $this->hasStdoutSupport() ? 'php://stdout' : 'php://output';
63160
63161 return @fopen($outputStream, 'w') ?: fopen('php://output', 'w');
63162 }
63163
63164
63165
63166
63167 private function openErrorStream()
63168 {
63169 $errorStream = $this->hasStderrSupport() ? 'php://stderr' : 'php://output';
63170
63171 return fopen($errorStream, 'w');
63172 }
63173 }
63174 <?php
63175
63176
63177
63178
63179
63180
63181
63182
63183
63184
63185 namespace Symfony\Component\Console\Output;
63186
63187
63188
63189
63190
63191
63192
63193 interface ConsoleOutputInterface extends OutputInterface
63194 {
63195
63196
63197
63198
63199
63200 public function getErrorOutput();
63201
63202 public function setErrorOutput(OutputInterface $error);
63203 }
63204 <?php
63205
63206
63207
63208
63209
63210
63211
63212
63213
63214
63215 namespace Symfony\Component\Console\Output;
63216
63217 use Symfony\Component\Console\Formatter\OutputFormatter;
63218 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
63219
63220
63221
63222
63223
63224
63225
63226
63227
63228 class NullOutput implements OutputInterface
63229 {
63230
63231
63232
63233 public function setFormatter(OutputFormatterInterface $formatter)
63234 {
63235
63236 }
63237
63238
63239
63240
63241 public function getFormatter()
63242 {
63243
63244 return new OutputFormatter();
63245 }
63246
63247
63248
63249
63250 public function setDecorated($decorated)
63251 {
63252
63253 }
63254
63255
63256
63257
63258 public function isDecorated()
63259 {
63260 return false;
63261 }
63262
63263
63264
63265
63266 public function setVerbosity($level)
63267 {
63268
63269 }
63270
63271
63272
63273
63274 public function getVerbosity()
63275 {
63276 return self::VERBOSITY_QUIET;
63277 }
63278
63279
63280
63281
63282 public function isQuiet()
63283 {
63284 return true;
63285 }
63286
63287
63288
63289
63290 public function isVerbose()
63291 {
63292 return false;
63293 }
63294
63295
63296
63297
63298 public function isVeryVerbose()
63299 {
63300 return false;
63301 }
63302
63303
63304
63305
63306 public function isDebug()
63307 {
63308 return false;
63309 }
63310
63311
63312
63313
63314 public function writeln($messages, $options = self::OUTPUT_NORMAL)
63315 {
63316
63317 }
63318
63319
63320
63321
63322 public function write($messages, $newline = false, $options = self::OUTPUT_NORMAL)
63323 {
63324
63325 }
63326 }
63327 <?php
63328
63329
63330
63331
63332
63333
63334
63335
63336
63337
63338 namespace Symfony\Component\Console\Output;
63339
63340 use Symfony\Component\Console\Formatter\OutputFormatter;
63341 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
63342
63343
63344
63345
63346
63347
63348
63349
63350
63351
63352
63353
63354
63355
63356 abstract class Output implements OutputInterface
63357 {
63358 private $verbosity;
63359 private $formatter;
63360
63361
63362
63363
63364
63365
63366 public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = false, OutputFormatterInterface $formatter = null)
63367 {
63368 $this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity;
63369 $this->formatter = $formatter ?: new OutputFormatter();
63370 $this->formatter->setDecorated($decorated);
63371 }
63372
63373
63374
63375
63376 public function setFormatter(OutputFormatterInterface $formatter)
63377 {
63378 $this->formatter = $formatter;
63379 }
63380
63381
63382
63383
63384 public function getFormatter()
63385 {
63386 return $this->formatter;
63387 }
63388
63389
63390
63391
63392 public function setDecorated($decorated)
63393 {
63394 $this->formatter->setDecorated($decorated);
63395 }
63396
63397
63398
63399
63400 public function isDecorated()
63401 {
63402 return $this->formatter->isDecorated();
63403 }
63404
63405
63406
63407
63408 public function setVerbosity($level)
63409 {
63410 $this->verbosity = (int) $level;
63411 }
63412
63413
63414
63415
63416 public function getVerbosity()
63417 {
63418 return $this->verbosity;
63419 }
63420
63421
63422
63423
63424 public function isQuiet()
63425 {
63426 return self::VERBOSITY_QUIET === $this->verbosity;
63427 }
63428
63429
63430
63431
63432 public function isVerbose()
63433 {
63434 return self::VERBOSITY_VERBOSE <= $this->verbosity;
63435 }
63436
63437
63438
63439
63440 public function isVeryVerbose()
63441 {
63442 return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity;
63443 }
63444
63445
63446
63447
63448 public function isDebug()
63449 {
63450 return self::VERBOSITY_DEBUG <= $this->verbosity;
63451 }
63452
63453
63454
63455
63456 public function writeln($messages, $options = self::OUTPUT_NORMAL)
63457 {
63458 $this->write($messages, true, $options);
63459 }
63460
63461
63462
63463
63464 public function write($messages, $newline = false, $options = self::OUTPUT_NORMAL)
63465 {
63466 $messages = (array) $messages;
63467
63468 $types = self::OUTPUT_NORMAL | self::OUTPUT_RAW | self::OUTPUT_PLAIN;
63469 $type = $types & $options ?: self::OUTPUT_NORMAL;
63470
63471 $verbosities = self::VERBOSITY_QUIET | self::VERBOSITY_NORMAL | self::VERBOSITY_VERBOSE | self::VERBOSITY_VERY_VERBOSE | self::VERBOSITY_DEBUG;
63472 $verbosity = $verbosities & $options ?: self::VERBOSITY_NORMAL;
63473
63474 if ($verbosity > $this->getVerbosity()) {
63475 return;
63476 }
63477
63478 foreach ($messages as $message) {
63479 switch ($type) {
63480 case OutputInterface::OUTPUT_NORMAL:
63481 $message = $this->formatter->format($message);
63482 break;
63483 case OutputInterface::OUTPUT_RAW:
63484 break;
63485 case OutputInterface::OUTPUT_PLAIN:
63486 $message = strip_tags($this->formatter->format($message));
63487 break;
63488 }
63489
63490 $this->doWrite($message, $newline);
63491 }
63492 }
63493
63494
63495
63496
63497
63498
63499
63500 abstract protected function doWrite($message, $newline);
63501 }
63502 <?php
63503
63504
63505
63506
63507
63508
63509
63510
63511
63512
63513 namespace Symfony\Component\Console\Output;
63514
63515 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
63516
63517
63518
63519
63520
63521
63522 interface OutputInterface
63523 {
63524 const VERBOSITY_QUIET = 16;
63525 const VERBOSITY_NORMAL = 32;
63526 const VERBOSITY_VERBOSE = 64;
63527 const VERBOSITY_VERY_VERBOSE = 128;
63528 const VERBOSITY_DEBUG = 256;
63529
63530 const OUTPUT_NORMAL = 1;
63531 const OUTPUT_RAW = 2;
63532 const OUTPUT_PLAIN = 4;
63533
63534
63535
63536
63537
63538
63539
63540
63541 public function write($messages, $newline = false, $options = 0);
63542
63543
63544
63545
63546
63547
63548
63549 public function writeln($messages, $options = 0);
63550
63551
63552
63553
63554
63555
63556 public function setVerbosity($level);
63557
63558
63559
63560
63561
63562
63563 public function getVerbosity();
63564
63565
63566
63567
63568
63569
63570 public function setDecorated($decorated);
63571
63572
63573
63574
63575
63576
63577 public function isDecorated();
63578
63579 public function setFormatter(OutputFormatterInterface $formatter);
63580
63581
63582
63583
63584
63585
63586 public function getFormatter();
63587 }
63588 <?php
63589
63590
63591
63592
63593
63594
63595
63596
63597
63598
63599 namespace Symfony\Component\Console\Output;
63600
63601 use Symfony\Component\Console\Exception\InvalidArgumentException;
63602 use Symfony\Component\Console\Exception\RuntimeException;
63603 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
63604
63605
63606
63607
63608
63609
63610
63611
63612
63613
63614
63615
63616
63617
63618 class StreamOutput extends Output
63619 {
63620 private $stream;
63621
63622
63623
63624
63625
63626
63627
63628
63629
63630 public function __construct($stream, $verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null)
63631 {
63632 if (!\is_resource($stream) || 'stream' !== get_resource_type($stream)) {
63633 throw new InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
63634 }
63635
63636 $this->stream = $stream;
63637
63638 if (null === $decorated) {
63639 $decorated = $this->hasColorSupport();
63640 }
63641
63642 parent::__construct($verbosity, $decorated, $formatter);
63643 }
63644
63645
63646
63647
63648
63649
63650 public function getStream()
63651 {
63652 return $this->stream;
63653 }
63654
63655
63656
63657
63658 protected function doWrite($message, $newline)
63659 {
63660 if ($newline) {
63661 $message .= PHP_EOL;
63662 }
63663
63664 if (false === @fwrite($this->stream, $message)) {
63665
63666 throw new RuntimeException('Unable to write output.');
63667 }
63668
63669 fflush($this->stream);
63670 }
63671
63672
63673
63674
63675
63676
63677
63678
63679
63680
63681
63682
63683
63684
63685 protected function hasColorSupport()
63686 {
63687 if ('Hyper' === getenv('TERM_PROGRAM')) {
63688 return true;
63689 }
63690
63691 if (\DIRECTORY_SEPARATOR === '\\') {
63692 return (\function_exists('sapi_windows_vt100_support')
63693 && @sapi_windows_vt100_support($this->stream))
63694 || false !== getenv('ANSICON')
63695 || 'ON' === getenv('ConEmuANSI')
63696 || 'xterm' === getenv('TERM');
63697 }
63698
63699 if (\function_exists('stream_isatty')) {
63700 return @stream_isatty($this->stream);
63701 }
63702
63703 if (\function_exists('posix_isatty')) {
63704 return @posix_isatty($this->stream);
63705 }
63706
63707 $stat = @fstat($this->stream);
63708
63709 return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
63710 }
63711 }
63712 <?php
63713
63714
63715
63716
63717
63718
63719
63720
63721
63722
63723 namespace Symfony\Component\Console\Question;
63724
63725 use Symfony\Component\Console\Exception\InvalidArgumentException;
63726
63727
63728
63729
63730
63731
63732 class ChoiceQuestion extends Question
63733 {
63734 private $choices;
63735 private $multiselect = false;
63736 private $prompt = ' > ';
63737 private $errorMessage = 'Value "%s" is invalid';
63738
63739
63740
63741
63742
63743
63744 public function __construct($question, array $choices, $default = null)
63745 {
63746 if (!$choices) {
63747 throw new \LogicException('Choice question must have at least 1 choice available.');
63748 }
63749
63750 parent::__construct($question, $default);
63751
63752 $this->choices = $choices;
63753 $this->setValidator($this->getDefaultValidator());
63754 $this->setAutocompleterValues($choices);
63755 }
63756
63757
63758
63759
63760
63761
63762 public function getChoices()
63763 {
63764 return $this->choices;
63765 }
63766
63767
63768
63769
63770
63771
63772
63773
63774
63775
63776 public function setMultiselect($multiselect)
63777 {
63778 $this->multiselect = $multiselect;
63779 $this->setValidator($this->getDefaultValidator());
63780
63781 return $this;
63782 }
63783
63784
63785
63786
63787
63788
63789 public function isMultiselect()
63790 {
63791 return $this->multiselect;
63792 }
63793
63794
63795
63796
63797
63798
63799 public function getPrompt()
63800 {
63801 return $this->prompt;
63802 }
63803
63804
63805
63806
63807
63808
63809
63810
63811 public function setPrompt($prompt)
63812 {
63813 $this->prompt = $prompt;
63814
63815 return $this;
63816 }
63817
63818
63819
63820
63821
63822
63823
63824
63825
63826
63827 public function setErrorMessage($errorMessage)
63828 {
63829 $this->errorMessage = $errorMessage;
63830 $this->setValidator($this->getDefaultValidator());
63831
63832 return $this;
63833 }
63834
63835
63836
63837
63838
63839
63840 private function getDefaultValidator()
63841 {
63842 $choices = $this->choices;
63843 $errorMessage = $this->errorMessage;
63844 $multiselect = $this->multiselect;
63845 $isAssoc = $this->isAssoc($choices);
63846
63847 return function ($selected) use ($choices, $errorMessage, $multiselect, $isAssoc) {
63848
63849 $selectedChoices = str_replace(' ', '', $selected);
63850
63851 if ($multiselect) {
63852
63853 if (!preg_match('/^[^,]+(?:,[^,]+)*$/', $selectedChoices, $matches)) {
63854 throw new InvalidArgumentException(sprintf($errorMessage, $selected));
63855 }
63856 $selectedChoices = explode(',', $selectedChoices);
63857 } else {
63858 $selectedChoices = array($selected);
63859 }
63860
63861 $multiselectChoices = array();
63862 foreach ($selectedChoices as $value) {
63863 $results = array();
63864 foreach ($choices as $key => $choice) {
63865 if ($choice === $value) {
63866 $results[] = $key;
63867 }
63868 }
63869
63870 if (\count($results) > 1) {
63871 throw new InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of %s.', implode(' or ', $results)));
63872 }
63873
63874 $result = array_search($value, $choices);
63875
63876 if (!$isAssoc) {
63877 if (false !== $result) {
63878 $result = $choices[$result];
63879 } elseif (isset($choices[$value])) {
63880 $result = $choices[$value];
63881 }
63882 } elseif (false === $result && isset($choices[$value])) {
63883 $result = $value;
63884 }
63885
63886 if (false === $result) {
63887 throw new InvalidArgumentException(sprintf($errorMessage, $value));
63888 }
63889
63890 $multiselectChoices[] = (string) $result;
63891 }
63892
63893 if ($multiselect) {
63894 return $multiselectChoices;
63895 }
63896
63897 return current($multiselectChoices);
63898 };
63899 }
63900 }
63901 <?php
63902
63903
63904
63905
63906
63907
63908
63909
63910
63911
63912 namespace Symfony\Component\Console\Question;
63913
63914
63915
63916
63917
63918
63919 class ConfirmationQuestion extends Question
63920 {
63921 private $trueAnswerRegex;
63922
63923
63924
63925
63926
63927
63928 public function __construct($question, $default = true, $trueAnswerRegex = '/^y/i')
63929 {
63930 parent::__construct($question, (bool) $default);
63931
63932 $this->trueAnswerRegex = $trueAnswerRegex;
63933 $this->setNormalizer($this->getDefaultNormalizer());
63934 }
63935
63936
63937
63938
63939
63940
63941 private function getDefaultNormalizer()
63942 {
63943 $default = $this->getDefault();
63944 $regex = $this->trueAnswerRegex;
63945
63946 return function ($answer) use ($default, $regex) {
63947 if (\is_bool($answer)) {
63948 return $answer;
63949 }
63950
63951 $answerIsTrue = (bool) preg_match($regex, $answer);
63952 if (false === $default) {
63953 return $answer && $answerIsTrue;
63954 }
63955
63956 return !$answer || $answerIsTrue;
63957 };
63958 }
63959 }
63960 <?php
63961
63962
63963
63964
63965
63966
63967
63968
63969
63970
63971 namespace Symfony\Component\Console\Question;
63972
63973 use Symfony\Component\Console\Exception\InvalidArgumentException;
63974 use Symfony\Component\Console\Exception\LogicException;
63975
63976
63977
63978
63979
63980
63981 class Question
63982 {
63983 private $question;
63984 private $attempts;
63985 private $hidden = false;
63986 private $hiddenFallback = true;
63987 private $autocompleterValues;
63988 private $validator;
63989 private $default;
63990 private $normalizer;
63991
63992
63993
63994
63995
63996 public function __construct($question, $default = null)
63997 {
63998 $this->question = $question;
63999 $this->default = $default;
64000 }
64001
64002
64003
64004
64005
64006
64007 public function getQuestion()
64008 {
64009 return $this->question;
64010 }
64011
64012
64013
64014
64015
64016
64017 public function getDefault()
64018 {
64019 return $this->default;
64020 }
64021
64022
64023
64024
64025
64026
64027 public function isHidden()
64028 {
64029 return $this->hidden;
64030 }
64031
64032
64033
64034
64035
64036
64037
64038
64039
64040
64041 public function setHidden($hidden)
64042 {
64043 if ($this->autocompleterValues) {
64044 throw new LogicException('A hidden question cannot use the autocompleter.');
64045 }
64046
64047 $this->hidden = (bool) $hidden;
64048
64049 return $this;
64050 }
64051
64052
64053
64054
64055
64056
64057 public function isHiddenFallback()
64058 {
64059 return $this->hiddenFallback;
64060 }
64061
64062
64063
64064
64065
64066
64067
64068
64069 public function setHiddenFallback($fallback)
64070 {
64071 $this->hiddenFallback = (bool) $fallback;
64072
64073 return $this;
64074 }
64075
64076
64077
64078
64079
64080
64081 public function getAutocompleterValues()
64082 {
64083 return $this->autocompleterValues;
64084 }
64085
64086
64087
64088
64089
64090
64091
64092
64093
64094
64095
64096 public function setAutocompleterValues($values)
64097 {
64098 if (\is_array($values)) {
64099 $values = $this->isAssoc($values) ? array_merge(array_keys($values), array_values($values)) : array_values($values);
64100 }
64101
64102 if (null !== $values && !\is_array($values) && !$values instanceof \Traversable) {
64103 throw new InvalidArgumentException('Autocompleter values can be either an array, `null` or a `Traversable` object.');
64104 }
64105
64106 if ($this->hidden) {
64107 throw new LogicException('A hidden question cannot use the autocompleter.');
64108 }
64109
64110 $this->autocompleterValues = $values;
64111
64112 return $this;
64113 }
64114
64115
64116
64117
64118
64119
64120
64121
64122 public function setValidator($validator)
64123 {
64124 $this->validator = $validator;
64125
64126 return $this;
64127 }
64128
64129
64130
64131
64132
64133
64134 public function getValidator()
64135 {
64136 return $this->validator;
64137 }
64138
64139
64140
64141
64142
64143
64144
64145
64146
64147
64148
64149
64150 public function setMaxAttempts($attempts)
64151 {
64152 if (null !== $attempts && $attempts < 1) {
64153 throw new InvalidArgumentException('Maximum number of attempts must be a positive value.');
64154 }
64155
64156 $this->attempts = $attempts;
64157
64158 return $this;
64159 }
64160
64161
64162
64163
64164
64165
64166
64167
64168 public function getMaxAttempts()
64169 {
64170 return $this->attempts;
64171 }
64172
64173
64174
64175
64176
64177
64178
64179
64180
64181
64182 public function setNormalizer($normalizer)
64183 {
64184 $this->normalizer = $normalizer;
64185
64186 return $this;
64187 }
64188
64189
64190
64191
64192
64193
64194
64195
64196 public function getNormalizer()
64197 {
64198 return $this->normalizer;
64199 }
64200
64201 protected function isAssoc($array)
64202 {
64203 return (bool) \count(array_filter(array_keys($array), 'is_string'));
64204 }
64205 }
64206 <?php
64207
64208
64209
64210
64211
64212
64213
64214
64215
64216
64217 namespace Symfony\Component\Console;
64218
64219 use Symfony\Component\Console\Exception\RuntimeException;
64220 use Symfony\Component\Console\Input\StringInput;
64221 use Symfony\Component\Console\Output\ConsoleOutput;
64222 use Symfony\Component\Process\PhpExecutableFinder;
64223 use Symfony\Component\Process\ProcessBuilder;
64224
64225
64226
64227
64228
64229
64230
64231
64232
64233
64234
64235
64236 class Shell
64237 {
64238 private $application;
64239 private $history;
64240 private $output;
64241 private $hasReadline;
64242 private $processIsolation = false;
64243
64244
64245
64246
64247
64248 public function __construct(Application $application)
64249 {
64250 @trigger_error('The '.__CLASS__.' class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
64251
64252 $this->hasReadline = \function_exists('readline');
64253 $this->application = $application;
64254 $this->history = getenv('HOME').'/.history_'.$application->getName();
64255 $this->output = new ConsoleOutput();
64256 }
64257
64258
64259
64260
64261 public function run()
64262 {
64263 $this->application->setAutoExit(false);
64264 $this->application->setCatchExceptions(true);
64265
64266 if ($this->hasReadline) {
64267 readline_read_history($this->history);
64268 readline_completion_function(array($this, 'autocompleter'));
64269 }
64270
64271 $this->output->writeln($this->getHeader());
64272 $php = null;
64273 if ($this->processIsolation) {
64274 $finder = new PhpExecutableFinder();
64275 $php = $finder->find();
64276 $this->output->writeln(<<<'EOF'
64277 <info>Running with process isolation, you should consider this:</info>
64278   * each command is executed as separate process,
64279   * commands don't support interactivity, all params must be passed explicitly,
64280   * commands output is not colorized.
64281
64282 EOF
64283 );
64284 }
64285
64286 while (true) {
64287 $command = $this->readline();
64288
64289 if (false === $command) {
64290 $this->output->writeln("\n");
64291
64292 break;
64293 }
64294
64295 if ($this->hasReadline) {
64296 readline_add_history($command);
64297 readline_write_history($this->history);
64298 }
64299
64300 if ($this->processIsolation) {
64301 $pb = new ProcessBuilder();
64302
64303 $process = $pb
64304 ->add($php)
64305 ->add($_SERVER['argv'][0])
64306 ->add($command)
64307 ->inheritEnvironmentVariables(true)
64308 ->getProcess()
64309 ;
64310
64311 $output = $this->output;
64312 $process->run(function ($type, $data) use ($output) {
64313 $output->writeln($data);
64314 });
64315
64316 $ret = $process->getExitCode();
64317 } else {
64318 $ret = $this->application->run(new StringInput($command), $this->output);
64319 }
64320
64321 if (0 !== $ret) {
64322 $this->output->writeln(sprintf('<error>The command terminated with an error status (%s)</error>', $ret));
64323 }
64324 }
64325 }
64326
64327
64328
64329
64330
64331
64332 protected function getHeader()
64333 {
64334 return <<<EOF
64335
64336 Welcome to the <info>{$this->application->getName()}</info> shell (<comment>{$this->application->getVersion()}</comment>).
64337
64338 At the prompt, type <comment>help</comment> for some help,
64339 or <comment>list</comment> to get a list of available commands.
64340
64341 To exit the shell, type <comment>^D</comment>.
64342
64343 EOF;
64344 }
64345
64346
64347
64348
64349
64350
64351 protected function getPrompt()
64352 {
64353
64354 return $this->output->getFormatter()->format($this->application->getName().' > ');
64355 }
64356
64357 protected function getOutput()
64358 {
64359 return $this->output;
64360 }
64361
64362 protected function getApplication()
64363 {
64364 return $this->application;
64365 }
64366
64367
64368
64369
64370
64371
64372
64373
64374 private function autocompleter($text)
64375 {
64376 $info = readline_info();
64377 $text = substr($info['line_buffer'], 0, $info['end']);
64378
64379 if ($info['point'] !== $info['end']) {
64380 return true;
64381 }
64382
64383
64384 if (false === strpos($text, ' ') || !$text) {
64385 return array_keys($this->application->all());
64386 }
64387
64388
64389 try {
64390 $command = $this->application->find(substr($text, 0, strpos($text, ' ')));
64391 } catch (\Exception $e) {
64392 return true;
64393 }
64394
64395 $list = array('--help');
64396 foreach ($command->getDefinition()->getOptions() as $option) {
64397 $list[] = '--'.$option->getName();
64398 }
64399
64400 return $list;
64401 }
64402
64403
64404
64405
64406
64407
64408 private function readline()
64409 {
64410 if ($this->hasReadline) {
64411 $line = readline($this->getPrompt());
64412 } else {
64413 $this->output->write($this->getPrompt());
64414 $line = fgets(STDIN, 1024);
64415 $line = (false === $line || '' === $line) ? false : rtrim($line);
64416 }
64417
64418 return $line;
64419 }
64420
64421 public function getProcessIsolation()
64422 {
64423 return $this->processIsolation;
64424 }
64425
64426 public function setProcessIsolation($processIsolation)
64427 {
64428 $this->processIsolation = (bool) $processIsolation;
64429
64430 if ($this->processIsolation && !class_exists('Symfony\\Component\\Process\\Process')) {
64431 throw new RuntimeException('Unable to isolate processes as the Symfony Process Component is not installed.');
64432 }
64433 }
64434 }
64435 <?php
64436
64437
64438
64439
64440
64441
64442
64443
64444
64445
64446 namespace Symfony\Component\Console\Style;
64447
64448 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
64449 use Symfony\Component\Console\Helper\ProgressBar;
64450 use Symfony\Component\Console\Output\OutputInterface;
64451
64452
64453
64454
64455
64456
64457 abstract class OutputStyle implements OutputInterface, StyleInterface
64458 {
64459 private $output;
64460
64461 public function __construct(OutputInterface $output)
64462 {
64463 $this->output = $output;
64464 }
64465
64466
64467
64468
64469 public function newLine($count = 1)
64470 {
64471 $this->output->write(str_repeat(PHP_EOL, $count));
64472 }
64473
64474
64475
64476
64477
64478
64479 public function createProgressBar($max = 0)
64480 {
64481 return new ProgressBar($this->output, $max);
64482 }
64483
64484
64485
64486
64487 public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
64488 {
64489 $this->output->write($messages, $newline, $type);
64490 }
64491
64492
64493
64494
64495 public function writeln($messages, $type = self::OUTPUT_NORMAL)
64496 {
64497 $this->output->writeln($messages, $type);
64498 }
64499
64500
64501
64502
64503 public function setVerbosity($level)
64504 {
64505 $this->output->setVerbosity($level);
64506 }
64507
64508
64509
64510
64511 public function getVerbosity()
64512 {
64513 return $this->output->getVerbosity();
64514 }
64515
64516
64517
64518
64519 public function setDecorated($decorated)
64520 {
64521 $this->output->setDecorated($decorated);
64522 }
64523
64524
64525
64526
64527 public function isDecorated()
64528 {
64529 return $this->output->isDecorated();
64530 }
64531
64532
64533
64534
64535 public function setFormatter(OutputFormatterInterface $formatter)
64536 {
64537 $this->output->setFormatter($formatter);
64538 }
64539
64540
64541
64542
64543 public function getFormatter()
64544 {
64545 return $this->output->getFormatter();
64546 }
64547 }
64548 <?php
64549
64550
64551
64552
64553
64554
64555
64556
64557
64558
64559 namespace Symfony\Component\Console\Style;
64560
64561
64562
64563
64564
64565
64566 interface StyleInterface
64567 {
64568
64569
64570
64571
64572
64573 public function title($message);
64574
64575
64576
64577
64578
64579
64580 public function section($message);
64581
64582
64583
64584
64585 public function listing(array $elements);
64586
64587
64588
64589
64590
64591
64592 public function text($message);
64593
64594
64595
64596
64597
64598
64599 public function success($message);
64600
64601
64602
64603
64604
64605
64606 public function error($message);
64607
64608
64609
64610
64611
64612
64613 public function warning($message);
64614
64615
64616
64617
64618
64619
64620 public function note($message);
64621
64622
64623
64624
64625
64626
64627 public function caution($message);
64628
64629
64630
64631
64632 public function table(array $headers, array $rows);
64633
64634
64635
64636
64637
64638
64639
64640
64641
64642
64643 public function ask($question, $default = null, $validator = null);
64644
64645
64646
64647
64648
64649
64650
64651
64652
64653 public function askHidden($question, $validator = null);
64654
64655
64656
64657
64658
64659
64660
64661
64662
64663 public function confirm($question, $default = true);
64664
64665
64666
64667
64668
64669
64670
64671
64672
64673
64674 public function choice($question, array $choices, $default = null);
64675
64676
64677
64678
64679
64680
64681 public function newLine($count = 1);
64682
64683
64684
64685
64686
64687
64688 public function progressStart($max = 0);
64689
64690
64691
64692
64693
64694
64695 public function progressAdvance($step = 1);
64696
64697
64698
64699
64700 public function progressFinish();
64701 }
64702 <?php
64703
64704
64705
64706
64707
64708
64709
64710
64711
64712
64713 namespace Symfony\Component\Console\Style;
64714
64715 use Symfony\Component\Console\Application;
64716 use Symfony\Component\Console\Exception\RuntimeException;
64717 use Symfony\Component\Console\Formatter\OutputFormatter;
64718 use Symfony\Component\Console\Helper\Helper;
64719 use Symfony\Component\Console\Helper\ProgressBar;
64720 use Symfony\Component\Console\Helper\SymfonyQuestionHelper;
64721 use Symfony\Component\Console\Helper\Table;
64722 use Symfony\Component\Console\Input\InputInterface;
64723 use Symfony\Component\Console\Output\BufferedOutput;
64724 use Symfony\Component\Console\Output\OutputInterface;
64725 use Symfony\Component\Console\Question\ChoiceQuestion;
64726 use Symfony\Component\Console\Question\ConfirmationQuestion;
64727 use Symfony\Component\Console\Question\Question;
64728
64729
64730
64731
64732
64733
64734 class SymfonyStyle extends OutputStyle
64735 {
64736 const MAX_LINE_LENGTH = 120;
64737
64738 private $input;
64739 private $questionHelper;
64740 private $progressBar;
64741 private $lineLength;
64742 private $bufferedOutput;
64743
64744 public function __construct(InputInterface $input, OutputInterface $output)
64745 {
64746 $this->input = $input;
64747 $this->bufferedOutput = new BufferedOutput($output->getVerbosity(), false, clone $output->getFormatter());
64748
64749 $this->lineLength = min($this->getTerminalWidth() - (int) (\DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH);
64750
64751 parent::__construct($output);
64752 }
64753
64754
64755
64756
64757
64758
64759
64760
64761
64762
64763 public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false)
64764 {
64765 $messages = \is_array($messages) ? array_values($messages) : array($messages);
64766
64767 $this->autoPrependBlock();
64768 $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, true));
64769 $this->newLine();
64770 }
64771
64772
64773
64774
64775 public function title($message)
64776 {
64777 $this->autoPrependBlock();
64778 $this->writeln(array(
64779 sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),
64780 sprintf('<comment>%s</>', str_repeat('=', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
64781 ));
64782 $this->newLine();
64783 }
64784
64785
64786
64787
64788 public function section($message)
64789 {
64790 $this->autoPrependBlock();
64791 $this->writeln(array(
64792 sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),
64793 sprintf('<comment>%s</>', str_repeat('-', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
64794 ));
64795 $this->newLine();
64796 }
64797
64798
64799
64800
64801 public function listing(array $elements)
64802 {
64803 $this->autoPrependText();
64804 $elements = array_map(function ($element) {
64805 return sprintf(' * %s', $element);
64806 }, $elements);
64807
64808 $this->writeln($elements);
64809 $this->newLine();
64810 }
64811
64812
64813
64814
64815 public function text($message)
64816 {
64817 $this->autoPrependText();
64818
64819 $messages = \is_array($message) ? array_values($message) : array($message);
64820 foreach ($messages as $message) {
64821 $this->writeln(sprintf(' %s', $message));
64822 }
64823 }
64824
64825
64826
64827
64828
64829
64830 public function comment($message)
64831 {
64832 $messages = \is_array($message) ? array_values($message) : array($message);
64833
64834 $this->autoPrependBlock();
64835 $this->writeln($this->createBlock($messages, null, null, '<fg=default;bg=default> // </>'));
64836 $this->newLine();
64837 }
64838
64839
64840
64841
64842 public function success($message)
64843 {
64844 $this->block($message, 'OK', 'fg=black;bg=green', ' ', true);
64845 }
64846
64847
64848
64849
64850 public function error($message)
64851 {
64852 $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', true);
64853 }
64854
64855
64856
64857
64858 public function warning($message)
64859 {
64860 $this->block($message, 'WARNING', 'fg=white;bg=red', ' ', true);
64861 }
64862
64863
64864
64865
64866 public function note($message)
64867 {
64868 $this->block($message, 'NOTE', 'fg=yellow', ' ! ');
64869 }
64870
64871
64872
64873
64874 public function caution($message)
64875 {
64876 $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', true);
64877 }
64878
64879
64880
64881
64882 public function table(array $headers, array $rows)
64883 {
64884 $style = clone Table::getStyleDefinition('symfony-style-guide');
64885 $style->setCellHeaderFormat('<info>%s</info>');
64886
64887 $table = new Table($this);
64888 $table->setHeaders($headers);
64889 $table->setRows($rows);
64890 $table->setStyle($style);
64891
64892 $table->render();
64893 $this->newLine();
64894 }
64895
64896
64897
64898
64899 public function ask($question, $default = null, $validator = null)
64900 {
64901 $question = new Question($question, $default);
64902 $question->setValidator($validator);
64903
64904 return $this->askQuestion($question);
64905 }
64906
64907
64908
64909
64910 public function askHidden($question, $validator = null)
64911 {
64912 $question = new Question($question);
64913
64914 $question->setHidden(true);
64915 $question->setValidator($validator);
64916
64917 return $this->askQuestion($question);
64918 }
64919
64920
64921
64922
64923 public function confirm($question, $default = true)
64924 {
64925 return $this->askQuestion(new ConfirmationQuestion($question, $default));
64926 }
64927
64928
64929
64930
64931 public function choice($question, array $choices, $default = null)
64932 {
64933 if (null !== $default) {
64934 $values = array_flip($choices);
64935 $default = $values[$default];
64936 }
64937
64938 return $this->askQuestion(new ChoiceQuestion($question, $choices, $default));
64939 }
64940
64941
64942
64943
64944 public function progressStart($max = 0)
64945 {
64946 $this->progressBar = $this->createProgressBar($max);
64947 $this->progressBar->start();
64948 }
64949
64950
64951
64952
64953 public function progressAdvance($step = 1)
64954 {
64955 $this->getProgressBar()->advance($step);
64956 }
64957
64958
64959
64960
64961 public function progressFinish()
64962 {
64963 $this->getProgressBar()->finish();
64964 $this->newLine(2);
64965 $this->progressBar = null;
64966 }
64967
64968
64969
64970
64971 public function createProgressBar($max = 0)
64972 {
64973 $progressBar = parent::createProgressBar($max);
64974
64975 if ('\\' !== \DIRECTORY_SEPARATOR || 'Hyper' === getenv('TERM_PROGRAM')) {
64976 $progressBar->setEmptyBarCharacter('░'); 
64977 $progressBar->setProgressCharacter('');
64978 $progressBar->setBarCharacter('▓'); 
64979 }
64980
64981 return $progressBar;
64982 }
64983
64984
64985
64986
64987 public function askQuestion(Question $question)
64988 {
64989 if ($this->input->isInteractive()) {
64990 $this->autoPrependBlock();
64991 }
64992
64993 if (!$this->questionHelper) {
64994 $this->questionHelper = new SymfonyQuestionHelper();
64995 }
64996
64997 $answer = $this->questionHelper->ask($this->input, $this, $question);
64998
64999 if ($this->input->isInteractive()) {
65000 $this->newLine();
65001 $this->bufferedOutput->write("\n");
65002 }
65003
65004 return $answer;
65005 }
65006
65007
65008
65009
65010 public function writeln($messages, $type = self::OUTPUT_NORMAL)
65011 {
65012 parent::writeln($messages, $type);
65013 $this->bufferedOutput->writeln($this->reduceBuffer($messages), $type);
65014 }
65015
65016
65017
65018
65019 public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
65020 {
65021 parent::write($messages, $newline, $type);
65022 $this->bufferedOutput->write($this->reduceBuffer($messages), $newline, $type);
65023 }
65024
65025
65026
65027
65028 public function newLine($count = 1)
65029 {
65030 parent::newLine($count);
65031 $this->bufferedOutput->write(str_repeat("\n", $count));
65032 }
65033
65034
65035
65036
65037 private function getProgressBar()
65038 {
65039 if (!$this->progressBar) {
65040 throw new RuntimeException('The ProgressBar is not started.');
65041 }
65042
65043 return $this->progressBar;
65044 }
65045
65046 private function getTerminalWidth()
65047 {
65048 $application = new Application();
65049 $dimensions = $application->getTerminalDimensions();
65050
65051 return $dimensions[0] ?: self::MAX_LINE_LENGTH;
65052 }
65053
65054 private function autoPrependBlock()
65055 {
65056 $chars = substr(str_replace(PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2);
65057
65058 if (!isset($chars[0])) {
65059 return $this->newLine(); 
65060 }
65061
65062 $this->newLine(2 - substr_count($chars, "\n"));
65063 }
65064
65065 private function autoPrependText()
65066 {
65067 $fetched = $this->bufferedOutput->fetch();
65068
65069 if ("\n" !== substr($fetched, -1)) {
65070 $this->newLine();
65071 }
65072 }
65073
65074 private function reduceBuffer($messages)
65075 {
65076
65077
65078 return array_map(function ($value) {
65079 return substr($value, -4);
65080 }, array_merge(array($this->bufferedOutput->fetch()), (array) $messages));
65081 }
65082
65083 private function createBlock($messages, $type = null, $style = null, $prefix = ' ', $padding = false, $escape = false)
65084 {
65085 $indentLength = 0;
65086 $prefixLength = Helper::strlenWithoutDecoration($this->getFormatter(), $prefix);
65087 $lines = array();
65088
65089 if (null !== $type) {
65090 $type = sprintf('[%s] ', $type);
65091 $indentLength = \strlen($type);
65092 $lineIndentation = str_repeat(' ', $indentLength);
65093 }
65094
65095
65096 foreach ($messages as $key => $message) {
65097 if ($escape) {
65098 $message = OutputFormatter::escape($message);
65099 }
65100
65101 $lines = array_merge($lines, explode(PHP_EOL, wordwrap($message, $this->lineLength - $prefixLength - $indentLength, PHP_EOL, true)));
65102
65103 if (\count($messages) > 1 && $key < \count($messages) - 1) {
65104 $lines[] = '';
65105 }
65106 }
65107
65108 $firstLineIndex = 0;
65109 if ($padding && $this->isDecorated()) {
65110 $firstLineIndex = 1;
65111 array_unshift($lines, '');
65112 $lines[] = '';
65113 }
65114
65115 foreach ($lines as $i => &$line) {
65116 if (null !== $type) {
65117 $line = $firstLineIndex === $i ? $type.$line : $lineIndentation.$line;
65118 }
65119
65120 $line = $prefix.$line;
65121 $line .= str_repeat(' ', $this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line));
65122
65123 if ($style) {
65124 $line = sprintf('<%s>%s</>', $style, $line);
65125 }
65126 }
65127
65128 return $lines;
65129 }
65130 }
65131 <?php
65132
65133
65134
65135
65136
65137
65138
65139
65140
65141
65142 namespace Symfony\Component\Console\Tester;
65143
65144 use Symfony\Component\Console\Application;
65145 use Symfony\Component\Console\Input\ArrayInput;
65146 use Symfony\Component\Console\Input\InputInterface;
65147 use Symfony\Component\Console\Output\OutputInterface;
65148 use Symfony\Component\Console\Output\StreamOutput;
65149
65150
65151
65152
65153
65154
65155
65156
65157
65158
65159
65160 class ApplicationTester
65161 {
65162 private $application;
65163 private $input;
65164 private $output;
65165 private $statusCode;
65166
65167 public function __construct(Application $application)
65168 {
65169 $this->application = $application;
65170 }
65171
65172
65173
65174
65175
65176
65177
65178
65179
65180
65181
65182
65183
65184
65185
65186 public function run(array $input, $options = array())
65187 {
65188 $this->input = new ArrayInput($input);
65189 if (isset($options['interactive'])) {
65190 $this->input->setInteractive($options['interactive']);
65191 }
65192
65193 $this->output = new StreamOutput(fopen('php://memory', 'w', false));
65194 if (isset($options['decorated'])) {
65195 $this->output->setDecorated($options['decorated']);
65196 }
65197 if (isset($options['verbosity'])) {
65198 $this->output->setVerbosity($options['verbosity']);
65199 }
65200
65201 return $this->statusCode = $this->application->run($this->input, $this->output);
65202 }
65203
65204
65205
65206
65207
65208
65209
65210
65211 public function getDisplay($normalize = false)
65212 {
65213 rewind($this->output->getStream());
65214
65215 $display = stream_get_contents($this->output->getStream());
65216
65217 if ($normalize) {
65218 $display = str_replace(PHP_EOL, "\n", $display);
65219 }
65220
65221 return $display;
65222 }
65223
65224
65225
65226
65227
65228
65229 public function getInput()
65230 {
65231 return $this->input;
65232 }
65233
65234
65235
65236
65237
65238
65239 public function getOutput()
65240 {
65241 return $this->output;
65242 }
65243
65244
65245
65246
65247
65248
65249 public function getStatusCode()
65250 {
65251 return $this->statusCode;
65252 }
65253 }
65254 <?php
65255
65256
65257
65258
65259
65260
65261
65262
65263
65264
65265 namespace Symfony\Component\Console\Tester;
65266
65267 use Symfony\Component\Console\Command\Command;
65268 use Symfony\Component\Console\Input\ArrayInput;
65269 use Symfony\Component\Console\Input\InputInterface;
65270 use Symfony\Component\Console\Output\OutputInterface;
65271 use Symfony\Component\Console\Output\StreamOutput;
65272
65273
65274
65275
65276
65277
65278 class CommandTester
65279 {
65280 private $command;
65281 private $input;
65282 private $output;
65283 private $statusCode;
65284
65285 public function __construct(Command $command)
65286 {
65287 $this->command = $command;
65288 }
65289
65290
65291
65292
65293
65294
65295
65296
65297
65298
65299
65300
65301
65302
65303
65304 public function execute(array $input, array $options = array())
65305 {
65306
65307
65308 if (!isset($input['command'])
65309 && (null !== $application = $this->command->getApplication())
65310 && $application->getDefinition()->hasArgument('command')
65311 ) {
65312 $input = array_merge(array('command' => $this->command->getName()), $input);
65313 }
65314
65315 $this->input = new ArrayInput($input);
65316 if (isset($options['interactive'])) {
65317 $this->input->setInteractive($options['interactive']);
65318 }
65319
65320 $this->output = new StreamOutput(fopen('php://memory', 'w', false));
65321 $this->output->setDecorated(isset($options['decorated']) ? $options['decorated'] : false);
65322 if (isset($options['verbosity'])) {
65323 $this->output->setVerbosity($options['verbosity']);
65324 }
65325
65326 return $this->statusCode = $this->command->run($this->input, $this->output);
65327 }
65328
65329
65330
65331
65332
65333
65334
65335
65336 public function getDisplay($normalize = false)
65337 {
65338 rewind($this->output->getStream());
65339
65340 $display = stream_get_contents($this->output->getStream());
65341
65342 if ($normalize) {
65343 $display = str_replace(PHP_EOL, "\n", $display);
65344 }
65345
65346 return $display;
65347 }
65348
65349
65350
65351
65352
65353
65354 public function getInput()
65355 {
65356 return $this->input;
65357 }
65358
65359
65360
65361
65362
65363
65364 public function getOutput()
65365 {
65366 return $this->output;
65367 }
65368
65369
65370
65371
65372
65373
65374 public function getStatusCode()
65375 {
65376 return $this->statusCode;
65377 }
65378 }
65379 <?php
65380
65381
65382
65383
65384
65385
65386
65387
65388
65389
65390 namespace Symfony\Component\Debug;
65391
65392 use Psr\Log\AbstractLogger;
65393
65394
65395
65396
65397
65398
65399 class BufferingLogger extends AbstractLogger
65400 {
65401 private $logs = array();
65402
65403 public function log($level, $message, array $context = array())
65404 {
65405 $this->logs[] = array($level, $message, $context);
65406 }
65407
65408 public function cleanLogs()
65409 {
65410 $logs = $this->logs;
65411 $this->logs = array();
65412
65413 return $logs;
65414 }
65415 }
65416 <?php
65417
65418
65419
65420
65421
65422
65423
65424
65425
65426
65427 namespace Symfony\Component\Debug;
65428
65429
65430
65431
65432
65433
65434 class Debug
65435 {
65436 private static $enabled = false;
65437
65438
65439
65440
65441
65442
65443
65444
65445
65446 public static function enable($errorReportingLevel = null, $displayErrors = true)
65447 {
65448 if (static::$enabled) {
65449 return;
65450 }
65451
65452 static::$enabled = true;
65453
65454 if (null !== $errorReportingLevel) {
65455 error_reporting($errorReportingLevel);
65456 } else {
65457 error_reporting(-1);
65458 }
65459
65460 if (!\in_array(\PHP_SAPI, array('cli', 'phpdbg'), true)) {
65461 ini_set('display_errors', 0);
65462 ExceptionHandler::register();
65463 } elseif ($displayErrors && (!filter_var(ini_get('log_errors'), FILTER_VALIDATE_BOOLEAN) || ini_get('error_log'))) {
65464
65465 ini_set('display_errors', 1);
65466 }
65467 if ($displayErrors) {
65468 ErrorHandler::register(new ErrorHandler(new BufferingLogger()));
65469 } else {
65470 ErrorHandler::register()->throwAt(0, true);
65471 }
65472
65473 DebugClassLoader::enable();
65474 }
65475 }
65476 <?php
65477
65478
65479
65480
65481
65482
65483
65484
65485
65486
65487 namespace Symfony\Component\Debug;
65488
65489
65490
65491
65492
65493
65494
65495
65496
65497
65498
65499
65500 class DebugClassLoader
65501 {
65502 private $classLoader;
65503 private $isFinder;
65504 private $loaded = array();
65505 private $wasFinder;
65506 private static $caseCheck;
65507 private static $deprecated = array();
65508 private static $php7Reserved = array('int', 'float', 'bool', 'string', 'true', 'false', 'null');
65509 private static $darwinCache = array('/' => array('/', array()));
65510
65511
65512
65513
65514 public function __construct($classLoader)
65515 {
65516 $this->wasFinder = \is_object($classLoader) && method_exists($classLoader, 'findFile');
65517
65518 if ($this->wasFinder) {
65519 @trigger_error('The '.__METHOD__.' method will no longer support receiving an object into its $classLoader argument in 3.0.', E_USER_DEPRECATED);
65520 $this->classLoader = array($classLoader, 'loadClass');
65521 $this->isFinder = true;
65522 } else {
65523 $this->classLoader = $classLoader;
65524 $this->isFinder = \is_array($classLoader) && method_exists($classLoader[0], 'findFile');
65525 }
65526
65527 if (!isset(self::$caseCheck)) {
65528 $file = file_exists(__FILE__) ? __FILE__ : rtrim(realpath('.'), \DIRECTORY_SEPARATOR);
65529 $i = strrpos($file, \DIRECTORY_SEPARATOR);
65530 $dir = substr($file, 0, 1 + $i);
65531 $file = substr($file, 1 + $i);
65532 $test = strtoupper($file) === $file ? strtolower($file) : strtoupper($file);
65533 $test = realpath($dir.$test);
65534
65535 if (false === $test || false === $i) {
65536
65537 self::$caseCheck = 0;
65538 } elseif (substr($test, -\strlen($file)) === $file) {
65539
65540 self::$caseCheck = 1;
65541 } elseif (false !== stripos(PHP_OS, 'darwin')) {
65542
65543 self::$caseCheck = 2;
65544 } else {
65545
65546 self::$caseCheck = 0;
65547 }
65548 }
65549 }
65550
65551
65552
65553
65554
65555
65556 public function getClassLoader()
65557 {
65558 return $this->wasFinder ? $this->classLoader[0] : $this->classLoader;
65559 }
65560
65561
65562
65563
65564 public static function enable()
65565 {
65566
65567 class_exists('Symfony\Component\Debug\ErrorHandler');
65568 class_exists('Psr\Log\LogLevel');
65569
65570 if (!\is_array($functions = spl_autoload_functions())) {
65571 return;
65572 }
65573
65574 foreach ($functions as $function) {
65575 spl_autoload_unregister($function);
65576 }
65577
65578 foreach ($functions as $function) {
65579 if (!\is_array($function) || !$function[0] instanceof self) {
65580 $function = array(new static($function), 'loadClass');
65581 }
65582
65583 spl_autoload_register($function);
65584 }
65585 }
65586
65587
65588
65589
65590 public static function disable()
65591 {
65592 if (!\is_array($functions = spl_autoload_functions())) {
65593 return;
65594 }
65595
65596 foreach ($functions as $function) {
65597 spl_autoload_unregister($function);
65598 }
65599
65600 foreach ($functions as $function) {
65601 if (\is_array($function) && $function[0] instanceof self) {
65602 $function = $function[0]->getClassLoader();
65603 }
65604
65605 spl_autoload_register($function);
65606 }
65607 }
65608
65609
65610
65611
65612
65613
65614
65615
65616
65617
65618 public function findFile($class)
65619 {
65620 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.5 and will be removed in 3.0.', E_USER_DEPRECATED);
65621
65622 if ($this->wasFinder) {
65623 return $this->classLoader[0]->findFile($class);
65624 }
65625 }
65626
65627
65628
65629
65630
65631
65632
65633
65634
65635
65636 public function loadClass($class)
65637 {
65638 ErrorHandler::stackErrors();
65639
65640 try {
65641 if ($this->isFinder && !isset($this->loaded[$class])) {
65642 $this->loaded[$class] = true;
65643 if ($file = $this->classLoader[0]->findFile($class)) {
65644 require $file;
65645 }
65646 } else {
65647 \call_user_func($this->classLoader, $class);
65648 $file = false;
65649 }
65650 } catch (\Exception $e) {
65651 ErrorHandler::unstackErrors();
65652
65653 throw $e;
65654 } catch (\Throwable $e) {
65655 ErrorHandler::unstackErrors();
65656
65657 throw $e;
65658 }
65659
65660 ErrorHandler::unstackErrors();
65661
65662 $exists = class_exists($class, false) || interface_exists($class, false) || (\function_exists('trait_exists') && trait_exists($class, false));
65663
65664 if ($class && '\\' === $class[0]) {
65665 $class = substr($class, 1);
65666 }
65667
65668 if ($exists) {
65669 $refl = new \ReflectionClass($class);
65670 $name = $refl->getName();
65671
65672 if ($name !== $class && 0 === strcasecmp($name, $class)) {
65673 throw new \RuntimeException(sprintf('Case mismatch between loaded and declared class names: %s vs %s', $class, $name));
65674 }
65675
65676 if (\in_array(strtolower($refl->getShortName()), self::$php7Reserved)) {
65677 @trigger_error(sprintf('%s uses a reserved class name (%s) that will break on PHP 7 and higher', $name, $refl->getShortName()), E_USER_DEPRECATED);
65678 } elseif (preg_match('#\n \* @deprecated (.*?)\r?\n \*(?: @|/$)#s', $refl->getDocComment(), $notice)) {
65679 self::$deprecated[$name] = preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]);
65680 } else {
65681 if (2 > $len = 1 + (strpos($name, '\\') ?: strpos($name, '_'))) {
65682 $len = 0;
65683 $ns = '';
65684 } else {
65685 $ns = substr($name, 0, $len);
65686 }
65687 $parent = get_parent_class($class);
65688
65689 if (!$parent || strncmp($ns, $parent, $len)) {
65690 if ($parent && isset(self::$deprecated[$parent]) && strncmp($ns, $parent, $len)) {
65691 @trigger_error(sprintf('The %s class extends %s that is deprecated %s', $name, $parent, self::$deprecated[$parent]), E_USER_DEPRECATED);
65692 }
65693
65694 $parentInterfaces = array();
65695 $deprecatedInterfaces = array();
65696 if ($parent) {
65697 foreach (class_implements($parent) as $interface) {
65698 $parentInterfaces[$interface] = 1;
65699 }
65700 }
65701
65702 foreach ($refl->getInterfaceNames() as $interface) {
65703 if (isset(self::$deprecated[$interface]) && strncmp($ns, $interface, $len)) {
65704 $deprecatedInterfaces[] = $interface;
65705 }
65706 foreach (class_implements($interface) as $interface) {
65707 $parentInterfaces[$interface] = 1;
65708 }
65709 }
65710
65711 foreach ($deprecatedInterfaces as $interface) {
65712 if (!isset($parentInterfaces[$interface])) {
65713 @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);
65714 }
65715 }
65716 }
65717 }
65718 }
65719
65720 if ($file) {
65721 if (!$exists) {
65722 if (false !== strpos($class, '/')) {
65723 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));
65724 }
65725
65726 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));
65727 }
65728 if (self::$caseCheck) {
65729 $real = explode('\\', $class.strrchr($file, '.'));
65730 $tail = explode(\DIRECTORY_SEPARATOR, str_replace('/', \DIRECTORY_SEPARATOR, $file));
65731
65732 $i = \count($tail) - 1;
65733 $j = \count($real) - 1;
65734
65735 while (isset($tail[$i], $real[$j]) && $tail[$i] === $real[$j]) {
65736 --$i;
65737 --$j;
65738 }
65739
65740 array_splice($tail, 0, $i + 1);
65741 }
65742 if (self::$caseCheck && $tail) {
65743 $tail = \DIRECTORY_SEPARATOR.implode(\DIRECTORY_SEPARATOR, $tail);
65744 $tailLen = \strlen($tail);
65745 $real = $refl->getFileName();
65746
65747 if (2 === self::$caseCheck) {
65748
65749
65750 $i = 1 + strrpos($real, '/');
65751 $file = substr($real, $i);
65752 $real = substr($real, 0, $i);
65753
65754 if (isset(self::$darwinCache[$real])) {
65755 $kDir = $real;
65756 } else {
65757 $kDir = strtolower($real);
65758
65759 if (isset(self::$darwinCache[$kDir])) {
65760 $real = self::$darwinCache[$kDir][0];
65761 } else {
65762 $dir = getcwd();
65763 chdir($real);
65764 $real = getcwd().'/';
65765 chdir($dir);
65766
65767 $dir = $real;
65768 $k = $kDir;
65769 $i = \strlen($dir) - 1;
65770 while (!isset(self::$darwinCache[$k])) {
65771 self::$darwinCache[$k] = array($dir, array());
65772 self::$darwinCache[$dir] = &self::$darwinCache[$k];
65773
65774 while ('/' !== $dir[--$i]) {
65775 }
65776 $k = substr($k, 0, ++$i);
65777 $dir = substr($dir, 0, $i--);
65778 }
65779 }
65780 }
65781
65782 $dirFiles = self::$darwinCache[$kDir][1];
65783
65784 if (isset($dirFiles[$file])) {
65785 $kFile = $file;
65786 } else {
65787 $kFile = strtolower($file);
65788
65789 if (!isset($dirFiles[$kFile])) {
65790 foreach (scandir($real, 2) as $f) {
65791 if ('.' !== $f[0]) {
65792 $dirFiles[$f] = $f;
65793 if ($f === $file) {
65794 $kFile = $k = $file;
65795 } elseif ($f !== $k = strtolower($f)) {
65796 $dirFiles[$k] = $f;
65797 }
65798 }
65799 }
65800 self::$darwinCache[$kDir][1] = $dirFiles;
65801 }
65802 }
65803
65804 $real .= $dirFiles[$kFile];
65805 }
65806
65807 if (0 === substr_compare($real, $tail, -$tailLen, $tailLen, true)
65808 && 0 !== substr_compare($real, $tail, -$tailLen, $tailLen, false)
65809 ) {
65810 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)));
65811 }
65812 }
65813
65814 return true;
65815 }
65816 }
65817 }
65818 <?php
65819
65820
65821
65822
65823
65824
65825
65826
65827
65828
65829 namespace Symfony\Component\Debug;
65830
65831 use Psr\Log\LoggerInterface;
65832 use Psr\Log\LogLevel;
65833 use Symfony\Component\Debug\Exception\ContextErrorException;
65834 use Symfony\Component\Debug\Exception\FatalErrorException;
65835 use Symfony\Component\Debug\Exception\FatalThrowableError;
65836 use Symfony\Component\Debug\Exception\OutOfMemoryException;
65837 use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler;
65838 use Symfony\Component\Debug\FatalErrorHandler\FatalErrorHandlerInterface;
65839 use Symfony\Component\Debug\FatalErrorHandler\UndefinedFunctionFatalErrorHandler;
65840 use Symfony\Component\Debug\FatalErrorHandler\UndefinedMethodFatalErrorHandler;
65841
65842
65843
65844
65845
65846
65847
65848
65849
65850
65851
65852
65853
65854
65855
65856
65857
65858
65859
65860
65861
65862
65863
65864 class ErrorHandler
65865 {
65866
65867
65868
65869 const TYPE_DEPRECATION = -100;
65870
65871 private $levels = array(
65872 E_DEPRECATED => 'Deprecated',
65873 E_USER_DEPRECATED => 'User Deprecated',
65874 E_NOTICE => 'Notice',
65875 E_USER_NOTICE => 'User Notice',
65876 E_STRICT => 'Runtime Notice',
65877 E_WARNING => 'Warning',
65878 E_USER_WARNING => 'User Warning',
65879 E_COMPILE_WARNING => 'Compile Warning',
65880 E_CORE_WARNING => 'Core Warning',
65881 E_USER_ERROR => 'User Error',
65882 E_RECOVERABLE_ERROR => 'Catchable Fatal Error',
65883 E_COMPILE_ERROR => 'Compile Error',
65884 E_PARSE => 'Parse Error',
65885 E_ERROR => 'Error',
65886 E_CORE_ERROR => 'Core Error',
65887 );
65888
65889 private $loggers = array(
65890 E_DEPRECATED => array(null, LogLevel::INFO),
65891 E_USER_DEPRECATED => array(null, LogLevel::INFO),
65892 E_NOTICE => array(null, LogLevel::WARNING),
65893 E_USER_NOTICE => array(null, LogLevel::WARNING),
65894 E_STRICT => array(null, LogLevel::WARNING),
65895 E_WARNING => array(null, LogLevel::WARNING),
65896 E_USER_WARNING => array(null, LogLevel::WARNING),
65897 E_COMPILE_WARNING => array(null, LogLevel::WARNING),
65898 E_CORE_WARNING => array(null, LogLevel::WARNING),
65899 E_USER_ERROR => array(null, LogLevel::CRITICAL),
65900 E_RECOVERABLE_ERROR => array(null, LogLevel::CRITICAL),
65901 E_COMPILE_ERROR => array(null, LogLevel::CRITICAL),
65902 E_PARSE => array(null, LogLevel::CRITICAL),
65903 E_ERROR => array(null, LogLevel::CRITICAL),
65904 E_CORE_ERROR => array(null, LogLevel::CRITICAL),
65905 );
65906
65907 private $thrownErrors = 0x1FFF; 
65908 private $scopedErrors = 0x1FFF; 
65909 private $tracedErrors = 0x77FB; 
65910 private $screamedErrors = 0x55; 
65911 private $loggedErrors = 0;
65912
65913 private $loggedTraces = array();
65914 private $isRecursive = 0;
65915 private $isRoot = false;
65916 private $exceptionHandler;
65917 private $bootstrappingLogger;
65918
65919 private static $reservedMemory;
65920 private static $stackedErrors = array();
65921 private static $stackedErrorLevels = array();
65922 private static $toStringException = null;
65923 private static $exitCode = 0;
65924
65925
65926
65927
65928
65929
65930 private $displayErrors = 0x1FFF;
65931
65932
65933
65934
65935
65936
65937
65938
65939
65940 public static function register($handler = null, $replace = true)
65941 {
65942 if (null === self::$reservedMemory) {
65943 self::$reservedMemory = str_repeat('x', 10240);
65944 register_shutdown_function(__CLASS__.'::handleFatalError');
65945 }
65946
65947 $levels = -1;
65948
65949 if ($handlerIsNew = !$handler instanceof self) {
65950
65951 if (null !== $handler) {
65952 $levels = $replace ? $handler : 0;
65953 $replace = true;
65954 }
65955 $handler = new static();
65956 }
65957
65958 if (null === $prev = set_error_handler(array($handler, 'handleError'))) {
65959 restore_error_handler();
65960
65961 set_error_handler(array($handler, 'handleError'), $handler->thrownErrors | $handler->loggedErrors);
65962 $handler->isRoot = true;
65963 }
65964
65965 if ($handlerIsNew && \is_array($prev) && $prev[0] instanceof self) {
65966 $handler = $prev[0];
65967 $replace = false;
65968 }
65969 if (!$replace && $prev) {
65970 restore_error_handler();
65971 $handlerIsRegistered = \is_array($prev) && $handler === $prev[0];
65972 } else {
65973 $handlerIsRegistered = true;
65974 }
65975 if (\is_array($prev = set_exception_handler(array($handler, 'handleException'))) && $prev[0] instanceof self) {
65976 restore_exception_handler();
65977 if (!$handlerIsRegistered) {
65978 $handler = $prev[0];
65979 } elseif ($handler !== $prev[0] && $replace) {
65980 set_exception_handler(array($handler, 'handleException'));
65981 $p = $prev[0]->setExceptionHandler(null);
65982 $handler->setExceptionHandler($p);
65983 $prev[0]->setExceptionHandler($p);
65984 }
65985 } else {
65986 $handler->setExceptionHandler($prev);
65987 }
65988
65989 $handler->throwAt($levels & $handler->thrownErrors, true);
65990
65991 return $handler;
65992 }
65993
65994 public function __construct(BufferingLogger $bootstrappingLogger = null)
65995 {
65996 if ($bootstrappingLogger) {
65997 $this->bootstrappingLogger = $bootstrappingLogger;
65998 $this->setDefaultLogger($bootstrappingLogger);
65999 }
66000 }
66001
66002
66003
66004
66005
66006
66007
66008
66009 public function setDefaultLogger(LoggerInterface $logger, $levels = null, $replace = false)
66010 {
66011 $loggers = array();
66012
66013 if (\is_array($levels)) {
66014 foreach ($levels as $type => $logLevel) {
66015 if (empty($this->loggers[$type][0]) || $replace || $this->loggers[$type][0] === $this->bootstrappingLogger) {
66016 $loggers[$type] = array($logger, $logLevel);
66017 }
66018 }
66019 } else {
66020 if (null === $levels) {
66021 $levels = E_ALL | E_STRICT;
66022 }
66023 foreach ($this->loggers as $type => $log) {
66024 if (($type & $levels) && (empty($log[0]) || $replace || $log[0] === $this->bootstrappingLogger)) {
66025 $log[0] = $logger;
66026 $loggers[$type] = $log;
66027 }
66028 }
66029 }
66030
66031 $this->setLoggers($loggers);
66032 }
66033
66034
66035
66036
66037
66038
66039
66040
66041
66042
66043 public function setLoggers(array $loggers)
66044 {
66045 $prevLogged = $this->loggedErrors;
66046 $prev = $this->loggers;
66047 $flush = array();
66048
66049 foreach ($loggers as $type => $log) {
66050 if (!isset($prev[$type])) {
66051 throw new \InvalidArgumentException('Unknown error type: '.$type);
66052 }
66053 if (!\is_array($log)) {
66054 $log = array($log);
66055 } elseif (!array_key_exists(0, $log)) {
66056 throw new \InvalidArgumentException('No logger provided');
66057 }
66058 if (null === $log[0]) {
66059 $this->loggedErrors &= ~$type;
66060 } elseif ($log[0] instanceof LoggerInterface) {
66061 $this->loggedErrors |= $type;
66062 } else {
66063 throw new \InvalidArgumentException('Invalid logger provided');
66064 }
66065 $this->loggers[$type] = $log + $prev[$type];
66066
66067 if ($this->bootstrappingLogger && $prev[$type][0] === $this->bootstrappingLogger) {
66068 $flush[$type] = $type;
66069 }
66070 }
66071 $this->reRegister($prevLogged | $this->thrownErrors);
66072
66073 if ($flush) {
66074 foreach ($this->bootstrappingLogger->cleanLogs() as $log) {
66075 $type = $log[2]['type'];
66076 if (!isset($flush[$type])) {
66077 $this->bootstrappingLogger->log($log[0], $log[1], $log[2]);
66078 } elseif ($this->loggers[$type][0]) {
66079 $this->loggers[$type][0]->log($this->loggers[$type][1], $log[1], $log[2]);
66080 }
66081 }
66082 }
66083
66084 return $prev;
66085 }
66086
66087
66088
66089
66090
66091
66092
66093
66094
66095
66096 public function setExceptionHandler($handler)
66097 {
66098 if (null !== $handler && !\is_callable($handler)) {
66099 throw new \LogicException('The exception handler must be a valid PHP callable.');
66100 }
66101 $prev = $this->exceptionHandler;
66102 $this->exceptionHandler = $handler;
66103
66104 return $prev;
66105 }
66106
66107
66108
66109
66110
66111
66112
66113
66114
66115 public function throwAt($levels, $replace = false)
66116 {
66117 $prev = $this->thrownErrors;
66118 $this->thrownErrors = ($levels | E_RECOVERABLE_ERROR | E_USER_ERROR) & ~E_USER_DEPRECATED & ~E_DEPRECATED;
66119 if (!$replace) {
66120 $this->thrownErrors |= $prev;
66121 }
66122 $this->reRegister($prev | $this->loggedErrors);
66123
66124
66125 $this->displayErrors = $this->thrownErrors;
66126
66127 return $prev;
66128 }
66129
66130
66131
66132
66133
66134
66135
66136
66137
66138 public function scopeAt($levels, $replace = false)
66139 {
66140 $prev = $this->scopedErrors;
66141 $this->scopedErrors = (int) $levels;
66142 if (!$replace) {
66143 $this->scopedErrors |= $prev;
66144 }
66145
66146 return $prev;
66147 }
66148
66149
66150
66151
66152
66153
66154
66155
66156
66157 public function traceAt($levels, $replace = false)
66158 {
66159 $prev = $this->tracedErrors;
66160 $this->tracedErrors = (int) $levels;
66161 if (!$replace) {
66162 $this->tracedErrors |= $prev;
66163 }
66164
66165 return $prev;
66166 }
66167
66168
66169
66170
66171
66172
66173
66174
66175
66176 public function screamAt($levels, $replace = false)
66177 {
66178 $prev = $this->screamedErrors;
66179 $this->screamedErrors = (int) $levels;
66180 if (!$replace) {
66181 $this->screamedErrors |= $prev;
66182 }
66183
66184 return $prev;
66185 }
66186
66187
66188
66189
66190 private function reRegister($prev)
66191 {
66192 if ($prev !== $this->thrownErrors | $this->loggedErrors) {
66193 $handler = set_error_handler('var_dump');
66194 $handler = \is_array($handler) ? $handler[0] : null;
66195 restore_error_handler();
66196 if ($handler === $this) {
66197 restore_error_handler();
66198 if ($this->isRoot) {
66199 set_error_handler(array($this, 'handleError'), $this->thrownErrors | $this->loggedErrors);
66200 } else {
66201 set_error_handler(array($this, 'handleError'));
66202 }
66203 }
66204 }
66205 }
66206
66207
66208
66209
66210
66211
66212
66213
66214
66215
66216
66217
66218
66219
66220
66221 public function handleError($type, $message, $file, $line)
66222 {
66223 $level = error_reporting();
66224 $silenced = 0 === ($level & $type);
66225 $level |= E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED;
66226 $log = $this->loggedErrors & $type;
66227 $throw = $this->thrownErrors & $type & $level;
66228 $type &= $level | $this->screamedErrors;
66229
66230 if (!$type || (!$log && !$throw)) {
66231 return !$silenced && $type && $log;
66232 }
66233 $scope = $this->scopedErrors & $type;
66234
66235 if (4 < $numArgs = \func_num_args()) {
66236 $context = $scope ? (func_get_arg(4) ?: array()) : array();
66237 $backtrace = 5 < $numArgs ? func_get_arg(5) : null; 
66238 } else {
66239 $context = array();
66240 $backtrace = null;
66241 }
66242
66243 if (isset($context['GLOBALS']) && $scope) {
66244 $e = $context; 
66245 unset($e['GLOBALS'], $context); 
66246 $context = $e;
66247 }
66248
66249 if (null !== $backtrace && $type & E_ERROR) {
66250
66251
66252
66253 $this->handleFatalError(compact('type', 'message', 'file', 'line', 'backtrace'));
66254
66255 return true;
66256 }
66257
66258 if ($throw) {
66259 if (null !== self::$toStringException) {
66260 $throw = self::$toStringException;
66261 self::$toStringException = null;
66262 } elseif ($scope && class_exists('Symfony\Component\Debug\Exception\ContextErrorException')) {
66263
66264 $throw = new ContextErrorException($this->levels[$type].': '.$message, 0, $type, $file, $line, $context);
66265 } else {
66266 $throw = new \ErrorException($this->levels[$type].': '.$message, 0, $type, $file, $line);
66267 }
66268
66269 if (\PHP_VERSION_ID <= 50407 && (\PHP_VERSION_ID >= 50400 || \PHP_VERSION_ID <= 50317)) {
66270
66271
66272
66273
66274 $throw->errorHandlerCanary = new ErrorHandlerCanary();
66275 }
66276
66277 if (E_USER_ERROR & $type) {
66278 $backtrace = $backtrace ?: $throw->getTrace();
66279
66280 for ($i = 1; isset($backtrace[$i]); ++$i) {
66281 if (isset($backtrace[$i]['function'], $backtrace[$i]['type'], $backtrace[$i - 1]['function'])
66282 && '__toString' === $backtrace[$i]['function']
66283 && '->' === $backtrace[$i]['type']
66284 && !isset($backtrace[$i - 1]['class'])
66285 && ('trigger_error' === $backtrace[$i - 1]['function'] || 'user_error' === $backtrace[$i - 1]['function'])
66286 ) {
66287
66288
66289
66290
66291
66292
66293
66294 foreach ($context as $e) {
66295 if (($e instanceof \Exception || $e instanceof \Throwable) && $e->__toString() === $message) {
66296 if (1 === $i) {
66297
66298 $throw = $e;
66299 break;
66300 }
66301 self::$toStringException = $e;
66302
66303 return true;
66304 }
66305 }
66306
66307 if (1 < $i) {
66308
66309 $this->handleException($throw);
66310
66311
66312 return false;
66313 }
66314 }
66315 }
66316 }
66317
66318 throw $throw;
66319 }
66320
66321
66322 $e = md5("{$type}/{$line}/{$file}\x00{$message}", true);
66323 $trace = true;
66324
66325 if (!($this->tracedErrors & $type) || isset($this->loggedTraces[$e])) {
66326 $trace = false;
66327 } else {
66328 $this->loggedTraces[$e] = 1;
66329 }
66330
66331 $e = compact('type', 'file', 'line', 'level');
66332
66333 if ($type & $level) {
66334 if ($scope) {
66335 $e['scope_vars'] = $context;
66336 if ($trace) {
66337 $e['stack'] = $backtrace ?: debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT);
66338 }
66339 } elseif ($trace) {
66340 if (null === $backtrace) {
66341 $e['stack'] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
66342 } else {
66343 foreach ($backtrace as &$frame) {
66344 unset($frame['args'], $frame);
66345 }
66346 $e['stack'] = $backtrace;
66347 }
66348 }
66349 }
66350
66351 if ($this->isRecursive) {
66352 $log = 0;
66353 } elseif (self::$stackedErrorLevels) {
66354 self::$stackedErrors[] = array($this->loggers[$type][0], ($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG, $message, $e);
66355 } else {
66356 try {
66357 $this->isRecursive = true;
66358 $this->loggers[$type][0]->log(($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG, $message, $e);
66359 $this->isRecursive = false;
66360 } catch (\Exception $e) {
66361 $this->isRecursive = false;
66362
66363 throw $e;
66364 } catch (\Throwable $e) {
66365 $this->isRecursive = false;
66366
66367 throw $e;
66368 }
66369 }
66370
66371 return !$silenced && $type && $log;
66372 }
66373
66374
66375
66376
66377
66378
66379
66380
66381
66382 public function handleException($exception, array $error = null)
66383 {
66384 if (null === $error) {
66385 self::$exitCode = 255;
66386 }
66387 if (!$exception instanceof \Exception) {
66388 $exception = new FatalThrowableError($exception);
66389 }
66390 $type = $exception instanceof FatalErrorException ? $exception->getSeverity() : E_ERROR;
66391 $handlerException = null;
66392
66393 if (($this->loggedErrors & $type) || $exception instanceof FatalThrowableError) {
66394 $e = array(
66395 'type' => $type,
66396 'file' => $exception->getFile(),
66397 'line' => $exception->getLine(),
66398 'level' => error_reporting(),
66399 'stack' => $exception->getTrace(),
66400 );
66401 if ($exception instanceof FatalErrorException) {
66402 if ($exception instanceof FatalThrowableError) {
66403 $error = array(
66404 'type' => $type,
66405 'message' => $message = $exception->getMessage(),
66406 'file' => $e['file'],
66407 'line' => $e['line'],
66408 );
66409 } else {
66410 $message = 'Fatal '.$exception->getMessage();
66411 }
66412 } elseif ($exception instanceof \ErrorException) {
66413 $message = 'Uncaught '.$exception->getMessage();
66414 if ($exception instanceof ContextErrorException) {
66415 $e['context'] = $exception->getContext();
66416 }
66417 } else {
66418 $message = 'Uncaught Exception: '.$exception->getMessage();
66419 }
66420 }
66421 if ($this->loggedErrors & $type) {
66422 try {
66423 $this->loggers[$type][0]->log($this->loggers[$type][1], $message, $e);
66424 } catch (\Exception $handlerException) {
66425 } catch (\Throwable $handlerException) {
66426 }
66427 }
66428 if ($exception instanceof FatalErrorException && !$exception instanceof OutOfMemoryException && $error) {
66429 foreach ($this->getFatalErrorHandlers() as $handler) {
66430 if ($e = $handler->handleError($error, $exception)) {
66431 $exception = $e;
66432 break;
66433 }
66434 }
66435 }
66436 $exceptionHandler = $this->exceptionHandler;
66437 $this->exceptionHandler = null;
66438 try {
66439 if (null !== $exceptionHandler) {
66440 return \call_user_func($exceptionHandler, $exception);
66441 }
66442 $handlerException = $handlerException ?: $exception;
66443 } catch (\Exception $handlerException) {
66444 } catch (\Throwable $handlerException) {
66445 }
66446 if ($exception === $handlerException) {
66447 self::$reservedMemory = null; 
66448 throw $exception; 
66449 }
66450 $this->handleException($handlerException);
66451 }
66452
66453
66454
66455
66456
66457
66458
66459
66460 public static function handleFatalError(array $error = null)
66461 {
66462 if (null === self::$reservedMemory) {
66463 return;
66464 }
66465
66466 $handler = self::$reservedMemory = null;
66467 $handlers = array();
66468 $previousHandler = null;
66469 $sameHandlerLimit = 10;
66470
66471 while (!\is_array($handler) || !$handler[0] instanceof self) {
66472 $handler = set_exception_handler('var_dump');
66473 restore_exception_handler();
66474
66475 if (!$handler) {
66476 break;
66477 }
66478 restore_exception_handler();
66479
66480 if ($handler !== $previousHandler) {
66481 array_unshift($handlers, $handler);
66482 $previousHandler = $handler;
66483 } elseif (0 === --$sameHandlerLimit) {
66484 $handler = null;
66485 break;
66486 }
66487 }
66488 foreach ($handlers as $h) {
66489 set_exception_handler($h);
66490 }
66491 if (!$handler) {
66492 return;
66493 }
66494 if ($handler !== $h) {
66495 $handler[0]->setExceptionHandler($h);
66496 }
66497 $handler = $handler[0];
66498 $handlers = array();
66499
66500 if ($exit = null === $error) {
66501 $error = error_get_last();
66502 }
66503
66504 try {
66505 while (self::$stackedErrorLevels) {
66506 static::unstackErrors();
66507 }
66508 } catch (\Exception $exception) {
66509
66510 } catch (\Throwable $exception) {
66511
66512 }
66513
66514 if ($error && $error['type'] &= E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR) {
66515
66516 $handler->throwAt(0, true);
66517 $trace = isset($error['backtrace']) ? $error['backtrace'] : null;
66518
66519 if (0 === strpos($error['message'], 'Allowed memory') || 0 === strpos($error['message'], 'Out of memory')) {
66520 $exception = new OutOfMemoryException($handler->levels[$error['type']].': '.$error['message'], 0, $error['type'], $error['file'], $error['line'], 2, false, $trace);
66521 } else {
66522 $exception = new FatalErrorException($handler->levels[$error['type']].': '.$error['message'], 0, $error['type'], $error['file'], $error['line'], 2, true, $trace);
66523 }
66524 }
66525
66526 try {
66527 if (isset($exception)) {
66528 self::$exitCode = 255;
66529 $handler->handleException($exception, $error);
66530 }
66531 } catch (FatalErrorException $e) {
66532
66533 }
66534
66535 if ($exit && self::$exitCode) {
66536 $exitCode = self::$exitCode;
66537 register_shutdown_function('register_shutdown_function', function () use ($exitCode) { exit($exitCode); });
66538 }
66539 }
66540
66541
66542
66543
66544
66545
66546
66547
66548
66549
66550
66551
66552 public static function stackErrors()
66553 {
66554 self::$stackedErrorLevels[] = error_reporting(error_reporting() | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR);
66555 }
66556
66557
66558
66559
66560 public static function unstackErrors()
66561 {
66562 $level = array_pop(self::$stackedErrorLevels);
66563
66564 if (null !== $level) {
66565 $e = error_reporting($level);
66566 if ($e !== ($level | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)) {
66567
66568 error_reporting($e);
66569 }
66570 }
66571
66572 if (empty(self::$stackedErrorLevels)) {
66573 $errors = self::$stackedErrors;
66574 self::$stackedErrors = array();
66575
66576 foreach ($errors as $e) {
66577 $e[0]->log($e[1], $e[2], $e[3]);
66578 }
66579 }
66580 }
66581
66582
66583
66584
66585
66586
66587
66588
66589 protected function getFatalErrorHandlers()
66590 {
66591 return array(
66592 new UndefinedFunctionFatalErrorHandler(),
66593 new UndefinedMethodFatalErrorHandler(),
66594 new ClassNotFoundFatalErrorHandler(),
66595 );
66596 }
66597
66598
66599
66600
66601
66602
66603
66604
66605 public function setLevel($level)
66606 {
66607 @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);
66608
66609 $level = null === $level ? error_reporting() : $level;
66610 $this->throwAt($level, true);
66611 }
66612
66613
66614
66615
66616
66617
66618
66619
66620 public function setDisplayErrors($displayErrors)
66621 {
66622 @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);
66623
66624 if ($displayErrors) {
66625 $this->throwAt($this->displayErrors, true);
66626 } else {
66627 $displayErrors = $this->displayErrors;
66628 $this->throwAt(0, true);
66629 $this->displayErrors = $displayErrors;
66630 }
66631 }
66632
66633
66634
66635
66636
66637
66638
66639
66640
66641 public static function setLogger(LoggerInterface $logger, $channel = 'deprecation')
66642 {
66643 @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);
66644
66645 $handler = set_error_handler('var_dump');
66646 $handler = \is_array($handler) ? $handler[0] : null;
66647 restore_error_handler();
66648 if (!$handler instanceof self) {
66649 return;
66650 }
66651 if ('deprecation' === $channel) {
66652 $handler->setDefaultLogger($logger, E_DEPRECATED | E_USER_DEPRECATED, true);
66653 $handler->screamAt(E_DEPRECATED | E_USER_DEPRECATED);
66654 } elseif ('scream' === $channel) {
66655 $handler->setDefaultLogger($logger, E_ALL | E_STRICT, false);
66656 $handler->screamAt(E_ALL | E_STRICT);
66657 } elseif ('emergency' === $channel) {
66658 $handler->setDefaultLogger($logger, E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR, true);
66659 $handler->screamAt(E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR);
66660 }
66661 }
66662
66663
66664
66665
66666 public function handle($level, $message, $file = 'unknown', $line = 0, $context = array())
66667 {
66668 $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());
66669
66670 return $this->handleError($level, $message, $file, $line, (array) $context);
66671 }
66672
66673
66674
66675
66676
66677
66678 public function handleFatal()
66679 {
66680 @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);
66681
66682 static::handleFatalError();
66683 }
66684 }
66685
66686
66687
66688
66689
66690
66691
66692
66693 class ErrorHandlerCanary
66694 {
66695 private static $displayErrors = null;
66696
66697 public function __construct()
66698 {
66699 if (null === self::$displayErrors) {
66700 self::$displayErrors = ini_set('display_errors', 1);
66701 }
66702 }
66703
66704 public function __destruct()
66705 {
66706 if (null !== self::$displayErrors) {
66707 ini_set('display_errors', self::$displayErrors);
66708 self::$displayErrors = null;
66709 }
66710 }
66711 }
66712 <?php
66713
66714
66715
66716
66717
66718
66719
66720
66721
66722
66723 namespace Symfony\Component\Debug\Exception;
66724
66725
66726
66727
66728
66729
66730 class ClassNotFoundException extends FatalErrorException
66731 {
66732 public function __construct($message, \ErrorException $previous)
66733 {
66734 parent::__construct(
66735 $message,
66736 $previous->getCode(),
66737 $previous->getSeverity(),
66738 $previous->getFile(),
66739 $previous->getLine(),
66740 null,
66741 true,
66742 null,
66743 $previous->getPrevious()
66744 );
66745 $this->setTrace($previous->getTrace());
66746 }
66747 }
66748 <?php
66749
66750
66751
66752
66753
66754
66755
66756
66757
66758
66759 namespace Symfony\Component\Debug\Exception;
66760
66761
66762
66763
66764
66765
66766 class ContextErrorException extends \ErrorException
66767 {
66768 private $context = array();
66769
66770 public function __construct($message, $code, $severity, $filename, $lineno, $context = array())
66771 {
66772 parent::__construct($message, $code, $severity, $filename, $lineno);
66773 $this->context = $context;
66774 }
66775
66776
66777
66778
66779 public function getContext()
66780 {
66781 return $this->context;
66782 }
66783 }
66784 <?php
66785
66786
66787
66788
66789
66790
66791
66792
66793
66794
66795 namespace Symfony\Component\Debug\Exception;
66796
66797 @trigger_error('The '.__NAMESPACE__.'\DummyException class is deprecated since Symfony 2.5 and will be removed in 3.0.', E_USER_DEPRECATED);
66798
66799
66800
66801
66802
66803
66804 class DummyException extends \ErrorException
66805 {
66806 }
66807 <?php
66808
66809
66810
66811
66812
66813
66814
66815
66816
66817
66818 namespace Symfony\Component\HttpKernel\Exception;
66819
66820
66821
66822
66823
66824
66825
66826
66827
66828
66829 class FatalErrorException extends \ErrorException
66830 {
66831 }
66832
66833 namespace Symfony\Component\Debug\Exception;
66834
66835 use Symfony\Component\HttpKernel\Exception\FatalErrorException as LegacyFatalErrorException;
66836
66837
66838
66839
66840
66841
66842 class FatalErrorException extends LegacyFatalErrorException
66843 {
66844 public function __construct($message, $code, $severity, $filename, $lineno, $traceOffset = null, $traceArgs = true, array $trace = null, $previous = null)
66845 {
66846 parent::__construct($message, $code, $severity, $filename, $lineno, $previous);
66847
66848 if (null !== $trace) {
66849 if (!$traceArgs) {
66850 foreach ($trace as &$frame) {
66851 unset($frame['args'], $frame['this'], $frame);
66852 }
66853 }
66854
66855 $this->setTrace($trace);
66856 } elseif (null !== $traceOffset) {
66857 if (\function_exists('xdebug_get_function_stack')) {
66858 $trace = xdebug_get_function_stack();
66859 if (0 < $traceOffset) {
66860 array_splice($trace, -$traceOffset);
66861 }
66862
66863 foreach ($trace as &$frame) {
66864 if (!isset($frame['type'])) {
66865
66866 if (isset($frame['class'])) {
66867 $frame['type'] = '::';
66868 }
66869 } elseif ('dynamic' === $frame['type']) {
66870 $frame['type'] = '->';
66871 } elseif ('static' === $frame['type']) {
66872 $frame['type'] = '::';
66873 }
66874
66875
66876 if (!$traceArgs) {
66877 unset($frame['params'], $frame['args']);
66878 } elseif (isset($frame['params']) && !isset($frame['args'])) {
66879 $frame['args'] = $frame['params'];
66880 unset($frame['params']);
66881 }
66882 }
66883
66884 unset($frame);
66885 $trace = array_reverse($trace);
66886 } elseif (\function_exists('symfony_debug_backtrace')) {
66887 $trace = symfony_debug_backtrace();
66888 if (0 < $traceOffset) {
66889 array_splice($trace, 0, $traceOffset);
66890 }
66891 } else {
66892 $trace = array();
66893 }
66894
66895 $this->setTrace($trace);
66896 }
66897 }
66898
66899 protected function setTrace($trace)
66900 {
66901 $traceReflector = new \ReflectionProperty('Exception', 'trace');
66902 $traceReflector->setAccessible(true);
66903 $traceReflector->setValue($this, $trace);
66904 }
66905 }
66906 <?php
66907
66908
66909
66910
66911
66912
66913
66914
66915
66916
66917 namespace Symfony\Component\Debug\Exception;
66918
66919
66920
66921
66922
66923
66924 class FatalThrowableError extends FatalErrorException
66925 {
66926 public function __construct(\Throwable $e)
66927 {
66928 if ($e instanceof \ParseError) {
66929 $message = 'Parse error: '.$e->getMessage();
66930 $severity = E_PARSE;
66931 } elseif ($e instanceof \TypeError) {
66932 $message = 'Type error: '.$e->getMessage();
66933 $severity = E_RECOVERABLE_ERROR;
66934 } else {
66935 $message = $e->getMessage();
66936 $severity = E_ERROR;
66937 }
66938
66939 \ErrorException::__construct(
66940 $message,
66941 $e->getCode(),
66942 $severity,
66943 $e->getFile(),
66944 $e->getLine(),
66945 $e->getPrevious()
66946 );
66947
66948 $this->setTrace($e->getTrace());
66949 }
66950 }
66951 <?php
66952
66953
66954
66955
66956
66957
66958
66959
66960
66961
66962 namespace Symfony\Component\HttpKernel\Exception;
66963
66964 use Symfony\Component\Debug\Exception\FlattenException as DebugFlattenException;
66965
66966
66967
66968
66969
66970
66971
66972
66973
66974
66975 class FlattenException
66976 {
66977 private $handler;
66978
66979 public static function __callStatic($method, $args)
66980 {
66981 if (!method_exists('Symfony\Component\Debug\Exception\FlattenException', $method)) {
66982 throw new \BadMethodCallException(sprintf('Call to undefined method %s::%s()', \get_called_class(), $method));
66983 }
66984
66985 return \call_user_func_array(array('Symfony\Component\Debug\Exception\FlattenException', $method), $args);
66986 }
66987
66988 public function __call($method, $args)
66989 {
66990 if (!isset($this->handler)) {
66991 $this->handler = new DebugFlattenException();
66992 }
66993
66994 if (!method_exists($this->handler, $method)) {
66995 throw new \BadMethodCallException(sprintf('Call to undefined method %s::%s()', \get_class($this), $method));
66996 }
66997
66998 return \call_user_func_array(array($this->handler, $method), $args);
66999 }
67000 }
67001
67002 namespace Symfony\Component\Debug\Exception;
67003
67004 use Symfony\Component\HttpKernel\Exception\FlattenException as LegacyFlattenException;
67005 use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
67006
67007
67008
67009
67010
67011
67012
67013
67014 class FlattenException extends LegacyFlattenException
67015 {
67016 private $message;
67017 private $code;
67018 private $previous;
67019 private $trace;
67020 private $class;
67021 private $statusCode;
67022 private $headers;
67023 private $file;
67024 private $line;
67025
67026 public static function create(\Exception $exception, $statusCode = null, array $headers = array())
67027 {
67028 $e = new static();
67029 $e->setMessage($exception->getMessage());
67030 $e->setCode($exception->getCode());
67031
67032 if ($exception instanceof HttpExceptionInterface) {
67033 $statusCode = $exception->getStatusCode();
67034 $headers = array_merge($headers, $exception->getHeaders());
67035 }
67036
67037 if (null === $statusCode) {
67038 $statusCode = 500;
67039 }
67040
67041 $e->setStatusCode($statusCode);
67042 $e->setHeaders($headers);
67043 $e->setTraceFromException($exception);
67044 $e->setClass(\get_class($exception));
67045 $e->setFile($exception->getFile());
67046 $e->setLine($exception->getLine());
67047
67048 $previous = $exception->getPrevious();
67049
67050 if ($previous instanceof \Exception) {
67051 $e->setPrevious(static::create($previous));
67052 } elseif ($previous instanceof \Throwable) {
67053 $e->setPrevious(static::create(new FatalThrowableError($previous)));
67054 }
67055
67056 return $e;
67057 }
67058
67059 public function toArray()
67060 {
67061 $exceptions = array();
67062 foreach (array_merge(array($this), $this->getAllPrevious()) as $exception) {
67063 $exceptions[] = array(
67064 'message' => $exception->getMessage(),
67065 'class' => $exception->getClass(),
67066 'trace' => $exception->getTrace(),
67067 );
67068 }
67069
67070 return $exceptions;
67071 }
67072
67073 public function getStatusCode()
67074 {
67075 return $this->statusCode;
67076 }
67077
67078 public function setStatusCode($code)
67079 {
67080 $this->statusCode = $code;
67081 }
67082
67083 public function getHeaders()
67084 {
67085 return $this->headers;
67086 }
67087
67088 public function setHeaders(array $headers)
67089 {
67090 $this->headers = $headers;
67091 }
67092
67093 public function getClass()
67094 {
67095 return $this->class;
67096 }
67097
67098 public function setClass($class)
67099 {
67100 $this->class = $class;
67101 }
67102
67103 public function getFile()
67104 {
67105 return $this->file;
67106 }
67107
67108 public function setFile($file)
67109 {
67110 $this->file = $file;
67111 }
67112
67113 public function getLine()
67114 {
67115 return $this->line;
67116 }
67117
67118 public function setLine($line)
67119 {
67120 $this->line = $line;
67121 }
67122
67123 public function getMessage()
67124 {
67125 return $this->message;
67126 }
67127
67128 public function setMessage($message)
67129 {
67130 $this->message = $message;
67131 }
67132
67133 public function getCode()
67134 {
67135 return $this->code;
67136 }
67137
67138 public function setCode($code)
67139 {
67140 $this->code = $code;
67141 }
67142
67143 public function getPrevious()
67144 {
67145 return $this->previous;
67146 }
67147
67148 public function setPrevious(FlattenException $previous)
67149 {
67150 $this->previous = $previous;
67151 }
67152
67153 public function getAllPrevious()
67154 {
67155 $exceptions = array();
67156 $e = $this;
67157 while ($e = $e->getPrevious()) {
67158 $exceptions[] = $e;
67159 }
67160
67161 return $exceptions;
67162 }
67163
67164 public function getTrace()
67165 {
67166 return $this->trace;
67167 }
67168
67169 public function setTraceFromException(\Exception $exception)
67170 {
67171 $this->setTrace($exception->getTrace(), $exception->getFile(), $exception->getLine());
67172 }
67173
67174 public function setTrace($trace, $file, $line)
67175 {
67176 $this->trace = array();
67177 $this->trace[] = array(
67178 'namespace' => '',
67179 'short_class' => '',
67180 'class' => '',
67181 'type' => '',
67182 'function' => '',
67183 'file' => $file,
67184 'line' => $line,
67185 'args' => array(),
67186 );
67187 foreach ($trace as $entry) {
67188 $class = '';
67189 $namespace = '';
67190 if (isset($entry['class'])) {
67191 $parts = explode('\\', $entry['class']);
67192 $class = array_pop($parts);
67193 $namespace = implode('\\', $parts);
67194 }
67195
67196 $this->trace[] = array(
67197 'namespace' => $namespace,
67198 'short_class' => $class,
67199 'class' => isset($entry['class']) ? $entry['class'] : '',
67200 'type' => isset($entry['type']) ? $entry['type'] : '',
67201 'function' => isset($entry['function']) ? $entry['function'] : null,
67202 'file' => isset($entry['file']) ? $entry['file'] : null,
67203 'line' => isset($entry['line']) ? $entry['line'] : null,
67204 'args' => isset($entry['args']) ? $this->flattenArgs($entry['args']) : array(),
67205 );
67206 }
67207 }
67208
67209 private function flattenArgs($args, $level = 0, &$count = 0)
67210 {
67211 $result = array();
67212 foreach ($args as $key => $value) {
67213 if (++$count > 1e4) {
67214 return array('array', '*SKIPPED over 10000 entries*');
67215 }
67216 if ($value instanceof \__PHP_Incomplete_Class) {
67217
67218 $result[$key] = array('incomplete-object', $this->getClassNameFromIncomplete($value));
67219 } elseif (\is_object($value)) {
67220 $result[$key] = array('object', \get_class($value));
67221 } elseif (\is_array($value)) {
67222 if ($level > 10) {
67223 $result[$key] = array('array', '*DEEP NESTED ARRAY*');
67224 } else {
67225 $result[$key] = array('array', $this->flattenArgs($value, $level + 1, $count));
67226 }
67227 } elseif (null === $value) {
67228 $result[$key] = array('null', null);
67229 } elseif (\is_bool($value)) {
67230 $result[$key] = array('boolean', $value);
67231 } elseif (\is_resource($value)) {
67232 $result[$key] = array('resource', get_resource_type($value));
67233 } else {
67234 $result[$key] = array('string', (string) $value);
67235 }
67236 }
67237
67238 return $result;
67239 }
67240
67241 private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value)
67242 {
67243 $array = new \ArrayObject($value);
67244
67245 return $array['__PHP_Incomplete_Class_Name'];
67246 }
67247 }
67248 <?php
67249
67250
67251
67252
67253
67254
67255
67256
67257
67258
67259 namespace Symfony\Component\Debug\Exception;
67260
67261
67262
67263
67264
67265
67266 class OutOfMemoryException extends FatalErrorException
67267 {
67268 }
67269 <?php
67270
67271
67272
67273
67274
67275
67276
67277
67278
67279
67280 namespace Symfony\Component\Debug\Exception;
67281
67282
67283
67284
67285
67286
67287 class UndefinedFunctionException extends FatalErrorException
67288 {
67289 public function __construct($message, \ErrorException $previous)
67290 {
67291 parent::__construct(
67292 $message,
67293 $previous->getCode(),
67294 $previous->getSeverity(),
67295 $previous->getFile(),
67296 $previous->getLine(),
67297 null,
67298 true,
67299 null,
67300 $previous->getPrevious()
67301 );
67302 $this->setTrace($previous->getTrace());
67303 }
67304 }
67305 <?php
67306
67307
67308
67309
67310
67311
67312
67313
67314
67315
67316 namespace Symfony\Component\Debug\Exception;
67317
67318
67319
67320
67321
67322
67323 class UndefinedMethodException extends FatalErrorException
67324 {
67325 public function __construct($message, \ErrorException $previous)
67326 {
67327 parent::__construct(
67328 $message,
67329 $previous->getCode(),
67330 $previous->getSeverity(),
67331 $previous->getFile(),
67332 $previous->getLine(),
67333 null,
67334 true,
67335 null,
67336 $previous->getPrevious()
67337 );
67338 $this->setTrace($previous->getTrace());
67339 }
67340 }
67341 <?php
67342
67343
67344
67345
67346
67347
67348
67349
67350
67351
67352 namespace Symfony\Component\Debug;
67353
67354 use Symfony\Component\Debug\Exception\FlattenException;
67355 use Symfony\Component\Debug\Exception\OutOfMemoryException;
67356 use Symfony\Component\HttpFoundation\Response;
67357
67358
67359
67360
67361
67362
67363
67364
67365
67366
67367
67368
67369
67370 class ExceptionHandler
67371 {
67372 private $debug;
67373 private $charset;
67374 private $handler;
67375 private $caughtBuffer;
67376 private $caughtLength;
67377 private $fileLinkFormat;
67378
67379 public function __construct($debug = true, $charset = null, $fileLinkFormat = null)
67380 {
67381 if (false !== strpos($charset, '%')) {
67382 @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);
67383
67384
67385 $pivot = $fileLinkFormat;
67386 $fileLinkFormat = $charset;
67387 $charset = $pivot;
67388 }
67389 $this->debug = $debug;
67390 $this->charset = $charset ?: ini_get('default_charset') ?: 'UTF-8';
67391 $this->fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
67392 }
67393
67394
67395
67396
67397
67398
67399
67400
67401
67402
67403 public static function register($debug = true, $charset = null, $fileLinkFormat = null)
67404 {
67405 $handler = new static($debug, $charset, $fileLinkFormat);
67406
67407 $prev = set_exception_handler(array($handler, 'handle'));
67408 if (\is_array($prev) && $prev[0] instanceof ErrorHandler) {
67409 restore_exception_handler();
67410 $prev[0]->setExceptionHandler(array($handler, 'handle'));
67411 }
67412
67413 return $handler;
67414 }
67415
67416
67417
67418
67419
67420
67421
67422
67423 public function setHandler($handler)
67424 {
67425 if (null !== $handler && !\is_callable($handler)) {
67426 throw new \LogicException('The exception handler must be a valid PHP callable.');
67427 }
67428 $old = $this->handler;
67429 $this->handler = $handler;
67430
67431 return $old;
67432 }
67433
67434
67435
67436
67437
67438
67439
67440
67441 public function setFileLinkFormat($format)
67442 {
67443 $old = $this->fileLinkFormat;
67444 $this->fileLinkFormat = $format;
67445
67446 return $old;
67447 }
67448
67449
67450
67451
67452
67453
67454
67455
67456
67457 public function handle(\Exception $exception)
67458 {
67459 if (null === $this->handler || $exception instanceof OutOfMemoryException) {
67460 $this->failSafeHandle($exception);
67461
67462 return;
67463 }
67464
67465 $caughtLength = $this->caughtLength = 0;
67466
67467 ob_start(array($this, 'catchOutput'));
67468 $this->failSafeHandle($exception);
67469 while (null === $this->caughtBuffer && ob_end_flush()) {
67470
67471 }
67472 if (isset($this->caughtBuffer[0])) {
67473 ob_start(array($this, 'cleanOutput'));
67474 echo $this->caughtBuffer;
67475 $caughtLength = ob_get_length();
67476 }
67477 $this->caughtBuffer = null;
67478
67479 try {
67480 \call_user_func($this->handler, $exception);
67481 $this->caughtLength = $caughtLength;
67482 } catch (\Exception $e) {
67483 if (!$caughtLength) {
67484
67485 throw $exception;
67486 }
67487 }
67488 }
67489
67490
67491
67492
67493
67494
67495
67496
67497 private function failSafeHandle(\Exception $exception)
67498 {
67499 if (class_exists('Symfony\Component\HttpFoundation\Response', false)
67500 && __CLASS__ !== \get_class($this)
67501 && ($reflector = new \ReflectionMethod($this, 'createResponse'))
67502 && __CLASS__ !== $reflector->class
67503 ) {
67504 $response = $this->createResponse($exception);
67505 $response->sendHeaders();
67506 $response->sendContent();
67507 @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);
67508
67509 return;
67510 }
67511
67512 $this->sendPhpResponse($exception);
67513 }
67514
67515
67516
67517
67518
67519
67520
67521
67522
67523 public function sendPhpResponse($exception)
67524 {
67525 if (!$exception instanceof FlattenException) {
67526 $exception = FlattenException::create($exception);
67527 }
67528
67529 if (!headers_sent()) {
67530 header(sprintf('HTTP/1.0 %s', $exception->getStatusCode()));
67531 foreach ($exception->getHeaders() as $name => $value) {
67532 header($name.': '.$value, false);
67533 }
67534 header('Content-Type: text/html; charset='.$this->charset);
67535 }
67536
67537 echo $this->decorate($this->getContent($exception), $this->getStylesheet($exception));
67538 }
67539
67540
67541
67542
67543
67544
67545
67546
67547
67548
67549 public function createResponse($exception)
67550 {
67551 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
67552
67553 if (!$exception instanceof FlattenException) {
67554 $exception = FlattenException::create($exception);
67555 }
67556
67557 return Response::create($this->getHtml($exception), $exception->getStatusCode(), $exception->getHeaders())->setCharset($this->charset);
67558 }
67559
67560
67561
67562
67563
67564
67565
67566
67567 public function getHtml($exception)
67568 {
67569 if (!$exception instanceof FlattenException) {
67570 $exception = FlattenException::create($exception);
67571 }
67572
67573 return $this->decorate($this->getContent($exception), $this->getStylesheet($exception));
67574 }
67575
67576
67577
67578
67579
67580
67581 public function getContent(FlattenException $exception)
67582 {
67583 switch ($exception->getStatusCode()) {
67584 case 404:
67585 $title = 'Sorry, the page you are looking for could not be found.';
67586 break;
67587 default:
67588 $title = 'Whoops, looks like something went wrong.';
67589 }
67590
67591 $content = '';
67592 if ($this->debug) {
67593 try {
67594 $count = \count($exception->getAllPrevious());
67595 $total = $count + 1;
67596 foreach ($exception->toArray() as $position => $e) {
67597 $ind = $count - $position + 1;
67598 $class = $this->formatClass($e['class']);
67599 $message = nl2br($this->escapeHtml($e['message']));
67600 $content .= sprintf(<<<'EOF'
67601                         <h2 class="block_exception clear_fix">
67602                             <span class="exception_counter">%d/%d</span>
67603                             <span class="exception_title">%s%s:</span>
67604                             <span class="exception_message">%s</span>
67605                         </h2>
67606                         <div class="block">
67607                             <ol class="traces list_exception">
67608
67609 EOF
67610 , $ind, $total, $class, $this->formatPath($e['trace'][0]['file'], $e['trace'][0]['line']), $message);
67611 foreach ($e['trace'] as $trace) {
67612 $content .= '       <li>';
67613 if ($trace['function']) {
67614 $content .= sprintf('at %s%s%s(%s)', $this->formatClass($trace['class']), $trace['type'], $trace['function'], $this->formatArgs($trace['args']));
67615 }
67616 if (isset($trace['file']) && isset($trace['line'])) {
67617 $content .= $this->formatPath($trace['file'], $trace['line']);
67618 }
67619 $content .= "</li>\n";
67620 }
67621
67622 $content .= "    </ol>\n</div>\n";
67623 }
67624 } catch (\Exception $e) {
67625
67626 if ($this->debug) {
67627 $title = sprintf('Exception thrown when handling an exception (%s: %s)', \get_class($e), $this->escapeHtml($e->getMessage()));
67628 } else {
67629 $title = 'Whoops, looks like something went wrong.';
67630 }
67631 }
67632 }
67633
67634 return <<<EOF
67635             <div id="sf-resetcontent" class="sf-reset">
67636                 <h1>$title</h1>
67637                 $content
67638             </div>
67639 EOF;
67640 }
67641
67642
67643
67644
67645
67646
67647 public function getStylesheet(FlattenException $exception)
67648 {
67649 return <<<'EOF'
67650             .sf-reset { font: 11px Verdana, Arial, sans-serif; color: #333 }
67651             .sf-reset .clear { clear:both; height:0; font-size:0; line-height:0; }
67652             .sf-reset .clear_fix:after { display:block; height:0; clear:both; visibility:hidden; }
67653             .sf-reset .clear_fix { display:inline-block; }
67654             .sf-reset * html .clear_fix { height:1%; }
67655             .sf-reset .clear_fix { display:block; }
67656             .sf-reset, .sf-reset .block { margin: auto }
67657             .sf-reset abbr { border-bottom: 1px dotted #000; cursor: help; }
67658             .sf-reset p { font-size:14px; line-height:20px; color:#868686; padding-bottom:20px }
67659             .sf-reset strong { font-weight:bold; }
67660             .sf-reset a { color:#6c6159; cursor: default; }
67661             .sf-reset a img { border:none; }
67662             .sf-reset a:hover { text-decoration:underline; }
67663             .sf-reset em { font-style:italic; }
67664             .sf-reset h1, .sf-reset h2 { font: 20px Georgia, "Times New Roman", Times, serif }
67665             .sf-reset .exception_counter { background-color: #fff; color: #333; padding: 6px; float: left; margin-right: 10px; float: left; display: block; }
67666             .sf-reset .exception_title { margin-left: 3em; margin-bottom: 0.7em; display: block; }
67667             .sf-reset .exception_message { margin-left: 3em; display: block; }
67668             .sf-reset .traces li { font-size:12px; padding: 2px 4px; list-style-type:decimal; margin-left:20px; }
67669             .sf-reset .block { background-color:#FFFFFF; padding:10px 28px; margin-bottom:20px;
67670                 -webkit-border-bottom-right-radius: 16px;
67671                 -webkit-border-bottom-left-radius: 16px;
67672                 -moz-border-radius-bottomright: 16px;
67673                 -moz-border-radius-bottomleft: 16px;
67674                 border-bottom-right-radius: 16px;
67675                 border-bottom-left-radius: 16px;
67676                 border-bottom:1px solid #ccc;
67677                 border-right:1px solid #ccc;
67678                 border-left:1px solid #ccc;
67679                 word-wrap: break-word;
67680             }
67681             .sf-reset .block_exception { background-color:#ddd; color: #333; padding:20px;
67682                 -webkit-border-top-left-radius: 16px;
67683                 -webkit-border-top-right-radius: 16px;
67684                 -moz-border-radius-topleft: 16px;
67685                 -moz-border-radius-topright: 16px;
67686                 border-top-left-radius: 16px;
67687                 border-top-right-radius: 16px;
67688                 border-top:1px solid #ccc;
67689                 border-right:1px solid #ccc;
67690                 border-left:1px solid #ccc;
67691                 overflow: hidden;
67692                 word-wrap: break-word;
67693             }
67694             .sf-reset a { background:none; color:#868686; text-decoration:none; }
67695             .sf-reset a:hover { background:none; color:#313131; text-decoration:underline; }
67696             .sf-reset ol { padding: 10px 0; }
67697             .sf-reset h1 { background-color:#FFFFFF; padding: 15px 28px; margin-bottom: 20px;
67698                 -webkit-border-radius: 10px;
67699                 -moz-border-radius: 10px;
67700                 border-radius: 10px;
67701                 border: 1px solid #ccc;
67702             }
67703 EOF;
67704 }
67705
67706 private function decorate($content, $css)
67707 {
67708 return <<<EOF
67709 <!DOCTYPE html>
67710 <html>
67711     <head>
67712         <meta charset="{$this->charset}" />
67713         <meta name="robots" content="noindex,nofollow" />
67714         <style>
67715             /* Copyright (c) 2010, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.com/yui/license.html */
67716             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;}
67717
67718             html { background: #eee; padding: 10px }
67719             img { border: 0; }
67720             #sf-resetcontent { width:970px; margin:0 auto; }
67721             $css
67722         </style>
67723     </head>
67724     <body>
67725         $content
67726     </body>
67727 </html>
67728 EOF;
67729 }
67730
67731 private function formatClass($class)
67732 {
67733 $parts = explode('\\', $class);
67734
67735 return sprintf('<abbr title="%s">%s</abbr>', $class, array_pop($parts));
67736 }
67737
67738 private function formatPath($path, $line)
67739 {
67740 $path = $this->escapeHtml($path);
67741 $file = preg_match('#[^/\\\\]*$#', $path, $file) ? $file[0] : $path;
67742
67743 if ($linkFormat = $this->fileLinkFormat) {
67744 $link = strtr($this->escapeHtml($linkFormat), array('%f' => $path, '%l' => (int) $line));
67745
67746 return sprintf(' in <a href="%s" title="Go to source">%s line %d</a>', $link, $file, $line);
67747 }
67748
67749 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);
67750 }
67751
67752
67753
67754
67755
67756
67757
67758
67759 private function formatArgs(array $args)
67760 {
67761 $result = array();
67762 foreach ($args as $key => $item) {
67763 if ('object' === $item[0]) {
67764 $formattedValue = sprintf('<em>object</em>(%s)', $this->formatClass($item[1]));
67765 } elseif ('array' === $item[0]) {
67766 $formattedValue = sprintf('<em>array</em>(%s)', \is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]);
67767 } elseif ('string' === $item[0]) {
67768 $formattedValue = sprintf("'%s'", $this->escapeHtml($item[1]));
67769 } elseif ('null' === $item[0]) {
67770 $formattedValue = '<em>null</em>';
67771 } elseif ('boolean' === $item[0]) {
67772 $formattedValue = '<em>'.strtolower(var_export($item[1], true)).'</em>';
67773 } elseif ('resource' === $item[0]) {
67774 $formattedValue = '<em>resource</em>';
67775 } else {
67776 $formattedValue = str_replace("\n", '', var_export($this->escapeHtml((string) $item[1]), true));
67777 }
67778
67779 $result[] = \is_int($key) ? $formattedValue : sprintf("'%s' => %s", $this->escapeHtml($key), $formattedValue);
67780 }
67781
67782 return implode(', ', $result);
67783 }
67784
67785
67786
67787
67788
67789
67790 protected static function utf8Htmlize($str)
67791 {
67792 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.7 and will be removed in 3.0.', E_USER_DEPRECATED);
67793
67794 return htmlspecialchars($str, ENT_QUOTES | (\PHP_VERSION_ID >= 50400 ? ENT_SUBSTITUTE : 0), 'UTF-8');
67795 }
67796
67797
67798
67799
67800 private function escapeHtml($str)
67801 {
67802 return htmlspecialchars($str, ENT_QUOTES | (\PHP_VERSION_ID >= 50400 ? ENT_SUBSTITUTE : 0), $this->charset);
67803 }
67804
67805
67806
67807
67808 public function catchOutput($buffer)
67809 {
67810 $this->caughtBuffer = $buffer;
67811
67812 return '';
67813 }
67814
67815
67816
67817
67818 public function cleanOutput($buffer)
67819 {
67820 if ($this->caughtLength) {
67821
67822 $cleanBuffer = substr_replace($buffer, '', 0, $this->caughtLength);
67823 if (isset($cleanBuffer[0])) {
67824 $buffer = $cleanBuffer;
67825 }
67826 }
67827
67828 return $buffer;
67829 }
67830 }
67831 <?php
67832
67833
67834
67835
67836
67837
67838
67839
67840
67841
67842 namespace Symfony\Component\Debug\FatalErrorHandler;
67843
67844 use Composer\Autoload\ClassLoader as ComposerClassLoader;
67845 use Symfony\Component\ClassLoader\ClassLoader as SymfonyClassLoader;
67846 use Symfony\Component\ClassLoader\UniversalClassLoader as SymfonyUniversalClassLoader;
67847 use Symfony\Component\Debug\DebugClassLoader;
67848 use Symfony\Component\Debug\Exception\ClassNotFoundException;
67849 use Symfony\Component\Debug\Exception\FatalErrorException;
67850
67851
67852
67853
67854
67855
67856 class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
67857 {
67858
67859
67860
67861 public function handleError(array $error, FatalErrorException $exception)
67862 {
67863 $messageLen = \strlen($error['message']);
67864 $notFoundSuffix = '\' not found';
67865 $notFoundSuffixLen = \strlen($notFoundSuffix);
67866 if ($notFoundSuffixLen > $messageLen) {
67867 return;
67868 }
67869
67870 if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
67871 return;
67872 }
67873
67874 foreach (array('class', 'interface', 'trait') as $typeName) {
67875 $prefix = ucfirst($typeName).' \'';
67876 $prefixLen = \strlen($prefix);
67877 if (0 !== strpos($error['message'], $prefix)) {
67878 continue;
67879 }
67880
67881 $fullyQualifiedClassName = substr($error['message'], $prefixLen, -$notFoundSuffixLen);
67882 if (false !== $namespaceSeparatorIndex = strrpos($fullyQualifiedClassName, '\\')) {
67883 $className = substr($fullyQualifiedClassName, $namespaceSeparatorIndex + 1);
67884 $namespacePrefix = substr($fullyQualifiedClassName, 0, $namespaceSeparatorIndex);
67885 $message = sprintf('Attempted to load %s "%s" from namespace "%s".', $typeName, $className, $namespacePrefix);
67886 $tail = ' for another namespace?';
67887 } else {
67888 $className = $fullyQualifiedClassName;
67889 $message = sprintf('Attempted to load %s "%s" from the global namespace.', $typeName, $className);
67890 $tail = '?';
67891 }
67892
67893 if ($candidates = $this->getClassCandidates($className)) {
67894 $tail = array_pop($candidates).'"?';
67895 if ($candidates) {
67896 $tail = ' for e.g. "'.implode('", "', $candidates).'" or "'.$tail;
67897 } else {
67898 $tail = ' for "'.$tail;
67899 }
67900 }
67901 $message .= "\nDid you forget a \"use\" statement".$tail;
67902
67903 return new ClassNotFoundException($message, $exception);
67904 }
67905 }
67906
67907
67908
67909
67910
67911
67912
67913
67914
67915
67916
67917 private function getClassCandidates($class)
67918 {
67919 if (!\is_array($functions = spl_autoload_functions())) {
67920 return array();
67921 }
67922
67923
67924 $classes = array();
67925
67926 foreach ($functions as $function) {
67927 if (!\is_array($function)) {
67928 continue;
67929 }
67930
67931 if ($function[0] instanceof DebugClassLoader) {
67932 $function = $function[0]->getClassLoader();
67933
67934
67935 if (\is_object($function)) {
67936 $function = array($function);
67937 }
67938
67939 if (!\is_array($function)) {
67940 continue;
67941 }
67942 }
67943
67944 if ($function[0] instanceof ComposerClassLoader || $function[0] instanceof SymfonyClassLoader || $function[0] instanceof SymfonyUniversalClassLoader) {
67945 foreach ($function[0]->getPrefixes() as $prefix => $paths) {
67946 foreach ($paths as $path) {
67947 $classes = array_merge($classes, $this->findClassInPath($path, $class, $prefix));
67948 }
67949 }
67950 }
67951 if ($function[0] instanceof ComposerClassLoader) {
67952 foreach ($function[0]->getPrefixesPsr4() as $prefix => $paths) {
67953 foreach ($paths as $path) {
67954 $classes = array_merge($classes, $this->findClassInPath($path, $class, $prefix));
67955 }
67956 }
67957 }
67958 }
67959
67960 return array_unique($classes);
67961 }
67962
67963
67964
67965
67966
67967
67968
67969
67970 private function findClassInPath($path, $class, $prefix)
67971 {
67972 if (!$path = realpath($path.'/'.strtr($prefix, '\\_', '//')) ?: realpath($path.'/'.\dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path)) {
67973 return array();
67974 }
67975
67976 $classes = array();
67977 $filename = $class.'.php';
67978 foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
67979 if ($filename == $file->getFileName() && $class = $this->convertFileToClass($path, $file->getPathName(), $prefix)) {
67980 $classes[] = $class;
67981 }
67982 }
67983
67984 return $classes;
67985 }
67986
67987
67988
67989
67990
67991
67992
67993
67994 private function convertFileToClass($path, $file, $prefix)
67995 {
67996 $candidates = array(
67997
67998 $namespacedClass = str_replace(array($path.\DIRECTORY_SEPARATOR, '.php', '/'), array('', '', '\\'), $file),
67999
68000 $prefix.$namespacedClass,
68001
68002 $prefix.'\\'.$namespacedClass,
68003
68004 str_replace('\\', '_', $namespacedClass),
68005
68006 str_replace('\\', '_', $prefix.$namespacedClass),
68007
68008 str_replace('\\', '_', $prefix.'\\'.$namespacedClass),
68009 );
68010
68011 if ($prefix) {
68012 $candidates = array_filter($candidates, function ($candidate) use ($prefix) { return 0 === strpos($candidate, $prefix); });
68013 }
68014
68015
68016
68017
68018 foreach ($candidates as $candidate) {
68019 if ($this->classExists($candidate)) {
68020 return $candidate;
68021 }
68022 }
68023
68024 require_once $file;
68025
68026 foreach ($candidates as $candidate) {
68027 if ($this->classExists($candidate)) {
68028 return $candidate;
68029 }
68030 }
68031 }
68032
68033
68034
68035
68036
68037
68038 private function classExists($class)
68039 {
68040 return class_exists($class, false) || interface_exists($class, false) || (\function_exists('trait_exists') && trait_exists($class, false));
68041 }
68042 }
68043 <?php
68044
68045
68046
68047
68048
68049
68050
68051
68052
68053
68054 namespace Symfony\Component\Debug\FatalErrorHandler;
68055
68056 use Symfony\Component\Debug\Exception\FatalErrorException;
68057
68058
68059
68060
68061
68062
68063 interface FatalErrorHandlerInterface
68064 {
68065
68066
68067
68068
68069
68070
68071
68072
68073 public function handleError(array $error, FatalErrorException $exception);
68074 }
68075 <?php
68076
68077
68078
68079
68080
68081
68082
68083
68084
68085
68086 namespace Symfony\Component\Debug\FatalErrorHandler;
68087
68088 use Symfony\Component\Debug\Exception\FatalErrorException;
68089 use Symfony\Component\Debug\Exception\UndefinedFunctionException;
68090
68091
68092
68093
68094
68095
68096 class UndefinedFunctionFatalErrorHandler implements FatalErrorHandlerInterface
68097 {
68098
68099
68100
68101 public function handleError(array $error, FatalErrorException $exception)
68102 {
68103 $messageLen = \strlen($error['message']);
68104 $notFoundSuffix = '()';
68105 $notFoundSuffixLen = \strlen($notFoundSuffix);
68106 if ($notFoundSuffixLen > $messageLen) {
68107 return;
68108 }
68109
68110 if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
68111 return;
68112 }
68113
68114 $prefix = 'Call to undefined function ';
68115 $prefixLen = \strlen($prefix);
68116 if (0 !== strpos($error['message'], $prefix)) {
68117 return;
68118 }
68119
68120 $fullyQualifiedFunctionName = substr($error['message'], $prefixLen, -$notFoundSuffixLen);
68121 if (false !== $namespaceSeparatorIndex = strrpos($fullyQualifiedFunctionName, '\\')) {
68122 $functionName = substr($fullyQualifiedFunctionName, $namespaceSeparatorIndex + 1);
68123 $namespacePrefix = substr($fullyQualifiedFunctionName, 0, $namespaceSeparatorIndex);
68124 $message = sprintf('Attempted to call function "%s" from namespace "%s".', $functionName, $namespacePrefix);
68125 } else {
68126 $functionName = $fullyQualifiedFunctionName;
68127 $message = sprintf('Attempted to call function "%s" from the global namespace.', $functionName);
68128 }
68129
68130 $candidates = array();
68131 foreach (get_defined_functions() as $type => $definedFunctionNames) {
68132 foreach ($definedFunctionNames as $definedFunctionName) {
68133 if (false !== $namespaceSeparatorIndex = strrpos($definedFunctionName, '\\')) {
68134 $definedFunctionNameBasename = substr($definedFunctionName, $namespaceSeparatorIndex + 1);
68135 } else {
68136 $definedFunctionNameBasename = $definedFunctionName;
68137 }
68138
68139 if ($definedFunctionNameBasename === $functionName) {
68140 $candidates[] = '\\'.$definedFunctionName;
68141 }
68142 }
68143 }
68144
68145 if ($candidates) {
68146 sort($candidates);
68147 $last = array_pop($candidates).'"?';
68148 if ($candidates) {
68149 $candidates = 'e.g. "'.implode('", "', $candidates).'" or "'.$last;
68150 } else {
68151 $candidates = '"'.$last;
68152 }
68153 $message .= "\nDid you mean to call ".$candidates;
68154 }
68155
68156 return new UndefinedFunctionException($message, $exception);
68157 }
68158 }
68159 <?php
68160
68161
68162
68163
68164
68165
68166
68167
68168
68169
68170 namespace Symfony\Component\Debug\FatalErrorHandler;
68171
68172 use Symfony\Component\Debug\Exception\FatalErrorException;
68173 use Symfony\Component\Debug\Exception\UndefinedMethodException;
68174
68175
68176
68177
68178
68179
68180 class UndefinedMethodFatalErrorHandler implements FatalErrorHandlerInterface
68181 {
68182
68183
68184
68185 public function handleError(array $error, FatalErrorException $exception)
68186 {
68187 preg_match('/^Call to undefined method (.*)::(.*)\(\)$/', $error['message'], $matches);
68188 if (!$matches) {
68189 return;
68190 }
68191
68192 $className = $matches[1];
68193 $methodName = $matches[2];
68194
68195 $message = sprintf('Attempted to call an undefined method named "%s" of class "%s".', $methodName, $className);
68196
68197 if (!class_exists($className) || null === $methods = get_class_methods($className)) {
68198
68199 return new UndefinedMethodException($message, $exception);
68200 }
68201
68202 $candidates = array();
68203 foreach ($methods as $definedMethodName) {
68204 $lev = levenshtein($methodName, $definedMethodName);
68205 if ($lev <= \strlen($methodName) / 3 || false !== strpos($definedMethodName, $methodName)) {
68206 $candidates[] = $definedMethodName;
68207 }
68208 }
68209
68210 if ($candidates) {
68211 sort($candidates);
68212 $last = array_pop($candidates).'"?';
68213 if ($candidates) {
68214 $candidates = 'e.g. "'.implode('", "', $candidates).'" or "'.$last;
68215 } else {
68216 $candidates = '"'.$last;
68217 }
68218
68219 $message .= "\nDid you mean to call ".$candidates;
68220 }
68221
68222 return new UndefinedMethodException($message, $exception);
68223 }
68224 }
68225 Copyright (c) 2004-2018 Fabien Potencier
68226
68227 Permission is hereby granted, free of charge, to any person obtaining a copy
68228 of this software and associated documentation files (the "Software"), to deal
68229 in the Software without restriction, including without limitation the rights
68230 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
68231 copies of the Software, and to permit persons to whom the Software is furnished
68232 to do so, subject to the following conditions:
68233
68234 The above copyright notice and this permission notice shall be included in all
68235 copies or substantial portions of the Software.
68236
68237 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
68238 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
68239 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
68240 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
68241 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
68242 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
68243 THE SOFTWARE.
68244 <?php
68245
68246
68247
68248
68249
68250
68251
68252
68253
68254
68255 namespace Symfony\Component\Filesystem\Exception;
68256
68257
68258
68259
68260
68261
68262 interface ExceptionInterface
68263 {
68264 }
68265 <?php
68266
68267
68268
68269
68270
68271
68272
68273
68274
68275
68276 namespace Symfony\Component\Filesystem\Exception;
68277
68278
68279
68280
68281
68282
68283
68284 class FileNotFoundException extends IOException
68285 {
68286 public function __construct($message = null, $code = 0, \Exception $previous = null, $path = null)
68287 {
68288 if (null === $message) {
68289 if (null === $path) {
68290 $message = 'File could not be found.';
68291 } else {
68292 $message = sprintf('File "%s" could not be found.', $path);
68293 }
68294 }
68295
68296 parent::__construct($message, $code, $previous, $path);
68297 }
68298 }
68299 <?php
68300
68301
68302
68303
68304
68305
68306
68307
68308
68309
68310 namespace Symfony\Component\Filesystem\Exception;
68311
68312
68313
68314
68315
68316
68317
68318
68319 class IOException extends \RuntimeException implements IOExceptionInterface
68320 {
68321 private $path;
68322
68323 public function __construct($message, $code = 0, \Exception $previous = null, $path = null)
68324 {
68325 $this->path = $path;
68326
68327 parent::__construct($message, $code, $previous);
68328 }
68329
68330
68331
68332
68333 public function getPath()
68334 {
68335 return $this->path;
68336 }
68337 }
68338 <?php
68339
68340
68341
68342
68343
68344
68345
68346
68347
68348
68349 namespace Symfony\Component\Filesystem\Exception;
68350
68351
68352
68353
68354
68355
68356 interface IOExceptionInterface extends ExceptionInterface
68357 {
68358
68359
68360
68361
68362
68363 public function getPath();
68364 }
68365 <?php
68366
68367
68368
68369
68370
68371
68372
68373
68374
68375
68376 namespace Symfony\Component\Filesystem;
68377
68378 use Symfony\Component\Filesystem\Exception\FileNotFoundException;
68379 use Symfony\Component\Filesystem\Exception\IOException;
68380
68381
68382
68383
68384
68385
68386 class Filesystem
68387 {
68388 private static $lastError;
68389
68390
68391
68392
68393
68394
68395
68396
68397
68398
68399
68400
68401
68402
68403
68404 public function copy($originFile, $targetFile, $overwriteNewerFiles = false)
68405 {
68406 $originIsLocal = stream_is_local($originFile) || 0 === stripos($originFile, 'file://');
68407 if ($originIsLocal && !is_file($originFile)) {
68408 throw new FileNotFoundException(sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile);
68409 }
68410
68411 $this->mkdir(\dirname($targetFile));
68412
68413 $doCopy = true;
68414 if (!$overwriteNewerFiles && null === parse_url($originFile, PHP_URL_HOST) && is_file($targetFile)) {
68415 $doCopy = filemtime($originFile) > filemtime($targetFile);
68416 }
68417
68418 if ($doCopy) {
68419
68420 if (false === $source = @fopen($originFile, 'r')) {
68421 throw new IOException(sprintf('Failed to copy "%s" to "%s" because source file could not be opened for reading.', $originFile, $targetFile), 0, null, $originFile);
68422 }
68423
68424
68425 if (false === $target = @fopen($targetFile, 'w', null, stream_context_create(array('ftp' => array('overwrite' => true))))) {
68426 throw new IOException(sprintf('Failed to copy "%s" to "%s" because target file could not be opened for writing.', $originFile, $targetFile), 0, null, $originFile);
68427 }
68428
68429 $bytesCopied = stream_copy_to_stream($source, $target);
68430 fclose($source);
68431 fclose($target);
68432 unset($source, $target);
68433
68434 if (!is_file($targetFile)) {
68435 throw new IOException(sprintf('Failed to copy "%s" to "%s".', $originFile, $targetFile), 0, null, $originFile);
68436 }
68437
68438 if ($originIsLocal) {
68439
68440 @chmod($targetFile, fileperms($targetFile) | (fileperms($originFile) & 0111));
68441
68442 if ($bytesCopied !== $bytesOrigin = filesize($originFile)) {
68443 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);
68444 }
68445 }
68446 }
68447 }
68448
68449
68450
68451
68452
68453
68454
68455
68456
68457 public function mkdir($dirs, $mode = 0777)
68458 {
68459 foreach ($this->toIterator($dirs) as $dir) {
68460 if (is_dir($dir)) {
68461 continue;
68462 }
68463
68464 if (!self::box('mkdir', $dir, $mode, true)) {
68465 if (!is_dir($dir)) {
68466
68467 if (self::$lastError) {
68468 throw new IOException(sprintf('Failed to create "%s": %s.', $dir, self::$lastError), 0, null, $dir);
68469 }
68470 throw new IOException(sprintf('Failed to create "%s"', $dir), 0, null, $dir);
68471 }
68472 }
68473 }
68474 }
68475
68476
68477
68478
68479
68480
68481
68482
68483 public function exists($files)
68484 {
68485 $maxPathLength = PHP_MAXPATHLEN - 2;
68486
68487 foreach ($this->toIterator($files) as $file) {
68488 if (\strlen($file) > $maxPathLength) {
68489 throw new IOException(sprintf('Could not check if file exist because path length exceeds %d characters.', $maxPathLength), 0, null, $file);
68490 }
68491
68492 if (!file_exists($file)) {
68493 return false;
68494 }
68495 }
68496
68497 return true;
68498 }
68499
68500
68501
68502
68503
68504
68505
68506
68507
68508
68509 public function touch($files, $time = null, $atime = null)
68510 {
68511 foreach ($this->toIterator($files) as $file) {
68512 $touch = $time ? @touch($file, $time, $atime) : @touch($file);
68513 if (true !== $touch) {
68514 throw new IOException(sprintf('Failed to touch "%s".', $file), 0, null, $file);
68515 }
68516 }
68517 }
68518
68519
68520
68521
68522
68523
68524
68525
68526 public function remove($files)
68527 {
68528 if ($files instanceof \Traversable) {
68529 $files = iterator_to_array($files, false);
68530 } elseif (!\is_array($files)) {
68531 $files = array($files);
68532 }
68533 $files = array_reverse($files);
68534 foreach ($files as $file) {
68535 if (is_link($file)) {
68536
68537 if (!(self::box('unlink', $file) || '\\' !== \DIRECTORY_SEPARATOR || self::box('rmdir', $file)) && file_exists($file)) {
68538 throw new IOException(sprintf('Failed to remove symlink "%s": %s.', $file, self::$lastError));
68539 }
68540 } elseif (is_dir($file)) {
68541 $this->remove(new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS));
68542
68543 if (!self::box('rmdir', $file) && file_exists($file)) {
68544 throw new IOException(sprintf('Failed to remove directory "%s": %s.', $file, self::$lastError));
68545 }
68546 } elseif (!self::box('unlink', $file) && file_exists($file)) {
68547 throw new IOException(sprintf('Failed to remove file "%s": %s.', $file, self::$lastError));
68548 }
68549 }
68550 }
68551
68552
68553
68554
68555
68556
68557
68558
68559
68560
68561
68562 public function chmod($files, $mode, $umask = 0000, $recursive = false)
68563 {
68564 foreach ($this->toIterator($files) as $file) {
68565 if (true !== @chmod($file, $mode & ~$umask)) {
68566 throw new IOException(sprintf('Failed to chmod file "%s".', $file), 0, null, $file);
68567 }
68568 if ($recursive && is_dir($file) && !is_link($file)) {
68569 $this->chmod(new \FilesystemIterator($file), $mode, $umask, true);
68570 }
68571 }
68572 }
68573
68574
68575
68576
68577
68578
68579
68580
68581
68582
68583 public function chown($files, $user, $recursive = false)
68584 {
68585 foreach ($this->toIterator($files) as $file) {
68586 if ($recursive && is_dir($file) && !is_link($file)) {
68587 $this->chown(new \FilesystemIterator($file), $user, true);
68588 }
68589 if (is_link($file) && \function_exists('lchown')) {
68590 if (true !== @lchown($file, $user)) {
68591 throw new IOException(sprintf('Failed to chown file "%s".', $file), 0, null, $file);
68592 }
68593 } else {
68594 if (true !== @chown($file, $user)) {
68595 throw new IOException(sprintf('Failed to chown file "%s".', $file), 0, null, $file);
68596 }
68597 }
68598 }
68599 }
68600
68601
68602
68603
68604
68605
68606
68607
68608
68609
68610 public function chgrp($files, $group, $recursive = false)
68611 {
68612 foreach ($this->toIterator($files) as $file) {
68613 if ($recursive && is_dir($file) && !is_link($file)) {
68614 $this->chgrp(new \FilesystemIterator($file), $group, true);
68615 }
68616 if (is_link($file) && \function_exists('lchgrp')) {
68617 if (true !== @lchgrp($file, $group) || (\defined('HHVM_VERSION') && !posix_getgrnam($group))) {
68618 throw new IOException(sprintf('Failed to chgrp file "%s".', $file), 0, null, $file);
68619 }
68620 } else {
68621 if (true !== @chgrp($file, $group)) {
68622 throw new IOException(sprintf('Failed to chgrp file "%s".', $file), 0, null, $file);
68623 }
68624 }
68625 }
68626 }
68627
68628
68629
68630
68631
68632
68633
68634
68635
68636
68637
68638 public function rename($origin, $target, $overwrite = false)
68639 {
68640
68641 if (!$overwrite && $this->isReadable($target)) {
68642 throw new IOException(sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target);
68643 }
68644
68645 if (true !== @rename($origin, $target)) {
68646 if (is_dir($origin)) {
68647
68648 $this->mirror($origin, $target, null, array('override' => $overwrite, 'delete' => $overwrite));
68649 $this->remove($origin);
68650
68651 return;
68652 }
68653 throw new IOException(sprintf('Cannot rename "%s" to "%s".', $origin, $target), 0, null, $target);
68654 }
68655 }
68656
68657
68658
68659
68660
68661
68662
68663
68664
68665
68666 private function isReadable($filename)
68667 {
68668 $maxPathLength = PHP_MAXPATHLEN - 2;
68669
68670 if (\strlen($filename) > $maxPathLength) {
68671 throw new IOException(sprintf('Could not check if file is readable because path length exceeds %d characters.', $maxPathLength), 0, null, $filename);
68672 }
68673
68674 return is_readable($filename);
68675 }
68676
68677
68678
68679
68680
68681
68682
68683
68684
68685
68686 public function symlink($originDir, $targetDir, $copyOnWindows = false)
68687 {
68688 if ('\\' === \DIRECTORY_SEPARATOR) {
68689 $originDir = strtr($originDir, '/', '\\');
68690 $targetDir = strtr($targetDir, '/', '\\');
68691
68692 if ($copyOnWindows) {
68693 $this->mirror($originDir, $targetDir);
68694
68695 return;
68696 }
68697 }
68698
68699 $this->mkdir(\dirname($targetDir));
68700
68701 if (is_link($targetDir)) {
68702 if (readlink($targetDir) === $originDir) {
68703 return;
68704 }
68705 $this->remove($targetDir);
68706 }
68707
68708 if (!self::box('symlink', $originDir, $targetDir)) {
68709 if (null !== self::$lastError) {
68710 if ('\\' === \DIRECTORY_SEPARATOR && false !== strpos(self::$lastError, 'error code(1314)')) {
68711 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);
68712 }
68713 }
68714 throw new IOException(sprintf('Failed to create symbolic link from "%s" to "%s".', $originDir, $targetDir), 0, null, $targetDir);
68715 }
68716 }
68717
68718
68719
68720
68721
68722
68723
68724
68725
68726 public function makePathRelative($endPath, $startPath)
68727 {
68728
68729 if ('\\' === \DIRECTORY_SEPARATOR) {
68730 $endPath = str_replace('\\', '/', $endPath);
68731 $startPath = str_replace('\\', '/', $startPath);
68732 }
68733
68734 $stripDriveLetter = function ($path) {
68735 if (\strlen($path) > 2 && ':' === $path[1] && '/' === $path[2] && ctype_alpha($path[0])) {
68736 return substr($path, 2);
68737 }
68738
68739 return $path;
68740 };
68741
68742 $endPath = $stripDriveLetter($endPath);
68743 $startPath = $stripDriveLetter($startPath);
68744
68745
68746 $startPathArr = explode('/', trim($startPath, '/'));
68747 $endPathArr = explode('/', trim($endPath, '/'));
68748
68749 $normalizePathArray = function ($pathSegments, $absolute) {
68750 $result = array();
68751
68752 foreach ($pathSegments as $segment) {
68753 if ('..' === $segment && ($absolute || \count($result))) {
68754 array_pop($result);
68755 } elseif ('.' !== $segment) {
68756 $result[] = $segment;
68757 }
68758 }
68759
68760 return $result;
68761 };
68762
68763 $startPathArr = $normalizePathArray($startPathArr, static::isAbsolutePath($startPath));
68764 $endPathArr = $normalizePathArray($endPathArr, static::isAbsolutePath($endPath));
68765
68766
68767 $index = 0;
68768 while (isset($startPathArr[$index]) && isset($endPathArr[$index]) && $startPathArr[$index] === $endPathArr[$index]) {
68769 ++$index;
68770 }
68771
68772
68773 if (1 === \count($startPathArr) && '' === $startPathArr[0]) {
68774 $depth = 0;
68775 } else {
68776 $depth = \count($startPathArr) - $index;
68777 }
68778
68779
68780 $traverser = str_repeat('../', $depth);
68781
68782 $endPathRemainder = implode('/', \array_slice($endPathArr, $index));
68783
68784
68785 $relativePath = $traverser.('' !== $endPathRemainder ? $endPathRemainder.'/' : '');
68786
68787 return '' === $relativePath ? './' : $relativePath;
68788 }
68789
68790
68791
68792
68793
68794
68795
68796
68797
68798
68799
68800
68801
68802
68803
68804
68805
68806
68807
68808
68809 public function mirror($originDir, $targetDir, \Traversable $iterator = null, $options = array())
68810 {
68811 $targetDir = rtrim($targetDir, '/\\');
68812 $originDir = rtrim($originDir, '/\\');
68813 $originDirLen = \strlen($originDir);
68814
68815
68816 if ($this->exists($targetDir) && isset($options['delete']) && $options['delete']) {
68817 $deleteIterator = $iterator;
68818 if (null === $deleteIterator) {
68819 $flags = \FilesystemIterator::SKIP_DOTS;
68820 $deleteIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($targetDir, $flags), \RecursiveIteratorIterator::CHILD_FIRST);
68821 }
68822 $targetDirLen = \strlen($targetDir);
68823 foreach ($deleteIterator as $file) {
68824 $origin = $originDir.substr($file->getPathname(), $targetDirLen);
68825 if (!$this->exists($origin)) {
68826 $this->remove($file);
68827 }
68828 }
68829 }
68830
68831 $copyOnWindows = false;
68832 if (isset($options['copy_on_windows'])) {
68833 $copyOnWindows = $options['copy_on_windows'];
68834 }
68835
68836 if (null === $iterator) {
68837 $flags = $copyOnWindows ? \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS : \FilesystemIterator::SKIP_DOTS;
68838 $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($originDir, $flags), \RecursiveIteratorIterator::SELF_FIRST);
68839 }
68840
68841 if ($this->exists($originDir)) {
68842 $this->mkdir($targetDir);
68843 }
68844
68845 foreach ($iterator as $file) {
68846 $target = $targetDir.substr($file->getPathname(), $originDirLen);
68847
68848 if ($copyOnWindows) {
68849 if (is_file($file)) {
68850 $this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
68851 } elseif (is_dir($file)) {
68852 $this->mkdir($target);
68853 } else {
68854 throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file);
68855 }
68856 } else {
68857 if (is_link($file)) {
68858 $this->symlink($file->getLinkTarget(), $target);
68859 } elseif (is_dir($file)) {
68860 $this->mkdir($target);
68861 } elseif (is_file($file)) {
68862 $this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
68863 } else {
68864 throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file);
68865 }
68866 }
68867 }
68868 }
68869
68870
68871
68872
68873
68874
68875
68876
68877 public function isAbsolutePath($file)
68878 {
68879 return strspn($file, '/\\', 0, 1)
68880 || (\strlen($file) > 3 && ctype_alpha($file[0])
68881 && ':' === substr($file, 1, 1)
68882 && strspn($file, '/\\', 2, 1)
68883 )
68884 || null !== parse_url($file, PHP_URL_SCHEME)
68885 ;
68886 }
68887
68888
68889
68890
68891
68892
68893
68894
68895
68896
68897 public function tempnam($dir, $prefix)
68898 {
68899 list($scheme, $hierarchy) = $this->getSchemeAndHierarchy($dir);
68900
68901
68902 if (null === $scheme || 'file' === $scheme || 'gs' === $scheme) {
68903 $tmpFile = @tempnam($hierarchy, $prefix);
68904
68905
68906 if (false !== $tmpFile) {
68907 if (null !== $scheme && 'gs' !== $scheme) {
68908 return $scheme.'://'.$tmpFile;
68909 }
68910
68911 return $tmpFile;
68912 }
68913
68914 throw new IOException('A temporary file could not be created.');
68915 }
68916
68917
68918 for ($i = 0; $i < 10; ++$i) {
68919
68920 $tmpFile = $dir.'/'.$prefix.uniqid(mt_rand(), true);
68921
68922
68923
68924 $handle = @fopen($tmpFile, 'x+');
68925
68926
68927 if (false === $handle) {
68928 continue;
68929 }
68930
68931
68932 @fclose($handle);
68933
68934 return $tmpFile;
68935 }
68936
68937 throw new IOException('A temporary file could not be created.');
68938 }
68939
68940
68941
68942
68943
68944
68945
68946
68947
68948
68949
68950 public function dumpFile($filename, $content, $mode = 0666)
68951 {
68952 $dir = \dirname($filename);
68953
68954 if (!is_dir($dir)) {
68955 $this->mkdir($dir);
68956 }
68957
68958 if (!is_writable($dir)) {
68959 throw new IOException(sprintf('Unable to write to the "%s" directory.', $dir), 0, null, $dir);
68960 }
68961
68962 $tmpFile = $this->tempnam($dir, basename($filename));
68963
68964 if (false === @file_put_contents($tmpFile, $content)) {
68965 throw new IOException(sprintf('Failed to write file "%s".', $filename), 0, null, $filename);
68966 }
68967
68968 if (null !== $mode) {
68969 if (\func_num_args() > 2) {
68970 @trigger_error('Support for modifying file permissions is deprecated since Symfony 2.3.12 and will be removed in 3.0.', E_USER_DEPRECATED);
68971 }
68972
68973 $this->chmod($tmpFile, $mode);
68974 } elseif (file_exists($filename)) {
68975 @chmod($tmpFile, fileperms($filename));
68976 }
68977
68978 $this->rename($tmpFile, $filename, true);
68979 }
68980
68981
68982
68983
68984
68985
68986 private function toIterator($files)
68987 {
68988 if (!$files instanceof \Traversable) {
68989 $files = new \ArrayObject(\is_array($files) ? $files : array($files));
68990 }
68991
68992 return $files;
68993 }
68994
68995
68996
68997
68998
68999
69000
69001
69002 private function getSchemeAndHierarchy($filename)
69003 {
69004 $components = explode('://', $filename, 2);
69005
69006 return 2 === \count($components) ? array($components[0], $components[1]) : array(null, $components[0]);
69007 }
69008
69009 private static function box($func)
69010 {
69011 self::$lastError = null;
69012 \set_error_handler(__CLASS__.'::handleError');
69013 try {
69014 $result = \call_user_func_array($func, \array_slice(\func_get_args(), 1));
69015 \restore_error_handler();
69016
69017 return $result;
69018 } catch (\Throwable $e) {
69019 } catch (\Exception $e) {
69020 }
69021 \restore_error_handler();
69022
69023 throw $e;
69024 }
69025
69026
69027
69028
69029 public static function handleError($type, $msg)
69030 {
69031 self::$lastError = $msg;
69032 }
69033 }
69034 Copyright (c) 2004-2018 Fabien Potencier
69035
69036 Permission is hereby granted, free of charge, to any person obtaining a copy
69037 of this software and associated documentation files (the "Software"), to deal
69038 in the Software without restriction, including without limitation the rights
69039 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
69040 copies of the Software, and to permit persons to whom the Software is furnished
69041 to do so, subject to the following conditions:
69042
69043 The above copyright notice and this permission notice shall be included in all
69044 copies or substantial portions of the Software.
69045
69046 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
69047 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
69048 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
69049 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
69050 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
69051 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
69052 THE SOFTWARE.
69053 <?php
69054
69055
69056
69057
69058
69059
69060
69061
69062
69063
69064 namespace Symfony\Component\Filesystem;
69065
69066 use Symfony\Component\Filesystem\Exception\IOException;
69067
69068
69069
69070
69071
69072
69073
69074
69075
69076
69077
69078
69079
69080
69081 class LockHandler
69082 {
69083 private $file;
69084 private $handle;
69085
69086
69087
69088
69089
69090
69091
69092 public function __construct($name, $lockPath = null)
69093 {
69094 $lockPath = $lockPath ?: sys_get_temp_dir();
69095
69096 if (!is_dir($lockPath)) {
69097 $fs = new Filesystem();
69098 $fs->mkdir($lockPath);
69099 }
69100
69101 if (!is_writable($lockPath)) {
69102 throw new IOException(sprintf('The directory "%s" is not writable.', $lockPath), 0, null, $lockPath);
69103 }
69104
69105 $this->file = sprintf('%s/sf.%s.%s.lock', $lockPath, preg_replace('/[^a-z0-9\._-]+/i', '-', $name), hash('sha256', $name));
69106 }
69107
69108
69109
69110
69111
69112
69113
69114
69115
69116
69117 public function lock($blocking = false)
69118 {
69119 if ($this->handle) {
69120 return true;
69121 }
69122
69123 $error = null;
69124
69125
69126 set_error_handler(function ($errno, $msg) use (&$error) {
69127 $error = $msg;
69128 });
69129
69130 if (!$this->handle = fopen($this->file, 'r+') ?: fopen($this->file, 'r')) {
69131 if ($this->handle = fopen($this->file, 'x')) {
69132 chmod($this->file, 0666);
69133 } elseif (!$this->handle = fopen($this->file, 'r+') ?: fopen($this->file, 'r')) {
69134 usleep(100); 
69135 $this->handle = fopen($this->file, 'r+') ?: fopen($this->file, 'r');
69136 }
69137 }
69138 restore_error_handler();
69139
69140 if (!$this->handle) {
69141 throw new IOException($error, 0, null, $this->file);
69142 }
69143
69144
69145
69146 if (!flock($this->handle, LOCK_EX | ($blocking ? 0 : LOCK_NB))) {
69147 fclose($this->handle);
69148 $this->handle = null;
69149
69150 return false;
69151 }
69152
69153 return true;
69154 }
69155
69156
69157
69158
69159 public function release()
69160 {
69161 if ($this->handle) {
69162 flock($this->handle, LOCK_UN | LOCK_NB);
69163 fclose($this->handle);
69164 $this->handle = null;
69165 }
69166 }
69167 }
69168 <?php
69169
69170
69171
69172
69173
69174
69175
69176
69177
69178
69179 namespace Symfony\Component\Finder\Adapter;
69180
69181 @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);
69182
69183
69184
69185
69186
69187
69188
69189
69190 abstract class AbstractAdapter implements AdapterInterface
69191 {
69192 protected $followLinks = false;
69193 protected $mode = 0;
69194 protected $minDepth = 0;
69195 protected $maxDepth = PHP_INT_MAX;
69196 protected $exclude = array();
69197 protected $names = array();
69198 protected $notNames = array();
69199 protected $contains = array();
69200 protected $notContains = array();
69201 protected $sizes = array();
69202 protected $dates = array();
69203 protected $filters = array();
69204 protected $sort = false;
69205 protected $paths = array();
69206 protected $notPaths = array();
69207 protected $ignoreUnreadableDirs = false;
69208
69209 private static $areSupported = array();
69210
69211
69212
69213
69214 public function isSupported()
69215 {
69216 $name = $this->getName();
69217
69218 if (!array_key_exists($name, self::$areSupported)) {
69219 self::$areSupported[$name] = $this->canBeUsed();
69220 }
69221
69222 return self::$areSupported[$name];
69223 }
69224
69225
69226
69227
69228 public function setFollowLinks($followLinks)
69229 {
69230 $this->followLinks = $followLinks;
69231
69232 return $this;
69233 }
69234
69235
69236
69237
69238 public function setMode($mode)
69239 {
69240 $this->mode = $mode;
69241
69242 return $this;
69243 }
69244
69245
69246
69247
69248 public function setDepths(array $depths)
69249 {
69250 $this->minDepth = 0;
69251 $this->maxDepth = PHP_INT_MAX;
69252
69253 foreach ($depths as $comparator) {
69254 switch ($comparator->getOperator()) {
69255 case '>':
69256 $this->minDepth = $comparator->getTarget() + 1;
69257 break;
69258 case '>=':
69259 $this->minDepth = $comparator->getTarget();
69260 break;
69261 case '<':
69262 $this->maxDepth = $comparator->getTarget() - 1;
69263 break;
69264 case '<=':
69265 $this->maxDepth = $comparator->getTarget();
69266 break;
69267 default:
69268 $this->minDepth = $this->maxDepth = $comparator->getTarget();
69269 }
69270 }
69271
69272 return $this;
69273 }
69274
69275
69276
69277
69278 public function setExclude(array $exclude)
69279 {
69280 $this->exclude = $exclude;
69281
69282 return $this;
69283 }
69284
69285
69286
69287
69288 public function setNames(array $names)
69289 {
69290 $this->names = $names;
69291
69292 return $this;
69293 }
69294
69295
69296
69297
69298 public function setNotNames(array $notNames)
69299 {
69300 $this->notNames = $notNames;
69301
69302 return $this;
69303 }
69304
69305
69306
69307
69308 public function setContains(array $contains)
69309 {
69310 $this->contains = $contains;
69311
69312 return $this;
69313 }
69314
69315
69316
69317
69318 public function setNotContains(array $notContains)
69319 {
69320 $this->notContains = $notContains;
69321
69322 return $this;
69323 }
69324
69325
69326
69327
69328 public function setSizes(array $sizes)
69329 {
69330 $this->sizes = $sizes;
69331
69332 return $this;
69333 }
69334
69335
69336
69337
69338 public function setDates(array $dates)
69339 {
69340 $this->dates = $dates;
69341
69342 return $this;
69343 }
69344
69345
69346
69347
69348 public function setFilters(array $filters)
69349 {
69350 $this->filters = $filters;
69351
69352 return $this;
69353 }
69354
69355
69356
69357
69358 public function setSort($sort)
69359 {
69360 $this->sort = $sort;
69361
69362 return $this;
69363 }
69364
69365
69366
69367
69368 public function setPath(array $paths)
69369 {
69370 $this->paths = $paths;
69371
69372 return $this;
69373 }
69374
69375
69376
69377
69378 public function setNotPath(array $notPaths)
69379 {
69380 $this->notPaths = $notPaths;
69381
69382 return $this;
69383 }
69384
69385
69386
69387
69388 public function ignoreUnreadableDirs($ignore = true)
69389 {
69390 $this->ignoreUnreadableDirs = (bool) $ignore;
69391
69392 return $this;
69393 }
69394
69395
69396
69397
69398
69399
69400
69401
69402
69403
69404
69405
69406 abstract protected function canBeUsed();
69407 }
69408 <?php
69409
69410
69411
69412
69413
69414
69415
69416
69417
69418
69419 namespace Symfony\Component\Finder\Adapter;
69420
69421 @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);
69422
69423 use Symfony\Component\Finder\Comparator\DateComparator;
69424 use Symfony\Component\Finder\Comparator\NumberComparator;
69425 use Symfony\Component\Finder\Exception\AccessDeniedException;
69426 use Symfony\Component\Finder\Expression\Expression;
69427 use Symfony\Component\Finder\Iterator;
69428 use Symfony\Component\Finder\Shell\Command;
69429 use Symfony\Component\Finder\Shell\Shell;
69430
69431
69432
69433
69434
69435
69436
69437
69438 abstract class AbstractFindAdapter extends AbstractAdapter
69439 {
69440 protected $shell;
69441
69442 public function __construct()
69443 {
69444 $this->shell = new Shell();
69445 }
69446
69447
69448
69449
69450 public function searchInDirectory($dir)
69451 {
69452
69453 $dir = realpath($dir);
69454
69455
69456 if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode && ($this->contains || $this->notContains)) {
69457 return new Iterator\FilePathsIterator(array(), $dir);
69458 }
69459
69460 $command = Command::create();
69461 $find = $this->buildFindCommand($command, $dir);
69462
69463 if ($this->followLinks) {
69464 $find->add('-follow');
69465 }
69466
69467 $find->add('-mindepth')->add($this->minDepth + 1);
69468
69469 if (PHP_INT_MAX !== $this->maxDepth) {
69470 $find->add('-maxdepth')->add($this->maxDepth + 1);
69471 }
69472
69473 if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode) {
69474 $find->add('-type d');
69475 } elseif (Iterator\FileTypeFilterIterator::ONLY_FILES === $this->mode) {
69476 $find->add('-type f');
69477 }
69478
69479 $this->buildNamesFiltering($find, $this->names);
69480 $this->buildNamesFiltering($find, $this->notNames, true);
69481 $this->buildPathsFiltering($find, $dir, $this->paths);
69482 $this->buildPathsFiltering($find, $dir, $this->notPaths, true);
69483 $this->buildSizesFiltering($find, $this->sizes);
69484 $this->buildDatesFiltering($find, $this->dates);
69485
69486 $useGrep = $this->shell->testCommand('grep') && $this->shell->testCommand('xargs');
69487 $useSort = \is_int($this->sort) && $this->shell->testCommand('sort') && $this->shell->testCommand('cut');
69488
69489 if ($useGrep && ($this->contains || $this->notContains)) {
69490 $grep = $command->ins('grep');
69491 $this->buildContentFiltering($grep, $this->contains);
69492 $this->buildContentFiltering($grep, $this->notContains, true);
69493 }
69494
69495 if ($useSort) {
69496 $this->buildSorting($command, $this->sort);
69497 }
69498
69499 $command->setErrorHandler(
69500 $this->ignoreUnreadableDirs
69501
69502 ? function ($stderr) { }
69503 : function ($stderr) { throw new AccessDeniedException($stderr); }
69504 );
69505
69506 $paths = $this->shell->testCommand('uniq') ? $command->add('| uniq')->execute() : array_unique($command->execute());
69507 $iterator = new Iterator\FilePathsIterator($paths, $dir);
69508
69509 if ($this->exclude) {
69510 $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
69511 }
69512
69513 if (!$useGrep && ($this->contains || $this->notContains)) {
69514 $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
69515 }
69516
69517 if ($this->filters) {
69518 $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
69519 }
69520
69521 if (!$useSort && $this->sort) {
69522 $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
69523 $iterator = $iteratorAggregate->getIterator();
69524 }
69525
69526 return $iterator;
69527 }
69528
69529
69530
69531
69532 protected function canBeUsed()
69533 {
69534 return $this->shell->testCommand('find');
69535 }
69536
69537
69538
69539
69540
69541
69542
69543 protected function buildFindCommand(Command $command, $dir)
69544 {
69545 return $command
69546 ->ins('find')
69547 ->add('find ')
69548 ->arg($dir)
69549 ->add('-noleaf'); 
69550 }
69551
69552
69553
69554
69555
69556
69557 private function buildNamesFiltering(Command $command, array $names, $not = false)
69558 {
69559 if (0 === \count($names)) {
69560 return;
69561 }
69562
69563 $command->add($not ? '-not' : null)->cmd('(');
69564
69565 foreach ($names as $i => $name) {
69566 $expr = Expression::create($name);
69567
69568
69569 if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
69570 $expr = Expression::create($expr->getGlob()->toRegex(false));
69571 }
69572
69573
69574
69575
69576 if ($expr->isRegex()) {
69577 $regex = $expr->getRegex();
69578 $regex->prepend($regex->hasStartFlag() ? '/' : '/[^/]*')
69579 ->setStartFlag(false)
69580 ->setStartJoker(true)
69581 ->replaceJokers('[^/]');
69582 if (!$regex->hasEndFlag() || $regex->hasEndJoker()) {
69583 $regex->setEndJoker(false)->append('[^/]*');
69584 }
69585 }
69586
69587 $command
69588 ->add($i > 0 ? '-or' : null)
69589 ->add($expr->isRegex()
69590 ? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
69591 : ($expr->isCaseSensitive() ? '-name' : '-iname')
69592 )
69593 ->arg($expr->renderPattern());
69594 }
69595
69596 $command->cmd(')');
69597 }
69598
69599
69600
69601
69602
69603
69604
69605 private function buildPathsFiltering(Command $command, $dir, array $paths, $not = false)
69606 {
69607 if (0 === \count($paths)) {
69608 return;
69609 }
69610
69611 $command->add($not ? '-not' : null)->cmd('(');
69612
69613 foreach ($paths as $i => $path) {
69614 $expr = Expression::create($path);
69615
69616
69617 if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
69618 $expr = Expression::create($expr->getGlob()->toRegex(false));
69619 }
69620
69621
69622 if ($expr->isRegex()) {
69623 $regex = $expr->getRegex();
69624 $regex->prepend($regex->hasStartFlag() ? preg_quote($dir).\DIRECTORY_SEPARATOR : '.*')->setEndJoker(!$regex->hasEndFlag());
69625 } else {
69626 $expr->prepend('*')->append('*');
69627 }
69628
69629 $command
69630 ->add($i > 0 ? '-or' : null)
69631 ->add($expr->isRegex()
69632 ? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
69633 : ($expr->isCaseSensitive() ? '-path' : '-ipath')
69634 )
69635 ->arg($expr->renderPattern());
69636 }
69637
69638 $command->cmd(')');
69639 }
69640
69641
69642
69643
69644
69645 private function buildSizesFiltering(Command $command, array $sizes)
69646 {
69647 foreach ($sizes as $i => $size) {
69648 $command->add($i > 0 ? '-and' : null);
69649
69650 switch ($size->getOperator()) {
69651 case '<=':
69652 $command->add('-size -'.($size->getTarget() + 1).'c');
69653 break;
69654 case '>=':
69655 $command->add('-size +'.($size->getTarget() - 1).'c');
69656 break;
69657 case '>':
69658 $command->add('-size +'.$size->getTarget().'c');
69659 break;
69660 case '!=':
69661 $command->add('-size -'.$size->getTarget().'c');
69662 $command->add('-size +'.$size->getTarget().'c');
69663 break;
69664 case '<':
69665 default:
69666 $command->add('-size -'.$size->getTarget().'c');
69667 }
69668 }
69669 }
69670
69671
69672
69673
69674
69675 private function buildDatesFiltering(Command $command, array $dates)
69676 {
69677 foreach ($dates as $i => $date) {
69678 $command->add($i > 0 ? '-and' : null);
69679
69680 $mins = (int) round((time() - $date->getTarget()) / 60);
69681
69682 if (0 > $mins) {
69683
69684 $command->add(' -mmin -0');
69685
69686 return;
69687 }
69688
69689 switch ($date->getOperator()) {
69690 case '<=':
69691 $command->add('-mmin +'.($mins - 1));
69692 break;
69693 case '>=':
69694 $command->add('-mmin -'.($mins + 1));
69695 break;
69696 case '>':
69697 $command->add('-mmin -'.$mins);
69698 break;
69699 case '!=':
69700 $command->add('-mmin +'.$mins.' -or -mmin -'.$mins);
69701 break;
69702 case '<':
69703 default:
69704 $command->add('-mmin +'.$mins);
69705 }
69706 }
69707 }
69708
69709
69710
69711
69712
69713
69714
69715 private function buildSorting(Command $command, $sort)
69716 {
69717 $this->buildFormatSorting($command, $sort);
69718 }
69719
69720
69721
69722
69723
69724 abstract protected function buildFormatSorting(Command $command, $sort);
69725
69726
69727
69728
69729
69730
69731 abstract protected function buildContentFiltering(Command $command, array $contains, $not = false);
69732 }
69733 <?php
69734
69735
69736
69737
69738
69739
69740
69741
69742
69743
69744 namespace Symfony\Component\Finder\Adapter;
69745
69746
69747
69748
69749
69750
69751 interface AdapterInterface
69752 {
69753
69754
69755
69756
69757
69758 public function setFollowLinks($followLinks);
69759
69760
69761
69762
69763
69764
69765 public function setMode($mode);
69766
69767
69768
69769
69770 public function setExclude(array $exclude);
69771
69772
69773
69774
69775 public function setDepths(array $depths);
69776
69777
69778
69779
69780 public function setNames(array $names);
69781
69782
69783
69784
69785 public function setNotNames(array $notNames);
69786
69787
69788
69789
69790 public function setContains(array $contains);
69791
69792
69793
69794
69795 public function setNotContains(array $notContains);
69796
69797
69798
69799
69800 public function setSizes(array $sizes);
69801
69802
69803
69804
69805 public function setDates(array $dates);
69806
69807
69808
69809
69810 public function setFilters(array $filters);
69811
69812
69813
69814
69815
69816
69817 public function setSort($sort);
69818
69819
69820
69821
69822 public function setPath(array $paths);
69823
69824
69825
69826
69827 public function setNotPath(array $notPaths);
69828
69829
69830
69831
69832
69833
69834 public function ignoreUnreadableDirs($ignore = true);
69835
69836
69837
69838
69839
69840
69841 public function searchInDirectory($dir);
69842
69843
69844
69845
69846
69847
69848 public function isSupported();
69849
69850
69851
69852
69853
69854
69855 public function getName();
69856 }
69857 <?php
69858
69859
69860
69861
69862
69863
69864
69865
69866
69867
69868 namespace Symfony\Component\Finder\Adapter;
69869
69870 @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);
69871
69872 use Symfony\Component\Finder\Expression\Expression;
69873 use Symfony\Component\Finder\Iterator\SortableIterator;
69874 use Symfony\Component\Finder\Shell\Command;
69875 use Symfony\Component\Finder\Shell\Shell;
69876
69877
69878
69879
69880
69881
69882
69883
69884 class BsdFindAdapter extends AbstractFindAdapter
69885 {
69886
69887
69888
69889 public function getName()
69890 {
69891 return 'bsd_find';
69892 }
69893
69894
69895
69896
69897 protected function canBeUsed()
69898 {
69899 return \in_array($this->shell->getType(), array(Shell::TYPE_BSD, Shell::TYPE_DARWIN)) && parent::canBeUsed();
69900 }
69901
69902
69903
69904
69905 protected function buildFormatSorting(Command $command, $sort)
69906 {
69907 switch ($sort) {
69908 case SortableIterator::SORT_BY_NAME:
69909 $command->ins('sort')->add('| sort');
69910
69911 return;
69912 case SortableIterator::SORT_BY_TYPE:
69913 $format = '%HT';
69914 break;
69915 case SortableIterator::SORT_BY_ACCESSED_TIME:
69916 $format = '%a';
69917 break;
69918 case SortableIterator::SORT_BY_CHANGED_TIME:
69919 $format = '%c';
69920 break;
69921 case SortableIterator::SORT_BY_MODIFIED_TIME:
69922 $format = '%m';
69923 break;
69924 default:
69925 throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort));
69926 }
69927
69928 $command
69929 ->add('-print0 | xargs -0 stat -f')
69930 ->arg($format.'%t%N')
69931 ->add('| sort | cut -f 2');
69932 }
69933
69934
69935
69936
69937 protected function buildFindCommand(Command $command, $dir)
69938 {
69939 parent::buildFindCommand($command, $dir)->addAtIndex('-E', 1);
69940
69941 return $command;
69942 }
69943
69944
69945
69946
69947 protected function buildContentFiltering(Command $command, array $contains, $not = false)
69948 {
69949 foreach ($contains as $contain) {
69950 $expr = Expression::create($contain);
69951
69952
69953 $command
69954 ->add('| grep -v \'^$\'')
69955 ->add('| xargs -I{} grep -I')
69956 ->add($expr->isCaseSensitive() ? null : '-i')
69957 ->add($not ? '-L' : '-l')
69958 ->add('-Ee')->arg($expr->renderPattern())
69959 ->add('{}')
69960 ;
69961 }
69962 }
69963 }
69964 <?php
69965
69966
69967
69968
69969
69970
69971
69972
69973
69974
69975 namespace Symfony\Component\Finder\Adapter;
69976
69977 @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);
69978
69979 use Symfony\Component\Finder\Expression\Expression;
69980 use Symfony\Component\Finder\Iterator\SortableIterator;
69981 use Symfony\Component\Finder\Shell\Command;
69982 use Symfony\Component\Finder\Shell\Shell;
69983
69984
69985
69986
69987
69988
69989
69990
69991 class GnuFindAdapter extends AbstractFindAdapter
69992 {
69993
69994
69995
69996 public function getName()
69997 {
69998 return 'gnu_find';
69999 }
70000
70001
70002
70003
70004 protected function buildFormatSorting(Command $command, $sort)
70005 {
70006 switch ($sort) {
70007 case SortableIterator::SORT_BY_NAME:
70008 $command->ins('sort')->add('| sort');
70009
70010 return;
70011 case SortableIterator::SORT_BY_TYPE:
70012 $format = '%y';
70013 break;
70014 case SortableIterator::SORT_BY_ACCESSED_TIME:
70015 $format = '%A@';
70016 break;
70017 case SortableIterator::SORT_BY_CHANGED_TIME:
70018 $format = '%C@';
70019 break;
70020 case SortableIterator::SORT_BY_MODIFIED_TIME:
70021 $format = '%T@';
70022 break;
70023 default:
70024 throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort));
70025 }
70026
70027 $command
70028 ->get('find')
70029 ->add('-printf')
70030 ->arg($format.' %h/%f\\n')
70031 ->add('| sort | cut')
70032 ->arg('-d ')
70033 ->arg('-f2-')
70034 ;
70035 }
70036
70037
70038
70039
70040 protected function canBeUsed()
70041 {
70042 return Shell::TYPE_UNIX === $this->shell->getType() && parent::canBeUsed();
70043 }
70044
70045
70046
70047
70048 protected function buildFindCommand(Command $command, $dir)
70049 {
70050 return parent::buildFindCommand($command, $dir)->add('-regextype posix-extended');
70051 }
70052
70053
70054
70055
70056 protected function buildContentFiltering(Command $command, array $contains, $not = false)
70057 {
70058 foreach ($contains as $contain) {
70059 $expr = Expression::create($contain);
70060
70061
70062 $command
70063 ->add('| xargs -I{} -r grep -I')
70064 ->add($expr->isCaseSensitive() ? null : '-i')
70065 ->add($not ? '-L' : '-l')
70066 ->add('-Ee')->arg($expr->renderPattern())
70067 ->add('{}')
70068 ;
70069 }
70070 }
70071 }
70072 <?php
70073
70074
70075
70076
70077
70078
70079
70080
70081
70082
70083 namespace Symfony\Component\Finder\Adapter;
70084
70085 @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);
70086
70087 use Symfony\Component\Finder\Iterator;
70088
70089
70090
70091
70092
70093
70094
70095
70096 class PhpAdapter extends AbstractAdapter
70097 {
70098
70099
70100
70101 public function searchInDirectory($dir)
70102 {
70103 $flags = \RecursiveDirectoryIterator::SKIP_DOTS;
70104
70105 if ($this->followLinks) {
70106 $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
70107 }
70108
70109 $iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs);
70110
70111 if ($this->exclude) {
70112 $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
70113 }
70114
70115 $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);
70116
70117 if ($this->minDepth > 0 || $this->maxDepth < PHP_INT_MAX) {
70118 $iterator = new Iterator\DepthRangeFilterIterator($iterator, $this->minDepth, $this->maxDepth);
70119 }
70120
70121 if ($this->mode) {
70122 $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
70123 }
70124
70125 if ($this->names || $this->notNames) {
70126 $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
70127 }
70128
70129 if ($this->contains || $this->notContains) {
70130 $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
70131 }
70132
70133 if ($this->sizes) {
70134 $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
70135 }
70136
70137 if ($this->dates) {
70138 $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
70139 }
70140
70141 if ($this->filters) {
70142 $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
70143 }
70144
70145 if ($this->paths || $this->notPaths) {
70146 $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
70147 }
70148
70149 if ($this->sort) {
70150 $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
70151 $iterator = $iteratorAggregate->getIterator();
70152 }
70153
70154 return $iterator;
70155 }
70156
70157
70158
70159
70160 public function getName()
70161 {
70162 return 'php';
70163 }
70164
70165
70166
70167
70168 protected function canBeUsed()
70169 {
70170 return true;
70171 }
70172 }
70173 <?php
70174
70175
70176
70177
70178
70179
70180
70181
70182
70183
70184 namespace Symfony\Component\Finder\Comparator;
70185
70186
70187
70188
70189
70190
70191 class Comparator
70192 {
70193 private $target;
70194 private $operator = '==';
70195
70196
70197
70198
70199
70200
70201 public function getTarget()
70202 {
70203 return $this->target;
70204 }
70205
70206
70207
70208
70209
70210
70211 public function setTarget($target)
70212 {
70213 $this->target = $target;
70214 }
70215
70216
70217
70218
70219
70220
70221 public function getOperator()
70222 {
70223 return $this->operator;
70224 }
70225
70226
70227
70228
70229
70230
70231
70232
70233 public function setOperator($operator)
70234 {
70235 if (!$operator) {
70236 $operator = '==';
70237 }
70238
70239 if (!\in_array($operator, array('>', '<', '>=', '<=', '==', '!='))) {
70240 throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator));
70241 }
70242
70243 $this->operator = $operator;
70244 }
70245
70246
70247
70248
70249
70250
70251
70252
70253 public function test($test)
70254 {
70255 switch ($this->operator) {
70256 case '>':
70257 return $test > $this->target;
70258 case '>=':
70259 return $test >= $this->target;
70260 case '<':
70261 return $test < $this->target;
70262 case '<=':
70263 return $test <= $this->target;
70264 case '!=':
70265 return $test != $this->target;
70266 }
70267
70268 return $test == $this->target;
70269 }
70270 }
70271 <?php
70272
70273
70274
70275
70276
70277
70278
70279
70280
70281
70282 namespace Symfony\Component\Finder\Comparator;
70283
70284
70285
70286
70287
70288
70289 class DateComparator extends Comparator
70290 {
70291
70292
70293
70294
70295
70296 public function __construct($test)
70297 {
70298 if (!preg_match('#^\s*(==|!=|[<>]=?|after|since|before|until)?\s*(.+?)\s*$#i', $test, $matches)) {
70299 throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a date test.', $test));
70300 }
70301
70302 try {
70303 $date = new \DateTime($matches[2]);
70304 $target = $date->format('U');
70305 } catch (\Exception $e) {
70306 throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2]));
70307 }
70308
70309 $operator = isset($matches[1]) ? $matches[1] : '==';
70310 if ('since' === $operator || 'after' === $operator) {
70311 $operator = '>';
70312 }
70313
70314 if ('until' === $operator || 'before' === $operator) {
70315 $operator = '<';
70316 }
70317
70318 $this->setOperator($operator);
70319 $this->setTarget($target);
70320 }
70321 }
70322 <?php
70323
70324
70325
70326
70327
70328
70329
70330
70331
70332
70333 namespace Symfony\Component\Finder\Comparator;
70334
70335
70336
70337
70338
70339
70340
70341
70342
70343
70344
70345
70346
70347
70348
70349
70350
70351
70352
70353
70354
70355
70356 class NumberComparator extends Comparator
70357 {
70358
70359
70360
70361
70362
70363 public function __construct($test)
70364 {
70365 if (!preg_match('#^\s*(==|!=|[<>]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $test, $matches)) {
70366 throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a number test.', $test));
70367 }
70368
70369 $target = $matches[2];
70370 if (!is_numeric($target)) {
70371 throw new \InvalidArgumentException(sprintf('Invalid number "%s".', $target));
70372 }
70373 if (isset($matches[3])) {
70374
70375 switch (strtolower($matches[3])) {
70376 case 'k':
70377 $target *= 1000;
70378 break;
70379 case 'ki':
70380 $target *= 1024;
70381 break;
70382 case 'm':
70383 $target *= 1000000;
70384 break;
70385 case 'mi':
70386 $target *= 1024 * 1024;
70387 break;
70388 case 'g':
70389 $target *= 1000000000;
70390 break;
70391 case 'gi':
70392 $target *= 1024 * 1024 * 1024;
70393 break;
70394 }
70395 }
70396
70397 $this->setTarget($target);
70398 $this->setOperator(isset($matches[1]) ? $matches[1] : '==');
70399 }
70400 }
70401 <?php
70402
70403
70404
70405
70406
70407
70408
70409
70410
70411
70412 namespace Symfony\Component\Finder\Exception;
70413
70414
70415
70416
70417 class AccessDeniedException extends \UnexpectedValueException
70418 {
70419 }
70420 <?php
70421
70422
70423
70424
70425
70426
70427
70428
70429
70430
70431 namespace Symfony\Component\Finder\Exception;
70432
70433 @trigger_error('The '.__NAMESPACE__.'\AdapterFailureException class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
70434
70435 use Symfony\Component\Finder\Adapter\AdapterInterface;
70436
70437
70438
70439
70440
70441
70442
70443
70444 class AdapterFailureException extends \RuntimeException implements ExceptionInterface
70445 {
70446 private $adapter;
70447
70448
70449
70450
70451
70452
70453 public function __construct(AdapterInterface $adapter, $message = null, \Exception $previous = null)
70454 {
70455 $this->adapter = $adapter;
70456 parent::__construct($message ?: 'Search failed with "'.$adapter->getName().'" adapter.', $previous);
70457 }
70458
70459
70460
70461
70462 public function getAdapter()
70463 {
70464 return $this->adapter;
70465 }
70466 }
70467 <?php
70468
70469
70470
70471
70472
70473
70474
70475
70476
70477
70478 namespace Symfony\Component\Finder\Exception;
70479
70480
70481
70482
70483 interface ExceptionInterface
70484 {
70485
70486
70487
70488 public function getAdapter();
70489 }
70490 <?php
70491
70492
70493
70494
70495
70496
70497
70498
70499
70500
70501 namespace Symfony\Component\Finder\Exception;
70502
70503 @trigger_error('The '.__NAMESPACE__.'\OperationNotPermitedException class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
70504
70505
70506
70507
70508
70509
70510 class OperationNotPermitedException extends AdapterFailureException
70511 {
70512 }
70513 <?php
70514
70515
70516
70517
70518
70519
70520
70521
70522
70523
70524 namespace Symfony\Component\Finder\Exception;
70525
70526 @trigger_error('The '.__NAMESPACE__.'\ShellCommandFailureException class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
70527
70528 use Symfony\Component\Finder\Adapter\AdapterInterface;
70529 use Symfony\Component\Finder\Shell\Command;
70530
70531
70532
70533
70534
70535
70536 class ShellCommandFailureException extends AdapterFailureException
70537 {
70538 private $command;
70539
70540 public function __construct(AdapterInterface $adapter, Command $command, \Exception $previous = null)
70541 {
70542 $this->command = $command;
70543 parent::__construct($adapter, 'Shell command failed: "'.$command->join().'".', $previous);
70544 }
70545
70546
70547
70548
70549 public function getCommand()
70550 {
70551 return $this->command;
70552 }
70553 }
70554 <?php
70555
70556
70557
70558
70559
70560
70561
70562
70563
70564
70565 namespace Symfony\Component\Finder\Expression;
70566
70567 @trigger_error('The '.__NAMESPACE__.'\Expression class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
70568
70569
70570
70571
70572 class Expression implements ValueInterface
70573 {
70574 const TYPE_REGEX = 1;
70575 const TYPE_GLOB = 2;
70576
70577
70578
70579
70580 private $value;
70581
70582
70583
70584
70585
70586
70587 public static function create($expr)
70588 {
70589 return new self($expr);
70590 }
70591
70592
70593
70594
70595 public function __construct($expr)
70596 {
70597 try {
70598 $this->value = Regex::create($expr);
70599 } catch (\InvalidArgumentException $e) {
70600 $this->value = new Glob($expr);
70601 }
70602 }
70603
70604
70605
70606
70607 public function __toString()
70608 {
70609 return $this->render();
70610 }
70611
70612
70613
70614
70615 public function render()
70616 {
70617 return $this->value->render();
70618 }
70619
70620
70621
70622
70623 public function renderPattern()
70624 {
70625 return $this->value->renderPattern();
70626 }
70627
70628
70629
70630
70631 public function isCaseSensitive()
70632 {
70633 return $this->value->isCaseSensitive();
70634 }
70635
70636
70637
70638
70639 public function getType()
70640 {
70641 return $this->value->getType();
70642 }
70643
70644
70645
70646
70647 public function prepend($expr)
70648 {
70649 $this->value->prepend($expr);
70650
70651 return $this;
70652 }
70653
70654
70655
70656
70657 public function append($expr)
70658 {
70659 $this->value->append($expr);
70660
70661 return $this;
70662 }
70663
70664
70665
70666
70667 public function isRegex()
70668 {
70669 return self::TYPE_REGEX === $this->value->getType();
70670 }
70671
70672
70673
70674
70675 public function isGlob()
70676 {
70677 return self::TYPE_GLOB === $this->value->getType();
70678 }
70679
70680
70681
70682
70683
70684
70685 public function getGlob()
70686 {
70687 if (self::TYPE_GLOB !== $this->value->getType()) {
70688 throw new \LogicException('Regex can\'t be transformed to glob.');
70689 }
70690
70691 return $this->value;
70692 }
70693
70694
70695
70696
70697 public function getRegex()
70698 {
70699 return self::TYPE_REGEX === $this->value->getType() ? $this->value : $this->value->toRegex();
70700 }
70701 }
70702 <?php
70703
70704
70705
70706
70707
70708
70709
70710
70711
70712
70713 namespace Symfony\Component\Finder\Expression;
70714
70715 @trigger_error('The '.__NAMESPACE__.'\Glob class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
70716
70717 use Symfony\Component\Finder\Glob as FinderGlob;
70718
70719
70720
70721
70722 class Glob implements ValueInterface
70723 {
70724 private $pattern;
70725
70726
70727
70728
70729 public function __construct($pattern)
70730 {
70731 $this->pattern = $pattern;
70732 }
70733
70734
70735
70736
70737 public function render()
70738 {
70739 return $this->pattern;
70740 }
70741
70742
70743
70744
70745 public function renderPattern()
70746 {
70747 return $this->pattern;
70748 }
70749
70750
70751
70752
70753 public function getType()
70754 {
70755 return Expression::TYPE_GLOB;
70756 }
70757
70758
70759
70760
70761 public function isCaseSensitive()
70762 {
70763 return true;
70764 }
70765
70766
70767
70768
70769 public function prepend($expr)
70770 {
70771 $this->pattern = $expr.$this->pattern;
70772
70773 return $this;
70774 }
70775
70776
70777
70778
70779 public function append($expr)
70780 {
70781 $this->pattern .= $expr;
70782
70783 return $this;
70784 }
70785
70786
70787
70788
70789
70790
70791 public function isExpandable()
70792 {
70793 return false !== strpos($this->pattern, '{')
70794 && false !== strpos($this->pattern, '}');
70795 }
70796
70797
70798
70799
70800
70801
70802
70803 public function toRegex($strictLeadingDot = true, $strictWildcardSlash = true)
70804 {
70805 $regex = FinderGlob::toRegex($this->pattern, $strictLeadingDot, $strictWildcardSlash, '');
70806
70807 return new Regex($regex);
70808 }
70809 }
70810 <?php
70811
70812
70813
70814
70815
70816
70817
70818
70819
70820
70821 namespace Symfony\Component\Finder\Expression;
70822
70823 @trigger_error('The '.__NAMESPACE__.'\Regex class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
70824
70825
70826
70827
70828 class Regex implements ValueInterface
70829 {
70830 const START_FLAG = '^';
70831 const END_FLAG = '$';
70832 const BOUNDARY = '~';
70833 const JOKER = '.*';
70834 const ESCAPING = '\\';
70835
70836
70837
70838
70839 private $pattern;
70840
70841
70842
70843
70844 private $options;
70845
70846
70847
70848
70849 private $startFlag;
70850
70851
70852
70853
70854 private $endFlag;
70855
70856
70857
70858
70859 private $startJoker;
70860
70861
70862
70863
70864 private $endJoker;
70865
70866
70867
70868
70869
70870
70871
70872
70873 public static function create($expr)
70874 {
70875 if (preg_match('/^(.{3,}?)([imsxuADU]*)$/', $expr, $m)) {
70876 $start = substr($m[1], 0, 1);
70877 $end = substr($m[1], -1);
70878
70879 if (
70880 ($start === $end && !preg_match('/[*?[:alnum:] \\\\]/', $start))
70881 || ('{' === $start && '}' === $end)
70882 || ('(' === $start && ')' === $end)
70883 ) {
70884 return new self(substr($m[1], 1, -1), $m[2], $end);
70885 }
70886 }
70887
70888 throw new \InvalidArgumentException('Given expression is not a regex.');
70889 }
70890
70891
70892
70893
70894
70895
70896 public function __construct($pattern, $options = '', $delimiter = null)
70897 {
70898 if (null !== $delimiter) {
70899
70900 $pattern = str_replace('\\'.$delimiter, $delimiter, $pattern);
70901 }
70902
70903 $this->parsePattern($pattern);
70904 $this->options = $options;
70905 }
70906
70907
70908
70909
70910 public function __toString()
70911 {
70912 return $this->render();
70913 }
70914
70915
70916
70917
70918 public function render()
70919 {
70920 return self::BOUNDARY
70921 .$this->renderPattern()
70922 .self::BOUNDARY
70923 .$this->options;
70924 }
70925
70926
70927
70928
70929 public function renderPattern()
70930 {
70931 return ($this->startFlag ? self::START_FLAG : '')
70932 .($this->startJoker ? self::JOKER : '')
70933 .str_replace(self::BOUNDARY, '\\'.self::BOUNDARY, $this->pattern)
70934 .($this->endJoker ? self::JOKER : '')
70935 .($this->endFlag ? self::END_FLAG : '');
70936 }
70937
70938
70939
70940
70941 public function isCaseSensitive()
70942 {
70943 return !$this->hasOption('i');
70944 }
70945
70946
70947
70948
70949 public function getType()
70950 {
70951 return Expression::TYPE_REGEX;
70952 }
70953
70954
70955
70956
70957 public function prepend($expr)
70958 {
70959 $this->pattern = $expr.$this->pattern;
70960
70961 return $this;
70962 }
70963
70964
70965
70966
70967 public function append($expr)
70968 {
70969 $this->pattern .= $expr;
70970
70971 return $this;
70972 }
70973
70974
70975
70976
70977
70978
70979 public function hasOption($option)
70980 {
70981 return false !== strpos($this->options, $option);
70982 }
70983
70984
70985
70986
70987
70988
70989 public function addOption($option)
70990 {
70991 if (!$this->hasOption($option)) {
70992 $this->options .= $option;
70993 }
70994
70995 return $this;
70996 }
70997
70998
70999
71000
71001
71002
71003 public function removeOption($option)
71004 {
71005 $this->options = str_replace($option, '', $this->options);
71006
71007 return $this;
71008 }
71009
71010
71011
71012
71013
71014
71015 public function setStartFlag($startFlag)
71016 {
71017 $this->startFlag = $startFlag;
71018
71019 return $this;
71020 }
71021
71022
71023
71024
71025 public function hasStartFlag()
71026 {
71027 return $this->startFlag;
71028 }
71029
71030
71031
71032
71033
71034
71035 public function setEndFlag($endFlag)
71036 {
71037 $this->endFlag = (bool) $endFlag;
71038
71039 return $this;
71040 }
71041
71042
71043
71044
71045 public function hasEndFlag()
71046 {
71047 return $this->endFlag;
71048 }
71049
71050
71051
71052
71053
71054
71055 public function setStartJoker($startJoker)
71056 {
71057 $this->startJoker = $startJoker;
71058
71059 return $this;
71060 }
71061
71062
71063
71064
71065 public function hasStartJoker()
71066 {
71067 return $this->startJoker;
71068 }
71069
71070
71071
71072
71073
71074
71075 public function setEndJoker($endJoker)
71076 {
71077 $this->endJoker = (bool) $endJoker;
71078
71079 return $this;
71080 }
71081
71082
71083
71084
71085 public function hasEndJoker()
71086 {
71087 return $this->endJoker;
71088 }
71089
71090
71091
71092
71093 public function replaceJokers($replacement)
71094 {
71095 $replace = function ($subject) use ($replacement) {
71096 $subject = $subject[0];
71097 $replace = 0 === substr_count($subject, '\\') % 2;
71098
71099 return $replace ? str_replace('.', $replacement, $subject) : $subject;
71100 };
71101
71102 $this->pattern = preg_replace_callback('~[\\\\]*\\.~', $replace, $this->pattern);
71103
71104 return $this;
71105 }
71106
71107
71108
71109
71110 private function parsePattern($pattern)
71111 {
71112 if ($this->startFlag = self::START_FLAG === substr($pattern, 0, 1)) {
71113 $pattern = substr($pattern, 1);
71114 }
71115
71116 if ($this->startJoker = self::JOKER === substr($pattern, 0, 2)) {
71117 $pattern = substr($pattern, 2);
71118 }
71119
71120 if ($this->endFlag = (self::END_FLAG === substr($pattern, -1) && self::ESCAPING !== substr($pattern, -2, -1))) {
71121 $pattern = substr($pattern, 0, -1);
71122 }
71123
71124 if ($this->endJoker = (self::JOKER === substr($pattern, -2) && self::ESCAPING !== substr($pattern, -3, -2))) {
71125 $pattern = substr($pattern, 0, -2);
71126 }
71127
71128 $this->pattern = $pattern;
71129 }
71130 }
71131 <?php
71132
71133
71134
71135
71136
71137
71138
71139
71140
71141
71142 namespace Symfony\Component\Finder\Expression;
71143
71144 @trigger_error('The '.__NAMESPACE__.'\ValueInterface interface is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
71145
71146
71147
71148
71149 interface ValueInterface
71150 {
71151
71152
71153
71154
71155
71156 public function render();
71157
71158
71159
71160
71161
71162
71163 public function renderPattern();
71164
71165
71166
71167
71168
71169
71170 public function isCaseSensitive();
71171
71172
71173
71174
71175
71176
71177 public function getType();
71178
71179
71180
71181
71182
71183
71184 public function prepend($expr);
71185
71186
71187
71188
71189
71190
71191 public function append($expr);
71192 }
71193 <?php
71194
71195
71196
71197
71198
71199
71200
71201
71202
71203
71204 namespace Symfony\Component\Finder;
71205
71206 use Symfony\Component\Finder\Adapter\AdapterInterface;
71207 use Symfony\Component\Finder\Adapter\BsdFindAdapter;
71208 use Symfony\Component\Finder\Adapter\GnuFindAdapter;
71209 use Symfony\Component\Finder\Adapter\PhpAdapter;
71210 use Symfony\Component\Finder\Comparator\DateComparator;
71211 use Symfony\Component\Finder\Comparator\NumberComparator;
71212 use Symfony\Component\Finder\Exception\ExceptionInterface;
71213 use Symfony\Component\Finder\Iterator\CustomFilterIterator;
71214 use Symfony\Component\Finder\Iterator\DateRangeFilterIterator;
71215 use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator;
71216 use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator;
71217 use Symfony\Component\Finder\Iterator\FilecontentFilterIterator;
71218 use Symfony\Component\Finder\Iterator\FilenameFilterIterator;
71219 use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator;
71220 use Symfony\Component\Finder\Iterator\SortableIterator;
71221
71222
71223
71224
71225
71226
71227
71228
71229
71230
71231
71232
71233
71234
71235 class Finder implements \IteratorAggregate, \Countable
71236 {
71237 const IGNORE_VCS_FILES = 1;
71238 const IGNORE_DOT_FILES = 2;
71239
71240 private $mode = 0;
71241 private $names = array();
71242 private $notNames = array();
71243 private $exclude = array();
71244 private $filters = array();
71245 private $depths = array();
71246 private $sizes = array();
71247 private $followLinks = false;
71248 private $sort = false;
71249 private $ignore = 0;
71250 private $dirs = array();
71251 private $dates = array();
71252 private $iterators = array();
71253 private $contains = array();
71254 private $notContains = array();
71255 private $adapters = null;
71256 private $paths = array();
71257 private $notPaths = array();
71258 private $ignoreUnreadableDirs = false;
71259
71260 private static $vcsPatterns = array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg');
71261
71262 public function __construct()
71263 {
71264 $this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
71265 }
71266
71267
71268
71269
71270
71271
71272 public static function create()
71273 {
71274 return new static();
71275 }
71276
71277
71278
71279
71280
71281
71282
71283
71284
71285
71286
71287 public function addAdapter(AdapterInterface $adapter, $priority = 0)
71288 {
71289 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
71290
71291 $this->initDefaultAdapters();
71292
71293 $this->adapters[$adapter->getName()] = array(
71294 'adapter' => $adapter,
71295 'priority' => $priority,
71296 'selected' => false,
71297 );
71298
71299 return $this->sortAdapters();
71300 }
71301
71302
71303
71304
71305
71306
71307
71308
71309 public function useBestAdapter()
71310 {
71311 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
71312
71313 $this->initDefaultAdapters();
71314
71315 $this->resetAdapterSelection();
71316
71317 return $this->sortAdapters();
71318 }
71319
71320
71321
71322
71323
71324
71325
71326
71327
71328
71329
71330
71331 public function setAdapter($name)
71332 {
71333 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
71334
71335 $this->initDefaultAdapters();
71336
71337 if (!isset($this->adapters[$name])) {
71338 throw new \InvalidArgumentException(sprintf('Adapter "%s" does not exist.', $name));
71339 }
71340
71341 $this->resetAdapterSelection();
71342 $this->adapters[$name]['selected'] = true;
71343
71344 return $this->sortAdapters();
71345 }
71346
71347
71348
71349
71350
71351
71352
71353
71354 public function removeAdapters()
71355 {
71356 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
71357
71358 $this->adapters = array();
71359
71360 return $this;
71361 }
71362
71363
71364
71365
71366
71367
71368
71369
71370 public function getAdapters()
71371 {
71372 @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
71373
71374 $this->initDefaultAdapters();
71375
71376 return array_values(array_map(function (array $adapter) {
71377 return $adapter['adapter'];
71378 }, $this->adapters));
71379 }
71380
71381
71382
71383
71384
71385
71386 public function directories()
71387 {
71388 $this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES;
71389
71390 return $this;
71391 }
71392
71393
71394
71395
71396
71397
71398 public function files()
71399 {
71400 $this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES;
71401
71402 return $this;
71403 }
71404
71405
71406
71407
71408
71409
71410
71411
71412
71413
71414
71415
71416
71417
71418
71419
71420 public function depth($level)
71421 {
71422 $this->depths[] = new Comparator\NumberComparator($level);
71423
71424 return $this;
71425 }
71426
71427
71428
71429
71430
71431
71432
71433
71434
71435
71436
71437
71438
71439
71440
71441
71442
71443
71444
71445 public function date($date)
71446 {
71447 $this->dates[] = new Comparator\DateComparator($date);
71448
71449 return $this;
71450 }
71451
71452
71453
71454
71455
71456
71457
71458
71459
71460
71461
71462
71463
71464
71465
71466
71467 public function name($pattern)
71468 {
71469 $this->names[] = $pattern;
71470
71471 return $this;
71472 }
71473
71474
71475
71476
71477
71478
71479
71480
71481
71482
71483 public function notName($pattern)
71484 {
71485 $this->notNames[] = $pattern;
71486
71487 return $this;
71488 }
71489
71490
71491
71492
71493
71494
71495
71496
71497
71498
71499
71500
71501
71502
71503
71504 public function contains($pattern)
71505 {
71506 $this->contains[] = $pattern;
71507
71508 return $this;
71509 }
71510
71511
71512
71513
71514
71515
71516
71517
71518
71519
71520
71521
71522
71523
71524
71525 public function notContains($pattern)
71526 {
71527 $this->notContains[] = $pattern;
71528
71529 return $this;
71530 }
71531
71532
71533
71534
71535
71536
71537
71538
71539
71540
71541
71542
71543
71544
71545
71546
71547
71548 public function path($pattern)
71549 {
71550 $this->paths[] = $pattern;
71551
71552 return $this;
71553 }
71554
71555
71556
71557
71558
71559
71560
71561
71562
71563
71564
71565
71566
71567
71568
71569
71570
71571 public function notPath($pattern)
71572 {
71573 $this->notPaths[] = $pattern;
71574
71575 return $this;
71576 }
71577
71578
71579
71580
71581
71582
71583
71584
71585
71586
71587
71588
71589
71590
71591
71592 public function size($size)
71593 {
71594 $this->sizes[] = new Comparator\NumberComparator($size);
71595
71596 return $this;
71597 }
71598
71599
71600
71601
71602
71603
71604
71605
71606
71607
71608
71609
71610
71611
71612 public function exclude($dirs)
71613 {
71614 $this->exclude = array_merge($this->exclude, (array) $dirs);
71615
71616 return $this;
71617 }
71618
71619
71620
71621
71622
71623
71624
71625
71626
71627
71628
71629
71630 public function ignoreDotFiles($ignoreDotFiles)
71631 {
71632 if ($ignoreDotFiles) {
71633 $this->ignore |= static::IGNORE_DOT_FILES;
71634 } else {
71635 $this->ignore &= ~static::IGNORE_DOT_FILES;
71636 }
71637
71638 return $this;
71639 }
71640
71641
71642
71643
71644
71645
71646
71647
71648
71649
71650
71651
71652 public function ignoreVCS($ignoreVCS)
71653 {
71654 if ($ignoreVCS) {
71655 $this->ignore |= static::IGNORE_VCS_FILES;
71656 } else {
71657 $this->ignore &= ~static::IGNORE_VCS_FILES;
71658 }
71659
71660 return $this;
71661 }
71662
71663
71664
71665
71666
71667
71668
71669
71670 public static function addVCSPattern($pattern)
71671 {
71672 foreach ((array) $pattern as $p) {
71673 self::$vcsPatterns[] = $p;
71674 }
71675
71676 self::$vcsPatterns = array_unique(self::$vcsPatterns);
71677 }
71678
71679
71680
71681
71682
71683
71684
71685
71686
71687
71688
71689
71690 public function sort(\Closure $closure)
71691 {
71692 $this->sort = $closure;
71693
71694 return $this;
71695 }
71696
71697
71698
71699
71700
71701
71702
71703
71704
71705
71706 public function sortByName()
71707 {
71708 $this->sort = Iterator\SortableIterator::SORT_BY_NAME;
71709
71710 return $this;
71711 }
71712
71713
71714
71715
71716
71717
71718
71719
71720
71721
71722 public function sortByType()
71723 {
71724 $this->sort = Iterator\SortableIterator::SORT_BY_TYPE;
71725
71726 return $this;
71727 }
71728
71729
71730
71731
71732
71733
71734
71735
71736
71737
71738
71739
71740 public function sortByAccessedTime()
71741 {
71742 $this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME;
71743
71744 return $this;
71745 }
71746
71747
71748
71749
71750
71751
71752
71753
71754
71755
71756
71757
71758
71759
71760 public function sortByChangedTime()
71761 {
71762 $this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME;
71763
71764 return $this;
71765 }
71766
71767
71768
71769
71770
71771
71772
71773
71774
71775
71776
71777
71778 public function sortByModifiedTime()
71779 {
71780 $this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME;
71781
71782 return $this;
71783 }
71784
71785
71786
71787
71788
71789
71790
71791
71792
71793
71794
71795 public function filter(\Closure $closure)
71796 {
71797 $this->filters[] = $closure;
71798
71799 return $this;
71800 }
71801
71802
71803
71804
71805
71806
71807 public function followLinks()
71808 {
71809 $this->followLinks = true;
71810
71811 return $this;
71812 }
71813
71814
71815
71816
71817
71818
71819
71820
71821
71822
71823 public function ignoreUnreadableDirs($ignore = true)
71824 {
71825 $this->ignoreUnreadableDirs = (bool) $ignore;
71826
71827 return $this;
71828 }
71829
71830
71831
71832
71833
71834
71835
71836
71837
71838
71839 public function in($dirs)
71840 {
71841 $resolvedDirs = array();
71842
71843 foreach ((array) $dirs as $dir) {
71844 if (is_dir($dir)) {
71845 $resolvedDirs[] = $this->normalizeDir($dir);
71846 } elseif ($glob = glob($dir, (\defined('GLOB_BRACE') ? GLOB_BRACE : 0) | GLOB_ONLYDIR)) {
71847 $resolvedDirs = array_merge($resolvedDirs, array_map(array($this, 'normalizeDir'), $glob));
71848 } else {
71849 throw new \InvalidArgumentException(sprintf('The "%s" directory does not exist.', $dir));
71850 }
71851 }
71852
71853 $this->dirs = array_merge($this->dirs, $resolvedDirs);
71854
71855 return $this;
71856 }
71857
71858
71859
71860
71861
71862
71863
71864
71865
71866
71867 public function getIterator()
71868 {
71869 if (0 === \count($this->dirs) && 0 === \count($this->iterators)) {
71870 throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.');
71871 }
71872
71873 if (1 === \count($this->dirs) && 0 === \count($this->iterators)) {
71874 return $this->searchInDirectory($this->dirs[0]);
71875 }
71876
71877 $iterator = new \AppendIterator();
71878 foreach ($this->dirs as $dir) {
71879 $iterator->append($this->searchInDirectory($dir));
71880 }
71881
71882 foreach ($this->iterators as $it) {
71883 $iterator->append($it);
71884 }
71885
71886 return $iterator;
71887 }
71888
71889
71890
71891
71892
71893
71894
71895
71896
71897
71898
71899
71900 public function append($iterator)
71901 {
71902 if ($iterator instanceof \IteratorAggregate) {
71903 $this->iterators[] = $iterator->getIterator();
71904 } elseif ($iterator instanceof \Iterator) {
71905 $this->iterators[] = $iterator;
71906 } elseif ($iterator instanceof \Traversable || \is_array($iterator)) {
71907 $it = new \ArrayIterator();
71908 foreach ($iterator as $file) {
71909 $it->append($file instanceof \SplFileInfo ? $file : new \SplFileInfo($file));
71910 }
71911 $this->iterators[] = $it;
71912 } else {
71913 throw new \InvalidArgumentException('Finder::append() method wrong argument type.');
71914 }
71915
71916 return $this;
71917 }
71918
71919
71920
71921
71922
71923
71924 public function count()
71925 {
71926 return iterator_count($this->getIterator());
71927 }
71928
71929
71930
71931
71932 private function sortAdapters()
71933 {
71934 uasort($this->adapters, function (array $a, array $b) {
71935 if ($a['selected'] || $b['selected']) {
71936 return $a['selected'] ? -1 : 1;
71937 }
71938
71939 return $a['priority'] > $b['priority'] ? -1 : 1;
71940 });
71941
71942 return $this;
71943 }
71944
71945
71946
71947
71948
71949
71950 private function searchInDirectory($dir)
71951 {
71952 if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
71953 $this->exclude = array_merge($this->exclude, self::$vcsPatterns);
71954 }
71955
71956 if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
71957 $this->notPaths[] = '#(^|/)\..+(/|$)#';
71958 }
71959
71960 if ($this->adapters) {
71961 foreach ($this->adapters as $adapter) {
71962 if ($adapter['adapter']->isSupported()) {
71963 try {
71964 return $this
71965 ->buildAdapter($adapter['adapter'])
71966 ->searchInDirectory($dir);
71967 } catch (ExceptionInterface $e) {
71968 }
71969 }
71970 }
71971 }
71972
71973 $minDepth = 0;
71974 $maxDepth = PHP_INT_MAX;
71975
71976 foreach ($this->depths as $comparator) {
71977 switch ($comparator->getOperator()) {
71978 case '>':
71979 $minDepth = $comparator->getTarget() + 1;
71980 break;
71981 case '>=':
71982 $minDepth = $comparator->getTarget();
71983 break;
71984 case '<':
71985 $maxDepth = $comparator->getTarget() - 1;
71986 break;
71987 case '<=':
71988 $maxDepth = $comparator->getTarget();
71989 break;
71990 default:
71991 $minDepth = $maxDepth = $comparator->getTarget();
71992 }
71993 }
71994
71995 $flags = \RecursiveDirectoryIterator::SKIP_DOTS;
71996
71997 if ($this->followLinks) {
71998 $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
71999 }
72000
72001 $iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs);
72002
72003 if ($this->exclude) {
72004 $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
72005 }
72006
72007 $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);
72008
72009 if ($minDepth > 0 || $maxDepth < PHP_INT_MAX) {
72010 $iterator = new Iterator\DepthRangeFilterIterator($iterator, $minDepth, $maxDepth);
72011 }
72012
72013 if ($this->mode) {
72014 $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
72015 }
72016
72017 if ($this->names || $this->notNames) {
72018 $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
72019 }
72020
72021 if ($this->contains || $this->notContains) {
72022 $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
72023 }
72024
72025 if ($this->sizes) {
72026 $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
72027 }
72028
72029 if ($this->dates) {
72030 $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
72031 }
72032
72033 if ($this->filters) {
72034 $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
72035 }
72036
72037 if ($this->paths || $this->notPaths) {
72038 $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
72039 }
72040
72041 if ($this->sort) {
72042 $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
72043 $iterator = $iteratorAggregate->getIterator();
72044 }
72045
72046 return $iterator;
72047 }
72048
72049
72050
72051
72052 private function buildAdapter(AdapterInterface $adapter)
72053 {
72054 return $adapter
72055 ->setFollowLinks($this->followLinks)
72056 ->setDepths($this->depths)
72057 ->setMode($this->mode)
72058 ->setExclude($this->exclude)
72059 ->setNames($this->names)
72060 ->setNotNames($this->notNames)
72061 ->setContains($this->contains)
72062 ->setNotContains($this->notContains)
72063 ->setSizes($this->sizes)
72064 ->setDates($this->dates)
72065 ->setFilters($this->filters)
72066 ->setSort($this->sort)
72067 ->setPath($this->paths)
72068 ->setNotPath($this->notPaths)
72069 ->ignoreUnreadableDirs($this->ignoreUnreadableDirs);
72070 }
72071
72072
72073
72074
72075 private function resetAdapterSelection()
72076 {
72077 $this->adapters = array_map(function (array $properties) {
72078 $properties['selected'] = false;
72079
72080 return $properties;
72081 }, $this->adapters);
72082 }
72083
72084 private function initDefaultAdapters()
72085 {
72086 if (null === $this->adapters) {
72087 $this->adapters = array();
72088 $this
72089 ->addAdapter(new GnuFindAdapter())
72090 ->addAdapter(new BsdFindAdapter())
72091 ->addAdapter(new PhpAdapter(), -50)
72092 ->setAdapter('php')
72093 ;
72094 }
72095 }
72096
72097
72098
72099
72100
72101
72102
72103
72104 private function normalizeDir($dir)
72105 {
72106 return rtrim($dir, '/'.\DIRECTORY_SEPARATOR);
72107 }
72108 }
72109 <?php
72110
72111
72112
72113
72114
72115
72116
72117
72118
72119
72120 namespace Symfony\Component\Finder;
72121
72122
72123
72124
72125
72126
72127
72128
72129
72130
72131
72132
72133
72134
72135
72136
72137
72138
72139
72140
72141
72142
72143
72144 class Glob
72145 {
72146
72147
72148
72149
72150
72151
72152
72153
72154
72155
72156 public static function toRegex($glob, $strictLeadingDot = true, $strictWildcardSlash = true, $delimiter = '#')
72157 {
72158 $firstByte = true;
72159 $escaping = false;
72160 $inCurlies = 0;
72161 $regex = '';
72162 $sizeGlob = \strlen($glob);
72163 for ($i = 0; $i < $sizeGlob; ++$i) {
72164 $car = $glob[$i];
72165 if ($firstByte) {
72166 if ($strictLeadingDot && '.' !== $car) {
72167 $regex .= '(?=[^\.])';
72168 }
72169
72170 $firstByte = false;
72171 }
72172
72173 if ('/' === $car) {
72174 $firstByte = true;
72175 }
72176
72177 if ($delimiter === $car || '.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
72178 $regex .= "\\$car";
72179 } elseif ('*' === $car) {
72180 $regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
72181 } elseif ('?' === $car) {
72182 $regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
72183 } elseif ('{' === $car) {
72184 $regex .= $escaping ? '\\{' : '(';
72185 if (!$escaping) {
72186 ++$inCurlies;
72187 }
72188 } elseif ('}' === $car && $inCurlies) {
72189 $regex .= $escaping ? '}' : ')';
72190 if (!$escaping) {
72191 --$inCurlies;
72192 }
72193 } elseif (',' === $car && $inCurlies) {
72194 $regex .= $escaping ? ',' : '|';
72195 } elseif ('\\' === $car) {
72196 if ($escaping) {
72197 $regex .= '\\\\';
72198 $escaping = false;
72199 } else {
72200 $escaping = true;
72201 }
72202
72203 continue;
72204 } else {
72205 $regex .= $car;
72206 }
72207 $escaping = false;
72208 }
72209
72210 return $delimiter.'^'.$regex.'$'.$delimiter;
72211 }
72212 }
72213 <?php
72214
72215
72216
72217
72218
72219
72220
72221
72222
72223
72224 namespace Symfony\Component\Finder\Iterator;
72225
72226
72227
72228
72229
72230
72231
72232
72233
72234 class CustomFilterIterator extends FilterIterator
72235 {
72236 private $filters = array();
72237
72238
72239
72240
72241
72242
72243
72244 public function __construct(\Iterator $iterator, array $filters)
72245 {
72246 foreach ($filters as $filter) {
72247 if (!\is_callable($filter)) {
72248 throw new \InvalidArgumentException('Invalid PHP callback.');
72249 }
72250 }
72251 $this->filters = $filters;
72252
72253 parent::__construct($iterator);
72254 }
72255
72256
72257
72258
72259
72260
72261 public function accept()
72262 {
72263 $fileinfo = $this->current();
72264
72265 foreach ($this->filters as $filter) {
72266 if (false === \call_user_func($filter, $fileinfo)) {
72267 return false;
72268 }
72269 }
72270
72271 return true;
72272 }
72273 }
72274 <?php
72275
72276
72277
72278
72279
72280
72281
72282
72283
72284
72285 namespace Symfony\Component\Finder\Iterator;
72286
72287 use Symfony\Component\Finder\Comparator\DateComparator;
72288
72289
72290
72291
72292
72293
72294 class DateRangeFilterIterator extends FilterIterator
72295 {
72296 private $comparators = array();
72297
72298
72299
72300
72301
72302 public function __construct(\Iterator $iterator, array $comparators)
72303 {
72304 $this->comparators = $comparators;
72305
72306 parent::__construct($iterator);
72307 }
72308
72309
72310
72311
72312
72313
72314 public function accept()
72315 {
72316 $fileinfo = $this->current();
72317
72318 if (!file_exists($fileinfo->getPathname())) {
72319 return false;
72320 }
72321
72322 $filedate = $fileinfo->getMTime();
72323 foreach ($this->comparators as $compare) {
72324 if (!$compare->test($filedate)) {
72325 return false;
72326 }
72327 }
72328
72329 return true;
72330 }
72331 }
72332 <?php
72333
72334
72335
72336
72337
72338
72339
72340
72341
72342
72343 namespace Symfony\Component\Finder\Iterator;
72344
72345
72346
72347
72348
72349
72350 class DepthRangeFilterIterator extends FilterIterator
72351 {
72352 private $minDepth = 0;
72353
72354
72355
72356
72357
72358
72359 public function __construct(\RecursiveIteratorIterator $iterator, $minDepth = 0, $maxDepth = PHP_INT_MAX)
72360 {
72361 $this->minDepth = $minDepth;
72362 $iterator->setMaxDepth(PHP_INT_MAX === $maxDepth ? -1 : $maxDepth);
72363
72364 parent::__construct($iterator);
72365 }
72366
72367
72368
72369
72370
72371
72372 public function accept()
72373 {
72374 return $this->getInnerIterator()->getDepth() >= $this->minDepth;
72375 }
72376 }
72377 <?php
72378
72379
72380
72381
72382
72383
72384
72385
72386
72387
72388 namespace Symfony\Component\Finder\Iterator;
72389
72390
72391
72392
72393
72394
72395 class ExcludeDirectoryFilterIterator extends FilterIterator implements \RecursiveIterator
72396 {
72397 private $iterator;
72398 private $isRecursive;
72399 private $excludedDirs = array();
72400 private $excludedPattern;
72401
72402
72403
72404
72405
72406 public function __construct(\Iterator $iterator, array $directories)
72407 {
72408 $this->iterator = $iterator;
72409 $this->isRecursive = $iterator instanceof \RecursiveIterator;
72410 $patterns = array();
72411 foreach ($directories as $directory) {
72412 $directory = rtrim($directory, '/');
72413 if (!$this->isRecursive || false !== strpos($directory, '/')) {
72414 $patterns[] = preg_quote($directory, '#');
72415 } else {
72416 $this->excludedDirs[$directory] = true;
72417 }
72418 }
72419 if ($patterns) {
72420 $this->excludedPattern = '#(?:^|/)(?:'.implode('|', $patterns).')(?:/|$)#';
72421 }
72422
72423 parent::__construct($iterator);
72424 }
72425
72426
72427
72428
72429
72430
72431 public function accept()
72432 {
72433 if ($this->isRecursive && isset($this->excludedDirs[$this->getFilename()]) && $this->isDir()) {
72434 return false;
72435 }
72436
72437 if ($this->excludedPattern) {
72438 $path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath();
72439 $path = str_replace('\\', '/', $path);
72440
72441 return !preg_match($this->excludedPattern, $path);
72442 }
72443
72444 return true;
72445 }
72446
72447 public function hasChildren()
72448 {
72449 return $this->isRecursive && $this->iterator->hasChildren();
72450 }
72451
72452 public function getChildren()
72453 {
72454 $children = new self($this->iterator->getChildren(), array());
72455 $children->excludedDirs = $this->excludedDirs;
72456 $children->excludedPattern = $this->excludedPattern;
72457
72458 return $children;
72459 }
72460 }
72461 <?php
72462
72463
72464
72465
72466
72467
72468
72469
72470
72471
72472 namespace Symfony\Component\Finder\Iterator;
72473
72474 @trigger_error('The '.__NAMESPACE__.'\FilePathsIterator class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
72475
72476 use Symfony\Component\Finder\SplFileInfo;
72477
72478
72479
72480
72481
72482
72483
72484
72485 class FilePathsIterator extends \ArrayIterator
72486 {
72487
72488
72489
72490 private $baseDir;
72491
72492
72493
72494
72495 private $baseDirLength;
72496
72497
72498
72499
72500 private $subPath;
72501
72502
72503
72504
72505 private $subPathname;
72506
72507
72508
72509
72510 private $current;
72511
72512
72513
72514
72515
72516 public function __construct(array $paths, $baseDir)
72517 {
72518 $this->baseDir = $baseDir;
72519 $this->baseDirLength = \strlen($baseDir);
72520
72521 parent::__construct($paths);
72522 }
72523
72524
72525
72526
72527
72528
72529
72530 public function __call($name, array $arguments)
72531 {
72532 return \call_user_func_array(array($this->current(), $name), $arguments);
72533 }
72534
72535
72536
72537
72538
72539
72540 public function current()
72541 {
72542 return $this->current;
72543 }
72544
72545
72546
72547
72548 public function key()
72549 {
72550 return $this->current->getPathname();
72551 }
72552
72553 public function next()
72554 {
72555 parent::next();
72556 $this->buildProperties();
72557 }
72558
72559 public function rewind()
72560 {
72561 parent::rewind();
72562 $this->buildProperties();
72563 }
72564
72565
72566
72567
72568 public function getSubPath()
72569 {
72570 return $this->subPath;
72571 }
72572
72573
72574
72575
72576 public function getSubPathname()
72577 {
72578 return $this->subPathname;
72579 }
72580
72581 private function buildProperties()
72582 {
72583 $absolutePath = parent::current();
72584
72585 if ($this->baseDir === substr($absolutePath, 0, $this->baseDirLength)) {
72586 $this->subPathname = ltrim(substr($absolutePath, $this->baseDirLength), '/\\');
72587 $dir = \dirname($this->subPathname);
72588 $this->subPath = '.' === $dir ? '' : $dir;
72589 } else {
72590 $this->subPath = $this->subPathname = '';
72591 }
72592
72593 $this->current = new SplFileInfo(parent::current(), $this->subPath, $this->subPathname);
72594 }
72595 }
72596 <?php
72597
72598
72599
72600
72601
72602
72603
72604
72605
72606
72607 namespace Symfony\Component\Finder\Iterator;
72608
72609
72610
72611
72612
72613
72614 class FileTypeFilterIterator extends FilterIterator
72615 {
72616 const ONLY_FILES = 1;
72617 const ONLY_DIRECTORIES = 2;
72618
72619 private $mode;
72620
72621
72622
72623
72624
72625 public function __construct(\Iterator $iterator, $mode)
72626 {
72627 $this->mode = $mode;
72628
72629 parent::__construct($iterator);
72630 }
72631
72632
72633
72634
72635
72636
72637 public function accept()
72638 {
72639 $fileinfo = $this->current();
72640 if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $fileinfo->isFile()) {
72641 return false;
72642 } elseif (self::ONLY_FILES === (self::ONLY_FILES & $this->mode) && $fileinfo->isDir()) {
72643 return false;
72644 }
72645
72646 return true;
72647 }
72648 }
72649 <?php
72650
72651
72652
72653
72654
72655
72656
72657
72658
72659
72660 namespace Symfony\Component\Finder\Iterator;
72661
72662
72663
72664
72665
72666
72667
72668 class FilecontentFilterIterator extends MultiplePcreFilterIterator
72669 {
72670
72671
72672
72673
72674
72675 public function accept()
72676 {
72677 if (!$this->matchRegexps && !$this->noMatchRegexps) {
72678 return true;
72679 }
72680
72681 $fileinfo = $this->current();
72682
72683 if ($fileinfo->isDir() || !$fileinfo->isReadable()) {
72684 return false;
72685 }
72686
72687 $content = $fileinfo->getContents();
72688 if (!$content) {
72689 return false;
72690 }
72691
72692 return $this->isAccepted($content);
72693 }
72694
72695
72696
72697
72698
72699
72700
72701
72702 protected function toRegex($str)
72703 {
72704 return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
72705 }
72706 }
72707 <?php
72708
72709
72710
72711
72712
72713
72714
72715
72716
72717
72718 namespace Symfony\Component\Finder\Iterator;
72719
72720 use Symfony\Component\Finder\Glob;
72721
72722
72723
72724
72725
72726
72727 class FilenameFilterIterator extends MultiplePcreFilterIterator
72728 {
72729
72730
72731
72732
72733
72734 public function accept()
72735 {
72736 return $this->isAccepted($this->current()->getFilename());
72737 }
72738
72739
72740
72741
72742
72743
72744
72745
72746
72747
72748
72749 protected function toRegex($str)
72750 {
72751 return $this->isRegex($str) ? $str : Glob::toRegex($str);
72752 }
72753 }
72754 <?php
72755
72756
72757
72758
72759
72760
72761
72762
72763
72764
72765 namespace Symfony\Component\Finder\Iterator;
72766
72767
72768
72769
72770
72771
72772
72773
72774
72775 abstract class FilterIterator extends \FilterIterator
72776 {
72777
72778
72779
72780
72781
72782
72783 public function rewind()
72784 {
72785 if (\PHP_VERSION_ID > 50607 || (\PHP_VERSION_ID > 50523 && \PHP_VERSION_ID < 50600)) {
72786 parent::rewind();
72787
72788 return;
72789 }
72790
72791 $iterator = $this;
72792 while ($iterator instanceof \OuterIterator) {
72793 $innerIterator = $iterator->getInnerIterator();
72794
72795 if ($innerIterator instanceof RecursiveDirectoryIterator) {
72796
72797 if ($innerIterator->isRewindable()) {
72798 $innerIterator->next();
72799 $innerIterator->rewind();
72800 }
72801 } elseif ($innerIterator instanceof \FilesystemIterator) {
72802 $innerIterator->next();
72803 $innerIterator->rewind();
72804 }
72805
72806 $iterator = $innerIterator;
72807 }
72808
72809 parent::rewind();
72810 }
72811 }
72812 <?php
72813
72814
72815
72816
72817
72818
72819
72820
72821
72822
72823 namespace Symfony\Component\Finder\Iterator;
72824
72825
72826
72827
72828
72829
72830 abstract class MultiplePcreFilterIterator extends FilterIterator
72831 {
72832 protected $matchRegexps = array();
72833 protected $noMatchRegexps = array();
72834
72835
72836
72837
72838
72839
72840 public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns)
72841 {
72842 foreach ($matchPatterns as $pattern) {
72843 $this->matchRegexps[] = $this->toRegex($pattern);
72844 }
72845
72846 foreach ($noMatchPatterns as $pattern) {
72847 $this->noMatchRegexps[] = $this->toRegex($pattern);
72848 }
72849
72850 parent::__construct($iterator);
72851 }
72852
72853
72854
72855
72856
72857
72858
72859
72860
72861
72862
72863
72864 protected function isAccepted($string)
72865 {
72866
72867 foreach ($this->noMatchRegexps as $regex) {
72868 if (preg_match($regex, $string)) {
72869 return false;
72870 }
72871 }
72872
72873
72874 if ($this->matchRegexps) {
72875 foreach ($this->matchRegexps as $regex) {
72876 if (preg_match($regex, $string)) {
72877 return true;
72878 }
72879 }
72880
72881 return false;
72882 }
72883
72884
72885 return true;
72886 }
72887
72888
72889
72890
72891
72892
72893
72894
72895 protected function isRegex($str)
72896 {
72897 if (preg_match('/^(.{3,}?)[imsxuADU]*$/', $str, $m)) {
72898 $start = substr($m[1], 0, 1);
72899 $end = substr($m[1], -1);
72900
72901 if ($start === $end) {
72902 return !preg_match('/[*?[:alnum:] \\\\]/', $start);
72903 }
72904
72905 foreach (array(array('{', '}'), array('(', ')'), array('[', ']'), array('<', '>')) as $delimiters) {
72906 if ($start === $delimiters[0] && $end === $delimiters[1]) {
72907 return true;
72908 }
72909 }
72910 }
72911
72912 return false;
72913 }
72914
72915
72916
72917
72918
72919
72920
72921
72922 abstract protected function toRegex($str);
72923 }
72924 <?php
72925
72926
72927
72928
72929
72930
72931
72932
72933
72934
72935 namespace Symfony\Component\Finder\Iterator;
72936
72937
72938
72939
72940
72941
72942
72943 class PathFilterIterator extends MultiplePcreFilterIterator
72944 {
72945
72946
72947
72948
72949
72950 public function accept()
72951 {
72952 $filename = $this->current()->getRelativePathname();
72953
72954 if ('\\' === \DIRECTORY_SEPARATOR) {
72955 $filename = str_replace('\\', '/', $filename);
72956 }
72957
72958 return $this->isAccepted($filename);
72959 }
72960
72961
72962
72963
72964
72965
72966
72967
72968
72969
72970
72971
72972
72973
72974
72975 protected function toRegex($str)
72976 {
72977 return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
72978 }
72979 }
72980 <?php
72981
72982
72983
72984
72985
72986
72987
72988
72989
72990
72991 namespace Symfony\Component\Finder\Iterator;
72992
72993 use Symfony\Component\Finder\Exception\AccessDeniedException;
72994 use Symfony\Component\Finder\SplFileInfo;
72995
72996
72997
72998
72999
73000
73001 class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
73002 {
73003
73004
73005
73006 private $ignoreUnreadableDirs;
73007
73008
73009
73010
73011 private $rewindable;
73012
73013
73014 private $rootPath;
73015 private $subPath;
73016 private $directorySeparator = '/';
73017
73018
73019
73020
73021
73022
73023
73024
73025 public function __construct($path, $flags, $ignoreUnreadableDirs = false)
73026 {
73027 if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
73028 throw new \RuntimeException('This iterator only support returning current as fileinfo.');
73029 }
73030
73031 parent::__construct($path, $flags);
73032 $this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
73033 $this->rootPath = (string) $path;
73034 if ('/' !== \DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) {
73035 $this->directorySeparator = \DIRECTORY_SEPARATOR;
73036 }
73037 }
73038
73039
73040
73041
73042
73043
73044 public function current()
73045 {
73046
73047
73048 if (null === $subPathname = $this->subPath) {
73049 $subPathname = $this->subPath = (string) $this->getSubPath();
73050 }
73051 if ('' !== $subPathname) {
73052 $subPathname .= $this->directorySeparator;
73053 }
73054 $subPathname .= $this->getFilename();
73055
73056 return new SplFileInfo($this->rootPath.$this->directorySeparator.$subPathname, $this->subPath, $subPathname);
73057 }
73058
73059
73060
73061
73062
73063
73064 public function getChildren()
73065 {
73066 try {
73067 $children = parent::getChildren();
73068
73069 if ($children instanceof self) {
73070
73071 $children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;
73072
73073
73074 $children->rewindable = &$this->rewindable;
73075 $children->rootPath = $this->rootPath;
73076 }
73077
73078 return $children;
73079 } catch (\UnexpectedValueException $e) {
73080 if ($this->ignoreUnreadableDirs) {
73081
73082 return new \RecursiveArrayIterator(array());
73083 } else {
73084 throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
73085 }
73086 }
73087 }
73088
73089
73090
73091
73092 public function rewind()
73093 {
73094 if (false === $this->isRewindable()) {
73095 return;
73096 }
73097
73098
73099 if (\PHP_VERSION_ID < 50523 || \PHP_VERSION_ID >= 50600 && \PHP_VERSION_ID < 50607) {
73100 parent::next();
73101 }
73102
73103 parent::rewind();
73104 }
73105
73106
73107
73108
73109
73110
73111 public function isRewindable()
73112 {
73113 if (null !== $this->rewindable) {
73114 return $this->rewindable;
73115 }
73116
73117
73118 if ('' === $this->getPath()) {
73119 return $this->rewindable = false;
73120 }
73121
73122 if (false !== $stream = @opendir($this->getPath())) {
73123 $infos = stream_get_meta_data($stream);
73124 closedir($stream);
73125
73126 if ($infos['seekable']) {
73127 return $this->rewindable = true;
73128 }
73129 }
73130
73131 return $this->rewindable = false;
73132 }
73133 }
73134 <?php
73135
73136
73137
73138
73139
73140
73141
73142
73143
73144
73145 namespace Symfony\Component\Finder\Iterator;
73146
73147 use Symfony\Component\Finder\Comparator\NumberComparator;
73148
73149
73150
73151
73152
73153
73154 class SizeRangeFilterIterator extends FilterIterator
73155 {
73156 private $comparators = array();
73157
73158
73159
73160
73161
73162 public function __construct(\Iterator $iterator, array $comparators)
73163 {
73164 $this->comparators = $comparators;
73165
73166 parent::__construct($iterator);
73167 }
73168
73169
73170
73171
73172
73173
73174 public function accept()
73175 {
73176 $fileinfo = $this->current();
73177 if (!$fileinfo->isFile()) {
73178 return true;
73179 }
73180
73181 $filesize = $fileinfo->getSize();
73182 foreach ($this->comparators as $compare) {
73183 if (!$compare->test($filesize)) {
73184 return false;
73185 }
73186 }
73187
73188 return true;
73189 }
73190 }
73191 <?php
73192
73193
73194
73195
73196
73197
73198
73199
73200
73201
73202 namespace Symfony\Component\Finder\Iterator;
73203
73204
73205
73206
73207
73208
73209 class SortableIterator implements \IteratorAggregate
73210 {
73211 const SORT_BY_NAME = 1;
73212 const SORT_BY_TYPE = 2;
73213 const SORT_BY_ACCESSED_TIME = 3;
73214 const SORT_BY_CHANGED_TIME = 4;
73215 const SORT_BY_MODIFIED_TIME = 5;
73216
73217 private $iterator;
73218 private $sort;
73219
73220
73221
73222
73223
73224
73225
73226 public function __construct(\Traversable $iterator, $sort)
73227 {
73228 $this->iterator = $iterator;
73229
73230 if (self::SORT_BY_NAME === $sort) {
73231 $this->sort = function ($a, $b) {
73232 return strcmp($a->getRealpath() ?: $a->getPathname(), $b->getRealpath() ?: $b->getPathname());
73233 };
73234 } elseif (self::SORT_BY_TYPE === $sort) {
73235 $this->sort = function ($a, $b) {
73236 if ($a->isDir() && $b->isFile()) {
73237 return -1;
73238 } elseif ($a->isFile() && $b->isDir()) {
73239 return 1;
73240 }
73241
73242 return strcmp($a->getRealpath() ?: $a->getPathname(), $b->getRealpath() ?: $b->getPathname());
73243 };
73244 } elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
73245 $this->sort = function ($a, $b) {
73246 return $a->getATime() - $b->getATime();
73247 };
73248 } elseif (self::SORT_BY_CHANGED_TIME === $sort) {
73249 $this->sort = function ($a, $b) {
73250 return $a->getCTime() - $b->getCTime();
73251 };
73252 } elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
73253 $this->sort = function ($a, $b) {
73254 return $a->getMTime() - $b->getMTime();
73255 };
73256 } elseif (\is_callable($sort)) {
73257 $this->sort = $sort;
73258 } else {
73259 throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');
73260 }
73261 }
73262
73263 public function getIterator()
73264 {
73265 $array = iterator_to_array($this->iterator, true);
73266 uasort($array, $this->sort);
73267
73268 return new \ArrayIterator($array);
73269 }
73270 }
73271 Copyright (c) 2004-2018 Fabien Potencier
73272
73273 Permission is hereby granted, free of charge, to any person obtaining a copy
73274 of this software and associated documentation files (the "Software"), to deal
73275 in the Software without restriction, including without limitation the rights
73276 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
73277 copies of the Software, and to permit persons to whom the Software is furnished
73278 to do so, subject to the following conditions:
73279
73280 The above copyright notice and this permission notice shall be included in all
73281 copies or substantial portions of the Software.
73282
73283 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
73284 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
73285 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
73286 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
73287 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
73288 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
73289 THE SOFTWARE.
73290 <?php
73291
73292
73293
73294
73295
73296
73297
73298
73299
73300
73301 namespace Symfony\Component\Finder\Shell;
73302
73303 @trigger_error('The '.__NAMESPACE__.'\Command class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
73304
73305
73306
73307
73308
73309
73310 class Command
73311 {
73312 private $parent;
73313 private $bits = array();
73314 private $labels = array();
73315
73316
73317
73318
73319 private $errorHandler;
73320
73321 public function __construct(Command $parent = null)
73322 {
73323 $this->parent = $parent;
73324 }
73325
73326
73327
73328
73329
73330
73331 public function __toString()
73332 {
73333 return $this->join();
73334 }
73335
73336
73337
73338
73339
73340
73341 public static function create(Command $parent = null)
73342 {
73343 return new self($parent);
73344 }
73345
73346
73347
73348
73349
73350
73351
73352
73353 public static function escape($input)
73354 {
73355 return escapeshellcmd($input);
73356 }
73357
73358
73359
73360
73361
73362
73363
73364
73365 public static function quote($input)
73366 {
73367 return escapeshellarg($input);
73368 }
73369
73370
73371
73372
73373
73374
73375
73376
73377 public function add($bit)
73378 {
73379 $this->bits[] = $bit;
73380
73381 return $this;
73382 }
73383
73384
73385
73386
73387
73388
73389
73390
73391 public function top($bit)
73392 {
73393 array_unshift($this->bits, $bit);
73394
73395 foreach ($this->labels as $label => $index) {
73396 ++$this->labels[$label];
73397 }
73398
73399 return $this;
73400 }
73401
73402
73403
73404
73405
73406
73407
73408
73409 public function arg($arg)
73410 {
73411 $this->bits[] = self::quote($arg);
73412
73413 return $this;
73414 }
73415
73416
73417
73418
73419
73420
73421
73422
73423 public function cmd($esc)
73424 {
73425 $this->bits[] = self::escape($esc);
73426
73427 return $this;
73428 }
73429
73430
73431
73432
73433
73434
73435
73436
73437
73438
73439 public function ins($label)
73440 {
73441 if (isset($this->labels[$label])) {
73442 throw new \RuntimeException(sprintf('Label "%s" already exists.', $label));
73443 }
73444
73445 $this->bits[] = self::create($this);
73446 $this->labels[$label] = \count($this->bits) - 1;
73447
73448 return $this->bits[$this->labels[$label]];
73449 }
73450
73451
73452
73453
73454
73455
73456
73457
73458
73459
73460 public function get($label)
73461 {
73462 if (!isset($this->labels[$label])) {
73463 throw new \RuntimeException(sprintf('Label "%s" does not exist.', $label));
73464 }
73465
73466 return $this->bits[$this->labels[$label]];
73467 }
73468
73469
73470
73471
73472
73473
73474
73475
73476 public function end()
73477 {
73478 if (null === $this->parent) {
73479 throw new \RuntimeException('Calling end on root command doesn\'t make sense.');
73480 }
73481
73482 return $this->parent;
73483 }
73484
73485
73486
73487
73488
73489
73490 public function length()
73491 {
73492 return \count($this->bits);
73493 }
73494
73495
73496
73497
73498 public function setErrorHandler(\Closure $errorHandler)
73499 {
73500 $this->errorHandler = $errorHandler;
73501
73502 return $this;
73503 }
73504
73505
73506
73507
73508 public function getErrorHandler()
73509 {
73510 return $this->errorHandler;
73511 }
73512
73513
73514
73515
73516
73517
73518
73519
73520 public function execute()
73521 {
73522 if (null === $errorHandler = $this->errorHandler) {
73523 exec($this->join(), $output);
73524 } else {
73525 $process = proc_open($this->join(), array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $pipes);
73526 $output = preg_split('~(\r\n|\r|\n)~', stream_get_contents($pipes[1]), -1, PREG_SPLIT_NO_EMPTY);
73527
73528 if ($error = stream_get_contents($pipes[2])) {
73529 $errorHandler($error);
73530 }
73531
73532 proc_close($process);
73533 }
73534
73535 return $output ?: array();
73536 }
73537
73538
73539
73540
73541
73542
73543 public function join()
73544 {
73545 return implode(' ', array_filter(
73546 array_map(function ($bit) {
73547 return $bit instanceof Command ? $bit->join() : ($bit ?: null);
73548 }, $this->bits),
73549 function ($bit) { return null !== $bit; }
73550 ));
73551 }
73552
73553
73554
73555
73556
73557
73558
73559
73560
73561 public function addAtIndex($bit, $index)
73562 {
73563 array_splice($this->bits, $index, 0, $bit instanceof self ? array($bit) : $bit);
73564
73565 return $this;
73566 }
73567 }
73568 <?php
73569
73570
73571
73572
73573
73574
73575
73576
73577
73578
73579 namespace Symfony\Component\Finder\Shell;
73580
73581 @trigger_error('The '.__NAMESPACE__.'\Shell class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
73582
73583
73584
73585
73586
73587
73588 class Shell
73589 {
73590 const TYPE_UNIX = 1;
73591 const TYPE_DARWIN = 2;
73592 const TYPE_CYGWIN = 3;
73593 const TYPE_WINDOWS = 4;
73594 const TYPE_BSD = 5;
73595
73596
73597
73598
73599 private $type;
73600
73601
73602
73603
73604
73605
73606 public function getType()
73607 {
73608 if (null === $this->type) {
73609 $this->type = $this->guessType();
73610 }
73611
73612 return $this->type;
73613 }
73614
73615
73616
73617
73618
73619
73620
73621
73622 public function testCommand($command)
73623 {
73624 if (!\function_exists('exec')) {
73625 return false;
73626 }
73627
73628
73629 $testCommand = 'which ';
73630 if (self::TYPE_WINDOWS === $this->type) {
73631 $testCommand = 'where ';
73632 }
73633
73634 $command = escapeshellcmd($command);
73635
73636 exec($testCommand.$command, $output, $code);
73637
73638 return 0 === $code && \count($output) > 0;
73639 }
73640
73641
73642
73643
73644
73645
73646 private function guessType()
73647 {
73648 $os = strtolower(PHP_OS);
73649
73650 if (false !== strpos($os, 'cygwin')) {
73651 return self::TYPE_CYGWIN;
73652 }
73653
73654 if (false !== strpos($os, 'darwin')) {
73655 return self::TYPE_DARWIN;
73656 }
73657
73658 if (false !== strpos($os, 'bsd')) {
73659 return self::TYPE_BSD;
73660 }
73661
73662 if (0 === strpos($os, 'win')) {
73663 return self::TYPE_WINDOWS;
73664 }
73665
73666 return self::TYPE_UNIX;
73667 }
73668 }
73669 <?php
73670
73671
73672
73673
73674
73675
73676
73677
73678
73679
73680 namespace Symfony\Component\Finder;
73681
73682
73683
73684
73685
73686
73687 class SplFileInfo extends \SplFileInfo
73688 {
73689 private $relativePath;
73690 private $relativePathname;
73691
73692
73693
73694
73695
73696
73697 public function __construct($file, $relativePath, $relativePathname)
73698 {
73699 parent::__construct($file);
73700 $this->relativePath = $relativePath;
73701 $this->relativePathname = $relativePathname;
73702 }
73703
73704
73705
73706
73707
73708
73709
73710
73711 public function getRelativePath()
73712 {
73713 return $this->relativePath;
73714 }
73715
73716
73717
73718
73719
73720
73721
73722
73723 public function getRelativePathname()
73724 {
73725 return $this->relativePathname;
73726 }
73727
73728
73729
73730
73731
73732
73733
73734
73735 public function getContents()
73736 {
73737 set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
73738 $content = file_get_contents($this->getPathname());
73739 restore_error_handler();
73740 if (false === $content) {
73741 throw new \RuntimeException($error);
73742 }
73743
73744 return $content;
73745 }
73746 }
73747 <?php
73748
73749
73750
73751
73752
73753
73754
73755
73756
73757
73758 namespace Symfony\Polyfill\Ctype;
73759
73760
73761
73762
73763
73764
73765
73766
73767 final class Ctype
73768 {
73769
73770
73771
73772
73773
73774
73775
73776
73777
73778 public static function ctype_alnum($text)
73779 {
73780 $text = self::convert_int_to_char_for_ctype($text);
73781
73782 return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text);
73783 }
73784
73785
73786
73787
73788
73789
73790
73791
73792
73793
73794 public static function ctype_alpha($text)
73795 {
73796 $text = self::convert_int_to_char_for_ctype($text);
73797
73798 return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text);
73799 }
73800
73801
73802
73803
73804
73805
73806
73807
73808
73809
73810 public static function ctype_cntrl($text)
73811 {
73812 $text = self::convert_int_to_char_for_ctype($text);
73813
73814 return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text);
73815 }
73816
73817
73818
73819
73820
73821
73822
73823
73824
73825
73826 public static function ctype_digit($text)
73827 {
73828 $text = self::convert_int_to_char_for_ctype($text);
73829
73830 return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text);
73831 }
73832
73833
73834
73835
73836
73837
73838
73839
73840
73841
73842 public static function ctype_graph($text)
73843 {
73844 $text = self::convert_int_to_char_for_ctype($text);
73845
73846 return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text);
73847 }
73848
73849
73850
73851
73852
73853
73854
73855
73856
73857
73858 public static function ctype_lower($text)
73859 {
73860 $text = self::convert_int_to_char_for_ctype($text);
73861
73862 return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text);
73863 }
73864
73865
73866
73867
73868
73869
73870
73871
73872
73873
73874 public static function ctype_print($text)
73875 {
73876 $text = self::convert_int_to_char_for_ctype($text);
73877
73878 return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text);
73879 }
73880
73881
73882
73883
73884
73885
73886
73887
73888
73889
73890 public static function ctype_punct($text)
73891 {
73892 $text = self::convert_int_to_char_for_ctype($text);
73893
73894 return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text);
73895 }
73896
73897
73898
73899
73900
73901
73902
73903
73904
73905
73906 public static function ctype_space($text)
73907 {
73908 $text = self::convert_int_to_char_for_ctype($text);
73909
73910 return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text);
73911 }
73912
73913
73914
73915
73916
73917
73918
73919
73920
73921
73922 public static function ctype_upper($text)
73923 {
73924 $text = self::convert_int_to_char_for_ctype($text);
73925
73926 return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text);
73927 }
73928
73929
73930
73931
73932
73933
73934
73935
73936
73937
73938 public static function ctype_xdigit($text)
73939 {
73940 $text = self::convert_int_to_char_for_ctype($text);
73941
73942 return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text);
73943 }
73944
73945
73946
73947
73948
73949
73950
73951
73952
73953
73954
73955
73956
73957 private static function convert_int_to_char_for_ctype($int)
73958 {
73959 if (!\is_int($int)) {
73960 return $int;
73961 }
73962
73963 if ($int < -128 || $int > 255) {
73964 return (string) $int;
73965 }
73966
73967 if ($int < 0) {
73968 $int += 256;
73969 }
73970
73971 return \chr($int);
73972 }
73973 }
73974 Copyright (c) 2018-2019 Fabien Potencier
73975
73976 Permission is hereby granted, free of charge, to any person obtaining a copy
73977 of this software and associated documentation files (the "Software"), to deal
73978 in the Software without restriction, including without limitation the rights
73979 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
73980 copies of the Software, and to permit persons to whom the Software is furnished
73981 to do so, subject to the following conditions:
73982
73983 The above copyright notice and this permission notice shall be included in all
73984 copies or substantial portions of the Software.
73985
73986 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
73987 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
73988 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
73989 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
73990 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
73991 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
73992 THE SOFTWARE.
73993 <?php
73994
73995
73996
73997
73998
73999
74000
74001
74002
74003
74004 use Symfony\Polyfill\Ctype as p;
74005
74006 if (!function_exists('ctype_alnum')) {
74007 function ctype_alnum($input) { return p\Ctype::ctype_alnum($input); }
74008 }
74009 if (!function_exists('ctype_alpha')) {
74010 function ctype_alpha($input) { return p\Ctype::ctype_alpha($input); }
74011 }
74012 if (!function_exists('ctype_cntrl')) {
74013 function ctype_cntrl($input) { return p\Ctype::ctype_cntrl($input); }
74014 }
74015 if (!function_exists('ctype_digit')) {
74016 function ctype_digit($input) { return p\Ctype::ctype_digit($input); }
74017 }
74018 if (!function_exists('ctype_graph')) {
74019 function ctype_graph($input) { return p\Ctype::ctype_graph($input); }
74020 }
74021 if (!function_exists('ctype_lower')) {
74022 function ctype_lower($input) { return p\Ctype::ctype_lower($input); }
74023 }
74024 if (!function_exists('ctype_print')) {
74025 function ctype_print($input) { return p\Ctype::ctype_print($input); }
74026 }
74027 if (!function_exists('ctype_punct')) {
74028 function ctype_punct($input) { return p\Ctype::ctype_punct($input); }
74029 }
74030 if (!function_exists('ctype_space')) {
74031 function ctype_space($input) { return p\Ctype::ctype_space($input); }
74032 }
74033 if (!function_exists('ctype_upper')) {
74034 function ctype_upper($input) { return p\Ctype::ctype_upper($input); }
74035 }
74036 if (!function_exists('ctype_xdigit')) {
74037 function ctype_xdigit($input) { return p\Ctype::ctype_xdigit($input); }
74038 }
74039 Copyright (c) 2015-2019 Fabien Potencier
74040
74041 Permission is hereby granted, free of charge, to any person obtaining a copy
74042 of this software and associated documentation files (the "Software"), to deal
74043 in the Software without restriction, including without limitation the rights
74044 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
74045 copies of the Software, and to permit persons to whom the Software is furnished
74046 to do so, subject to the following conditions:
74047
74048 The above copyright notice and this permission notice shall be included in all
74049 copies or substantial portions of the Software.
74050
74051 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
74052 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
74053 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
74054 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
74055 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
74056 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
74057 THE SOFTWARE.
74058 <?php
74059
74060
74061
74062
74063
74064
74065
74066
74067
74068
74069 namespace Symfony\Polyfill\Mbstring;
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
74116
74117
74118
74119
74120
74121
74122
74123
74124
74125 final class Mbstring
74126 {
74127 const MB_CASE_FOLD = PHP_INT_MAX;
74128
74129 private static $encodingList = array('ASCII', 'UTF-8');
74130 private static $language = 'neutral';
74131 private static $internalEncoding = 'UTF-8';
74132 private static $caseFold = array(
74133 array('µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"),
74134 array('μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'),
74135 );
74136
74137 public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
74138 {
74139 if (\is_array($fromEncoding) || false !== strpos($fromEncoding, ',')) {
74140 $fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
74141 } else {
74142 $fromEncoding = self::getEncoding($fromEncoding);
74143 }
74144
74145 $toEncoding = self::getEncoding($toEncoding);
74146
74147 if ('BASE64' === $fromEncoding) {
74148 $s = base64_decode($s);
74149 $fromEncoding = $toEncoding;
74150 }
74151
74152 if ('BASE64' === $toEncoding) {
74153 return base64_encode($s);
74154 }
74155
74156 if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {
74157 if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {
74158 $fromEncoding = 'Windows-1252';
74159 }
74160 if ('UTF-8' !== $fromEncoding) {
74161 $s = iconv($fromEncoding, 'UTF-8//IGNORE', $s);
74162 }
74163
74164 return preg_replace_callback('/[\x80-\xFF]+/', array(__CLASS__, 'html_encoding_callback'), $s);
74165 }
74166
74167 if ('HTML-ENTITIES' === $fromEncoding) {
74168 $s = html_entity_decode($s, ENT_COMPAT, 'UTF-8');
74169 $fromEncoding = 'UTF-8';
74170 }
74171
74172 return iconv($fromEncoding, $toEncoding.'//IGNORE', $s);
74173 }
74174
74175 public static function mb_convert_variables($toEncoding, $fromEncoding, &$a = null, &$b = null, &$c = null, &$d = null, &$e = null, &$f = null)
74176 {
74177 $vars = array(&$a, &$b, &$c, &$d, &$e, &$f);
74178
74179 $ok = true;
74180 array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
74181 if (false === $v = Mbstring::mb_convert_encoding($v, $toEncoding, $fromEncoding)) {
74182 $ok = false;
74183 }
74184 });
74185
74186 return $ok ? $fromEncoding : false;
74187 }
74188
74189 public static function mb_decode_mimeheader($s)
74190 {
74191 return iconv_mime_decode($s, 2, self::$internalEncoding);
74192 }
74193
74194 public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)
74195 {
74196 trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', E_USER_WARNING);
74197 }
74198
74199 public static function mb_decode_numericentity($s, $convmap, $encoding = null)
74200 {
74201 if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) {
74202 trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', E_USER_WARNING);
74203
74204 return null;
74205 }
74206
74207 if (!\is_array($convmap) || !$convmap) {
74208 return false;
74209 }
74210
74211 if (null !== $encoding && !\is_scalar($encoding)) {
74212 trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', E_USER_WARNING);
74213
74214 return ''; 
74215 }
74216
74217 $s = (string) $s;
74218 if ('' === $s) {
74219 return '';
74220 }
74221
74222 $encoding = self::getEncoding($encoding);
74223
74224 if ('UTF-8' === $encoding) {
74225 $encoding = null;
74226 if (!preg_match('//u', $s)) {
74227 $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
74228 }
74229 } else {
74230 $s = iconv($encoding, 'UTF-8//IGNORE', $s);
74231 }
74232
74233 $cnt = floor(\count($convmap) / 4) * 4;
74234
74235 for ($i = 0; $i < $cnt; $i += 4) {
74236
74237 $convmap[$i] += $convmap[$i + 2];
74238 $convmap[$i + 1] += $convmap[$i + 2];
74239 }
74240
74241 $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) {
74242 $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];
74243 for ($i = 0; $i < $cnt; $i += 4) {
74244 if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
74245 return Mbstring::mb_chr($c - $convmap[$i + 2]);
74246 }
74247 }
74248
74249 return $m[0];
74250 }, $s);
74251
74252 if (null === $encoding) {
74253 return $s;
74254 }
74255
74256 return iconv('UTF-8', $encoding.'//IGNORE', $s);
74257 }
74258
74259 public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)
74260 {
74261 if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) {
74262 trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', E_USER_WARNING);
74263
74264 return null;
74265 }
74266
74267 if (!\is_array($convmap) || !$convmap) {
74268 return false;
74269 }
74270
74271 if (null !== $encoding && !\is_scalar($encoding)) {
74272 trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', E_USER_WARNING);
74273
74274 return null; 
74275 }
74276
74277 if (null !== $is_hex && !\is_scalar($is_hex)) {
74278 trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', E_USER_WARNING);
74279
74280 return null;
74281 }
74282
74283 $s = (string) $s;
74284 if ('' === $s) {
74285 return '';
74286 }
74287
74288 $encoding = self::getEncoding($encoding);
74289
74290 if ('UTF-8' === $encoding) {
74291 $encoding = null;
74292 if (!preg_match('//u', $s)) {
74293 $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
74294 }
74295 } else {
74296 $s = iconv($encoding, 'UTF-8//IGNORE', $s);
74297 }
74298
74299 static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
74300
74301 $cnt = floor(\count($convmap) / 4) * 4;
74302 $i = 0;
74303 $len = \strlen($s);
74304 $result = '';
74305
74306 while ($i < $len) {
74307 $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
74308 $uchr = substr($s, $i, $ulen);
74309 $i += $ulen;
74310 $c = self::mb_ord($uchr);
74311
74312 for ($j = 0; $j < $cnt; $j += 4) {
74313 if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
74314 $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];
74315 $result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
74316 continue 2;
74317 }
74318 }
74319 $result .= $uchr;
74320 }
74321
74322 if (null === $encoding) {
74323 return $result;
74324 }
74325
74326 return iconv('UTF-8', $encoding.'//IGNORE', $result);
74327 }
74328
74329 public static function mb_convert_case($s, $mode, $encoding = null)
74330 {
74331 $s = (string) $s;
74332 if ('' === $s) {
74333 return '';
74334 }
74335
74336 $encoding = self::getEncoding($encoding);
74337
74338 if ('UTF-8' === $encoding) {
74339 $encoding = null;
74340 if (!preg_match('//u', $s)) {
74341 $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
74342 }
74343 } else {
74344 $s = iconv($encoding, 'UTF-8//IGNORE', $s);
74345 }
74346
74347 if (MB_CASE_TITLE == $mode) {
74348 static $titleRegexp = null;
74349 if (null === $titleRegexp) {
74350 $titleRegexp = self::getData('titleCaseRegexp');
74351 }
74352 $s = preg_replace_callback($titleRegexp, array(__CLASS__, 'title_case'), $s);
74353 } else {
74354 if (MB_CASE_UPPER == $mode) {
74355 static $upper = null;
74356 if (null === $upper) {
74357 $upper = self::getData('upperCase');
74358 }
74359 $map = $upper;
74360 } else {
74361 if (self::MB_CASE_FOLD === $mode) {
74362 $s = str_replace(self::$caseFold[0], self::$caseFold[1], $s);
74363 }
74364
74365 static $lower = null;
74366 if (null === $lower) {
74367 $lower = self::getData('lowerCase');
74368 }
74369 $map = $lower;
74370 }
74371
74372 static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
74373
74374 $i = 0;
74375 $len = \strlen($s);
74376
74377 while ($i < $len) {
74378 $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
74379 $uchr = substr($s, $i, $ulen);
74380 $i += $ulen;
74381
74382 if (isset($map[$uchr])) {
74383 $uchr = $map[$uchr];
74384 $nlen = \strlen($uchr);
74385
74386 if ($nlen == $ulen) {
74387 $nlen = $i;
74388 do {
74389 $s[--$nlen] = $uchr[--$ulen];
74390 } while ($ulen);
74391 } else {
74392 $s = substr_replace($s, $uchr, $i - $ulen, $ulen);
74393 $len += $nlen - $ulen;
74394 $i += $nlen - $ulen;
74395 }
74396 }
74397 }
74398 }
74399
74400 if (null === $encoding) {
74401 return $s;
74402 }
74403
74404 return iconv('UTF-8', $encoding.'//IGNORE', $s);
74405 }
74406
74407 public static function mb_internal_encoding($encoding = null)
74408 {
74409 if (null === $encoding) {
74410 return self::$internalEncoding;
74411 }
74412
74413 $encoding = self::getEncoding($encoding);
74414
74415 if ('UTF-8' === $encoding || false !== @iconv($encoding, $encoding, ' ')) {
74416 self::$internalEncoding = $encoding;
74417
74418 return true;
74419 }
74420
74421 return false;
74422 }
74423
74424 public static function mb_language($lang = null)
74425 {
74426 if (null === $lang) {
74427 return self::$language;
74428 }
74429
74430 switch ($lang = strtolower($lang)) {
74431 case 'uni':
74432 case 'neutral':
74433 self::$language = $lang;
74434
74435 return true;
74436 }
74437
74438 return false;
74439 }
74440
74441 public static function mb_list_encodings()
74442 {
74443 return array('UTF-8');
74444 }
74445
74446 public static function mb_encoding_aliases($encoding)
74447 {
74448 switch (strtoupper($encoding)) {
74449 case 'UTF8':
74450 case 'UTF-8':
74451 return array('utf8');
74452 }
74453
74454 return false;
74455 }
74456
74457 public static function mb_check_encoding($var = null, $encoding = null)
74458 {
74459 if (null === $encoding) {
74460 if (null === $var) {
74461 return false;
74462 }
74463 $encoding = self::$internalEncoding;
74464 }
74465
74466 return self::mb_detect_encoding($var, array($encoding)) || false !== @iconv($encoding, $encoding, $var);
74467 }
74468
74469 public static function mb_detect_encoding($str, $encodingList = null, $strict = false)
74470 {
74471 if (null === $encodingList) {
74472 $encodingList = self::$encodingList;
74473 } else {
74474 if (!\is_array($encodingList)) {
74475 $encodingList = array_map('trim', explode(',', $encodingList));
74476 }
74477 $encodingList = array_map('strtoupper', $encodingList);
74478 }
74479
74480 foreach ($encodingList as $enc) {
74481 switch ($enc) {
74482 case 'ASCII':
74483 if (!preg_match('/[\x80-\xFF]/', $str)) {
74484 return $enc;
74485 }
74486 break;
74487
74488 case 'UTF8':
74489 case 'UTF-8':
74490 if (preg_match('//u', $str)) {
74491 return 'UTF-8';
74492 }
74493 break;
74494
74495 default:
74496 if (0 === strncmp($enc, 'ISO-8859-', 9)) {
74497 return $enc;
74498 }
74499 }
74500 }
74501
74502 return false;
74503 }
74504
74505 public static function mb_detect_order($encodingList = null)
74506 {
74507 if (null === $encodingList) {
74508 return self::$encodingList;
74509 }
74510
74511 if (!\is_array($encodingList)) {
74512 $encodingList = array_map('trim', explode(',', $encodingList));
74513 }
74514 $encodingList = array_map('strtoupper', $encodingList);
74515
74516 foreach ($encodingList as $enc) {
74517 switch ($enc) {
74518 default:
74519 if (strncmp($enc, 'ISO-8859-', 9)) {
74520 return false;
74521 }
74522
74523 case 'ASCII':
74524 case 'UTF8':
74525 case 'UTF-8':
74526 }
74527 }
74528
74529 self::$encodingList = $encodingList;
74530
74531 return true;
74532 }
74533
74534 public static function mb_strlen($s, $encoding = null)
74535 {
74536 $encoding = self::getEncoding($encoding);
74537 if ('CP850' === $encoding || 'ASCII' === $encoding) {
74538 return \strlen($s);
74539 }
74540
74541 return @iconv_strlen($s, $encoding);
74542 }
74543
74544 public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
74545 {
74546 $encoding = self::getEncoding($encoding);
74547 if ('CP850' === $encoding || 'ASCII' === $encoding) {
74548 return strpos($haystack, $needle, $offset);
74549 }
74550
74551 $needle = (string) $needle;
74552 if ('' === $needle) {
74553 trigger_error(__METHOD__.': Empty delimiter', E_USER_WARNING);
74554
74555 return false;
74556 }
74557
74558 return iconv_strpos($haystack, $needle, $offset, $encoding);
74559 }
74560
74561 public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
74562 {
74563 $encoding = self::getEncoding($encoding);
74564 if ('CP850' === $encoding || 'ASCII' === $encoding) {
74565 return strrpos($haystack, $needle, $offset);
74566 }
74567
74568 if ($offset != (int) $offset) {
74569 $offset = 0;
74570 } elseif ($offset = (int) $offset) {
74571 if ($offset < 0) {
74572 if (0 > $offset += self::mb_strlen($needle)) {
74573 $haystack = self::mb_substr($haystack, 0, $offset, $encoding);
74574 }
74575 $offset = 0;
74576 } else {
74577 $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
74578 }
74579 }
74580
74581 $pos = iconv_strrpos($haystack, $needle, $encoding);
74582
74583 return false !== $pos ? $offset + $pos : false;
74584 }
74585
74586 public static function mb_str_split($string, $split_length = 1, $encoding = null)
74587 {
74588 if (null !== $string && !\is_scalar($string) && !(\is_object($string) && \method_exists($string, '__toString'))) {
74589 trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', E_USER_WARNING);
74590
74591 return null;
74592 }
74593
74594 if (1 > $split_length = (int) $split_length) {
74595 trigger_error('The length of each segment must be greater than zero', E_USER_WARNING);
74596
74597 return false;
74598 }
74599
74600 if (null === $encoding) {
74601 $encoding = mb_internal_encoding();
74602 }
74603
74604 if ('UTF-8' === $encoding = self::getEncoding($encoding)) {
74605 $rx = '/(';
74606 while (65535 < $split_length) {
74607 $rx .= '.{65535}';
74608 $split_length -= 65535;
74609 }
74610 $rx .= '.{'.$split_length.'})/us';
74611
74612 return preg_split($rx, $string, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
74613 }
74614
74615 $result = array();
74616 $length = mb_strlen($string, $encoding);
74617
74618 for ($i = 0; $i < $length; $i += $split_length) {
74619 $result[] = mb_substr($string, $i, $split_length, $encoding);
74620 }
74621
74622 return $result;
74623 }
74624
74625 public static function mb_strtolower($s, $encoding = null)
74626 {
74627 return self::mb_convert_case($s, MB_CASE_LOWER, $encoding);
74628 }
74629
74630 public static function mb_strtoupper($s, $encoding = null)
74631 {
74632 return self::mb_convert_case($s, MB_CASE_UPPER, $encoding);
74633 }
74634
74635 public static function mb_substitute_character($c = null)
74636 {
74637 if (0 === strcasecmp($c, 'none')) {
74638 return true;
74639 }
74640
74641 return null !== $c ? false : 'none';
74642 }
74643
74644 public static function mb_substr($s, $start, $length = null, $encoding = null)
74645 {
74646 $encoding = self::getEncoding($encoding);
74647 if ('CP850' === $encoding || 'ASCII' === $encoding) {
74648 return (string) substr($s, $start, null === $length ? 2147483647 : $length);
74649 }
74650
74651 if ($start < 0) {
74652 $start = iconv_strlen($s, $encoding) + $start;
74653 if ($start < 0) {
74654 $start = 0;
74655 }
74656 }
74657
74658 if (null === $length) {
74659 $length = 2147483647;
74660 } elseif ($length < 0) {
74661 $length = iconv_strlen($s, $encoding) + $length - $start;
74662 if ($length < 0) {
74663 return '';
74664 }
74665 }
74666
74667 return (string) iconv_substr($s, $start, $length, $encoding);
74668 }
74669
74670 public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
74671 {
74672 $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
74673 $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
74674
74675 return self::mb_strpos($haystack, $needle, $offset, $encoding);
74676 }
74677
74678 public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)
74679 {
74680 $pos = self::mb_stripos($haystack, $needle, 0, $encoding);
74681
74682 return self::getSubpart($pos, $part, $haystack, $encoding);
74683 }
74684
74685 public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)
74686 {
74687 $encoding = self::getEncoding($encoding);
74688 if ('CP850' === $encoding || 'ASCII' === $encoding) {
74689 $pos = strrpos($haystack, $needle);
74690 } else {
74691 $needle = self::mb_substr($needle, 0, 1, $encoding);
74692 $pos = iconv_strrpos($haystack, $needle, $encoding);
74693 }
74694
74695 return self::getSubpart($pos, $part, $haystack, $encoding);
74696 }
74697
74698 public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
74699 {
74700 $needle = self::mb_substr($needle, 0, 1, $encoding);
74701 $pos = self::mb_strripos($haystack, $needle, $encoding);
74702
74703 return self::getSubpart($pos, $part, $haystack, $encoding);
74704 }
74705
74706 public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
74707 {
74708 $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
74709 $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
74710
74711 return self::mb_strrpos($haystack, $needle, $offset, $encoding);
74712 }
74713
74714 public static function mb_strstr($haystack, $needle, $part = false, $encoding = null)
74715 {
74716 $pos = strpos($haystack, $needle);
74717 if (false === $pos) {
74718 return false;
74719 }
74720 if ($part) {
74721 return substr($haystack, 0, $pos);
74722 }
74723
74724 return substr($haystack, $pos);
74725 }
74726
74727 public static function mb_get_info($type = 'all')
74728 {
74729 $info = array(
74730 'internal_encoding' => self::$internalEncoding,
74731 'http_output' => 'pass',
74732 'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)',
74733 'func_overload' => 0,
74734 'func_overload_list' => 'no overload',
74735 'mail_charset' => 'UTF-8',
74736 'mail_header_encoding' => 'BASE64',
74737 'mail_body_encoding' => 'BASE64',
74738 'illegal_chars' => 0,
74739 'encoding_translation' => 'Off',
74740 'language' => self::$language,
74741 'detect_order' => self::$encodingList,
74742 'substitute_character' => 'none',
74743 'strict_detection' => 'Off',
74744 );
74745
74746 if ('all' === $type) {
74747 return $info;
74748 }
74749 if (isset($info[$type])) {
74750 return $info[$type];
74751 }
74752
74753 return false;
74754 }
74755
74756 public static function mb_http_input($type = '')
74757 {
74758 return false;
74759 }
74760
74761 public static function mb_http_output($encoding = null)
74762 {
74763 return null !== $encoding ? 'pass' === $encoding : 'pass';
74764 }
74765
74766 public static function mb_strwidth($s, $encoding = null)
74767 {
74768 $encoding = self::getEncoding($encoding);
74769
74770 if ('UTF-8' !== $encoding) {
74771 $s = iconv($encoding, 'UTF-8//IGNORE', $s);
74772 }
74773
74774 $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);
74775
74776 return ($wide << 1) + iconv_strlen($s, 'UTF-8');
74777 }
74778
74779 public static function mb_substr_count($haystack, $needle, $encoding = null)
74780 {
74781 return substr_count($haystack, $needle);
74782 }
74783
74784 public static function mb_output_handler($contents, $status)
74785 {
74786 return $contents;
74787 }
74788
74789 public static function mb_chr($code, $encoding = null)
74790 {
74791 if (0x80 > $code %= 0x200000) {
74792 $s = \chr($code);
74793 } elseif (0x800 > $code) {
74794 $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
74795 } elseif (0x10000 > $code) {
74796 $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
74797 } else {
74798 $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
74799 }
74800
74801 if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
74802 $s = mb_convert_encoding($s, $encoding, 'UTF-8');
74803 }
74804
74805 return $s;
74806 }
74807
74808 public static function mb_ord($s, $encoding = null)
74809 {
74810 if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
74811 $s = mb_convert_encoding($s, 'UTF-8', $encoding);
74812 }
74813
74814 if (1 === \strlen($s)) {
74815 return \ord($s);
74816 }
74817
74818 $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
74819 if (0xF0 <= $code) {
74820 return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
74821 }
74822 if (0xE0 <= $code) {
74823 return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
74824 }
74825 if (0xC0 <= $code) {
74826 return (($code - 0xC0) << 6) + $s[2] - 0x80;
74827 }
74828
74829 return $code;
74830 }
74831
74832 private static function getSubpart($pos, $part, $haystack, $encoding)
74833 {
74834 if (false === $pos) {
74835 return false;
74836 }
74837 if ($part) {
74838 return self::mb_substr($haystack, 0, $pos, $encoding);
74839 }
74840
74841 return self::mb_substr($haystack, $pos, null, $encoding);
74842 }
74843
74844 private static function html_encoding_callback(array $m)
74845 {
74846 $i = 1;
74847 $entities = '';
74848 $m = unpack('C*', htmlentities($m[0], ENT_COMPAT, 'UTF-8'));
74849
74850 while (isset($m[$i])) {
74851 if (0x80 > $m[$i]) {
74852 $entities .= \chr($m[$i++]);
74853 continue;
74854 }
74855 if (0xF0 <= $m[$i]) {
74856 $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
74857 } elseif (0xE0 <= $m[$i]) {
74858 $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
74859 } else {
74860 $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
74861 }
74862
74863 $entities .= '&#'.$c.';';
74864 }
74865
74866 return $entities;
74867 }
74868
74869 private static function title_case(array $s)
74870 {
74871 return self::mb_convert_case($s[1], MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], MB_CASE_LOWER, 'UTF-8');
74872 }
74873
74874 private static function getData($file)
74875 {
74876 if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
74877 return require $file;
74878 }
74879
74880 return false;
74881 }
74882
74883 private static function getEncoding($encoding)
74884 {
74885 if (null === $encoding) {
74886 return self::$internalEncoding;
74887 }
74888
74889 if ('UTF-8' === $encoding) {
74890 return 'UTF-8';
74891 }
74892
74893 $encoding = strtoupper($encoding);
74894
74895 if ('8BIT' === $encoding || 'BINARY' === $encoding) {
74896 return 'CP850';
74897 }
74898
74899 if ('UTF8' === $encoding) {
74900 return 'UTF-8';
74901 }
74902
74903 return $encoding;
74904 }
74905 }
74906 <?php
74907
74908 return array (
74909 'A' => 'a',
74910 'B' => 'b',
74911 'C' => 'c',
74912 'D' => 'd',
74913 'E' => 'e',
74914 'F' => 'f',
74915 'G' => 'g',
74916 'H' => 'h',
74917 'I' => 'i',
74918 'J' => 'j',
74919 'K' => 'k',
74920 'L' => 'l',
74921 'M' => 'm',
74922 'N' => 'n',
74923 'O' => 'o',
74924 'P' => 'p',
74925 'Q' => 'q',
74926 'R' => 'r',
74927 'S' => 's',
74928 'T' => 't',
74929 'U' => 'u',
74930 'V' => 'v',
74931 'W' => 'w',
74932 'X' => 'x',
74933 'Y' => 'y',
74934 'Z' => 'z',
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 'Ĝ' => 'ĝ',
74980 'Ğ' => 'ğ',
74981 'Ġ' => 'ġ',
74982 'Ģ' => 'ģ',
74983 'Ĥ' => 'ĥ',
74984 'Ħ' => 'ħ',
74985 'Ĩ' => 'ĩ',
74986 'Ī' => 'ī',
74987 'Ĭ' => 'ĭ',
74988 'Į' => 'į',
74989 'İ' => 'i',
74990 'IJ' => 'ij',
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 'Ƭ' => 'ƭ',
75055 'Ʈ' => 'ʈ',
75056 'Ư' => 'ư',
75057 'Ʊ' => 'ʊ',
75058 'Ʋ' => 'ʋ',
75059 'Ƴ' => 'ƴ',
75060 'Ƶ' => 'ƶ',
75061 'Ʒ' => 'ʒ',
75062 'Ƹ' => 'ƹ',
75063 'Ƽ' => 'ƽ',
75064 'DŽ' => 'dž',
75065 'Dž' => 'dž',
75066 'LJ' => 'lj',
75067 'Lj' => 'lj',
75068 'NJ' => 'nj',
75069 'Nj' => 'nj',
75070 'Ǎ' => 'ǎ',
75071 'Ǐ' => 'ǐ',
75072 'Ǒ' => 'ǒ',
75073 'Ǔ' => 'ǔ',
75074 'Ǖ' => 'ǖ',
75075 'Ǘ' => 'ǘ',
75076 'Ǚ' => 'ǚ',
75077 'Ǜ' => 'ǜ',
75078 'Ǟ' => 'ǟ',
75079 'Ǡ' => 'ǡ',
75080 'Ǣ' => 'ǣ',
75081 'Ǥ' => 'ǥ',
75082 'Ǧ' => 'ǧ',
75083 'Ǩ' => 'ǩ',
75084 'Ǫ' => 'ǫ',
75085 'Ǭ' => 'ǭ',
75086 'Ǯ' => 'ǯ',
75087 'DZ' => 'dz',
75088 'Dz' => 'dz',
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 'Ῡ' => 'ῡ',
75762 'Ὺ' => 'ὺ',
75763 'Ύ' => 'ύ',
75764 'Ῥ' => 'ῥ',
75765 'Ὸ' => 'ὸ',
75766 'Ό' => 'ό',
75767 'Ὼ' => 'ὼ',
75768 'Ώ' => 'ώ',
75769 'ῼ' => 'ῳ',
75770 'Ω' => 'ω',
75771 'K' => 'k',
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 'Ꞻ' => 'ꞻ',
76042 'Ꞽ' => 'ꞽ',
76043 'Ꞿ' => 'ꞿ',
76044 'Ꟃ' => 'ꟃ',
76045 'Ꞔ' => 'ꞔ',
76046 'Ʂ' => 'ʂ',
76047 'Ᶎ' => 'ᶎ',
76048 'Ꟈ' => 'ꟈ',
76049 'Ꟊ' => 'ꟊ',
76050 'Ꟶ' => 'ꟶ',
76051 'A' => 'a',
76052 'B' => 'b',
76053 'C' => 'c',
76054 'D' => 'd',
76055 'E' => 'e',
76056 'F' => 'f',
76057 'G' => 'g',
76058 'H' => 'h',
76059 'I' => 'i',
76060 'J' => 'j',
76061 'K' => 'k',
76062 'L' => 'l',
76063 'M' => 'm',
76064 'N' => 'n',
76065 'O' => 'o',
76066 'P' => 'p',
76067 'Q' => 'q',
76068 'R' => 'r',
76069 'S' => 's',
76070 'T' => 't',
76071 'U' => 'u',
76072 'V' => 'v',
76073 'W' => 'w',
76074 'X' => 'x',
76075 'Y' => 'y',
76076 'Z' => 'z',
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 '𞤙' => '𞤻',
76294 '𞤚' => '𞤼',
76295 '𞤛' => '𞤽',
76296 '𞤜' => '𞤾',
76297 '𞤝' => '𞤿',
76298 '𞤞' => '𞥀',
76299 '𞤟' => '𞥁',
76300 '𞤠' => '𞥂',
76301 '𞤡' => '𞥃',
76302 );
76303 <?php
76304
76305
76306
76307 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';
76308 <?php
76309
76310 return array (
76311 'a' => 'A',
76312 'b' => 'B',
76313 'c' => 'C',
76314 'd' => 'D',
76315 'e' => 'E',
76316 'f' => 'F',
76317 'g' => 'G',
76318 'h' => 'H',
76319 'i' => 'I',
76320 'j' => 'J',
76321 'k' => 'K',
76322 'l' => 'L',
76323 'm' => 'M',
76324 'n' => 'N',
76325 'o' => 'O',
76326 'p' => 'P',
76327 'q' => 'Q',
76328 'r' => 'R',
76329 's' => 'S',
76330 't' => 'T',
76331 'u' => 'U',
76332 'v' => 'V',
76333 'w' => 'W',
76334 'x' => 'X',
76335 'y' => 'Y',
76336 'z' => 'Z',
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 'ĝ' => 'Ĝ',
76384 'ğ' => 'Ğ',
76385 'ġ' => 'Ġ',
76386 'ģ' => 'Ģ',
76387 'ĥ' => 'Ĥ',
76388 'ħ' => 'Ħ',
76389 'ĩ' => 'Ĩ',
76390 'ī' => 'Ī',
76391 'ĭ' => 'Ĭ',
76392 'į' => 'Į',
76393 'ı' => 'I',
76394 'ij' => 'IJ',
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 'ū' => 'Ū',
76422 'ŭ' => 'Ŭ',
76423 'ů' => 'Ů',
76424 'ű' => 'Ű',
76425 'ų' => 'Ų',
76426 'ŵ' => 'Ŵ',
76427 'ŷ' => 'Ŷ',
76428 'ź' => 'Ź',
76429 'ż' => 'Ż',
76430 'ž' => 'Ž',
76431 'ſ' => 'S',
76432 'ƀ' => 'Ƀ',
76433 'ƃ' => 'Ƃ',
76434 'ƅ' => 'Ƅ',
76435 'ƈ' => 'Ƈ',
76436 'ƌ' => 'Ƌ',
76437 'ƒ' => 'Ƒ',
76438 'ƕ' => 'Ƕ',
76439 'ƙ' => 'Ƙ',
76440 'ƚ' => 'Ƚ',
76441 'ƞ' => 'Ƞ',
76442 'ơ' => 'Ơ',
76443 'ƣ' => 'Ƣ',
76444 'ƥ' => 'Ƥ',
76445 'ƨ' => 'Ƨ',
76446 'ƭ' => 'Ƭ',
76447 'ư' => 'Ư',
76448 'ƴ' => 'Ƴ',
76449 'ƶ' => 'Ƶ',
76450 'ƹ' => 'Ƹ',
76451 'ƽ' => 'Ƽ',
76452 'ƿ' => 'Ƿ',
76453 'Dž' => 'DŽ',
76454 'dž' => 'DŽ',
76455 'Lj' => 'LJ',
76456 'lj' => 'LJ',
76457 'Nj' => 'NJ',
76458 'nj' => 'NJ',
76459 'ǎ' => 'Ǎ',
76460 'ǐ' => 'Ǐ',
76461 'ǒ' => 'Ǒ',
76462 'ǔ' => 'Ǔ',
76463 'ǖ' => 'Ǖ',
76464 'ǘ' => 'Ǘ',
76465 'ǚ' => 'Ǚ',
76466 'ǜ' => 'Ǜ',
76467 'ǝ' => 'Ǝ',
76468 'ǟ' => 'Ǟ',
76469 'ǡ' => 'Ǡ',
76470 'ǣ' => 'Ǣ',
76471 'ǥ' => 'Ǥ',
76472 'ǧ' => 'Ǧ',
76473 'ǩ' => 'Ǩ',
76474 'ǫ' => 'Ǫ',
76475 'ǭ' => 'Ǭ',
76476 'ǯ' => 'Ǯ',
76477 'Dz' => 'DZ',
76478 'dz' => 'DZ',
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 'ꮶ' => 'Ꮶ',
77461 'ꮷ' => 'Ꮷ',
77462 'ꮸ' => 'Ꮸ',
77463 'ꮹ' => 'Ꮹ',
77464 'ꮺ' => 'Ꮺ',
77465 'ꮻ' => 'Ꮻ',
77466 'ꮼ' => 'Ꮼ',
77467 'ꮽ' => 'Ꮽ',
77468 'ꮾ' => 'Ꮾ',
77469 'ꮿ' => 'Ꮿ',
77470 'a' => 'A',
77471 'b' => 'B',
77472 'c' => 'C',
77473 'd' => 'D',
77474 'e' => 'E',
77475 'f' => 'F',
77476 'g' => 'G',
77477 'h' => 'H',
77478 'i' => 'I',
77479 'j' => 'J',
77480 'k' => 'K',
77481 'l' => 'L',
77482 'm' => 'M',
77483 'n' => 'N',
77484 'o' => 'O',
77485 'p' => 'P',
77486 'q' => 'Q',
77487 'r' => 'R',
77488 's' => 'S',
77489 't' => 'T',
77490 'u' => 'U',
77491 'v' => 'V',
77492 'w' => 'W',
77493 'x' => 'X',
77494 'y' => 'Y',
77495 'z' => 'Z',
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 '𞤻' => '𞤙',
77713 '𞤼' => '𞤚',
77714 '𞤽' => '𞤛',
77715 '𞤾' => '𞤜',
77716 '𞤿' => '𞤝',
77717 '𞥀' => '𞤞',
77718 '𞥁' => '𞤟',
77719 '𞥂' => '𞤠',
77720 '𞥃' => '𞤡',
77721 );
77722 <?php
77723
77724
77725
77726
77727
77728
77729
77730
77731
77732
77733 use Symfony\Polyfill\Mbstring as p;
77734
77735 if (!function_exists('mb_convert_encoding')) {
77736 function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); }
77737 }
77738 if (!function_exists('mb_decode_mimeheader')) {
77739 function mb_decode_mimeheader($string) { return p\Mbstring::mb_decode_mimeheader($string); }
77740 }
77741 if (!function_exists('mb_encode_mimeheader')) {
77742 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); }
77743 }
77744 if (!function_exists('mb_decode_numericentity')) {
77745 function mb_decode_numericentity($string, $map, $encoding = null) { return p\Mbstring::mb_decode_numericentity($string, $map, $encoding); }
77746 }
77747 if (!function_exists('mb_encode_numericentity')) {
77748 function mb_encode_numericentity($string, $map, $encoding = null, $hex = false) { return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); }
77749 }
77750 if (!function_exists('mb_convert_case')) {
77751 function mb_convert_case($string, $mode, $encoding = null) { return p\Mbstring::mb_convert_case($string, $mode, $encoding); }
77752 }
77753 if (!function_exists('mb_internal_encoding')) {
77754 function mb_internal_encoding($encoding = null) { return p\Mbstring::mb_internal_encoding($encoding); }
77755 }
77756 if (!function_exists('mb_language')) {
77757 function mb_language($language = null) { return p\Mbstring::mb_language($language); }
77758 }
77759 if (!function_exists('mb_list_encodings')) {
77760 function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); }
77761 }
77762 if (!function_exists('mb_encoding_aliases')) {
77763 function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); }
77764 }
77765 if (!function_exists('mb_check_encoding')) {
77766 function mb_check_encoding($value = null, $encoding = null) { return p\Mbstring::mb_check_encoding($value, $encoding); }
77767 }
77768 if (!function_exists('mb_detect_encoding')) {
77769 function mb_detect_encoding($string, $encodings = null, $strict = false) { return p\Mbstring::mb_detect_encoding($string, $encodings, $strict); }
77770 }
77771 if (!function_exists('mb_detect_order')) {
77772 function mb_detect_order($encoding = null) { return p\Mbstring::mb_detect_order($encoding); }
77773 }
77774 if (!function_exists('mb_parse_str')) {
77775 function mb_parse_str($string, &$result = array()) { parse_str($string, $result); }
77776 }
77777 if (!function_exists('mb_strlen')) {
77778 function mb_strlen($string, $encoding = null) { return p\Mbstring::mb_strlen($string, $encoding); }
77779 }
77780 if (!function_exists('mb_strpos')) {
77781 function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); }
77782 }
77783 if (!function_exists('mb_strtolower')) {
77784 function mb_strtolower($string, $encoding = null) { return p\Mbstring::mb_strtolower($string, $encoding); }
77785 }
77786 if (!function_exists('mb_strtoupper')) {
77787 function mb_strtoupper($string, $encoding = null) { return p\Mbstring::mb_strtoupper($string, $encoding); }
77788 }
77789 if (!function_exists('mb_substitute_character')) {
77790 function mb_substitute_character($substitute_character = null) { return p\Mbstring::mb_substitute_character($substitute_character); }
77791 }
77792 if (!function_exists('mb_substr')) {
77793 function mb_substr($string, $start, $length = 2147483647, $encoding = null) { return p\Mbstring::mb_substr($string, $start, $length, $encoding); }
77794 }
77795 if (!function_exists('mb_stripos')) {
77796 function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); }
77797 }
77798 if (!function_exists('mb_stristr')) {
77799 function mb_stristr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); }
77800 }
77801 if (!function_exists('mb_strrchr')) {
77802 function mb_strrchr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); }
77803 }
77804 if (!function_exists('mb_strrichr')) {
77805 function mb_strrichr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); }
77806 }
77807 if (!function_exists('mb_strripos')) {
77808 function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); }
77809 }
77810 if (!function_exists('mb_strrpos')) {
77811 function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); }
77812 }
77813 if (!function_exists('mb_strstr')) {
77814 function mb_strstr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); }
77815 }
77816 if (!function_exists('mb_get_info')) {
77817 function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); }
77818 }
77819 if (!function_exists('mb_http_output')) {
77820 function mb_http_output($encoding = null) { return p\Mbstring::mb_http_output($encoding); }
77821 }
77822 if (!function_exists('mb_strwidth')) {
77823 function mb_strwidth($string, $encoding = null) { return p\Mbstring::mb_strwidth($string, $encoding); }
77824 }
77825 if (!function_exists('mb_substr_count')) {
77826 function mb_substr_count($haystack, $needle, $encoding = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $encoding); }
77827 }
77828 if (!function_exists('mb_output_handler')) {
77829 function mb_output_handler($string, $status) { return p\Mbstring::mb_output_handler($string, $status); }
77830 }
77831 if (!function_exists('mb_http_input')) {
77832 function mb_http_input($type = '') { return p\Mbstring::mb_http_input($type); }
77833 }
77834
77835 if (PHP_VERSION_ID >= 80000) {
77836 require_once __DIR__.'/Resources/mb_convert_variables.php8';
77837 } elseif (!function_exists('mb_convert_variables')) {
77838 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); }
77839 }
77840
77841 if (!function_exists('mb_ord')) {
77842 function mb_ord($string, $encoding = null) { return p\Mbstring::mb_ord($string, $encoding); }
77843 }
77844 if (!function_exists('mb_chr')) {
77845 function mb_chr($codepoint, $encoding = null) { return p\Mbstring::mb_chr($codepoint, $encoding); }
77846 }
77847 if (!function_exists('mb_scrub')) {
77848 function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); }
77849 }
77850 if (!function_exists('mb_str_split')) {
77851 function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); }
77852 }
77853
77854 if (extension_loaded('mbstring')) {
77855 return;
77856 }
77857
77858 if (!defined('MB_CASE_UPPER')) {
77859 define('MB_CASE_UPPER', 0);
77860 }
77861 if (!defined('MB_CASE_LOWER')) {
77862 define('MB_CASE_LOWER', 1);
77863 }
77864 if (!defined('MB_CASE_TITLE')) {
77865 define('MB_CASE_TITLE', 2);
77866 }
77867 <?php
77868
77869
77870
77871
77872
77873
77874
77875
77876
77877
77878 namespace Symfony\Component\Process\Exception;
77879
77880
77881
77882
77883
77884
77885 interface ExceptionInterface
77886 {
77887 }
77888 <?php
77889
77890
77891
77892
77893
77894
77895
77896
77897
77898
77899 namespace Symfony\Component\Process\Exception;
77900
77901
77902
77903
77904
77905
77906 class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
77907 {
77908 }
77909 <?php
77910
77911
77912
77913
77914
77915
77916
77917
77918
77919
77920 namespace Symfony\Component\Process\Exception;
77921
77922
77923
77924
77925
77926
77927 class LogicException extends \LogicException implements ExceptionInterface
77928 {
77929 }
77930 <?php
77931
77932
77933
77934
77935
77936
77937
77938
77939
77940
77941 namespace Symfony\Component\Process\Exception;
77942
77943 use Symfony\Component\Process\Process;
77944
77945
77946
77947
77948
77949
77950 class ProcessFailedException extends RuntimeException
77951 {
77952 private $process;
77953
77954 public function __construct(Process $process)
77955 {
77956 if ($process->isSuccessful()) {
77957 throw new InvalidArgumentException('Expected a failed process, but the given process was successful.');
77958 }
77959
77960 $error = sprintf('The command "%s" failed.'."\n\nExit Code: %s(%s)\n\nWorking directory: %s",
77961 $process->getCommandLine(),
77962 $process->getExitCode(),
77963 $process->getExitCodeText(),
77964 $process->getWorkingDirectory()
77965 );
77966
77967 if (!$process->isOutputDisabled()) {
77968 $error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s",
77969 $process->getOutput(),
77970 $process->getErrorOutput()
77971 );
77972 }
77973
77974 parent::__construct($error);
77975
77976 $this->process = $process;
77977 }
77978
77979 public function getProcess()
77980 {
77981 return $this->process;
77982 }
77983 }
77984 <?php
77985
77986
77987
77988
77989
77990
77991
77992
77993
77994
77995 namespace Symfony\Component\Process\Exception;
77996
77997 use Symfony\Component\Process\Process;
77998
77999
78000
78001
78002
78003
78004 class ProcessTimedOutException extends RuntimeException
78005 {
78006 const TYPE_GENERAL = 1;
78007 const TYPE_IDLE = 2;
78008
78009 private $process;
78010 private $timeoutType;
78011
78012 public function __construct(Process $process, $timeoutType)
78013 {
78014 $this->process = $process;
78015 $this->timeoutType = $timeoutType;
78016
78017 parent::__construct(sprintf(
78018 'The process "%s" exceeded the timeout of %s seconds.',
78019 $process->getCommandLine(),
78020 $this->getExceededTimeout()
78021 ));
78022 }
78023
78024 public function getProcess()
78025 {
78026 return $this->process;
78027 }
78028
78029 public function isGeneralTimeout()
78030 {
78031 return self::TYPE_GENERAL === $this->timeoutType;
78032 }
78033
78034 public function isIdleTimeout()
78035 {
78036 return self::TYPE_IDLE === $this->timeoutType;
78037 }
78038
78039 public function getExceededTimeout()
78040 {
78041 switch ($this->timeoutType) {
78042 case self::TYPE_GENERAL:
78043 return $this->process->getTimeout();
78044
78045 case self::TYPE_IDLE:
78046 return $this->process->getIdleTimeout();
78047
78048 default:
78049 throw new \LogicException(sprintf('Unknown timeout type "%d".', $this->timeoutType));
78050 }
78051 }
78052 }
78053 <?php
78054
78055
78056
78057
78058
78059
78060
78061
78062
78063
78064 namespace Symfony\Component\Process\Exception;
78065
78066
78067
78068
78069
78070
78071 class RuntimeException extends \RuntimeException implements ExceptionInterface
78072 {
78073 }
78074 <?php
78075
78076
78077
78078
78079
78080
78081
78082
78083
78084
78085 namespace Symfony\Component\Process;
78086
78087
78088
78089
78090
78091
78092
78093 class ExecutableFinder
78094 {
78095 private $suffixes = array('.exe', '.bat', '.cmd', '.com');
78096
78097
78098
78099
78100 public function setSuffixes(array $suffixes)
78101 {
78102 $this->suffixes = $suffixes;
78103 }
78104
78105
78106
78107
78108
78109
78110 public function addSuffix($suffix)
78111 {
78112 $this->suffixes[] = $suffix;
78113 }
78114
78115
78116
78117
78118
78119
78120
78121
78122
78123
78124 public function find($name, $default = null, array $extraDirs = array())
78125 {
78126 if (ini_get('open_basedir')) {
78127 $searchPath = explode(PATH_SEPARATOR, ini_get('open_basedir'));
78128 $dirs = array();
78129 foreach ($searchPath as $path) {
78130
78131 if (@is_dir($path)) {
78132 $dirs[] = $path;
78133 } else {
78134 if (basename($path) == $name && @is_executable($path)) {
78135 return $path;
78136 }
78137 }
78138 }
78139 } else {
78140 $dirs = array_merge(
78141 explode(PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
78142 $extraDirs
78143 );
78144 }
78145
78146 $suffixes = array('');
78147 if ('\\' === \DIRECTORY_SEPARATOR) {
78148 $pathExt = getenv('PATHEXT');
78149 $suffixes = array_merge($pathExt ? explode(PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes);
78150 }
78151 foreach ($suffixes as $suffix) {
78152 foreach ($dirs as $dir) {
78153 if (@is_file($file = $dir.\DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === \DIRECTORY_SEPARATOR || @is_executable($file))) {
78154 return $file;
78155 }
78156 }
78157 }
78158
78159 return $default;
78160 }
78161 }
78162 Copyright (c) 2004-2018 Fabien Potencier
78163
78164 Permission is hereby granted, free of charge, to any person obtaining a copy
78165 of this software and associated documentation files (the "Software"), to deal
78166 in the Software without restriction, including without limitation the rights
78167 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
78168 copies of the Software, and to permit persons to whom the Software is furnished
78169 to do so, subject to the following conditions:
78170
78171 The above copyright notice and this permission notice shall be included in all
78172 copies or substantial portions of the Software.
78173
78174 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
78175 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
78176 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
78177 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
78178 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
78179 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
78180 THE SOFTWARE.
78181 <?php
78182
78183
78184
78185
78186
78187
78188
78189
78190
78191
78192 namespace Symfony\Component\Process;
78193
78194
78195
78196
78197
78198
78199
78200 class PhpExecutableFinder
78201 {
78202 private $executableFinder;
78203
78204 public function __construct()
78205 {
78206 $this->executableFinder = new ExecutableFinder();
78207 }
78208
78209
78210
78211
78212
78213
78214
78215
78216 public function find($includeArgs = true)
78217 {
78218 $args = $this->findArguments();
78219 $args = $includeArgs && $args ? ' '.implode(' ', $args) : '';
78220
78221
78222 if (\defined('HHVM_VERSION')) {
78223 return (getenv('PHP_BINARY') ?: PHP_BINARY).$args;
78224 }
78225
78226
78227 if (\defined('PHP_BINARY') && PHP_BINARY && \in_array(\PHP_SAPI, array('cli', 'cli-server', 'phpdbg'), true)) {
78228 return PHP_BINARY.$args;
78229 }
78230
78231 if ($php = getenv('PHP_PATH')) {
78232 if (!@is_executable($php)) {
78233 return false;
78234 }
78235
78236 return $php;
78237 }
78238
78239 if ($php = getenv('PHP_PEAR_PHP_BIN')) {
78240 if (@is_executable($php)) {
78241 return $php;
78242 }
78243 }
78244
78245 if (@is_executable($php = PHP_BINDIR.('\\' === \DIRECTORY_SEPARATOR ? '\\php.exe' : '/php'))) {
78246 return $php;
78247 }
78248
78249 $dirs = array(PHP_BINDIR);
78250 if ('\\' === \DIRECTORY_SEPARATOR) {
78251 $dirs[] = 'C:\xampp\php\\';
78252 }
78253
78254 return $this->executableFinder->find('php', false, $dirs);
78255 }
78256
78257
78258
78259
78260
78261
78262 public function findArguments()
78263 {
78264 $arguments = array();
78265
78266 if (\defined('HHVM_VERSION')) {
78267 $arguments[] = '--php';
78268 } elseif ('phpdbg' === \PHP_SAPI) {
78269 $arguments[] = '-qrr';
78270 }
78271
78272 return $arguments;
78273 }
78274 }
78275 <?php
78276
78277
78278
78279
78280
78281
78282
78283
78284
78285
78286 namespace Symfony\Component\Process;
78287
78288 use Symfony\Component\Process\Exception\RuntimeException;
78289
78290
78291
78292
78293
78294
78295
78296
78297
78298
78299 class PhpProcess extends Process
78300 {
78301
78302
78303
78304
78305
78306
78307
78308 public function __construct($script, $cwd = null, array $env = null, $timeout = 60, array $options = array())
78309 {
78310 $executableFinder = new PhpExecutableFinder();
78311 if (false === $php = $executableFinder->find()) {
78312 $php = null;
78313 }
78314 if ('phpdbg' === \PHP_SAPI) {
78315 $file = tempnam(sys_get_temp_dir(), 'dbg');
78316 file_put_contents($file, $script);
78317 register_shutdown_function('unlink', $file);
78318 $php .= ' '.ProcessUtils::escapeArgument($file);
78319 $script = null;
78320 }
78321 if ('\\' !== \DIRECTORY_SEPARATOR && null !== $php) {
78322
78323
78324
78325 $php = 'exec '.$php;
78326 }
78327
78328 parent::__construct($php, $cwd, $env, $script, $timeout, $options);
78329 }
78330
78331
78332
78333
78334 public function setPhpBinary($php)
78335 {
78336 $this->setCommandLine($php);
78337 }
78338
78339
78340
78341
78342 public function start($callback = null)
78343 {
78344 if (null === $this->getCommandLine()) {
78345 throw new RuntimeException('Unable to find the PHP executable.');
78346 }
78347
78348 parent::start($callback);
78349 }
78350 }
78351 <?php
78352
78353
78354
78355
78356
78357
78358
78359
78360
78361
78362 namespace Symfony\Component\Process\Pipes;
78363
78364
78365
78366
78367
78368
78369 abstract class AbstractPipes implements PipesInterface
78370 {
78371 public $pipes = array();
78372
78373 private $inputBuffer = '';
78374 private $input;
78375 private $blocked = true;
78376 private $lastError;
78377
78378
78379
78380
78381 public function __construct($input)
78382 {
78383 if (\is_resource($input)) {
78384 $this->input = $input;
78385 } elseif (\is_string($input)) {
78386 $this->inputBuffer = $input;
78387 } else {
78388 $this->inputBuffer = (string) $input;
78389 }
78390 }
78391
78392
78393
78394
78395 public function close()
78396 {
78397 foreach ($this->pipes as $pipe) {
78398 fclose($pipe);
78399 }
78400 $this->pipes = array();
78401 }
78402
78403
78404
78405
78406
78407
78408 protected function hasSystemCallBeenInterrupted()
78409 {
78410 $lastError = $this->lastError;
78411 $this->lastError = null;
78412
78413
78414 return null !== $lastError && false !== stripos($lastError, 'interrupted system call');
78415 }
78416
78417
78418
78419
78420 protected function unblock()
78421 {
78422 if (!$this->blocked) {
78423 return;
78424 }
78425
78426 foreach ($this->pipes as $pipe) {
78427 stream_set_blocking($pipe, 0);
78428 }
78429 if (null !== $this->input) {
78430 stream_set_blocking($this->input, 0);
78431 }
78432
78433 $this->blocked = false;
78434 }
78435
78436
78437
78438
78439 protected function write()
78440 {
78441 if (!isset($this->pipes[0])) {
78442 return;
78443 }
78444 $input = $this->input;
78445 $r = $e = array();
78446 $w = array($this->pipes[0]);
78447
78448
78449 if (false === @stream_select($r, $w, $e, 0, 0)) {
78450 return;
78451 }
78452
78453 foreach ($w as $stdin) {
78454 if (isset($this->inputBuffer[0])) {
78455 $written = fwrite($stdin, $this->inputBuffer);
78456 $this->inputBuffer = substr($this->inputBuffer, $written);
78457 if (isset($this->inputBuffer[0])) {
78458 return array($this->pipes[0]);
78459 }
78460 }
78461
78462 if ($input) {
78463 for (;;) {
78464 $data = fread($input, self::CHUNK_SIZE);
78465 if (!isset($data[0])) {
78466 break;
78467 }
78468 $written = fwrite($stdin, $data);
78469 $data = substr($data, $written);
78470 if (isset($data[0])) {
78471 $this->inputBuffer = $data;
78472
78473 return array($this->pipes[0]);
78474 }
78475 }
78476 if (feof($input)) {
78477
78478
78479 $this->input = null;
78480 }
78481 }
78482 }
78483
78484
78485 if (null === $this->input && !isset($this->inputBuffer[0])) {
78486 fclose($this->pipes[0]);
78487 unset($this->pipes[0]);
78488 } elseif (!$w) {
78489 return array($this->pipes[0]);
78490 }
78491 }
78492
78493
78494
78495
78496 public function handleError($type, $msg)
78497 {
78498 $this->lastError = $msg;
78499 }
78500 }
78501 <?php
78502
78503
78504
78505
78506
78507
78508
78509
78510
78511
78512 namespace Symfony\Component\Process\Pipes;
78513
78514
78515
78516
78517
78518
78519
78520
78521 interface PipesInterface
78522 {
78523 const CHUNK_SIZE = 16384;
78524
78525
78526
78527
78528
78529
78530 public function getDescriptors();
78531
78532
78533
78534
78535
78536
78537 public function getFiles();
78538
78539
78540
78541
78542
78543
78544
78545
78546
78547 public function readAndWrite($blocking, $close = false);
78548
78549
78550
78551
78552
78553
78554 public function areOpen();
78555
78556
78557
78558
78559 public function close();
78560 }
78561 <?php
78562
78563
78564
78565
78566
78567
78568
78569
78570
78571
78572 namespace Symfony\Component\Process\Pipes;
78573
78574 use Symfony\Component\Process\Process;
78575
78576
78577
78578
78579
78580
78581
78582
78583 class UnixPipes extends AbstractPipes
78584 {
78585 private $ttyMode;
78586 private $ptyMode;
78587 private $disableOutput;
78588
78589 public function __construct($ttyMode, $ptyMode, $input, $disableOutput)
78590 {
78591 $this->ttyMode = (bool) $ttyMode;
78592 $this->ptyMode = (bool) $ptyMode;
78593 $this->disableOutput = (bool) $disableOutput;
78594
78595 parent::__construct($input);
78596 }
78597
78598 public function __destruct()
78599 {
78600 $this->close();
78601 }
78602
78603
78604
78605
78606 public function getDescriptors()
78607 {
78608 if ($this->disableOutput) {
78609 $nullstream = fopen('/dev/null', 'c');
78610
78611 return array(
78612 array('pipe', 'r'),
78613 $nullstream,
78614 $nullstream,
78615 );
78616 }
78617
78618 if ($this->ttyMode) {
78619 return array(
78620 array('file', '/dev/tty', 'r'),
78621 array('file', '/dev/tty', 'w'),
78622 array('file', '/dev/tty', 'w'),
78623 );
78624 }
78625
78626 if ($this->ptyMode && Process::isPtySupported()) {
78627 return array(
78628 array('pty'),
78629 array('pty'),
78630 array('pty'),
78631 );
78632 }
78633
78634 return array(
78635 array('pipe', 'r'),
78636 array('pipe', 'w'), 
78637 array('pipe', 'w'), 
78638 );
78639 }
78640
78641
78642
78643
78644 public function getFiles()
78645 {
78646 return array();
78647 }
78648
78649
78650
78651
78652 public function readAndWrite($blocking, $close = false)
78653 {
78654 $this->unblock();
78655 $w = $this->write();
78656
78657 $read = $e = array();
78658 $r = $this->pipes;
78659 unset($r[0]);
78660
78661
78662 set_error_handler(array($this, 'handleError'));
78663 if (($r || $w) && false === stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {
78664 restore_error_handler();
78665
78666
78667 if (!$this->hasSystemCallBeenInterrupted()) {
78668 $this->pipes = array();
78669 }
78670
78671 return $read;
78672 }
78673 restore_error_handler();
78674
78675 foreach ($r as $pipe) {
78676
78677
78678 $read[$type = array_search($pipe, $this->pipes, true)] = '';
78679
78680 do {
78681 $data = fread($pipe, self::CHUNK_SIZE);
78682 $read[$type] .= $data;
78683 } while (isset($data[0]) && ($close || isset($data[self::CHUNK_SIZE - 1])));
78684
78685 if (!isset($read[$type][0])) {
78686 unset($read[$type]);
78687 }
78688
78689 if ($close && feof($pipe)) {
78690 fclose($pipe);
78691 unset($this->pipes[$type]);
78692 }
78693 }
78694
78695 return $read;
78696 }
78697
78698
78699
78700
78701 public function areOpen()
78702 {
78703 return (bool) $this->pipes;
78704 }
78705
78706
78707
78708
78709
78710
78711
78712
78713
78714 public static function create(Process $process, $input)
78715 {
78716 return new static($process->isTty(), $process->isPty(), $input, $process->isOutputDisabled());
78717 }
78718 }
78719 <?php
78720
78721
78722
78723
78724
78725
78726
78727
78728
78729
78730 namespace Symfony\Component\Process\Pipes;
78731
78732 use Symfony\Component\Process\Exception\RuntimeException;
78733 use Symfony\Component\Process\Process;
78734
78735
78736
78737
78738
78739
78740
78741
78742
78743
78744
78745 class WindowsPipes extends AbstractPipes
78746 {
78747 private $files = array();
78748 private $fileHandles = array();
78749 private $lockHandles = array();
78750 private $readBytes = array(
78751 Process::STDOUT => 0,
78752 Process::STDERR => 0,
78753 );
78754 private $disableOutput;
78755
78756 public function __construct($disableOutput, $input)
78757 {
78758 $this->disableOutput = (bool) $disableOutput;
78759
78760 if (!$this->disableOutput) {
78761
78762
78763
78764
78765 $pipes = array(
78766 Process::STDOUT => Process::OUT,
78767 Process::STDERR => Process::ERR,
78768 );
78769 $tmpDir = sys_get_temp_dir();
78770 $lastError = 'unknown reason';
78771 set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; });
78772 for ($i = 0;; ++$i) {
78773 foreach ($pipes as $pipe => $name) {
78774 $file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name);
78775
78776 if (!$h = fopen($file.'.lock', 'w')) {
78777 restore_error_handler();
78778 throw new RuntimeException(sprintf('A temporary file could not be opened to write the process output: %s', $lastError));
78779 }
78780 if (!flock($h, LOCK_EX | LOCK_NB)) {
78781 continue 2;
78782 }
78783 if (isset($this->lockHandles[$pipe])) {
78784 flock($this->lockHandles[$pipe], LOCK_UN);
78785 fclose($this->lockHandles[$pipe]);
78786 }
78787 $this->lockHandles[$pipe] = $h;
78788
78789 if (!fclose(fopen($file, 'w')) || !$h = fopen($file, 'r')) {
78790 flock($this->lockHandles[$pipe], LOCK_UN);
78791 fclose($this->lockHandles[$pipe]);
78792 unset($this->lockHandles[$pipe]);
78793 continue 2;
78794 }
78795 $this->fileHandles[$pipe] = $h;
78796 $this->files[$pipe] = $file;
78797 }
78798 break;
78799 }
78800 restore_error_handler();
78801 }
78802
78803 parent::__construct($input);
78804 }
78805
78806 public function __destruct()
78807 {
78808 $this->close();
78809 }
78810
78811
78812
78813
78814 public function getDescriptors()
78815 {
78816 if ($this->disableOutput) {
78817 $nullstream = fopen('NUL', 'c');
78818
78819 return array(
78820 array('pipe', 'r'),
78821 $nullstream,
78822 $nullstream,
78823 );
78824 }
78825
78826
78827
78828
78829 return array(
78830 array('pipe', 'r'),
78831 array('file', 'NUL', 'w'),
78832 array('file', 'NUL', 'w'),
78833 );
78834 }
78835
78836
78837
78838
78839 public function getFiles()
78840 {
78841 return $this->files;
78842 }
78843
78844
78845
78846
78847 public function readAndWrite($blocking, $close = false)
78848 {
78849 $this->unblock();
78850 $w = $this->write();
78851 $read = $r = $e = array();
78852
78853 if ($blocking) {
78854 if ($w) {
78855 @stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6);
78856 } elseif ($this->fileHandles) {
78857 usleep(Process::TIMEOUT_PRECISION * 1E6);
78858 }
78859 }
78860 foreach ($this->fileHandles as $type => $fileHandle) {
78861 $data = stream_get_contents($fileHandle, -1, $this->readBytes[$type]);
78862
78863 if (isset($data[0])) {
78864 $this->readBytes[$type] += \strlen($data);
78865 $read[$type] = $data;
78866 }
78867 if ($close) {
78868 ftruncate($fileHandle, 0);
78869 fclose($fileHandle);
78870 flock($this->lockHandles[$type], LOCK_UN);
78871 fclose($this->lockHandles[$type]);
78872 unset($this->fileHandles[$type], $this->lockHandles[$type]);
78873 }
78874 }
78875
78876 return $read;
78877 }
78878
78879
78880
78881
78882 public function areOpen()
78883 {
78884 return $this->pipes && $this->fileHandles;
78885 }
78886
78887
78888
78889
78890 public function close()
78891 {
78892 parent::close();
78893 foreach ($this->fileHandles as $type => $handle) {
78894 ftruncate($handle, 0);
78895 fclose($handle);
78896 flock($this->lockHandles[$type], LOCK_UN);
78897 fclose($this->lockHandles[$type]);
78898 }
78899 $this->fileHandles = $this->lockHandles = array();
78900 }
78901
78902
78903
78904
78905
78906
78907
78908
78909
78910 public static function create(Process $process, $input)
78911 {
78912 return new static($process->isOutputDisabled(), $input);
78913 }
78914 }
78915 <?php
78916
78917
78918
78919
78920
78921
78922
78923
78924
78925
78926 namespace Symfony\Component\Process;
78927
78928 use Symfony\Component\Process\Exception\InvalidArgumentException;
78929 use Symfony\Component\Process\Exception\LogicException;
78930 use Symfony\Component\Process\Exception\ProcessFailedException;
78931 use Symfony\Component\Process\Exception\ProcessTimedOutException;
78932 use Symfony\Component\Process\Exception\RuntimeException;
78933 use Symfony\Component\Process\Pipes\PipesInterface;
78934 use Symfony\Component\Process\Pipes\UnixPipes;
78935 use Symfony\Component\Process\Pipes\WindowsPipes;
78936
78937
78938
78939
78940
78941
78942
78943
78944 class Process
78945 {
78946 const ERR = 'err';
78947 const OUT = 'out';
78948
78949 const STATUS_READY = 'ready';
78950 const STATUS_STARTED = 'started';
78951 const STATUS_TERMINATED = 'terminated';
78952
78953 const STDIN = 0;
78954 const STDOUT = 1;
78955 const STDERR = 2;
78956
78957
78958 const TIMEOUT_PRECISION = 0.2;
78959
78960 private $callback;
78961 private $commandline;
78962 private $cwd;
78963 private $env;
78964 private $input;
78965 private $starttime;
78966 private $lastOutputTime;
78967 private $timeout;
78968 private $idleTimeout;
78969 private $options;
78970 private $exitcode;
78971 private $fallbackStatus = array();
78972 private $processInformation;
78973 private $outputDisabled = false;
78974 private $stdout;
78975 private $stderr;
78976 private $enhanceWindowsCompatibility = true;
78977 private $enhanceSigchildCompatibility;
78978 private $process;
78979 private $status = self::STATUS_READY;
78980 private $incrementalOutputOffset = 0;
78981 private $incrementalErrorOutputOffset = 0;
78982 private $tty;
78983 private $pty;
78984
78985 private $useFileHandles = false;
78986
78987 private $processPipes;
78988
78989 private $latestSignal;
78990
78991 private static $sigchild;
78992
78993
78994
78995
78996
78997
78998 public static $exitCodes = array(
78999 0 => 'OK',
79000 1 => 'General error',
79001 2 => 'Misuse of shell builtins',
79002
79003 126 => 'Invoked command cannot execute',
79004 127 => 'Command not found',
79005 128 => 'Invalid exit argument',
79006
79007
79008 129 => 'Hangup',
79009 130 => 'Interrupt',
79010 131 => 'Quit and dump core',
79011 132 => 'Illegal instruction',
79012 133 => 'Trace/breakpoint trap',
79013 134 => 'Process aborted',
79014 135 => 'Bus error: "access to undefined portion of memory object"',
79015 136 => 'Floating point exception: "erroneous arithmetic operation"',
79016 137 => 'Kill (terminate immediately)',
79017 138 => 'User-defined 1',
79018 139 => 'Segmentation violation',
79019 140 => 'User-defined 2',
79020 141 => 'Write to pipe with no one reading',
79021 142 => 'Signal raised by alarm',
79022 143 => 'Termination (request to terminate)',
79023
79024 145 => 'Child process terminated, stopped (or continued*)',
79025 146 => 'Continue if stopped',
79026 147 => 'Stop executing temporarily',
79027 148 => 'Terminal stop signal',
79028 149 => 'Background process attempting to read from tty ("in")',
79029 150 => 'Background process attempting to write to tty ("out")',
79030 151 => 'Urgent data available on socket',
79031 152 => 'CPU time limit exceeded',
79032 153 => 'File size limit exceeded',
79033 154 => 'Signal raised by timer counting virtual time: "virtual timer expired"',
79034 155 => 'Profiling timer expired',
79035
79036 157 => 'Pollable event',
79037
79038 159 => 'Bad syscall',
79039 );
79040
79041
79042
79043
79044
79045
79046
79047
79048
79049
79050
79051 public function __construct($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = array())
79052 {
79053 if (!\function_exists('proc_open')) {
79054 throw new RuntimeException('The Process class relies on proc_open, which is not available on your PHP installation.');
79055 }
79056
79057 $this->commandline = $commandline;
79058 $this->cwd = $cwd;
79059
79060
79061
79062
79063
79064 if (null === $this->cwd && (\defined('ZEND_THREAD_SAFE') || '\\' === \DIRECTORY_SEPARATOR)) {
79065 $this->cwd = getcwd();
79066 }
79067 if (null !== $env) {
79068 $this->setEnv($env);
79069 }
79070
79071 $this->setInput($input);
79072 $this->setTimeout($timeout);
79073 $this->useFileHandles = '\\' === \DIRECTORY_SEPARATOR;
79074 $this->pty = false;
79075 $this->enhanceSigchildCompatibility = '\\' !== \DIRECTORY_SEPARATOR && $this->isSigchildEnabled();
79076 $this->options = array_replace(array('suppress_errors' => true, 'binary_pipes' => true), $options);
79077 }
79078
79079 public function __destruct()
79080 {
79081 $this->stop(0);
79082 }
79083
79084 public function __clone()
79085 {
79086 $this->resetProcessData();
79087 }
79088
79089
79090
79091
79092
79093
79094
79095
79096
79097
79098
79099
79100
79101
79102
79103
79104
79105
79106
79107
79108 public function run($callback = null)
79109 {
79110 $this->start($callback);
79111
79112 return $this->wait();
79113 }
79114
79115
79116
79117
79118
79119
79120
79121
79122
79123
79124
79125
79126
79127
79128 public function mustRun($callback = null)
79129 {
79130 if (!$this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
79131 throw new RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.');
79132 }
79133
79134 if (0 !== $this->run($callback)) {
79135 throw new ProcessFailedException($this);
79136 }
79137
79138 return $this;
79139 }
79140
79141
79142
79143
79144
79145
79146
79147
79148
79149
79150
79151
79152
79153
79154
79155
79156
79157
79158
79159
79160 public function start($callback = null)
79161 {
79162 if ($this->isRunning()) {
79163 throw new RuntimeException('Process is already running');
79164 }
79165 if ($this->outputDisabled && null !== $callback) {
79166 throw new LogicException('Output has been disabled, enable it to allow the use of a callback.');
79167 }
79168
79169 $this->resetProcessData();
79170 $this->starttime = $this->lastOutputTime = microtime(true);
79171 $this->callback = $this->buildCallback($callback);
79172 $descriptors = $this->getDescriptors();
79173
79174 $commandline = $this->commandline;
79175
79176 if ('\\' === \DIRECTORY_SEPARATOR && $this->enhanceWindowsCompatibility) {
79177 $commandline = 'cmd /V:ON /E:ON /D /C "('.$commandline.')';
79178 foreach ($this->processPipes->getFiles() as $offset => $filename) {
79179 $commandline .= ' '.$offset.'>'.ProcessUtils::escapeArgument($filename);
79180 }
79181 $commandline .= '"';
79182
79183 if (!isset($this->options['bypass_shell'])) {
79184 $this->options['bypass_shell'] = true;
79185 }
79186 } elseif (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
79187
79188 $descriptors[3] = array('pipe', 'w');
79189
79190
79191 $commandline = '{ ('.$this->commandline.') <&3 3<&- 3>/dev/null & } 3<&0;';
79192 $commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code';
79193
79194
79195
79196 $ptsWorkaround = fopen(__FILE__, 'r');
79197 }
79198
79199 $this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $this->env, $this->options);
79200
79201 if (!\is_resource($this->process)) {
79202 throw new RuntimeException('Unable to launch a new process.');
79203 }
79204 $this->status = self::STATUS_STARTED;
79205
79206 if (isset($descriptors[3])) {
79207 $this->fallbackStatus['pid'] = (int) fgets($this->processPipes->pipes[3]);
79208 }
79209
79210 if ($this->tty) {
79211 return;
79212 }
79213
79214 $this->updateStatus(false);
79215 $this->checkTimeout();
79216 }
79217
79218
79219
79220
79221
79222
79223
79224
79225
79226
79227
79228
79229
79230
79231
79232
79233 public function restart($callback = null)
79234 {
79235 if ($this->isRunning()) {
79236 throw new RuntimeException('Process is already running');
79237 }
79238
79239 $process = clone $this;
79240 $process->start($callback);
79241
79242 return $process;
79243 }
79244
79245
79246
79247
79248
79249
79250
79251
79252
79253
79254
79255
79256
79257
79258
79259
79260 public function wait($callback = null)
79261 {
79262 $this->requireProcessIsStarted(__FUNCTION__);
79263
79264 $this->updateStatus(false);
79265 if (null !== $callback) {
79266 $this->callback = $this->buildCallback($callback);
79267 }
79268
79269 do {
79270 $this->checkTimeout();
79271 $running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
79272 $this->readPipes($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
79273 } while ($running);
79274
79275 while ($this->isRunning()) {
79276 usleep(1000);
79277 }
79278
79279 if ($this->processInformation['signaled'] && $this->processInformation['termsig'] !== $this->latestSignal) {
79280 throw new RuntimeException(sprintf('The process has been signaled with signal "%s".', $this->processInformation['termsig']));
79281 }
79282
79283 return $this->exitcode;
79284 }
79285
79286
79287
79288
79289
79290
79291 public function getPid()
79292 {
79293 return $this->isRunning() ? $this->processInformation['pid'] : null;
79294 }
79295
79296
79297
79298
79299
79300
79301
79302
79303
79304
79305
79306
79307 public function signal($signal)
79308 {
79309 $this->doSignal($signal, true);
79310
79311 return $this;
79312 }
79313
79314
79315
79316
79317
79318
79319
79320
79321
79322 public function disableOutput()
79323 {
79324 if ($this->isRunning()) {
79325 throw new RuntimeException('Disabling output while the process is running is not possible.');
79326 }
79327 if (null !== $this->idleTimeout) {
79328 throw new LogicException('Output can not be disabled while an idle timeout is set.');
79329 }
79330
79331 $this->outputDisabled = true;
79332
79333 return $this;
79334 }
79335
79336
79337
79338
79339
79340
79341
79342
79343 public function enableOutput()
79344 {
79345 if ($this->isRunning()) {
79346 throw new RuntimeException('Enabling output while the process is running is not possible.');
79347 }
79348
79349 $this->outputDisabled = false;
79350
79351 return $this;
79352 }
79353
79354
79355
79356
79357
79358
79359 public function isOutputDisabled()
79360 {
79361 return $this->outputDisabled;
79362 }
79363
79364
79365
79366
79367
79368
79369
79370
79371
79372 public function getOutput()
79373 {
79374 $this->readPipesForOutput(__FUNCTION__);
79375
79376 if (false === $ret = stream_get_contents($this->stdout, -1, 0)) {
79377 return '';
79378 }
79379
79380 return $ret;
79381 }
79382
79383
79384
79385
79386
79387
79388
79389
79390
79391
79392
79393
79394 public function getIncrementalOutput()
79395 {
79396 $this->readPipesForOutput(__FUNCTION__);
79397
79398 $latest = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
79399 $this->incrementalOutputOffset = ftell($this->stdout);
79400
79401 if (false === $latest) {
79402 return '';
79403 }
79404
79405 return $latest;
79406 }
79407
79408
79409
79410
79411
79412
79413 public function clearOutput()
79414 {
79415 ftruncate($this->stdout, 0);
79416 fseek($this->stdout, 0);
79417 $this->incrementalOutputOffset = 0;
79418
79419 return $this;
79420 }
79421
79422
79423
79424
79425
79426
79427
79428
79429
79430 public function getErrorOutput()
79431 {
79432 $this->readPipesForOutput(__FUNCTION__);
79433
79434 if (false === $ret = stream_get_contents($this->stderr, -1, 0)) {
79435 return '';
79436 }
79437
79438 return $ret;
79439 }
79440
79441
79442
79443
79444
79445
79446
79447
79448
79449
79450
79451
79452
79453 public function getIncrementalErrorOutput()
79454 {
79455 $this->readPipesForOutput(__FUNCTION__);
79456
79457 $latest = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
79458 $this->incrementalErrorOutputOffset = ftell($this->stderr);
79459
79460 if (false === $latest) {
79461 return '';
79462 }
79463
79464 return $latest;
79465 }
79466
79467
79468
79469
79470
79471
79472 public function clearErrorOutput()
79473 {
79474 ftruncate($this->stderr, 0);
79475 fseek($this->stderr, 0);
79476 $this->incrementalErrorOutputOffset = 0;
79477
79478 return $this;
79479 }
79480
79481
79482
79483
79484
79485
79486
79487
79488 public function getExitCode()
79489 {
79490 if (!$this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
79491 throw new RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.');
79492 }
79493
79494 $this->updateStatus(false);
79495
79496 return $this->exitcode;
79497 }
79498
79499
79500
79501
79502
79503
79504
79505
79506
79507
79508
79509
79510 public function getExitCodeText()
79511 {
79512 if (null === $exitcode = $this->getExitCode()) {
79513 return;
79514 }
79515
79516 return isset(self::$exitCodes[$exitcode]) ? self::$exitCodes[$exitcode] : 'Unknown error';
79517 }
79518
79519
79520
79521
79522
79523
79524 public function isSuccessful()
79525 {
79526 return 0 === $this->getExitCode();
79527 }
79528
79529
79530
79531
79532
79533
79534
79535
79536
79537
79538
79539 public function hasBeenSignaled()
79540 {
79541 $this->requireProcessIsTerminated(__FUNCTION__);
79542
79543 if (!$this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
79544 throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
79545 }
79546
79547 return $this->processInformation['signaled'];
79548 }
79549
79550
79551
79552
79553
79554
79555
79556
79557
79558
79559
79560 public function getTermSignal()
79561 {
79562 $this->requireProcessIsTerminated(__FUNCTION__);
79563
79564 if ($this->isSigchildEnabled() && (!$this->enhanceSigchildCompatibility || -1 === $this->processInformation['termsig'])) {
79565 throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
79566 }
79567
79568 return $this->processInformation['termsig'];
79569 }
79570
79571
79572
79573
79574
79575
79576
79577
79578
79579
79580 public function hasBeenStopped()
79581 {
79582 $this->requireProcessIsTerminated(__FUNCTION__);
79583
79584 return $this->processInformation['stopped'];
79585 }
79586
79587
79588
79589
79590
79591
79592
79593
79594
79595
79596 public function getStopSignal()
79597 {
79598 $this->requireProcessIsTerminated(__FUNCTION__);
79599
79600 return $this->processInformation['stopsig'];
79601 }
79602
79603
79604
79605
79606
79607
79608 public function isRunning()
79609 {
79610 if (self::STATUS_STARTED !== $this->status) {
79611 return false;
79612 }
79613
79614 $this->updateStatus(false);
79615
79616 return $this->processInformation['running'];
79617 }
79618
79619
79620
79621
79622
79623
79624 public function isStarted()
79625 {
79626 return self::STATUS_READY != $this->status;
79627 }
79628
79629
79630
79631
79632
79633
79634 public function isTerminated()
79635 {
79636 $this->updateStatus(false);
79637
79638 return self::STATUS_TERMINATED == $this->status;
79639 }
79640
79641
79642
79643
79644
79645
79646
79647
79648 public function getStatus()
79649 {
79650 $this->updateStatus(false);
79651
79652 return $this->status;
79653 }
79654
79655
79656
79657
79658
79659
79660
79661
79662
79663 public function stop($timeout = 10, $signal = null)
79664 {
79665 $timeoutMicro = microtime(true) + $timeout;
79666 if ($this->isRunning()) {
79667
79668 $this->doSignal(15, false);
79669 do {
79670 usleep(1000);
79671 } while ($this->isRunning() && microtime(true) < $timeoutMicro);
79672
79673 if ($this->isRunning()) {
79674
79675
79676 $this->doSignal($signal ?: 9, false);
79677 }
79678 }
79679
79680 if ($this->isRunning()) {
79681 if (isset($this->fallbackStatus['pid'])) {
79682 unset($this->fallbackStatus['pid']);
79683
79684 return $this->stop(0, $signal);
79685 }
79686 $this->close();
79687 }
79688
79689 return $this->exitcode;
79690 }
79691
79692
79693
79694
79695
79696
79697
79698
79699 public function addOutput($line)
79700 {
79701 $this->lastOutputTime = microtime(true);
79702
79703 fseek($this->stdout, 0, SEEK_END);
79704 fwrite($this->stdout, $line);
79705 fseek($this->stdout, $this->incrementalOutputOffset);
79706 }
79707
79708
79709
79710
79711
79712
79713
79714
79715 public function addErrorOutput($line)
79716 {
79717 $this->lastOutputTime = microtime(true);
79718
79719 fseek($this->stderr, 0, SEEK_END);
79720 fwrite($this->stderr, $line);
79721 fseek($this->stderr, $this->incrementalErrorOutputOffset);
79722 }
79723
79724
79725
79726
79727
79728
79729 public function getCommandLine()
79730 {
79731 return $this->commandline;
79732 }
79733
79734
79735
79736
79737
79738
79739
79740
79741 public function setCommandLine($commandline)
79742 {
79743 $this->commandline = $commandline;
79744
79745 return $this;
79746 }
79747
79748
79749
79750
79751
79752
79753 public function getTimeout()
79754 {
79755 return $this->timeout;
79756 }
79757
79758
79759
79760
79761
79762
79763 public function getIdleTimeout()
79764 {
79765 return $this->idleTimeout;
79766 }
79767
79768
79769
79770
79771
79772
79773
79774
79775
79776
79777
79778
79779 public function setTimeout($timeout)
79780 {
79781 $this->timeout = $this->validateTimeout($timeout);
79782
79783 return $this;
79784 }
79785
79786
79787
79788
79789
79790
79791
79792
79793
79794
79795
79796
79797
79798 public function setIdleTimeout($timeout)
79799 {
79800 if (null !== $timeout && $this->outputDisabled) {
79801 throw new LogicException('Idle timeout can not be set while the output is disabled.');
79802 }
79803
79804 $this->idleTimeout = $this->validateTimeout($timeout);
79805
79806 return $this;
79807 }
79808
79809
79810
79811
79812
79813
79814
79815
79816
79817
79818 public function setTty($tty)
79819 {
79820 if ('\\' === \DIRECTORY_SEPARATOR && $tty) {
79821 throw new RuntimeException('TTY mode is not supported on Windows platform.');
79822 }
79823 if ($tty) {
79824 static $isTtySupported;
79825
79826 if (null === $isTtySupported) {
79827 $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);
79828 }
79829
79830 if (!$isTtySupported) {
79831 throw new RuntimeException('TTY mode requires /dev/tty to be read/writable.');
79832 }
79833 }
79834
79835 $this->tty = (bool) $tty;
79836
79837 return $this;
79838 }
79839
79840
79841
79842
79843
79844
79845 public function isTty()
79846 {
79847 return $this->tty;
79848 }
79849
79850
79851
79852
79853
79854
79855
79856
79857 public function setPty($bool)
79858 {
79859 $this->pty = (bool) $bool;
79860
79861 return $this;
79862 }
79863
79864
79865
79866
79867
79868
79869 public function isPty()
79870 {
79871 return $this->pty;
79872 }
79873
79874
79875
79876
79877
79878
79879 public function getWorkingDirectory()
79880 {
79881 if (null === $this->cwd) {
79882
79883
79884 return getcwd() ?: null;
79885 }
79886
79887 return $this->cwd;
79888 }
79889
79890
79891
79892
79893
79894
79895
79896
79897 public function setWorkingDirectory($cwd)
79898 {
79899 $this->cwd = $cwd;
79900
79901 return $this;
79902 }
79903
79904
79905
79906
79907
79908
79909 public function getEnv()
79910 {
79911 return $this->env;
79912 }
79913
79914
79915
79916
79917
79918
79919
79920
79921
79922
79923
79924
79925
79926
79927 public function setEnv(array $env)
79928 {
79929
79930 $env = array_filter($env, function ($value) {
79931 return !\is_array($value);
79932 });
79933
79934 $this->env = array();
79935 foreach ($env as $key => $value) {
79936 $this->env[$key] = (string) $value;
79937 }
79938
79939 return $this;
79940 }
79941
79942
79943
79944
79945
79946
79947
79948
79949
79950
79951 public function getStdin()
79952 {
79953 @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);
79954
79955 return $this->getInput();
79956 }
79957
79958
79959
79960
79961
79962
79963 public function getInput()
79964 {
79965 return $this->input;
79966 }
79967
79968
79969
79970
79971
79972
79973
79974
79975
79976
79977
79978
79979
79980
79981 public function setStdin($stdin)
79982 {
79983 @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);
79984
79985 return $this->setInput($stdin);
79986 }
79987
79988
79989
79990
79991
79992
79993
79994
79995
79996
79997
79998
79999
80000
80001 public function setInput($input)
80002 {
80003 if ($this->isRunning()) {
80004 throw new LogicException('Input can not be set while the process is running.');
80005 }
80006
80007 $this->input = ProcessUtils::validateInput(__METHOD__, $input);
80008
80009 return $this;
80010 }
80011
80012
80013
80014
80015
80016
80017 public function getOptions()
80018 {
80019 return $this->options;
80020 }
80021
80022
80023
80024
80025
80026
80027
80028
80029 public function setOptions(array $options)
80030 {
80031 $this->options = $options;
80032
80033 return $this;
80034 }
80035
80036
80037
80038
80039
80040
80041
80042
80043 public function getEnhanceWindowsCompatibility()
80044 {
80045 return $this->enhanceWindowsCompatibility;
80046 }
80047
80048
80049
80050
80051
80052
80053
80054
80055 public function setEnhanceWindowsCompatibility($enhance)
80056 {
80057 $this->enhanceWindowsCompatibility = (bool) $enhance;
80058
80059 return $this;
80060 }
80061
80062
80063
80064
80065
80066
80067 public function getEnhanceSigchildCompatibility()
80068 {
80069 return $this->enhanceSigchildCompatibility;
80070 }
80071
80072
80073
80074
80075
80076
80077
80078
80079
80080
80081
80082
80083 public function setEnhanceSigchildCompatibility($enhance)
80084 {
80085 $this->enhanceSigchildCompatibility = (bool) $enhance;
80086
80087 return $this;
80088 }
80089
80090
80091
80092
80093
80094
80095
80096
80097
80098 public function checkTimeout()
80099 {
80100 if (self::STATUS_STARTED !== $this->status) {
80101 return;
80102 }
80103
80104 if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
80105 $this->stop(0);
80106
80107 throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_GENERAL);
80108 }
80109
80110 if (null !== $this->idleTimeout && $this->idleTimeout < microtime(true) - $this->lastOutputTime) {
80111 $this->stop(0);
80112
80113 throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_IDLE);
80114 }
80115 }
80116
80117
80118
80119
80120
80121
80122 public static function isPtySupported()
80123 {
80124 static $result;
80125
80126 if (null !== $result) {
80127 return $result;
80128 }
80129
80130 if ('\\' === \DIRECTORY_SEPARATOR) {
80131 return $result = false;
80132 }
80133
80134 return $result = (bool) @proc_open('echo 1 >/dev/null', array(array('pty'), array('pty'), array('pty')), $pipes);
80135 }
80136
80137
80138
80139
80140
80141
80142 private function getDescriptors()
80143 {
80144 if ('\\' === \DIRECTORY_SEPARATOR) {
80145 $this->processPipes = WindowsPipes::create($this, $this->input);
80146 } else {
80147 $this->processPipes = UnixPipes::create($this, $this->input);
80148 }
80149
80150 return $this->processPipes->getDescriptors();
80151 }
80152
80153
80154
80155
80156
80157
80158
80159
80160
80161
80162
80163 protected function buildCallback($callback)
80164 {
80165 $that = $this;
80166 $out = self::OUT;
80167 $callback = function ($type, $data) use ($that, $callback, $out) {
80168 if ($out == $type) {
80169 $that->addOutput($data);
80170 } else {
80171 $that->addErrorOutput($data);
80172 }
80173
80174 if (null !== $callback) {
80175 \call_user_func($callback, $type, $data);
80176 }
80177 };
80178
80179 return $callback;
80180 }
80181
80182
80183
80184
80185
80186
80187 protected function updateStatus($blocking)
80188 {
80189 if (self::STATUS_STARTED !== $this->status) {
80190 return;
80191 }
80192
80193 $this->processInformation = proc_get_status($this->process);
80194 $running = $this->processInformation['running'];
80195
80196 $this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running);
80197
80198 if ($this->fallbackStatus && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
80199 $this->processInformation = $this->fallbackStatus + $this->processInformation;
80200 }
80201
80202 if (!$running) {
80203 $this->close();
80204 }
80205 }
80206
80207
80208
80209
80210
80211
80212 protected function isSigchildEnabled()
80213 {
80214 if (null !== self::$sigchild) {
80215 return self::$sigchild;
80216 }
80217
80218 if (!\function_exists('phpinfo') || \defined('HHVM_VERSION')) {
80219 return self::$sigchild = false;
80220 }
80221
80222 ob_start();
80223 phpinfo(INFO_GENERAL);
80224
80225 return self::$sigchild = false !== strpos(ob_get_clean(), '--enable-sigchild');
80226 }
80227
80228
80229
80230
80231
80232
80233
80234
80235 private function readPipesForOutput($caller)
80236 {
80237 if ($this->outputDisabled) {
80238 throw new LogicException('Output has been disabled.');
80239 }
80240
80241 $this->requireProcessIsStarted($caller);
80242
80243 $this->updateStatus(false);
80244 }
80245
80246
80247
80248
80249
80250
80251
80252
80253
80254
80255 private function validateTimeout($timeout)
80256 {
80257 $timeout = (float) $timeout;
80258
80259 if (0.0 === $timeout) {
80260 $timeout = null;
80261 } elseif ($timeout < 0) {
80262 throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
80263 }
80264
80265 return $timeout;
80266 }
80267
80268
80269
80270
80271
80272
80273
80274 private function readPipes($blocking, $close)
80275 {
80276 $result = $this->processPipes->readAndWrite($blocking, $close);
80277
80278 $callback = $this->callback;
80279 foreach ($result as $type => $data) {
80280 if (3 !== $type) {
80281 $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data);
80282 } elseif (!isset($this->fallbackStatus['signaled'])) {
80283 $this->fallbackStatus['exitcode'] = (int) $data;
80284 }
80285 }
80286 }
80287
80288
80289
80290
80291
80292
80293 private function close()
80294 {
80295 $this->processPipes->close();
80296 if (\is_resource($this->process)) {
80297 proc_close($this->process);
80298 }
80299 $this->exitcode = $this->processInformation['exitcode'];
80300 $this->status = self::STATUS_TERMINATED;
80301
80302 if (-1 === $this->exitcode) {
80303 if ($this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) {
80304
80305 $this->exitcode = 128 + $this->processInformation['termsig'];
80306 } elseif ($this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
80307 $this->processInformation['signaled'] = true;
80308 $this->processInformation['termsig'] = -1;
80309 }
80310 }
80311
80312
80313
80314
80315 $this->callback = null;
80316
80317 return $this->exitcode;
80318 }
80319
80320
80321
80322
80323 private function resetProcessData()
80324 {
80325 $this->starttime = null;
80326 $this->callback = null;
80327 $this->exitcode = null;
80328 $this->fallbackStatus = array();
80329 $this->processInformation = null;
80330 $this->stdout = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+b');
80331 $this->stderr = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+b');
80332 $this->process = null;
80333 $this->latestSignal = null;
80334 $this->status = self::STATUS_READY;
80335 $this->incrementalOutputOffset = 0;
80336 $this->incrementalErrorOutputOffset = 0;
80337 }
80338
80339
80340
80341
80342
80343
80344
80345
80346
80347
80348
80349
80350
80351 private function doSignal($signal, $throwException)
80352 {
80353 if (null === $pid = $this->getPid()) {
80354 if ($throwException) {
80355 throw new LogicException('Can not send signal on a non running process.');
80356 }
80357
80358 return false;
80359 }
80360
80361 if ('\\' === \DIRECTORY_SEPARATOR) {
80362 exec(sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode);
80363 if ($exitCode && $this->isRunning()) {
80364 if ($throwException) {
80365 throw new RuntimeException(sprintf('Unable to kill the process (%s).', implode(' ', $output)));
80366 }
80367
80368 return false;
80369 }
80370 } else {
80371 if (!$this->enhanceSigchildCompatibility || !$this->isSigchildEnabled()) {
80372 $ok = @proc_terminate($this->process, $signal);
80373 } elseif (\function_exists('posix_kill')) {
80374 $ok = @posix_kill($pid, $signal);
80375 } elseif ($ok = proc_open(sprintf('kill -%d %d', $signal, $pid), array(2 => array('pipe', 'w')), $pipes)) {
80376 $ok = false === fgets($pipes[2]);
80377 }
80378 if (!$ok) {
80379 if ($throwException) {
80380 throw new RuntimeException(sprintf('Error while sending signal `%s`.', $signal));
80381 }
80382
80383 return false;
80384 }
80385 }
80386
80387 $this->latestSignal = (int) $signal;
80388 $this->fallbackStatus['signaled'] = true;
80389 $this->fallbackStatus['exitcode'] = -1;
80390 $this->fallbackStatus['termsig'] = $this->latestSignal;
80391
80392 return true;
80393 }
80394
80395
80396
80397
80398
80399
80400
80401
80402 private function requireProcessIsStarted($functionName)
80403 {
80404 if (!$this->isStarted()) {
80405 throw new LogicException(sprintf('Process must be started before calling %s.', $functionName));
80406 }
80407 }
80408
80409
80410
80411
80412
80413
80414
80415
80416 private function requireProcessIsTerminated($functionName)
80417 {
80418 if (!$this->isTerminated()) {
80419 throw new LogicException(sprintf('Process must be terminated before calling %s.', $functionName));
80420 }
80421 }
80422 }
80423 <?php
80424
80425
80426
80427
80428
80429
80430
80431
80432
80433
80434 namespace Symfony\Component\Process;
80435
80436 use Symfony\Component\Process\Exception\InvalidArgumentException;
80437 use Symfony\Component\Process\Exception\LogicException;
80438
80439
80440
80441
80442 class ProcessBuilder
80443 {
80444 private $arguments;
80445 private $cwd;
80446 private $env = array();
80447 private $input;
80448 private $timeout = 60;
80449 private $options = array();
80450 private $inheritEnv = true;
80451 private $prefix = array();
80452 private $outputDisabled = false;
80453
80454
80455
80456
80457 public function __construct(array $arguments = array())
80458 {
80459 $this->arguments = $arguments;
80460 }
80461
80462
80463
80464
80465
80466
80467
80468
80469 public static function create(array $arguments = array())
80470 {
80471 return new static($arguments);
80472 }
80473
80474
80475
80476
80477
80478
80479
80480
80481 public function add($argument)
80482 {
80483 $this->arguments[] = $argument;
80484
80485 return $this;
80486 }
80487
80488
80489
80490
80491
80492
80493
80494
80495
80496
80497 public function setPrefix($prefix)
80498 {
80499 $this->prefix = \is_array($prefix) ? $prefix : array($prefix);
80500
80501 return $this;
80502 }
80503
80504
80505
80506
80507
80508
80509
80510
80511
80512
80513
80514 public function setArguments(array $arguments)
80515 {
80516 $this->arguments = $arguments;
80517
80518 return $this;
80519 }
80520
80521
80522
80523
80524
80525
80526
80527
80528 public function setWorkingDirectory($cwd)
80529 {
80530 $this->cwd = $cwd;
80531
80532 return $this;
80533 }
80534
80535
80536
80537
80538
80539
80540
80541
80542 public function inheritEnvironmentVariables($inheritEnv = true)
80543 {
80544 $this->inheritEnv = $inheritEnv;
80545
80546 return $this;
80547 }
80548
80549
80550
80551
80552
80553
80554
80555
80556
80557
80558
80559
80560 public function setEnv($name, $value)
80561 {
80562 $this->env[$name] = $value;
80563
80564 return $this;
80565 }
80566
80567
80568
80569
80570
80571
80572
80573
80574
80575
80576
80577
80578 public function addEnvironmentVariables(array $variables)
80579 {
80580 $this->env = array_replace($this->env, $variables);
80581
80582 return $this;
80583 }
80584
80585
80586
80587
80588
80589
80590
80591
80592
80593
80594
80595
80596 public function setInput($input)
80597 {
80598 $this->input = ProcessUtils::validateInput(__METHOD__, $input);
80599
80600 return $this;
80601 }
80602
80603
80604
80605
80606
80607
80608
80609
80610
80611
80612
80613
80614 public function setTimeout($timeout)
80615 {
80616 if (null === $timeout) {
80617 $this->timeout = null;
80618
80619 return $this;
80620 }
80621
80622 $timeout = (float) $timeout;
80623
80624 if ($timeout < 0) {
80625 throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
80626 }
80627
80628 $this->timeout = $timeout;
80629
80630 return $this;
80631 }
80632
80633
80634
80635
80636
80637
80638
80639
80640
80641 public function setOption($name, $value)
80642 {
80643 $this->options[$name] = $value;
80644
80645 return $this;
80646 }
80647
80648
80649
80650
80651
80652
80653 public function disableOutput()
80654 {
80655 $this->outputDisabled = true;
80656
80657 return $this;
80658 }
80659
80660
80661
80662
80663
80664
80665 public function enableOutput()
80666 {
80667 $this->outputDisabled = false;
80668
80669 return $this;
80670 }
80671
80672
80673
80674
80675
80676
80677
80678
80679 public function getProcess()
80680 {
80681 if (0 === \count($this->prefix) && 0 === \count($this->arguments)) {
80682 throw new LogicException('You must add() command arguments before calling getProcess().');
80683 }
80684
80685 $options = $this->options;
80686
80687 $arguments = array_merge($this->prefix, $this->arguments);
80688 $script = implode(' ', array_map(array(__NAMESPACE__.'\\ProcessUtils', 'escapeArgument'), $arguments));
80689
80690 if ($this->inheritEnv) {
80691
80692 $env = array_replace($_ENV, $_SERVER, $this->env);
80693 } else {
80694 $env = $this->env;
80695 }
80696
80697 $process = new Process($script, $this->cwd, $env, $this->input, $this->timeout, $options);
80698
80699 if ($this->outputDisabled) {
80700 $process->disableOutput();
80701 }
80702
80703 return $process;
80704 }
80705 }
80706 <?php
80707
80708
80709
80710
80711
80712
80713
80714
80715
80716
80717 namespace Symfony\Component\Process;
80718
80719 use Symfony\Component\Process\Exception\InvalidArgumentException;
80720
80721
80722
80723
80724
80725
80726
80727
80728 class ProcessUtils
80729 {
80730
80731
80732
80733 private function __construct()
80734 {
80735 }
80736
80737
80738
80739
80740
80741
80742
80743
80744 public static function escapeArgument($argument)
80745 {
80746
80747
80748
80749
80750 if ('\\' === \DIRECTORY_SEPARATOR) {
80751 if ('' === $argument) {
80752 return escapeshellarg($argument);
80753 }
80754
80755 $escapedArgument = '';
80756 $quote = false;
80757 foreach (preg_split('/(")/', $argument, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $part) {
80758 if ('"' === $part) {
80759 $escapedArgument .= '\\"';
80760 } elseif (self::isSurroundedBy($part, '%')) {
80761
80762 $escapedArgument .= '^%"'.substr($part, 1, -1).'"^%';
80763 } else {
80764
80765 if ('\\' === substr($part, -1)) {
80766 $part .= '\\';
80767 }
80768 $quote = true;
80769 $escapedArgument .= $part;
80770 }
80771 }
80772 if ($quote) {
80773 $escapedArgument = '"'.$escapedArgument.'"';
80774 }
80775
80776 return $escapedArgument;
80777 }
80778
80779 return "'".str_replace("'", "'\\''", $argument)."'";
80780 }
80781
80782
80783
80784
80785
80786
80787
80788
80789
80790
80791
80792
80793
80794 public static function validateInput($caller, $input)
80795 {
80796 if (null !== $input) {
80797 if (\is_resource($input)) {
80798 return $input;
80799 }
80800 if (\is_string($input)) {
80801 return $input;
80802 }
80803 if (is_scalar($input)) {
80804 return (string) $input;
80805 }
80806
80807 if (\is_object($input) && method_exists($input, '__toString')) {
80808 @trigger_error('Passing an object as an input is deprecated since Symfony 2.5 and will be removed in 3.0.', E_USER_DEPRECATED);
80809
80810 return (string) $input;
80811 }
80812
80813 throw new InvalidArgumentException(sprintf('%s only accepts strings or stream resources.', $caller));
80814 }
80815
80816 return $input;
80817 }
80818
80819 private static function isSurroundedBy($arg, $char)
80820 {
80821 return 2 < \strlen($arg) && $char === $arg[0] && $char === $arg[\strlen($arg) - 1];
80822 }
80823 }
80824 Copyright (c) 2011 Jordi Boggiano
80825
80826 Permission is hereby granted, free of charge, to any person obtaining a copy
80827 of this software and associated documentation files (the "Software"), to deal
80828 in the Software without restriction, including without limitation the rights
80829 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
80830 copies of the Software, and to permit persons to whom the Software is furnished
80831 to do so, subject to the following conditions:
80832
80833 The above copyright notice and this permission notice shall be included in all
80834 copies or substantial portions of the Software.
80835
80836 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
80837 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
80838 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
80839 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
80840 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
80841 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
80842 THE SOFTWARE.
80843 <?php
80844
80845
80846
80847
80848
80849
80850
80851
80852
80853
80854 namespace Seld\JsonLint;
80855
80856 class DuplicateKeyException extends ParsingException
80857 {
80858
80859
80860
80861
80862
80863 public function __construct($message, $key, array $details = array())
80864 {
80865 $details['key'] = $key;
80866 parent::__construct($message, $details);
80867 }
80868
80869 public function getKey()
80870 {
80871 return $this->details['key'];
80872 }
80873
80874
80875
80876
80877 public function getDetails()
80878 {
80879 return $this->details;
80880 }
80881 }
80882 <?php
80883
80884
80885
80886
80887
80888
80889
80890
80891
80892
80893 namespace Seld\JsonLint;
80894 use stdClass;
80895
80896
80897
80898
80899
80900
80901
80902
80903
80904
80905
80906
80907
80908
80909 class JsonParser
80910 {
80911 const DETECT_KEY_CONFLICTS = 1;
80912 const ALLOW_DUPLICATE_KEYS = 2;
80913 const PARSE_TO_ASSOC = 4;
80914
80915 private $lexer;
80916
80917 private $flags;
80918 private $stack;
80919 private $vstack; 
80920 private $lstack; 
80921
80922
80923
80924
80925 private $symbols = array(
80926 'error' => 2,
80927 'JSONString' => 3,
80928 'STRING' => 4,
80929 'JSONNumber' => 5,
80930 'NUMBER' => 6,
80931 'JSONNullLiteral' => 7,
80932 'NULL' => 8,
80933 'JSONBooleanLiteral' => 9,
80934 'TRUE' => 10,
80935 'FALSE' => 11,
80936 'JSONText' => 12,
80937 'JSONValue' => 13,
80938 'EOF' => 14,
80939 'JSONObject' => 15,
80940 'JSONArray' => 16,
80941 '{' => 17,
80942 '}' => 18,
80943 'JSONMemberList' => 19,
80944 'JSONMember' => 20,
80945 ':' => 21,
80946 ',' => 22,
80947 '[' => 23,
80948 ']' => 24,
80949 'JSONElementList' => 25,
80950 '$accept' => 0,
80951 '$end' => 1,
80952 );
80953
80954
80955
80956
80957 private $terminals_ = array(
80958 2 => "error",
80959 4 => "STRING",
80960 6 => "NUMBER",
80961 8 => "NULL",
80962 10 => "TRUE",
80963 11 => "FALSE",
80964 14 => "EOF",
80965 17 => "{",
80966 18 => "}",
80967 21 => ":",
80968 22 => ",",
80969 23 => "[",
80970 24 => "]",
80971 );
80972
80973 private $productions_ = array(
80974 0,
80975 array(3, 1),
80976 array(5, 1),
80977 array(7, 1),
80978 array(9, 1),
80979 array(9, 1),
80980 array(12, 2),
80981 array(13, 1),
80982 array(13, 1),
80983 array(13, 1),
80984 array(13, 1),
80985 array(13, 1),
80986 array(13, 1),
80987 array(15, 2),
80988 array(15, 3),
80989 array(20, 3),
80990 array(19, 1),
80991 array(19, 3),
80992 array(16, 2),
80993 array(16, 3),
80994 array(25, 1),
80995 array(25, 3)
80996 );
80997
80998 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)),
80999 );
81000
81001 private $defaultActions = array(
81002 16 => array(2, 6)
81003 );
81004
81005
81006
81007
81008
81009
81010 public function lint($input, $flags = 0)
81011 {
81012 try {
81013 $this->parse($input, $flags);
81014 } catch (ParsingException $e) {
81015 return $e;
81016 }
81017 return null;
81018 }
81019
81020
81021
81022
81023
81024
81025
81026 public function parse($input, $flags = 0)
81027 {
81028 $this->failOnBOM($input);
81029
81030 $this->flags = $flags;
81031
81032 $this->stack = array(0);
81033 $this->vstack = array(null);
81034 $this->lstack = array();
81035
81036 $yytext = '';
81037 $yylineno = 0;
81038 $yyleng = 0;
81039 $recovering = 0;
81040 $TERROR = 2;
81041 $EOF = 1;
81042
81043 $this->lexer = new Lexer();
81044 $this->lexer->setInput($input);
81045
81046 $yyloc = $this->lexer->yylloc;
81047 $this->lstack[] = $yyloc;
81048
81049 $symbol = null;
81050 $preErrorSymbol = null;
81051 $state = null;
81052 $action = null;
81053 $a = null;
81054 $r = null;
81055 $yyval = new stdClass;
81056 $p = null;
81057 $len = null;
81058 $newState = null;
81059 $expected = null;
81060 $errStr = null;
81061
81062 while (true) {
81063
81064 $state = $this->stack[\count($this->stack)-1];
81065
81066
81067 if (isset($this->defaultActions[$state])) {
81068 $action = $this->defaultActions[$state];
81069 } else {
81070 if ($symbol == null) {
81071 $symbol = $this->lex();
81072 }
81073
81074 $action = isset($this->table[$state][$symbol]) ? $this->table[$state][$symbol] : false;
81075 }
81076
81077
81078 if (!$action || !$action[0]) {
81079 if (!$recovering) {
81080
81081 $expected = array();
81082 foreach ($this->table[$state] as $p => $ignore) {
81083 if (isset($this->terminals_[$p]) && $p > 2) {
81084 $expected[] = "'" . $this->terminals_[$p] . "'";
81085 }
81086 }
81087
81088 $message = null;
81089 if (\in_array("'STRING'", $expected) && \in_array(substr($this->lexer->match, 0, 1), array('"', "'"))) {
81090 $message = "Invalid string";
81091 if ("'" === substr($this->lexer->match, 0, 1)) {
81092 $message .= ", it appears you used single quotes instead of double quotes";
81093 } elseif (preg_match('{".+?(\\\\[^"bfnrt/\\\\u](...)?)}', $this->lexer->getFullUpcomingInput(), $match)) {
81094 $message .= ", it appears you have an unescaped backslash at: ".$match[1];
81095 } elseif (preg_match('{"(?:[^"]+|\\\\")*$}m', $this->lexer->getFullUpcomingInput())) {
81096 $message .= ", it appears you forgot to terminate a string, or attempted to write a multiline string which is invalid";
81097 }
81098 }
81099
81100 $errStr = 'Parse error on line ' . ($yylineno+1) . ":\n";
81101 $errStr .= $this->lexer->showPosition() . "\n";
81102 if ($message) {
81103 $errStr .= $message;
81104 } else {
81105 $errStr .= (\count($expected) > 1) ? "Expected one of: " : "Expected: ";
81106 $errStr .= implode(', ', $expected);
81107 }
81108
81109 if (',' === substr(trim($this->lexer->getPastInput()), -1)) {
81110 $errStr .= " - It appears you have an extra trailing comma";
81111 }
81112
81113 $this->parseError($errStr, array(
81114 'text' => $this->lexer->match,
81115 'token' => !empty($this->terminals_[$symbol]) ? $this->terminals_[$symbol] : $symbol,
81116 'line' => $this->lexer->yylineno,
81117 'loc' => $yyloc,
81118 'expected' => $expected,
81119 ));
81120 }
81121
81122
81123 if ($recovering == 3) {
81124 if ($symbol == $EOF) {
81125 throw new ParsingException($errStr ?: 'Parsing halted.');
81126 }
81127
81128
81129 $yyleng = $this->lexer->yyleng;
81130 $yytext = $this->lexer->yytext;
81131 $yylineno = $this->lexer->yylineno;
81132 $yyloc = $this->lexer->yylloc;
81133 $symbol = $this->lex();
81134 }
81135
81136
81137 while (true) {
81138
81139 if (\array_key_exists($TERROR, $this->table[$state])) {
81140 break;
81141 }
81142 if ($state == 0) {
81143 throw new ParsingException($errStr ?: 'Parsing halted.');
81144 }
81145 $this->popStack(1);
81146 $state = $this->stack[\count($this->stack)-1];
81147 }
81148
81149 $preErrorSymbol = $symbol; 
81150 $symbol = $TERROR; 
81151 $state = $this->stack[\count($this->stack)-1];
81152 $action = isset($this->table[$state][$TERROR]) ? $this->table[$state][$TERROR] : false;
81153 $recovering = 3; 
81154 }
81155
81156
81157 if (\is_array($action[0]) && \count($action) > 1) {
81158 throw new ParsingException('Parse Error: multiple actions possible at state: ' . $state . ', token: ' . $symbol);
81159 }
81160
81161 switch ($action[0]) {
81162 case 1: 
81163 $this->stack[] = $symbol;
81164 $this->vstack[] = $this->lexer->yytext;
81165 $this->lstack[] = $this->lexer->yylloc;
81166 $this->stack[] = $action[1]; 
81167 $symbol = null;
81168 if (!$preErrorSymbol) { 
81169 $yyleng = $this->lexer->yyleng;
81170 $yytext = $this->lexer->yytext;
81171 $yylineno = $this->lexer->yylineno;
81172 $yyloc = $this->lexer->yylloc;
81173 if ($recovering > 0) {
81174 $recovering--;
81175 }
81176 } else { 
81177 $symbol = $preErrorSymbol;
81178 $preErrorSymbol = null;
81179 }
81180 break;
81181
81182 case 2: 
81183 $len = $this->productions_[$action[1]][1];
81184
81185
81186 $yyval->token = $this->vstack[\count($this->vstack) - $len]; 
81187
81188 $yyval->store = array( 
81189 'first_line' => $this->lstack[\count($this->lstack) - ($len ?: 1)]['first_line'],
81190 'last_line' => $this->lstack[\count($this->lstack) - 1]['last_line'],
81191 'first_column' => $this->lstack[\count($this->lstack) - ($len ?: 1)]['first_column'],
81192 'last_column' => $this->lstack[\count($this->lstack) - 1]['last_column'],
81193 );
81194 $r = $this->performAction($yyval, $yytext, $yyleng, $yylineno, $action[1], $this->vstack);
81195
81196 if (!$r instanceof Undefined) {
81197 return $r;
81198 }
81199
81200 if ($len) {
81201 $this->popStack($len);
81202 }
81203
81204 $this->stack[] = $this->productions_[$action[1]][0]; 
81205 $this->vstack[] = $yyval->token;
81206 $this->lstack[] = $yyval->store;
81207 $newState = $this->table[$this->stack[\count($this->stack)-2]][$this->stack[\count($this->stack)-1]];
81208 $this->stack[] = $newState;
81209 break;
81210
81211 case 3: 
81212
81213 return true;
81214 }
81215 }
81216 }
81217
81218 protected function parseError($str, $hash)
81219 {
81220 throw new ParsingException($str, $hash);
81221 }
81222
81223
81224
81225
81226 private function performAction(stdClass $yyval, $yytext, $yyleng, $yylineno, $yystate, &$tokens)
81227 {
81228
81229 $len = \count($tokens) - 1;
81230 switch ($yystate) {
81231 case 1:
81232 $yytext = preg_replace_callback('{(?:\\\\["bfnrt/\\\\]|\\\\u[a-fA-F0-9]{4})}', array($this, 'stringInterpolation'), $yytext);
81233 $yyval->token = $yytext;
81234 break;
81235 case 2:
81236 if (strpos($yytext, 'e') !== false || strpos($yytext, 'E') !== false) {
81237 $yyval->token = \floatval($yytext);
81238 } else {
81239 $yyval->token = strpos($yytext, '.') === false ? \intval($yytext) : \floatval($yytext);
81240 }
81241 break;
81242 case 3:
81243 $yyval->token = null;
81244 break;
81245 case 4:
81246 $yyval->token = true;
81247 break;
81248 case 5:
81249 $yyval->token = false;
81250 break;
81251 case 6:
81252 return $yyval->token = $tokens[$len-1];
81253 case 13:
81254 if ($this->flags & self::PARSE_TO_ASSOC) {
81255 $yyval->token = array();
81256 } else {
81257 $yyval->token = new stdClass;
81258 }
81259 break;
81260 case 14:
81261 $yyval->token = $tokens[$len-1];
81262 break;
81263 case 15:
81264 $yyval->token = array($tokens[$len-2], $tokens[$len]);
81265 break;
81266 case 16:
81267 if (PHP_VERSION_ID < 70100) {
81268 $property = $tokens[$len][0] === '' ? '_empty_' : $tokens[$len][0];
81269 } else {
81270 $property = $tokens[$len][0];
81271 }
81272 if ($this->flags & self::PARSE_TO_ASSOC) {
81273 $yyval->token = array();
81274 $yyval->token[$property] = $tokens[$len][1];
81275 } else {
81276 $yyval->token = new stdClass;
81277 $yyval->token->$property = $tokens[$len][1];
81278 }
81279 break;
81280 case 17:
81281 if ($this->flags & self::PARSE_TO_ASSOC) {
81282 $yyval->token =& $tokens[$len-2];
81283 $key = $tokens[$len][0];
81284 if (($this->flags & self::DETECT_KEY_CONFLICTS) && isset($tokens[$len-2][$key])) {
81285 $errStr = 'Parse error on line ' . ($yylineno+1) . ":\n";
81286 $errStr .= $this->lexer->showPosition() . "\n";
81287 $errStr .= "Duplicate key: ".$tokens[$len][0];
81288 throw new DuplicateKeyException($errStr, $tokens[$len][0], array('line' => $yylineno+1));
81289 } elseif (($this->flags & self::ALLOW_DUPLICATE_KEYS) && isset($tokens[$len-2][$key])) {
81290 $duplicateCount = 1;
81291 do {
81292 $duplicateKey = $key . '.' . $duplicateCount++;
81293 } while (isset($tokens[$len-2][$duplicateKey]));
81294 $key = $duplicateKey;
81295 }
81296 $tokens[$len-2][$key] = $tokens[$len][1];
81297 } else {
81298 $yyval->token = $tokens[$len-2];
81299 if (PHP_VERSION_ID < 70100) {
81300 $key = $tokens[$len][0] === '' ? '_empty_' : $tokens[$len][0];
81301 } else {
81302 $key = $tokens[$len][0];
81303 }
81304 if (($this->flags & self::DETECT_KEY_CONFLICTS) && isset($tokens[$len-2]->{$key})) {
81305 $errStr = 'Parse error on line ' . ($yylineno+1) . ":\n";
81306 $errStr .= $this->lexer->showPosition() . "\n";
81307 $errStr .= "Duplicate key: ".$tokens[$len][0];
81308 throw new DuplicateKeyException($errStr, $tokens[$len][0], array('line' => $yylineno+1));
81309 } elseif (($this->flags & self::ALLOW_DUPLICATE_KEYS) && isset($tokens[$len-2]->{$key})) {
81310 $duplicateCount = 1;
81311 do {
81312 $duplicateKey = $key . '.' . $duplicateCount++;
81313 } while (isset($tokens[$len-2]->$duplicateKey));
81314 $key = $duplicateKey;
81315 }
81316 $tokens[$len-2]->$key = $tokens[$len][1];
81317 }
81318 break;
81319 case 18:
81320 $yyval->token = array();
81321 break;
81322 case 19:
81323 $yyval->token = $tokens[$len-1];
81324 break;
81325 case 20:
81326 $yyval->token = array($tokens[$len]);
81327 break;
81328 case 21:
81329 $tokens[$len-2][] = $tokens[$len];
81330 $yyval->token = $tokens[$len-2];
81331 break;
81332 }
81333
81334 return new Undefined();
81335 }
81336
81337 private function stringInterpolation($match)
81338 {
81339 switch ($match[0]) {
81340 case '\\\\':
81341 return '\\';
81342 case '\"':
81343 return '"';
81344 case '\b':
81345 return \chr(8);
81346 case '\f':
81347 return \chr(12);
81348 case '\n':
81349 return "\n";
81350 case '\r':
81351 return "\r";
81352 case '\t':
81353 return "\t";
81354 case '\/':
81355 return "/";
81356 default:
81357 return html_entity_decode('&#x'.ltrim(substr($match[0], 2), '0').';', ENT_QUOTES, 'UTF-8');
81358 }
81359 }
81360
81361 private function popStack($n)
81362 {
81363 $this->stack = \array_slice($this->stack, 0, - (2 * $n));
81364 $this->vstack = \array_slice($this->vstack, 0, - $n);
81365 $this->lstack = \array_slice($this->lstack, 0, - $n);
81366 }
81367
81368 private function lex()
81369 {
81370 $token = $this->lexer->lex() ?: 1; 
81371
81372 if (!is_numeric($token)) {
81373 $token = isset($this->symbols[$token]) ? $this->symbols[$token] : $token;
81374 }
81375
81376 return $token;
81377 }
81378
81379 private function failOnBOM($input)
81380 {
81381
81382 $bom = "\xEF\xBB\xBF";
81383
81384 if (substr($input, 0, 3) === $bom) {
81385 $this->parseError("BOM detected, make sure your input does not include a Unicode Byte-Order-Mark", array());
81386 }
81387 }
81388 }
81389 <?php
81390
81391
81392
81393
81394
81395
81396
81397
81398
81399
81400 namespace Seld\JsonLint;
81401
81402
81403
81404
81405
81406
81407 class Lexer
81408 {
81409 private $EOF = 1;
81410
81411
81412
81413 private $rules = array(
81414 0 => '/\G\s+/',
81415 1 => '/\G-?([0-9]|[1-9][0-9]+)(\.[0-9]+)?([eE][+-]?[0-9]+)?\b/',
81416 2 => '{\G"(?>\\\\["bfnrt/\\\\]|\\\\u[a-fA-F0-9]{4}|[^\0-\x1f\\\\"]++)*+"}',
81417 3 => '/\G\{/',
81418 4 => '/\G\}/',
81419 5 => '/\G\[/',
81420 6 => '/\G\]/',
81421 7 => '/\G,/',
81422 8 => '/\G:/',
81423 9 => '/\Gtrue\b/',
81424 10 => '/\Gfalse\b/',
81425 11 => '/\Gnull\b/',
81426 12 => '/\G$/',
81427 13 => '/\G./',
81428 );
81429
81430 private $conditions = array(
81431 "INITIAL" => array(
81432 "rules" => array(0,1,2,3,4,5,6,7,8,9,10,11,12,13),
81433 "inclusive" => true,
81434 ),
81435 );
81436
81437 private $conditionStack;
81438 private $input;
81439 private $more;
81440 private $done;
81441 private $offset;
81442
81443 public $match;
81444 public $yylineno;
81445 public $yyleng;
81446 public $yytext;
81447 public $yylloc;
81448
81449 public function lex()
81450 {
81451 $r = $this->next();
81452 if (!$r instanceof Undefined) {
81453 return $r;
81454 }
81455
81456 return $this->lex();
81457 }
81458
81459 public function setInput($input)
81460 {
81461 $this->input = $input;
81462 $this->more = false;
81463 $this->done = false;
81464 $this->offset = 0;
81465 $this->yylineno = $this->yyleng = 0;
81466 $this->yytext = $this->match = '';
81467 $this->conditionStack = array('INITIAL');
81468 $this->yylloc = array('first_line' => 1, 'first_column' => 0, 'last_line' => 1, 'last_column' => 0);
81469
81470 return $this;
81471 }
81472
81473 public function showPosition()
81474 {
81475 $pre = str_replace("\n", '', $this->getPastInput());
81476 $c = str_repeat('-', max(0, \strlen($pre) - 1)); 
81477
81478 return $pre . str_replace("\n", '', $this->getUpcomingInput()) . "\n" . $c . "^";
81479 }
81480
81481 public function getPastInput()
81482 {
81483 $pastLength = $this->offset - \strlen($this->match);
81484
81485 return ($pastLength > 20 ? '...' : '') . substr($this->input, max(0, $pastLength - 20), min(20, $pastLength));
81486 }
81487
81488 public function getUpcomingInput()
81489 {
81490 $next = $this->match;
81491 if (\strlen($next) < 20) {
81492 $next .= substr($this->input, $this->offset, 20 - \strlen($next));
81493 }
81494
81495 return substr($next, 0, 20) . (\strlen($next) > 20 ? '...' : '');
81496 }
81497
81498 public function getFullUpcomingInput()
81499 {
81500 $next = $this->match;
81501 if (substr($next, 0, 1) === '"' && substr_count($next, '"') === 1) {
81502 $len = \strlen($this->input);
81503 $strEnd = min(strpos($this->input, '"', $this->offset + 1) ?: $len, strpos($this->input, "\n", $this->offset + 1) ?: $len);
81504 $next .= substr($this->input, $this->offset, $strEnd - $this->offset);
81505 } elseif (\strlen($next) < 20) {
81506 $next .= substr($this->input, $this->offset, 20 - \strlen($next));
81507 }
81508
81509 return $next;
81510 }
81511
81512 protected function parseError($str, $hash)
81513 {
81514 throw new \Exception($str);
81515 }
81516
81517 private function next()
81518 {
81519 if ($this->done) {
81520 return $this->EOF;
81521 }
81522 if ($this->offset === \strlen($this->input)) {
81523 $this->done = true;
81524 }
81525
81526 $token = null;
81527 $match = null;
81528 $col = null;
81529 $lines = null;
81530
81531 if (!$this->more) {
81532 $this->yytext = '';
81533 $this->match = '';
81534 }
81535
81536 $rules = $this->getCurrentRules();
81537 $rulesLen = \count($rules);
81538
81539 for ($i=0; $i < $rulesLen; $i++) {
81540 if (preg_match($this->rules[$rules[$i]], $this->input, $match, 0, $this->offset)) {
81541 preg_match_all('/\n.*/', $match[0], $lines);
81542 $lines = $lines[0];
81543 if ($lines) {
81544 $this->yylineno += \count($lines);
81545 }
81546
81547 $this->yylloc = array(
81548 'first_line' => $this->yylloc['last_line'],
81549 'last_line' => $this->yylineno+1,
81550 'first_column' => $this->yylloc['last_column'],
81551 'last_column' => $lines ? \strlen($lines[\count($lines) - 1]) - 1 : $this->yylloc['last_column'] + \strlen($match[0]),
81552 );
81553 $this->yytext .= $match[0];
81554 $this->match .= $match[0];
81555 $this->yyleng = \strlen($this->yytext);
81556 $this->more = false;
81557 $this->offset += \strlen($match[0]);
81558 $token = $this->performAction($rules[$i], $this->conditionStack[\count($this->conditionStack)-1]);
81559 if ($token) {
81560 return $token;
81561 }
81562
81563 return new Undefined();
81564 }
81565 }
81566
81567 if ($this->offset === \strlen($this->input)) {
81568 return $this->EOF;
81569 }
81570
81571 $this->parseError(
81572 'Lexical error on line ' . ($this->yylineno+1) . ". Unrecognized text.\n" . $this->showPosition(),
81573 array(
81574 'text' => "",
81575 'token' => null,
81576 'line' => $this->yylineno,
81577 )
81578 );
81579 }
81580
81581 private function getCurrentRules()
81582 {
81583 return $this->conditions[$this->conditionStack[\count($this->conditionStack)-1]]['rules'];
81584 }
81585
81586 private function performAction($avoiding_name_collisions, $YY_START)
81587 {
81588 switch ($avoiding_name_collisions) {
81589 case 0:
81590 break;
81591 case 1:
81592 return 6;
81593 case 2:
81594 $this->yytext = substr($this->yytext, 1, $this->yyleng-2);
81595
81596 return 4;
81597 case 3:
81598 return 17;
81599 case 4:
81600 return 18;
81601 case 5:
81602 return 23;
81603 case 6:
81604 return 24;
81605 case 7:
81606 return 22;
81607 case 8:
81608 return 21;
81609 case 9:
81610 return 10;
81611 case 10:
81612 return 11;
81613 case 11:
81614 return 8;
81615 case 12:
81616 return 14;
81617 case 13:
81618 return 'INVALID';
81619 }
81620 }
81621 }
81622 <?php
81623
81624
81625
81626
81627
81628
81629
81630
81631
81632
81633 namespace Seld\JsonLint;
81634
81635 class ParsingException extends \Exception
81636 {
81637 protected $details;
81638
81639
81640
81641
81642
81643 public function __construct($message, $details = array())
81644 {
81645 $this->details = $details;
81646 parent::__construct($message);
81647 }
81648
81649
81650
81651
81652 public function getDetails()
81653 {
81654 return $this->details;
81655 }
81656 }
81657 <?php
81658
81659
81660
81661
81662
81663
81664
81665
81666
81667
81668 namespace Seld\JsonLint;
81669
81670 class Undefined
81671 {
81672 }
81673 MIT License
81674
81675 Copyright (c) 2016
81676
81677 Permission is hereby granted, free of charge, to any person obtaining a copy
81678 of this software and associated documentation files (the "Software"), to deal
81679 in the Software without restriction, including without limitation the rights
81680 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
81681 copies of the Software, and to permit persons to whom the Software is
81682 furnished to do so, subject to the following conditions:
81683
81684 The above copyright notice and this permission notice shall be included in all
81685 copies or substantial portions of the Software.
81686
81687 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
81688 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
81689 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
81690 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
81691 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
81692 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
81693 SOFTWARE.
81694 <?php
81695
81696 require __DIR__ . '/../vendor/autoload.php';
81697
81698 $data = json_decode(file_get_contents('data.json'));
81699
81700
81701 $validator = new JsonSchema\Validator();
81702 $validator->check($data, (object) array('$ref' => 'file://' . realpath('schema.json')));
81703
81704 if ($validator->isValid()) {
81705 echo "The supplied JSON validates against the schema.\n";
81706 } else {
81707 echo "JSON does not validate. Violations:\n";
81708 foreach ($validator->getErrors() as $error) {
81709 echo sprintf("[%s] %s\n", $error['property'], $error['message']);
81710 }
81711 }
81712 <?php
81713
81714
81715
81716
81717
81718
81719
81720
81721 namespace JsonSchema\Constraints;
81722
81723 use JsonSchema\Entity\JsonPointer;
81724 use JsonSchema\Exception\InvalidArgumentException;
81725 use JsonSchema\Exception\ValidationException;
81726 use JsonSchema\Validator;
81727
81728
81729
81730
81731
81732 class BaseConstraint
81733 {
81734
81735
81736
81737 protected $errors = array();
81738
81739
81740
81741
81742 protected $errorMask = Validator::ERROR_NONE;
81743
81744
81745
81746
81747 protected $factory;
81748
81749
81750
81751
81752 public function __construct(Factory $factory = null)
81753 {
81754 $this->factory = $factory ?: new Factory();
81755 }
81756
81757 public function addError(JsonPointer $path = null, $message, $constraint = '', array $more = null)
81758 {
81759 $error = array(
81760 'property' => $this->convertJsonPointerIntoPropertyPath($path ?: new JsonPointer('')),
81761 'pointer' => ltrim(strval($path ?: new JsonPointer('')), '#'),
81762 'message' => $message,
81763 'constraint' => $constraint,
81764 'context' => $this->factory->getErrorContext(),
81765 );
81766
81767 if ($this->factory->getConfig(Constraint::CHECK_MODE_EXCEPTIONS)) {
81768 throw new ValidationException(sprintf('Error validating %s: %s', $error['pointer'], $error['message']));
81769 }
81770
81771 if (is_array($more) && count($more) > 0) {
81772 $error += $more;
81773 }
81774
81775 $this->errors[] = $error;
81776 $this->errorMask |= $error['context'];
81777 }
81778
81779 public function addErrors(array $errors)
81780 {
81781 if ($errors) {
81782 $this->errors = array_merge($this->errors, $errors);
81783 $errorMask = &$this->errorMask;
81784 array_walk($errors, function ($error) use (&$errorMask) {
81785 if (isset($error['context'])) {
81786 $errorMask |= $error['context'];
81787 }
81788 });
81789 }
81790 }
81791
81792 public function getErrors($errorContext = Validator::ERROR_ALL)
81793 {
81794 if ($errorContext === Validator::ERROR_ALL) {
81795 return $this->errors;
81796 }
81797
81798 return array_filter($this->errors, function ($error) use ($errorContext) {
81799 if ($errorContext & $error['context']) {
81800 return true;
81801 }
81802 });
81803 }
81804
81805 public function numErrors($errorContext = Validator::ERROR_ALL)
81806 {
81807 if ($errorContext === Validator::ERROR_ALL) {
81808 return count($this->errors);
81809 }
81810
81811 return count($this->getErrors($errorContext));
81812 }
81813
81814 public function isValid()
81815 {
81816 return !$this->getErrors();
81817 }
81818
81819
81820
81821
81822
81823 public function reset()
81824 {
81825 $this->errors = array();
81826 $this->errorMask = Validator::ERROR_NONE;
81827 }
81828
81829
81830
81831
81832
81833
81834 public function getErrorMask()
81835 {
81836 return $this->errorMask;
81837 }
81838
81839
81840
81841
81842
81843
81844
81845
81846 public static function arrayToObjectRecursive($array)
81847 {
81848 $json = json_encode($array);
81849 if (json_last_error() !== \JSON_ERROR_NONE) {
81850 $message = 'Unable to encode schema array as JSON';
81851 if (function_exists('json_last_error_msg')) {
81852 $message .= ': ' . json_last_error_msg();
81853 }
81854 throw new InvalidArgumentException($message);
81855 }
81856
81857 return (object) json_decode($json);
81858 }
81859 }
81860 <?php
81861
81862
81863
81864
81865
81866
81867
81868
81869 namespace JsonSchema\Constraints;
81870
81871 use JsonSchema\Entity\JsonPointer;
81872
81873
81874
81875
81876
81877
81878
81879 class CollectionConstraint extends Constraint
81880 {
81881
81882
81883
81884 public function check(&$value, $schema = null, JsonPointer $path = null, $i = null)
81885 {
81886
81887 if (isset($schema->minItems) && count($value) < $schema->minItems) {
81888 $this->addError($path, 'There must be a minimum of ' . $schema->minItems . ' items in the array', 'minItems', array('minItems' => $schema->minItems));
81889 }
81890
81891
81892 if (isset($schema->maxItems) && count($value) > $schema->maxItems) {
81893 $this->addError($path, 'There must be a maximum of ' . $schema->maxItems . ' items in the array', 'maxItems', array('maxItems' => $schema->maxItems));
81894 }
81895
81896
81897 if (isset($schema->uniqueItems) && $schema->uniqueItems) {
81898 $unique = $value;
81899 if (is_array($value) && count($value)) {
81900 $unique = array_map(function ($e) {
81901 return var_export($e, true);
81902 }, $value);
81903 }
81904 if (count(array_unique($unique)) != count($value)) {
81905 $this->addError($path, 'There are no duplicates allowed in the array', 'uniqueItems');
81906 }
81907 }
81908
81909
81910 if (isset($schema->items)) {
81911 $this->validateItems($value, $schema, $path, $i);
81912 }
81913 }
81914
81915
81916
81917
81918
81919
81920
81921
81922
81923 protected function validateItems(&$value, $schema = null, JsonPointer $path = null, $i = null)
81924 {
81925 if (is_object($schema->items)) {
81926
81927 foreach ($value as $k => &$v) {
81928 $initErrors = $this->getErrors();
81929
81930
81931 $this->checkUndefined($v, $schema->items, $path, $k);
81932
81933
81934 if (count($initErrors) < count($this->getErrors()) && (isset($schema->additionalItems) && $schema->additionalItems !== false)) {
81935 $secondErrors = $this->getErrors();
81936 $this->checkUndefined($v, $schema->additionalItems, $path, $k);
81937 }
81938
81939
81940 if (isset($secondErrors) && count($secondErrors) < count($this->getErrors())) {
81941 $this->errors = $secondErrors;
81942 } elseif (isset($secondErrors) && count($secondErrors) === count($this->getErrors())) {
81943 $this->errors = $initErrors;
81944 }
81945 }
81946 unset($v); 
81947
81948 } else {
81949
81950 foreach ($value as $k => &$v) {
81951 if (array_key_exists($k, $schema->items)) {
81952 $this->checkUndefined($v, $schema->items[$k], $path, $k);
81953 } else {
81954
81955 if (property_exists($schema, 'additionalItems')) {
81956 if ($schema->additionalItems !== false) {
81957 $this->checkUndefined($v, $schema->additionalItems, $path, $k);
81958 } else {
81959 $this->addError(
81960 $path, 'The item ' . $i . '[' . $k . '] is not defined and the definition does not allow additional items', 'additionalItems', array('additionalItems' => $schema->additionalItems));
81961 }
81962 } else {
81963
81964 $this->checkUndefined($v, new \stdClass(), $path, $k);
81965 }
81966 }
81967 }
81968 unset($v); 
81969
81970
81971
81972 if (count($value) > 0) {
81973 for ($k = count($value); $k < count($schema->items); $k++) {
81974 $undefinedInstance = $this->factory->createInstanceFor('undefined');
81975 $this->checkUndefined($undefinedInstance, $schema->items[$k], $path, $k);
81976 }
81977 }
81978 }
81979 }
81980 }
81981 <?php
81982
81983
81984
81985
81986
81987
81988
81989
81990 namespace JsonSchema\Constraints;
81991
81992 use JsonSchema\Entity\JsonPointer;
81993
81994
81995
81996
81997
81998
81999
82000 abstract class Constraint extends BaseConstraint implements ConstraintInterface
82001 {
82002 protected $inlineSchemaProperty = '$schema';
82003
82004 const CHECK_MODE_NONE = 0x00000000;
82005 const CHECK_MODE_NORMAL = 0x00000001;
82006 const CHECK_MODE_TYPE_CAST = 0x00000002;
82007 const CHECK_MODE_COERCE_TYPES = 0x00000004;
82008 const CHECK_MODE_APPLY_DEFAULTS = 0x00000008;
82009 const CHECK_MODE_EXCEPTIONS = 0x00000010;
82010 const CHECK_MODE_DISABLE_FORMAT = 0x00000020;
82011 const CHECK_MODE_ONLY_REQUIRED_DEFAULTS = 0x00000080;
82012 const CHECK_MODE_VALIDATE_SCHEMA = 0x00000100;
82013
82014
82015
82016
82017
82018
82019
82020
82021
82022 protected function incrementPath(JsonPointer $path = null, $i)
82023 {
82024 $path = $path ?: new JsonPointer('');
82025 $path = $path->withPropertyPaths(
82026 array_merge(
82027 $path->getPropertyPaths(),
82028 array_filter(array($i), 'strlen')
82029 )
82030 );
82031
82032 return $path;
82033 }
82034
82035
82036
82037
82038
82039
82040
82041
82042
82043 protected function checkArray(&$value, $schema = null, JsonPointer $path = null, $i = null)
82044 {
82045 $validator = $this->factory->createInstanceFor('collection');
82046 $validator->check($value, $schema, $path, $i);
82047
82048 $this->addErrors($validator->getErrors());
82049 }
82050
82051
82052
82053
82054
82055
82056
82057
82058
82059
82060
82061 protected function checkObject(&$value, $schema = null, JsonPointer $path = null, $properties = null,
82062 $additionalProperties = null, $patternProperties = null, $appliedDefaults = array())
82063 {
82064 $validator = $this->factory->createInstanceFor('object');
82065 $validator->check($value, $schema, $path, $properties, $additionalProperties, $patternProperties, $appliedDefaults);
82066
82067 $this->addErrors($validator->getErrors());
82068 }
82069
82070
82071
82072
82073
82074
82075
82076
82077
82078 protected function checkType(&$value, $schema = null, JsonPointer $path = null, $i = null)
82079 {
82080 $validator = $this->factory->createInstanceFor('type');
82081 $validator->check($value, $schema, $path, $i);
82082
82083 $this->addErrors($validator->getErrors());
82084 }
82085
82086
82087
82088
82089
82090
82091
82092
82093
82094 protected function checkUndefined(&$value, $schema = null, JsonPointer $path = null, $i = null, $fromDefault = false)
82095 {
82096 $validator = $this->factory->createInstanceFor('undefined');
82097
82098 $validator->check($value, $this->factory->getSchemaStorage()->resolveRefSchema($schema), $path, $i, $fromDefault);
82099
82100 $this->addErrors($validator->getErrors());
82101 }
82102
82103
82104
82105
82106
82107
82108
82109
82110
82111 protected function checkString($value, $schema = null, JsonPointer $path = null, $i = null)
82112 {
82113 $validator = $this->factory->createInstanceFor('string');
82114 $validator->check($value, $schema, $path, $i);
82115
82116 $this->addErrors($validator->getErrors());
82117 }
82118
82119
82120
82121
82122
82123
82124
82125
82126
82127 protected function checkNumber($value, $schema = null, JsonPointer $path = null, $i = null)
82128 {
82129 $validator = $this->factory->createInstanceFor('number');
82130 $validator->check($value, $schema, $path, $i);
82131
82132 $this->addErrors($validator->getErrors());
82133 }
82134
82135
82136
82137
82138
82139
82140
82141
82142
82143 protected function checkEnum($value, $schema = null, JsonPointer $path = null, $i = null)
82144 {
82145 $validator = $this->factory->createInstanceFor('enum');
82146 $validator->check($value, $schema, $path, $i);
82147
82148 $this->addErrors($validator->getErrors());
82149 }
82150
82151
82152
82153
82154
82155
82156
82157
82158
82159 protected function checkFormat($value, $schema = null, JsonPointer $path = null, $i = null)
82160 {
82161 $validator = $this->factory->createInstanceFor('format');
82162 $validator->check($value, $schema, $path, $i);
82163
82164 $this->addErrors($validator->getErrors());
82165 }
82166
82167
82168
82169
82170
82171
82172 protected function getTypeCheck()
82173 {
82174 return $this->factory->getTypeCheck();
82175 }
82176
82177
82178
82179
82180
82181
82182 protected function convertJsonPointerIntoPropertyPath(JsonPointer $pointer)
82183 {
82184 $result = array_map(
82185 function ($path) {
82186 return sprintf(is_numeric($path) ? '[%d]' : '.%s', $path);
82187 },
82188 $pointer->getPropertyPaths()
82189 );
82190
82191 return trim(implode('', $result), '.');
82192 }
82193 }
82194 <?php
82195
82196
82197
82198
82199
82200
82201
82202
82203 namespace JsonSchema\Constraints;
82204
82205 use JsonSchema\Entity\JsonPointer;
82206
82207
82208
82209
82210
82211
82212 interface ConstraintInterface
82213 {
82214
82215
82216
82217
82218
82219 public function getErrors();
82220
82221
82222
82223
82224
82225
82226 public function addErrors(array $errors);
82227
82228
82229
82230
82231
82232
82233
82234
82235
82236 public function addError(JsonPointer $path = null, $message, $constraint='', array $more = null);
82237
82238
82239
82240
82241
82242
82243 public function isValid();
82244
82245
82246
82247
82248
82249
82250
82251
82252
82253
82254
82255
82256
82257 public function check(&$value, $schema = null, JsonPointer $path = null, $i = null);
82258 }
82259 <?php
82260
82261
82262
82263
82264
82265
82266
82267
82268 namespace JsonSchema\Constraints;
82269
82270 use JsonSchema\Entity\JsonPointer;
82271
82272
82273
82274
82275
82276
82277
82278 class EnumConstraint extends Constraint
82279 {
82280
82281
82282
82283 public function check(&$element, $schema = null, JsonPointer $path = null, $i = null)
82284 {
82285
82286 if ($element instanceof UndefinedConstraint && (!isset($schema->required) || !$schema->required)) {
82287 return;
82288 }
82289 $type = gettype($element);
82290
82291 foreach ($schema->enum as $enum) {
82292 $enumType = gettype($enum);
82293 if ($this->factory->getConfig(self::CHECK_MODE_TYPE_CAST) && $type == 'array' && $enumType == 'object') {
82294 if ((object) $element == $enum) {
82295 return;
82296 }
82297 }
82298
82299 if ($type === gettype($enum)) {
82300 if ($type == 'object') {
82301 if ($element == $enum) {
82302 return;
82303 }
82304 } elseif ($element === $enum) {
82305 return;
82306 }
82307 }
82308 }
82309
82310 $this->addError($path, 'Does not have a value in the enumeration ' . json_encode($schema->enum), 'enum', array('enum' => $schema->enum));
82311 }
82312 }
82313 <?php
82314
82315
82316
82317
82318
82319
82320
82321
82322 namespace JsonSchema\Constraints;
82323
82324 use JsonSchema\Exception\InvalidArgumentException;
82325 use JsonSchema\SchemaStorage;
82326 use JsonSchema\SchemaStorageInterface;
82327 use JsonSchema\Uri\UriRetriever;
82328 use JsonSchema\UriRetrieverInterface;
82329 use JsonSchema\Validator;
82330
82331
82332
82333
82334 class Factory
82335 {
82336
82337
82338
82339 protected $schemaStorage;
82340
82341
82342
82343
82344 protected $uriRetriever;
82345
82346
82347
82348
82349 private $checkMode = Constraint::CHECK_MODE_NORMAL;
82350
82351
82352
82353
82354 private $typeCheck = array();
82355
82356
82357
82358
82359 protected $errorContext = Validator::ERROR_DOCUMENT_VALIDATION;
82360
82361
82362
82363
82364 protected $constraintMap = array(
82365 'array' => 'JsonSchema\Constraints\CollectionConstraint',
82366 'collection' => 'JsonSchema\Constraints\CollectionConstraint',
82367 'object' => 'JsonSchema\Constraints\ObjectConstraint',
82368 'type' => 'JsonSchema\Constraints\TypeConstraint',
82369 'undefined' => 'JsonSchema\Constraints\UndefinedConstraint',
82370 'string' => 'JsonSchema\Constraints\StringConstraint',
82371 'number' => 'JsonSchema\Constraints\NumberConstraint',
82372 'enum' => 'JsonSchema\Constraints\EnumConstraint',
82373 'format' => 'JsonSchema\Constraints\FormatConstraint',
82374 'schema' => 'JsonSchema\Constraints\SchemaConstraint',
82375 'validator' => 'JsonSchema\Validator'
82376 );
82377
82378
82379
82380
82381 private $instanceCache = array();
82382
82383
82384
82385
82386
82387
82388 public function __construct(
82389 SchemaStorageInterface $schemaStorage = null,
82390 UriRetrieverInterface $uriRetriever = null,
82391 $checkMode = Constraint::CHECK_MODE_NORMAL
82392 ) {
82393
82394 $this->setConfig($checkMode);
82395
82396 $this->uriRetriever = $uriRetriever ?: new UriRetriever();
82397 $this->schemaStorage = $schemaStorage ?: new SchemaStorage($this->uriRetriever);
82398 }
82399
82400
82401
82402
82403
82404
82405 public function setConfig($checkMode = Constraint::CHECK_MODE_NORMAL)
82406 {
82407 $this->checkMode = $checkMode;
82408 }
82409
82410
82411
82412
82413
82414
82415 public function addConfig($options)
82416 {
82417 $this->checkMode |= $options;
82418 }
82419
82420
82421
82422
82423
82424
82425 public function removeConfig($options)
82426 {
82427 $this->checkMode &= ~$options;
82428 }
82429
82430
82431
82432
82433
82434
82435
82436
82437 public function getConfig($options = null)
82438 {
82439 if ($options === null) {
82440 return $this->checkMode;
82441 }
82442
82443 return $this->checkMode & $options;
82444 }
82445
82446
82447
82448
82449 public function getUriRetriever()
82450 {
82451 return $this->uriRetriever;
82452 }
82453
82454 public function getSchemaStorage()
82455 {
82456 return $this->schemaStorage;
82457 }
82458
82459 public function getTypeCheck()
82460 {
82461 if (!isset($this->typeCheck[$this->checkMode])) {
82462 $this->typeCheck[$this->checkMode] = ($this->checkMode & Constraint::CHECK_MODE_TYPE_CAST)
82463 ? new TypeCheck\LooseTypeCheck()
82464 : new TypeCheck\StrictTypeCheck();
82465 }
82466
82467 return $this->typeCheck[$this->checkMode];
82468 }
82469
82470
82471
82472
82473
82474
82475
82476 public function setConstraintClass($name, $class)
82477 {
82478
82479 if (!class_exists($class)) {
82480 throw new InvalidArgumentException('Unknown constraint ' . $name);
82481 }
82482
82483 if (!in_array('JsonSchema\Constraints\ConstraintInterface', class_implements($class))) {
82484 throw new InvalidArgumentException('Invalid class ' . $name);
82485 }
82486 $this->constraintMap[$name] = $class;
82487
82488 return $this;
82489 }
82490
82491
82492
82493
82494
82495
82496
82497
82498
82499
82500 public function createInstanceFor($constraintName)
82501 {
82502 if (!isset($this->constraintMap[$constraintName])) {
82503 throw new InvalidArgumentException('Unknown constraint ' . $constraintName);
82504 }
82505
82506 if (!isset($this->instanceCache[$constraintName])) {
82507 $this->instanceCache[$constraintName] = new $this->constraintMap[$constraintName]($this);
82508 }
82509
82510 return clone $this->instanceCache[$constraintName];
82511 }
82512
82513
82514
82515
82516
82517
82518 public function getErrorContext()
82519 {
82520 return $this->errorContext;
82521 }
82522
82523
82524
82525
82526
82527
82528 public function setErrorContext($errorContext)
82529 {
82530 $this->errorContext = $errorContext;
82531 }
82532 }
82533 <?php
82534
82535
82536
82537
82538
82539
82540
82541
82542 namespace JsonSchema\Constraints;
82543
82544 use JsonSchema\Entity\JsonPointer;
82545 use JsonSchema\Rfc3339;
82546
82547
82548
82549
82550
82551
82552
82553
82554 class FormatConstraint extends Constraint
82555 {
82556
82557
82558
82559 public function check(&$element, $schema = null, JsonPointer $path = null, $i = null)
82560 {
82561 if (!isset($schema->format) || $this->factory->getConfig(self::CHECK_MODE_DISABLE_FORMAT)) {
82562 return;
82563 }
82564
82565 switch ($schema->format) {
82566 case 'date':
82567 if (!$date = $this->validateDateTime($element, 'Y-m-d')) {
82568 $this->addError($path, sprintf('Invalid date %s, expected format YYYY-MM-DD', json_encode($element)), 'format', array('format' => $schema->format));
82569 }
82570 break;
82571
82572 case 'time':
82573 if (!$this->validateDateTime($element, 'H:i:s')) {
82574 $this->addError($path, sprintf('Invalid time %s, expected format hh:mm:ss', json_encode($element)), 'format', array('format' => $schema->format));
82575 }
82576 break;
82577
82578 case 'date-time':
82579 if (null === Rfc3339::createFromString($element)) {
82580 $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));
82581 }
82582 break;
82583
82584 case 'utc-millisec':
82585 if (!$this->validateDateTime($element, 'U')) {
82586 $this->addError($path, sprintf('Invalid time %s, expected integer of milliseconds since Epoch', json_encode($element)), 'format', array('format' => $schema->format));
82587 }
82588 break;
82589
82590 case 'regex':
82591 if (!$this->validateRegex($element)) {
82592 $this->addError($path, 'Invalid regex format ' . $element, 'format', array('format' => $schema->format));
82593 }
82594 break;
82595
82596 case 'color':
82597 if (!$this->validateColor($element)) {
82598 $this->addError($path, 'Invalid color', 'format', array('format' => $schema->format));
82599 }
82600 break;
82601
82602 case 'style':
82603 if (!$this->validateStyle($element)) {
82604 $this->addError($path, 'Invalid style', 'format', array('format' => $schema->format));
82605 }
82606 break;
82607
82608 case 'phone':
82609 if (!$this->validatePhone($element)) {
82610 $this->addError($path, 'Invalid phone number', 'format', array('format' => $schema->format));
82611 }
82612 break;
82613
82614 case 'uri':
82615 if (null === filter_var($element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE)) {
82616 $this->addError($path, 'Invalid URL format', 'format', array('format' => $schema->format));
82617 }
82618 break;
82619
82620 case 'uriref':
82621 case 'uri-reference':
82622 if (null === filter_var($element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE)) {
82623
82624
82625
82626 if (substr($element, 0, 2) === '//') { 
82627 $validURL = filter_var('scheme:' . $element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE);
82628 } elseif (substr($element, 0, 1) === '/') { 
82629 $validURL = filter_var('scheme://host' . $element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE);
82630 } elseif (strlen($element)) { 
82631 $pathParts = explode('/', $element, 2);
82632 if (strpos($pathParts[0], ':') !== false) {
82633 $validURL = null;
82634 } else {
82635 $validURL = filter_var('scheme://host/' . $element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE);
82636 }
82637 } else {
82638 $validURL = null;
82639 }
82640 if ($validURL === null) {
82641 $this->addError($path, 'Invalid URL format', 'format', array('format' => $schema->format));
82642 }
82643 }
82644 break;
82645
82646 case 'email':
82647 $filterFlags = FILTER_NULL_ON_FAILURE;
82648 if (defined('FILTER_FLAG_EMAIL_UNICODE')) {
82649
82650 $filterFlags |= constant('FILTER_FLAG_EMAIL_UNICODE'); 
82651 }
82652 if (null === filter_var($element, FILTER_VALIDATE_EMAIL, $filterFlags)) {
82653 $this->addError($path, 'Invalid email', 'format', array('format' => $schema->format));
82654 }
82655 break;
82656
82657 case 'ip-address':
82658 case 'ipv4':
82659 if (null === filter_var($element, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV4)) {
82660 $this->addError($path, 'Invalid IP address', 'format', array('format' => $schema->format));
82661 }
82662 break;
82663
82664 case 'ipv6':
82665 if (null === filter_var($element, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV6)) {
82666 $this->addError($path, 'Invalid IP address', 'format', array('format' => $schema->format));
82667 }
82668 break;
82669
82670 case 'host-name':
82671 case 'hostname':
82672 if (!$this->validateHostname($element)) {
82673 $this->addError($path, 'Invalid hostname', 'format', array('format' => $schema->format));
82674 }
82675 break;
82676
82677 default:
82678
82679
82680
82681
82682
82683
82684 break;
82685 }
82686 }
82687
82688 protected function validateDateTime($datetime, $format)
82689 {
82690 $dt = \DateTime::createFromFormat($format, $datetime);
82691
82692 if (!$dt) {
82693 return false;
82694 }
82695
82696 if ($datetime === $dt->format($format)) {
82697 return true;
82698 }
82699
82700
82701
82702
82703
82704 if ((strpos('u', $format) !== -1) && (preg_match('/\.\d+Z$/', $datetime))) {
82705 return true;
82706 }
82707
82708 return false;
82709 }
82710
82711 protected function validateRegex($regex)
82712 {
82713 return false !== @preg_match('/' . $regex . '/u', '');
82714 }
82715
82716 protected function validateColor($color)
82717 {
82718 if (in_array(strtolower($color), array('aqua', 'black', 'blue', 'fuchsia',
82719 'gray', 'green', 'lime', 'maroon', 'navy', 'olive', 'orange', 'purple',
82720 'red', 'silver', 'teal', 'white', 'yellow'))) {
82721 return true;
82722 }
82723
82724 return preg_match('/^#([a-f0-9]{3}|[a-f0-9]{6})$/i', $color);
82725 }
82726
82727 protected function validateStyle($style)
82728 {
82729 $properties = explode(';', rtrim($style, ';'));
82730 $invalidEntries = preg_grep('/^\s*[-a-z]+\s*:\s*.+$/i', $properties, PREG_GREP_INVERT);
82731
82732 return empty($invalidEntries);
82733 }
82734
82735 protected function validatePhone($phone)
82736 {
82737 return preg_match('/^\+?(\(\d{3}\)|\d{3}) \d{3} \d{4}$/', $phone);
82738 }
82739
82740 protected function validateHostname($host)
82741 {
82742 $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';
82743
82744 return preg_match($hostnameRegex, $host);
82745 }
82746 }
82747 <?php
82748
82749
82750
82751
82752
82753
82754
82755
82756 namespace JsonSchema\Constraints;
82757
82758 use JsonSchema\Entity\JsonPointer;
82759
82760
82761
82762
82763
82764
82765
82766 class NumberConstraint extends Constraint
82767 {
82768
82769
82770
82771 public function check(&$element, $schema = null, JsonPointer $path = null, $i = null)
82772 {
82773
82774 if (isset($schema->exclusiveMinimum)) {
82775 if (isset($schema->minimum)) {
82776 if ($schema->exclusiveMinimum && $element <= $schema->minimum) {
82777 $this->addError($path, 'Must have a minimum value of ' . $schema->minimum, 'exclusiveMinimum', array('minimum' => $schema->minimum));
82778 } elseif ($element < $schema->minimum) {
82779 $this->addError($path, 'Must have a minimum value of ' . $schema->minimum, 'minimum', array('minimum' => $schema->minimum));
82780 }
82781 } else {
82782 $this->addError($path, 'Use of exclusiveMinimum requires presence of minimum', 'missingMinimum');
82783 }
82784 } elseif (isset($schema->minimum) && $element < $schema->minimum) {
82785 $this->addError($path, 'Must have a minimum value of ' . $schema->minimum, 'minimum', array('minimum' => $schema->minimum));
82786 }
82787
82788
82789 if (isset($schema->exclusiveMaximum)) {
82790 if (isset($schema->maximum)) {
82791 if ($schema->exclusiveMaximum && $element >= $schema->maximum) {
82792 $this->addError($path, 'Must have a maximum value of ' . $schema->maximum, 'exclusiveMaximum', array('maximum' => $schema->maximum));
82793 } elseif ($element > $schema->maximum) {
82794 $this->addError($path, 'Must have a maximum value of ' . $schema->maximum, 'maximum', array('maximum' => $schema->maximum));
82795 }
82796 } else {
82797 $this->addError($path, 'Use of exclusiveMaximum requires presence of maximum', 'missingMaximum');
82798 }
82799 } elseif (isset($schema->maximum) && $element > $schema->maximum) {
82800 $this->addError($path, 'Must have a maximum value of ' . $schema->maximum, 'maximum', array('maximum' => $schema->maximum));
82801 }
82802
82803
82804 if (isset($schema->divisibleBy) && $this->fmod($element, $schema->divisibleBy) != 0) {
82805 $this->addError($path, 'Is not divisible by ' . $schema->divisibleBy, 'divisibleBy', array('divisibleBy' => $schema->divisibleBy));
82806 }
82807
82808
82809 if (isset($schema->multipleOf) && $this->fmod($element, $schema->multipleOf) != 0) {
82810 $this->addError($path, 'Must be a multiple of ' . $schema->multipleOf, 'multipleOf', array('multipleOf' => $schema->multipleOf));
82811 }
82812
82813 $this->checkFormat($element, $schema, $path, $i);
82814 }
82815
82816 private function fmod($number1, $number2)
82817 {
82818 $modulus = ($number1 - round($number1 / $number2) * $number2);
82819 $precision = 0.0000000001;
82820
82821 if (-$precision < $modulus && $modulus < $precision) {
82822 return 0.0;
82823 }
82824
82825 return $modulus;
82826 }
82827 }
82828 <?php
82829
82830
82831
82832
82833
82834
82835
82836
82837 namespace JsonSchema\Constraints;
82838
82839 use JsonSchema\Entity\JsonPointer;
82840
82841
82842
82843
82844
82845
82846
82847 class ObjectConstraint extends Constraint
82848 {
82849
82850
82851
82852 protected $appliedDefaults = array();
82853
82854
82855
82856
82857 public function check(&$element, $schema = null, JsonPointer $path = null, $properties = null,
82858 $additionalProp = null, $patternProperties = null, $appliedDefaults = array())
82859 {
82860 if ($element instanceof UndefinedConstraint) {
82861 return;
82862 }
82863
82864 $this->appliedDefaults = $appliedDefaults;
82865
82866 $matches = array();
82867 if ($patternProperties) {
82868
82869 $matches = $this->validatePatternProperties($element, $path, $patternProperties);
82870 }
82871
82872 if ($properties) {
82873
82874 $this->validateProperties($element, $properties, $path);
82875 }
82876
82877
82878 $this->validateElement($element, $matches, $schema, $path, $properties, $additionalProp);
82879 }
82880
82881 public function validatePatternProperties($element, JsonPointer $path = null, $patternProperties)
82882 {
82883 $try = array('/', '#', '+', '~', '%');
82884 $matches = array();
82885 foreach ($patternProperties as $pregex => $schema) {
82886 $delimiter = '/';
82887
82888 foreach ($try as $delimiter) {
82889 if (strpos($pregex, $delimiter) === false) { 
82890 break;
82891 }
82892 }
82893
82894
82895 if (@preg_match($delimiter . $pregex . $delimiter . 'u', '') === false) {
82896 $this->addError($path, 'The pattern "' . $pregex . '" is invalid', 'pregex', array('pregex' => $pregex));
82897 continue;
82898 }
82899 foreach ($element as $i => $value) {
82900 if (preg_match($delimiter . $pregex . $delimiter . 'u', $i)) {
82901 $matches[] = $i;
82902 $this->checkUndefined($value, $schema ?: new \stdClass(), $path, $i, in_array($i, $this->appliedDefaults));
82903 }
82904 }
82905 }
82906
82907 return $matches;
82908 }
82909
82910
82911
82912
82913
82914
82915
82916
82917
82918
82919
82920 public function validateElement($element, $matches, $schema = null, JsonPointer $path = null,
82921 $properties = null, $additionalProp = null)
82922 {
82923 $this->validateMinMaxConstraint($element, $schema, $path);
82924
82925 foreach ($element as $i => $value) {
82926 $definition = $this->getProperty($properties, $i);
82927
82928
82929 if (!in_array($i, $matches) && $additionalProp === false && $this->inlineSchemaProperty !== $i && !$definition) {
82930 $this->addError($path, 'The property ' . $i . ' is not defined and the definition does not allow additional properties', 'additionalProp');
82931 }
82932
82933
82934 if (!in_array($i, $matches) && $additionalProp && !$definition) {
82935 if ($additionalProp === true) {
82936 $this->checkUndefined($value, null, $path, $i, in_array($i, $this->appliedDefaults));
82937 } else {
82938 $this->checkUndefined($value, $additionalProp, $path, $i, in_array($i, $this->appliedDefaults));
82939 }
82940 }
82941
82942
82943 $require = $this->getProperty($definition, 'requires');
82944 if ($require && !$this->getProperty($element, $require)) {
82945 $this->addError($path, 'The presence of the property ' . $i . ' requires that ' . $require . ' also be present', 'requires');
82946 }
82947
82948 $property = $this->getProperty($element, $i, $this->factory->createInstanceFor('undefined'));
82949 if (is_object($property)) {
82950 $this->validateMinMaxConstraint(!($property instanceof UndefinedConstraint) ? $property : $element, $definition, $path);
82951 }
82952 }
82953 }
82954
82955
82956
82957
82958
82959
82960
82961
82962 public function validateProperties(&$element, $properties = null, JsonPointer $path = null)
82963 {
82964 $undefinedConstraint = $this->factory->createInstanceFor('undefined');
82965
82966 foreach ($properties as $i => $value) {
82967 $property = &$this->getProperty($element, $i, $undefinedConstraint);
82968 $definition = $this->getProperty($properties, $i);
82969
82970 if (is_object($definition)) {
82971
82972 $this->checkUndefined($property, $definition, $path, $i, in_array($i, $this->appliedDefaults));
82973 }
82974 }
82975 }
82976
82977
82978
82979
82980
82981
82982
82983
82984
82985
82986 protected function &getProperty(&$element, $property, $fallback = null)
82987 {
82988 if (is_array($element) && (isset($element[$property]) || array_key_exists($property, $element)) ) {
82989 return $element[$property];
82990 } elseif (is_object($element) && property_exists($element, $property)) {
82991 return $element->$property;
82992 }
82993
82994 return $fallback;
82995 }
82996
82997
82998
82999
83000
83001
83002
83003
83004 protected function validateMinMaxConstraint($element, $objectDefinition, JsonPointer $path = null)
83005 {
83006
83007 if (isset($objectDefinition->minProperties) && !is_object($objectDefinition->minProperties)) {
83008 if ($this->getTypeCheck()->propertyCount($element) < $objectDefinition->minProperties) {
83009 $this->addError($path, 'Must contain a minimum of ' . $objectDefinition->minProperties . ' properties', 'minProperties', array('minProperties' => $objectDefinition->minProperties));
83010 }
83011 }
83012
83013 if (isset($objectDefinition->maxProperties) && !is_object($objectDefinition->maxProperties)) {
83014 if ($this->getTypeCheck()->propertyCount($element) > $objectDefinition->maxProperties) {
83015 $this->addError($path, 'Must contain no more than ' . $objectDefinition->maxProperties . ' properties', 'maxProperties', array('maxProperties' => $objectDefinition->maxProperties));
83016 }
83017 }
83018 }
83019 }
83020 <?php
83021
83022
83023
83024
83025
83026
83027
83028
83029 namespace JsonSchema\Constraints;
83030
83031 use JsonSchema\Entity\JsonPointer;
83032 use JsonSchema\Exception\InvalidArgumentException;
83033 use JsonSchema\Exception\InvalidSchemaException;
83034 use JsonSchema\Exception\RuntimeException;
83035 use JsonSchema\Validator;
83036
83037
83038
83039
83040
83041
83042
83043 class SchemaConstraint extends Constraint
83044 {
83045 const DEFAULT_SCHEMA_SPEC = 'http://json-schema.org/draft-04/schema#';
83046
83047
83048
83049
83050 public function check(&$element, $schema = null, JsonPointer $path = null, $i = null)
83051 {
83052 if ($schema !== null) {
83053
83054 $validationSchema = $schema;
83055 } elseif ($this->getTypeCheck()->propertyExists($element, $this->inlineSchemaProperty)) {
83056
83057 $validationSchema = $this->getTypeCheck()->propertyGet($element, $this->inlineSchemaProperty);
83058 } else {
83059 throw new InvalidArgumentException('no schema found to verify against');
83060 }
83061
83062
83063 if (is_array($validationSchema)) {
83064 $validationSchema = BaseConstraint::arrayToObjectRecursive($validationSchema);
83065 }
83066
83067
83068
83069 if ($this->factory->getConfig(self::CHECK_MODE_VALIDATE_SCHEMA)) {
83070 if (!$this->getTypeCheck()->isObject($validationSchema)) {
83071 throw new RuntimeException('Cannot validate the schema of a non-object');
83072 }
83073 if ($this->getTypeCheck()->propertyExists($validationSchema, '$schema')) {
83074 $schemaSpec = $this->getTypeCheck()->propertyGet($validationSchema, '$schema');
83075 } else {
83076 $schemaSpec = self::DEFAULT_SCHEMA_SPEC;
83077 }
83078
83079
83080 $schemaStorage = $this->factory->getSchemaStorage();
83081 if (!$this->getTypeCheck()->isObject($schemaSpec)) {
83082 $schemaSpec = $schemaStorage->getSchema($schemaSpec);
83083 }
83084
83085
83086 $initialErrorCount = $this->numErrors();
83087 $initialConfig = $this->factory->getConfig();
83088 $initialContext = $this->factory->getErrorContext();
83089 $this->factory->removeConfig(self::CHECK_MODE_VALIDATE_SCHEMA | self::CHECK_MODE_APPLY_DEFAULTS);
83090 $this->factory->addConfig(self::CHECK_MODE_TYPE_CAST);
83091 $this->factory->setErrorContext(Validator::ERROR_SCHEMA_VALIDATION);
83092
83093
83094 try {
83095 $this->check($validationSchema, $schemaSpec);
83096 } catch (\Exception $e) {
83097 if ($this->factory->getConfig(self::CHECK_MODE_EXCEPTIONS)) {
83098 throw new InvalidSchemaException('Schema did not pass validation', 0, $e);
83099 }
83100 }
83101 if ($this->numErrors() > $initialErrorCount) {
83102 $this->addError($path, 'Schema is not valid', 'schema');
83103 }
83104
83105
83106 $this->factory->setConfig($initialConfig);
83107 $this->factory->setErrorContext($initialContext);
83108 }
83109
83110
83111 $this->checkUndefined($element, $validationSchema, $path, $i);
83112 }
83113 }
83114 <?php
83115
83116
83117
83118
83119
83120
83121
83122
83123 namespace JsonSchema\Constraints;
83124
83125 use JsonSchema\Entity\JsonPointer;
83126
83127
83128
83129
83130
83131
83132
83133 class StringConstraint extends Constraint
83134 {
83135
83136
83137
83138 public function check(&$element, $schema = null, JsonPointer $path = null, $i = null)
83139 {
83140
83141 if (isset($schema->maxLength) && $this->strlen($element) > $schema->maxLength) {
83142 $this->addError($path, 'Must be at most ' . $schema->maxLength . ' characters long', 'maxLength', array(
83143 'maxLength' => $schema->maxLength,
83144 ));
83145 }
83146
83147
83148 if (isset($schema->minLength) && $this->strlen($element) < $schema->minLength) {
83149 $this->addError($path, 'Must be at least ' . $schema->minLength . ' characters long', 'minLength', array(
83150 'minLength' => $schema->minLength,
83151 ));
83152 }
83153
83154
83155 if (isset($schema->pattern) && !preg_match('#' . str_replace('#', '\\#', $schema->pattern) . '#u', $element)) {
83156 $this->addError($path, 'Does not match the regex pattern ' . $schema->pattern, 'pattern', array(
83157 'pattern' => $schema->pattern,
83158 ));
83159 }
83160
83161 $this->checkFormat($element, $schema, $path, $i);
83162 }
83163
83164 private function strlen($string)
83165 {
83166 if (extension_loaded('mbstring')) {
83167 return mb_strlen($string, mb_detect_encoding($string));
83168 }
83169
83170
83171 return strlen($string); 
83172 }
83173 }
83174 <?php
83175
83176 namespace JsonSchema\Constraints\TypeCheck;
83177
83178 class LooseTypeCheck implements TypeCheckInterface
83179 {
83180 public static function isObject($value)
83181 {
83182 return
83183 is_object($value) ||
83184 (is_array($value) && (count($value) == 0 || self::isAssociativeArray($value)));
83185 }
83186
83187 public static function isArray($value)
83188 {
83189 return
83190 is_array($value) &&
83191 (count($value) == 0 || !self::isAssociativeArray($value));
83192 }
83193
83194 public static function propertyGet($value, $property)
83195 {
83196 if (is_object($value)) {
83197 return $value->{$property};
83198 }
83199
83200 return $value[$property];
83201 }
83202
83203 public static function propertySet(&$value, $property, $data)
83204 {
83205 if (is_object($value)) {
83206 $value->{$property} = $data;
83207 } else {
83208 $value[$property] = $data;
83209 }
83210 }
83211
83212 public static function propertyExists($value, $property)
83213 {
83214 if (is_object($value)) {
83215 return property_exists($value, $property);
83216 }
83217
83218 return array_key_exists($property, $value);
83219 }
83220
83221 public static function propertyCount($value)
83222 {
83223 if (is_object($value)) {
83224 return count(get_object_vars($value));
83225 }
83226
83227 return count($value);
83228 }
83229
83230
83231
83232
83233
83234
83235
83236
83237 private static function isAssociativeArray($arr)
83238 {
83239 return array_keys($arr) !== range(0, count($arr) - 1);
83240 }
83241 }
83242 <?php
83243
83244 namespace JsonSchema\Constraints\TypeCheck;
83245
83246 class StrictTypeCheck implements TypeCheckInterface
83247 {
83248 public static function isObject($value)
83249 {
83250 return is_object($value);
83251 }
83252
83253 public static function isArray($value)
83254 {
83255 return is_array($value);
83256 }
83257
83258 public static function propertyGet($value, $property)
83259 {
83260 return $value->{$property};
83261 }
83262
83263 public static function propertySet(&$value, $property, $data)
83264 {
83265 $value->{$property} = $data;
83266 }
83267
83268 public static function propertyExists($value, $property)
83269 {
83270 return property_exists($value, $property);
83271 }
83272
83273 public static function propertyCount($value)
83274 {
83275 if (!is_object($value)) {
83276 return 0;
83277 }
83278
83279 return count(get_object_vars($value));
83280 }
83281 }
83282 <?php
83283
83284 namespace JsonSchema\Constraints\TypeCheck;
83285
83286 interface TypeCheckInterface
83287 {
83288 public static function isObject($value);
83289
83290 public static function isArray($value);
83291
83292 public static function propertyGet($value, $property);
83293
83294 public static function propertySet(&$value, $property, $data);
83295
83296 public static function propertyExists($value, $property);
83297
83298 public static function propertyCount($value);
83299 }
83300 <?php
83301
83302
83303
83304
83305
83306
83307
83308
83309 namespace JsonSchema\Constraints;
83310
83311 use JsonSchema\Entity\JsonPointer;
83312 use JsonSchema\Exception\InvalidArgumentException;
83313 use UnexpectedValueException as StandardUnexpectedValueException;
83314
83315
83316
83317
83318
83319
83320
83321 class TypeConstraint extends Constraint
83322 {
83323
83324
83325
83326 public static $wording = array(
83327 'integer' => 'an integer',
83328 'number' => 'a number',
83329 'boolean' => 'a boolean',
83330 'object' => 'an object',
83331 'array' => 'an array',
83332 'string' => 'a string',
83333 'null' => 'a null',
83334 'any' => null, 
83335 0 => null, 
83336 );
83337
83338
83339
83340
83341 public function check(&$value = null, $schema = null, JsonPointer $path = null, $i = null)
83342 {
83343 $type = isset($schema->type) ? $schema->type : null;
83344 $isValid = false;
83345 $wording = array();
83346
83347 if (is_array($type)) {
83348 $this->validateTypesArray($value, $type, $wording, $isValid, $path);
83349 } elseif (is_object($type)) {
83350 $this->checkUndefined($value, $type, $path);
83351
83352 return;
83353 } else {
83354 $isValid = $this->validateType($value, $type);
83355 }
83356
83357 if ($isValid === false) {
83358 if (!is_array($type)) {
83359 $this->validateTypeNameWording($type);
83360 $wording[] = self::$wording[$type];
83361 }
83362 $this->addError($path, ucwords(gettype($value)) . ' value found, but ' .
83363 $this->implodeWith($wording, ', ', 'or') . ' is required', 'type');
83364 }
83365 }
83366
83367
83368
83369
83370
83371
83372
83373
83374
83375
83376
83377
83378 protected function validateTypesArray(&$value, array $type, &$validTypesWording, &$isValid, $path)
83379 {
83380 foreach ($type as $tp) {
83381
83382
83383 if (is_object($tp)) {
83384 if (!$isValid) {
83385 $validator = $this->factory->createInstanceFor('type');
83386 $subSchema = new \stdClass();
83387 $subSchema->type = $tp;
83388 $validator->check($value, $subSchema, $path, null);
83389 $error = $validator->getErrors();
83390 $isValid = !(bool) $error;
83391 $validTypesWording[] = self::$wording['object'];
83392 }
83393 } else {
83394 $this->validateTypeNameWording($tp);
83395 $validTypesWording[] = self::$wording[$tp];
83396 if (!$isValid) {
83397 $isValid = $this->validateType($value, $tp);
83398 }
83399 }
83400 }
83401 }
83402
83403
83404
83405
83406
83407
83408
83409
83410
83411
83412
83413
83414 protected function implodeWith(array $elements, $delimiter = ', ', $listEnd = false)
83415 {
83416 if ($listEnd === false || !isset($elements[1])) {
83417 return implode($delimiter, $elements);
83418 }
83419 $lastElement = array_slice($elements, -1);
83420 $firsElements = join($delimiter, array_slice($elements, 0, -1));
83421 $implodedElements = array_merge(array($firsElements), $lastElement);
83422
83423 return join(" $listEnd ", $implodedElements);
83424 }
83425
83426
83427
83428
83429
83430
83431
83432
83433
83434 protected function validateTypeNameWording($type)
83435 {
83436 if (!isset(self::$wording[$type])) {
83437 throw new StandardUnexpectedValueException(
83438 sprintf(
83439 'No wording for %s available, expected wordings are: [%s]',
83440 var_export($type, true),
83441 implode(', ', array_filter(self::$wording)))
83442 );
83443 }
83444 }
83445
83446
83447
83448
83449
83450
83451
83452
83453
83454
83455
83456 protected function validateType(&$value, $type)
83457 {
83458
83459 if (!$type) {
83460 return true;
83461 }
83462
83463 if ('any' === $type) {
83464 return true;
83465 }
83466
83467 if ('object' === $type) {
83468 return $this->getTypeCheck()->isObject($value);
83469 }
83470
83471 if ('array' === $type) {
83472 return $this->getTypeCheck()->isArray($value);
83473 }
83474
83475 $coerce = $this->factory->getConfig(Constraint::CHECK_MODE_COERCE_TYPES);
83476
83477 if ('integer' === $type) {
83478 if ($coerce) {
83479 $value = $this->toInteger($value);
83480 }
83481
83482 return is_int($value);
83483 }
83484
83485 if ('number' === $type) {
83486 if ($coerce) {
83487 $value = $this->toNumber($value);
83488 }
83489
83490 return is_numeric($value) && !is_string($value);
83491 }
83492
83493 if ('boolean' === $type) {
83494 if ($coerce) {
83495 $value = $this->toBoolean($value);
83496 }
83497
83498 return is_bool($value);
83499 }
83500
83501 if ('string' === $type) {
83502 return is_string($value);
83503 }
83504
83505 if ('email' === $type) {
83506 return is_string($value);
83507 }
83508
83509 if ('null' === $type) {
83510 return is_null($value);
83511 }
83512
83513 throw new InvalidArgumentException((is_object($value) ? 'object' : $value) . ' is an invalid type for ' . $type);
83514 }
83515
83516
83517
83518
83519
83520
83521
83522
83523 protected function toBoolean($value)
83524 {
83525 if ($value === 'true') {
83526 return true;
83527 }
83528
83529 if ($value === 'false') {
83530 return false;
83531 }
83532
83533 return $value;
83534 }
83535
83536
83537
83538
83539
83540
83541
83542
83543 protected function toNumber($value)
83544 {
83545 if (is_numeric($value)) {
83546 return $value + 0; 
83547 }
83548
83549 return $value;
83550 }
83551
83552 protected function toInteger($value)
83553 {
83554 if (is_numeric($value) && (int) $value == $value) {
83555 return (int) $value; 
83556 }
83557
83558 return $value;
83559 }
83560 }
83561 <?php
83562
83563
83564
83565
83566
83567
83568
83569
83570 namespace JsonSchema\Constraints;
83571
83572 use JsonSchema\Constraints\TypeCheck\LooseTypeCheck;
83573 use JsonSchema\Entity\JsonPointer;
83574 use JsonSchema\Exception\ValidationException;
83575 use JsonSchema\Uri\UriResolver;
83576
83577
83578
83579
83580
83581
83582
83583 class UndefinedConstraint extends Constraint
83584 {
83585
83586
83587
83588 protected $appliedDefaults = array();
83589
83590
83591
83592
83593 public function check(&$value, $schema = null, JsonPointer $path = null, $i = null, $fromDefault = false)
83594 {
83595 if (is_null($schema) || !is_object($schema)) {
83596 return;
83597 }
83598
83599 $path = $this->incrementPath($path ?: new JsonPointer(''), $i);
83600 if ($fromDefault) {
83601 $path->setFromDefault();
83602 }
83603
83604
83605 $this->validateCommonProperties($value, $schema, $path, $i);
83606
83607
83608 $this->validateOfProperties($value, $schema, $path, '');
83609
83610
83611 $this->validateTypes($value, $schema, $path, $i);
83612 }
83613
83614
83615
83616
83617
83618
83619
83620
83621
83622 public function validateTypes(&$value, $schema, JsonPointer $path, $i = null)
83623 {
83624
83625 if ($this->getTypeCheck()->isArray($value)) {
83626 $this->checkArray($value, $schema, $path, $i);
83627 }
83628
83629
83630 if (LooseTypeCheck::isObject($value)) { 
83631
83632
83633 $this->checkObject(
83634 $value,
83635 $schema,
83636 $path,
83637 isset($schema->properties) ? $schema->properties : null,
83638 isset($schema->additionalProperties) ? $schema->additionalProperties : null,
83639 isset($schema->patternProperties) ? $schema->patternProperties : null,
83640 $this->appliedDefaults
83641 );
83642 }
83643
83644
83645 if (is_string($value)) {
83646 $this->checkString($value, $schema, $path, $i);
83647 }
83648
83649
83650 if (is_numeric($value)) {
83651 $this->checkNumber($value, $schema, $path, $i);
83652 }
83653
83654
83655 if (isset($schema->enum)) {
83656 $this->checkEnum($value, $schema, $path, $i);
83657 }
83658 }
83659
83660
83661
83662
83663
83664
83665
83666
83667
83668 protected function validateCommonProperties(&$value, $schema, JsonPointer $path, $i = '')
83669 {
83670
83671 if (isset($schema->extends)) {
83672 if (is_string($schema->extends)) {
83673 $schema->extends = $this->validateUri($schema, $schema->extends);
83674 }
83675 if (is_array($schema->extends)) {
83676 foreach ($schema->extends as $extends) {
83677 $this->checkUndefined($value, $extends, $path, $i);
83678 }
83679 } else {
83680 $this->checkUndefined($value, $schema->extends, $path, $i);
83681 }
83682 }
83683
83684
83685 if (!$path->fromDefault()) {
83686 $this->applyDefaultValues($value, $schema, $path);
83687 }
83688
83689
83690 if ($this->getTypeCheck()->isObject($value)) {
83691 if (!($value instanceof self) && isset($schema->required) && is_array($schema->required)) {
83692
83693 foreach ($schema->required as $required) {
83694 if (!$this->getTypeCheck()->propertyExists($value, $required)) {
83695 $this->addError(
83696 $this->incrementPath($path ?: new JsonPointer(''), $required),
83697 'The property ' . $required . ' is required',
83698 'required'
83699 );
83700 }
83701 }
83702 } elseif (isset($schema->required) && !is_array($schema->required)) {
83703
83704 if ($schema->required && $value instanceof self) {
83705 $propertyPaths = $path->getPropertyPaths();
83706 $propertyName = end($propertyPaths);
83707 $this->addError(
83708 $path,
83709 'The property ' . $propertyName . ' is required',
83710 'required'
83711 );
83712 }
83713 } else {
83714
83715
83716 if ($value instanceof self) {
83717 return;
83718 }
83719 }
83720 }
83721
83722
83723 if (!($value instanceof self)) {
83724 $this->checkType($value, $schema, $path, $i);
83725 }
83726
83727
83728 if (isset($schema->disallow)) {
83729 $initErrors = $this->getErrors();
83730
83731 $typeSchema = new \stdClass();
83732 $typeSchema->type = $schema->disallow;
83733 $this->checkType($value, $typeSchema, $path);
83734
83735
83736 if (count($this->getErrors()) == count($initErrors)) {
83737 $this->addError($path, 'Disallowed value was matched', 'disallow');
83738 } else {
83739 $this->errors = $initErrors;
83740 }
83741 }
83742
83743 if (isset($schema->not)) {
83744 $initErrors = $this->getErrors();
83745 $this->checkUndefined($value, $schema->not, $path, $i);
83746
83747
83748 if (count($this->getErrors()) == count($initErrors)) {
83749 $this->addError($path, 'Matched a schema which it should not', 'not');
83750 } else {
83751 $this->errors = $initErrors;
83752 }
83753 }
83754
83755
83756 if (isset($schema->dependencies) && $this->getTypeCheck()->isObject($value)) {
83757 $this->validateDependencies($value, $schema->dependencies, $path);
83758 }
83759 }
83760
83761
83762
83763
83764
83765
83766
83767
83768
83769
83770 private function shouldApplyDefaultValue($requiredOnly, $schema, $name = null, $parentSchema = null)
83771 {
83772
83773 if (!$requiredOnly) {
83774 return true;
83775 }
83776
83777 if (
83778 $name !== null
83779 && isset($parentSchema->required)
83780 && is_array($parentSchema->required)
83781 && in_array($name, $parentSchema->required)
83782 ) {
83783 return true;
83784 }
83785
83786 if (isset($schema->required) && !is_array($schema->required) && $schema->required) {
83787 return true;
83788 }
83789
83790 return false;
83791 }
83792
83793
83794
83795
83796
83797
83798
83799
83800 protected function applyDefaultValues(&$value, $schema, $path)
83801 {
83802
83803 if (!$this->factory->getConfig(self::CHECK_MODE_APPLY_DEFAULTS)) {
83804 return;
83805 }
83806
83807
83808 $requiredOnly = $this->factory->getConfig(self::CHECK_MODE_ONLY_REQUIRED_DEFAULTS);
83809 if (isset($schema->properties) && LooseTypeCheck::isObject($value)) {
83810
83811 foreach ($schema->properties as $currentProperty => $propertyDefinition) {
83812 $propertyDefinition = $this->factory->getSchemaStorage()->resolveRefSchema($propertyDefinition);
83813 if (
83814 !LooseTypeCheck::propertyExists($value, $currentProperty)
83815 && property_exists($propertyDefinition, 'default')
83816 && $this->shouldApplyDefaultValue($requiredOnly, $propertyDefinition, $currentProperty, $schema)
83817 ) {
83818
83819 if (is_object($propertyDefinition->default)) {
83820 LooseTypeCheck::propertySet($value, $currentProperty, clone $propertyDefinition->default);
83821 } else {
83822 LooseTypeCheck::propertySet($value, $currentProperty, $propertyDefinition->default);
83823 }
83824 $this->appliedDefaults[] = $currentProperty;
83825 }
83826 }
83827 } elseif (isset($schema->items) && LooseTypeCheck::isArray($value)) {
83828 $items = array();
83829 if (LooseTypeCheck::isArray($schema->items)) {
83830 $items = $schema->items;
83831 } elseif (isset($schema->minItems) && count($value) < $schema->minItems) {
83832 $items = array_fill(count($value), $schema->minItems - count($value), $schema->items);
83833 }
83834
83835 foreach ($items as $currentItem => $itemDefinition) {
83836 $itemDefinition = $this->factory->getSchemaStorage()->resolveRefSchema($itemDefinition);
83837 if (
83838 !array_key_exists($currentItem, $value)
83839 && property_exists($itemDefinition, 'default')
83840 && $this->shouldApplyDefaultValue($requiredOnly, $itemDefinition)) {
83841 if (is_object($itemDefinition->default)) {
83842 $value[$currentItem] = clone $itemDefinition->default;
83843 } else {
83844 $value[$currentItem] = $itemDefinition->default;
83845 }
83846 }
83847 $path->setFromDefault();
83848 }
83849 } elseif (
83850 $value instanceof self
83851 && property_exists($schema, 'default')
83852 && $this->shouldApplyDefaultValue($requiredOnly, $schema)) {
83853
83854 $value = is_object($schema->default) ? clone $schema->default : $schema->default;
83855 $path->setFromDefault();
83856 }
83857 }
83858
83859
83860
83861
83862
83863
83864
83865
83866
83867 protected function validateOfProperties(&$value, $schema, JsonPointer $path, $i = '')
83868 {
83869
83870 if ($value instanceof self) {
83871 return;
83872 }
83873
83874 if (isset($schema->allOf)) {
83875 $isValid = true;
83876 foreach ($schema->allOf as $allOf) {
83877 $initErrors = $this->getErrors();
83878 $this->checkUndefined($value, $allOf, $path, $i);
83879 $isValid = $isValid && (count($this->getErrors()) == count($initErrors));
83880 }
83881 if (!$isValid) {
83882 $this->addError($path, 'Failed to match all schemas', 'allOf');
83883 }
83884 }
83885
83886 if (isset($schema->anyOf)) {
83887 $isValid = false;
83888 $startErrors = $this->getErrors();
83889 $caughtException = null;
83890 foreach ($schema->anyOf as $anyOf) {
83891 $initErrors = $this->getErrors();
83892 try {
83893 $this->checkUndefined($value, $anyOf, $path, $i);
83894 if ($isValid = (count($this->getErrors()) == count($initErrors))) {
83895 break;
83896 }
83897 } catch (ValidationException $e) {
83898 $isValid = false;
83899 }
83900 }
83901 if (!$isValid) {
83902 $this->addError($path, 'Failed to match at least one schema', 'anyOf');
83903 } else {
83904 $this->errors = $startErrors;
83905 }
83906 }
83907
83908 if (isset($schema->oneOf)) {
83909 $allErrors = array();
83910 $matchedSchemas = 0;
83911 $startErrors = $this->getErrors();
83912 foreach ($schema->oneOf as $oneOf) {
83913 try {
83914 $this->errors = array();
83915 $this->checkUndefined($value, $oneOf, $path, $i);
83916 if (count($this->getErrors()) == 0) {
83917 $matchedSchemas++;
83918 }
83919 $allErrors = array_merge($allErrors, array_values($this->getErrors()));
83920 } catch (ValidationException $e) {
83921
83922
83923 }
83924 }
83925 if ($matchedSchemas !== 1) {
83926 $this->addErrors(array_merge($allErrors, $startErrors));
83927 $this->addError($path, 'Failed to match exactly one schema', 'oneOf');
83928 } else {
83929 $this->errors = $startErrors;
83930 }
83931 }
83932 }
83933
83934
83935
83936
83937
83938
83939
83940
83941
83942 protected function validateDependencies($value, $dependencies, JsonPointer $path, $i = '')
83943 {
83944 foreach ($dependencies as $key => $dependency) {
83945 if ($this->getTypeCheck()->propertyExists($value, $key)) {
83946 if (is_string($dependency)) {
83947
83948 if (!$this->getTypeCheck()->propertyExists($value, $dependency)) {
83949 $this->addError($path, "$key depends on $dependency and $dependency is missing", 'dependencies');
83950 }
83951 } elseif (is_array($dependency)) {
83952
83953 foreach ($dependency as $d) {
83954 if (!$this->getTypeCheck()->propertyExists($value, $d)) {
83955 $this->addError($path, "$key depends on $d and $d is missing", 'dependencies');
83956 }
83957 }
83958 } elseif (is_object($dependency)) {
83959
83960 $this->checkUndefined($value, $dependency, $path, $i);
83961 }
83962 }
83963 }
83964 }
83965
83966 protected function validateUri($schema, $schemaUri = null)
83967 {
83968 $resolver = new UriResolver();
83969 $retriever = $this->factory->getUriRetriever();
83970
83971 $jsonSchema = null;
83972 if ($resolver->isValid($schemaUri)) {
83973 $schemaId = property_exists($schema, 'id') ? $schema->id : null;
83974 $jsonSchema = $retriever->retrieve($schemaId, $schemaUri);
83975 }
83976
83977 return $jsonSchema;
83978 }
83979 }
83980 <?php
83981
83982
83983
83984
83985
83986
83987
83988
83989 namespace JsonSchema\Entity;
83990
83991 use JsonSchema\Exception\InvalidArgumentException;
83992
83993
83994
83995
83996
83997
83998 class JsonPointer
83999 {
84000
84001 private $filename;
84002
84003
84004 private $propertyPaths = array();
84005
84006
84007
84008
84009 private $fromDefault = false;
84010
84011
84012
84013
84014
84015
84016 public function __construct($value)
84017 {
84018 if (!is_string($value)) {
84019 throw new InvalidArgumentException('Ref value must be a string');
84020 }
84021
84022 $splitRef = explode('#', $value, 2);
84023 $this->filename = $splitRef[0];
84024 if (array_key_exists(1, $splitRef)) {
84025 $this->propertyPaths = $this->decodePropertyPaths($splitRef[1]);
84026 }
84027 }
84028
84029
84030
84031
84032
84033
84034 private function decodePropertyPaths($propertyPathString)
84035 {
84036 $paths = array();
84037 foreach (explode('/', trim($propertyPathString, '/')) as $path) {
84038 $path = $this->decodePath($path);
84039 if (is_string($path) && '' !== $path) {
84040 $paths[] = $path;
84041 }
84042 }
84043
84044 return $paths;
84045 }
84046
84047
84048
84049
84050 private function encodePropertyPaths()
84051 {
84052 return array_map(
84053 array($this, 'encodePath'),
84054 $this->getPropertyPaths()
84055 );
84056 }
84057
84058
84059
84060
84061
84062
84063 private function decodePath($path)
84064 {
84065 return strtr($path, array('~1' => '/', '~0' => '~', '%25' => '%'));
84066 }
84067
84068
84069
84070
84071
84072
84073 private function encodePath($path)
84074 {
84075 return strtr($path, array('/' => '~1', '~' => '~0', '%' => '%25'));
84076 }
84077
84078
84079
84080
84081 public function getFilename()
84082 {
84083 return $this->filename;
84084 }
84085
84086
84087
84088
84089 public function getPropertyPaths()
84090 {
84091 return $this->propertyPaths;
84092 }
84093
84094
84095
84096
84097
84098
84099 public function withPropertyPaths(array $propertyPaths)
84100 {
84101 $new = clone $this;
84102 $new->propertyPaths = $propertyPaths;
84103
84104 return $new;
84105 }
84106
84107
84108
84109
84110 public function getPropertyPathAsString()
84111 {
84112 return rtrim('#/' . implode('/', $this->encodePropertyPaths()), '/');
84113 }
84114
84115
84116
84117
84118 public function __toString()
84119 {
84120 return $this->getFilename() . $this->getPropertyPathAsString();
84121 }
84122
84123
84124
84125
84126 public function setFromDefault()
84127 {
84128 $this->fromDefault = true;
84129 }
84130
84131
84132
84133
84134
84135
84136 public function fromDefault()
84137 {
84138 return $this->fromDefault;
84139 }
84140 }
84141 <?php
84142
84143 namespace JsonSchema\Exception;
84144
84145 interface ExceptionInterface
84146 {
84147 }
84148 <?php
84149
84150
84151
84152
84153
84154
84155
84156
84157 namespace JsonSchema\Exception;
84158
84159
84160
84161
84162 class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
84163 {
84164 }
84165 <?php
84166
84167
84168
84169
84170
84171
84172
84173
84174 namespace JsonSchema\Exception;
84175
84176
84177
84178
84179 class InvalidConfigException extends RuntimeException
84180 {
84181 }
84182 <?php
84183
84184
84185
84186
84187
84188
84189
84190
84191 namespace JsonSchema\Exception;
84192
84193
84194
84195
84196 class InvalidSchemaException extends RuntimeException
84197 {
84198 }
84199 <?php
84200
84201
84202
84203
84204
84205
84206
84207
84208 namespace JsonSchema\Exception;
84209
84210
84211
84212
84213 class InvalidSchemaMediaTypeException extends RuntimeException
84214 {
84215 }
84216 <?php
84217
84218
84219
84220
84221
84222
84223
84224
84225 namespace JsonSchema\Exception;
84226
84227
84228
84229
84230 class InvalidSourceUriException extends InvalidArgumentException
84231 {
84232 }
84233 <?php
84234
84235
84236
84237
84238
84239
84240
84241
84242 namespace JsonSchema\Exception;
84243
84244
84245
84246
84247 class JsonDecodingException extends RuntimeException
84248 {
84249 public function __construct($code = JSON_ERROR_NONE, \Exception $previous = null)
84250 {
84251 switch ($code) {
84252 case JSON_ERROR_DEPTH:
84253 $message = 'The maximum stack depth has been exceeded';
84254 break;
84255 case JSON_ERROR_STATE_MISMATCH:
84256 $message = 'Invalid or malformed JSON';
84257 break;
84258 case JSON_ERROR_CTRL_CHAR:
84259 $message = 'Control character error, possibly incorrectly encoded';
84260 break;
84261 case JSON_ERROR_UTF8:
84262 $message = 'Malformed UTF-8 characters, possibly incorrectly encoded';
84263 break;
84264 case JSON_ERROR_SYNTAX:
84265 $message = 'JSON syntax is malformed';
84266 break;
84267 default:
84268 $message = 'Syntax error';
84269 }
84270 parent::__construct($message, $code, $previous);
84271 }
84272 }
84273 <?php
84274
84275
84276
84277
84278
84279
84280
84281
84282 namespace JsonSchema\Exception;
84283
84284
84285
84286
84287 class ResourceNotFoundException extends RuntimeException
84288 {
84289 }
84290 <?php
84291
84292
84293
84294
84295
84296
84297
84298
84299 namespace JsonSchema\Exception;
84300
84301
84302
84303
84304 class RuntimeException extends \RuntimeException implements ExceptionInterface
84305 {
84306 }
84307 <?php
84308
84309
84310
84311
84312
84313
84314
84315
84316 namespace JsonSchema\Exception;
84317
84318
84319
84320
84321
84322
84323 class UnresolvableJsonPointerException extends InvalidArgumentException
84324 {
84325 }
84326 <?php
84327
84328
84329
84330
84331
84332
84333
84334
84335 namespace JsonSchema\Exception;
84336
84337
84338
84339
84340 class UriResolverException extends RuntimeException
84341 {
84342 }
84343 <?php
84344
84345
84346
84347
84348
84349
84350
84351
84352 namespace JsonSchema\Exception;
84353
84354 class ValidationException extends RuntimeException
84355 {
84356 }
84357 <?php
84358
84359
84360
84361
84362
84363
84364
84365
84366 namespace JsonSchema\Iterator;
84367
84368
84369
84370
84371
84372
84373 class ObjectIterator implements \Iterator, \Countable
84374 {
84375
84376 private $object;
84377
84378
84379 private $position = 0;
84380
84381
84382 private $data = array();
84383
84384
84385 private $initialized = false;
84386
84387
84388
84389
84390 public function __construct($object)
84391 {
84392 $this->object = $object;
84393 }
84394
84395
84396
84397
84398 public function current()
84399 {
84400 $this->initialize();
84401
84402 return $this->data[$this->position];
84403 }
84404
84405
84406
84407
84408 public function next()
84409 {
84410 $this->initialize();
84411 $this->position++;
84412 }
84413
84414
84415
84416
84417 public function key()
84418 {
84419 $this->initialize();
84420
84421 return $this->position;
84422 }
84423
84424
84425
84426
84427 public function valid()
84428 {
84429 $this->initialize();
84430
84431 return isset($this->data[$this->position]);
84432 }
84433
84434
84435
84436
84437 public function rewind()
84438 {
84439 $this->initialize();
84440 $this->position = 0;
84441 }
84442
84443
84444
84445
84446 public function count()
84447 {
84448 $this->initialize();
84449
84450 return count($this->data);
84451 }
84452
84453
84454
84455
84456 private function initialize()
84457 {
84458 if (!$this->initialized) {
84459 $this->data = $this->buildDataFromObject($this->object);
84460 $this->initialized = true;
84461 }
84462 }
84463
84464
84465
84466
84467
84468
84469 private function buildDataFromObject($object)
84470 {
84471 $result = array();
84472
84473 $stack = new \SplStack();
84474 $stack->push($object);
84475
84476 while (!$stack->isEmpty()) {
84477 $current = $stack->pop();
84478 if (is_object($current)) {
84479 array_push($result, $current);
84480 }
84481
84482 foreach ($this->getDataFromItem($current) as $propertyName => $propertyValue) {
84483 if (is_object($propertyValue) || is_array($propertyValue)) {
84484 $stack->push($propertyValue);
84485 }
84486 }
84487 }
84488
84489 return $result;
84490 }
84491
84492
84493
84494
84495
84496
84497 private function getDataFromItem($item)
84498 {
84499 if (!is_object($item) && !is_array($item)) {
84500 return array();
84501 }
84502
84503 return is_object($item) ? get_object_vars($item) : $item;
84504 }
84505 }
84506 <?php
84507
84508 namespace JsonSchema;
84509
84510 class Rfc3339
84511 {
84512 const REGEX = '/^(\d{4}-\d{2}-\d{2}[T ]{1}\d{2}:\d{2}:\d{2})(\.\d+)?(Z|([+-]\d{2}):?(\d{2}))$/';
84513
84514
84515
84516
84517
84518
84519
84520
84521 public static function createFromString($string)
84522 {
84523 if (!preg_match(self::REGEX, strtoupper($string), $matches)) {
84524 return null;
84525 }
84526
84527 $dateAndTime = $matches[1];
84528 $microseconds = $matches[2] ?: '.000000';
84529 $timeZone = 'Z' !== $matches[3] ? $matches[4] . ':' . $matches[5] : '+00:00';
84530 $dateFormat = strpos($dateAndTime, 'T') === false ? 'Y-m-d H:i:s.uP' : 'Y-m-d\TH:i:s.uP';
84531 $dateTime = \DateTime::createFromFormat($dateFormat, $dateAndTime . $microseconds . $timeZone, new \DateTimeZone('UTC'));
84532
84533 return $dateTime ?: null;
84534 }
84535 }
84536 <?php
84537
84538 namespace JsonSchema;
84539
84540 use JsonSchema\Constraints\BaseConstraint;
84541 use JsonSchema\Entity\JsonPointer;
84542 use JsonSchema\Exception\UnresolvableJsonPointerException;
84543 use JsonSchema\Uri\UriResolver;
84544 use JsonSchema\Uri\UriRetriever;
84545
84546 class SchemaStorage implements SchemaStorageInterface
84547 {
84548 const INTERNAL_PROVIDED_SCHEMA_URI = 'internal://provided-schema/';
84549
84550 protected $uriRetriever;
84551 protected $uriResolver;
84552 protected $schemas = array();
84553
84554 public function __construct(
84555 UriRetrieverInterface $uriRetriever = null,
84556 UriResolverInterface $uriResolver = null
84557 ) {
84558 $this->uriRetriever = $uriRetriever ?: new UriRetriever();
84559 $this->uriResolver = $uriResolver ?: new UriResolver();
84560 }
84561
84562
84563
84564
84565 public function getUriRetriever()
84566 {
84567 return $this->uriRetriever;
84568 }
84569
84570
84571
84572
84573 public function getUriResolver()
84574 {
84575 return $this->uriResolver;
84576 }
84577
84578
84579
84580
84581 public function addSchema($id, $schema = null)
84582 {
84583 if (is_null($schema) && $id !== self::INTERNAL_PROVIDED_SCHEMA_URI) {
84584
84585
84586
84587 $schema = $this->uriRetriever->retrieve($id);
84588 }
84589
84590
84591 if (is_array($schema)) {
84592 $schema = BaseConstraint::arrayToObjectRecursive($schema);
84593 }
84594
84595
84596
84597 if (is_object($schema) && property_exists($schema, 'id')) {
84598 if ($schema->id == 'http://json-schema.org/draft-04/schema#') {
84599 $schema->properties->id->format = 'uri-reference';
84600 } elseif ($schema->id == 'http://json-schema.org/draft-03/schema#') {
84601 $schema->properties->id->format = 'uri-reference';
84602 $schema->properties->{'$ref'}->format = 'uri-reference';
84603 }
84604 }
84605
84606
84607 $this->expandRefs($schema, $id);
84608
84609 $this->schemas[$id] = $schema;
84610 }
84611
84612
84613
84614
84615
84616
84617
84618 private function expandRefs(&$schema, $base = null)
84619 {
84620 if (!is_object($schema)) {
84621 if (is_array($schema)) {
84622 foreach ($schema as &$member) {
84623 $this->expandRefs($member, $base);
84624 }
84625 }
84626
84627 return;
84628 }
84629
84630 if (property_exists($schema, 'id') && is_string($schema->id) && $base != $schema->id) {
84631 $base = $this->uriResolver->resolve($schema->id, $base);
84632 }
84633
84634 if (property_exists($schema, '$ref') && is_string($schema->{'$ref'})) {
84635 $refPointer = new JsonPointer($this->uriResolver->resolve($schema->{'$ref'}, $base));
84636 $schema->{'$ref'} = (string) $refPointer;
84637 }
84638
84639 foreach ($schema as &$member) {
84640 $this->expandRefs($member, $base);
84641 }
84642 }
84643
84644
84645
84646
84647 public function getSchema($id)
84648 {
84649 if (!array_key_exists($id, $this->schemas)) {
84650 $this->addSchema($id);
84651 }
84652
84653 return $this->schemas[$id];
84654 }
84655
84656
84657
84658
84659 public function resolveRef($ref)
84660 {
84661 $jsonPointer = new JsonPointer($ref);
84662
84663
84664 $fileName = $jsonPointer->getFilename();
84665 if (!strlen($fileName)) {
84666 throw new UnresolvableJsonPointerException(sprintf(
84667 "Could not resolve fragment '%s': no file is defined",
84668 $jsonPointer->getPropertyPathAsString()
84669 ));
84670 }
84671
84672
84673 $refSchema = $this->getSchema($fileName);
84674 foreach ($jsonPointer->getPropertyPaths() as $path) {
84675 if (is_object($refSchema) && property_exists($refSchema, $path)) {
84676 $refSchema = $this->resolveRefSchema($refSchema->{$path});
84677 } elseif (is_array($refSchema) && array_key_exists($path, $refSchema)) {
84678 $refSchema = $this->resolveRefSchema($refSchema[$path]);
84679 } else {
84680 throw new UnresolvableJsonPointerException(sprintf(
84681 'File: %s is found, but could not resolve fragment: %s',
84682 $jsonPointer->getFilename(),
84683 $jsonPointer->getPropertyPathAsString()
84684 ));
84685 }
84686 }
84687
84688 return $refSchema;
84689 }
84690
84691
84692
84693
84694 public function resolveRefSchema($refSchema)
84695 {
84696 if (is_object($refSchema) && property_exists($refSchema, '$ref') && is_string($refSchema->{'$ref'})) {
84697 $newSchema = $this->resolveRef($refSchema->{'$ref'});
84698 $refSchema = (object) (get_object_vars($refSchema) + get_object_vars($newSchema));
84699 unset($refSchema->{'$ref'});
84700 }
84701
84702 return $refSchema;
84703 }
84704 }
84705 <?php
84706
84707 namespace JsonSchema;
84708
84709 interface SchemaStorageInterface
84710 {
84711
84712
84713
84714
84715
84716
84717 public function addSchema($id, $schema = null);
84718
84719
84720
84721
84722
84723
84724
84725
84726 public function getSchema($id);
84727
84728
84729
84730
84731
84732
84733
84734
84735 public function resolveRef($ref);
84736
84737
84738
84739
84740
84741
84742
84743
84744 public function resolveRefSchema($refSchema);
84745 }
84746 <?php
84747
84748
84749
84750
84751
84752
84753 namespace JsonSchema\Uri\Retrievers;
84754
84755
84756
84757
84758
84759
84760
84761 abstract class AbstractRetriever implements UriRetrieverInterface
84762 {
84763
84764
84765
84766
84767
84768 protected $contentType;
84769
84770
84771
84772
84773
84774
84775 public function getContentType()
84776 {
84777 return $this->contentType;
84778 }
84779 }
84780 <?php
84781
84782
84783
84784
84785
84786
84787
84788
84789 namespace JsonSchema\Uri\Retrievers;
84790
84791 use JsonSchema\Exception\RuntimeException;
84792 use JsonSchema\Validator;
84793
84794
84795
84796
84797
84798
84799 class Curl extends AbstractRetriever
84800 {
84801 protected $messageBody;
84802
84803 public function __construct()
84804 {
84805 if (!function_exists('curl_init')) {
84806
84807 throw new RuntimeException('cURL not installed'); 
84808 }
84809 }
84810
84811
84812
84813
84814
84815
84816 public function retrieve($uri)
84817 {
84818 $ch = curl_init();
84819
84820 curl_setopt($ch, CURLOPT_URL, $uri);
84821 curl_setopt($ch, CURLOPT_HEADER, true);
84822 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
84823 curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: ' . Validator::SCHEMA_MEDIA_TYPE));
84824
84825 $response = curl_exec($ch);
84826 if (false === $response) {
84827 throw new \JsonSchema\Exception\ResourceNotFoundException('JSON schema not found');
84828 }
84829
84830 $this->fetchMessageBody($response);
84831 $this->fetchContentType($response);
84832
84833 curl_close($ch);
84834
84835 return $this->messageBody;
84836 }
84837
84838
84839
84840
84841 private function fetchMessageBody($response)
84842 {
84843 preg_match("/(?:\r\n){2}(.*)$/ms", $response, $match);
84844 $this->messageBody = $match[1];
84845 }
84846
84847
84848
84849
84850
84851
84852 protected function fetchContentType($response)
84853 {
84854 if (0 < preg_match("/Content-Type:(\V*)/ims", $response, $match)) {
84855 $this->contentType = trim($match[1]);
84856
84857 return true;
84858 }
84859
84860 return false;
84861 }
84862 }
84863 <?php
84864
84865
84866
84867
84868
84869
84870
84871
84872 namespace JsonSchema\Uri\Retrievers;
84873
84874 use JsonSchema\Exception\ResourceNotFoundException;
84875
84876
84877
84878
84879
84880
84881 class FileGetContents extends AbstractRetriever
84882 {
84883 protected $messageBody;
84884
84885
84886
84887
84888
84889
84890 public function retrieve($uri)
84891 {
84892 $errorMessage = null;
84893 set_error_handler(function ($errno, $errstr) use (&$errorMessage) {
84894 $errorMessage = $errstr;
84895 });
84896 $response = file_get_contents($uri);
84897 restore_error_handler();
84898
84899 if ($errorMessage) {
84900 throw new ResourceNotFoundException($errorMessage);
84901 }
84902
84903 if (false === $response) {
84904 throw new ResourceNotFoundException('JSON schema not found at ' . $uri);
84905 }
84906
84907 if ($response == ''
84908 && substr($uri, 0, 7) == 'file://' && substr($uri, -1) == '/'
84909 ) {
84910 throw new ResourceNotFoundException('JSON schema not found at ' . $uri);
84911 }
84912
84913 $this->messageBody = $response;
84914 if (!empty($http_response_header)) {
84915
84916
84917 $this->fetchContentType($http_response_header); 
84918 } else { 
84919
84920 $this->contentType = null;
84921 }
84922
84923 return $this->messageBody;
84924 }
84925
84926
84927
84928
84929
84930
84931 private function fetchContentType(array $headers)
84932 {
84933 foreach ($headers as $header) {
84934 if ($this->contentType = self::getContentTypeMatchInHeader($header)) {
84935 return true;
84936 }
84937 }
84938
84939 return false;
84940 }
84941
84942
84943
84944
84945
84946
84947 protected static function getContentTypeMatchInHeader($header)
84948 {
84949 if (0 < preg_match("/Content-Type:(\V*)/ims", $header, $match)) {
84950 return trim($match[1]);
84951 }
84952
84953 return null;
84954 }
84955 }
84956 <?php
84957
84958 namespace JsonSchema\Uri\Retrievers;
84959
84960 use JsonSchema\Validator;
84961
84962
84963
84964
84965
84966
84967
84968
84969
84970
84971
84972
84973
84974 class PredefinedArray extends AbstractRetriever
84975 {
84976
84977
84978
84979
84980
84981 private $schemas;
84982
84983
84984
84985
84986
84987
84988
84989 public function __construct(array $schemas, $contentType = Validator::SCHEMA_MEDIA_TYPE)
84990 {
84991 $this->schemas = $schemas;
84992 $this->contentType = $contentType;
84993 }
84994
84995
84996
84997
84998
84999
85000 public function retrieve($uri)
85001 {
85002 if (!array_key_exists($uri, $this->schemas)) {
85003 throw new \JsonSchema\Exception\ResourceNotFoundException(sprintf(
85004 'The JSON schema "%s" was not found.',
85005 $uri
85006 ));
85007 }
85008
85009 return $this->schemas[$uri];
85010 }
85011 }
85012 <?php
85013
85014
85015
85016
85017
85018
85019
85020
85021 namespace JsonSchema\Uri\Retrievers;
85022
85023
85024
85025
85026
85027
85028 interface UriRetrieverInterface
85029 {
85030
85031
85032
85033
85034
85035
85036
85037
85038
85039 public function retrieve($uri);
85040
85041
85042
85043
85044
85045
85046 public function getContentType();
85047 }
85048 <?php
85049
85050
85051
85052
85053
85054
85055
85056
85057 namespace JsonSchema\Uri;
85058
85059 use JsonSchema\Exception\UriResolverException;
85060 use JsonSchema\UriResolverInterface;
85061
85062
85063
85064
85065
85066
85067 class UriResolver implements UriResolverInterface
85068 {
85069
85070
85071
85072
85073
85074
85075
85076 public function parse($uri)
85077 {
85078 preg_match('|^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?|', $uri, $match);
85079
85080 $components = array();
85081 if (5 < count($match)) {
85082 $components = array(
85083 'scheme' => $match[2],
85084 'authority' => $match[4],
85085 'path' => $match[5]
85086 );
85087 }
85088 if (7 < count($match)) {
85089 $components['query'] = $match[7];
85090 }
85091 if (9 < count($match)) {
85092 $components['fragment'] = $match[9];
85093 }
85094
85095 return $components;
85096 }
85097
85098
85099
85100
85101
85102
85103
85104
85105 public function generate(array $components)
85106 {
85107 $uri = $components['scheme'] . '://'
85108 . $components['authority']
85109 . $components['path'];
85110
85111 if (array_key_exists('query', $components) && strlen($components['query'])) {
85112 $uri .= '?' . $components['query'];
85113 }
85114 if (array_key_exists('fragment', $components)) {
85115 $uri .= '#' . $components['fragment'];
85116 }
85117
85118 return $uri;
85119 }
85120
85121
85122
85123
85124 public function resolve($uri, $baseUri = null)
85125 {
85126
85127 if (
85128 !is_null($baseUri) &&
85129 !filter_var($baseUri, \FILTER_VALIDATE_URL) &&
85130 !preg_match('|^[^/]+://|u', $baseUri)
85131 ) {
85132 if (is_file($baseUri)) {
85133 $baseUri = 'file://' . realpath($baseUri);
85134 } elseif (is_dir($baseUri)) {
85135 $baseUri = 'file://' . realpath($baseUri) . '/';
85136 } else {
85137 $baseUri = 'file://' . getcwd() . '/' . $baseUri;
85138 }
85139 }
85140
85141 if ($uri == '') {
85142 return $baseUri;
85143 }
85144
85145 $components = $this->parse($uri);
85146 $path = $components['path'];
85147
85148 if (!empty($components['scheme'])) {
85149 return $uri;
85150 }
85151 $baseComponents = $this->parse($baseUri);
85152 $basePath = $baseComponents['path'];
85153
85154 $baseComponents['path'] = self::combineRelativePathWithBasePath($path, $basePath);
85155 if (isset($components['fragment'])) {
85156 $baseComponents['fragment'] = $components['fragment'];
85157 }
85158
85159 return $this->generate($baseComponents);
85160 }
85161
85162
85163
85164
85165
85166
85167
85168
85169
85170
85171
85172 public static function combineRelativePathWithBasePath($relativePath, $basePath)
85173 {
85174 $relativePath = self::normalizePath($relativePath);
85175 if ($relativePath == '') {
85176 return $basePath;
85177 }
85178 if ($relativePath[0] == '/') {
85179 return $relativePath;
85180 }
85181
85182 $basePathSegments = explode('/', $basePath);
85183
85184 preg_match('|^/?(\.\./(?:\./)*)*|', $relativePath, $match);
85185 $numLevelUp = strlen($match[0]) /3 + 1;
85186 if ($numLevelUp >= count($basePathSegments)) {
85187 throw new UriResolverException(sprintf("Unable to resolve URI '%s' from base '%s'", $relativePath, $basePath));
85188 }
85189
85190 $basePathSegments = array_slice($basePathSegments, 0, -$numLevelUp);
85191 $path = preg_replace('|^/?(\.\./(\./)*)*|', '', $relativePath);
85192
85193 return implode('/', $basePathSegments) . '/' . $path;
85194 }
85195
85196
85197
85198
85199
85200
85201
85202
85203 private static function normalizePath($path)
85204 {
85205 $path = preg_replace('|((?<!\.)\./)*|', '', $path);
85206 $path = preg_replace('|//|', '/', $path);
85207
85208 return $path;
85209 }
85210
85211
85212
85213
85214
85215
85216 public function isValid($uri)
85217 {
85218 $components = $this->parse($uri);
85219
85220 return !empty($components);
85221 }
85222 }
85223 <?php
85224
85225
85226
85227
85228
85229
85230
85231
85232 namespace JsonSchema\Uri;
85233
85234 use JsonSchema\Exception\InvalidSchemaMediaTypeException;
85235 use JsonSchema\Exception\JsonDecodingException;
85236 use JsonSchema\Exception\ResourceNotFoundException;
85237 use JsonSchema\Uri\Retrievers\FileGetContents;
85238 use JsonSchema\Uri\Retrievers\UriRetrieverInterface;
85239 use JsonSchema\UriRetrieverInterface as BaseUriRetrieverInterface;
85240 use JsonSchema\Validator;
85241
85242
85243
85244
85245
85246
85247 class UriRetriever implements BaseUriRetrieverInterface
85248 {
85249
85250
85251
85252 protected $translationMap = array(
85253
85254 '|^https?://json-schema.org/draft-(0[34])/schema#?|' => 'package://dist/schema/json-schema-draft-$1.json'
85255 );
85256
85257
85258
85259
85260 protected $allowedInvalidContentTypeEndpoints = array(
85261 'http://json-schema.org/',
85262 'https://json-schema.org/'
85263 );
85264
85265
85266
85267
85268 protected $uriRetriever = null;
85269
85270
85271
85272
85273
85274
85275 private $schemaCache = array();
85276
85277
85278
85279
85280
85281
85282 public function addInvalidContentTypeEndpoint($endpoint)
85283 {
85284 $this->allowedInvalidContentTypeEndpoints[] = $endpoint;
85285 }
85286
85287
85288
85289
85290
85291
85292
85293
85294
85295 public function confirmMediaType($uriRetriever, $uri)
85296 {
85297 $contentType = $uriRetriever->getContentType();
85298
85299 if (is_null($contentType)) {
85300
85301 return;
85302 }
85303
85304 if (in_array($contentType, array(Validator::SCHEMA_MEDIA_TYPE, 'application/json'))) {
85305 return;
85306 }
85307
85308 foreach ($this->allowedInvalidContentTypeEndpoints as $endpoint) {
85309 if (strpos($uri, $endpoint) === 0) {
85310 return true;
85311 }
85312 }
85313
85314 throw new InvalidSchemaMediaTypeException(sprintf('Media type %s expected', Validator::SCHEMA_MEDIA_TYPE));
85315 }
85316
85317
85318
85319
85320
85321
85322
85323
85324
85325 public function getUriRetriever()
85326 {
85327 if (is_null($this->uriRetriever)) {
85328 $this->setUriRetriever(new FileGetContents());
85329 }
85330
85331 return $this->uriRetriever;
85332 }
85333
85334
85335
85336
85337
85338
85339
85340
85341
85342
85343
85344
85345
85346
85347
85348 public function resolvePointer($jsonSchema, $uri)
85349 {
85350 $resolver = new UriResolver();
85351 $parsed = $resolver->parse($uri);
85352 if (empty($parsed['fragment'])) {
85353 return $jsonSchema;
85354 }
85355
85356 $path = explode('/', $parsed['fragment']);
85357 while ($path) {
85358 $pathElement = array_shift($path);
85359 if (!empty($pathElement)) {
85360 $pathElement = str_replace('~1', '/', $pathElement);
85361 $pathElement = str_replace('~0', '~', $pathElement);
85362 if (!empty($jsonSchema->$pathElement)) {
85363 $jsonSchema = $jsonSchema->$pathElement;
85364 } else {
85365 throw new ResourceNotFoundException(
85366 'Fragment "' . $parsed['fragment'] . '" not found'
85367 . ' in ' . $uri
85368 );
85369 }
85370
85371 if (!is_object($jsonSchema)) {
85372 throw new ResourceNotFoundException(
85373 'Fragment part "' . $pathElement . '" is no object '
85374 . ' in ' . $uri
85375 );
85376 }
85377 }
85378 }
85379
85380 return $jsonSchema;
85381 }
85382
85383
85384
85385
85386 public function retrieve($uri, $baseUri = null, $translate = true)
85387 {
85388 $resolver = new UriResolver();
85389 $resolvedUri = $fetchUri = $resolver->resolve($uri, $baseUri);
85390
85391
85392 $arParts = $resolver->parse($resolvedUri);
85393 if (isset($arParts['fragment'])) {
85394 unset($arParts['fragment']);
85395 $fetchUri = $resolver->generate($arParts);
85396 }
85397
85398
85399 if ($translate) {
85400 $fetchUri = $this->translate($fetchUri);
85401 }
85402
85403 $jsonSchema = $this->loadSchema($fetchUri);
85404
85405
85406 $jsonSchema = $this->resolvePointer($jsonSchema, $resolvedUri);
85407
85408 if ($jsonSchema instanceof \stdClass) {
85409 $jsonSchema->id = $resolvedUri;
85410 }
85411
85412 return $jsonSchema;
85413 }
85414
85415
85416
85417
85418
85419
85420
85421
85422
85423 protected function loadSchema($fetchUri)
85424 {
85425 if (isset($this->schemaCache[$fetchUri])) {
85426 return $this->schemaCache[$fetchUri];
85427 }
85428
85429 $uriRetriever = $this->getUriRetriever();
85430 $contents = $this->uriRetriever->retrieve($fetchUri);
85431 $this->confirmMediaType($uriRetriever, $fetchUri);
85432 $jsonSchema = json_decode($contents);
85433
85434 if (JSON_ERROR_NONE < $error = json_last_error()) {
85435 throw new JsonDecodingException($error);
85436 }
85437
85438 $this->schemaCache[$fetchUri] = $jsonSchema;
85439
85440 return $jsonSchema;
85441 }
85442
85443
85444
85445
85446
85447
85448
85449
85450 public function setUriRetriever(UriRetrieverInterface $uriRetriever)
85451 {
85452 $this->uriRetriever = $uriRetriever;
85453
85454 return $this;
85455 }
85456
85457
85458
85459
85460
85461
85462
85463
85464 public function parse($uri)
85465 {
85466 preg_match('|^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?|', $uri, $match);
85467
85468 $components = array();
85469 if (5 < count($match)) {
85470 $components = array(
85471 'scheme' => $match[2],
85472 'authority' => $match[4],
85473 'path' => $match[5]
85474 );
85475 }
85476
85477 if (7 < count($match)) {
85478 $components['query'] = $match[7];
85479 }
85480
85481 if (9 < count($match)) {
85482 $components['fragment'] = $match[9];
85483 }
85484
85485 return $components;
85486 }
85487
85488
85489
85490
85491
85492
85493
85494
85495 public function generate(array $components)
85496 {
85497 $uri = $components['scheme'] . '://'
85498 . $components['authority']
85499 . $components['path'];
85500
85501 if (array_key_exists('query', $components)) {
85502 $uri .= $components['query'];
85503 }
85504
85505 if (array_key_exists('fragment', $components)) {
85506 $uri .= $components['fragment'];
85507 }
85508
85509 return $uri;
85510 }
85511
85512
85513
85514
85515
85516
85517
85518
85519
85520 public function resolve($uri, $baseUri = null)
85521 {
85522 $components = $this->parse($uri);
85523 $path = $components['path'];
85524
85525 if ((array_key_exists('scheme', $components)) && ('http' === $components['scheme'])) {
85526 return $uri;
85527 }
85528
85529 $baseComponents = $this->parse($baseUri);
85530 $basePath = $baseComponents['path'];
85531
85532 $baseComponents['path'] = UriResolver::combineRelativePathWithBasePath($path, $basePath);
85533
85534 return $this->generate($baseComponents);
85535 }
85536
85537
85538
85539
85540
85541
85542 public function isValid($uri)
85543 {
85544 $components = $this->parse($uri);
85545
85546 return !empty($components);
85547 }
85548
85549
85550
85551
85552 public function setTranslation($from, $to)
85553 {
85554 $this->translationMap[$from] = $to;
85555 }
85556
85557
85558
85559
85560 public function translate($uri)
85561 {
85562 foreach ($this->translationMap as $from => $to) {
85563 $uri = preg_replace($from, $to, $uri);
85564 }
85565
85566
85567 $uri = preg_replace('|^package://|', sprintf('file://%s/', realpath(__DIR__ . '/../../..')), $uri);
85568
85569 return $uri;
85570 }
85571 }
85572 <?php
85573
85574
85575
85576
85577
85578
85579
85580
85581 namespace JsonSchema;
85582
85583
85584
85585
85586 interface UriResolverInterface
85587 {
85588
85589
85590
85591
85592
85593
85594
85595
85596 public function resolve($uri, $baseUri = null);
85597 }
85598 <?php
85599
85600
85601
85602
85603
85604
85605
85606
85607 namespace JsonSchema;
85608
85609
85610
85611
85612 interface UriRetrieverInterface
85613 {
85614
85615
85616
85617
85618
85619
85620
85621
85622 public function retrieve($uri, $baseUri = null);
85623 }
85624 <?php
85625
85626
85627
85628
85629
85630
85631
85632
85633 namespace JsonSchema;
85634
85635 use JsonSchema\Constraints\BaseConstraint;
85636 use JsonSchema\Constraints\Constraint;
85637
85638
85639
85640
85641
85642
85643
85644
85645
85646 class Validator extends BaseConstraint
85647 {
85648 const SCHEMA_MEDIA_TYPE = 'application/schema+json';
85649
85650 const ERROR_NONE = 0x00000000;
85651 const ERROR_ALL = 0xFFFFFFFF;
85652 const ERROR_DOCUMENT_VALIDATION = 0x00000001;
85653 const ERROR_SCHEMA_VALIDATION = 0x00000002;
85654
85655
85656
85657
85658
85659
85660
85661
85662 public function validate(&$value, $schema = null, $checkMode = null)
85663 {
85664
85665 if (is_array($schema)) {
85666 $schema = self::arrayToObjectRecursive($schema);
85667 }
85668
85669
85670 $initialCheckMode = $this->factory->getConfig();
85671 if ($checkMode !== null) {
85672 $this->factory->setConfig($checkMode);
85673 }
85674
85675
85676 if (is_object($schema) && property_exists($schema, 'id')) {
85677 $schemaURI = $schema->id;
85678 } else {
85679 $schemaURI = SchemaStorage::INTERNAL_PROVIDED_SCHEMA_URI;
85680 }
85681 $this->factory->getSchemaStorage()->addSchema($schemaURI, $schema);
85682
85683 $validator = $this->factory->createInstanceFor('schema');
85684 $validator->check(
85685 $value,
85686 $this->factory->getSchemaStorage()->getSchema($schemaURI)
85687 );
85688
85689 $this->factory->setConfig($initialCheckMode);
85690
85691 $this->addErrors(array_unique($validator->getErrors(), SORT_REGULAR));
85692
85693 return $validator->getErrorMask();
85694 }
85695
85696
85697
85698
85699 public function check($value, $schema)
85700 {
85701 return $this->validate($value, $schema);
85702 }
85703
85704
85705
85706
85707 public function coerce(&$value, $schema)
85708 {
85709 return $this->validate($value, $schema, Constraint::CHECK_MODE_COERCE_TYPES);
85710 }
85711 }
85712 Copyright (C) 2015 Composer
85713
85714 Permission is hereby granted, free of charge, to any person obtaining a copy of
85715 this software and associated documentation files (the "Software"), to deal in
85716 the Software without restriction, including without limitation the rights to
85717 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
85718 of the Software, and to permit persons to whom the Software is furnished to do
85719 so, subject to the following conditions:
85720
85721 The above copyright notice and this permission notice shall be included in all
85722 copies or substantial portions of the Software.
85723
85724 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
85725 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
85726 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
85727 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
85728 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
85729 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
85730 SOFTWARE.
85731 <?php
85732
85733
85734
85735
85736
85737
85738
85739
85740
85741
85742 namespace Composer\Spdx;
85743
85744 class SpdxLicenses
85745 {
85746
85747 const LICENSES_FILE = 'spdx-licenses.json';
85748
85749
85750 const EXCEPTIONS_FILE = 'spdx-exceptions.json';
85751
85752
85753
85754
85755
85756
85757
85758
85759
85760
85761
85762
85763
85764
85765 private $licenses;
85766
85767
85768
85769
85770 private $licensesExpression;
85771
85772
85773
85774
85775
85776
85777
85778
85779
85780
85781
85782
85783
85784
85785 private $exceptions;
85786
85787
85788
85789
85790 private $exceptionsExpression;
85791
85792 public function __construct()
85793 {
85794 $this->loadLicenses();
85795 $this->loadExceptions();
85796 }
85797
85798
85799
85800
85801
85802
85803
85804
85805
85806
85807
85808
85809
85810 public function getLicenseByIdentifier($identifier)
85811 {
85812 $key = strtolower($identifier);
85813
85814 if (!isset($this->licenses[$key])) {
85815 return;
85816 }
85817
85818 list($identifier, $name, $isOsiApproved, $isDeprecatedLicenseId) = $this->licenses[$key];
85819
85820 return array(
85821 $name,
85822 $isOsiApproved,
85823 'https://spdx.org/licenses/' . $identifier . '.html#licenseText',
85824 $isDeprecatedLicenseId,
85825 );
85826 }
85827
85828
85829
85830
85831
85832
85833 public function getLicenses()
85834 {
85835 return $this->licenses;
85836 }
85837
85838
85839
85840
85841
85842
85843
85844
85845
85846
85847
85848
85849
85850 public function getExceptionByIdentifier($identifier)
85851 {
85852 $key = strtolower($identifier);
85853
85854 if (!isset($this->exceptions[$key])) {
85855 return;
85856 }
85857
85858 list($identifier, $name) = $this->exceptions[$key];
85859
85860 return array(
85861 $name,
85862 'https://spdx.org/licenses/' . $identifier . '.html#licenseExceptionText',
85863 );
85864 }
85865
85866
85867
85868
85869
85870
85871
85872
85873 public function getIdentifierByName($name)
85874 {
85875 foreach ($this->licenses as $licenseData) {
85876 if ($licenseData[1] === $name) {
85877 return $licenseData[0];
85878 }
85879 }
85880
85881 foreach ($this->exceptions as $licenseData) {
85882 if ($licenseData[1] === $name) {
85883 return $licenseData[0];
85884 }
85885 }
85886 }
85887
85888
85889
85890
85891
85892
85893
85894
85895 public function isOsiApprovedByIdentifier($identifier)
85896 {
85897 return $this->licenses[strtolower($identifier)][2];
85898 }
85899
85900
85901
85902
85903
85904
85905
85906
85907 public function isDeprecatedByIdentifier($identifier)
85908 {
85909 return $this->licenses[strtolower($identifier)][3];
85910 }
85911
85912
85913
85914
85915
85916
85917
85918
85919 public function validate($license)
85920 {
85921 if (is_array($license)) {
85922 $count = count($license);
85923 if ($count !== count(array_filter($license, 'is_string'))) {
85924 throw new \InvalidArgumentException('Array of strings expected.');
85925 }
85926 $license = $count > 1 ? '(' . implode(' OR ', $license) . ')' : (string) reset($license);
85927 }
85928
85929 if (!is_string($license)) {
85930 throw new \InvalidArgumentException(sprintf(
85931 'Array or String expected, %s given.',
85932 gettype($license)
85933 ));
85934 }
85935
85936 return $this->isValidLicenseString($license);
85937 }
85938
85939
85940
85941
85942 public static function getResourcesDir()
85943 {
85944 return dirname(__DIR__) . '/res';
85945 }
85946
85947 private function loadLicenses()
85948 {
85949 if (null !== $this->licenses) {
85950 return;
85951 }
85952
85953 $json = file_get_contents(self::getResourcesDir() . '/' . self::LICENSES_FILE);
85954 $this->licenses = array();
85955
85956 foreach (json_decode($json, true) as $identifier => $license) {
85957 $this->licenses[strtolower($identifier)] = array($identifier, $license[0], $license[1], $license[2]);
85958 }
85959 }
85960
85961 private function loadExceptions()
85962 {
85963 if (null !== $this->exceptions) {
85964 return;
85965 }
85966
85967 $json = file_get_contents(self::getResourcesDir() . '/' . self::EXCEPTIONS_FILE);
85968 $this->exceptions = array();
85969
85970 foreach (json_decode($json, true) as $identifier => $exception) {
85971 $this->exceptions[strtolower($identifier)] = array($identifier, $exception[0]);
85972 }
85973 }
85974
85975
85976
85977
85978 private function getLicensesExpression()
85979 {
85980 if (null === $this->licensesExpression) {
85981 $licenses = array_map('preg_quote', array_keys($this->licenses));
85982 rsort($licenses);
85983 $licenses = implode('|', $licenses);
85984 $this->licensesExpression = $licenses;
85985 }
85986
85987 return $this->licensesExpression;
85988 }
85989
85990
85991
85992
85993 private function getExceptionsExpression()
85994 {
85995 if (null === $this->exceptionsExpression) {
85996 $exceptions = array_map('preg_quote', array_keys($this->exceptions));
85997 rsort($exceptions);
85998 $exceptions = implode('|', $exceptions);
85999 $this->exceptionsExpression = $exceptions;
86000 }
86001
86002 return $this->exceptionsExpression;
86003 }
86004
86005
86006
86007
86008
86009
86010
86011
86012 private function isValidLicenseString($license)
86013 {
86014 if (isset($this->licenses[strtolower($license)])) {
86015 return true;
86016 }
86017
86018 $licenses = $this->getLicensesExpression();
86019 $exceptions = $this->getExceptionsExpression();
86020
86021 $regex = <<<REGEX
86022 {
86023 (?(DEFINE)
86024     # idstring: 1*( ALPHA / DIGIT / - / . )
86025     (?<idstring>[\pL\pN.-]{1,})
86026
86027     # license-id: taken from list
86028     (?<licenseid>${licenses})
86029
86030     # license-exception-id: taken from list
86031     (?<licenseexceptionid>${exceptions})
86032
86033     # license-ref: [DocumentRef-1*(idstring):]LicenseRef-1*(idstring)
86034     (?<licenseref>(?:DocumentRef-(?&idstring):)?LicenseRef-(?&idstring))
86035
86036     # simple-expresssion: license-id / license-id+ / license-ref
86037     (?<simple_expression>(?&licenseid)\+? | (?&licenseid) | (?&licenseref))
86038
86039     # compound-expression: 1*(
86040     #   simple-expression /
86041     #   simple-expression WITH license-exception-id /
86042     #   compound-expression AND compound-expression /
86043     #   compound-expression OR compound-expression
86044     # ) / ( compound-expression ) )
86045     (?<compound_head>
86046         (?&simple_expression) ( \s+ WITH \s+ (?&licenseexceptionid))?
86047             | \( \s* (?&compound_expression) \s* \)
86048     )
86049     (?<compound_expression>
86050         (?&compound_head) (?: \s+ (?:AND|OR) \s+ (?&compound_expression))?
86051     )
86052
86053     # license-expression: 1*1(simple-expression / compound-expression)
86054     (?<license_expression>(?&compound_expression) | (?&simple_expression))
86055 ) # end of define
86056
86057 ^(NONE | NOASSERTION | (?&license_expression))$
86058 }xi
86059 REGEX;
86060
86061 $match = preg_match($regex, $license);
86062
86063 if (0 === $match) {
86064 return false;
86065 }
86066
86067 if (false === $match) {
86068 throw new \RuntimeException('Regex failed to compile/run.');
86069 }
86070
86071 return true;
86072 }
86073 }
86074 Copyright (C) 2015 Composer
86075
86076 Permission is hereby granted, free of charge, to any person obtaining a copy of
86077 this software and associated documentation files (the "Software"), to deal in
86078 the Software without restriction, including without limitation the rights to
86079 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
86080 of the Software, and to permit persons to whom the Software is furnished to do
86081 so, subject to the following conditions:
86082
86083 The above copyright notice and this permission notice shall be included in all
86084 copies or substantial portions of the Software.
86085
86086 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
86087 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
86088 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
86089 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
86090 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
86091 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
86092 SOFTWARE.
86093 <?php
86094
86095
86096
86097
86098
86099
86100
86101
86102
86103
86104 namespace Composer\Semver;
86105
86106 use Composer\Semver\Constraint\Constraint;
86107
86108 class Comparator
86109 {
86110
86111
86112
86113
86114
86115
86116
86117
86118 public static function greaterThan($version1, $version2)
86119 {
86120 return self::compare($version1, '>', $version2);
86121 }
86122
86123
86124
86125
86126
86127
86128
86129
86130
86131 public static function greaterThanOrEqualTo($version1, $version2)
86132 {
86133 return self::compare($version1, '>=', $version2);
86134 }
86135
86136
86137
86138
86139
86140
86141
86142
86143
86144 public static function lessThan($version1, $version2)
86145 {
86146 return self::compare($version1, '<', $version2);
86147 }
86148
86149
86150
86151
86152
86153
86154
86155
86156
86157 public static function lessThanOrEqualTo($version1, $version2)
86158 {
86159 return self::compare($version1, '<=', $version2);
86160 }
86161
86162
86163
86164
86165
86166
86167
86168
86169
86170 public static function equalTo($version1, $version2)
86171 {
86172 return self::compare($version1, '==', $version2);
86173 }
86174
86175
86176
86177
86178
86179
86180
86181
86182
86183 public static function notEqualTo($version1, $version2)
86184 {
86185 return self::compare($version1, '!=', $version2);
86186 }
86187
86188
86189
86190
86191
86192
86193
86194
86195
86196
86197 public static function compare($version1, $operator, $version2)
86198 {
86199 $constraint = new Constraint($operator, $version2);
86200
86201 return $constraint->matches(new Constraint('==', $version1));
86202 }
86203 }
86204 <?php
86205
86206
86207
86208
86209
86210
86211
86212
86213
86214
86215 namespace Composer\Semver\Constraint;
86216
86217 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);
86218
86219
86220
86221
86222 abstract class AbstractConstraint implements ConstraintInterface
86223 {
86224
86225 protected $prettyString;
86226
86227
86228
86229
86230
86231
86232 public function matches(ConstraintInterface $provider)
86233 {
86234 if ($provider instanceof $this) {
86235
86236 return $this->matchSpecific($provider);
86237 }
86238
86239
86240 return $provider->matches($this);
86241 }
86242
86243
86244
86245
86246 public function setPrettyString($prettyString)
86247 {
86248 $this->prettyString = $prettyString;
86249 }
86250
86251
86252
86253
86254 public function getPrettyString()
86255 {
86256 if ($this->prettyString) {
86257 return $this->prettyString;
86258 }
86259
86260 return $this->__toString();
86261 }
86262
86263
86264
86265
86266 }
86267 <?php
86268
86269
86270
86271
86272
86273
86274
86275
86276
86277
86278 namespace Composer\Semver\Constraint;
86279
86280
86281
86282
86283 class Constraint implements ConstraintInterface
86284 {
86285
86286 const OP_EQ = 0;
86287 const OP_LT = 1;
86288 const OP_LE = 2;
86289 const OP_GT = 3;
86290 const OP_GE = 4;
86291 const OP_NE = 5;
86292
86293
86294
86295
86296
86297
86298 private static $transOpStr = array(
86299 '=' => self::OP_EQ,
86300 '==' => self::OP_EQ,
86301 '<' => self::OP_LT,
86302 '<=' => self::OP_LE,
86303 '>' => self::OP_GT,
86304 '>=' => self::OP_GE,
86305 '<>' => self::OP_NE,
86306 '!=' => self::OP_NE,
86307 );
86308
86309
86310
86311
86312
86313
86314 private static $transOpInt = array(
86315 self::OP_EQ => '==',
86316 self::OP_LT => '<',
86317 self::OP_LE => '<=',
86318 self::OP_GT => '>',
86319 self::OP_GE => '>=',
86320 self::OP_NE => '!=',
86321 );
86322
86323
86324 protected $operator;
86325
86326
86327 protected $version;
86328
86329
86330 protected $prettyString;
86331
86332
86333
86334
86335
86336
86337 public function matches(ConstraintInterface $provider)
86338 {
86339 if ($provider instanceof $this) {
86340 return $this->matchSpecific($provider);
86341 }
86342
86343
86344 return $provider->matches($this);
86345 }
86346
86347
86348
86349
86350 public function setPrettyString($prettyString)
86351 {
86352 $this->prettyString = $prettyString;
86353 }
86354
86355
86356
86357
86358 public function getPrettyString()
86359 {
86360 if ($this->prettyString) {
86361 return $this->prettyString;
86362 }
86363
86364 return $this->__toString();
86365 }
86366
86367
86368
86369
86370
86371
86372 public static function getSupportedOperators()
86373 {
86374 return array_keys(self::$transOpStr);
86375 }
86376
86377
86378
86379
86380
86381
86382
86383
86384
86385 public function __construct($operator, $version)
86386 {
86387 if (!isset(self::$transOpStr[$operator])) {
86388 throw new \InvalidArgumentException(sprintf(
86389 'Invalid operator "%s" given, expected one of: %s',
86390 $operator,
86391 implode(', ', self::getSupportedOperators())
86392 ));
86393 }
86394
86395 $this->operator = self::$transOpStr[$operator];
86396 $this->version = $version;
86397 }
86398
86399
86400
86401
86402
86403
86404
86405
86406
86407
86408
86409 public function versionCompare($a, $b, $operator, $compareBranches = false)
86410 {
86411 if (!isset(self::$transOpStr[$operator])) {
86412 throw new \InvalidArgumentException(sprintf(
86413 'Invalid operator "%s" given, expected one of: %s',
86414 $operator,
86415 implode(', ', self::getSupportedOperators())
86416 ));
86417 }
86418
86419 $aIsBranch = 'dev-' === substr($a, 0, 4);
86420 $bIsBranch = 'dev-' === substr($b, 0, 4);
86421
86422 if ($aIsBranch && $bIsBranch) {
86423 return $operator === '==' && $a === $b;
86424 }
86425
86426
86427 if (!$compareBranches && ($aIsBranch || $bIsBranch)) {
86428 return false;
86429 }
86430
86431 return version_compare($a, $b, $operator);
86432 }
86433
86434
86435
86436
86437
86438
86439
86440 public function matchSpecific(Constraint $provider, $compareBranches = false)
86441 {
86442 $noEqualOp = str_replace('=', '', self::$transOpInt[$this->operator]);
86443 $providerNoEqualOp = str_replace('=', '', self::$transOpInt[$provider->operator]);
86444
86445 $isEqualOp = self::OP_EQ === $this->operator;
86446 $isNonEqualOp = self::OP_NE === $this->operator;
86447 $isProviderEqualOp = self::OP_EQ === $provider->operator;
86448 $isProviderNonEqualOp = self::OP_NE === $provider->operator;
86449
86450
86451
86452 if ($isNonEqualOp || $isProviderNonEqualOp) {
86453 return (!$isEqualOp && !$isProviderEqualOp)
86454 || $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
86455 }
86456
86457
86458
86459 if ($this->operator !== self::OP_EQ && $noEqualOp === $providerNoEqualOp) {
86460 return true;
86461 }
86462
86463 if ($this->versionCompare($provider->version, $this->version, self::$transOpInt[$this->operator], $compareBranches)) {
86464
86465
86466 return !($provider->version === $this->version
86467 && self::$transOpInt[$provider->operator] === $providerNoEqualOp
86468 && self::$transOpInt[$this->operator] !== $noEqualOp);
86469 }
86470
86471 return false;
86472 }
86473
86474
86475
86476
86477 public function __toString()
86478 {
86479 return self::$transOpInt[$this->operator] . ' ' . $this->version;
86480 }
86481 }
86482 <?php
86483
86484
86485
86486
86487
86488
86489
86490
86491
86492
86493 namespace Composer\Semver\Constraint;
86494
86495 interface ConstraintInterface
86496 {
86497
86498
86499
86500
86501
86502 public function matches(ConstraintInterface $provider);
86503
86504
86505
86506
86507 public function getPrettyString();
86508
86509
86510
86511
86512 public function __toString();
86513 }
86514 <?php
86515
86516
86517
86518
86519
86520
86521
86522
86523
86524
86525 namespace Composer\Semver\Constraint;
86526
86527
86528
86529
86530 class EmptyConstraint implements ConstraintInterface
86531 {
86532
86533 protected $prettyString;
86534
86535
86536
86537
86538
86539
86540 public function matches(ConstraintInterface $provider)
86541 {
86542 return true;
86543 }
86544
86545
86546
86547
86548 public function setPrettyString($prettyString)
86549 {
86550 $this->prettyString = $prettyString;
86551 }
86552
86553
86554
86555
86556 public function getPrettyString()
86557 {
86558 if ($this->prettyString) {
86559 return $this->prettyString;
86560 }
86561
86562 return (string) $this;
86563 }
86564
86565
86566
86567
86568 public function __toString()
86569 {
86570 return '[]';
86571 }
86572 }
86573 <?php
86574
86575
86576
86577
86578
86579
86580
86581
86582
86583
86584 namespace Composer\Semver\Constraint;
86585
86586
86587
86588
86589 class MultiConstraint implements ConstraintInterface
86590 {
86591
86592 protected $constraints;
86593
86594
86595 protected $prettyString;
86596
86597
86598 protected $conjunctive;
86599
86600
86601
86602
86603
86604 public function __construct(array $constraints, $conjunctive = true)
86605 {
86606 $this->constraints = $constraints;
86607 $this->conjunctive = $conjunctive;
86608 }
86609
86610
86611
86612
86613 public function getConstraints()
86614 {
86615 return $this->constraints;
86616 }
86617
86618
86619
86620
86621 public function isConjunctive()
86622 {
86623 return $this->conjunctive;
86624 }
86625
86626
86627
86628
86629 public function isDisjunctive()
86630 {
86631 return !$this->conjunctive;
86632 }
86633
86634
86635
86636
86637
86638
86639 public function matches(ConstraintInterface $provider)
86640 {
86641 if (false === $this->conjunctive) {
86642 foreach ($this->constraints as $constraint) {
86643 if ($constraint->matches($provider)) {
86644 return true;
86645 }
86646 }
86647
86648 return false;
86649 }
86650
86651 foreach ($this->constraints as $constraint) {
86652 if (!$constraint->matches($provider)) {
86653 return false;
86654 }
86655 }
86656
86657 return true;
86658 }
86659
86660
86661
86662
86663 public function setPrettyString($prettyString)
86664 {
86665 $this->prettyString = $prettyString;
86666 }
86667
86668
86669
86670
86671 public function getPrettyString()
86672 {
86673 if ($this->prettyString) {
86674 return $this->prettyString;
86675 }
86676
86677 return (string) $this;
86678 }
86679
86680
86681
86682
86683 public function __toString()
86684 {
86685 $constraints = array();
86686 foreach ($this->constraints as $constraint) {
86687 $constraints[] = (string) $constraint;
86688 }
86689
86690 return '[' . implode($this->conjunctive ? ' ' : ' || ', $constraints) . ']';
86691 }
86692 }
86693 <?php
86694
86695
86696
86697
86698
86699
86700
86701
86702
86703
86704 namespace Composer\Semver;
86705
86706 use Composer\Semver\Constraint\Constraint;
86707
86708 class Semver
86709 {
86710 const SORT_ASC = 1;
86711 const SORT_DESC = -1;
86712
86713
86714 private static $versionParser;
86715
86716
86717
86718
86719
86720
86721
86722
86723
86724 public static function satisfies($version, $constraints)
86725 {
86726 if (null === self::$versionParser) {
86727 self::$versionParser = new VersionParser();
86728 }
86729
86730 $versionParser = self::$versionParser;
86731 $provider = new Constraint('==', $versionParser->normalize($version));
86732 $parsedConstraints = $versionParser->parseConstraints($constraints);
86733
86734 return $parsedConstraints->matches($provider);
86735 }
86736
86737
86738
86739
86740
86741
86742
86743
86744
86745 public static function satisfiedBy(array $versions, $constraints)
86746 {
86747 $versions = array_filter($versions, function ($version) use ($constraints) {
86748 return Semver::satisfies($version, $constraints);
86749 });
86750
86751 return array_values($versions);
86752 }
86753
86754
86755
86756
86757
86758
86759
86760
86761 public static function sort(array $versions)
86762 {
86763 return self::usort($versions, self::SORT_ASC);
86764 }
86765
86766
86767
86768
86769
86770
86771
86772
86773 public static function rsort(array $versions)
86774 {
86775 return self::usort($versions, self::SORT_DESC);
86776 }
86777
86778
86779
86780
86781
86782
86783
86784 private static function usort(array $versions, $direction)
86785 {
86786 if (null === self::$versionParser) {
86787 self::$versionParser = new VersionParser();
86788 }
86789
86790 $versionParser = self::$versionParser;
86791 $normalized = array();
86792
86793
86794
86795 foreach ($versions as $key => $version) {
86796 $normalized[] = array($versionParser->normalize($version), $key);
86797 }
86798
86799 usort($normalized, function (array $left, array $right) use ($direction) {
86800 if ($left[0] === $right[0]) {
86801 return 0;
86802 }
86803
86804 if (Comparator::lessThan($left[0], $right[0])) {
86805 return -$direction;
86806 }
86807
86808 return $direction;
86809 });
86810
86811
86812 $sorted = array();
86813 foreach ($normalized as $item) {
86814 $sorted[] = $versions[$item[1]];
86815 }
86816
86817 return $sorted;
86818 }
86819 }
86820 <?php
86821
86822
86823
86824
86825
86826
86827
86828
86829
86830
86831 namespace Composer\Semver;
86832
86833 use Composer\Semver\Constraint\ConstraintInterface;
86834 use Composer\Semver\Constraint\EmptyConstraint;
86835 use Composer\Semver\Constraint\MultiConstraint;
86836 use Composer\Semver\Constraint\Constraint;
86837
86838
86839
86840
86841
86842
86843 class VersionParser
86844 {
86845
86846
86847
86848
86849
86850
86851
86852
86853
86854
86855
86856
86857
86858 private static $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)((?:[.-]?\d+)*+)?)?([.-]?dev)?';
86859
86860
86861 private static $stabilitiesRegex = 'stable|RC|beta|alpha|dev';
86862
86863
86864
86865
86866
86867
86868
86869
86870 public static function parseStability($version)
86871 {
86872 $version = preg_replace('{#.+$}i', '', $version);
86873
86874 if (strpos($version, 'dev-') === 0 || '-dev' === substr($version, -4)) {
86875 return 'dev';
86876 }
86877
86878 preg_match('{' . self::$modifierRegex . '(?:\+.*)?$}i', strtolower($version), $match);
86879
86880 if (!empty($match[3])) {
86881 return 'dev';
86882 }
86883
86884 if (!empty($match[1])) {
86885 if ('beta' === $match[1] || 'b' === $match[1]) {
86886 return 'beta';
86887 }
86888 if ('alpha' === $match[1] || 'a' === $match[1]) {
86889 return 'alpha';
86890 }
86891 if ('rc' === $match[1]) {
86892 return 'RC';
86893 }
86894 }
86895
86896 return 'stable';
86897 }
86898
86899
86900
86901
86902
86903
86904 public static function normalizeStability($stability)
86905 {
86906 $stability = strtolower($stability);
86907
86908 return $stability === 'rc' ? 'RC' : $stability;
86909 }
86910
86911
86912
86913
86914
86915
86916
86917
86918
86919
86920
86921 public function normalize($version, $fullVersion = null)
86922 {
86923 $version = trim($version);
86924 $origVersion = $version;
86925 if (null === $fullVersion) {
86926 $fullVersion = $version;
86927 }
86928
86929
86930 if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $version, $match)) {
86931 $version = $match[1];
86932 }
86933
86934
86935 if (preg_match('{@(?:' . self::$stabilitiesRegex . ')$}i', $version, $match)) {
86936 $version = substr($version, 0, strlen($version) - strlen($match[0]));
86937 }
86938
86939
86940 if (preg_match('{^(?:dev-)?(?:master|trunk|default)$}i', $version)) {
86941 return '9999999-dev';
86942 }
86943
86944
86945 if (stripos($version, 'dev-') === 0) {
86946 return 'dev-' . substr($version, 4);
86947 }
86948
86949
86950 if (preg_match('{^([^,\s+]++)\+[^\s]++$}', $version, $match)) {
86951 $version = $match[1];
86952 }
86953
86954
86955 if (preg_match('{^v?(\d{1,5})(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
86956 $version = $matches[1]
86957 . (!empty($matches[2]) ? $matches[2] : '.0')
86958 . (!empty($matches[3]) ? $matches[3] : '.0')
86959 . (!empty($matches[4]) ? $matches[4] : '.0');
86960 $index = 5;
86961
86962 } elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)' . self::$modifierRegex . '$}i', $version, $matches)) {
86963 $version = preg_replace('{\D}', '.', $matches[1]);
86964 $index = 2;
86965 }
86966
86967
86968 if (isset($index)) {
86969 if (!empty($matches[$index])) {
86970 if ('stable' === $matches[$index]) {
86971 return $version;
86972 }
86973 $version .= '-' . $this->expandStability($matches[$index]) . (isset($matches[$index + 1]) && '' !== $matches[$index + 1] ? ltrim($matches[$index + 1], '.-') : '');
86974 }
86975
86976 if (!empty($matches[$index + 2])) {
86977 $version .= '-dev';
86978 }
86979
86980 return $version;
86981 }
86982
86983
86984 if (preg_match('{(.*?)[.-]?dev$}i', $version, $match)) {
86985 try {
86986 $normalized = $this->normalizeBranch($match[1]);
86987
86988
86989
86990 if (strpos($normalized, 'dev-') === false) {
86991 return $normalized;
86992 }
86993 } catch (\Exception $e) {
86994 }
86995 }
86996
86997 $extraMessage = '';
86998 if (preg_match('{ +as +' . preg_quote($version) . '(?:@(?:'.self::$stabilitiesRegex.'))?$}', $fullVersion)) {
86999 $extraMessage = ' in "' . $fullVersion . '", the alias must be an exact version';
87000 } elseif (preg_match('{^' . preg_quote($version) . '(?:@(?:'.self::$stabilitiesRegex.'))? +as +}', $fullVersion)) {
87001 $extraMessage = ' in "' . $fullVersion . '", the alias source must be an exact version, if it is a branch name you should prefix it with dev-';
87002 }
87003
87004 throw new \UnexpectedValueException('Invalid version string "' . $origVersion . '"' . $extraMessage);
87005 }
87006
87007
87008
87009
87010
87011
87012
87013
87014 public function parseNumericAliasPrefix($branch)
87015 {
87016 if (preg_match('{^(?P<version>(\d++\\.)*\d++)(?:\.x)?-dev$}i', $branch, $matches)) {
87017 return $matches['version'] . '.';
87018 }
87019
87020 return false;
87021 }
87022
87023
87024
87025
87026
87027
87028
87029
87030 public function normalizeBranch($name)
87031 {
87032 $name = trim($name);
87033
87034 if (in_array($name, array('master', 'trunk', 'default'))) {
87035 return $this->normalize($name);
87036 }
87037
87038 if (preg_match('{^v?(\d++)(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?$}i', $name, $matches)) {
87039 $version = '';
87040 for ($i = 1; $i < 5; ++$i) {
87041 $version .= isset($matches[$i]) ? str_replace(array('*', 'X'), 'x', $matches[$i]) : '.x';
87042 }
87043
87044 return str_replace('x', '9999999', $version) . '-dev';
87045 }
87046
87047 return 'dev-' . $name;
87048 }
87049
87050
87051
87052
87053
87054
87055
87056
87057 public function parseConstraints($constraints)
87058 {
87059 $prettyConstraint = $constraints;
87060
87061 $orConstraints = preg_split('{\s*\|\|?\s*}', trim($constraints));
87062 $orGroups = array();
87063
87064 foreach ($orConstraints as $constraints) {
87065 $andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraints);
87066 if (count($andConstraints) > 1) {
87067 $constraintObjects = array();
87068 foreach ($andConstraints as $constraint) {
87069 foreach ($this->parseConstraint($constraint) as $parsedConstraint) {
87070 $constraintObjects[] = $parsedConstraint;
87071 }
87072 }
87073 } else {
87074 $constraintObjects = $this->parseConstraint($andConstraints[0]);
87075 }
87076
87077 if (1 === count($constraintObjects)) {
87078 $constraint = $constraintObjects[0];
87079 } else {
87080 $constraint = new MultiConstraint($constraintObjects);
87081 }
87082
87083 $orGroups[] = $constraint;
87084 }
87085
87086 if (1 === count($orGroups)) {
87087 $constraint = $orGroups[0];
87088 } elseif (2 === count($orGroups)
87089
87090
87091 && $orGroups[0] instanceof MultiConstraint
87092 && $orGroups[1] instanceof MultiConstraint
87093 && 2 === count($orGroups[0]->getConstraints())
87094 && 2 === count($orGroups[1]->getConstraints())
87095 && ($a = (string) $orGroups[0])
87096 && strpos($a, '[>=') === 0 && (false !== ($posA = strpos($a, '<', 4)))
87097 && ($b = (string) $orGroups[1])
87098 && strpos($b, '[>=') === 0 && (false !== ($posB = strpos($b, '<', 4)))
87099 && substr($a, $posA + 2, -1) === substr($b, 4, $posB - 5)
87100 ) {
87101 $constraint = new MultiConstraint(array(
87102 new Constraint('>=', substr($a, 4, $posA - 5)),
87103 new Constraint('<', substr($b, $posB + 2, -1)),
87104 ));
87105 } else {
87106 $constraint = new MultiConstraint($orGroups, false);
87107 }
87108
87109 $constraint->setPrettyString($prettyConstraint);
87110
87111 return $constraint;
87112 }
87113
87114
87115
87116
87117
87118
87119
87120
87121 private function parseConstraint($constraint)
87122 {
87123
87124 if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $constraint, $match)) {
87125 $constraint = $match[1];
87126 }
87127
87128
87129 if (preg_match('{^([^,\s]*?)@(' . self::$stabilitiesRegex . ')$}i', $constraint, $match)) {
87130 $constraint = '' !== $match[1] ? $match[1] : '*';
87131 if ($match[2] !== 'stable') {
87132 $stabilityModifier = $match[2];
87133 }
87134 }
87135
87136
87137 if (preg_match('{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i', $constraint, $match)) {
87138 $constraint = $match[1];
87139 }
87140
87141 if (preg_match('{^v?[xX*](\.[xX*])*$}i', $constraint)) {
87142 return array(new EmptyConstraint());
87143 }
87144
87145 $versionRegex = 'v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.(\d++))?(?:' . self::$modifierRegex . '|\.([xX*][.-]?dev))(?:\+[^\s]+)?';
87146
87147
87148
87149
87150
87151
87152 if (preg_match('{^~>?' . $versionRegex . '$}i', $constraint, $matches)) {
87153 if (strpos($constraint, '~>') === 0) {
87154 throw new \UnexpectedValueException(
87155 'Could not parse version constraint ' . $constraint . ': ' .
87156 'Invalid operator "~>", you probably meant to use the "~" operator'
87157 );
87158 }
87159
87160
87161 if (isset($matches[4]) && '' !== $matches[4] && null !== $matches[4]) {
87162 $position = 4;
87163 } elseif (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
87164 $position = 3;
87165 } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
87166 $position = 2;
87167 } else {
87168 $position = 1;
87169 }
87170
87171
87172 if (!empty($matches[8])) {
87173 $position++;
87174 }
87175
87176
87177 $stabilitySuffix = '';
87178 if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) {
87179 $stabilitySuffix .= '-dev';
87180 }
87181
87182 $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
87183 $lowerBound = new Constraint('>=', $lowVersion);
87184
87185
87186
87187 $highPosition = max(1, $position - 1);
87188 $highVersion = $this->manipulateVersionString($matches, $highPosition, 1) . '-dev';
87189 $upperBound = new Constraint('<', $highVersion);
87190
87191 return array(
87192 $lowerBound,
87193 $upperBound,
87194 );
87195 }
87196
87197
87198
87199
87200
87201
87202 if (preg_match('{^\^' . $versionRegex . '($)}i', $constraint, $matches)) {
87203
87204 if ('0' !== $matches[1] || '' === $matches[2] || null === $matches[2]) {
87205 $position = 1;
87206 } elseif ('0' !== $matches[2] || '' === $matches[3] || null === $matches[3]) {
87207 $position = 2;
87208 } else {
87209 $position = 3;
87210 }
87211
87212
87213 $stabilitySuffix = '';
87214 if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) {
87215 $stabilitySuffix .= '-dev';
87216 }
87217
87218 $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
87219 $lowerBound = new Constraint('>=', $lowVersion);
87220
87221
87222
87223 $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
87224 $upperBound = new Constraint('<', $highVersion);
87225
87226 return array(
87227 $lowerBound,
87228 $upperBound,
87229 );
87230 }
87231
87232
87233
87234
87235
87236 if (preg_match('{^v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.[xX*])++$}', $constraint, $matches)) {
87237 if (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
87238 $position = 3;
87239 } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
87240 $position = 2;
87241 } else {
87242 $position = 1;
87243 }
87244
87245 $lowVersion = $this->manipulateVersionString($matches, $position) . '-dev';
87246 $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
87247
87248 if ($lowVersion === '0.0.0.0-dev') {
87249 return array(new Constraint('<', $highVersion));
87250 }
87251
87252 return array(
87253 new Constraint('>=', $lowVersion),
87254 new Constraint('<', $highVersion),
87255 );
87256 }
87257
87258
87259
87260
87261
87262
87263
87264 if (preg_match('{^(?P<from>' . $versionRegex . ') +- +(?P<to>' . $versionRegex . ')($)}i', $constraint, $matches)) {
87265
87266 $lowStabilitySuffix = '';
87267 if (empty($matches[6]) && empty($matches[8]) && empty($matches[9])) {
87268 $lowStabilitySuffix = '-dev';
87269 }
87270
87271 $lowVersion = $this->normalize($matches['from']);
87272 $lowerBound = new Constraint('>=', $lowVersion . $lowStabilitySuffix);
87273
87274 $empty = function ($x) {
87275 return ($x === 0 || $x === '0') ? false : empty($x);
87276 };
87277
87278 if ((!$empty($matches[12]) && !$empty($matches[13])) || !empty($matches[15]) || !empty($matches[17]) || !empty($matches[18])) {
87279 $highVersion = $this->normalize($matches['to']);
87280 $upperBound = new Constraint('<=', $highVersion);
87281 } else {
87282 $highMatch = array('', $matches[11], $matches[12], $matches[13], $matches[14]);
87283
87284
87285 $this->normalize($matches['to']);
87286
87287 $highVersion = $this->manipulateVersionString($highMatch, $empty($matches[12]) ? 1 : 2, 1) . '-dev';
87288 $upperBound = new Constraint('<', $highVersion);
87289 }
87290
87291 return array(
87292 $lowerBound,
87293 $upperBound,
87294 );
87295 }
87296
87297
87298 if (preg_match('{^(<>|!=|>=?|<=?|==?)?\s*(.*)}', $constraint, $matches)) {
87299 try {
87300 try {
87301 $version = $this->normalize($matches[2]);
87302 } catch (\UnexpectedValueException $e) {
87303
87304
87305 if (substr($matches[2], -4) === '-dev' && preg_match('{^[0-9a-zA-Z-./]+$}', $matches[2])) {
87306 $version = $this->normalize('dev-'.substr($matches[2], 0, -4));
87307 } else {
87308 throw $e;
87309 }
87310 }
87311
87312 $op = $matches[1] ?: '=';
87313
87314 if ($op !== '==' && $op !== '=' && !empty($stabilityModifier) && self::parseStability($version) === 'stable') {
87315 $version .= '-' . $stabilityModifier;
87316 } elseif ('<' === $op || '>=' === $op) {
87317 if (!preg_match('/-' . self::$modifierRegex . '$/', strtolower($matches[2]))) {
87318 if (strpos($matches[2], 'dev-') !== 0) {
87319 $version .= '-dev';
87320 }
87321 }
87322 }
87323
87324 return array(new Constraint($matches[1] ?: '=', $version));
87325 } catch (\Exception $e) {
87326 }
87327 }
87328
87329 $message = 'Could not parse version constraint ' . $constraint;
87330 if (isset($e)) {
87331 $message .= ': ' . $e->getMessage();
87332 }
87333
87334 throw new \UnexpectedValueException($message);
87335 }
87336
87337
87338
87339
87340
87341
87342
87343
87344
87345
87346
87347
87348
87349 private function manipulateVersionString($matches, $position, $increment = 0, $pad = '0')
87350 {
87351 for ($i = 4; $i > 0; --$i) {
87352 if ($i > $position) {
87353 $matches[$i] = $pad;
87354 } elseif ($i === $position && $increment) {
87355 $matches[$i] += $increment;
87356
87357 if ($matches[$i] < 0) {
87358 $matches[$i] = $pad;
87359 --$position;
87360
87361
87362 if ($i === 1) {
87363 return null;
87364 }
87365 }
87366 }
87367 }
87368
87369 return $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.' . $matches[4];
87370 }
87371
87372
87373
87374
87375
87376
87377
87378
87379 private function expandStability($stability)
87380 {
87381 $stability = strtolower($stability);
87382
87383 switch ($stability) {
87384 case 'a':
87385 return 'alpha';
87386 case 'b':
87387 return 'beta';
87388 case 'p':
87389 case 'pl':
87390 return 'patch';
87391 case 'rc':
87392 return 'RC';
87393 default:
87394 return $stability;
87395 }
87396 }
87397 }
87398 Copyright (C) 2016 Composer
87399
87400 Permission is hereby granted, free of charge, to any person obtaining a copy of
87401 this software and associated documentation files (the "Software"), to deal in
87402 the Software without restriction, including without limitation the rights to
87403 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
87404 of the Software, and to permit persons to whom the Software is furnished to do
87405 so, subject to the following conditions:
87406
87407 The above copyright notice and this permission notice shall be included in all
87408 copies or substantial portions of the Software.
87409
87410 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
87411 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
87412 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
87413 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
87414 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
87415 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
87416 SOFTWARE.
87417 <?php
87418
87419
87420
87421
87422
87423
87424
87425
87426
87427
87428 namespace Composer\CaBundle;
87429
87430 use Psr\Log\LoggerInterface;
87431 use Symfony\Component\Process\PhpProcess;
87432
87433
87434
87435
87436
87437 class CaBundle
87438 {
87439
87440 private static $caPath;
87441
87442 private static $caFileValidity = array();
87443
87444 private static $useOpensslParse;
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
87474
87475
87476
87477
87478
87479
87480
87481
87482
87483 public static function getSystemCaRootBundlePath(LoggerInterface $logger = null)
87484 {
87485 if (self::$caPath !== null) {
87486 return self::$caPath;
87487 }
87488 $caBundlePaths = array();
87489
87490
87491
87492 $caBundlePaths[] = self::getEnvVariable('SSL_CERT_FILE');
87493
87494
87495
87496 $caBundlePaths[] = self::getEnvVariable('SSL_CERT_DIR');
87497
87498 $caBundlePaths[] = ini_get('openssl.cafile');
87499 $caBundlePaths[] = ini_get('openssl.capath');
87500
87501 $otherLocations = array(
87502 '/etc/pki/tls/certs/ca-bundle.crt', 
87503 '/etc/ssl/certs/ca-certificates.crt', 
87504 '/etc/ssl/ca-bundle.pem', 
87505 '/usr/local/share/certs/ca-root-nss.crt', 
87506 '/usr/ssl/certs/ca-bundle.crt', 
87507 '/opt/local/share/curl/curl-ca-bundle.crt', 
87508 '/usr/local/share/curl/curl-ca-bundle.crt', 
87509 '/usr/share/ssl/certs/ca-bundle.crt', 
87510 '/etc/ssl/cert.pem', 
87511 '/usr/local/etc/ssl/cert.pem', 
87512 '/usr/local/etc/openssl/cert.pem', 
87513 '/usr/local/etc/openssl@1.1/cert.pem', 
87514 );
87515
87516 foreach($otherLocations as $location) {
87517 $otherLocations[] = dirname($location);
87518 }
87519
87520 $caBundlePaths = array_merge($caBundlePaths, $otherLocations);
87521
87522 foreach ($caBundlePaths as $caBundle) {
87523 if ($caBundle && self::caFileUsable($caBundle, $logger)) {
87524 return self::$caPath = $caBundle;
87525 }
87526
87527 if ($caBundle && self::caDirUsable($caBundle)) {
87528 return self::$caPath = $caBundle;
87529 }
87530 }
87531
87532 return self::$caPath = static::getBundledCaBundlePath(); 
87533 }
87534
87535
87536
87537
87538
87539
87540
87541
87542 public static function getBundledCaBundlePath()
87543 {
87544 $caBundleFile = __DIR__.'/../res/cacert.pem';
87545
87546
87547
87548 if (0 === strpos($caBundleFile, 'phar://')) {
87549 $tempCaBundleFile = tempnam(sys_get_temp_dir(), 'openssl-ca-bundle-');
87550 if (false === $tempCaBundleFile) {
87551 throw new \RuntimeException('Could not create a temporary file to store the bundled CA file');
87552 }
87553
87554 file_put_contents(
87555 $tempCaBundleFile,
87556 file_get_contents($caBundleFile)
87557 );
87558
87559 register_shutdown_function(function() use ($tempCaBundleFile) {
87560 @unlink($tempCaBundleFile);
87561 });
87562
87563 $caBundleFile = $tempCaBundleFile;
87564 }
87565
87566 return $caBundleFile;
87567 }
87568
87569
87570
87571
87572
87573
87574
87575
87576
87577 public static function validateCaFile($filename, LoggerInterface $logger = null)
87578 {
87579 static $warned = false;
87580
87581 if (isset(self::$caFileValidity[$filename])) {
87582 return self::$caFileValidity[$filename];
87583 }
87584
87585 $contents = file_get_contents($filename);
87586
87587
87588
87589 if (!static::isOpensslParseSafe()) {
87590 if (!$warned && $logger) {
87591 $logger->warning(sprintf(
87592 'Your version of PHP, %s, is affected by CVE-2013-6420 and cannot safely perform certificate validation, we strongly suggest you upgrade.',
87593 PHP_VERSION
87594 ));
87595 $warned = true;
87596 }
87597
87598 $isValid = !empty($contents);
87599 } elseif (is_string($contents) && strlen($contents) > 0) {
87600 $contents = preg_replace("/^(\\-+(?:BEGIN|END))\\s+TRUSTED\\s+(CERTIFICATE\\-+)\$/m", '$1 $2', $contents);
87601 if (null === $contents) {
87602
87603 $isValid = false;
87604 } else {
87605 $isValid = (bool) openssl_x509_parse($contents);
87606 }
87607 } else {
87608 $isValid = false;
87609 }
87610
87611 if ($logger) {
87612 $logger->debug('Checked CA file '.realpath($filename).': '.($isValid ? 'valid' : 'invalid'));
87613 }
87614
87615 return self::$caFileValidity[$filename] = $isValid;
87616 }
87617
87618
87619
87620
87621
87622
87623
87624
87625
87626 public static function isOpensslParseSafe()
87627 {
87628 if (null !== self::$useOpensslParse) {
87629 return self::$useOpensslParse;
87630 }
87631
87632 if (PHP_VERSION_ID >= 50600) {
87633 return self::$useOpensslParse = true;
87634 }
87635
87636
87637
87638
87639
87640 if (
87641 (PHP_VERSION_ID < 50400 && PHP_VERSION_ID >= 50328)
87642 || (PHP_VERSION_ID < 50500 && PHP_VERSION_ID >= 50423)
87643 || PHP_VERSION_ID >= 50507
87644 ) {
87645
87646 return self::$useOpensslParse = true;
87647 }
87648
87649 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
87650
87651 return self::$useOpensslParse = false;
87652 }
87653
87654 $compareDistroVersionPrefix = function ($prefix, $fixedVersion) {
87655 $regex = '{^'.preg_quote($prefix).'([0-9]+)$}';
87656
87657 if (preg_match($regex, PHP_VERSION, $m)) {
87658 return ((int) $m[1]) >= $fixedVersion;
87659 }
87660
87661 return false;
87662 };
87663
87664
87665 if (
87666 $compareDistroVersionPrefix('5.3.3-7+squeeze', 18) 
87667 || $compareDistroVersionPrefix('5.4.4-14+deb7u', 7) 
87668 || $compareDistroVersionPrefix('5.3.10-1ubuntu3.', 9) 
87669 ) {
87670 return self::$useOpensslParse = true;
87671 }
87672
87673
87674 if (!class_exists('Symfony\Component\Process\PhpProcess')) {
87675 return self::$useOpensslParse = false;
87676 }
87677
87678
87679
87680
87681
87682
87683
87684
87685
87686
87687 $cert = 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVwRENDQTR5Z0F3SUJBZ0lKQUp6dThyNnU2ZUJjTUEwR0NTcUdTSWIzRFFFQkJRVUFNSUhETVFzd0NRWUQKVlFRR0V3SkVSVEVjTUJvR0ExVUVDQXdUVG05eVpISm9aV2x1TFZkbGMzUm1ZV3hsYmpFUU1BNEdBMVVFQnd3SApTOE9Ed3Jac2JqRVVNQklHQTFVRUNnd0xVMlZyZEdsdmJrVnBibk14SHpBZEJnTlZCQXNNRmsxaGJHbGphVzkxCmN5QkRaWEowSUZObFkzUnBiMjR4SVRBZkJnTlZCQU1NR0cxaGJHbGphVzkxY3k1elpXdDBhVzl1WldsdWN5NWsKWlRFcU1DZ0dDU3FHU0liM0RRRUpBUlliYzNSbFptRnVMbVZ6YzJWeVFITmxhM1JwYjI1bGFXNXpMbVJsTUhVWQpaREU1TnpBd01UQXhNREF3TURBd1dnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBCkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEKQUFBQUFBQVhEVEUwTVRFeU9ERXhNemt6TlZvd2djTXhDekFKQmdOVkJBWVRBa1JGTVJ3d0dnWURWUVFJREJOTwpiM0prY21obGFXNHRWMlZ6ZEdaaGJHVnVNUkF3RGdZRFZRUUhEQWRMdzRQQ3RteHVNUlF3RWdZRFZRUUtEQXRUClpXdDBhVzl1UldsdWN6RWZNQjBHQTFVRUN3d1dUV0ZzYVdOcGIzVnpJRU5sY25RZ1UyVmpkR2x2YmpFaE1COEcKQTFVRUF3d1liV0ZzYVdOcGIzVnpMbk5sYTNScGIyNWxhVzV6TG1SbE1Tb3dLQVlKS29aSWh2Y05BUWtCRmh0egpkR1ZtWVc0dVpYTnpaWEpBYzJWcmRHbHZibVZwYm5NdVpHVXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCCkR3QXdnZ0VLQW9JQkFRRERBZjNobDdKWTBYY0ZuaXlFSnBTU0RxbjBPcUJyNlFQNjV1c0pQUnQvOFBhRG9xQnUKd0VZVC9OYSs2ZnNnUGpDMHVLOURaZ1dnMnRIV1dvYW5TYmxBTW96NVBINlorUzRTSFJaN2UyZERJalBqZGhqaAowbUxnMlVNTzV5cDBWNzk3R2dzOWxOdDZKUmZIODFNTjJvYlhXczROdHp0TE11RDZlZ3FwcjhkRGJyMzRhT3M4CnBrZHVpNVVhd1Raa3N5NXBMUEhxNWNNaEZHbTA2djY1Q0xvMFYyUGQ5K0tBb2tQclBjTjVLTEtlYno3bUxwazYKU01lRVhPS1A0aWRFcXh5UTdPN2ZCdUhNZWRzUWh1K3ByWTNzaTNCVXlLZlF0UDVDWm5YMmJwMHdLSHhYMTJEWAoxbmZGSXQ5RGJHdkhUY3lPdU4rblpMUEJtM3ZXeG50eUlJdlZBZ01CQUFHalFqQkFNQWtHQTFVZEV3UUNNQUF3CkVRWUpZSVpJQVliNFFnRUJCQVFEQWdlQU1Bc0dBMVVkRHdRRUF3SUZvREFUQmdOVkhTVUVEREFLQmdnckJnRUYKQlFjREFqQU5CZ2txaGtpRzl3MEJBUVVGQUFPQ0FRRUFHMGZaWVlDVGJkajFYWWMrMVNub2FQUit2SThDOENhRAo4KzBVWWhkbnlVNGdnYTBCQWNEclk5ZTk0ZUVBdTZacXljRjZGakxxWFhkQWJvcHBXb2NyNlQ2R0QxeDMzQ2tsClZBcnpHL0t4UW9oR0QySmVxa2hJTWxEb214SE83a2EzOStPYThpMnZXTFZ5alU4QVp2V01BcnVIYTRFRU55RzcKbFcyQWFnYUZLRkNyOVRuWFRmcmR4R1ZFYnY3S1ZRNmJkaGc1cDVTanBXSDErTXEwM3VSM1pYUEJZZHlWODMxOQpvMGxWajFLRkkyRENML2xpV2lzSlJvb2YrMWNSMzVDdGQwd1lCY3BCNlRac2xNY09QbDc2ZHdLd0pnZUpvMlFnClpzZm1jMnZDMS9xT2xOdU5xLzBUenprVkd2OEVUVDNDZ2FVK1VYZTRYT1Z2a2NjZWJKbjJkZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K';
87688 $script = <<<'EOT'
87689
87690 error_reporting(-1);
87691 $info = openssl_x509_parse(base64_decode('%s'));
87692 var_dump(PHP_VERSION, $info['issuer']['emailAddress'], $info['validFrom_time_t']);
87693
87694 EOT;
87695 $script = '<'."?php\n".sprintf($script, $cert);
87696
87697 try {
87698 $process = new PhpProcess($script);
87699 $process->mustRun();
87700 } catch (\Exception $e) {
87701
87702
87703 return self::$useOpensslParse = false;
87704 }
87705
87706 $output = preg_split('{\r?\n}', trim($process->getOutput()));
87707 $errorOutput = trim($process->getErrorOutput());
87708
87709 if (
87710 is_array($output)
87711 && count($output) === 3
87712 && $output[0] === sprintf('string(%d) "%s"', strlen(PHP_VERSION), PHP_VERSION)
87713 && $output[1] === 'string(27) "stefan.esser@sektioneins.de"'
87714 && $output[2] === 'int(-1)'
87715 && preg_match('{openssl_x509_parse\(\): illegal (?:ASN1 data type for|length in) timestamp in - on line \d+}', $errorOutput)
87716 ) {
87717
87718 return self::$useOpensslParse = true;
87719 }
87720
87721 return self::$useOpensslParse = false;
87722 }
87723
87724
87725
87726
87727
87728 public static function reset()
87729 {
87730 self::$caFileValidity = array();
87731 self::$caPath = null;
87732 self::$useOpensslParse = null;
87733 }
87734
87735
87736
87737
87738
87739 private static function getEnvVariable($name)
87740 {
87741 if (isset($_SERVER[$name])) {
87742 return (string) $_SERVER[$name];
87743 }
87744
87745 if (PHP_SAPI === 'cli' && ($value = getenv($name)) !== false && $value !== null) {
87746 return (string) $value;
87747 }
87748
87749 return false;
87750 }
87751
87752
87753
87754
87755
87756 private static function caFileUsable($certFile, LoggerInterface $logger = null)
87757 {
87758 return $certFile && @is_file($certFile) && @is_readable($certFile) && static::validateCaFile($certFile, $logger);
87759 }
87760
87761
87762
87763
87764
87765 private static function caDirUsable($certDir)
87766 {
87767 return $certDir && @is_dir($certDir) && @is_readable($certDir) && glob($certDir . '/*');
87768 }
87769 }
87770 MIT License
87771
87772 Copyright (c) 2017 Composer
87773
87774 Permission is hereby granted, free of charge, to any person obtaining a copy
87775 of this software and associated documentation files (the "Software"), to deal
87776 in the Software without restriction, including without limitation the rights
87777 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
87778 copies of the Software, and to permit persons to whom the Software is
87779 furnished to do so, subject to the following conditions:
87780
87781 The above copyright notice and this permission notice shall be included in all
87782 copies or substantial portions of the Software.
87783
87784 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
87785 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
87786 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
87787 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
87788 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
87789 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
87790 SOFTWARE.
87791 <?php
87792
87793
87794
87795
87796
87797
87798
87799
87800
87801
87802 namespace Composer\XdebugHandler;
87803
87804
87805
87806
87807 class PhpConfig
87808 {
87809
87810
87811
87812
87813
87814 public function useOriginal()
87815 {
87816 $this->getDataAndReset();
87817 return array();
87818 }
87819
87820
87821
87822
87823
87824
87825 public function useStandard()
87826 {
87827 if ($data = $this->getDataAndReset()) {
87828 return array('-n', '-c', $data['tmpIni']);
87829 }
87830
87831 return array();
87832 }
87833
87834
87835
87836
87837
87838
87839 public function usePersistent()
87840 {
87841 if ($data = $this->getDataAndReset()) {
87842 Process::setEnv('PHPRC', $data['tmpIni']);
87843 Process::setEnv('PHP_INI_SCAN_DIR', '');
87844 }
87845
87846 return array();
87847 }
87848
87849
87850
87851
87852
87853
87854 private function getDataAndReset()
87855 {
87856 if ($data = XdebugHandler::getRestartSettings()) {
87857 Process::setEnv('PHPRC', $data['phprc']);
87858 Process::setEnv('PHP_INI_SCAN_DIR', $data['scanDir']);
87859 }
87860
87861 return $data;
87862 }
87863 }
87864 <?php
87865
87866
87867
87868
87869
87870
87871
87872
87873
87874
87875 namespace Composer\XdebugHandler;
87876
87877
87878
87879
87880
87881
87882
87883
87884 class Process
87885 {
87886
87887
87888
87889
87890
87891
87892
87893
87894
87895
87896 public static function addColorOption(array $args, $colorOption)
87897 {
87898 if (!$colorOption
87899 || in_array($colorOption, $args)
87900 || !preg_match('/^--([a-z]+$)|(^--[a-z]+=)/', $colorOption, $matches)) {
87901 return $args;
87902 }
87903
87904 if (isset($matches[2])) {
87905
87906 if (false !== ($index = array_search($matches[2].'auto', $args))) {
87907 $args[$index] = $colorOption;
87908 return $args;
87909 } elseif (preg_grep('/^'.$matches[2].'/', $args)) {
87910 return $args;
87911 }
87912 } elseif (in_array('--no-'.$matches[1], $args)) {
87913 return $args;
87914 }
87915
87916
87917 if (false !== getenv('NO_COLOR')) {
87918 return $args;
87919 }
87920
87921 if (false !== ($index = array_search('--', $args))) {
87922
87923 array_splice($args, $index, 0, $colorOption);
87924 } else {
87925 $args[] = $colorOption;
87926 }
87927
87928 return $args;
87929 }
87930
87931
87932
87933
87934
87935
87936
87937
87938
87939
87940
87941
87942
87943 public static function escape($arg, $meta = true, $module = false)
87944 {
87945 if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
87946 return "'".str_replace("'", "'\\''", $arg)."'";
87947 }
87948
87949 $quote = strpbrk($arg, " \t") !== false || $arg === '';
87950
87951 $arg = preg_replace('/(\\\\*)"/', '$1$1\\"', $arg, -1, $dquotes);
87952
87953 if ($meta) {
87954 $meta = $dquotes || preg_match('/%[^%]+%/', $arg);
87955
87956 if (!$meta) {
87957 $quote = $quote || strpbrk($arg, '^&|<>()') !== false;
87958 } elseif ($module && !$dquotes && $quote) {
87959 $meta = false;
87960 }
87961 }
87962
87963 if ($quote) {
87964 $arg = '"'.preg_replace('/(\\\\*)$/', '$1$1', $arg).'"';
87965 }
87966
87967 if ($meta) {
87968 $arg = preg_replace('/(["^&|<>()%])/', '^$1', $arg);
87969 }
87970
87971 return $arg;
87972 }
87973
87974
87975
87976
87977
87978
87979
87980
87981
87982
87983
87984 public static function supportsColor($output)
87985 {
87986 if ('Hyper' === getenv('TERM_PROGRAM')) {
87987 return true;
87988 }
87989
87990 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
87991 return (function_exists('sapi_windows_vt100_support')
87992 && sapi_windows_vt100_support($output))
87993 || false !== getenv('ANSICON')
87994 || 'ON' === getenv('ConEmuANSI')
87995 || 'xterm' === getenv('TERM');
87996 }
87997
87998 if (function_exists('stream_isatty')) {
87999 return stream_isatty($output);
88000 }
88001
88002 if (function_exists('posix_isatty')) {
88003 return posix_isatty($output);
88004 }
88005
88006 $stat = fstat($output);
88007
88008 return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
88009 }
88010
88011
88012
88013
88014
88015
88016
88017
88018
88019 public static function setEnv($name, $value = false)
88020 {
88021 $unset = false === $value;
88022
88023 if (!putenv($unset ? $name : $name.'='.$value)) {
88024 return false;
88025 }
88026
88027 if ($unset) {
88028 unset($_SERVER[$name]);
88029 } else {
88030 $_SERVER[$name] = $value;
88031 }
88032
88033
88034 if (false !== stripos((string) ini_get('variables_order'), 'E')) {
88035 if ($unset) {
88036 unset($_ENV[$name]);
88037 } else {
88038 $_ENV[$name] = $value;
88039 }
88040 }
88041
88042 return true;
88043 }
88044 }
88045 <?php
88046
88047
88048
88049
88050
88051
88052
88053
88054
88055
88056 namespace Composer\XdebugHandler;
88057
88058 use Psr\Log\LoggerInterface;
88059 use Psr\Log\LogLevel;
88060
88061
88062
88063
88064
88065 class Status
88066 {
88067 const ENV_RESTART = 'XDEBUG_HANDLER_RESTART';
88068 const CHECK = 'Check';
88069 const ERROR = 'Error';
88070 const INFO = 'Info';
88071 const NORESTART = 'NoRestart';
88072 const RESTART = 'Restart';
88073 const RESTARTING = 'Restarting';
88074 const RESTARTED = 'Restarted';
88075
88076 private $debug;
88077 private $envAllowXdebug;
88078 private $loaded;
88079 private $logger;
88080 private $time;
88081
88082
88083
88084
88085
88086
88087
88088 public function __construct($envAllowXdebug, $debug)
88089 {
88090 $start = getenv(self::ENV_RESTART);
88091 Process::setEnv(self::ENV_RESTART);
88092 $this->time = $start ? round((microtime(true) - $start) * 1000) : 0;
88093
88094 $this->envAllowXdebug = $envAllowXdebug;
88095 $this->debug = $debug && defined('STDERR');
88096 }
88097
88098
88099
88100
88101 public function setLogger(LoggerInterface $logger)
88102 {
88103 $this->logger = $logger;
88104 }
88105
88106
88107
88108
88109
88110
88111
88112 public function report($op, $data)
88113 {
88114 if ($this->logger || $this->debug) {
88115 call_user_func(array($this, 'report'.$op), $data);
88116 }
88117 }
88118
88119
88120
88121
88122
88123
88124
88125 private function output($text, $level = null)
88126 {
88127 if ($this->logger) {
88128 $this->logger->log($level ?: LogLevel::DEBUG, $text);
88129 }
88130
88131 if ($this->debug) {
88132 fwrite(STDERR, sprintf('xdebug-handler[%d] %s', getmypid(), $text.PHP_EOL));
88133 }
88134 }
88135
88136 private function reportCheck($loaded)
88137 {
88138 $this->loaded = $loaded;
88139 $this->output('Checking '.$this->envAllowXdebug);
88140 }
88141
88142 private function reportError($error)
88143 {
88144 $this->output(sprintf('No restart (%s)', $error), LogLevel::WARNING);
88145 }
88146
88147 private function reportInfo($info)
88148 {
88149 $this->output($info);
88150 }
88151
88152 private function reportNoRestart()
88153 {
88154 $this->output($this->getLoadedMessage());
88155
88156 if ($this->loaded) {
88157 $text = sprintf('No restart (%s)', $this->getEnvAllow());
88158 if (!getenv($this->envAllowXdebug)) {
88159 $text .= ' Allowed by application';
88160 }
88161 $this->output($text);
88162 }
88163 }
88164
88165 private function reportRestart()
88166 {
88167 $this->output($this->getLoadedMessage());
88168 Process::setEnv(self::ENV_RESTART, (string) microtime(true));
88169 }
88170
88171 private function reportRestarted()
88172 {
88173 $loaded = $this->getLoadedMessage();
88174 $text = sprintf('Restarted (%d ms). %s', $this->time, $loaded);
88175 $level = $this->loaded ? LogLevel::WARNING : null;
88176 $this->output($text, $level);
88177 }
88178
88179 private function reportRestarting($command)
88180 {
88181 $text = sprintf('Process restarting (%s)', $this->getEnvAllow());
88182 $this->output($text);
88183 $text = 'Running '.$command;
88184 $this->output($text);
88185 }
88186
88187
88188
88189
88190
88191
88192 private function getEnvAllow()
88193 {
88194 return $this->envAllowXdebug.'='.getenv($this->envAllowXdebug);
88195 }
88196
88197
88198
88199
88200
88201
88202 private function getLoadedMessage()
88203 {
88204 $loaded = $this->loaded ? sprintf('loaded (%s)', $this->loaded) : 'not loaded';
88205 return 'The Xdebug extension is '.$loaded;
88206 }
88207 }
88208 <?php
88209
88210
88211
88212
88213
88214
88215
88216
88217
88218
88219 namespace Composer\XdebugHandler;
88220
88221 use Psr\Log\LoggerInterface;
88222
88223
88224
88225
88226 class XdebugHandler
88227 {
88228 const SUFFIX_ALLOW = '_ALLOW_XDEBUG';
88229 const SUFFIX_INIS = '_ORIGINAL_INIS';
88230 const RESTART_ID = 'internal';
88231 const RESTART_SETTINGS = 'XDEBUG_HANDLER_SETTINGS';
88232 const DEBUG = 'XDEBUG_HANDLER_DEBUG';
88233
88234
88235 protected $tmpIni;
88236
88237 private static $inRestart;
88238 private static $name;
88239 private static $skipped;
88240
88241 private $cli;
88242 private $colorOption;
88243 private $debug;
88244 private $envAllowXdebug;
88245 private $envOriginalInis;
88246 private $loaded;
88247 private $persistent;
88248 private $script;
88249
88250 private $statusWriter;
88251
88252
88253
88254
88255
88256
88257
88258
88259
88260
88261
88262
88263 public function __construct($envPrefix, $colorOption = '')
88264 {
88265 if (!is_string($envPrefix) || empty($envPrefix) || !is_string($colorOption)) {
88266 throw new \RuntimeException('Invalid constructor parameter');
88267 }
88268
88269 self::$name = strtoupper($envPrefix);
88270 $this->envAllowXdebug = self::$name.self::SUFFIX_ALLOW;
88271 $this->envOriginalInis = self::$name.self::SUFFIX_INIS;
88272
88273 $this->colorOption = $colorOption;
88274
88275 if (extension_loaded('xdebug')) {
88276 $ext = new \ReflectionExtension('xdebug');
88277 $this->loaded = $ext->getVersion() ?: 'unknown';
88278 }
88279
88280 if ($this->cli = PHP_SAPI === 'cli') {
88281 $this->debug = getenv(self::DEBUG);
88282 }
88283
88284 $this->statusWriter = new Status($this->envAllowXdebug, (bool) $this->debug);
88285 }
88286
88287
88288
88289
88290
88291
88292
88293
88294 public function setLogger(LoggerInterface $logger)
88295 {
88296 $this->statusWriter->setLogger($logger);
88297 return $this;
88298 }
88299
88300
88301
88302
88303
88304
88305
88306
88307 public function setMainScript($script)
88308 {
88309 $this->script = $script;
88310 return $this;
88311 }
88312
88313
88314
88315
88316
88317
88318 public function setPersistent()
88319 {
88320 $this->persistent = true;
88321 return $this;
88322 }
88323
88324
88325
88326
88327
88328
88329
88330
88331 public function check()
88332 {
88333 $this->notify(Status::CHECK, $this->loaded);
88334 $envArgs = explode('|', (string) getenv($this->envAllowXdebug));
88335
88336 if (empty($envArgs[0]) && $this->requiresRestart((bool) $this->loaded)) {
88337
88338 $this->notify(Status::RESTART);
88339
88340 if ($this->prepareRestart()) {
88341 $command = $this->getCommand();
88342 $this->restart($command);
88343 }
88344 return;
88345 }
88346
88347 if (self::RESTART_ID === $envArgs[0] && count($envArgs) === 5) {
88348
88349 $this->notify(Status::RESTARTED);
88350
88351 Process::setEnv($this->envAllowXdebug);
88352 self::$inRestart = true;
88353
88354 if (!$this->loaded) {
88355
88356 self::$skipped = $envArgs[1];
88357 }
88358
88359 $this->tryEnableSignals();
88360
88361
88362 $this->setEnvRestartSettings($envArgs);
88363 return;
88364 }
88365
88366 $this->notify(Status::NORESTART);
88367
88368 if ($settings = self::getRestartSettings()) {
88369
88370 $this->syncSettings($settings);
88371 }
88372 }
88373
88374
88375
88376
88377
88378
88379
88380
88381
88382 public static function getAllIniFiles()
88383 {
88384 if (!empty(self::$name)) {
88385 $env = getenv(self::$name.self::SUFFIX_INIS);
88386
88387 if (false !== $env) {
88388 return explode(PATH_SEPARATOR, $env);
88389 }
88390 }
88391
88392 $paths = array((string) php_ini_loaded_file());
88393
88394 if ($scanned = php_ini_scanned_files()) {
88395 $paths = array_merge($paths, array_map('trim', explode(',', $scanned)));
88396 }
88397
88398 return $paths;
88399 }
88400
88401
88402
88403
88404
88405
88406
88407
88408
88409 public static function getRestartSettings()
88410 {
88411 $envArgs = explode('|', (string) getenv(self::RESTART_SETTINGS));
88412
88413 if (count($envArgs) !== 6
88414 || (!self::$inRestart && php_ini_loaded_file() !== $envArgs[0])) {
88415 return null;
88416 }
88417
88418 return array(
88419 'tmpIni' => $envArgs[0],
88420 'scannedInis' => (bool) $envArgs[1],
88421 'scanDir' => '*' === $envArgs[2] ? false : $envArgs[2],
88422 'phprc' => '*' === $envArgs[3] ? false : $envArgs[3],
88423 'inis' => explode(PATH_SEPARATOR, $envArgs[4]),
88424 'skipped' => $envArgs[5],
88425 );
88426 }
88427
88428
88429
88430
88431
88432
88433 public static function getSkippedVersion()
88434 {
88435 return (string) self::$skipped;
88436 }
88437
88438
88439
88440
88441
88442
88443
88444
88445 protected function requiresRestart($isLoaded)
88446 {
88447 return $isLoaded;
88448 }
88449
88450
88451
88452
88453
88454
88455 protected function restart($command)
88456 {
88457 $this->doRestart($command);
88458 }
88459
88460
88461
88462
88463
88464
88465 private function doRestart($command)
88466 {
88467 $this->tryEnableSignals();
88468 $this->notify(Status::RESTARTING, $command);
88469
88470
88471 if (function_exists('proc_open')) {
88472 if (defined('PHP_WINDOWS_VERSION_BUILD') && PHP_VERSION_ID < 80000) {
88473 $command = '"'.$command.'"';
88474 }
88475 $process = proc_open($command, array(), $pipes);
88476 if (is_resource($process)) {
88477 $exitCode = proc_close($process);
88478 }
88479 } else {
88480 passthru($command, $exitCode);
88481 }
88482
88483 if (!isset($exitCode)) {
88484
88485 $this->notify(Status::ERROR, 'Unable to restart process');
88486 $exitCode = -1;
88487 } else {
88488 $this->notify(Status::INFO, 'Restarted process exited '.$exitCode);
88489 }
88490
88491 if ($this->debug === '2') {
88492 $this->notify(Status::INFO, 'Temp ini saved: '.$this->tmpIni);
88493 } else {
88494 @unlink($this->tmpIni);
88495 }
88496
88497 exit($exitCode);
88498 }
88499
88500
88501
88502
88503
88504
88505
88506
88507
88508
88509
88510 private function prepareRestart()
88511 {
88512 $error = '';
88513 $iniFiles = self::getAllIniFiles();
88514 $scannedInis = count($iniFiles) > 1;
88515 $tmpDir = sys_get_temp_dir();
88516
88517 if (!$this->cli) {
88518 $error = 'Unsupported SAPI: '.PHP_SAPI;
88519 } elseif (!defined('PHP_BINARY')) {
88520 $error = 'PHP version is too old: '.PHP_VERSION;
88521 } elseif (!$this->checkConfiguration($info)) {
88522 $error = $info;
88523 } elseif (!$this->checkScanDirConfig()) {
88524 $error = 'PHP version does not report scanned inis: '.PHP_VERSION;
88525 } elseif (!$this->checkMainScript()) {
88526 $error = 'Unable to access main script: '.$this->script;
88527 } elseif (!$this->writeTmpIni($iniFiles, $tmpDir, $error)) {
88528 $error = $error ?: 'Unable to create temp ini file at: '.$tmpDir;
88529 } elseif (!$this->setEnvironment($scannedInis, $iniFiles)) {
88530 $error = 'Unable to set environment variables';
88531 }
88532
88533 if ($error) {
88534 $this->notify(Status::ERROR, $error);
88535 }
88536
88537 return empty($error);
88538 }
88539
88540
88541
88542
88543
88544
88545
88546
88547
88548
88549 private function writeTmpIni(array $iniFiles, $tmpDir, &$error)
88550 {
88551 if (!$this->tmpIni = @tempnam($tmpDir, '')) {
88552 return false;
88553 }
88554
88555
88556 if (empty($iniFiles[0])) {
88557 array_shift($iniFiles);
88558 }
88559
88560 $content = '';
88561 $regex = '/^\s*(zend_extension\s*=.*xdebug.*)$/mi';
88562
88563 foreach ($iniFiles as $file) {
88564
88565 if (($data = @file_get_contents($file)) === false) {
88566 $error = 'Unable to read ini: '.$file;
88567 return false;
88568 }
88569 $content .= preg_replace($regex, ';$1', $data).PHP_EOL;
88570 }
88571
88572
88573 if ($config = parse_ini_string($content)) {
88574 $loaded = ini_get_all(null, false);
88575 $content .= $this->mergeLoadedConfig($loaded, $config);
88576 }
88577
88578
88579 $content .= 'opcache.enable_cli=0'.PHP_EOL;
88580
88581 return @file_put_contents($this->tmpIni, $content);
88582 }
88583
88584
88585
88586
88587
88588
88589 private function getCommand()
88590 {
88591 $php = array(PHP_BINARY);
88592 $args = array_slice($_SERVER['argv'], 1);
88593
88594 if (!$this->persistent) {
88595
88596 array_push($php, '-n', '-c', $this->tmpIni);
88597 }
88598
88599 if (defined('STDOUT') && Process::supportsColor(STDOUT)) {
88600 $args = Process::addColorOption($args, $this->colorOption);
88601 }
88602
88603 $args = array_merge($php, array($this->script), $args);
88604
88605 $cmd = Process::escape(array_shift($args), true, true);
88606 foreach ($args as $arg) {
88607 $cmd .= ' '.Process::escape($arg);
88608 }
88609
88610 return $cmd;
88611 }
88612
88613
88614
88615
88616
88617
88618
88619
88620
88621
88622
88623 private function setEnvironment($scannedInis, array $iniFiles)
88624 {
88625 $scanDir = getenv('PHP_INI_SCAN_DIR');
88626 $phprc = getenv('PHPRC');
88627
88628
88629 if (!putenv($this->envOriginalInis.'='.implode(PATH_SEPARATOR, $iniFiles))) {
88630 return false;
88631 }
88632
88633 if ($this->persistent) {
88634
88635 if (!putenv('PHP_INI_SCAN_DIR=') || !putenv('PHPRC='.$this->tmpIni)) {
88636 return false;
88637 }
88638 }
88639
88640
88641 $envArgs = array(
88642 self::RESTART_ID,
88643 $this->loaded,
88644 (int) $scannedInis,
88645 false === $scanDir ? '*' : $scanDir,
88646 false === $phprc ? '*' : $phprc,
88647 );
88648
88649 return putenv($this->envAllowXdebug.'='.implode('|', $envArgs));
88650 }
88651
88652
88653
88654
88655
88656
88657
88658 private function notify($op, $data = null)
88659 {
88660 $this->statusWriter->report($op, $data);
88661 }
88662
88663
88664
88665
88666
88667
88668
88669
88670
88671 private function mergeLoadedConfig(array $loadedConfig, array $iniConfig)
88672 {
88673 $content = '';
88674
88675 foreach ($loadedConfig as $name => $value) {
88676
88677 if (!is_string($value)
88678 || strpos($name, 'xdebug') === 0
88679 || $name === 'apc.mmap_file_mask') {
88680 continue;
88681 }
88682
88683 if (!isset($iniConfig[$name]) || $iniConfig[$name] !== $value) {
88684
88685 $content .= $name.'="'.addcslashes($value, '\\"').'"'.PHP_EOL;
88686 }
88687 }
88688
88689 return $content;
88690 }
88691
88692
88693
88694
88695
88696
88697 private function checkMainScript()
88698 {
88699 if (null !== $this->script) {
88700
88701 return file_exists($this->script) || '--' === $this->script;
88702 }
88703
88704 if (file_exists($this->script = $_SERVER['argv'][0])) {
88705 return true;
88706 }
88707
88708
88709 $options = PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : false;
88710 $trace = debug_backtrace($options);
88711
88712 if (($main = end($trace)) && isset($main['file'])) {
88713 return file_exists($this->script = $main['file']);
88714 }
88715
88716 return false;
88717 }
88718
88719
88720
88721
88722
88723
88724 private function setEnvRestartSettings($envArgs)
88725 {
88726 $settings = array(
88727 php_ini_loaded_file(),
88728 $envArgs[2],
88729 $envArgs[3],
88730 $envArgs[4],
88731 getenv($this->envOriginalInis),
88732 self::$skipped,
88733 );
88734
88735 Process::setEnv(self::RESTART_SETTINGS, implode('|', $settings));
88736 }
88737
88738
88739
88740
88741
88742
88743 private function syncSettings(array $settings)
88744 {
88745 if (false === getenv($this->envOriginalInis)) {
88746
88747 Process::setEnv($this->envOriginalInis, implode(PATH_SEPARATOR, $settings['inis']));
88748 }
88749
88750 self::$skipped = $settings['skipped'];
88751 $this->notify(Status::INFO, 'Process called with existing restart settings');
88752 }
88753
88754
88755
88756
88757
88758
88759
88760
88761
88762 private function checkScanDirConfig()
88763 {
88764 return !(getenv('PHP_INI_SCAN_DIR')
88765 && !PHP_CONFIG_FILE_SCAN_DIR
88766 && (PHP_VERSION_ID < 70113
88767 || PHP_VERSION_ID === 70200));
88768 }
88769
88770
88771
88772
88773
88774
88775
88776 private function checkConfiguration(&$info)
88777 {
88778 if (!function_exists('proc_open') && !function_exists('passthru')) {
88779 $info = 'execution functions have been disabled (proc_open or passthru required)';
88780 return false;
88781 }
88782
88783 if (extension_loaded('uopz') && !ini_get('uopz.disable')) {
88784
88785 if (function_exists('uopz_allow_exit')) {
88786 @uopz_allow_exit(true);
88787 } else {
88788 $info = 'uopz extension is not compatible';
88789 return false;
88790 }
88791 }
88792
88793 return true;
88794 }
88795
88796
88797
88798
88799
88800
88801 private function tryEnableSignals()
88802 {
88803 if (function_exists('pcntl_async_signals') && function_exists('pcntl_signal')) {
88804 pcntl_async_signals(true);
88805 $message = 'Async signals enabled';
88806
88807 if (!self::$inRestart) {
88808
88809 pcntl_signal(SIGINT, SIG_IGN);
88810 $message .= ' (SIGINT = SIG_IGN)';
88811 } elseif (is_int(pcntl_signal_get_handler(SIGINT))) {
88812
88813 pcntl_signal(SIGINT, SIG_DFL);
88814 $message .= ' (SIGINT = SIG_DFL)';
88815 }
88816 $this->notify(Status::INFO, $message);
88817 }
88818
88819 if (!self::$inRestart && function_exists('sapi_windows_set_ctrl_handler')) {
88820
88821
88822
88823 sapi_windows_set_ctrl_handler(function ($evt) {});
88824 $this->notify(Status::INFO, 'CTRL signals suppressed');
88825 }
88826 }
88827 }
88828 Copyright (c) 2012 PHP Framework Interoperability Group
88829
88830 Permission is hereby granted, free of charge, to any person obtaining a copy 
88831 of this software and associated documentation files (the "Software"), to deal
88832 in the Software without restriction, including without limitation the rights 
88833 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
88834 copies of the Software, and to permit persons to whom the Software is 
88835 furnished to do so, subject to the following conditions:
88836
88837 The above copyright notice and this permission notice shall be included in 
88838 all copies or substantial portions of the Software.
88839
88840 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
88841 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
88842 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
88843 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
88844 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
88845 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
88846 THE SOFTWARE.
88847 <?php
88848
88849 namespace Psr\Log;
88850
88851
88852
88853
88854
88855
88856
88857
88858 abstract class AbstractLogger implements LoggerInterface
88859 {
88860
88861
88862
88863
88864
88865
88866
88867
88868 public function emergency($message, array $context = array())
88869 {
88870 $this->log(LogLevel::EMERGENCY, $message, $context);
88871 }
88872
88873
88874
88875
88876
88877
88878
88879
88880
88881
88882
88883
88884 public function alert($message, array $context = array())
88885 {
88886 $this->log(LogLevel::ALERT, $message, $context);
88887 }
88888
88889
88890
88891
88892
88893
88894
88895
88896
88897
88898
88899 public function critical($message, array $context = array())
88900 {
88901 $this->log(LogLevel::CRITICAL, $message, $context);
88902 }
88903
88904
88905
88906
88907
88908
88909
88910
88911
88912
88913 public function error($message, array $context = array())
88914 {
88915 $this->log(LogLevel::ERROR, $message, $context);
88916 }
88917
88918
88919
88920
88921
88922
88923
88924
88925
88926
88927
88928
88929 public function warning($message, array $context = array())
88930 {
88931 $this->log(LogLevel::WARNING, $message, $context);
88932 }
88933
88934
88935
88936
88937
88938
88939
88940
88941
88942 public function notice($message, array $context = array())
88943 {
88944 $this->log(LogLevel::NOTICE, $message, $context);
88945 }
88946
88947
88948
88949
88950
88951
88952
88953
88954
88955
88956
88957 public function info($message, array $context = array())
88958 {
88959 $this->log(LogLevel::INFO, $message, $context);
88960 }
88961
88962
88963
88964
88965
88966
88967
88968
88969
88970 public function debug($message, array $context = array())
88971 {
88972 $this->log(LogLevel::DEBUG, $message, $context);
88973 }
88974 }
88975 <?php
88976
88977 namespace Psr\Log;
88978
88979 class InvalidArgumentException extends \InvalidArgumentException
88980 {
88981 }
88982 <?php
88983
88984 namespace Psr\Log;
88985
88986
88987
88988
88989 class LogLevel
88990 {
88991 const EMERGENCY = 'emergency';
88992 const ALERT = 'alert';
88993 const CRITICAL = 'critical';
88994 const ERROR = 'error';
88995 const WARNING = 'warning';
88996 const NOTICE = 'notice';
88997 const INFO = 'info';
88998 const DEBUG = 'debug';
88999 }
89000 <?php
89001
89002 namespace Psr\Log;
89003
89004
89005
89006
89007 interface LoggerAwareInterface
89008 {
89009
89010
89011
89012
89013
89014
89015
89016 public function setLogger(LoggerInterface $logger);
89017 }
89018 <?php
89019
89020 namespace Psr\Log;
89021
89022
89023
89024
89025 trait LoggerAwareTrait
89026 {
89027
89028
89029
89030
89031
89032 protected $logger;
89033
89034
89035
89036
89037
89038
89039 public function setLogger(LoggerInterface $logger)
89040 {
89041 $this->logger = $logger;
89042 }
89043 }
89044 <?php
89045
89046 namespace Psr\Log;
89047
89048
89049
89050
89051
89052
89053
89054
89055
89056
89057
89058
89059
89060
89061
89062
89063 interface LoggerInterface
89064 {
89065
89066
89067
89068
89069
89070
89071
89072
89073 public function emergency($message, array $context = array());
89074
89075
89076
89077
89078
89079
89080
89081
89082
89083
89084
89085
89086 public function alert($message, array $context = array());
89087
89088
89089
89090
89091
89092
89093
89094
89095
89096
89097
89098 public function critical($message, array $context = array());
89099
89100
89101
89102
89103
89104
89105
89106
89107
89108
89109 public function error($message, array $context = array());
89110
89111
89112
89113
89114
89115
89116
89117
89118
89119
89120
89121
89122 public function warning($message, array $context = array());
89123
89124
89125
89126
89127
89128
89129
89130
89131
89132 public function notice($message, array $context = array());
89133
89134
89135
89136
89137
89138
89139
89140
89141
89142
89143
89144 public function info($message, array $context = array());
89145
89146
89147
89148
89149
89150
89151
89152
89153
89154 public function debug($message, array $context = array());
89155
89156
89157
89158
89159
89160
89161
89162
89163
89164
89165
89166
89167 public function log($level, $message, array $context = array());
89168 }
89169 <?php
89170
89171 namespace Psr\Log;
89172
89173
89174
89175
89176
89177
89178
89179
89180
89181 trait LoggerTrait
89182 {
89183
89184
89185
89186
89187
89188
89189
89190
89191 public function emergency($message, array $context = array())
89192 {
89193 $this->log(LogLevel::EMERGENCY, $message, $context);
89194 }
89195
89196
89197
89198
89199
89200
89201
89202
89203
89204
89205
89206
89207 public function alert($message, array $context = array())
89208 {
89209 $this->log(LogLevel::ALERT, $message, $context);
89210 }
89211
89212
89213
89214
89215
89216
89217
89218
89219
89220
89221
89222 public function critical($message, array $context = array())
89223 {
89224 $this->log(LogLevel::CRITICAL, $message, $context);
89225 }
89226
89227
89228
89229
89230
89231
89232
89233
89234
89235
89236 public function error($message, array $context = array())
89237 {
89238 $this->log(LogLevel::ERROR, $message, $context);
89239 }
89240
89241
89242
89243
89244
89245
89246
89247
89248
89249
89250
89251
89252 public function warning($message, array $context = array())
89253 {
89254 $this->log(LogLevel::WARNING, $message, $context);
89255 }
89256
89257
89258
89259
89260
89261
89262
89263
89264
89265 public function notice($message, array $context = array())
89266 {
89267 $this->log(LogLevel::NOTICE, $message, $context);
89268 }
89269
89270
89271
89272
89273
89274
89275
89276
89277
89278
89279
89280 public function info($message, array $context = array())
89281 {
89282 $this->log(LogLevel::INFO, $message, $context);
89283 }
89284
89285
89286
89287
89288
89289
89290
89291
89292
89293 public function debug($message, array $context = array())
89294 {
89295 $this->log(LogLevel::DEBUG, $message, $context);
89296 }
89297
89298
89299
89300
89301
89302
89303
89304
89305
89306
89307
89308
89309 abstract public function log($level, $message, array $context = array());
89310 }
89311 <?php
89312
89313 namespace Psr\Log;
89314
89315
89316
89317
89318
89319
89320
89321
89322
89323 class NullLogger extends AbstractLogger
89324 {
89325
89326
89327
89328
89329
89330
89331
89332
89333
89334
89335
89336 public function log($level, $message, array $context = array())
89337 {
89338
89339 }
89340 }
89341 <?php
89342
89343 namespace Psr\Log\Test;
89344
89345
89346
89347
89348
89349
89350
89351
89352 class DummyTest
89353 {
89354 public function __toString()
89355 {
89356 return 'DummyTest';
89357 }
89358 }
89359 <?php
89360
89361 namespace Psr\Log\Test;
89362
89363 use Psr\Log\LoggerInterface;
89364 use Psr\Log\LogLevel;
89365 use PHPUnit\Framework\TestCase;
89366
89367
89368
89369
89370
89371
89372
89373 abstract class LoggerInterfaceTest extends TestCase
89374 {
89375
89376
89377
89378 abstract public function getLogger();
89379
89380
89381
89382
89383
89384
89385
89386
89387
89388
89389 abstract public function getLogs();
89390
89391 public function testImplements()
89392 {
89393 $this->assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger());
89394 }
89395
89396
89397
89398
89399 public function testLogsAtAllLevels($level, $message)
89400 {
89401 $logger = $this->getLogger();
89402 $logger->{$level}($message, array('user' => 'Bob'));
89403 $logger->log($level, $message, array('user' => 'Bob'));
89404
89405 $expected = array(
89406 $level.' message of level '.$level.' with context: Bob',
89407 $level.' message of level '.$level.' with context: Bob',
89408 );
89409 $this->assertEquals($expected, $this->getLogs());
89410 }
89411
89412 public function provideLevelsAndMessages()
89413 {
89414 return array(
89415 LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'),
89416 LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'),
89417 LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'),
89418 LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'),
89419 LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'),
89420 LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'),
89421 LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'),
89422 LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}'),
89423 );
89424 }
89425
89426
89427
89428
89429 public function testThrowsOnInvalidLevel()
89430 {
89431 $logger = $this->getLogger();
89432 $logger->log('invalid level', 'Foo');
89433 }
89434
89435 public function testContextReplacement()
89436 {
89437 $logger = $this->getLogger();
89438 $logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar'));
89439
89440 $expected = array('info {Message {nothing} Bob Bar a}');
89441 $this->assertEquals($expected, $this->getLogs());
89442 }
89443
89444 public function testObjectCastToString()
89445 {
89446 if (method_exists($this, 'createPartialMock')) {
89447 $dummy = $this->createPartialMock('Psr\Log\Test\DummyTest', array('__toString'));
89448 } else {
89449 $dummy = $this->getMock('Psr\Log\Test\DummyTest', array('__toString'));
89450 }
89451 $dummy->expects($this->once())
89452 ->method('__toString')
89453 ->will($this->returnValue('DUMMY'));
89454
89455 $this->getLogger()->warning($dummy);
89456
89457 $expected = array('warning DUMMY');
89458 $this->assertEquals($expected, $this->getLogs());
89459 }
89460
89461 public function testContextCanContainAnything()
89462 {
89463 $closed = fopen('php://memory', 'r');
89464 fclose($closed);
89465
89466 $context = array(
89467 'bool' => true,
89468 'null' => null,
89469 'string' => 'Foo',
89470 'int' => 0,
89471 'float' => 0.5,
89472 'nested' => array('with object' => new DummyTest),
89473 'object' => new \DateTime,
89474 'resource' => fopen('php://memory', 'r'),
89475 'closed' => $closed,
89476 );
89477
89478 $this->getLogger()->warning('Crazy context data', $context);
89479
89480 $expected = array('warning Crazy context data');
89481 $this->assertEquals($expected, $this->getLogs());
89482 }
89483
89484 public function testContextExceptionKeyCanBeExceptionOrOtherValues()
89485 {
89486 $logger = $this->getLogger();
89487 $logger->warning('Random message', array('exception' => 'oops'));
89488 $logger->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail')));
89489
89490 $expected = array(
89491 'warning Random message',
89492 'critical Uncaught Exception!'
89493 );
89494 $this->assertEquals($expected, $this->getLogs());
89495 }
89496 }
89497 <?php
89498
89499 namespace Psr\Log\Test;
89500
89501 use Psr\Log\AbstractLogger;
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
89539
89540
89541
89542
89543
89544
89545
89546
89547
89548
89549
89550
89551
89552
89553 class TestLogger extends AbstractLogger
89554 {
89555
89556
89557
89558 public $records = [];
89559
89560 public $recordsByLevel = [];
89561
89562
89563
89564
89565 public function log($level, $message, array $context = [])
89566 {
89567 $record = [
89568 'level' => $level,
89569 'message' => $message,
89570 'context' => $context,
89571 ];
89572
89573 $this->recordsByLevel[$record['level']][] = $record;
89574 $this->records[] = $record;
89575 }
89576
89577 public function hasRecords($level)
89578 {
89579 return isset($this->recordsByLevel[$level]);
89580 }
89581
89582 public function hasRecord($record, $level)
89583 {
89584 if (is_string($record)) {
89585 $record = ['message' => $record];
89586 }
89587 return $this->hasRecordThatPasses(function ($rec) use ($record) {
89588 if ($rec['message'] !== $record['message']) {
89589 return false;
89590 }
89591 if (isset($record['context']) && $rec['context'] !== $record['context']) {
89592 return false;
89593 }
89594 return true;
89595 }, $level);
89596 }
89597
89598 public function hasRecordThatContains($message, $level)
89599 {
89600 return $this->hasRecordThatPasses(function ($rec) use ($message) {
89601 return strpos($rec['message'], $message) !== false;
89602 }, $level);
89603 }
89604
89605 public function hasRecordThatMatches($regex, $level)
89606 {
89607 return $this->hasRecordThatPasses(function ($rec) use ($regex) {
89608 return preg_match($regex, $rec['message']) > 0;
89609 }, $level);
89610 }
89611
89612 public function hasRecordThatPasses(callable $predicate, $level)
89613 {
89614 if (!isset($this->recordsByLevel[$level])) {
89615 return false;
89616 }
89617 foreach ($this->recordsByLevel[$level] as $i => $rec) {
89618 if (call_user_func($predicate, $rec, $i)) {
89619 return true;
89620 }
89621 }
89622 return false;
89623 }
89624
89625 public function __call($method, $args)
89626 {
89627 if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) {
89628 $genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3];
89629 $level = strtolower($matches[2]);
89630 if (method_exists($this, $genericMethod)) {
89631 $args[] = $level;
89632 return call_user_func_array([$this, $genericMethod], $args);
89633 }
89634 }
89635 throw new \BadMethodCallException('Call to undefined method ' . get_class($this) . '::' . $method . '()');
89636 }
89637
89638 public function reset()
89639 {
89640 $this->records = [];
89641 $this->recordsByLevel = [];
89642 }
89643 }
89644 <?php
89645
89646
89647
89648 require_once __DIR__ . '/composer/autoload_real.php';
89649
89650 return ComposerAutoloaderInitComposerPhar1619521845::getLoader();
89651 <?php
89652
89653
89654
89655 $vendorDir = dirname(dirname(__FILE__));
89656 $baseDir = dirname($vendorDir);
89657
89658 return array(
89659 );
89660 <?php
89661
89662
89663
89664 $vendorDir = dirname(dirname(__FILE__));
89665 $baseDir = dirname($vendorDir);
89666
89667 return array(
89668 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
89669 'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
89670 'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'),
89671 'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
89672 'Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'),
89673 'Symfony\\Component\\Debug\\' => array($vendorDir . '/symfony/debug'),
89674 'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'),
89675 'Seld\\PharUtils\\' => array($vendorDir . '/seld/phar-utils/src'),
89676 'Seld\\JsonLint\\' => array($vendorDir . '/seld/jsonlint/src/Seld/JsonLint'),
89677 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
89678 'JsonSchema\\' => array($vendorDir . '/justinrainbow/json-schema/src/JsonSchema'),
89679 'Composer\\XdebugHandler\\' => array($vendorDir . '/composer/xdebug-handler/src'),
89680 'Composer\\Spdx\\' => array($vendorDir . '/composer/spdx-licenses/src'),
89681 'Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'),
89682 'Composer\\CaBundle\\' => array($vendorDir . '/composer/ca-bundle/src'),
89683 'Composer\\' => array($baseDir . '/src/Composer'),
89684 );
89685 <?php
89686
89687
89688
89689 $vendorDir = dirname(dirname(__FILE__));
89690 $baseDir = dirname($vendorDir);
89691
89692 return array(
89693 );
89694 <?php
89695
89696
89697
89698 $vendorDir = dirname(dirname(__FILE__));
89699 $baseDir = dirname($vendorDir);
89700
89701 return array(
89702 '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
89703 '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
89704 );
89705 <?php
89706
89707
89708
89709 class ComposerAutoloaderInitComposerPhar1619521845
89710 {
89711 private static $loader;
89712
89713 public static function loadClassLoader($class)
89714 {
89715 if ('Composer\Autoload\ClassLoader' === $class) {
89716 require __DIR__ . '/ClassLoader.php';
89717 }
89718 }
89719
89720
89721
89722
89723 public static function getLoader()
89724 {
89725 if (null !== self::$loader) {
89726 return self::$loader;
89727 }
89728
89729 spl_autoload_register(array('ComposerAutoloaderInitComposerPhar1619521845', 'loadClassLoader'), true, true);
89730 self::$loader = $loader = new \Composer\Autoload\ClassLoader();
89731 spl_autoload_unregister(array('ComposerAutoloaderInitComposerPhar1619521845', 'loadClassLoader'));
89732
89733 $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
89734 if ($useStaticLoader) {
89735 require_once __DIR__ . '/autoload_static.php';
89736
89737 call_user_func(\Composer\Autoload\ComposerStaticInitComposerPhar1619521845::getInitializer($loader));
89738 } else {
89739 $map = require __DIR__ . '/autoload_namespaces.php';
89740 foreach ($map as $namespace => $path) {
89741 $loader->set($namespace, $path);
89742 }
89743
89744 $map = require __DIR__ . '/autoload_psr4.php';
89745 foreach ($map as $namespace => $path) {
89746 $loader->setPsr4($namespace, $path);
89747 }
89748
89749 $classMap = require __DIR__ . '/autoload_classmap.php';
89750 if ($classMap) {
89751 $loader->addClassMap($classMap);
89752 }
89753 }
89754
89755 $loader->register(true);
89756
89757 if ($useStaticLoader) {
89758 $includeFiles = Composer\Autoload\ComposerStaticInitComposerPhar1619521845::$files;
89759 } else {
89760 $includeFiles = require __DIR__ . '/autoload_files.php';
89761 }
89762 foreach ($includeFiles as $fileIdentifier => $file) {
89763 composerRequireComposerPhar1619521845($fileIdentifier, $file);
89764 }
89765
89766 return $loader;
89767 }
89768 }
89769
89770 function composerRequireComposerPhar1619521845($fileIdentifier, $file)
89771 {
89772 if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
89773 require $file;
89774
89775 $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
89776 }
89777 }
89778 <?php
89779
89780
89781
89782 namespace Composer\Autoload;
89783
89784 class ComposerStaticInitComposerPhar1619521845
89785 {
89786 public static $files = array (
89787 '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
89788 '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
89789 );
89790
89791 public static $prefixLengthsPsr4 = array (
89792 'S' => 
89793 array (
89794 'Symfony\\Polyfill\\Mbstring\\' => 26,
89795 'Symfony\\Polyfill\\Ctype\\' => 23,
89796 'Symfony\\Component\\Process\\' => 26,
89797 'Symfony\\Component\\Finder\\' => 25,
89798 'Symfony\\Component\\Filesystem\\' => 29,
89799 'Symfony\\Component\\Debug\\' => 24,
89800 'Symfony\\Component\\Console\\' => 26,
89801 'Seld\\PharUtils\\' => 15,
89802 'Seld\\JsonLint\\' => 14,
89803 ),
89804 'P' => 
89805 array (
89806 'Psr\\Log\\' => 8,
89807 ),
89808 'J' => 
89809 array (
89810 'JsonSchema\\' => 11,
89811 ),
89812 'C' => 
89813 array (
89814 'Composer\\XdebugHandler\\' => 23,
89815 'Composer\\Spdx\\' => 14,
89816 'Composer\\Semver\\' => 16,
89817 'Composer\\CaBundle\\' => 18,
89818 'Composer\\' => 9,
89819 ),
89820 );
89821
89822 public static $prefixDirsPsr4 = array (
89823 'Symfony\\Polyfill\\Mbstring\\' => 
89824 array (
89825 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
89826 ),
89827 'Symfony\\Polyfill\\Ctype\\' => 
89828 array (
89829 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
89830 ),
89831 'Symfony\\Component\\Process\\' => 
89832 array (
89833 0 => __DIR__ . '/..' . '/symfony/process',
89834 ),
89835 'Symfony\\Component\\Finder\\' => 
89836 array (
89837 0 => __DIR__ . '/..' . '/symfony/finder',
89838 ),
89839 'Symfony\\Component\\Filesystem\\' => 
89840 array (
89841 0 => __DIR__ . '/..' . '/symfony/filesystem',
89842 ),
89843 'Symfony\\Component\\Debug\\' => 
89844 array (
89845 0 => __DIR__ . '/..' . '/symfony/debug',
89846 ),
89847 'Symfony\\Component\\Console\\' => 
89848 array (
89849 0 => __DIR__ . '/..' . '/symfony/console',
89850 ),
89851 'Seld\\PharUtils\\' => 
89852 array (
89853 0 => __DIR__ . '/..' . '/seld/phar-utils/src',
89854 ),
89855 'Seld\\JsonLint\\' => 
89856 array (
89857 0 => __DIR__ . '/..' . '/seld/jsonlint/src/Seld/JsonLint',
89858 ),
89859 'Psr\\Log\\' => 
89860 array (
89861 0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
89862 ),
89863 'JsonSchema\\' => 
89864 array (
89865 0 => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema',
89866 ),
89867 'Composer\\XdebugHandler\\' => 
89868 array (
89869 0 => __DIR__ . '/..' . '/composer/xdebug-handler/src',
89870 ),
89871 'Composer\\Spdx\\' => 
89872 array (
89873 0 => __DIR__ . '/..' . '/composer/spdx-licenses/src',
89874 ),
89875 'Composer\\Semver\\' => 
89876 array (
89877 0 => __DIR__ . '/..' . '/composer/semver/src',
89878 ),
89879 'Composer\\CaBundle\\' => 
89880 array (
89881 0 => __DIR__ . '/..' . '/composer/ca-bundle/src',
89882 ),
89883 'Composer\\' => 
89884 array (
89885 0 => __DIR__ . '/../..' . '/src/Composer',
89886 ),
89887 );
89888
89889 public static function getInitializer(ClassLoader $loader)
89890 {
89891 return \Closure::bind(function () use ($loader) {
89892 $loader->prefixLengthsPsr4 = ComposerStaticInitComposerPhar1619521845::$prefixLengthsPsr4;
89893 $loader->prefixDirsPsr4 = ComposerStaticInitComposerPhar1619521845::$prefixDirsPsr4;
89894
89895 }, null, ClassLoader::class);
89896 }
89897 }
89898 <?php
89899
89900
89901
89902
89903
89904
89905
89906
89907
89908
89909
89910 namespace Composer\Autoload;
89911
89912
89913
89914
89915
89916
89917
89918
89919
89920
89921
89922
89923
89924
89925
89926
89927
89928
89929
89930
89931
89932
89933
89934
89935
89936
89937
89938
89939
89940 class ClassLoader
89941 {
89942
89943 private $prefixLengthsPsr4 = array();
89944 private $prefixDirsPsr4 = array();
89945 private $fallbackDirsPsr4 = array();
89946
89947
89948 private $prefixesPsr0 = array();
89949 private $fallbackDirsPsr0 = array();
89950
89951 private $useIncludePath = false;
89952 private $classMap = array();
89953 private $classMapAuthoritative = false;
89954 private $missingClasses = array();
89955 private $apcuPrefix;
89956
89957 public function getPrefixes()
89958 {
89959 if (!empty($this->prefixesPsr0)) {
89960 return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
89961 }
89962
89963 return array();
89964 }
89965
89966 public function getPrefixesPsr4()
89967 {
89968 return $this->prefixDirsPsr4;
89969 }
89970
89971 public function getFallbackDirs()
89972 {
89973 return $this->fallbackDirsPsr0;
89974 }
89975
89976 public function getFallbackDirsPsr4()
89977 {
89978 return $this->fallbackDirsPsr4;
89979 }
89980
89981 public function getClassMap()
89982 {
89983 return $this->classMap;
89984 }
89985
89986
89987
89988
89989 public function addClassMap(array $classMap)
89990 {
89991 if ($this->classMap) {
89992 $this->classMap = array_merge($this->classMap, $classMap);
89993 } else {
89994 $this->classMap = $classMap;
89995 }
89996 }
89997
89998
89999
90000
90001
90002
90003
90004
90005
90006 public function add($prefix, $paths, $prepend = false)
90007 {
90008 if (!$prefix) {
90009 if ($prepend) {
90010 $this->fallbackDirsPsr0 = array_merge(
90011 (array) $paths,
90012 $this->fallbackDirsPsr0
90013 );
90014 } else {
90015 $this->fallbackDirsPsr0 = array_merge(
90016 $this->fallbackDirsPsr0,
90017 (array) $paths
90018 );
90019 }
90020
90021 return;
90022 }
90023
90024 $first = $prefix[0];
90025 if (!isset($this->prefixesPsr0[$first][$prefix])) {
90026 $this->prefixesPsr0[$first][$prefix] = (array) $paths;
90027
90028 return;
90029 }
90030 if ($prepend) {
90031 $this->prefixesPsr0[$first][$prefix] = array_merge(
90032 (array) $paths,
90033 $this->prefixesPsr0[$first][$prefix]
90034 );
90035 } else {
90036 $this->prefixesPsr0[$first][$prefix] = array_merge(
90037 $this->prefixesPsr0[$first][$prefix],
90038 (array) $paths
90039 );
90040 }
90041 }
90042
90043
90044
90045
90046
90047
90048
90049
90050
90051
90052
90053 public function addPsr4($prefix, $paths, $prepend = false)
90054 {
90055 if (!$prefix) {
90056
90057 if ($prepend) {
90058 $this->fallbackDirsPsr4 = array_merge(
90059 (array) $paths,
90060 $this->fallbackDirsPsr4
90061 );
90062 } else {
90063 $this->fallbackDirsPsr4 = array_merge(
90064 $this->fallbackDirsPsr4,
90065 (array) $paths
90066 );
90067 }
90068 } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
90069
90070 $length = strlen($prefix);
90071 if ('\\' !== $prefix[$length - 1]) {
90072 throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
90073 }
90074 $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
90075 $this->prefixDirsPsr4[$prefix] = (array) $paths;
90076 } elseif ($prepend) {
90077
90078 $this->prefixDirsPsr4[$prefix] = array_merge(
90079 (array) $paths,
90080 $this->prefixDirsPsr4[$prefix]
90081 );
90082 } else {
90083
90084 $this->prefixDirsPsr4[$prefix] = array_merge(
90085 $this->prefixDirsPsr4[$prefix],
90086 (array) $paths
90087 );
90088 }
90089 }
90090
90091
90092
90093
90094
90095
90096
90097
90098 public function set($prefix, $paths)
90099 {
90100 if (!$prefix) {
90101 $this->fallbackDirsPsr0 = (array) $paths;
90102 } else {
90103 $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
90104 }
90105 }
90106
90107
90108
90109
90110
90111
90112
90113
90114
90115
90116 public function setPsr4($prefix, $paths)
90117 {
90118 if (!$prefix) {
90119 $this->fallbackDirsPsr4 = (array) $paths;
90120 } else {
90121 $length = strlen($prefix);
90122 if ('\\' !== $prefix[$length - 1]) {
90123 throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
90124 }
90125 $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
90126 $this->prefixDirsPsr4[$prefix] = (array) $paths;
90127 }
90128 }
90129
90130
90131
90132
90133
90134
90135 public function setUseIncludePath($useIncludePath)
90136 {
90137 $this->useIncludePath = $useIncludePath;
90138 }
90139
90140
90141
90142
90143
90144
90145
90146 public function getUseIncludePath()
90147 {
90148 return $this->useIncludePath;
90149 }
90150
90151
90152
90153
90154
90155
90156
90157 public function setClassMapAuthoritative($classMapAuthoritative)
90158 {
90159 $this->classMapAuthoritative = $classMapAuthoritative;
90160 }
90161
90162
90163
90164
90165
90166
90167 public function isClassMapAuthoritative()
90168 {
90169 return $this->classMapAuthoritative;
90170 }
90171
90172
90173
90174
90175
90176
90177 public function setApcuPrefix($apcuPrefix)
90178 {
90179 $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
90180 }
90181
90182
90183
90184
90185
90186
90187 public function getApcuPrefix()
90188 {
90189 return $this->apcuPrefix;
90190 }
90191
90192
90193
90194
90195
90196
90197 public function register($prepend = false)
90198 {
90199 spl_autoload_register(array($this, 'loadClass'), true, $prepend);
90200 }
90201
90202
90203
90204
90205 public function unregister()
90206 {
90207 spl_autoload_unregister(array($this, 'loadClass'));
90208 }
90209
90210
90211
90212
90213
90214
90215
90216 public function loadClass($class)
90217 {
90218 if ($file = $this->findFile($class)) {
90219 includeFile($file);
90220
90221 return true;
90222 }
90223 }
90224
90225
90226
90227
90228
90229
90230
90231
90232 public function findFile($class)
90233 {
90234
90235 if (isset($this->classMap[$class])) {
90236 return $this->classMap[$class];
90237 }
90238 if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
90239 return false;
90240 }
90241 if (null !== $this->apcuPrefix) {
90242 $file = apcu_fetch($this->apcuPrefix.$class, $hit);
90243 if ($hit) {
90244 return $file;
90245 }
90246 }
90247
90248 $file = $this->findFileWithExtension($class, '.php');
90249
90250
90251 if (false === $file && defined('HHVM_VERSION')) {
90252 $file = $this->findFileWithExtension($class, '.hh');
90253 }
90254
90255 if (null !== $this->apcuPrefix) {
90256 apcu_add($this->apcuPrefix.$class, $file);
90257 }
90258
90259 if (false === $file) {
90260
90261 $this->missingClasses[$class] = true;
90262 }
90263
90264 return $file;
90265 }
90266
90267 private function findFileWithExtension($class, $ext)
90268 {
90269
90270 $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
90271
90272 $first = $class[0];
90273 if (isset($this->prefixLengthsPsr4[$first])) {
90274 $subPath = $class;
90275 while (false !== $lastPos = strrpos($subPath, '\\')) {
90276 $subPath = substr($subPath, 0, $lastPos);
90277 $search = $subPath . '\\';
90278 if (isset($this->prefixDirsPsr4[$search])) {
90279 $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
90280 foreach ($this->prefixDirsPsr4[$search] as $dir) {
90281 if (file_exists($file = $dir . $pathEnd)) {
90282 return $file;
90283 }
90284 }
90285 }
90286 }
90287 }
90288
90289
90290 foreach ($this->fallbackDirsPsr4 as $dir) {
90291 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
90292 return $file;
90293 }
90294 }
90295
90296
90297 if (false !== $pos = strrpos($class, '\\')) {
90298
90299 $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
90300 . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
90301 } else {
90302
90303 $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
90304 }
90305
90306 if (isset($this->prefixesPsr0[$first])) {
90307 foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
90308 if (0 === strpos($class, $prefix)) {
90309 foreach ($dirs as $dir) {
90310 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
90311 return $file;
90312 }
90313 }
90314 }
90315 }
90316 }
90317
90318
90319 foreach ($this->fallbackDirsPsr0 as $dir) {
90320 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
90321 return $file;
90322 }
90323 }
90324
90325
90326 if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
90327 return $file;
90328 }
90329
90330 return false;
90331 }
90332 }
90333
90334
90335
90336
90337
90338
90339 function includeFile($file)
90340 {
90341 include $file;
90342 }
90343 ##
90344 ## Bundle of CA Root Certificates
90345 ##
90346 ## Certificate data from Mozilla as of: Tue Dec  8 04:12:05 2020 GMT
90347 ##
90348 ## This is a bundle of X.509 certificates of public Certificate Authorities
90349 ## (CA). These were automatically extracted from Mozilla's root certificates
90350 ## file (certdata.txt).  This file can be found in the mozilla source tree:
90351 ## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt
90352 ##
90353 ## It contains the certificates in PEM format and therefore
90354 ## can be directly used with curl / libcurl / php_curl, or with
90355 ## an Apache+mod_ssl webserver for SSL client authentication.
90356 ## Just configure this file as the SSLCACertificateFile.
90357 ##
90358 ## Conversion done with mk-ca-bundle.pl version 1.28.
90359 ## SHA256: d820b8696d8ffe42064a1384a56a8981cdc7e7e198036bbb5fa04a6c282dd9a2
90360 ##
90361
90362
90363 GlobalSign Root CA
90364 ==================
90365 -----BEGIN CERTIFICATE-----
90366 MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx
90367 GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds
90368 b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV
90369 BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD
90370 VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa
90371 DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc
90372 THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb
90373 Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP
90374 c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX
90375 gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
90376 HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF
90377 AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj
90378 Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG
90379 j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH
90380 hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC
90381 X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
90382 -----END CERTIFICATE-----
90383
90384 GlobalSign Root CA - R2
90385 =======================
90386 -----BEGIN CERTIFICATE-----
90387 MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv
90388 YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
90389 bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
90390 aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
90391 bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6
90392 ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp
90393 s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN
90394 S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL
90395 TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C
90396 ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
90397 FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i
90398 YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN
90399 BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp
90400 9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu
90401 01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7
90402 9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
90403 TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
90404 -----END CERTIFICATE-----
90405
90406 Entrust.net Premium 2048 Secure Server CA
90407 =========================================
90408 -----BEGIN CERTIFICATE-----
90409 MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u
90410 ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp
90411 bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV
90412 BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx
90413 NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3
90414 d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl
90415 MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u
90416 ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
90417 MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL
90418 Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr
90419 hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW
90420 nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi
90421 VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E
90422 BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ
90423 KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy
90424 T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf
90425 zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT
90426 J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e
90427 nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE=
90428 -----END CERTIFICATE-----
90429
90430 Baltimore CyberTrust Root
90431 =========================
90432 -----BEGIN CERTIFICATE-----
90433 MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE
90434 ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li
90435 ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC
90436 SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs
90437 dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME
90438 uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB
90439 UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C
90440 G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9
90441 XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr
90442 l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI
90443 VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB
90444 BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh
90445 cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5
90446 hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa
90447 Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H
90448 RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
90449 -----END CERTIFICATE-----
90450
90451 Entrust Root Certification Authority
90452 ====================================
90453 -----BEGIN CERTIFICATE-----
90454 MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV
90455 BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw
90456 b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG
90457 A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0
90458 MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu
90459 MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu
90460 Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v
90461 dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
90462 ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz
90463 A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww
90464 Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68
90465 j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN
90466 rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw
90467 DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1
90468 MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH
90469 hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
90470 A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM
90471 Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa
90472 v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS
90473 W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0
90474 tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8
90475 -----END CERTIFICATE-----
90476
90477 GeoTrust Global CA
90478 ==================
90479 -----BEGIN CERTIFICATE-----
90480 MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
90481 Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw
90482 MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j
90483 LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
90484 CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo
90485 BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet
90486 8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc
90487 T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU
90488 vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD
90489 AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk
90490 DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q
90491 zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4
90492 d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2
90493 mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p
90494 XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm
90495 Mw==
90496 -----END CERTIFICATE-----
90497
90498 GeoTrust Universal CA
90499 =====================
90500 -----BEGIN CERTIFICATE-----
90501 MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
90502 R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1
90503 MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu
90504 Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
90505 ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t
90506 JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e
90507 RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs
90508 7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d
90509 8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V
90510 qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga
90511 Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB
90512 Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu
90513 KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08
90514 ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0
90515 XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB
90516 hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
90517 aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2
90518 qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL
90519 oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK
90520 xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF
90521 KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2
90522 DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK
90523 xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU
90524 p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI
90525 P/rmMuGNG2+k5o7Y+SlIis5z/iw=
90526 -----END CERTIFICATE-----
90527
90528 GeoTrust Universal CA 2
90529 =======================
90530 -----BEGIN CERTIFICATE-----
90531 MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
90532 R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0
90533 MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg
90534 SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA
90535 A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0
90536 DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17
90537 j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q
90538 JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a
90539 QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2
90540 WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP
90541 20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn
90542 ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC
90543 SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG
90544 8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2
90545 +/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E
90546 BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
90547 dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ
90548 4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+
90549 mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq
90550 A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg
90551 Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP
90552 pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d
90553 FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp
90554 gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm
90555 X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
90556 -----END CERTIFICATE-----
90557
90558 Comodo AAA Services root
90559 ========================
90560 -----BEGIN CERTIFICATE-----
90561 MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
90562 R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
90563 TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw
90564 MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl
90565 c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
90566 BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
90567 ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG
90568 C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs
90569 i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW
90570 Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH
90571 Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK
90572 Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f
90573 BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl
90574 cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz
90575 LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm
90576 7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
90577 Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z
90578 8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C
90579 12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
90580 -----END CERTIFICATE-----
90581
90582 QuoVadis Root CA
90583 ================
90584 -----BEGIN CERTIFICATE-----
90585 MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE
90586 ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
90587 eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz
90588 MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp
90589 cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD
90590 EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
90591 AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk
90592 J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL
90593 F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL
90594 YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen
90595 AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w
90596 PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y
90597 ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7
90598 MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj
90599 YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs
90600 ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh
90601 Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW
90602 Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu
90603 BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw
90604 FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0
90605 aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6
90606 tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo
90607 fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul
90608 LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x
90609 gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi
90610 5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi
90611 5nrQNiOKSnQ2+Q==
90612 -----END CERTIFICATE-----
90613
90614 QuoVadis Root CA 2
90615 ==================
90616 -----BEGIN CERTIFICATE-----
90617 MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT
90618 EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx
90619 ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
90620 aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC
90621 DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6
90622 XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk
90623 lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB
90624 lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy
90625 lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt
90626 66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn
90627 wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh
90628 D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy
90629 BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie
90630 J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud
90631 DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU
90632 a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT
90633 ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv
90634 Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3
90635 UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm
90636 VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK
90637 +JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW
90638 IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1
90639 WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X
90640 f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II
90641 4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8
90642 VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
90643 -----END CERTIFICATE-----
90644
90645 QuoVadis Root CA 3
90646 ==================
90647 -----BEGIN CERTIFICATE-----
90648 MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT
90649 EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx
90650 OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
90651 aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
90652 DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg
90653 DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij
90654 KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K
90655 DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv
90656 BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp
90657 p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8
90658 nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX
90659 MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM
90660 Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz
90661 uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT
90662 BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj
90663 YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0
90664 aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB
90665 BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD
90666 VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4
90667 ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE
90668 AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV
90669 qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s
90670 hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z
90671 POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2
90672 Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp
90673 8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC
90674 bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu
90675 g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p
90676 vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr
90677 qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=
90678 -----END CERTIFICATE-----
90679
90680 Security Communication Root CA
90681 ==============================
90682 -----BEGIN CERTIFICATE-----
90683 MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
90684 U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
90685 HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
90686 U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
90687 ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw
90688 8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM
90689 DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX
90690 5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd
90691 DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2
90692 JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw
90693 DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g
90694 0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a
90695 mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ
90696 s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ
90697 6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi
90698 FL39vmwLAw==
90699 -----END CERTIFICATE-----
90700
90701 Sonera Class 2 Root CA
90702 ======================
90703 -----BEGIN CERTIFICATE-----
90704 MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG
90705 U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw
90706 NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh
90707 IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3
90708 /Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT
90709 dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG
90710 f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P
90711 tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH
90712 nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT
90713 XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt
90714 0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI
90715 cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph
90716 Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx
90717 EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH
90718 llpwrN9M
90719 -----END CERTIFICATE-----
90720
90721 XRamp Global CA Root
90722 ====================
90723 -----BEGIN CERTIFICATE-----
90724 MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE
90725 BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj
90726 dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
90727 dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx
90728 HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg
90729 U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
90730 dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu
90731 IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx
90732 foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE
90733 zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs
90734 AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry
90735 xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
90736 EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap
90737 oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC
90738 AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc
90739 /Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
90740 qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n
90741 nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz
90742 8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw=
90743 -----END CERTIFICATE-----
90744
90745 Go Daddy Class 2 CA
90746 ===================
90747 -----BEGIN CERTIFICATE-----
90748 MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY
90749 VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp
90750 ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG
90751 A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g
90752 RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD
90753 ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv
90754 2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32
90755 qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j
90756 YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY
90757 vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O
90758 BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o
90759 atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu
90760 MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG
90761 A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim
90762 PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt
90763 I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
90764 HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI
90765 Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b
90766 vZ8=
90767 -----END CERTIFICATE-----
90768
90769 Starfield Class 2 CA
90770 ====================
90771 -----BEGIN CERTIFICATE-----
90772 MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc
90773 U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg
90774 Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo
90775 MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG
90776 A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG
90777 SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY
90778 bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ
90779 JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm
90780 epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN
90781 F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF
90782 MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f
90783 hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo
90784 bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g
90785 QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs
90786 afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM
90787 PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
90788 xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD
90789 KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3
90790 QBFGmh95DmK/D5fs4C8fF5Q=
90791 -----END CERTIFICATE-----
90792
90793 DigiCert Assured ID Root CA
90794 ===========================
90795 -----BEGIN CERTIFICATE-----
90796 MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG
90797 EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
90798 IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx
90799 MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
90800 ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew
90801 ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO
90802 9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy
90803 UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW
90804 /lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy
90805 oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf
90806 GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF
90807 66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq
90808 hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc
90809 EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn
90810 SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i
90811 8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
90812 +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
90813 -----END CERTIFICATE-----
90814
90815 DigiCert Global Root CA
90816 =======================
90817 -----BEGIN CERTIFICATE-----
90818 MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG
90819 EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
90820 HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw
90821 MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
90822 dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq
90823 hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn
90824 TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5
90825 BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H
90826 4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y
90827 7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB
90828 o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm
90829 8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF
90830 BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr
90831 EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt
90832 tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886
90833 UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
90834 CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
90835 -----END CERTIFICATE-----
90836
90837 DigiCert High Assurance EV Root CA
90838 ==================================
90839 -----BEGIN CERTIFICATE-----
90840 MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG
90841 EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw
90842 KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw
90843 MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
90844 MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu
90845 Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t
90846 Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS
90847 OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3
90848 MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ
90849 NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe
90850 h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB
90851 Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY
90852 JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ
90853 V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp
90854 myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK
90855 mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
90856 vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K
90857 -----END CERTIFICATE-----
90858
90859 DST Root CA X3
90860 ==============
90861 -----BEGIN CERTIFICATE-----
90862 MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK
90863 ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X
90864 DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1
90865 cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD
90866 ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT
90867 rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9
90868 UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy
90869 xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d
90870 utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T
90871 AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ
90872 MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug
90873 dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE
90874 GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw
90875 RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS
90876 fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
90877 -----END CERTIFICATE-----
90878
90879 SwissSign Gold CA - G2
90880 ======================
90881 -----BEGIN CERTIFICATE-----
90882 MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw
90883 EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN
90884 MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp
90885 c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B
90886 AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq
90887 t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C
90888 jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg
90889 vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF
90890 ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR
90891 AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend
90892 jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO
90893 peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR
90894 7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi
90895 GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw
90896 AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64
90897 OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov
90898 L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm
90899 5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr
90900 44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf
90901 Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m
90902 Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp
90903 mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk
90904 vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf
90905 KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br
90906 NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj
90907 viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
90908 -----END CERTIFICATE-----
90909
90910 SwissSign Silver CA - G2
90911 ========================
90912 -----BEGIN CERTIFICATE-----
90913 MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT
90914 BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X
90915 DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3
90916 aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG
90917 9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644
90918 N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm
90919 +/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH
90920 6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu
90921 MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h
90922 qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5
90923 FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs
90924 ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc
90925 celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X
90926 CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
90927 BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB
90928 tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0
90929 cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P
90930 4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F
90931 kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L
90932 3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx
90933 /uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa
90934 DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP
90935 e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu
90936 WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ
90937 DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub
90938 DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
90939 -----END CERTIFICATE-----
90940
90941 GeoTrust Primary Certification Authority
90942 ========================================
90943 -----BEGIN CERTIFICATE-----
90944 MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG
90945 EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD
90946 ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx
90947 CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ
90948 cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
90949 CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN
90950 b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9
90951 nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge
90952 RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt
90953 tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
90954 AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI
90955 hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K
90956 Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN
90957 NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa
90958 Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG
90959 1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
90960 -----END CERTIFICATE-----
90961
90962 thawte Primary Root CA
90963 ======================
90964 -----BEGIN CERTIFICATE-----
90965 MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE
90966 BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2
90967 aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv
90968 cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3
90969 MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg
90970 SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv
90971 KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT
90972 FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs
90973 oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ
90974 1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc
90975 q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K
90976 aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p
90977 afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD
90978 VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF
90979 AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE
90980 uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
90981 xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89
90982 jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH
90983 z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA==
90984 -----END CERTIFICATE-----
90985
90986 VeriSign Class 3 Public Primary Certification Authority - G5
90987 ============================================================
90988 -----BEGIN CERTIFICATE-----
90989 MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
90990 BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
90991 ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
90992 IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp
90993 ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB
90994 yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln
90995 biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh
90996 dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt
90997 YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
90998 ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz
90999 j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD
91000 Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/
91001 Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r
91002 fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/
91003 BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv
91004 Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
91005 aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG
91006 SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+
91007 X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE
91008 KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC
91009 Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE
91010 ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
91011 -----END CERTIFICATE-----
91012
91013 SecureTrust CA
91014 ==============
91015 -----BEGIN CERTIFICATE-----
91016 MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG
91017 EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy
91018 dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe
91019 BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC
91020 ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX
91021 OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t
91022 DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH
91023 GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b
91024 01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH
91025 ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/
91026 BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj
91027 aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ
91028 KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu
91029 SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf
91030 mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ
91031 nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
91032 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
91033 -----END CERTIFICATE-----
91034
91035 Secure Global CA
91036 ================
91037 -----BEGIN CERTIFICATE-----
91038 MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG
91039 EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH
91040 bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg
91041 MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg
91042 Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx
91043 YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ
91044 bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g
91045 8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV
91046 HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi
91047 0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
91048 EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn
91049 oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA
91050 MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+
91051 OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn
91052 CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5
91053 3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc
91054 f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW
91055 -----END CERTIFICATE-----
91056
91057 COMODO Certification Authority
91058 ==============================
91059 -----BEGIN CERTIFICATE-----
91060 MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE
91061 BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG
91062 A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1
91063 dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb
91064 MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD
91065 T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
91066 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH
91067 +7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww
91068 xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV
91069 4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA
91070 1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI
91071 rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E
91072 BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k
91073 b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC
91074 AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP
91075 OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
91076 RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc
91077 IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN
91078 +8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ==
91079 -----END CERTIFICATE-----
91080
91081 Network Solutions Certificate Authority
91082 =======================================
91083 -----BEGIN CERTIFICATE-----
91084 MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG
91085 EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr
91086 IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx
91087 MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu
91088 MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G
91089 CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx
91090 jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT
91091 aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT
91092 crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc
91093 /Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB
91094 AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP
91095 BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv
91096 bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA
91097 A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q
91098 4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/
91099 GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv
91100 wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD
91101 ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
91102 -----END CERTIFICATE-----
91103
91104 COMODO ECC Certification Authority
91105 ==================================
91106 -----BEGIN CERTIFICATE-----
91107 MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC
91108 R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
91109 ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB
91110 dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix
91111 GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
91112 Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo
91113 b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X
91114 4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni
91115 wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E
91116 BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG
91117 FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA
91118 U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
91119 -----END CERTIFICATE-----
91120
91121 Certigna
91122 ========
91123 -----BEGIN CERTIFICATE-----
91124 MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw
91125 EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3
91126 MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI
91127 Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q
91128 XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH
91129 GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p
91130 ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg
91131 DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf
91132 Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ
91133 tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ
91134 BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J
91135 SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA
91136 hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+
91137 ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu
91138 PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY
91139 1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw
91140 WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
91141 -----END CERTIFICATE-----
91142
91143 Cybertrust Global Root
91144 ======================
91145 -----BEGIN CERTIFICATE-----
91146 MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li
91147 ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4
91148 MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD
91149 ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
91150 +Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW
91151 0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL
91152 AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin
91153 89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT
91154 8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP
91155 BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2
91156 MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G
91157 A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO
91158 lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi
91159 5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2
91160 hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T
91161 X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW
91162 WL1WMRJOEcgh4LMRkWXbtKaIOM5V
91163 -----END CERTIFICATE-----
91164
91165 ePKI Root Certification Authority
91166 =================================
91167 -----BEGIN CERTIFICATE-----
91168 MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG
91169 EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg
91170 Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx
91171 MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq
91172 MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B
91173 AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs
91174 IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi
91175 lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv
91176 qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX
91177 12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O
91178 WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+
91179 ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao
91180 lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/
91181 vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi
91182 Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi
91183 MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH
91184 ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0
91185 1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq
91186 KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV
91187 xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP
91188 NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r
91189 GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE
91190 xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx
91191 gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy
91192 sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD
91193 BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw=
91194 -----END CERTIFICATE-----
91195
91196 certSIGN ROOT CA
91197 ================
91198 -----BEGIN CERTIFICATE-----
91199 MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD
91200 VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa
91201 Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE
91202 CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I
91203 JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH
91204 rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2
91205 ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD
91206 0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943
91207 AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
91208 Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB
91209 AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8
91210 SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0
91211 x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt
91212 vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz
91213 TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD
91214 -----END CERTIFICATE-----
91215
91216 GeoTrust Primary Certification Authority - G3
91217 =============================================
91218 -----BEGIN CERTIFICATE-----
91219 MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE
91220 BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0
91221 IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy
91222 eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz
91223 NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo
91224 YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT
91225 LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI
91226 hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j
91227 K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE
91228 c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C
91229 IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu
91230 dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC
91231 MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr
91232 2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9
91233 cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE
91234 Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
91235 AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s
91236 t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt
91237 -----END CERTIFICATE-----
91238
91239 thawte Primary Root CA - G2
91240 ===========================
91241 -----BEGIN CERTIFICATE-----
91242 MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC
91243 VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu
91244 IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg
91245 Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV
91246 MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG
91247 b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt
91248 IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS
91249 LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5
91250 8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU
91251 mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN
91252 G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K
91253 rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
91254 -----END CERTIFICATE-----
91255
91256 thawte Primary Root CA - G3
91257 ===========================
91258 -----BEGIN CERTIFICATE-----
91259 MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE
91260 BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2
91261 aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv
91262 cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w
91263 ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
91264 d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD
91265 VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG
91266 A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
91267 MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At
91268 P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC
91269 +BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY
91270 7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW
91271 vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E
91272 BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ
91273 KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK
91274 A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
91275 t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC
91276 8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm
91277 er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A=
91278 -----END CERTIFICATE-----
91279
91280 GeoTrust Primary Certification Authority - G2
91281 =============================================
91282 -----BEGIN CERTIFICATE-----
91283 MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC
91284 VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu
91285 Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD
91286 ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1
91287 OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg
91288 MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl
91289 b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG
91290 BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc
91291 KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD
91292 VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+
91293 EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m
91294 ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2
91295 npaqBA+K
91296 -----END CERTIFICATE-----
91297
91298 VeriSign Universal Root Certification Authority
91299 ===============================================
91300 -----BEGIN CERTIFICATE-----
91301 MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE
91302 BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
91303 ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
91304 IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u
91305 IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV
91306 UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
91307 cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
91308 IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0
91309 aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj
91310 1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP
91311 MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72
91312 9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I
91313 AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR
91314 tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G
91315 CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O
91316 a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
91317 DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3
91318 Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx
91319 Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx
91320 P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P
91321 wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4
91322 mJO37M2CYfE45k+XmCpajQ==
91323 -----END CERTIFICATE-----
91324
91325 VeriSign Class 3 Public Primary Certification Authority - G4
91326 ============================================================
91327 -----BEGIN CERTIFICATE-----
91328 MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC
91329 VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3
91330 b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz
91331 ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj
91332 YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL
91333 MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU
91334 cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo
91335 b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5
91336 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8
91337 Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz
91338 rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB
91339 /zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw
91340 HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u
91341 Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD
91342 A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx
91343 AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
91344 -----END CERTIFICATE-----
91345
91346 NetLock Arany (Class Gold) Főtanúsítvány
91347 ========================================
91348 -----BEGIN CERTIFICATE-----
91349 MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G
91350 A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610
91351 dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB
91352 cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx
91353 MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO
91354 ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv
91355 biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6
91356 c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu
91357 0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw
91358 /HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk
91359 H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw
91360 fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1
91361 neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB
91362 BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW
91363 qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta
91364 YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC
91365 bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna
91366 NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu
91367 dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
91368 -----END CERTIFICATE-----
91369
91370 Hongkong Post Root CA 1
91371 =======================
91372 -----BEGIN CERTIFICATE-----
91373 MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT
91374 DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx
91375 NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n
91376 IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF
91377 AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1
91378 ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr
91379 auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh
91380 qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY
91381 V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV
91382 HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i
91383 h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio
91384 l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei
91385 IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps
91386 T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT
91387 c4afU9hDDl3WY4JxHYB0yvbiAmvZWg==
91388 -----END CERTIFICATE-----
91389
91390 SecureSign RootCA11
91391 ===================
91392 -----BEGIN CERTIFICATE-----
91393 MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi
91394 SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS
91395 b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw
91396 KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1
91397 cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL
91398 TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO
91399 wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq
91400 g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP
91401 O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA
91402 bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX
91403 t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh
91404 OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r
91405 bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ
91406 Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01
91407 y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061
91408 lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I=
91409 -----END CERTIFICATE-----
91410
91411 Microsec e-Szigno Root CA 2009
91412 ==============================
91413 -----BEGIN CERTIFICATE-----
91414 MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER
91415 MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv
91416 c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o
91417 dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE
91418 BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt
91419 U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw
91420 DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA
91421 fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG
91422 0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA
91423 pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm
91424 1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC
91425 AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf
91426 QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE
91427 FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o
91428 lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX
91429 I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775
91430 tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02
91431 yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi
91432 LXpUq3DDfSJlgnCW
91433 -----END CERTIFICATE-----
91434
91435 GlobalSign Root CA - R3
91436 =======================
91437 -----BEGIN CERTIFICATE-----
91438 MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv
91439 YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
91440 bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
91441 aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
91442 bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt
91443 iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ
91444 0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3
91445 rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl
91446 OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2
91447 xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
91448 FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7
91449 lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8
91450 EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E
91451 bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18
91452 YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r
91453 kpeDMdmztcpHWD9f
91454 -----END CERTIFICATE-----
91455
91456 Autoridad de Certificacion Firmaprofesional CIF A62634068
91457 =========================================================
91458 -----BEGIN CERTIFICATE-----
91459 MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA
91460 BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2
91461 MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw
91462 QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB
91463 NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD
91464 Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P
91465 B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY
91466 7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH
91467 ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI
91468 plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX
91469 MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX
91470 LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK
91471 bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU
91472 vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud
91473 EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH
91474 DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp
91475 cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA
91476 bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx
91477 ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx
91478 51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk
91479 R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP
91480 T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f
91481 Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl
91482 osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR
91483 crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR
91484 saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD
91485 KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi
91486 6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
91487 -----END CERTIFICATE-----
91488
91489 Izenpe.com
91490 ==========
91491 -----BEGIN CERTIFICATE-----
91492 MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG
91493 EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz
91494 MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu
91495 QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ
91496 03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK
91497 ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU
91498 +zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC
91499 PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT
91500 OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK
91501 F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK
91502 0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+
91503 0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB
91504 leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID
91505 AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+
91506 SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG
91507 NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx
91508 MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
91509 BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l
91510 Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga
91511 kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q
91512 hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs
91513 g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5
91514 aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5
91515 nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC
91516 ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo
91517 Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z
91518 WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
91519 -----END CERTIFICATE-----
91520
91521 Chambers of Commerce Root - 2008
91522 ================================
91523 -----BEGIN CERTIFICATE-----
91524 MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD
91525 MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
91526 bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
91527 QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy
91528 Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl
91529 ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF
91530 EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl
91531 cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
91532 AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA
91533 XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj
91534 h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/
91535 ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk
91536 NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g
91537 D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331
91538 lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ
91539 0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj
91540 ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2
91541 EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI
91542 G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ
91543 BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh
91544 bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh
91545 bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC
91546 CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH
91547 AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1
91548 wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH
91549 3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU
91550 RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6
91551 M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1
91552 YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF
91553 9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK
91554 zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG
91555 nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg
91556 OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ
91557 -----END CERTIFICATE-----
91558
91559 Global Chambersign Root - 2008
91560 ==============================
91561 -----BEGIN CERTIFICATE-----
91562 MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD
91563 MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
91564 bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
91565 QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx
91566 NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg
91567 Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ
91568 QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD
91569 aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf
91570 VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf
91571 XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0
91572 ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB
91573 /gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA
91574 TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M
91575 H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe
91576 Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF
91577 HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh
91578 wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB
91579 AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT
91580 BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE
91581 BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm
91582 aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm
91583 aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp
91584 1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0
91585 dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG
91586 /5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6
91587 ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s
91588 dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg
91589 9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH
91590 foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du
91591 qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr
91592 P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq
91593 c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z
91594 09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B
91595 -----END CERTIFICATE-----
91596
91597 Go Daddy Root Certificate Authority - G2
91598 ========================================
91599 -----BEGIN CERTIFICATE-----
91600 MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
91601 B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu
91602 MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
91603 MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
91604 b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G
91605 A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
91606 hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq
91607 9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD
91608 +qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd
91609 fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl
91610 NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC
91611 MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9
91612 BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac
91613 vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r
91614 5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV
91615 N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
91616 LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1
91617 -----END CERTIFICATE-----
91618
91619 Starfield Root Certificate Authority - G2
91620 =========================================
91621 -----BEGIN CERTIFICATE-----
91622 MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
91623 B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
91624 b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0
91625 eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw
91626 DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg
91627 VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB
91628 dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv
91629 W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs
91630 bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk
91631 N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf
91632 ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU
91633 JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
91634 AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol
91635 TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx
91636 4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw
91637 F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
91638 pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ
91639 c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
91640 -----END CERTIFICATE-----
91641
91642 Starfield Services Root Certificate Authority - G2
91643 ==================================================
91644 -----BEGIN CERTIFICATE-----
91645 MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
91646 B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
91647 b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl
91648 IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV
91649 BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT
91650 dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg
91651 Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
91652 AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2
91653 h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa
91654 hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP
91655 LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB
91656 rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw
91657 AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG
91658 SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP
91659 E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy
91660 xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
91661 iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza
91662 YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6
91663 -----END CERTIFICATE-----
91664
91665 AffirmTrust Commercial
91666 ======================
91667 -----BEGIN CERTIFICATE-----
91668 MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS
91669 BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw
91670 MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
91671 bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF
91672 AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb
91673 DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV
91674 C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6
91675 BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww
91676 MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV
91677 HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
91678 AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG
91679 hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi
91680 qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv
91681 0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh
91682 sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
91683 -----END CERTIFICATE-----
91684
91685 AffirmTrust Networking
91686 ======================
91687 -----BEGIN CERTIFICATE-----
91688 MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS
91689 BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw
91690 MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
91691 bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF
91692 AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE
91693 Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI
91694 dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24
91695 /PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb
91696 h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV
91697 HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
91698 AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu
91699 UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6
91700 12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23
91701 WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9
91702 /ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
91703 -----END CERTIFICATE-----
91704
91705 AffirmTrust Premium
91706 ===================
91707 -----BEGIN CERTIFICATE-----
91708 MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS
91709 BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy
91710 OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy
91711 dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
91712 MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn
91713 BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV
91714 5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs
91715 +7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd
91716 GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R
91717 p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI
91718 S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04
91719 6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5
91720 /bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo
91721 +Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB
91722 /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv
91723 MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
91724 Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC
91725 6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S
91726 L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK
91727 +4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV
91728 BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg
91729 IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60
91730 g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb
91731 zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw==
91732 -----END CERTIFICATE-----
91733
91734 AffirmTrust Premium ECC
91735 =======================
91736 -----BEGIN CERTIFICATE-----
91737 MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV
91738 BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx
91739 MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U
91740 cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA
91741 IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ
91742 N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW
91743 BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK
91744 BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X
91745 57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM
91746 eQ==
91747 -----END CERTIFICATE-----
91748
91749 Certum Trusted Network CA
91750 =========================
91751 -----BEGIN CERTIFICATE-----
91752 MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK
91753 ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv
91754 biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy
91755 MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU
91756 ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
91757 MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
91758 AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC
91759 l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J
91760 J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4
91761 fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0
91762 cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB
91763 Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw
91764 DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj
91765 jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1
91766 mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj
91767 Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
91768 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=
91769 -----END CERTIFICATE-----
91770
91771 TWCA Root Certification Authority
91772 =================================
91773 -----BEGIN CERTIFICATE-----
91774 MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ
91775 VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh
91776 dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG
91777 EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB
91778 IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
91779 AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx
91780 QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC
91781 oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP
91782 4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r
91783 y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB
91784 BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG
91785 9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC
91786 mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW
91787 QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY
91788 T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny
91789 Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
91790 -----END CERTIFICATE-----
91791
91792 Security Communication RootCA2
91793 ==============================
91794 -----BEGIN CERTIFICATE-----
91795 MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
91796 U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh
91797 dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC
91798 SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy
91799 aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
91800 ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++
91801 +T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R
91802 3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV
91803 spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K
91804 EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8
91805 QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB
91806 CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj
91807 u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk
91808 3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q
91809 tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29
91810 mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
91811 -----END CERTIFICATE-----
91812
91813 EC-ACC
91814 ======
91815 -----BEGIN CERTIFICATE-----
91816 MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE
91817 BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w
91818 ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD
91819 VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE
91820 CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT
91821 BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7
91822 MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt
91823 SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl
91824 Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh
91825 cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND
91826 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK
91827 w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT
91828 ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4
91829 HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a
91830 E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw
91831 0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E
91832 BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD
91833 VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0
91834 Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l
91835 dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ
91836 lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa
91837 Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe
91838 l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2
91839 E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D
91840 5EI=
91841 -----END CERTIFICATE-----
91842
91843 Hellenic Academic and Research Institutions RootCA 2011
91844 =======================================================
91845 -----BEGIN CERTIFICATE-----
91846 MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT
91847 O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y
91848 aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
91849 IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT
91850 AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
91851 IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo
91852 IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
91853 AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI
91854 1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa
91855 71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u
91856 8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH
91857 3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/
91858 MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8
91859 MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu
91860 b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt
91861 XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8
91862 TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD
91863 /md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N
91864 7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4
91865 -----END CERTIFICATE-----
91866
91867 Actalis Authentication Root CA
91868 ==============================
91869 -----BEGIN CERTIFICATE-----
91870 MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM
91871 BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE
91872 AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky
91873 MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz
91874 IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
91875 IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ
91876 wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa
91877 by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6
91878 zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f
91879 YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2
91880 oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l
91881 EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7
91882 hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8
91883 EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5
91884 jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY
91885 iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt
91886 ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI
91887 WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0
91888 JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx
91889 K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+
91890 Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC
91891 4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo
91892 2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz
91893 lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem
91894 OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9
91895 vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
91896 -----END CERTIFICATE-----
91897
91898 Trustis FPS Root CA
91899 ===================
91900 -----BEGIN CERTIFICATE-----
91901 MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG
91902 EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290
91903 IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV
91904 BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ
91905 KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ
91906 RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk
91907 H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa
91908 cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt
91909 o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA
91910 AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd
91911 BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c
91912 GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC
91913 yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P
91914 8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV
91915 l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl
91916 iB6XzCGcKQENZetX2fNXlrtIzYE=
91917 -----END CERTIFICATE-----
91918
91919 Buypass Class 2 Root CA
91920 =======================
91921 -----BEGIN CERTIFICATE-----
91922 MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
91923 QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X
91924 DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
91925 eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw
91926 DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1
91927 g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn
91928 9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b
91929 /+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU
91930 CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff
91931 awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI
91932 zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn
91933 Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX
91934 Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs
91935 M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
91936 VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
91937 AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s
91938 A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI
91939 osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S
91940 aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd
91941 DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD
91942 LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0
91943 oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC
91944 wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS
91945 CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN
91946 rJgWVqA=
91947 -----END CERTIFICATE-----
91948
91949 Buypass Class 3 Root CA
91950 =======================
91951 -----BEGIN CERTIFICATE-----
91952 MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
91953 QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X
91954 DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
91955 eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw
91956 DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH
91957 sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR
91958 5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh
91959 7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ
91960 ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH
91961 2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV
91962 /afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ
91963 RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA
91964 Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq
91965 j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
91966 VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
91967 AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV
91968 cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G
91969 uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG
91970 Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8
91971 ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2
91972 KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz
91973 6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug
91974 UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe
91975 eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi
91976 Cp/HuZc=
91977 -----END CERTIFICATE-----
91978
91979 T-TeleSec GlobalRoot Class 3
91980 ============================
91981 -----BEGIN CERTIFICATE-----
91982 MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
91983 IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
91984 cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx
91985 MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
91986 dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
91987 ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3
91988 DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK
91989 9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU
91990 NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF
91991 iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W
91992 0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA
91993 MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr
91994 AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb
91995 fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT
91996 ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h
91997 P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml
91998 e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw==
91999 -----END CERTIFICATE-----
92000
92001 D-TRUST Root Class 3 CA 2 2009
92002 ==============================
92003 -----BEGIN CERTIFICATE-----
92004 MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK
92005 DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe
92006 Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE
92007 LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw
92008 DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD
92009 ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA
92010 BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv
92011 KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z
92012 p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC
92013 AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ
92014 4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y
92015 eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw
92016 MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G
92017 PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw
92018 OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm
92019 2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
92020 o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV
92021 dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph
92022 X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I=
92023 -----END CERTIFICATE-----
92024
92025 D-TRUST Root Class 3 CA 2 EV 2009
92026 =================================
92027 -----BEGIN CERTIFICATE-----
92028 MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
92029 DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
92030 OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
92031 DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
92032 OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS
92033 egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh
92034 zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T
92035 7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60
92036 sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35
92037 11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv
92038 cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v
92039 ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El
92040 MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp
92041 b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh
92042 c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+
92043 PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05
92044 nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX
92045 ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA
92046 NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv
92047 w9y4AyHqnxbxLFS1
92048 -----END CERTIFICATE-----
92049
92050 CA Disig Root R2
92051 ================
92052 -----BEGIN CERTIFICATE-----
92053 MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw
92054 EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp
92055 ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx
92056 EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp
92057 c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC
92058 w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia
92059 xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7
92060 A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S
92061 GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV
92062 g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa
92063 5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE
92064 koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A
92065 Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i
92066 Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV
92067 HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u
92068 Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM
92069 tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV
92070 sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je
92071 dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8
92072 1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx
92073 mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01
92074 utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0
92075 sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg
92076 UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV
92077 7+ZtsH8tZ/3zbBt1RqPlShfppNcL
92078 -----END CERTIFICATE-----
92079
92080 ACCVRAIZ1
92081 =========
92082 -----BEGIN CERTIFICATE-----
92083 MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB
92084 SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1
92085 MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH
92086 UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
92087 DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM
92088 jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0
92089 RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD
92090 aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ
92091 0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG
92092 WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7
92093 8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR
92094 5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J
92095 9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK
92096 Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw
92097 Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu
92098 Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2
92099 VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM
92100 Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA
92101 QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh
92102 AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA
92103 YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj
92104 AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA
92105 IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk
92106 aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0
92107 dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2
92108 MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI
92109 hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E
92110 R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN
92111 YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49
92112 nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ
92113 TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3
92114 sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h
92115 I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg
92116 Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd
92117 3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p
92118 EfbRD0tVNEYqi4Y7
92119 -----END CERTIFICATE-----
92120
92121 TWCA Global Root CA
92122 ===================
92123 -----BEGIN CERTIFICATE-----
92124 MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT
92125 CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD
92126 QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK
92127 EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg
92128 Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C
92129 nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV
92130 r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR
92131 Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV
92132 tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W
92133 KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99
92134 sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p
92135 yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn
92136 kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI
92137 zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC
92138 AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g
92139 cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn
92140 LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M
92141 8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg
92142 /eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg
92143 lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP
92144 A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m
92145 i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8
92146 EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3
92147 zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0=
92148 -----END CERTIFICATE-----
92149
92150 TeliaSonera Root CA v1
92151 ======================
92152 -----BEGIN CERTIFICATE-----
92153 MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE
92154 CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4
92155 MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW
92156 VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+
92157 6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA
92158 3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k
92159 B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn
92160 Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH
92161 oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3
92162 F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ
92163 oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7
92164 gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc
92165 TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB
92166 AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW
92167 DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm
92168 zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx
92169 0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW
92170 pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV
92171 G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc
92172 c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT
92173 JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2
92174 qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6
92175 Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems
92176 WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=
92177 -----END CERTIFICATE-----
92178
92179 E-Tugra Certification Authority
92180 ===============================
92181 -----BEGIN CERTIFICATE-----
92182 MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w
92183 DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls
92184 ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN
92185 ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw
92186 NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx
92187 QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl
92188 cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD
92189 DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
92190 MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd
92191 hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K
92192 CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g
92193 ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ
92194 BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0
92195 E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz
92196 rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq
92197 jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn
92198 rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5
92199 dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB
92200 /wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG
92201 MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK
92202 kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO
92203 XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807
92204 VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo
92205 a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc
92206 dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV
92207 KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT
92208 Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0
92209 8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G
92210 C7TbO6Orb1wdtn7os4I07QZcJA==
92211 -----END CERTIFICATE-----
92212
92213 T-TeleSec GlobalRoot Class 2
92214 ============================
92215 -----BEGIN CERTIFICATE-----
92216 MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
92217 IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
92218 cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx
92219 MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
92220 dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
92221 ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3
92222 DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ
92223 SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F
92224 vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970
92225 2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV
92226 WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA
92227 MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy
92228 YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4
92229 r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf
92230 vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR
92231 3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN
92232 9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg==
92233 -----END CERTIFICATE-----
92234
92235 Atos TrustedRoot 2011
92236 =====================
92237 -----BEGIN CERTIFICATE-----
92238 MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU
92239 cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4
92240 MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG
92241 A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV
92242 hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr
92243 54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+
92244 DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320
92245 HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR
92246 z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R
92247 l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ
92248 bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
92249 CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h
92250 k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh
92251 TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9
92252 61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G
92253 3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
92254 -----END CERTIFICATE-----
92255
92256 QuoVadis Root CA 1 G3
92257 =====================
92258 -----BEGIN CERTIFICATE-----
92259 MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG
92260 A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
92261 b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN
92262 MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg
92263 RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE
92264 PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm
92265 PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6
92266 Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN
92267 ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l
92268 g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV
92269 7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX
92270 9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f
92271 iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg
92272 t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
92273 AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI
92274 hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC
92275 MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3
92276 GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct
92277 Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP
92278 +V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh
92279 3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa
92280 wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6
92281 O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0
92282 FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV
92283 hMJKzRwuJIczYOXD
92284 -----END CERTIFICATE-----
92285
92286 QuoVadis Root CA 2 G3
92287 =====================
92288 -----BEGIN CERTIFICATE-----
92289 MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG
92290 A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
92291 b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN
92292 MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg
92293 RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh
92294 ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY
92295 NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t
92296 oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o
92297 MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l
92298 V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo
92299 L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ
92300 sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD
92301 6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh
92302 lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
92303 AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI
92304 hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66
92305 AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K
92306 pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9
92307 x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz
92308 dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X
92309 U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw
92310 mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD
92311 zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN
92312 JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr
92313 O3jtZsSOeWmD3n+M
92314 -----END CERTIFICATE-----
92315
92316 QuoVadis Root CA 3 G3
92317 =====================
92318 -----BEGIN CERTIFICATE-----
92319 MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG
92320 A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
92321 b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN
92322 MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg
92323 RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286
92324 IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL
92325 Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe
92326 6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3
92327 I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U
92328 VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7
92329 5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi
92330 Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM
92331 dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt
92332 rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
92333 AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI
92334 hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px
92335 KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS
92336 t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ
92337 TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du
92338 DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib
92339 Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD
92340 hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX
92341 0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW
92342 dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2
92343 PpxxVJkES/1Y+Zj0
92344 -----END CERTIFICATE-----
92345
92346 DigiCert Assured ID Root G2
92347 ===========================
92348 -----BEGIN CERTIFICATE-----
92349 MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG
92350 EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
92351 IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw
92352 MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
92353 ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw
92354 ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH
92355 35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq
92356 bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw
92357 VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP
92358 YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn
92359 lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO
92360 w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv
92361 0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz
92362 d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW
92363 hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M
92364 jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo
92365 IhNzbM8m9Yop5w==
92366 -----END CERTIFICATE-----
92367
92368 DigiCert Assured ID Root G3
92369 ===========================
92370 -----BEGIN CERTIFICATE-----
92371 MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV
92372 UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD
92373 VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1
92374 MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
92375 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ
92376 BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb
92377 RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs
92378 KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF
92379 UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy
92380 YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy
92381 1vUhZscv6pZjamVFkpUBtA==
92382 -----END CERTIFICATE-----
92383
92384 DigiCert Global Root G2
92385 =======================
92386 -----BEGIN CERTIFICATE-----
92387 MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG
92388 EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
92389 HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx
92390 MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
92391 dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq
92392 hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ
92393 kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO
92394 3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV
92395 BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM
92396 UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB
92397 o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu
92398 5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr
92399 F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U
92400 WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH
92401 QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/
92402 iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
92403 MrY=
92404 -----END CERTIFICATE-----
92405
92406 DigiCert Global Root G3
92407 =======================
92408 -----BEGIN CERTIFICATE-----
92409 MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV
92410 UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD
92411 VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw
92412 MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k
92413 aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C
92414 AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O
92415 YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP
92416 BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp
92417 Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y
92418 3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34
92419 VOKa5Vt8sycX
92420 -----END CERTIFICATE-----
92421
92422 DigiCert Trusted Root G4
92423 ========================
92424 -----BEGIN CERTIFICATE-----
92425 MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG
92426 EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw
92427 HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1
92428 MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
92429 d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G
92430 CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp
92431 pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o
92432 k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa
92433 vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY
92434 QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6
92435 MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm
92436 mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7
92437 f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH
92438 dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8
92439 oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud
92440 DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD
92441 ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY
92442 ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr
92443 yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy
92444 7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah
92445 ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN
92446 5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb
92447 /UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa
92448 5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK
92449 G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP
92450 82Z+
92451 -----END CERTIFICATE-----
92452
92453 COMODO RSA Certification Authority
92454 ==================================
92455 -----BEGIN CERTIFICATE-----
92456 MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE
92457 BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG
92458 A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv
92459 biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC
92460 R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
92461 ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB
92462 dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn
92463 dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ
92464 FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+
92465 5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG
92466 x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX
92467 2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL
92468 OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3
92469 sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C
92470 GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5
92471 WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E
92472 FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
92473 DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt
92474 rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+
92475 nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg
92476 tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW
92477 sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp
92478 pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA
92479 zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq
92480 ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52
92481 7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I
92482 LaZRfyHBNVOFBkpdn627G190
92483 -----END CERTIFICATE-----
92484
92485 USERTrust RSA Certification Authority
92486 =====================================
92487 -----BEGIN CERTIFICATE-----
92488 MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE
92489 BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK
92490 ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh
92491 dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE
92492 BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK
92493 ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh
92494 dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz
92495 0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j
92496 Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn
92497 RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O
92498 +T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq
92499 /nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE
92500 Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM
92501 lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8
92502 yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+
92503 eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
92504 BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
92505 MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW
92506 FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ
92507 7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ
92508 Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM
92509 8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi
92510 FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi
92511 yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c
92512 J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw
92513 sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx
92514 Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9
92515 -----END CERTIFICATE-----
92516
92517 USERTrust ECC Certification Authority
92518 =====================================
92519 -----BEGIN CERTIFICATE-----
92520 MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC
92521 VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
92522 aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
92523 biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC
92524 VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
92525 aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
92526 biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2
92527 0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez
92528 nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV
92529 HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB
92530 HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu
92531 9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=
92532 -----END CERTIFICATE-----
92533
92534 GlobalSign ECC Root CA - R4
92535 ===========================
92536 -----BEGIN CERTIFICATE-----
92537 MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEkMCIGA1UECxMb
92538 R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
92539 EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb
92540 R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
92541 EwpHbG9iYWxTaWduMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprl
92542 OQcJFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAwDgYDVR0P
92543 AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61FuOJAf/sKbvu+M8k8o4TV
92544 MAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGXkPoUVy0D7O48027KqGx2vKLeuwIgJ6iF
92545 JzWbVsaj8kfSt24bAgAXqmemFZHe+pTsewv4n4Q=
92546 -----END CERTIFICATE-----
92547
92548 GlobalSign ECC Root CA - R5
92549 ===========================
92550 -----BEGIN CERTIFICATE-----
92551 MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb
92552 R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
92553 EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb
92554 R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
92555 EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6
92556 SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS
92557 h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd
92558 BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx
92559 uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7
92560 yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3
92561 -----END CERTIFICATE-----
92562
92563 Staat der Nederlanden Root CA - G3
92564 ==================================
92565 -----BEGIN CERTIFICATE-----
92566 MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE
92567 CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g
92568 Um9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloXDTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMC
92569 TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l
92570 ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4y
92571 olQPcPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WWIkYFsO2t
92572 x1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqXxz8ecAgwoNzFs21v0IJy
92573 EavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFyKJLZWyNtZrVtB0LrpjPOktvA9mxjeM3K
92574 Tj215VKb8b475lRgsGYeCasH/lSJEULR9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUur
92575 mkVLoR9BvUhTFXFkC4az5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU5
92576 1nus6+N86U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7Ngzp
92577 07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHPbMk7ccHViLVlvMDo
92578 FxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXtBznaqB16nzaeErAMZRKQFWDZJkBE
92579 41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTtXUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMB
92580 AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleu
92581 yjWcLhL75LpdINyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD
92582 U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwpLiniyMMB8jPq
92583 KqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8Ipf3YF3qKS9Ysr1YvY2WTxB1
92584 v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixpgZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA
92585 8KCWAg8zxXHzniN9lLf9OtMJgwYh/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b
92586 8KKaa8MFSu1BYBQw0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0r
92587 mj1AfsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq4BZ+Extq
92588 1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR1VmiiXTTn74eS9fGbbeI
92589 JG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/QFH1T/U67cjF68IeHRaVesd+QnGTbksV
92590 tzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM94B7IWcnMFk=
92591 -----END CERTIFICATE-----
92592
92593 Staat der Nederlanden EV Root CA
92594 ================================
92595 -----BEGIN CERTIFICATE-----
92596 MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJOTDEeMBwGA1UE
92597 CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFhdCBkZXIgTmVkZXJsYW5kZW4g
92598 RVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0yMjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5M
92599 MR4wHAYDVQQKDBVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRl
92600 cmxhbmRlbiBFViBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkk
92601 SzrSM4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nCUiY4iKTW
92602 O0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3dZ//BYY1jTw+bbRcwJu+r
92603 0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46prfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8
92604 Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13lpJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gV
92605 XJrm0w912fxBmJc+qiXbj5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr
92606 08C+eKxCKFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS/ZbV
92607 0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0XcgOPvZuM5l5Tnrmd
92608 74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH1vI4gnPah1vlPNOePqc7nvQDs/nx
92609 fRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrPpx9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNC
92610 MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwa
92611 ivsnuL8wbqg7MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI
92612 eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u2dfOWBfoqSmu
92613 c0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHSv4ilf0X8rLiltTMMgsT7B/Zq
92614 5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTCwPTxGfARKbalGAKb12NMcIxHowNDXLldRqAN
92615 b/9Zjr7dn3LDWyvfjFvO5QxGbJKyCqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tN
92616 f1zuacpzEPuKqf2evTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi
92617 5Dp6Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIaGl6I6lD4
92618 WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeLeG9QgkRQP2YGiqtDhFZK
92619 DyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGy
92620 eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg==
92621 -----END CERTIFICATE-----
92622
92623 IdenTrust Commercial Root CA 1
92624 ==============================
92625 -----BEGIN CERTIFICATE-----
92626 MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG
92627 EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS
92628 b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES
92629 MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB
92630 IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld
92631 hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/
92632 mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi
92633 1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C
92634 XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl
92635 3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy
92636 NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV
92637 WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg
92638 xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix
92639 uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC
92640 AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI
92641 hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH
92642 6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg
92643 ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt
92644 ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV
92645 YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX
92646 feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro
92647 kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe
92648 2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz
92649 Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R
92650 cGzM7vRX+Bi6hG6H
92651 -----END CERTIFICATE-----
92652
92653 IdenTrust Public Sector Root CA 1
92654 =================================
92655 -----BEGIN CERTIFICATE-----
92656 MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG
92657 EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv
92658 ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV
92659 UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS
92660 b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy
92661 P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6
92662 Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI
92663 rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf
92664 qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS
92665 mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn
92666 ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh
92667 LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v
92668 iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL
92669 4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B
92670 Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw
92671 DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj
92672 t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A
92673 mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt
92674 GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt
92675 m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx
92676 NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4
92677 Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI
92678 ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC
92679 ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ
92680 3Wl9af0AVqW3rLatt8o+Ae+c
92681 -----END CERTIFICATE-----
92682
92683 Entrust Root Certification Authority - G2
92684 =========================================
92685 -----BEGIN CERTIFICATE-----
92686 MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV
92687 BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy
92688 bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug
92689 b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw
92690 HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT
92691 DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx
92692 OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s
92693 eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi
92694 MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP
92695 /vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz
92696 HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU
92697 s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y
92698 TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx
92699 AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6
92700 0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z
92701 iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ
92702 Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi
92703 nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+
92704 vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO
92705 e4pIb4tF9g==
92706 -----END CERTIFICATE-----
92707
92708 Entrust Root Certification Authority - EC1
92709 ==========================================
92710 -----BEGIN CERTIFICATE-----
92711 MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx
92712 FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn
92713 YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl
92714 ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
92715 IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw
92716 FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs
92717 LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg
92718 dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt
92719 IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy
92720 AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef
92721 9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
92722 FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h
92723 vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8
92724 kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G
92725 -----END CERTIFICATE-----
92726
92727 CFCA EV ROOT
92728 ============
92729 -----BEGIN CERTIFICATE-----
92730 MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE
92731 CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB
92732 IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw
92733 MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD
92734 DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV
92735 BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD
92736 7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN
92737 uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW
92738 ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7
92739 xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f
92740 py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K
92741 gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol
92742 hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ
92743 tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf
92744 BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
92745 /wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB
92746 ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q
92747 ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua
92748 4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG
92749 E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX
92750 BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn
92751 aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy
92752 PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX
92753 kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C
92754 ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su
92755 -----END CERTIFICATE-----
92756
92757 OISTE WISeKey Global Root GB CA
92758 ===============================
92759 -----BEGIN CERTIFICATE-----
92760 MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG
92761 EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl
92762 ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw
92763 MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD
92764 VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds
92765 b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX
92766 scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP
92767 rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk
92768 9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o
92769 Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg
92770 GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
92771 /zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI
92772 hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD
92773 dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0
92774 VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui
92775 HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic
92776 Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=
92777 -----END CERTIFICATE-----
92778
92779 SZAFIR ROOT CA2
92780 ===============
92781 -----BEGIN CERTIFICATE-----
92782 MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG
92783 A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV
92784 BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ
92785 BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD
92786 VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q
92787 qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK
92788 DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE
92789 2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ
92790 ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi
92791 ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
92792 AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC
92793 AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5
92794 O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67
92795 oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul
92796 4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6
92797 +/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw==
92798 -----END CERTIFICATE-----
92799
92800 Certum Trusted Network CA 2
92801 ===========================
92802 -----BEGIN CERTIFICATE-----
92803 MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE
92804 BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1
92805 bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y
92806 ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ
92807 TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl
92808 cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB
92809 IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9
92810 7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o
92811 CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b
92812 Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p
92813 uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130
92814 GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ
92815 9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB
92816 Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye
92817 hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM
92818 BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
92819 AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI
92820 hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW
92821 Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA
92822 L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo
92823 clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM
92824 pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb
92825 w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo
92826 J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm
92827 ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX
92828 is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7
92829 zAYspsbiDrW5viSP
92830 -----END CERTIFICATE-----
92831
92832 Hellenic Academic and Research Institutions RootCA 2015
92833 =======================================================
92834 -----BEGIN CERTIFICATE-----
92835 MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT
92836 BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0
92837 aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl
92838 YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx
92839 MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg
92840 QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV
92841 BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw
92842 MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv
92843 bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh
92844 iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+
92845 6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd
92846 FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr
92847 i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F
92848 GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2
92849 fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu
92850 iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc
92851 Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
92852 AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI
92853 hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+
92854 D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM
92855 d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y
92856 d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn
92857 82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb
92858 davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F
92859 Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt
92860 J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa
92861 JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q
92862 p/UsQu0yrbYhnr68
92863 -----END CERTIFICATE-----
92864
92865 Hellenic Academic and Research Institutions ECC RootCA 2015
92866 ===========================================================
92867 -----BEGIN CERTIFICATE-----
92868 MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0
92869 aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u
92870 cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj
92871 aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw
92872 MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj
92873 IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD
92874 VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290
92875 Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP
92876 dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK
92877 Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
92878 BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA
92879 GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn
92880 dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR
92881 -----END CERTIFICATE-----
92882
92883 ISRG Root X1
92884 ============
92885 -----BEGIN CERTIFICATE-----
92886 MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE
92887 BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD
92888 EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG
92889 EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT
92890 DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r
92891 Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1
92892 3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K
92893 b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN
92894 Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ
92895 4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf
92896 1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu
92897 hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH
92898 usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r
92899 OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G
92900 A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY
92901 9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
92902 ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV
92903 0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt
92904 hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw
92905 TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx
92906 e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA
92907 JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD
92908 YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n
92909 JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ
92910 m+kXQ99b21/+jh5Xos1AnX5iItreGCc=
92911 -----END CERTIFICATE-----
92912
92913 AC RAIZ FNMT-RCM
92914 ================
92915 -----BEGIN CERTIFICATE-----
92916 MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT
92917 AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw
92918 MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD
92919 TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
92920 ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf
92921 qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr
92922 btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL
92923 j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou
92924 08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw
92925 WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT
92926 tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ
92927 47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC
92928 ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa
92929 i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
92930 FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o
92931 dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD
92932 nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s
92933 D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ
92934 j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT
92935 Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW
92936 +YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7
92937 Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d
92938 8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm
92939 5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG
92940 rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM=
92941 -----END CERTIFICATE-----
92942
92943 Amazon Root CA 1
92944 ================
92945 -----BEGIN CERTIFICATE-----
92946 MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD
92947 VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1
92948 MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv
92949 bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
92950 ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH
92951 FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ
92952 gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t
92953 dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce
92954 VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB
92955 /zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3
92956 DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM
92957 CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy
92958 8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa
92959 2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2
92960 xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5
92961 -----END CERTIFICATE-----
92962
92963 Amazon Root CA 2
92964 ================
92965 -----BEGIN CERTIFICATE-----
92966 MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD
92967 VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1
92968 MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv
92969 bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
92970 ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4
92971 kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp
92972 N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9
92973 AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd
92974 fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx
92975 kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS
92976 btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0
92977 Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN
92978 c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+
92979 3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw
92980 DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA
92981 A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY
92982 +gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE
92983 YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW
92984 xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ
92985 gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW
92986 aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV
92987 Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3
92988 KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi
92989 JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw=
92990 -----END CERTIFICATE-----
92991
92992 Amazon Root CA 3
92993 ================
92994 -----BEGIN CERTIFICATE-----
92995 MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG
92996 EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy
92997 NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ
92998 MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB
92999 f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr
93000 Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43
93001 rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc
93002 eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw==
93003 -----END CERTIFICATE-----
93004
93005 Amazon Root CA 4
93006 ================
93007 -----BEGIN CERTIFICATE-----
93008 MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG
93009 EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy
93010 NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ
93011 MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN
93012 /sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri
93013 83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
93014 HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA
93015 MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1
93016 AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA==
93017 -----END CERTIFICATE-----
93018
93019 TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1
93020 =============================================
93021 -----BEGIN CERTIFICATE-----
93022 MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT
93023 D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr
93024 IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g
93025 TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp
93026 ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD
93027 VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt
93028 c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth
93029 bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11
93030 IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
93031 MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8
93032 6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc
93033 wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0
93034 3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9
93035 WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU
93036 ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
93037 KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh
93038 AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc
93039 lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R
93040 e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j
93041 q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=
93042 -----END CERTIFICATE-----
93043
93044 GDCA TrustAUTH R5 ROOT
93045 ======================
93046 -----BEGIN CERTIFICATE-----
93047 MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCQ04xMjAw
93048 BgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8wHQYDVQQD
93049 DBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVow
93050 YjELMAkGA1UEBhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ
93051 IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0B
93052 AQEFAAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJjDp6L3TQs
93053 AlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBjTnnEt1u9ol2x8kECK62p
93054 OqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+uKU49tm7srsHwJ5uu4/Ts765/94Y9cnrr
93055 pftZTqfrlYwiOXnhLQiPzLyRuEH3FMEjqcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ
93056 9Cy5WmYqsBebnh52nUpmMUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQ
93057 xXABZG12ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloPzgsM
93058 R6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3GkL30SgLdTMEZeS1SZ
93059 D2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeCjGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4
93060 oR24qoAATILnsn8JuLwwoC8N9VKejveSswoAHQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx
93061 9hoh49pwBiFYFIeFd3mqgnkCAwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlR
93062 MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg
93063 p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZmDRd9FBUb1Ov9
93064 H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5COmSdI31R9KrO9b7eGZONn35
93065 6ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ryL3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd
93066 +PwyvzeG5LuOmCd+uh8W4XAR8gPfJWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQ
93067 HtZa37dG/OaG+svgIHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBD
93068 F8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ
93069 8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQXR4EzzffHqhmsYzmIGrv
93070 /EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrqT8p+ck0LcIymSLumoRT2+1hEmRSuqguT
93071 aaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g==
93072 -----END CERTIFICATE-----
93073
93074 TrustCor RootCert CA-1
93075 ======================
93076 -----BEGIN CERTIFICATE-----
93077 MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYDVQQGEwJQQTEP
93078 MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig
93079 U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp
93080 dHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkx
93081 MjMxMTcyMzE2WjCBpDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFu
93082 YW1hIENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUGA1UECwwe
93083 VHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZUcnVzdENvciBSb290Q2Vy
93084 dCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv463leLCJhJrMxnHQFgKq1mq
93085 jQCj/IDHUHuO1CAmujIS2CNUSSUQIpidRtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4
93086 pQa81QBeCQryJ3pS/C3Vseq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0
93087 JEsq1pme9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CVEY4h
93088 gLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorWhnAbJN7+KIor0Gqw
93089 /Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/DeOxCbeKyKsZn3MzUOcwHwYDVR0j
93090 BBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
93091 AYYwDQYJKoZIhvcNAQELBQADggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5
93092 mDo4Nvu7Zp5I/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf
93093 ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZyonnMlo2HD6C
93094 qFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djtsL1Ac59v2Z3kf9YKVmgenFK+P
93095 3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdNzl/HHk484IkzlQsPpTLWPFp5LBk=
93096 -----END CERTIFICATE-----
93097
93098 TrustCor RootCert CA-2
93099 ======================
93100 -----BEGIN CERTIFICATE-----
93101 MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNVBAYTAlBBMQ8w
93102 DQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQwIgYDVQQKDBtUcnVzdENvciBT
93103 eXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0
93104 eTEfMB0GA1UEAwwWVHJ1c3RDb3IgUm9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEy
93105 MzExNzI2MzlaMIGkMQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5h
93106 bWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U
93107 cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0
93108 IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnIG7CKqJiJJWQdsg4foDSq8Gb
93109 ZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9Nk
93110 RvRUqdw6VC0xK5mC8tkq1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1
93111 oYxOdqHp2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nKDOOb
93112 XUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hapeaz6LMvYHL1cEksr1
93113 /p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF3wP+TfSvPd9cW436cOGlfifHhi5q
93114 jxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQP
93115 eSghYA2FFn3XVDjxklb9tTNMg9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+Ctg
93116 rKAmrhQhJ8Z3mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh
93117 8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAdBgNVHQ4EFgQU
93118 2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6UnrybPZx9mCAZ5YwwYrIwDwYD
93119 VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/h
93120 Osh80QA9z+LqBrWyOrsGS2h60COXdKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnp
93121 kpfbsEZC89NiqpX+MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv
93122 2wnL/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RXCI/hOWB3
93123 S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYaZH9bDTMJBzN7Bj8RpFxw
93124 PIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dv
93125 DDqPys/cA8GiCcjl/YBeyGBCARsaU1q7N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYU
93126 RpFHmygk71dSTlxCnKr3Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANE
93127 xdqtvArBAs8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp5KeX
93128 RKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu1uwJ
93129 -----END CERTIFICATE-----
93130
93131 TrustCor ECA-1
93132 ==============
93133 -----BEGIN CERTIFICATE-----
93134 MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYDVQQGEwJQQTEP
93135 MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig
93136 U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp
93137 dHkxFzAVBgNVBAMMDlRydXN0Q29yIEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3Mjgw
93138 N1owgZwxCzAJBgNVBAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5
93139 MSQwIgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29y
93140 IENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3IgRUNBLTEwggEiMA0GCSqG
93141 SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb3w9U73NjKYKtR8aja+3+XzP4Q1HpGjOR
93142 MRegdMTUpwHmspI+ap3tDvl0mEDTPwOABoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23
93143 xFUfJ3zSCNV2HykVh0A53ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmc
93144 p0yJF4OuowReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/wZ0+
93145 fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZFZtS6mFjBAgMBAAGj
93146 YzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAfBgNVHSMEGDAWgBREnkj1zG1I1KBL
93147 f/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF
93148 AAOCAQEABT41XBVwm8nHc2FvcivUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u
93149 /ukZMjgDfxT2AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F
93150 hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50soIipX1TH0Xs
93151 J5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BIWJZpTdwHjFGTot+fDz2LYLSC
93152 jaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1WitJ/X5g==
93153 -----END CERTIFICATE-----
93154
93155 SSL.com Root Certification Authority RSA
93156 ========================================
93157 -----BEGIN CERTIFICATE-----
93158 MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxDjAM
93159 BgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24x
93160 MTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYw
93161 MjEyMTczOTM5WhcNNDEwMjEyMTczOTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx
93162 EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NM
93163 LmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcNAQEBBQAD
93164 ggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2RxFdHaxh3a3by/ZPkPQ/C
93165 Fp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aXqhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8
93166 P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcCC52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/ge
93167 oeOy3ZExqysdBP+lSgQ36YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkp
93168 k8zruFvh/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrFYD3Z
93169 fBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93EJNyAKoFBbZQ+yODJ
93170 gUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVcUS4cK38acijnALXRdMbX5J+tB5O2
93171 UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi8
93172 1xtZPCvM8hnIk2snYxnP/Okm+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4s
93173 bE6x/c+cCbqiM+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV
93174 HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4GA1UdDwEB/wQE
93175 AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGVcpNxJK1ok1iOMq8bs3AD/CUr
93176 dIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBcHadm47GUBwwyOabqG7B52B2ccETjit3E+ZUf
93177 ijhDPwGFpUenPUayvOUiaPd7nNgsPgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAsl
93178 u1OJD7OAUN5F7kR/q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjq
93179 erQ0cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jra6x+3uxj
93180 MxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90IH37hVZkLId6Tngr75qNJ
93181 vTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/YK9f1JmzJBjSWFupwWRoyeXkLtoh/D1JI
93182 Pb9s2KJELtFOt3JY04kTlf5Eq/jXixtunLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406y
93183 wKBjYZC6VWg3dGq2ktufoYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NI
93184 WuuA8ShYIc2wBlX7Jz9TkHCpBB5XJ7k=
93185 -----END CERTIFICATE-----
93186
93187 SSL.com Root Certification Authority ECC
93188 ========================================
93189 -----BEGIN CERTIFICATE-----
93190 MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCVVMxDjAMBgNV
93191 BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xMTAv
93192 BgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEy
93193 MTgxNDAzWhcNNDEwMjEyMTgxNDAzWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO
93194 BgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv
93195 bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA
93196 BEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI7Z4INcgn64mMU1jrYor+
93197 8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPgCemB+vNH06NjMGEwHQYDVR0OBBYEFILR
93198 hXMw5zUE044CkvvlpNHEIejNMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTT
93199 jgKS++Wk0cQh6M0wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCW
93200 e+0F+S8Tkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+gA0z
93201 5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl
93202 -----END CERTIFICATE-----
93203
93204 SSL.com EV Root Certification Authority RSA R2
93205 ==============================================
93206 -----BEGIN CERTIFICATE-----
93207 MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMQ4w
93208 DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9u
93209 MTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy
93210 MB4XDTE3MDUzMTE4MTQzN1oXDTQyMDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI
93211 DAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYD
93212 VQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMIICIjAN
93213 BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvqM0fNTPl9fb69LT3w23jh
93214 hqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssufOePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7w
93215 cXHswxzpY6IXFJ3vG2fThVUCAtZJycxa4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTO
93216 Zw+oz12WGQvE43LrrdF9HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+
93217 B6KjBSYRaZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcAb9Zh
93218 CBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQGp8hLH94t2S42Oim
93219 9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQVPWKchjgGAGYS5Fl2WlPAApiiECto
93220 RHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMOpgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+Slm
93221 JuwgUHfbSguPvuUCYHBBXtSuUDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48
93222 +qvWBkofZ6aYMBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV
93223 HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa49QaAJadz20Zp
93224 qJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBWs47LCp1Jjr+kxJG7ZhcFUZh1
93225 ++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nx
93226 Y/hoLVUE0fKNsKTPvDxeH3jnpaAgcLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2G
93227 guDKBAdRUNf/ktUM79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDz
93228 OFSz/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXtll9ldDz7
93229 CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEmKf7GUmG6sXP/wwyc5Wxq
93230 lD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKKQbNmC1r7fSOl8hqw/96bg5Qu0T/fkreR
93231 rwU7ZcegbLHNYhLDkBvjJc40vG93drEQw/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1
93232 hlMYegouCRw2n5H9gooiS9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX
93233 9hwJ1C07mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w==
93234 -----END CERTIFICATE-----
93235
93236 SSL.com EV Root Certification Authority ECC
93237 ===========================================
93238 -----BEGIN CERTIFICATE-----
93239 MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMCVVMxDjAMBgNV
93240 BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAy
93241 BgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYw
93242 MjEyMTgxNTIzWhcNNDEwMjEyMTgxNTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx
93243 EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NM
93244 LmNvbSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB
93245 BAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMAVIbc/R/fALhBYlzccBYy
93246 3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1KthkuWnBaBu2+8KGwytAJKaNjMGEwHQYDVR0O
93247 BBYEFFvKXuXe0oGqzagtZFG22XKbl+ZPMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe
93248 5d7SgarNqC1kUbbZcpuX5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJ
93249 N+vp1RPZytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZgh5Mm
93250 m7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg==
93251 -----END CERTIFICATE-----
93252
93253 GlobalSign Root CA - R6
93254 =======================
93255 -----BEGIN CERTIFICATE-----
93256 MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEgMB4GA1UECxMX
93257 R2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds
93258 b2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQxMjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9i
93259 YWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFs
93260 U2lnbjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQss
93261 grRIxutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1kZguSgMpE
93262 3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxDaNc9PIrFsmbVkJq3MQbF
93263 vuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJwLnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqM
93264 PKq0pPbzlUoSB239jLKJz9CgYXfIWHSw1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+
93265 azayOeSsJDa38O+2HBNXk7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05O
93266 WgtH8wY2SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/hbguy
93267 CLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4nWUx2OVvq+aWh2IMP
93268 0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpYrZxCRXluDocZXFSxZba/jJvcE+kN
93269 b7gu3GduyYsRtYQUigAZcIN5kZeR1BonvzceMgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQE
93270 AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNV
93271 HSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN
93272 nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGtIxg93eFyRJa0
93273 lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr6155wsTLxDKZmOMNOsIeDjHfrY
93274 BzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLjvUYAGm0CuiVdjaExUd1URhxN25mW7xocBFym
93275 Fe944Hn+Xds+qkxV/ZoVqW/hpvvfcDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr
93276 3TsTjxKM4kEaSHpzoHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB1
93277 0jZpnOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfspA9MRf/T
93278 uTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+vJJUEeKgDu+6B5dpffItK
93279 oZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+t
93280 JDfLRVpOoERIyNiwmcUVhAn21klJwGW45hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=
93281 -----END CERTIFICATE-----
93282
93283 OISTE WISeKey Global Root GC CA
93284 ===============================
93285 -----BEGIN CERTIFICATE-----
93286 MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQswCQYDVQQGEwJD
93287 SDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEo
93288 MCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRa
93289 Fw00MjA1MDkwOTU4MzNaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQL
93290 ExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh
93291 bCBSb290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4nieUqjFqdr
93292 VCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4Wp2OQ0jnUsYd4XxiWD1Ab
93293 NTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd
93294 BgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7TrYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0E
93295 AwMDaAAwZQIwJsdpW9zV57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtk
93296 AjEA2zQgMgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9
93297 -----END CERTIFICATE-----
93298
93299 GTS Root R1
93300 ===========
93301 -----BEGIN CERTIFICATE-----
93302 MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQG
93303 EwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJv
93304 b3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAG
93305 A1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIi
93306 MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx
93307 9vaMf/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7wCl7r
93308 aKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjwTcLCeoiKu7rPWRnW
93309 r4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0PfyblqAj+lug8aJRT7oM6iCsVlgmy4HqM
93310 LnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly
93311 4cpk9+aCEI3oncKKiPo4Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr
93312 06zqkUspzBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92
93313 wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70paDPvOmbsB4om
93314 3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrNVjzRlwW5y0vtOUucxD/SVRNu
93315 JLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD
93316 VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEM
93317 BQADggIBADiWCu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1
93318 d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6ZXPYfcX3v73sv
93319 fuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZRgyFmxhE+885H7pwoHyXa/6xm
93320 ld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9b
93321 gsiG1eGZbYwE8na6SfZu6W0eX6DvJ4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq
93322 4BjFbkerQUIpm/ZgDdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWEr
93323 tXvM+SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyyF62ARPBo
93324 pY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9SQ98POyDGCBDTtWTurQ0
93325 sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdwsE3PYJ/HQcu51OyLemGhmW/HGY0dVHLql
93326 CFF1pkgl
93327 -----END CERTIFICATE-----
93328
93329 GTS Root R2
93330 ===========
93331 -----BEGIN CERTIFICATE-----
93332 MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQG
93333 EwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJv
93334 b3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAG
93335 A1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIi
93336 MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTuk
93337 k3LvCvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY6Dlo
93338 7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAuMC6C/Pq8tBcKSOWI
93339 m8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7kRXuJVfeKH2JShBKzwkCX44ofR5Gm
93340 dFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbu
93341 ak7MkogwTZq9TwtImoS1mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscsz
93342 cTJGr61K8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW
93343 Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKaG73Vululycsl
93344 aVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCqgc7dGtxRcw1PcOnlthYhGXmy
93345 5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD
93346 VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEM
93347 BQADggIBALZp8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT
93348 vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiTz9D2PGcDFWEJ
93349 +YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiApJiS4wGWAqoC7o87xdFtCjMw
93350 c3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvbpxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3Da
93351 WsYDQvTtN6LwG1BUSw7YhN4ZKJmBR64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5r
93352 n/WkhLx3+WuXrD5RRaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56Gtmwfu
93353 Nmsk0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC5AwiWVIQ
93354 7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiFizoHCBy69Y9Vmhh1fuXs
93355 gWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLnyOd/xCxgXS/Dr55FBcOEArf9LAhST4Ld
93356 o/DUhgkC
93357 -----END CERTIFICATE-----
93358
93359 GTS Root R3
93360 ===========
93361 -----BEGIN CERTIFICATE-----
93362 MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJV
93363 UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg
93364 UjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE
93365 ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcq
93366 hkjOPQIBBgUrgQQAIgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUU
93367 Rout736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL24Cej
93368 QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTB8Sa6oC2uhYHP
93369 0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFukfCPAlaUs3L6JbyO5o91lAFJekazInXJ0
93370 glMLfalAvWhgxeG4VDvBNhcl2MG9AjEAnjWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOa
93371 KaqW04MjyaR7YbPMAuhd
93372 -----END CERTIFICATE-----
93373
93374 GTS Root R4
93375 ===========
93376 -----BEGIN CERTIFICATE-----
93377 MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJV
93378 UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg
93379 UjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE
93380 ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcq
93381 hkjOPQIBBgUrgQQAIgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa
93382 6zzuhXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvRHYqj
93383 QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSATNbrdP9JNqPV
93384 2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0CMRw3J5QdCHojXohw0+WbhXRIjVhLfoI
93385 N+4Zba3bssx9BzT1YBkstTTZbyACMANxsbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11x
93386 zPKwTdb+mciUqXWi4w==
93387 -----END CERTIFICATE-----
93388
93389 UCA Global G2 Root
93390 ==================
93391 -----BEGIN CERTIFICATE-----
93392 MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQG
93393 EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBHbG9iYWwgRzIgUm9vdDAeFw0x
93394 NjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0xCzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlU
93395 cnVzdDEbMBkGA1UEAwwSVUNBIEdsb2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
93396 MIICCgKCAgEAxeYrb3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmT
93397 oni9kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzmVHqUwCoV
93398 8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/RVogvGjqNO7uCEeBHANBS
93399 h6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDcC/Vkw85DvG1xudLeJ1uK6NjGruFZfc8o
93400 LTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIjtm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/
93401 R+zvWr9LesGtOxdQXGLYD0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBe
93402 KW4bHAyvj5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6DlNaBa
93403 4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6iIis7nCs+dwp4wwc
93404 OxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznPO6Q0ibd5Ei9Hxeepl2n8pndntd97
93405 8XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
93406 BBYEFIHEjMz15DD/pQwIX4wVZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo
93407 5sOASD0Ee/ojL3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5
93408 1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl1qnN3e92mI0A
93409 Ds0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oUb3n09tDh05S60FdRvScFDcH9
93410 yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LVPtateJLbXDzz2K36uGt/xDYotgIVilQsnLAX
93411 c47QN6MUPJiVAAwpBVueSUmxX8fjy88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHo
93412 jhJi6IjMtX9Gl8CbEGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZk
93413 bxqgDMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI+Vg7RE+x
93414 ygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGyYiGqhkCyLmTTX8jjfhFn
93415 RR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bXUB+K+wb1whnw0A==
93416 -----END CERTIFICATE-----
93417
93418 UCA Extended Validation Root
93419 ============================
93420 -----BEGIN CERTIFICATE-----
93421 MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQG
93422 EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9u
93423 IFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMxMDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8G
93424 A1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIi
93425 MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrs
93426 iWogD4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvSsPGP2KxF
93427 Rv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aopO2z6+I9tTcg1367r3CTu
93428 eUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dksHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR
93429 59mzLC52LqGj3n5qiAno8geK+LLNEOfic0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH
93430 0mK1lTnj8/FtDw5lhIpjVMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KR
93431 el7sFsLzKuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/TuDv
93432 B0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41Gsx2VYVdWf6/wFlth
93433 WG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs1+lvK9JKBZP8nm9rZ/+I8U6laUpS
93434 NwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQDfwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS
93435 3H5aBZ8eNJr34RQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL
93436 BQADggIBADaNl8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR
93437 ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQVBcZEhrxH9cM
93438 aVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5c6sq1WnIeJEmMX3ixzDx/BR4
93439 dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb
93440 +7lsq+KePRXBOy5nAliRn+/4Qh8st2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOW
93441 F3sGPjLtx7dCvHaj2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwi
93442 GpWOvpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2CxR9GUeOc
93443 GMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmxcmtpzyKEC2IPrNkZAJSi
93444 djzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbMfjKaiJUINlK73nZfdklJrX+9ZSCyycEr
93445 dhh2n1ax
93446 -----END CERTIFICATE-----
93447
93448 Certigna Root CA
93449 ================
93450 -----BEGIN CERTIFICATE-----
93451 MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UE
93452 BhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAwMiA0ODE0NjMwODEwMDAzNjEZ
93453 MBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0xMzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjda
93454 MFoxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYz
93455 MDgxMDAwMzYxGTAXBgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC
93456 DwAwggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sOty3tRQgX
93457 stmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9MCiBtnyN6tMbaLOQdLNyz
93458 KNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPuI9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8
93459 JXrJhFwLrN1CTivngqIkicuQstDuI7pmTLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16
93460 XdG+RCYyKfHx9WzMfgIhC59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq
93461 4NYKpkDfePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3YzIoej
93462 wpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWTCo/1VTp2lc5ZmIoJ
93463 lXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1kJWumIWmbat10TWuXekG9qxf5kBdI
93464 jzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp/
93465 /TBt2dzhauH8XwIDAQABo4IBGjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
93466 HQYDVR0OBBYEFBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of
93467 1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczovL3d3d3cuY2Vy
93468 dGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilodHRwOi8vY3JsLmNlcnRpZ25h
93469 LmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYraHR0cDovL2NybC5kaGlteW90aXMuY29tL2Nl
93470 cnRpZ25hcm9vdGNhLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOIt
93471 OoldaDgvUSILSo3L6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxP
93472 TGRGHVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH60BGM+RFq
93473 7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncBlA2c5uk5jR+mUYyZDDl3
93474 4bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdio2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd
93475 8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS
93476 6Cvu5zHbugRqh5jnxV/vfaci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaY
93477 tlu3zM63Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayhjWZS
93478 aX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw3kAP+HwV96LOPNde
93479 E4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0=
93480 -----END CERTIFICATE-----
93481
93482 emSign Root CA - G1
93483 ===================
93484 -----BEGIN CERTIFICATE-----
93485 MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJJTjET
93486 MBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl
93487 ZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBHMTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgx
93488 ODMwMDBaMGcxCzAJBgNVBAYTAklOMRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVk
93489 aHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIB
93490 IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQzf2N4aLTN
93491 LnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO8oG0x5ZOrRkVUkr+PHB1
93492 cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aqd7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHW
93493 DV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhMtTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ
93494 6DqS0hdW5TUaQBw+jSztOd9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrH
93495 hQIDAQABo0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQDAgEG
93496 MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31xPaOfG1vR2vjTnGs2
93497 vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjMwiI/aTvFthUvozXGaCocV685743Q
93498 NcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6dGNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q
93499 +Mri/Tm3R7nrft8EI6/6nAYH6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeih
93500 U80Bv2noWgbyRQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx
93501 iN66zB+Afko=
93502 -----END CERTIFICATE-----
93503
93504 emSign ECC Root CA - G3
93505 =======================
93506 -----BEGIN CERTIFICATE-----
93507 MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQGEwJJTjETMBEG
93508 A1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg
93509 MB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4
93510 MTgzMDAwWjBrMQswCQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11
93511 ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g
93512 RzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0WXTsuwYc
93513 58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xySfvalY8L1X44uT6EYGQIr
93514 MgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuBzhccLikenEhjQjAOBgNVHQ8BAf8EBAMC
93515 AQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+D
93516 CBeQyh+KTOgNG3qxrdWBCUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7
93517 jHvrZQnD+JbNR6iC8hZVdyR+EhCVBCyj
93518 -----END CERTIFICATE-----
93519
93520 emSign Root CA - C1
93521 ===================
93522 -----BEGIN CERTIFICATE-----
93523 MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCVVMx
93524 EzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNp
93525 Z24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UE
93526 BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQD
93527 ExNlbVNpZ24gUm9vdCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+up
93528 ufGZBczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZHdPIWoU/
93529 Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH3DspVpNqs8FqOp099cGX
93530 OFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvHGPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4V
93531 I5b2P/AgNBbeCsbEBEV5f6f9vtKppa+cxSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleooms
93532 lMuoaJuvimUnzYnu3Yy1aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+
93533 XJGFehiqTbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD
93534 ggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87/kOXSTKZEhVb3xEp
93535 /6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4kqNPEjE2NuLe/gDEo2APJ62gsIq1
93536 NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrGYQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9
93537 wC68AivTxEDkigcxHpvOJpkT+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQ
93538 BmIMMMAVSKeoWXzhriKi4gp6D/piq1JM4fHfyr6DDUI=
93539 -----END CERTIFICATE-----
93540
93541 emSign ECC Root CA - C3
93542 =======================
93543 -----BEGIN CERTIFICATE-----
93544 MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQGEwJVUzETMBEG
93545 A1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxIDAeBgNVBAMTF2VtU2lnbiBF
93546 Q0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UE
93547 BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQD
93548 ExdlbVNpZ24gRUNDIFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd
93549 6bciMK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4OjavtisIGJAnB9
93550 SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0OBBYEFPtaSNCAIEDyqOkA
93551 B2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gA
93552 MGUCMQC02C8Cif22TGK6Q04ThHK1rt0c3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwU
93553 ZOR8loMRnLDRWmFLpg9J0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ==
93554 -----END CERTIFICATE-----
93555
93556 Hongkong Post Root CA 3
93557 =======================
93558 -----BEGIN CERTIFICATE-----
93559 MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQELBQAwbzELMAkG
93560 A1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJSG9uZyBLb25nMRYwFAYDVQQK
93561 Ew1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25na29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2
93562 MDMwMjI5NDZaFw00MjA2MDMwMjI5NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtv
93563 bmcxEjAQBgNVBAcTCUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMX
93564 SG9uZ2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz
93565 iNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFOdem1p+/l6TWZ5Mwc50tf
93566 jTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mIVoBc+L0sPOFMV4i707mV78vH9toxdCim
93567 5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOe
93568 sL4jpNrcyCse2m5FHomY2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj
93569 0mRiikKYvLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+TtbNe/
93570 JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZbx39ri1UbSsUgYT2u
93571 y1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+l2oBlKN8W4UdKjk60FSh0Tlxnf0h
93572 +bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YKTE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsG
93573 xVd7GYYKecsAyVKvQv83j+GjHno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwID
93574 AQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e
93575 i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEwDQYJKoZIhvcN
93576 AQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG7BJ8dNVI0lkUmcDrudHr9Egw
93577 W62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCkMpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWld
93578 y8joRTnU+kLBEUx3XZL7av9YROXrgZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov
93579 +BS5gLNdTaqX4fnkGMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDc
93580 eqFS3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJmOzj/2ZQw
93581 9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+l6mc1X5VTMbeRRAc6uk7
93582 nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6cJfTzPV4e0hz5sy229zdcxsshTrD3mUcY
93583 hcErulWuBurQB7Lcq9CClnXO0lD+mefPL5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB
93584 60PZ2Pierc+xYw5F9KBaLJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fq
93585 dBb9HxEGmpv0
93586 -----END CERTIFICATE-----
93587
93588 Entrust Root Certification Authority - G4
93589 =========================================
93590 -----BEGIN CERTIFICATE-----
93591 MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAwgb4xCzAJBgNV
93592 BAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3Qu
93593 bmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1
93594 dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1
93595 dGhvcml0eSAtIEc0MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYT
93596 AlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0
93597 L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhv
93598 cml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhv
93599 cml0eSAtIEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3D
93600 umSXbcr3DbVZwbPLqGgZ2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV
93601 3imz/f3ET+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j5pds
93602 8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAMC1rlLAHGVK/XqsEQ
93603 e9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73TDtTUXm6Hnmo9RR3RXRv06QqsYJn7
93604 ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNXwbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5X
93605 xNMhIWNlUpEbsZmOeX7m640A2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV
93606 7rtNOzK+mndmnqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8
93607 dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwlN4y6mACXi0mW
93608 Hv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNjc0kCAwEAAaNCMEAwDwYDVR0T
93609 AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9n
93610 MA0GCSqGSIb3DQEBCwUAA4ICAQAS5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4Q
93611 jbRaZIxowLByQzTSGwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht
93612 7LGrhFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/B7NTeLUK
93613 YvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uIAeV8KEsD+UmDfLJ/fOPt
93614 jqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbwH5Lk6rWS02FREAutp9lfx1/cH6NcjKF+
93615 m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKW
93616 RGhXxNUzzxkvFMSUHHuk2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjA
93617 JOgc47OlIQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk5F6G
93618 +TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuYn/PIjhs4ViFqUZPT
93619 kcpG2om3PVODLAgfi49T3f+sHw==
93620 -----END CERTIFICATE-----
93621
93622 Microsoft ECC Root Certificate Authority 2017
93623 =============================================
93624 -----BEGIN CERTIFICATE-----
93625 MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV
93626 UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQgRUND
93627 IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4
93628 MjMxNjA0WjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw
93629 NAYDVQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQ
93630 BgcqhkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZRogPZnZH6
93631 thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYbhGBKia/teQ87zvH2RPUB
93632 eMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIy5lycFIM
93633 +Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlf
93634 Xu5gKcs68tvWMoQZP3zVL8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaR
93635 eNtUjGUBiudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M=
93636 -----END CERTIFICATE-----
93637
93638 Microsoft RSA Root Certificate Authority 2017
93639 =============================================
93640 -----BEGIN CERTIFICATE-----
93641 MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQG
93642 EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQg
93643 UlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIw
93644 NzE4MjMwMDIzWjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u
93645 MTYwNAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcw
93646 ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZNt9GkMml
93647 7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0ZdDMbRnMlfl7rEqUrQ7e
93648 S0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw7
93649 1VdyvD/IybLeS2v4I2wDwAW9lcfNcztmgGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+
93650 dkC0zVJhUXAoP8XFWvLJjEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49F
93651 yGcohJUcaDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaGYaRS
93652 MLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6W6IYZVcSn2i51BVr
93653 lMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4KUGsTuqwPN1q3ErWQgR5WrlcihtnJ
93654 0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJ
93655 ClTUFLkqqNfs+avNJVgyeY+QW5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYw
93656 DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC
93657 NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZCLgLNFgVZJ8og
93658 6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OCgMNPOsduET/m4xaRhPtthH80
93659 dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk
93660 +ONVFT24bcMKpBLBaYVu32TxU5nhSnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex
93661 /2kskZGT4d9Mozd2TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDy
93662 AmH3pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGRxpl/j8nW
93663 ZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiAppGWSZI1b7rCoucL5mxAyE
93664 7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKT
93665 c0QWbej09+CVgI+WXTik9KveCjCHk9hNAHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D
93666 5KbvtwEwXlGjefVwaaZBRA+GsCyRxj3qrg+E
93667 -----END CERTIFICATE-----
93668
93669 e-Szigno Root CA 2017
93670 =====================
93671 -----BEGIN CERTIFICATE-----
93672 MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNVBAYTAkhVMREw
93673 DwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUt
93674 MjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJvb3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZa
93675 Fw00MjA4MjIxMjA3MDZaMHExCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UE
93676 CgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3pp
93677 Z25vIFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtvxie+RJCx
93678 s1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+HWyx7xf58etqjYzBhMA8G
93679 A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSHERUI0arBeAyxr87GyZDv
93680 vzAEwDAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEA
93681 tVfd14pVCzbhhkT61NlojbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxO
93682 svxyqltZ+efcMQ==
93683 -----END CERTIFICATE-----
93684
93685 certSIGN Root CA G2
93686 ===================
93687 -----BEGIN CERTIFICATE-----
93688 MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNVBAYTAlJPMRQw
93689 EgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjAeFw0xNzAy
93690 MDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJBgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lH
93691 TiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
93692 ADCCAgoCggIBAMDFdRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05
93693 N0IwvlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZuIt4Imfk
93694 abBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhpn+Sc8CnTXPnGFiWeI8Mg
93695 wT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKscpc/I1mbySKEwQdPzH/iV8oScLumZfNp
93696 dWO9lfsbl83kqK/20U6o2YpxJM02PbyWxPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91Qqh
93697 ngLjYl/rNUssuHLoPj1PrCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732
93698 jcZZroiFDsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fxDTvf
93699 95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgyLcsUDFDYg2WD7rlc
93700 z8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6CeWRgKRM+o/1Pcmqr4tTluCRVLERL
93701 iohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1Ud
93702 DgQWBBSCIS1mxteg4BXrzkwJd8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOB
93703 ywaK8SJJ6ejqkX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC
93704 b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQlqiCA2ClV9+BB
93705 /AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0OJD7uNGzcgbJceaBxXntC6Z5
93706 8hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+cNywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5
93707 BiKDUyUM/FHE5r7iOZULJK2v0ZXkltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklW
93708 atKcsWMy5WHgUyIOpwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tU
93709 Sxfj03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZkPuXaTH4M
93710 NMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE1LlSVHJ7liXMvGnjSG4N
93711 0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MXQRBdJ3NghVdJIgc=
93712 -----END CERTIFICATE-----
93713
93714 Trustwave Global Certification Authority
93715 ========================================
93716 -----BEGIN CERTIFICATE-----
93717 MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJV
93718 UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2
93719 ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u
93720 IEF1dGhvcml0eTAeFw0xNzA4MjMxOTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJV
93721 UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2
93722 ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u
93723 IEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALldUShLPDeS0YLOvR29
93724 zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0XznswuvCAAJWX/NKSqIk4cXGIDtiLK0thAf
93725 LdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4Bq
93726 stTnoApTAbqOl5F2brz81Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9o
93727 WN0EACyW80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotPJqX+
93728 OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1lRtzuzWniTY+HKE40
93729 Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfwhI0Vcnyh78zyiGG69Gm7DIwLdVcE
93730 uE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm
93731 +9jaJXLE9gCxInm943xZYkqcBW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqj
93732 ifLJS3tBEW1ntwiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud
93733 EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1UdDwEB/wQEAwIB
93734 BjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W0OhUKDtkLSGm+J1WE2pIPU/H
93735 PinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfeuyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0H
93736 ZJDmHvUqoai7PF35owgLEQzxPy0QlG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla
93737 4gt5kNdXElE1GYhBaCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5R
93738 vbbEsLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPTMaCm/zjd
93739 zyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qequ5AvzSxnI9O4fKSTx+O
93740 856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxhVicGaeVyQYHTtgGJoC86cnn+OjC/QezH
93741 Yj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu
93742 3R3y4G5OBVixwJAWKqQ9EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP
93743 29FpHOTKyeC2nOnOcXHebD8WpHk=
93744 -----END CERTIFICATE-----
93745
93746 Trustwave Global ECC P256 Certification Authority
93747 =================================================
93748 -----BEGIN CERTIFICATE-----
93749 MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYDVQQGEwJVUzER
93750 MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI
93751 b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZp
93752 Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYD
93753 VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy
93754 dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1
93755 NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABH77bOYj
93756 43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoNFWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqm
93757 P62jQzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt
93758 0UrrdaVKEJmzsaGLSvcwCgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjz
93759 RM4q3wghDDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7
93760 -----END CERTIFICATE-----
93761
93762 Trustwave Global ECC P384 Certification Authority
93763 =================================================
93764 -----BEGIN CERTIFICATE-----
93765 MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYDVQQGEwJVUzER
93766 MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI
93767 b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZp
93768 Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYD
93769 VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy
93770 dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4
93771 NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuBBAAiA2IABGvaDXU1CDFH
93772 Ba5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJj9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr
93773 /TklZvFe/oyujUF5nQlgziip04pt89ZF1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNV
93774 HQ8BAf8EBQMDBwYAMB0GA1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNn
93775 ADBkAjA3AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsCMGcl
93776 CrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVuSw==
93777 -----END CERTIFICATE-----
93778 <?php
93779
93780 if (PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg') {
93781     echo 'Warning: Composer should be invoked via the CLI version of PHP, not the '.PHP_SAPI.' SAPI'.PHP_EOL;
93782 }
93783
93784 setlocale(LC_ALL, 'C');
93785 require __DIR__.'/../src/bootstrap.php';
93786
93787 use Composer\Console\Application;
93788 use Composer\XdebugHandler\XdebugHandler;
93789
93790 error_reporting(-1);
93791
93792 // Restart without Xdebug
93793 $xdebug = new XdebugHandler('Composer', '--ansi');
93794 $xdebug->check();
93795 unset($xdebug);
93796
93797 if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '4.0', '>=')) {
93798     echo 'HHVM 4.0 has dropped support for Composer, please use PHP instead. Aborting.'.PHP_EOL;
93799     exit(1);
93800 }
93801
93802 if (function_exists('ini_set')) {
93803     @ini_set('display_errors', 1);
93804
93805     $memoryInBytes = function ($value) {
93806         $unit = strtolower(substr($value, -1, 1));
93807         $value = (int) $value;
93808         switch($unit) {
93809             case 'g':
93810                 $value *= 1024;
93811                 // no break (cumulative multiplier)
93812             case 'm':
93813                 $value *= 1024;
93814                 // no break (cumulative multiplier)
93815             case 'k':
93816                 $value *= 1024;
93817         }
93818
93819         return $value;
93820     };
93821
93822     $memoryLimit = trim(ini_get('memory_limit'));
93823     // Increase memory_limit if it is lower than 1.5GB
93824     if ($memoryLimit != -1 && $memoryInBytes($memoryLimit) < 1024 * 1024 * 1536) {
93825         @ini_set('memory_limit', '1536M');
93826     }
93827     // Set user defined memory limit
93828     if ($memoryLimit = getenv('COMPOSER_MEMORY_LIMIT')) {
93829         @ini_set('memory_limit', $memoryLimit);
93830     }
93831     unset($memoryInBytes, $memoryLimit);
93832 }
93833
93834 putenv('COMPOSER_BINARY='.realpath($_SERVER['argv'][0]));
93835
93836 // run the command application
93837 $application = new Application();
93838 $application->run();
93839
93840 Copyright (c) Nils Adermann, Jordi Boggiano
93841
93842 Permission is hereby granted, free of charge, to any person obtaining a copy
93843 of this software and associated documentation files (the "Software"), to deal
93844 in the Software without restriction, including without limitation the rights
93845 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
93846 copies of the Software, and to permit persons to whom the Software is furnished
93847 to do so, subject to the following conditions:
93848
93849 The above copyright notice and this permission notice shall be included in all
93850 copies or substantial portions of the Software.
93851
93852 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
93853 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
93854 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
93855 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
93856 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
93857 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
93858 THE SOFTWARE.
93859
93860 H\ 2¼ìå\1aM?I\ 6\ 4\80Yñ)\9dÉ\0\ 2\0\0\0GBMB