/core/Associates/Whoops/vendor/filp/whoops/src/Whoops/Handler/PrettyPageHandler.php
PHP | 576 lines | 282 code | 76 blank | 218 comment | 28 complexity | edf4d164c673989b7ede1f116f437f98 MD5 | raw file
- <?php
- /**
- * Whoops - php errors for cool kids
- * @author Filipe Dobreira <http://github.com/filp>
- */
- namespace Whoops\Handler;
- use InvalidArgumentException;
- use RuntimeException;
- use Whoops\Exception\Formatter;
- use Whoops\Util\Misc;
- use Whoops\Util\TemplateHelper;
- class PrettyPageHandler extends Handler
- {
- /**
- * Search paths to be scanned for resources, in the reverse
- * order they're declared.
- *
- * @var array
- */
- private $searchPaths = array();
- /**
- * Fast lookup cache for known resource locations.
- *
- * @var array
- */
- private $resourceCache = array();
- /**
- * The name of the custom css file.
- *
- * @var string
- */
- private $customCss = null;
- /**
- * @var array[]
- */
- private $extraTables = array();
- /**
- * @var bool
- */
- private $handleUnconditionally = false;
- /**
- * @var string
- */
- private $pageTitle = "Whoops! There was an error.";
- /**
- * A string identifier for a known IDE/text editor, or a closure
- * that resolves a string that can be used to open a given file
- * in an editor. If the string contains the special substrings
- * %file or %line, they will be replaced with the correct data.
- *
- * @example
- * "txmt://open?url=%file&line=%line"
- * @var mixed $editor
- */
- protected $editor;
- /**
- * A list of known editor strings
- * @var array
- */
- protected $editors = array(
- "sublime" => "subl://open?url=file://%file&line=%line",
- "textmate" => "txmt://open?url=file://%file&line=%line",
- "emacs" => "emacs://open?url=file://%file&line=%line",
- "macvim" => "mvim://open/?url=file://%file&line=%line",
- );
- /**
- * Constructor.
- */
- public function __construct()
- {
- if (ini_get('xdebug.file_link_format') || extension_loaded('xdebug')) {
- // Register editor using xdebug's file_link_format option.
- $this->editors['xdebug'] = function ($file, $line) {
- return str_replace(array('%f', '%l'), array($file, $line), ini_get('xdebug.file_link_format'));
- };
- }
- // Add the default, local resource search path:
- $this->searchPaths[] = __DIR__ . "/../Resources";
- }
- /**
- * @return int|null
- */
- public function handle()
- {
- if (!$this->handleUnconditionally()) {
- // Check conditions for outputting HTML:
- // @todo: Make this more robust
- if (php_sapi_name() === 'cli') {
- // Help users who have been relying on an internal test value
- // fix their code to the proper method
- if (isset($_ENV['whoops-test'])) {
- throw new \Exception(
- 'Use handleUnconditionally instead of whoops-test'
- .' environment variable'
- );
- }
- return Handler::DONE;
- }
- }
- // @todo: Make this more dynamic
- $helper = new TemplateHelper();
- $templateFile = $this->getResource("views/layout.html.php");
- $cssFile = $this->getResource("css/whoops.base.css");
- $zeptoFile = $this->getResource("js/zepto.min.js");
- $jsFile = $this->getResource("js/whoops.base.js");
- if ($this->customCss) {
- $customCssFile = $this->getResource($this->customCss);
- }
- $inspector = $this->getInspector();
- $frames = $inspector->getFrames();
- //
- $code = $inspector->getException()->getCode();
- if ($inspector->getException() instanceof \ErrorException) {
- $code = Misc::translateErrorCode($code);
- }
- //error_log("###".Formatter::formatExceptionPlain($inspector)."###");
- // List of variables that will be passed to the layout template.
- $vars = array(
- "page_title" => $this->getPageTitle(),
- // @todo: Asset compiler
- "stylesheet" => file_get_contents($cssFile),
- "zepto" => file_get_contents($zeptoFile),
- "javascript" => file_get_contents($jsFile),
- // Template paths:
- "header" => $this->getResource("views/header.html.php"),
- "frame_list" => $this->getResource("views/frame_list.html.php"),
- "frame_code" => $this->getResource("views/frame_code.html.php"),
- "env_details" => $this->getResource("views/env_details.html.php"),
- "title" => $this->getPageTitle(),
- "name" => explode("\\", $inspector->getExceptionName()),
- "message" => $inspector->getException()->getMessage(),
- "code" => $code,
- "plain_exception" => Formatter::formatExceptionPlain($inspector),
- "frames" => $frames,
- "has_frames" => !!count($frames),
- "handler" => $this,
- "handlers" => $this->getRun()->getHandlers(),
- "tables" => array(
- "Server/Request Data" => $_SERVER,
- "GET Data" => $_GET,
- "POST Data" => $_POST,
- "Files" => $_FILES,
- "Cookies" => $_COOKIE,
- "Session" => isset($_SESSION) ? $_SESSION : array(),
- "Environment Variables" => $_ENV,
- ),
- );
- if (isset($customCssFile)) {
- $vars["stylesheet"] .= file_get_contents($customCssFile);
- }
- // Add extra entries list of data tables:
- // @todo: Consolidate addDataTable and addDataTableCallback
- $extraTables = array_map(function ($table) {
- return $table instanceof \Closure ? $table() : $table;
- }, $this->getDataTables());
- $vars["tables"] = array_merge($extraTables, $vars["tables"]);
- $helper->setVariables($vars);
- $helper->render($templateFile);
- //
- return Handler::QUIT;
- }
- /**
- * Adds an entry to the list of tables displayed in the template.
- * The expected data is a simple associative array. Any nested arrays
- * will be flattened with print_r
- * @param string $label
- * @param array $data
- */
- public function addDataTable($label, array $data)
- {
- $this->extraTables[$label] = $data;
- }
- /**
- * Lazily adds an entry to the list of tables displayed in the table.
- * The supplied callback argument will be called when the error is rendered,
- * it should produce a simple associative array. Any nested arrays will
- * be flattened with print_r.
- *
- * @throws InvalidArgumentException If $callback is not callable
- * @param string $label
- * @param callable $callback Callable returning an associative array
- */
- public function addDataTableCallback($label, /* callable */ $callback)
- {
- if (!is_callable($callback)) {
- throw new InvalidArgumentException('Expecting callback argument to be callable');
- }
- $this->extraTables[$label] = function () use ($callback) {
- try {
- $result = call_user_func($callback);
- // Only return the result if it can be iterated over by foreach().
- return is_array($result) || $result instanceof \Traversable ? $result : array();
- } catch (\Exception $e) {
- // Don't allow failure to break the rendering of the original exception.
- return array();
- }
- };
- }
- /**
- * Returns all the extra data tables registered with this handler.
- * Optionally accepts a 'label' parameter, to only return the data
- * table under that label.
- * @param string|null $label
- * @return array[]|callable
- */
- public function getDataTables($label = null)
- {
- if ($label !== null) {
- return isset($this->extraTables[$label]) ?
- $this->extraTables[$label] : array();
- }
- return $this->extraTables;
- }
- /**
- * Allows to disable all attempts to dynamically decide whether to
- * handle or return prematurely.
- * Set this to ensure that the handler will perform no matter what.
- * @param bool|null $value
- * @return bool|null
- */
- public function handleUnconditionally($value = null)
- {
- if (func_num_args() == 0) {
- return $this->handleUnconditionally;
- }
- $this->handleUnconditionally = (bool) $value;
- }
- /**
- * Adds an editor resolver, identified by a string
- * name, and that may be a string path, or a callable
- * resolver. If the callable returns a string, it will
- * be set as the file reference's href attribute.
- *
- * @example
- * $run->addEditor('macvim', "mvim://open?url=file://%file&line=%line")
- * @example
- * $run->addEditor('remove-it', function($file, $line) {
- * unlink($file);
- * return "http://stackoverflow.com";
- * });
- * @param string $identifier
- * @param string $resolver
- */
- public function addEditor($identifier, $resolver)
- {
- $this->editors[$identifier] = $resolver;
- }
- /**
- * Set the editor to use to open referenced files, by a string
- * identifier, or a callable that will be executed for every
- * file reference, with a $file and $line argument, and should
- * return a string.
- *
- * @example
- * $run->setEditor(function($file, $line) { return "file:///{$file}"; });
- * @example
- * $run->setEditor('sublime');
- *
- * @throws InvalidArgumentException If invalid argument identifier provided
- * @param string|callable $editor
- */
- public function setEditor($editor)
- {
- if (!is_callable($editor) && !isset($this->editors[$editor])) {
- throw new InvalidArgumentException(
- "Unknown editor identifier: $editor. Known editors:" .
- implode(",", array_keys($this->editors))
- );
- }
- $this->editor = $editor;
- }
- /**
- * Given a string file path, and an integer file line,
- * executes the editor resolver and returns, if available,
- * a string that may be used as the href property for that
- * file reference.
- *
- * @throws InvalidArgumentException If editor resolver does not return a string
- * @param string $filePath
- * @param int $line
- * @return false|string
- */
- public function getEditorHref($filePath, $line)
- {
- if ($this->editor === null) {
- return false;
- }
- $editor = $this->editor;
- if (is_string($editor)) {
- $editor = $this->editors[$editor];
- }
- if (is_callable($editor)) {
- $editor = call_user_func($editor, $filePath, $line);
- }
- // Check that the editor is a string, and replace the
- // %line and %file placeholders:
- if (!is_string($editor)) {
- throw new InvalidArgumentException(
- __METHOD__ . " should always resolve to a string; got something else instead"
- );
- }
- $editor = str_replace("%line", rawurlencode($line), $editor);
- $editor = str_replace("%file", rawurlencode($filePath), $editor);
- return $editor;
- }
- /**
- * @param string $title
- * @return void
- */
- public function setPageTitle($title)
- {
- $this->pageTitle = (string) $title;
- }
- /**
- * @return string
- */
- public function getPageTitle()
- {
- return $this->pageTitle;
- }
- /**
- * Adds a path to the list of paths to be searched for
- * resources.
- *
- * @throws InvalidArgumnetException If $path is not a valid directory
- *
- * @param string $path
- * @return void
- */
- public function addResourcePath($path)
- {
- if (!is_dir($path)) {
- throw new InvalidArgumentException(
- "'$path' is not a valid directory"
- );
- }
- array_unshift($this->searchPaths, $path);
- }
- /**
- * Adds a custom css file to be loaded.
- *
- * @param string $name
- * @return void
- */
- public function addCustomCss($name)
- {
- $this->customCss = $name;
- }
- /**
- * @return array
- */
- public function getResourcePaths()
- {
- return $this->searchPaths;
- }
- /**
- * Finds a resource, by its relative path, in all available search paths.
- * The search is performed starting at the last search path, and all the
- * way back to the first, enabling a cascading-type system of overrides
- * for all resources.
- *
- * @throws RuntimeException If resource cannot be found in any of the available paths
- *
- * @param string $resource
- * @return string
- */
- protected function getResource($resource)
- {
- // If the resource was found before, we can speed things up
- // by caching its absolute, resolved path:
- if (isset($this->resourceCache[$resource])) {
- return $this->resourceCache[$resource];
- }
- // Search through available search paths, until we find the
- // resource we're after:
- foreach ($this->searchPaths as $path) {
- $fullPath = $path . "/$resource";
- if (is_file($fullPath)) {
- // Cache the result:
- $this->resourceCache[$resource] = $fullPath;
- return $fullPath;
- }
- }
- // If we got this far, nothing was found.
- throw new RuntimeException(
- "Could not find resource '$resource' in any resource paths."
- . "(searched: " . join(", ", $this->searchPaths). ")"
- );
- }
- /**
- * @deprecated
- *
- * @return string
- */
- public function getResourcesPath()
- {
- $allPaths = $this->getResourcePaths();
- // Compat: return only the first path added
- return end($allPaths) ?: null;
- }
- /**
- * @deprecated
- *
- * @param string $resourcesPath
- * @return void
- */
- public function setResourcesPath($resourcesPath)
- {
- $this->addResourcePath($resourcesPath);
- }
- /**
- * @return int|null
- */
- public function handleUserDebug($name2,$array)
- {
- if (!$this->handleUnconditionally()) {
- // Check conditions for outputting HTML:
- // @todo: Make this more robust
- if (php_sapi_name() === 'cli') {
- // Help users who have been relying on an internal test value
- // fix their code to the proper method
- if (isset($_ENV['whoops-test'])) {
- throw new \Exception(
- 'Use handleUnconditionally instead of whoops-test'
- .' environment variable'
- );
- }
- return Handler::DONE;
- }
- }
- // @todo: Make this more dynamic
- $helper = new TemplateHelper();
- $templateFile = $this->getResource("views/layout.html.php");
- $cssFile = $this->getResource("css/whoops.base.css");
- $zeptoFile = $this->getResource("js/zepto.min.js");
- $jsFile = $this->getResource("js/whoops.base.js");
- if ($this->customCss) {
- $customCssFile = $this->getResource($this->customCss);
- }
- //$inspector = $this->getInspector();
- $frames = array();
- $code = 1;
- //
- // List of variables that will be passed to the layout template.
- $vars = array(
- "page_title" => $this->getPageTitle(),
- // @todo: Asset compiler
- "stylesheet" => file_get_contents($cssFile),
- "zepto" => file_get_contents($zeptoFile),
- "javascript" => file_get_contents($jsFile),
- // Template paths:
- "header" => $this->getResource("views/header.html.php"),
- "frame_list" => $this->getResource("views/frame_list.html.php"),
- "frame_code" => $this->getResource("views/frame_code.html.php"),
- "env_details" => $this->getResource("views/env_details.html.php"),
- "title" => $this->getPageTitle(),
- "name" => array("Fiesta","Debug"),
- "message" => $name2,
- "code" => $code,
- "plain_exception" => "DebugStatus thrown with message 'hhhh'\n
- \n
- Stacktrace:\n
- #8 DebugStatus in C:\wamp\www\fiesta\core\Debug.php:10\n
- #7 Debug:stop in C:\wamp\www\fiesta\app\Routes.php:17\n
- #6 App:{closure} in <#unknown>:0\n
- #5 call_user_func_array in C:\wamp\www\fiesta\core\Access\Routes_2.php:405\n
- #4 Routes:runRoute in C:\wamp\www\fiesta\core\Access\Routes_2.php:303\n
- #3 Routes:exec in C:\wamp\www\fiesta\core\Access\Routes_2.php:246\n
- #2 Routes:run in C:\wamp\www\fiesta\core\Ini.php:147\n
- #1 App:run in C:\wamp\www\fiesta\bootstrap\start.php:28\n
- #0 require in C:\wamp\www\fiesta\public\index.php:13",
- "frames" => $frames,
- "has_frames" => !!count($frames),
- "handler" => $this,
- "handlers" => array($this),
- "tables" => array(
- "Selected parameters" => $array,
- "Server/Request Data" => $_SERVER,
- "GET Data" => $_GET,
- "POST Data" => $_POST,
- "Files" => $_FILES,
- "Cookies" => $_COOKIE,
- "Session" => isset($_SESSION) ? $_SESSION : array(),
- "Environment Variables" => $_ENV,
-
- ),
- );
- if (isset($customCssFile)) {
- $vars["stylesheet"] .= file_get_contents($customCssFile);
- }
- // Add extra entries list of data tables:
- // @todo: Consolidate addDataTable and addDataTableCallback
- $extraTables = array_map(function ($table) {
- return $table instanceof \Closure ? $table() : $table;
- }, $this->getDataTables());
- $vars["tables"] = array_merge($extraTables, $vars["tables"]);
- $helper->setVariables($vars);
- $helper->render($templateFile);
- return Handler::QUIT;
- }
- }