* Jordi Boggiano * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Composer\Autoload; use Composer\ClassMapGenerator\ClassMap; use Composer\ClassMapGenerator\ClassMapGenerator; use Composer\Config; use Composer\EventDispatcher\EventDispatcher; use Composer\Filter\PlatformRequirementFilter\IgnoreAllPlatformRequirementFilter; use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory; use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterInterface; use Composer\Installer\InstallationManager; use Composer\IO\IOInterface; use Composer\IO\NullIO; use Composer\Package\AliasPackage; use Composer\Package\PackageInterface; use Composer\Package\RootPackageInterface; use Composer\Pcre\Preg; use Composer\Repository\InstalledRepositoryInterface; use Composer\Semver\Constraint\Bound; use Composer\Util\Filesystem; use Composer\Util\Platform; use Composer\Script\ScriptEvents; use Composer\Util\PackageSorter; use Composer\Json\JsonFile; /** * @author Igor Wiedler * @author Jordi Boggiano */ class AutoloadGenerator { /** * @var EventDispatcher */ private $eventDispatcher; /** * @var IOInterface */ private $io; /** * @var ?bool */ private $devMode = null; /** * @var bool */ private $classMapAuthoritative = false; /** * @var bool */ private $apcu = false; /** * @var string|null */ private $apcuPrefix; /** * @var bool */ private $runScripts = false; /** * @var PlatformRequirementFilterInterface */ private $platformRequirementFilter; public function __construct(EventDispatcher $eventDispatcher, ?IOInterface $io = null) { $this->eventDispatcher = $eventDispatcher; $this->io = $io ?? new NullIO(); $this->platformRequirementFilter = PlatformRequirementFilterFactory::ignoreNothing(); } /** * @return void */ public function setDevMode(bool $devMode = true) { $this->devMode = $devMode; } /** * Whether generated autoloader considers the class map authoritative. * * @return void */ public function setClassMapAuthoritative(bool $classMapAuthoritative) { $this->classMapAuthoritative = $classMapAuthoritative; } /** * Whether generated autoloader considers APCu caching. * * @return void */ public function setApcu(bool $apcu, ?string $apcuPrefix = null) { $this->apcu = $apcu; $this->apcuPrefix = $apcuPrefix !== null ? $apcuPrefix : $apcuPrefix; } /** * Whether to run scripts or not * * @return void */ public function setRunScripts(bool $runScripts = true) { $this->runScripts = $runScripts; } /** * Whether platform requirements should be ignored. * * If this is set to true, the platform check file will not be generated * If this is set to false, the platform check file will be generated with all requirements * If this is set to string[], those packages will be ignored from the platform check file * * @param bool|string[] $ignorePlatformReqs * @return void * * @deprecated use setPlatformRequirementFilter instead */ public function setIgnorePlatformRequirements($ignorePlatformReqs) { trigger_error('AutoloadGenerator::setIgnorePlatformRequirements is deprecated since Composer 2.2, use setPlatformRequirementFilter instead.', E_USER_DEPRECATED); $this->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs)); } /** * @return void */ public function setPlatformRequirementFilter(PlatformRequirementFilterInterface $platformRequirementFilter) { $this->platformRequirementFilter = $platformRequirementFilter; } /** * @return ClassMap * @throws \Seld\JsonLint\ParsingException * @throws \RuntimeException */ public function dump(Config $config, InstalledRepositoryInterface $localRepo, RootPackageInterface $rootPackage, InstallationManager $installationManager, string $targetDir, bool $scanPsrPackages = false, ?string $suffix = null) { if ($this->classMapAuthoritative) { // Force scanPsrPackages when classmap is authoritative $scanPsrPackages = true; } // auto-set devMode based on whether dev dependencies are installed or not if (null === $this->devMode) { // we assume no-dev mode if no vendor dir is present or it is too old to contain dev information $this->devMode = false; $installedJson = new JsonFile($config->get('vendor-dir').'/composer/installed.json'); if ($installedJson->exists()) { $installedJson = $installedJson->read(); if (isset($installedJson['dev'])) { $this->devMode = $installedJson['dev']; } } } if ($this->runScripts) { // set COMPOSER_DEV_MODE in case not set yet so it is available in the dump-autoload event listeners if (!isset($_SERVER['COMPOSER_DEV_MODE'])) { Platform::putEnv('COMPOSER_DEV_MODE', $this->devMode ? '1' : '0'); } $this->eventDispatcher->dispatchScript(ScriptEvents::PRE_AUTOLOAD_DUMP, $this->devMode, [], [ 'optimize' => $scanPsrPackages, ]); } $classMapGenerator = new ClassMapGenerator(['php', 'inc', 'hh']); $classMapGenerator->avoidDuplicateScans(); $filesystem = new Filesystem(); $filesystem->ensureDirectoryExists($config->get('vendor-dir')); // Do not remove double realpath() calls. // Fixes failing Windows realpath() implementation. // See https://bugs.php.net/bug.php?id=72738 $basePath = $filesystem->normalizePath(realpath(realpath(Platform::getCwd()))); $vendorPath = $filesystem->normalizePath(realpath(realpath($config->get('vendor-dir')))); $useGlobalIncludePath = $config->get('use-include-path'); $prependAutoloader = $config->get('prepend-autoloader') === false ? 'false' : 'true'; $targetDir = $vendorPath.'/'.$targetDir; $filesystem->ensureDirectoryExists($targetDir); $vendorPathCode = $filesystem->findShortestPathCode(realpath($targetDir), $vendorPath, true); $vendorPathToTargetDirCode = $filesystem->findShortestPathCode($vendorPath, realpath($targetDir), true); $appBaseDirCode = $filesystem->findShortestPathCode($vendorPath, $basePath, true); $appBaseDirCode = str_replace('__DIR__', '$vendorDir', $appBaseDirCode); $namespacesFile = <<getDevPackageNames(); $packageMap = $this->buildPackageMap($installationManager, $rootPackage, $localRepo->getCanonicalPackages()); if ($this->devMode) { // if dev mode is enabled, then we do not filter any dev packages out so disable this entirely $filteredDevPackages = false; } else { // if the list of dev package names is available we use that straight, otherwise pass true which means use legacy algo to figure them out $filteredDevPackages = $devPackageNames ?: true; } $autoloads = $this->parseAutoloads($packageMap, $rootPackage, $filteredDevPackages); // Process the 'psr-0' base directories. foreach ($autoloads['psr-0'] as $namespace => $paths) { $exportedPaths = []; foreach ($paths as $path) { $exportedPaths[] = $this->getPathCode($filesystem, $basePath, $vendorPath, $path); } $exportedPrefix = var_export($namespace, true); $namespacesFile .= " $exportedPrefix => "; $namespacesFile .= "array(".implode(', ', $exportedPaths)."),\n"; } $namespacesFile .= ");\n"; // Process the 'psr-4' base directories. foreach ($autoloads['psr-4'] as $namespace => $paths) { $exportedPaths = []; foreach ($paths as $path) { $exportedPaths[] = $this->getPathCode($filesystem, $basePath, $vendorPath, $path); } $exportedPrefix = var_export($namespace, true); $psr4File .= " $exportedPrefix => "; $psr4File .= "array(".implode(', ', $exportedPaths)."),\n"; } $psr4File .= ");\n"; // add custom psr-0 autoloading if the root package has a target dir $targetDirLoader = null; $mainAutoload = $rootPackage->getAutoload(); if ($rootPackage->getTargetDir() && !empty($mainAutoload['psr-0'])) { $levels = substr_count($filesystem->normalizePath($rootPackage->getTargetDir()), '/') + 1; $prefixes = implode(', ', array_map(static function ($prefix): string { return var_export($prefix, true); }, array_keys($mainAutoload['psr-0']))); $baseDirFromTargetDirCode = $filesystem->findShortestPathCode($targetDir, $basePath, true); $targetDirLoader = <<scanPaths($dir, $this->buildExclusionRegex($dir, $excluded)); } if ($scanPsrPackages) { $namespacesToScan = []; // Scan the PSR-0/4 directories for class files, and add them to the class map foreach (['psr-4', 'psr-0'] as $psrType) { foreach ($autoloads[$psrType] as $namespace => $paths) { $namespacesToScan[$namespace][] = ['paths' => $paths, 'type' => $psrType]; } } krsort($namespacesToScan); foreach ($namespacesToScan as $namespace => $groups) { foreach ($groups as $group) { foreach ($group['paths'] as $dir) { $dir = $filesystem->normalizePath($filesystem->isAbsolutePath($dir) ? $dir : $basePath.'/'.$dir); if (!is_dir($dir)) { continue; } $classMapGenerator->scanPaths($dir, $this->buildExclusionRegex($dir, $excluded), $group['type'], $namespace); } } } } $classMap = $classMapGenerator->getClassMap(); foreach ($classMap->getAmbiguousClasses() as $className => $ambiguousPaths) { if (count($ambiguousPaths) > 1) { $this->io->writeError( 'Warning: Ambiguous class resolution, "'.$className.'"'. ' was found '. (count($ambiguousPaths) + 1) .'x: in "'.$classMap->getClassPath($className).'" and "'. implode('", "', $ambiguousPaths) .'", the first will be used.' ); } else { $this->io->writeError( 'Warning: Ambiguous class resolution, "'.$className.'"'. ' was found in both "'.$classMap->getClassPath($className).'" and "'. implode('", "', $ambiguousPaths) .'", the first will be used.' ); } } foreach ($classMap->getPsrViolations() as $msg) { $this->io->writeError("$msg"); } $classMap->addClass('Composer\InstalledVersions', $vendorPath . '/composer/InstalledVersions.php'); $classMap->sort(); $classmapFile = <<getMap() as $className => $path) { $pathCode = $this->getPathCode($filesystem, $basePath, $vendorPath, $path).",\n"; $classmapFile .= ' '.var_export($className, true).' => '.$pathCode; } $classmapFile .= ");\n"; if ('' === $suffix) { $suffix = null; } if (null === $suffix) { $suffix = $config->get('autoloader-suffix'); // carry over existing autoload.php's suffix if possible and none is configured if (null === $suffix && Filesystem::isReadable($vendorPath.'/autoload.php')) { $content = file_get_contents($vendorPath.'/autoload.php'); if (Preg::isMatch('{ComposerAutoloaderInit([^:\s]+)::}', $content, $match)) { $suffix = $match[1]; } } // generate one if we still haven't got a suffix if (null === $suffix) { $suffix = md5(uniqid('', true)); } } $filesystem->filePutContentsIfModified($targetDir.'/autoload_namespaces.php', $namespacesFile); $filesystem->filePutContentsIfModified($targetDir.'/autoload_psr4.php', $psr4File); $filesystem->filePutContentsIfModified($targetDir.'/autoload_classmap.php', $classmapFile); $includePathFilePath = $targetDir.'/include_paths.php'; if ($includePathFileContents = $this->getIncludePathsFile($packageMap, $filesystem, $basePath, $vendorPath, $vendorPathCode, $appBaseDirCode)) { $filesystem->filePutContentsIfModified($includePathFilePath, $includePathFileContents); } elseif (file_exists($includePathFilePath)) { unlink($includePathFilePath); } $includeFilesFilePath = $targetDir.'/autoload_files.php'; if ($includeFilesFileContents = $this->getIncludeFilesFile($autoloads['files'], $filesystem, $basePath, $vendorPath, $vendorPathCode, $appBaseDirCode)) { $filesystem->filePutContentsIfModified($includeFilesFilePath, $includeFilesFileContents); } elseif (file_exists($includeFilesFilePath)) { unlink($includeFilesFilePath); } $filesystem->filePutContentsIfModified($targetDir.'/autoload_static.php', $this->getStaticFile($suffix, $targetDir, $vendorPath, $basePath)); $checkPlatform = $config->get('platform-check') !== false && !($this->platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter); $platformCheckContent = null; if ($checkPlatform) { $platformCheckContent = $this->getPlatformCheck($packageMap, $config->get('platform-check'), $devPackageNames); if (null === $platformCheckContent) { $checkPlatform = false; } } if ($checkPlatform) { $filesystem->filePutContentsIfModified($targetDir.'/platform_check.php', $platformCheckContent); } elseif (file_exists($targetDir.'/platform_check.php')) { unlink($targetDir.'/platform_check.php'); } $filesystem->filePutContentsIfModified($vendorPath.'/autoload.php', $this->getAutoloadFile($vendorPathToTargetDirCode, $suffix)); $filesystem->filePutContentsIfModified($targetDir.'/autoload_real.php', $this->getAutoloadRealFile(true, (bool) $includePathFileContents, $targetDirLoader, (bool) $includeFilesFileContents, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader, $checkPlatform)); $filesystem->safeCopy(__DIR__.'/ClassLoader.php', $targetDir.'/ClassLoader.php'); $filesystem->safeCopy(__DIR__.'/../../../LICENSE', $targetDir.'/LICENSE'); if ($this->runScripts) { $this->eventDispatcher->dispatchScript(ScriptEvents::POST_AUTOLOAD_DUMP, $this->devMode, [], [ 'optimize' => $scanPsrPackages, ]); } return $classMap; } /** * @param array|null $excluded * @return non-empty-string|null */ private function buildExclusionRegex(string $dir, ?array $excluded): ?string { if (null === $excluded) { return null; } // filter excluded patterns here to only use those matching $dir // exclude-from-classmap patterns are all realpath'd so we can only filter them if $dir exists so that realpath($dir) will work // if $dir does not exist, it should anyway not find anything there so no trouble if (file_exists($dir)) { // transform $dir in the same way that exclude-from-classmap patterns are transformed so we can match them against each other $dirMatch = preg_quote(strtr(realpath($dir), '\\', '/')); foreach ($excluded as $index => $pattern) { // extract the constant string prefix of the pattern here, until we reach a non-escaped regex special character $pattern = Preg::replace('{^(([^.+*?\[^\]$(){}=!<>|:\\\\#-]+|\\\\[.+*?\[^\]$(){}=!<>|:#-])*).*}', '$1', $pattern); // if the pattern is not a subset or superset of $dir, it is unrelated and we skip it if (0 !== strpos($pattern, $dirMatch) && 0 !== strpos($dirMatch, $pattern)) { unset($excluded[$index]); } } } return \count($excluded) > 0 ? '{(' . implode('|', $excluded) . ')}' : null; } /** * @param PackageInterface[] $packages * @return array */ public function buildPackageMap(InstallationManager $installationManager, PackageInterface $rootPackage, array $packages) { // build package => install path map $packageMap = [[$rootPackage, '']]; foreach ($packages as $package) { if ($package instanceof AliasPackage) { continue; } $this->validatePackage($package); $packageMap[] = [ $package, $installationManager->getInstallPath($package), ]; } return $packageMap; } /** * @return void * @throws \InvalidArgumentException Throws an exception, if the package has illegal settings. */ protected function validatePackage(PackageInterface $package) { $autoload = $package->getAutoload(); if (!empty($autoload['psr-4']) && null !== $package->getTargetDir()) { $name = $package->getName(); $package->getTargetDir(); throw new \InvalidArgumentException("PSR-4 autoloading is incompatible with the target-dir property, remove the target-dir in package '$name'."); } if (!empty($autoload['psr-4'])) { foreach ($autoload['psr-4'] as $namespace => $dirs) { if ($namespace !== '' && '\\' !== substr($namespace, -1)) { throw new \InvalidArgumentException("psr-4 namespaces must end with a namespace separator, '$namespace' does not, use '$namespace\\'."); } } } } /** * Compiles an ordered list of namespace => path mappings * * @param array $packageMap array of array(package, installDir-relative-to-composer.json) * @param RootPackageInterface $rootPackage root package instance * @param bool|string[] $filteredDevPackages If an array, the list of packages that must be removed. If bool, whether to filter out require-dev packages * @return array * @phpstan-return array{ * 'psr-0': array>, * 'psr-4': array>, * 'classmap': array, * 'files': array, * 'exclude-from-classmap': array, * } */ public function parseAutoloads(array $packageMap, PackageInterface $rootPackage, $filteredDevPackages = false) { $rootPackageMap = array_shift($packageMap); if (is_array($filteredDevPackages)) { $packageMap = array_filter($packageMap, static function ($item) use ($filteredDevPackages): bool { return !in_array($item[0]->getName(), $filteredDevPackages, true); }); } elseif ($filteredDevPackages) { $packageMap = $this->filterPackageMap($packageMap, $rootPackage); } $sortedPackageMap = $this->sortPackageMap($packageMap); $sortedPackageMap[] = $rootPackageMap; array_unshift($packageMap, $rootPackageMap); $psr0 = $this->parseAutoloadsType($packageMap, 'psr-0', $rootPackage); $psr4 = $this->parseAutoloadsType($packageMap, 'psr-4', $rootPackage); $classmap = $this->parseAutoloadsType(array_reverse($sortedPackageMap), 'classmap', $rootPackage); $files = $this->parseAutoloadsType($sortedPackageMap, 'files', $rootPackage); $exclude = $this->parseAutoloadsType($sortedPackageMap, 'exclude-from-classmap', $rootPackage); krsort($psr0); krsort($psr4); return [ 'psr-0' => $psr0, 'psr-4' => $psr4, 'classmap' => $classmap, 'files' => $files, 'exclude-from-classmap' => $exclude, ]; } /** * Registers an autoloader based on an autoload-map returned by parseAutoloads * * @param array $autoloads see parseAutoloads return value * @return ClassLoader */ public function createLoader(array $autoloads, ?string $vendorDir = null) { $loader = new ClassLoader($vendorDir); if (isset($autoloads['psr-0'])) { foreach ($autoloads['psr-0'] as $namespace => $path) { $loader->add($namespace, $path); } } if (isset($autoloads['psr-4'])) { foreach ($autoloads['psr-4'] as $namespace => $path) { $loader->addPsr4($namespace, $path); } } if (isset($autoloads['classmap'])) { $excluded = null; if (!empty($autoloads['exclude-from-classmap'])) { $excluded = $autoloads['exclude-from-classmap']; } $classMapGenerator = new ClassMapGenerator(['php', 'inc', 'hh']); $classMapGenerator->avoidDuplicateScans(); foreach ($autoloads['classmap'] as $dir) { try { $classMapGenerator->scanPaths($dir, $this->buildExclusionRegex($dir, $excluded)); } catch (\RuntimeException $e) { $this->io->writeError(''.$e->getMessage().''); } } $loader->addClassMap($classMapGenerator->getClassMap()->getMap()); } return $loader; } /** * @param array $packageMap * @return ?string */ protected function getIncludePathsFile(array $packageMap, Filesystem $filesystem, string $basePath, string $vendorPath, string $vendorPathCode, string $appBaseDirCode) { $includePaths = []; foreach ($packageMap as $item) { [$package, $installPath] = $item; if (null !== $package->getTargetDir() && strlen($package->getTargetDir()) > 0) { $installPath = substr($installPath, 0, -strlen('/'.$package->getTargetDir())); } foreach ($package->getIncludePaths() as $includePath) { $includePath = trim($includePath, '/'); $includePaths[] = empty($installPath) ? $includePath : $installPath.'/'.$includePath; } } if (!$includePaths) { return null; } $includePathsCode = ''; foreach ($includePaths as $path) { $includePathsCode .= " " . $this->getPathCode($filesystem, $basePath, $vendorPath, $path) . ",\n"; } return << $files * @return ?string */ protected function getIncludeFilesFile(array $files, Filesystem $filesystem, string $basePath, string $vendorPath, string $vendorPathCode, string $appBaseDirCode) { $filesCode = ''; foreach ($files as $fileIdentifier => $functionFile) { $filesCode .= ' ' . var_export($fileIdentifier, true) . ' => ' . $this->getPathCode($filesystem, $basePath, $vendorPath, $functionFile) . ",\n"; } if (!$filesCode) { return null; } return <<isAbsolutePath($path)) { $path = $basePath . '/' . $path; } $path = $filesystem->normalizePath($path); $baseDir = ''; if (strpos($path.'/', $vendorPath.'/') === 0) { $path = (string) substr($path, strlen($vendorPath)); $baseDir = '$vendorDir . '; } else { $path = $filesystem->normalizePath($filesystem->findShortestPath($basePath, $path, true)); if (!$filesystem->isAbsolutePath($path)) { $baseDir = '$baseDir . '; $path = '/' . $path; } } if (strpos($path, '.phar') !== false) { $baseDir = "'phar://' . " . $baseDir; } return $baseDir . var_export($path, true); } /** * @param array $packageMap * @param bool|'php-only' $checkPlatform * @param string[] $devPackageNames * @return ?string */ protected function getPlatformCheck(array $packageMap, $checkPlatform, array $devPackageNames) { $lowestPhpVersion = Bound::zero(); $requiredExtensions = []; $extensionProviders = []; foreach ($packageMap as $item) { $package = $item[0]; foreach (array_merge($package->getReplaces(), $package->getProvides()) as $link) { if (Preg::isMatch('{^ext-(.+)$}iD', $link->getTarget(), $match)) { $extensionProviders[$match[1]][] = $link->getConstraint(); } } } foreach ($packageMap as $item) { $package = $item[0]; // skip dev dependencies platform requirements as platform-check really should only be a production safeguard if (in_array($package->getName(), $devPackageNames, true)) { continue; } foreach ($package->getRequires() as $link) { if ($this->platformRequirementFilter->isIgnored($link->getTarget())) { continue; } if ('php' === $link->getTarget()) { $constraint = $link->getConstraint(); if ($constraint->getLowerBound()->compareTo($lowestPhpVersion, '>')) { $lowestPhpVersion = $constraint->getLowerBound(); } } if ($checkPlatform === true && Preg::isMatch('{^ext-(.+)$}iD', $link->getTarget(), $match)) { // skip extension checks if they have a valid provider/replacer if (isset($extensionProviders[$match[1]])) { foreach ($extensionProviders[$match[1]] as $provided) { if ($provided->matches($link->getConstraint())) { continue 2; } } } if ($match[1] === 'zend-opcache') { $match[1] = 'zend opcache'; } $extension = var_export($match[1], true); if ($match[1] === 'pcntl' || $match[1] === 'readline') { $requiredExtensions[$extension] = "PHP_SAPI !== 'cli' || extension_loaded($extension) || \$missingExtensions[] = $extension;\n"; } else { $requiredExtensions[$extension] = "extension_loaded($extension) || \$missingExtensions[] = $extension;\n"; } } } } ksort($requiredExtensions); $formatToPhpVersionId = static function (Bound $bound): int { if ($bound->isZero()) { return 0; } if ($bound->isPositiveInfinity()) { return 99999; } $version = str_replace('-', '.', $bound->getVersion()); $chunks = array_map('intval', explode('.', $version)); return $chunks[0] * 10000 + $chunks[1] * 100 + $chunks[2]; }; $formatToHumanReadable = static function (Bound $bound) { if ($bound->isZero()) { return 0; } if ($bound->isPositiveInfinity()) { return 99999; } $version = str_replace('-', '.', $bound->getVersion()); $chunks = explode('.', $version); $chunks = array_slice($chunks, 0, 3); return implode('.', $chunks); }; $requiredPhp = ''; $requiredPhpError = ''; if (!$lowestPhpVersion->isZero()) { $operator = $lowestPhpVersion->isInclusive() ? '>=' : '>'; $requiredPhp = 'PHP_VERSION_ID '.$operator.' '.$formatToPhpVersionId($lowestPhpVersion); $requiredPhpError = '"'.$operator.' '.$formatToHumanReadable($lowestPhpVersion).'"'; } if ($requiredPhp) { $requiredPhp = <<classMapAuthoritative) { $file .= <<<'CLASSMAPAUTHORITATIVE' $loader->setClassMapAuthoritative(true); CLASSMAPAUTHORITATIVE; } if ($this->apcu) { $apcuPrefix = var_export(($this->apcuPrefix !== null ? $this->apcuPrefix : substr(base64_encode(md5(uniqid('', true), true)), 0, -3)), true); $file .= <<setApcuPrefix($apcuPrefix); APCU; } if ($useGlobalIncludePath) { $file .= <<<'INCLUDEPATH' $loader->setUseIncludePath(true); INCLUDEPATH; } if ($targetDirLoader) { $file .= <<register($prependAutoloader); REGISTER_LOADER; if ($useIncludeFiles) { $file .= << \$file) { \$requireFile(\$fileIdentifier, \$file); } INCLUDE_FILES; } $file .= << $path) { $loader->set($namespace, $path); } $map = require $targetDir . '/autoload_psr4.php'; foreach ($map as $namespace => $path) { $loader->setPsr4($namespace, $path); } $classMap = require $targetDir . '/autoload_classmap.php'; if ($classMap) { $loader->addClassMap($classMap); } $filesystem = new Filesystem(); $vendorPathCode = ' => ' . $filesystem->findShortestPathCode(realpath($targetDir), $vendorPath, true, true) . " . '/"; $vendorPharPathCode = ' => \'phar://\' . ' . $filesystem->findShortestPathCode(realpath($targetDir), $vendorPath, true, true) . " . '/"; $appBaseDirCode = ' => ' . $filesystem->findShortestPathCode(realpath($targetDir), $basePath, true, true) . " . '/"; $appBaseDirPharCode = ' => \'phar://\' . ' . $filesystem->findShortestPathCode(realpath($targetDir), $basePath, true, true) . " . '/"; $absoluteVendorPathCode = ' => ' . substr(var_export(rtrim($vendorDir, '\\/') . '/', true), 0, -1); $absoluteVendorPharPathCode = ' => ' . substr(var_export(rtrim('phar://' . $vendorDir, '\\/') . '/', true), 0, -1); $absoluteAppBaseDirCode = ' => ' . substr(var_export(rtrim($baseDir, '\\/') . '/', true), 0, -1); $absoluteAppBaseDirPharCode = ' => ' . substr(var_export(rtrim('phar://' . $baseDir, '\\/') . '/', true), 0, -1); $initializer = ''; $prefix = "\0Composer\Autoload\ClassLoader\0"; $prefixLen = strlen($prefix); if (file_exists($targetDir . '/autoload_files.php')) { $maps = ['files' => require $targetDir . '/autoload_files.php']; } else { $maps = []; } foreach ((array) $loader as $prop => $value) { if (!is_array($value) || \count($value) === 0 || !str_starts_with($prop, $prefix)) { continue; } $maps[substr($prop, $prefixLen)] = $value; } foreach ($maps as $prop => $value) { $value = strtr( var_export($value, true), [ $absoluteVendorPathCode => $vendorPathCode, $absoluteVendorPharPathCode => $vendorPharPathCode, $absoluteAppBaseDirCode => $appBaseDirCode, $absoluteAppBaseDirPharCode => $appBaseDirPharCode, ] ); $value = ltrim(Preg::replace('/^ */m', ' $0$0', $value)); $file .= sprintf(" public static $%s = %s;\n\n", $prop, $value); if ('files' !== $prop) { $initializer .= " \$loader->$prop = ComposerStaticInit$suffix::\$$prop;\n"; } } return $file . << $packageMap * @param string $type one of: 'psr-0'|'psr-4'|'classmap'|'files' * @return array|array>|array */ protected function parseAutoloadsType(array $packageMap, string $type, RootPackageInterface $rootPackage) { $autoloads = []; foreach ($packageMap as $item) { [$package, $installPath] = $item; $autoload = $package->getAutoload(); if ($this->devMode && $package === $rootPackage) { $autoload = array_merge_recursive($autoload, $package->getDevAutoload()); } // skip misconfigured packages if (!isset($autoload[$type]) || !is_array($autoload[$type])) { continue; } if (null !== $package->getTargetDir() && $package !== $rootPackage) { $installPath = substr($installPath, 0, -strlen('/'.$package->getTargetDir())); } foreach ($autoload[$type] as $namespace => $paths) { foreach ((array) $paths as $path) { if (($type === 'files' || $type === 'classmap' || $type === 'exclude-from-classmap') && $package->getTargetDir() && !Filesystem::isReadable($installPath.'/'.$path)) { // remove target-dir from file paths of the root package if ($package === $rootPackage) { $targetDir = str_replace('\\', '[\\\\/]', preg_quote(str_replace(['/', '\\'], '', $package->getTargetDir()))); $path = ltrim(Preg::replace('{^'.$targetDir.'}', '', ltrim($path, '\\/')), '\\/'); } else { // add target-dir from file paths that don't have it $path = $package->getTargetDir() . '/' . $path; } } if ($type === 'exclude-from-classmap') { // first escape user input $path = Preg::replace('{/+}', '/', preg_quote(trim(strtr($path, '\\', '/'), '/'))); // add support for wildcards * and ** $path = strtr($path, ['\\*\\*' => '.+?', '\\*' => '[^/]+?']); // add support for up-level relative paths $updir = null; $path = Preg::replaceCallback( '{^((?:(?:\\\\\\.){1,2}+/)+)}', static function ($matches) use (&$updir): string { if (isset($matches[1])) { // undo preg_quote for the matched string $updir = str_replace('\\.', '.', $matches[1]); } return ''; }, $path ); if (empty($installPath)) { $installPath = strtr(Platform::getCwd(), '\\', '/'); } $resolvedPath = realpath($installPath . '/' . $updir); if (false === $resolvedPath) { continue; } $autoloads[] = preg_quote(strtr($resolvedPath, '\\', '/')) . '/' . $path . '($|/)'; continue; } $relativePath = empty($installPath) ? (empty($path) ? '.' : $path) : $installPath.'/'.$path; if ($type === 'files') { $autoloads[$this->getFileIdentifier($package, $path)] = $relativePath; continue; } if ($type === 'classmap') { $autoloads[] = $relativePath; continue; } $autoloads[$namespace][] = $relativePath; } } } return $autoloads; } /** * @return string */ protected function getFileIdentifier(PackageInterface $package, string $path) { return md5($package->getName() . ':' . $path); } /** * Filters out dev-dependencies * * @param array $packageMap * @return array * * @phpstan-param array $packageMap */ protected function filterPackageMap(array $packageMap, RootPackageInterface $rootPackage) { $packages = []; $include = []; $replacedBy = []; foreach ($packageMap as $item) { $package = $item[0]; $name = $package->getName(); $packages[$name] = $package; foreach ($package->getReplaces() as $replace) { $replacedBy[$replace->getTarget()] = $name; } } $add = static function (PackageInterface $package) use (&$add, $packages, &$include, $replacedBy): void { foreach ($package->getRequires() as $link) { $target = $link->getTarget(); if (isset($replacedBy[$target])) { $target = $replacedBy[$target]; } if (!isset($include[$target])) { $include[$target] = true; if (isset($packages[$target])) { $add($packages[$target]); } } } }; $add($rootPackage); return array_filter( $packageMap, static function ($item) use ($include): bool { $package = $item[0]; foreach ($package->getNames() as $name) { if (isset($include[$name])) { return true; } } return false; } ); } /** * Sorts packages by dependency weight * * Packages of equal weight are sorted alphabetically * * @param array $packageMap * @return array */ protected function sortPackageMap(array $packageMap) { $packages = []; $paths = []; foreach ($packageMap as $item) { [$package, $path] = $item; $name = $package->getName(); $packages[$name] = $package; $paths[$name] = $path; } $sortedPackages = PackageSorter::sortPackages($packages); $sortedPackageMap = []; foreach ($sortedPackages as $package) { $name = $package->getName(); $sortedPackageMap[] = [$packages[$name], $paths[$name]]; } return $sortedPackageMap; } } function composerRequire(string $fileIdentifier, string $file): void { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; require $file; } } __halt_compiler();----SIGNATURE:----qcJ/oAjksyPymG0Mgu5qt3uhdWZTyryzSeiP4p9R+BcA3s+ZRS7uEiYeOL1k4RHQPLrkaDko9xtqcR8aDQlf2nA+ue41iAKL70MgD9PBFZfDK1FMJw+dC+O0Xt4GHRwvtUhzo95O+425XqdhZSoGro2uJs/cRPapr0wHoY4Ud7rVJMikc1ujaN/4Pm6FeKUtW+1IY1zvxvVEpAJVEelpKKNR3j/geyO2S86bNd/2Pgl0YjAFhLZoZvT6Jgj6ZVC5i9P1KGjHnBqOndezCPttV7PKpdO/YcUgs3nHZodK/sNkixSSJTWciXNEWY+dMhEznXdHmhblB0njPAmf80DTfU9ID/WtHTkYfXZTliAhbk8oLEJAyZ61afng5npa3ZXN4VesUqho4NjxdqUF3piOIGMtZPIwmJhCn/cie8PpEXrWXLmBVQQmenzf3H5KtPDuic/C3wFRCtOZq5EwcIwddYcFhVIKL0MrtDCHRp9JJFrvFdXXe7us51Be2Bs2gcf8BJcCiLaw46kepPtxmai4fLVskkFXKfDQH44rjT6098hHoaJ6HRUd5sHo3YP80d5Zyspw7n/l5IZXZNqpVtd8dsJlyqbT5kderR9CDEiH6ZJMCpdWQvcCqluOc8kqboxEGm8Acg2DsRttbA/HxzIGrN8nMizcG7Fdia4/4BrYMqM=----ATTACHMENT:----OTQxNDUwMzIwMDMwNTMxMiA0NzU2NjQ4Mjk2MTc2ODgyIDY4MzMzMDA3Nzk0ODAzNTQ=