ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
PrettyPageHandler.php
Go to the documentation of this file.
1<?php
7namespace Whoops\Handler;
8
9use InvalidArgumentException;
10use RuntimeException;
14
16{
23 private $searchPaths = array();
24
30 private $resourceCache = array();
31
37 private $customCss = null;
38
42 private $extraTables = array();
43
47 private $handleUnconditionally = false;
48
52 private $pageTitle = "Whoops! There was an error.";
53
64 protected $editor;
65
70 protected $editors = array(
71 "sublime" => "subl://open?url=file://%file&line=%line",
72 "textmate" => "txmt://open?url=file://%file&line=%line",
73 "emacs" => "emacs://open?url=file://%file&line=%line",
74 "macvim" => "mvim://open/?url=file://%file&line=%line",
75 );
76
80 public function __construct()
81 {
82 if (ini_get('xdebug.file_link_format') || extension_loaded('xdebug')) {
83 // Register editor using xdebug's file_link_format option.
84 $this->editors['xdebug'] = function ($file, $line) {
85 return str_replace(array('%f', '%l'), array($file, $line), ini_get('xdebug.file_link_format'));
86 };
87 }
88
89 // Add the default, local resource search path:
90 $this->searchPaths[] = __DIR__ . "/../Resources";
91 }
92
96 public function handle()
97 {
98 if (!$this->handleUnconditionally()) {
99 // Check conditions for outputting HTML:
100 // @todo: Make this more robust
101 if (php_sapi_name() === 'cli') {
102 // Help users who have been relying on an internal test value
103 // fix their code to the proper method
104 if (isset($_ENV['whoops-test'])) {
105 throw new \Exception(
106 'Use handleUnconditionally instead of whoops-test'
107 .' environment variable'
108 );
109 }
110
111 return Handler::DONE;
112 }
113 }
114
115 // @todo: Make this more dynamic
116 $helper = new TemplateHelper();
117
118 $templateFile = $this->getResource("views/layout.html.php");
119 $cssFile = $this->getResource("css/whoops.base.css");
120 $zeptoFile = $this->getResource("js/zepto.min.js");
121 $jsFile = $this->getResource("js/whoops.base.js");
122
123 if ($this->customCss) {
124 $customCssFile = $this->getResource($this->customCss);
125 }
126
127 $inspector = $this->getInspector();
128 $frames = $inspector->getFrames();
129
130 $code = $inspector->getException()->getCode();
131
132 if ($inspector->getException() instanceof \ErrorException) {
134 }
135
136 // List of variables that will be passed to the layout template.
137 $vars = array(
138 "page_title" => $this->getPageTitle(),
139
140 // @todo: Asset compiler
141 "stylesheet" => file_get_contents($cssFile),
142 "zepto" => file_get_contents($zeptoFile),
143 "javascript" => file_get_contents($jsFile),
144
145 // Template paths:
146 "header" => $this->getResource("views/header.html.php"),
147 "frame_list" => $this->getResource("views/frame_list.html.php"),
148 "frame_code" => $this->getResource("views/frame_code.html.php"),
149 "env_details" => $this->getResource("views/env_details.html.php"),
150
151 "title" => $this->getPageTitle(),
152 "name" => explode("\\", $inspector->getExceptionName()),
153 "message" => $inspector->getException()->getMessage(),
154 "code" => $code,
155 "plain_exception" => Formatter::formatExceptionPlain($inspector),
156 "frames" => $frames,
157 "has_frames" => !!count($frames),
158 "handler" => $this,
159 "handlers" => $this->getRun()->getHandlers(),
160
161 "tables" => array(
162 "Server/Request Data" => $_SERVER,
163 "GET Data" => $_GET,
164 "POST Data" => $_POST,
165 "Files" => $_FILES,
166 "Cookies" => $_COOKIE,
167 "Session" => isset($_SESSION) ? $_SESSION : array(),
168 "Environment Variables" => $_ENV,
169 ),
170 );
171
172 if (isset($customCssFile)) {
173 $vars["stylesheet"] .= file_get_contents($customCssFile);
174 }
175
176 // Add extra entries list of data tables:
177 // @todo: Consolidate addDataTable and addDataTableCallback
178 $extraTables = array_map(function ($table) {
179 return $table instanceof \Closure ? $table() : $table;
180 }, $this->getDataTables());
181 $vars["tables"] = array_merge($extraTables, $vars["tables"]);
182
183 $helper->setVariables($vars);
184 $helper->render($templateFile);
185
186 return Handler::QUIT;
187 }
188
196 public function addDataTable($label, array $data)
197 {
198 $this->extraTables[$label] = $data;
199 }
200
211 public function addDataTableCallback($label, /* callable */ $callback)
212 {
213 if (!is_callable($callback)) {
214 throw new InvalidArgumentException('Expecting callback argument to be callable');
215 }
216
217 $this->extraTables[$label] = function () use ($callback) {
218 try {
219 $result = call_user_func($callback);
220
221 // Only return the result if it can be iterated over by foreach().
222 return is_array($result) || $result instanceof \Traversable ? $result : array();
223 } catch (\Exception $e) {
224 // Don't allow failure to break the rendering of the original exception.
225 return array();
226 }
227 };
228 }
229
237 public function getDataTables($label = null)
238 {
239 if ($label !== null) {
240 return isset($this->extraTables[$label]) ?
241 $this->extraTables[$label] : array();
242 }
243
244 return $this->extraTables;
245 }
246
254 public function handleUnconditionally($value = null)
255 {
256 if (func_num_args() == 0) {
258 }
259
260 $this->handleUnconditionally = (bool) $value;
261 }
262
279 public function addEditor($identifier, $resolver)
280 {
281 $this->editors[$identifier] = $resolver;
282 }
283
298 public function setEditor($editor)
299 {
300 if (!is_callable($editor) && !isset($this->editors[$editor])) {
301 throw new InvalidArgumentException(
302 "Unknown editor identifier: $editor. Known editors:" .
303 implode(",", array_keys($this->editors))
304 );
305 }
306
307 $this->editor = $editor;
308 }
309
321 public function getEditorHref($filePath, $line)
322 {
323 if ($this->editor === null) {
324 return false;
325 }
326
328 if (is_string($editor)) {
329 $editor = $this->editors[$editor];
330 }
331
332 if (is_callable($editor)) {
333 $editor = call_user_func($editor, $filePath, $line);
334 }
335
336 // Check that the editor is a string, and replace the
337 // %line and %file placeholders:
338 if (!is_string($editor)) {
339 throw new InvalidArgumentException(
340 __METHOD__ . " should always resolve to a string; got something else instead"
341 );
342 }
343
344 $editor = str_replace("%line", rawurlencode($line), $editor);
345 $editor = str_replace("%file", rawurlencode($filePath), $editor);
346
347 return $editor;
348 }
349
354 public function setPageTitle($title)
355 {
356 $this->pageTitle = (string) $title;
357 }
358
362 public function getPageTitle()
363 {
364 return $this->pageTitle;
365 }
366
376 public function addResourcePath($path)
377 {
378 if (!is_dir($path)) {
379 throw new InvalidArgumentException(
380 "'$path' is not a valid directory"
381 );
382 }
383
384 array_unshift($this->searchPaths, $path);
385 }
386
393 public function addCustomCss($name)
394 {
395 $this->customCss = $name;
396 }
397
401 public function getResourcePaths()
402 {
403 return $this->searchPaths;
404 }
405
417 protected function getResource($resource)
418 {
419 // If the resource was found before, we can speed things up
420 // by caching its absolute, resolved path:
421 if (isset($this->resourceCache[$resource])) {
422 return $this->resourceCache[$resource];
423 }
424
425 // Search through available search paths, until we find the
426 // resource we're after:
427 foreach ($this->searchPaths as $path) {
428 $fullPath = $path . "/$resource";
429
430 if (is_file($fullPath)) {
431 // Cache the result:
432 $this->resourceCache[$resource] = $fullPath;
433 return $fullPath;
434 }
435 }
436
437 // If we got this far, nothing was found.
438 throw new RuntimeException(
439 "Could not find resource '$resource' in any resource paths."
440 . "(searched: " . join(", ", $this->searchPaths). ")"
441 );
442 }
443
449 public function getResourcesPath()
450 {
451 $allPaths = $this->getResourcePaths();
452
453 // Compat: return only the first path added
454 return end($allPaths) ?: null;
455 }
456
463 public function setResourcesPath($resourcesPath)
464 {
465 $this->addResourcePath($resourcesPath);
466 }
467}
$result
print $file
$_GET["client_id"]
$_SESSION["AccountId"]
Wraps ErrorException; mostly used for typing (at least now) to easily cleanup the stack trace of redu...
static formatExceptionPlain(Inspector $inspector)
Definition: Formatter.php:50
Abstract implementation of a Handler.
Definition: Handler.php:17
const DONE
Return constants that can be returned from Handler::handle to message the handler walker.
Definition: Handler.php:22
getEditorHref($filePath, $line)
Given a string file path, and an integer file line, executes the editor resolver and returns,...
addEditor($identifier, $resolver)
addDataTableCallback($label, $callback)
Lazily adds an entry to the list of tables displayed in the table.
handleUnconditionally($value=null)
Allows to disable all attempts to dynamically decide whether to handle or return prematurely.
addResourcePath($path)
Adds a path to the list of paths to be searched for resources.
addCustomCss($name)
Adds a custom css file to be loaded.
addDataTable($label, array $data)
Adds an entry to the list of tables displayed in the template.
getDataTables($label=null)
Returns all the extra data tables registered with this handler.
getResource($resource)
Finds a resource, by its relative path, in all available search paths.
static translateErrorCode($error_code)
Translate ErrorException code into the represented constant.
Definition: Misc.php:32
Exposes useful tools for working with/in templates.
$_POST['username']
Definition: cron.php:12
$_COOKIE["ilClientId"]
Definition: cron.php:11
$data
$code
Definition: example_050.php:99
Whoops - php errors for cool kids.
$path
Definition: index.php:22
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']