* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Debug\FatalErrorHandler; use Symfony\Component\Debug\Exception\ClassNotFoundException; use Symfony\Component\Debug\Exception\FatalErrorException; use Symfony\Component\Debug\DebugClassLoader; use Composer\Autoload\ClassLoader as ComposerClassLoader; use Symfony\Component\ClassLoader\ClassLoader as SymfonyClassLoader; /** * ErrorHandler for classes that do not exist. * * @author Fabien Potencier */ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface { /** * {@inheritdoc} */ public function handleError(array $error, FatalErrorException $exception) { $messageLen = strlen($error['message']); $notFoundSuffix = '\' not found'; $notFoundSuffixLen = strlen($notFoundSuffix); if ($notFoundSuffixLen > $messageLen) { return; } if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) { return; } foreach (array('class', 'interface', 'trait') as $typeName) { $prefix = ucfirst($typeName).' \''; $prefixLen = strlen($prefix); if (0 !== strpos($error['message'], $prefix)) { continue; } $fullyQualifiedClassName = substr($error['message'], $prefixLen, -$notFoundSuffixLen); if (false !== $namespaceSeparatorIndex = strrpos($fullyQualifiedClassName, '\\')) { $className = substr($fullyQualifiedClassName, $namespaceSeparatorIndex + 1); $namespacePrefix = substr($fullyQualifiedClassName, 0, $namespaceSeparatorIndex); $message = sprintf('Attempted to load %s "%s" from namespace "%s".', $typeName, $className, $namespacePrefix); $tail = ' for another namespace?'; } else { $className = $fullyQualifiedClassName; $message = sprintf('Attempted to load %s "%s" from the global namespace.', $typeName, $className); $tail = '?'; } if ($candidates = $this->getClassCandidates($className)) { $tail = array_pop($candidates).'"?'; if ($candidates) { $tail = ' for e.g. "'.implode('", "', $candidates).'" or "'.$tail; } else { $tail = ' for "'.$tail; } } $message .= "\nDid you forget a \"use\" statement".$tail; return new ClassNotFoundException($message, $exception); } } /** * Tries to guess the full namespace for a given class name. * * By default, it looks for PSR-0 and PSR-4 classes registered via a Symfony or a Composer * autoloader (that should cover all common cases). * * @param string $class A class name (without its namespace) * * @return array An array of possible fully qualified class names */ private function getClassCandidates($class) { if (!is_array($functions = spl_autoload_functions())) { return array(); } // find Symfony and Composer autoloaders $classes = array(); foreach ($functions as $function) { if (!is_array($function)) { continue; } // get class loaders wrapped by DebugClassLoader if ($function[0] instanceof DebugClassLoader) { $function = $function[0]->getClassLoader(); if (!is_array($function)) { continue; } } if ($function[0] instanceof ComposerClassLoader || $function[0] instanceof SymfonyClassLoader) { foreach ($function[0]->getPrefixes() as $prefix => $paths) { foreach ($paths as $path) { $classes = array_merge($classes, $this->findClassInPath($path, $class, $prefix)); } } } if ($function[0] instanceof ComposerClassLoader) { foreach ($function[0]->getPrefixesPsr4() as $prefix => $paths) { foreach ($paths as $path) { $classes = array_merge($classes, $this->findClassInPath($path, $class, $prefix)); } } } } return array_unique($classes); } /** * @param string $path * @param string $class * @param string $prefix * * @return array */ private function findClassInPath($path, $class, $prefix) { if (!$path = realpath($path.'/'.strtr($prefix, '\\_', '//')) ?: realpath($path.'/'.dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path)) { return array(); } $classes = array(); $filename = $class.'.php'; foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) { if ($filename == $file->getFileName() && $class = $this->convertFileToClass($path, $file->getPathName(), $prefix)) { $classes[] = $class; } } return $classes; } /** * @param string $path * @param string $file * @param string $prefix * * @return string|null */ private function convertFileToClass($path, $file, $prefix) { $candidates = array( // namespaced class $namespacedClass = str_replace(array($path.DIRECTORY_SEPARATOR, '.php', '/'), array('', '', '\\'), $file), // namespaced class (with target dir) $prefix.$namespacedClass, // namespaced class (with target dir and separator) $prefix.'\\'.$namespacedClass, // PEAR class str_replace('\\', '_', $namespacedClass), // PEAR class (with target dir) str_replace('\\', '_', $prefix.$namespacedClass), // PEAR class (with target dir and separator) str_replace('\\', '_', $prefix.'\\'.$namespacedClass), ); if ($prefix) { $candidates = array_filter($candidates, function ($candidate) use ($prefix) { return 0 === strpos($candidate, $prefix); }); } // We cannot use the autoloader here as most of them use require; but if the class // is not found, the new autoloader call will require the file again leading to a // "cannot redeclare class" error. foreach ($candidates as $candidate) { if ($this->classExists($candidate)) { return $candidate; } } require_once $file; foreach ($candidates as $candidate) { if ($this->classExists($candidate)) { return $candidate; } } } /** * @param string $class * * @return bool */ private function classExists($class) { return class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false); } } __halt_compiler();----SIGNATURE:----CbW6o8+olvRQ2DxQ1fOVdwS87nTLPZEZYNlBoFNOvdpdeXUIgZhSQP7fJVRXieOvg7a57b42vcV2ItsgGG1VsvzT6+FgpxJqDCfbz2FP83T6cgMLA851jer9KRN2HD+5M13oPT+hNKidsNr3BET2cTD2NNrEQJHNZH6tuZVnUnRm1SNFk56HAMnFcSvq3y7Zr4oOEQGTEmN5dmrnz9V465uO+uu4k7nnVwr1nwMv0Q0Phxo1hlHZTPrNlLDnbETg99yDCvmg2c8Ab/uPpT2+gu3yCK9nvNiP6xv3fi91fshY3aLrN2JXCc0OPqAohBkTMmjnZbIxvkGizJ0c9W4kUq5PHmg4qoYgmw0nYuqVFC2AE2nm02/K6rXJij9uaNOsu7CD1aHMCf6aE6aH6tdcaMTdlXJzAUTyVLQ+9Ym5GTsBwKrDdwvtAA7IqXGEKsYn5xPBWPOIZjB3p6aNSdnsEd5YvVRJB4XHY+6w1ZerNsJtufscS+W4Vy5i3MhfEP1LMP6q879/uaua4liLBEi3CTVNZUrHg4LbvLuZ3Hn3lBZ2FjOQ3ZPTw1tc4yt7rBdKwOwCV77WpbCy6MIbPsuS7ii55KpfdeG0OdEMiplhezaIR5AoL+TXWULXsVDF7lBRvUIVmqaq1Dz24jwZoUFSQrAyaMa8j9bFhJWWfCnfXGg=----ATTACHMENT:----Mzg4MjkxOTA4NjAzMDAwMCA5MTg0MTA2Mzc5MzEyNTQyIDc2NTEyMDM5NTIwODY4MTY=