Mercurial > hg > Members > shoshi > webvirt
comparison cake/libs/debugger.php @ 0:261e66bd5a0c
hg init
author | Shoshi TAMAKI <shoshi@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Sun, 24 Jul 2011 21:08:31 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:261e66bd5a0c |
---|---|
1 <?php | |
2 /** | |
3 * Framework debugging and PHP error-handling class | |
4 * | |
5 * Provides enhanced logging, stack traces, and rendering debug views | |
6 * | |
7 * PHP versions 4 and 5 | |
8 * | |
9 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) | |
10 * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) | |
11 * | |
12 * Licensed under The MIT License | |
13 * Redistributions of files must retain the above copyright notice. | |
14 * | |
15 * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) | |
16 * @link http://cakephp.org CakePHP(tm) Project | |
17 * @package cake | |
18 * @subpackage cake.cake.libs | |
19 * @since CakePHP(tm) v 1.2.4560 | |
20 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) | |
21 */ | |
22 | |
23 /** | |
24 * Included libraries. | |
25 * | |
26 */ | |
27 if (!class_exists('Object')) { | |
28 require_once LIBS . 'object.php'; | |
29 } | |
30 if (!class_exists('CakeLog')) { | |
31 require_once LIBS . 'cake_log.php'; | |
32 } | |
33 if (!class_exists('String')) { | |
34 require_once LIBS . 'string.php'; | |
35 } | |
36 | |
37 /** | |
38 * Provide custom logging and error handling. | |
39 * | |
40 * Debugger overrides PHP's default error handling to provide stack traces and enhanced logging | |
41 * | |
42 * @package cake | |
43 * @subpackage cake.cake.libs | |
44 * @link http://book.cakephp.org/view/1191/Using-the-Debugger-Class | |
45 */ | |
46 class Debugger extends Object { | |
47 | |
48 /** | |
49 * A list of errors generated by the application. | |
50 * | |
51 * @var array | |
52 * @access public | |
53 */ | |
54 var $errors = array(); | |
55 | |
56 /** | |
57 * Contains the base URL for error code documentation. | |
58 * | |
59 * @var string | |
60 * @access public | |
61 */ | |
62 var $helpPath = null; | |
63 | |
64 /** | |
65 * The current output format. | |
66 * | |
67 * @var string | |
68 * @access protected | |
69 */ | |
70 var $_outputFormat = 'js'; | |
71 | |
72 /** | |
73 * Templates used when generating trace or error strings. Can be global or indexed by the format | |
74 * value used in $_outputFormat. | |
75 * | |
76 * @var string | |
77 * @access protected | |
78 */ | |
79 var $_templates = array( | |
80 'log' => array( | |
81 'trace' => '{:reference} - {:path}, line {:line}', | |
82 'error' => "{:error} ({:code}): {:description} in [{:file}, line {:line}]" | |
83 ), | |
84 'js' => array( | |
85 'error' => '', | |
86 'info' => '', | |
87 'trace' => '<pre class="stack-trace">{:trace}</pre>', | |
88 'code' => '', | |
89 'context' => '', | |
90 'links' => array() | |
91 ), | |
92 'html' => array( | |
93 'trace' => '<pre class="cake-debug trace"><b>Trace</b> <p>{:trace}</p></pre>', | |
94 'context' => '<pre class="cake-debug context"><b>Context</b> <p>{:context}</p></pre>' | |
95 ), | |
96 'txt' => array( | |
97 'error' => "{:error}: {:code} :: {:description} on line {:line} of {:path}\n{:info}", | |
98 'context' => "Context:\n{:context}\n", | |
99 'trace' => "Trace:\n{:trace}\n", | |
100 'code' => '', | |
101 'info' => '' | |
102 ), | |
103 'base' => array( | |
104 'traceLine' => '{:reference} - {:path}, line {:line}' | |
105 ) | |
106 ); | |
107 | |
108 /** | |
109 * Holds current output data when outputFormat is false. | |
110 * | |
111 * @var string | |
112 * @access private | |
113 */ | |
114 var $_data = array(); | |
115 | |
116 /** | |
117 * Constructor. | |
118 * | |
119 */ | |
120 function __construct() { | |
121 $docRef = ini_get('docref_root'); | |
122 | |
123 if (empty($docRef) && function_exists('ini_set')) { | |
124 ini_set('docref_root', 'http://php.net/'); | |
125 } | |
126 if (!defined('E_RECOVERABLE_ERROR')) { | |
127 define('E_RECOVERABLE_ERROR', 4096); | |
128 } | |
129 if (!defined('E_DEPRECATED')) { | |
130 define('E_DEPRECATED', 8192); | |
131 } | |
132 | |
133 $e = '<pre class="cake-debug">'; | |
134 $e .= '<a href="javascript:void(0);" onclick="document.getElementById(\'{:id}-trace\')'; | |
135 $e .= '.style.display = (document.getElementById(\'{:id}-trace\').style.display == '; | |
136 $e .= '\'none\' ? \'\' : \'none\');"><b>{:error}</b> ({:code})</a>: {:description} '; | |
137 $e .= '[<b>{:path}</b>, line <b>{:line}</b>]'; | |
138 | |
139 $e .= '<div id="{:id}-trace" class="cake-stack-trace" style="display: none;">'; | |
140 $e .= '{:links}{:info}</div>'; | |
141 $e .= '</pre>'; | |
142 $this->_templates['js']['error'] = $e; | |
143 | |
144 $t = '<div id="{:id}-trace" class="cake-stack-trace" style="display: none;">'; | |
145 $t .= '{:context}{:code}{:trace}</div>'; | |
146 $this->_templates['js']['info'] = $t; | |
147 | |
148 $links = array(); | |
149 $link = '<a href="javascript:void(0);" onclick="document.getElementById(\'{:id}-code\')'; | |
150 $link .= '.style.display = (document.getElementById(\'{:id}-code\').style.display == '; | |
151 $link .= '\'none\' ? \'\' : \'none\')">Code</a>'; | |
152 $links['code'] = $link; | |
153 | |
154 $link = '<a href="javascript:void(0);" onclick="document.getElementById(\'{:id}-context\')'; | |
155 $link .= '.style.display = (document.getElementById(\'{:id}-context\').style.display == '; | |
156 $link .= '\'none\' ? \'\' : \'none\')">Context</a>'; | |
157 $links['context'] = $link; | |
158 | |
159 $links['help'] = '<a href="{:helpPath}{:code}" target="_blank">Help</a>'; | |
160 $this->_templates['js']['links'] = $links; | |
161 | |
162 $this->_templates['js']['context'] = '<pre id="{:id}-context" class="cake-context" '; | |
163 $this->_templates['js']['context'] .= 'style="display: none;">{:context}</pre>'; | |
164 | |
165 $this->_templates['js']['code'] = '<div id="{:id}-code" class="cake-code-dump" '; | |
166 $this->_templates['js']['code'] .= 'style="display: none;"><pre>{:code}</pre></div>'; | |
167 | |
168 $e = '<pre class="cake-debug"><b>{:error}</b> ({:code}) : {:description} '; | |
169 $e .= '[<b>{:path}</b>, line <b>{:line}]</b></pre>'; | |
170 $this->_templates['html']['error'] = $e; | |
171 | |
172 $this->_templates['html']['context'] = '<pre class="cake-debug context"><b>Context</b> '; | |
173 $this->_templates['html']['context'] .= '<p>{:context}</p></pre>'; | |
174 } | |
175 | |
176 /** | |
177 * Returns a reference to the Debugger singleton object instance. | |
178 * | |
179 * @return object | |
180 * @access public | |
181 * @static | |
182 */ | |
183 function &getInstance($class = null) { | |
184 static $instance = array(); | |
185 if (!empty($class)) { | |
186 if (!$instance || strtolower($class) != strtolower(get_class($instance[0]))) { | |
187 $instance[0] = & new $class(); | |
188 if (Configure::read() > 0) { | |
189 Configure::version(); // Make sure the core config is loaded | |
190 $instance[0]->helpPath = Configure::read('Cake.Debugger.HelpPath'); | |
191 } | |
192 } | |
193 } | |
194 | |
195 if (!$instance) { | |
196 $instance[0] =& new Debugger(); | |
197 if (Configure::read() > 0) { | |
198 Configure::version(); // Make sure the core config is loaded | |
199 $instance[0]->helpPath = Configure::read('Cake.Debugger.HelpPath'); | |
200 } | |
201 } | |
202 return $instance[0]; | |
203 } | |
204 | |
205 /** | |
206 * Formats and outputs the contents of the supplied variable. | |
207 * | |
208 * @param $var mixed the variable to dump | |
209 * @return void | |
210 * @see Debugger::exportVar() | |
211 * @access public | |
212 * @static | |
213 * @link http://book.cakephp.org/view/1191/Using-the-Debugger-Class | |
214 */ | |
215 function dump($var) { | |
216 $_this =& Debugger::getInstance(); | |
217 pr($_this->exportVar($var)); | |
218 } | |
219 | |
220 /** | |
221 * Creates an entry in the log file. The log entry will contain a stack trace from where it was called. | |
222 * as well as export the variable using exportVar. By default the log is written to the debug log. | |
223 * | |
224 * @param $var mixed Variable or content to log | |
225 * @param $level int type of log to use. Defaults to LOG_DEBUG | |
226 * @return void | |
227 * @static | |
228 * @link http://book.cakephp.org/view/1191/Using-the-Debugger-Class | |
229 */ | |
230 function log($var, $level = LOG_DEBUG) { | |
231 $_this =& Debugger::getInstance(); | |
232 $source = $_this->trace(array('start' => 1)) . "\n"; | |
233 CakeLog::write($level, "\n" . $source . $_this->exportVar($var)); | |
234 } | |
235 | |
236 /** | |
237 * Overrides PHP's default error handling. | |
238 * | |
239 * @param integer $code Code of error | |
240 * @param string $description Error description | |
241 * @param string $file File on which error occurred | |
242 * @param integer $line Line that triggered the error | |
243 * @param array $context Context | |
244 * @return boolean true if error was handled | |
245 * @access public | |
246 */ | |
247 function handleError($code, $description, $file = null, $line = null, $context = null) { | |
248 if (error_reporting() == 0 || $code === 2048 || $code === 8192) { | |
249 return; | |
250 } | |
251 | |
252 $_this =& Debugger::getInstance(); | |
253 | |
254 if (empty($file)) { | |
255 $file = '[internal]'; | |
256 } | |
257 if (empty($line)) { | |
258 $line = '??'; | |
259 } | |
260 $path = $_this->trimPath($file); | |
261 | |
262 $info = compact('code', 'description', 'file', 'line'); | |
263 if (!in_array($info, $_this->errors)) { | |
264 $_this->errors[] = $info; | |
265 } else { | |
266 return; | |
267 } | |
268 | |
269 switch ($code) { | |
270 case E_PARSE: | |
271 case E_ERROR: | |
272 case E_CORE_ERROR: | |
273 case E_COMPILE_ERROR: | |
274 case E_USER_ERROR: | |
275 $error = 'Fatal Error'; | |
276 $level = LOG_ERROR; | |
277 break; | |
278 case E_WARNING: | |
279 case E_USER_WARNING: | |
280 case E_COMPILE_WARNING: | |
281 case E_RECOVERABLE_ERROR: | |
282 $error = 'Warning'; | |
283 $level = LOG_WARNING; | |
284 break; | |
285 case E_NOTICE: | |
286 case E_USER_NOTICE: | |
287 $error = 'Notice'; | |
288 $level = LOG_NOTICE; | |
289 break; | |
290 default: | |
291 return; | |
292 break; | |
293 } | |
294 | |
295 $helpCode = null; | |
296 if (!empty($_this->helpPath) && preg_match('/.*\[([0-9]+)\]$/', $description, $codes)) { | |
297 if (isset($codes[1])) { | |
298 $helpID = $codes[1]; | |
299 $description = trim(preg_replace('/\[[0-9]+\]$/', '', $description)); | |
300 } | |
301 } | |
302 | |
303 $data = compact( | |
304 'level', 'error', 'code', 'helpID', 'description', 'file', 'path', 'line', 'context' | |
305 ); | |
306 echo $_this->_output($data); | |
307 | |
308 if (Configure::read('log')) { | |
309 $tpl = $_this->_templates['log']['error']; | |
310 $options = array('before' => '{:', 'after' => '}'); | |
311 CakeLog::write($level, String::insert($tpl, $data, $options)); | |
312 } | |
313 | |
314 if ($error == 'Fatal Error') { | |
315 exit(); | |
316 } | |
317 return true; | |
318 } | |
319 | |
320 /** | |
321 * Outputs a stack trace based on the supplied options. | |
322 * | |
323 * ### Options | |
324 * | |
325 * - `depth` - The number of stack frames to return. Defaults to 999 | |
326 * - `format` - The format you want the return. Defaults to the currently selected format. If | |
327 * format is 'array' or 'points' the return will be an array. | |
328 * - `args` - Should arguments for functions be shown? If true, the arguments for each method call | |
329 * will be displayed. | |
330 * - `start` - The stack frame to start generating a trace from. Defaults to 0 | |
331 * | |
332 * @param array $options Format for outputting stack trace | |
333 * @return mixed Formatted stack trace | |
334 * @access public | |
335 * @static | |
336 * @link http://book.cakephp.org/view/1191/Using-the-Debugger-Class | |
337 */ | |
338 function trace($options = array()) { | |
339 $_this =& Debugger::getInstance(); | |
340 $defaults = array( | |
341 'depth' => 999, | |
342 'format' => $_this->_outputFormat, | |
343 'args' => false, | |
344 'start' => 0, | |
345 'scope' => null, | |
346 'exclude' => null | |
347 ); | |
348 $options += $defaults; | |
349 | |
350 $backtrace = debug_backtrace(); | |
351 $count = count($backtrace); | |
352 $back = array(); | |
353 | |
354 $_trace = array( | |
355 'line' => '??', | |
356 'file' => '[internal]', | |
357 'class' => null, | |
358 'function' => '[main]' | |
359 ); | |
360 | |
361 for ($i = $options['start']; $i < $count && $i < $options['depth']; $i++) { | |
362 $trace = array_merge(array('file' => '[internal]', 'line' => '??'), $backtrace[$i]); | |
363 | |
364 if (isset($backtrace[$i + 1])) { | |
365 $next = array_merge($_trace, $backtrace[$i + 1]); | |
366 $reference = $next['function']; | |
367 | |
368 if (!empty($next['class'])) { | |
369 $reference = $next['class'] . '::' . $reference . '('; | |
370 if ($options['args'] && isset($next['args'])) { | |
371 $args = array(); | |
372 foreach ($next['args'] as $arg) { | |
373 $args[] = Debugger::exportVar($arg); | |
374 } | |
375 $reference .= join(', ', $args); | |
376 } | |
377 $reference .= ')'; | |
378 } | |
379 } else { | |
380 $reference = '[main]'; | |
381 } | |
382 if (in_array($reference, array('call_user_func_array', 'trigger_error'))) { | |
383 continue; | |
384 } | |
385 if ($options['format'] == 'points' && $trace['file'] != '[internal]') { | |
386 $back[] = array('file' => $trace['file'], 'line' => $trace['line']); | |
387 } elseif ($options['format'] == 'array') { | |
388 $back[] = $trace; | |
389 } else { | |
390 if (isset($_this->_templates[$options['format']]['traceLine'])) { | |
391 $tpl = $_this->_templates[$options['format']]['traceLine']; | |
392 } else { | |
393 $tpl = $_this->_templates['base']['traceLine']; | |
394 } | |
395 $trace['path'] = Debugger::trimPath($trace['file']); | |
396 $trace['reference'] = $reference; | |
397 unset($trace['object'], $trace['args']); | |
398 $back[] = String::insert($tpl, $trace, array('before' => '{:', 'after' => '}')); | |
399 } | |
400 } | |
401 | |
402 if ($options['format'] == 'array' || $options['format'] == 'points') { | |
403 return $back; | |
404 } | |
405 return implode("\n", $back); | |
406 } | |
407 | |
408 /** | |
409 * Shortens file paths by replacing the application base path with 'APP', and the CakePHP core | |
410 * path with 'CORE'. | |
411 * | |
412 * @param string $path Path to shorten | |
413 * @return string Normalized path | |
414 * @access public | |
415 * @static | |
416 */ | |
417 function trimPath($path) { | |
418 if (!defined('CAKE_CORE_INCLUDE_PATH') || !defined('APP')) { | |
419 return $path; | |
420 } | |
421 | |
422 if (strpos($path, APP) === 0) { | |
423 return str_replace(APP, 'APP' . DS, $path); | |
424 } elseif (strpos($path, CAKE_CORE_INCLUDE_PATH) === 0) { | |
425 return str_replace(CAKE_CORE_INCLUDE_PATH, 'CORE', $path); | |
426 } elseif (strpos($path, ROOT) === 0) { | |
427 return str_replace(ROOT, 'ROOT', $path); | |
428 } | |
429 $corePaths = App::core('cake'); | |
430 | |
431 foreach ($corePaths as $corePath) { | |
432 if (strpos($path, $corePath) === 0) { | |
433 return str_replace($corePath, 'CORE' .DS . 'cake' .DS, $path); | |
434 } | |
435 } | |
436 return $path; | |
437 } | |
438 | |
439 /** | |
440 * Grabs an excerpt from a file and highlights a given line of code | |
441 * | |
442 * @param string $file Absolute path to a PHP file | |
443 * @param integer $line Line number to highlight | |
444 * @param integer $context Number of lines of context to extract above and below $line | |
445 * @return array Set of lines highlighted | |
446 * @access public | |
447 * @static | |
448 * @link http://book.cakephp.org/view/1191/Using-the-Debugger-Class | |
449 */ | |
450 function excerpt($file, $line, $context = 2) { | |
451 $data = $lines = array(); | |
452 if (!file_exists($file)) { | |
453 return array(); | |
454 } | |
455 $data = @explode("\n", file_get_contents($file)); | |
456 | |
457 if (empty($data) || !isset($data[$line])) { | |
458 return; | |
459 } | |
460 for ($i = $line - ($context + 1); $i < $line + $context; $i++) { | |
461 if (!isset($data[$i])) { | |
462 continue; | |
463 } | |
464 $string = str_replace(array("\r\n", "\n"), "", highlight_string($data[$i], true)); | |
465 if ($i == $line) { | |
466 $lines[] = '<span class="code-highlight">' . $string . '</span>'; | |
467 } else { | |
468 $lines[] = $string; | |
469 } | |
470 } | |
471 return $lines; | |
472 } | |
473 | |
474 /** | |
475 * Converts a variable to a string for debug output. | |
476 * | |
477 * @param string $var Variable to convert | |
478 * @return string Variable as a formatted string | |
479 * @access public | |
480 * @static | |
481 * @link http://book.cakephp.org/view/1191/Using-the-Debugger-Class | |
482 */ | |
483 function exportVar($var, $recursion = 0) { | |
484 $_this =& Debugger::getInstance(); | |
485 switch (strtolower(gettype($var))) { | |
486 case 'boolean': | |
487 return ($var) ? 'true' : 'false'; | |
488 break; | |
489 case 'integer': | |
490 case 'double': | |
491 return $var; | |
492 break; | |
493 case 'string': | |
494 if (trim($var) == "") { | |
495 return '""'; | |
496 } | |
497 return '"' . h($var) . '"'; | |
498 break; | |
499 case 'object': | |
500 return get_class($var) . "\n" . $_this->__object($var); | |
501 case 'array': | |
502 $out = "array("; | |
503 $vars = array(); | |
504 foreach ($var as $key => $val) { | |
505 if ($recursion >= 0) { | |
506 if (is_numeric($key)) { | |
507 $vars[] = "\n\t" . $_this->exportVar($val, $recursion - 1); | |
508 } else { | |
509 $vars[] = "\n\t" .$_this->exportVar($key, $recursion - 1) | |
510 . ' => ' . $_this->exportVar($val, $recursion - 1); | |
511 } | |
512 } | |
513 } | |
514 $n = null; | |
515 if (!empty($vars)) { | |
516 $n = "\n"; | |
517 } | |
518 return $out . implode(",", $vars) . "{$n})"; | |
519 break; | |
520 case 'resource': | |
521 return strtolower(gettype($var)); | |
522 break; | |
523 case 'null': | |
524 return 'null'; | |
525 break; | |
526 } | |
527 } | |
528 | |
529 /** | |
530 * Handles object to string conversion. | |
531 * | |
532 * @param string $var Object to convert | |
533 * @return string | |
534 * @access private | |
535 * @see Debugger::exportVar() | |
536 */ | |
537 function __object($var) { | |
538 $out = array(); | |
539 | |
540 if (is_object($var)) { | |
541 $className = get_class($var); | |
542 $objectVars = get_object_vars($var); | |
543 | |
544 foreach ($objectVars as $key => $value) { | |
545 if (is_object($value)) { | |
546 $value = get_class($value) . ' object'; | |
547 } elseif (is_array($value)) { | |
548 $value = 'array'; | |
549 } elseif ($value === null) { | |
550 $value = 'NULL'; | |
551 } elseif (in_array(gettype($value), array('boolean', 'integer', 'double', 'string', 'array', 'resource'))) { | |
552 $value = Debugger::exportVar($value); | |
553 } | |
554 $out[] = "$className::$$key = " . $value; | |
555 } | |
556 } | |
557 return implode("\n", $out); | |
558 } | |
559 | |
560 /** | |
561 * Switches output format, updates format strings | |
562 * | |
563 * @param string $format Format to use, including 'js' for JavaScript-enhanced HTML, 'html' for | |
564 * straight HTML output, or 'txt' for unformatted text. | |
565 * @param array $strings Template strings to be used for the output format. | |
566 * @access protected | |
567 */ | |
568 function output($format = null, $strings = array()) { | |
569 $_this =& Debugger::getInstance(); | |
570 $data = null; | |
571 | |
572 if (is_null($format)) { | |
573 return $_this->_outputFormat; | |
574 } | |
575 | |
576 if (!empty($strings)) { | |
577 if (isset($_this->_templates[$format])) { | |
578 if (isset($strings['links'])) { | |
579 $_this->_templates[$format]['links'] = array_merge( | |
580 $_this->_templates[$format]['links'], | |
581 $strings['links'] | |
582 ); | |
583 unset($strings['links']); | |
584 } | |
585 $_this->_templates[$format] = array_merge($_this->_templates[$format], $strings); | |
586 } else { | |
587 $_this->_templates[$format] = $strings; | |
588 } | |
589 return $_this->_templates[$format]; | |
590 } | |
591 | |
592 if ($format === true && !empty($_this->_data)) { | |
593 $data = $_this->_data; | |
594 $_this->_data = array(); | |
595 $format = false; | |
596 } | |
597 $_this->_outputFormat = $format; | |
598 | |
599 return $data; | |
600 } | |
601 | |
602 /** | |
603 * Renders error messages | |
604 * | |
605 * @param array $data Data about the current error | |
606 * @access private | |
607 */ | |
608 function _output($data = array()) { | |
609 $defaults = array( | |
610 'level' => 0, | |
611 'error' => 0, | |
612 'code' => 0, | |
613 'helpID' => null, | |
614 'description' => '', | |
615 'file' => '', | |
616 'line' => 0, | |
617 'context' => array() | |
618 ); | |
619 $data += $defaults; | |
620 | |
621 $files = $this->trace(array('start' => 2, 'format' => 'points')); | |
622 $code = $this->excerpt($files[0]['file'], $files[0]['line'] - 1, 1); | |
623 $trace = $this->trace(array('start' => 2, 'depth' => '20')); | |
624 $insertOpts = array('before' => '{:', 'after' => '}'); | |
625 $context = array(); | |
626 $links = array(); | |
627 $info = ''; | |
628 | |
629 foreach ((array)$data['context'] as $var => $value) { | |
630 $context[] = "\${$var}\t=\t" . $this->exportVar($value, 1); | |
631 } | |
632 | |
633 switch ($this->_outputFormat) { | |
634 case false: | |
635 $this->_data[] = compact('context', 'trace') + $data; | |
636 return; | |
637 case 'log': | |
638 $this->log(compact('context', 'trace') + $data); | |
639 return; | |
640 } | |
641 | |
642 if (empty($this->_outputFormat) || !isset($this->_templates[$this->_outputFormat])) { | |
643 $this->_outputFormat = 'js'; | |
644 } | |
645 | |
646 $data['id'] = 'cakeErr' . count($this->errors); | |
647 $tpl = array_merge($this->_templates['base'], $this->_templates[$this->_outputFormat]); | |
648 $insert = array('context' => join("\n", $context), 'helpPath' => $this->helpPath) + $data; | |
649 | |
650 $detect = array('help' => 'helpID', 'context' => 'context'); | |
651 | |
652 if (isset($tpl['links'])) { | |
653 foreach ($tpl['links'] as $key => $val) { | |
654 if (isset($detect[$key]) && empty($insert[$detect[$key]])) { | |
655 continue; | |
656 } | |
657 $links[$key] = String::insert($val, $insert, $insertOpts); | |
658 } | |
659 } | |
660 | |
661 foreach (array('code', 'context', 'trace') as $key) { | |
662 if (empty($$key) || !isset($tpl[$key])) { | |
663 continue; | |
664 } | |
665 if (is_array($$key)) { | |
666 $$key = join("\n", $$key); | |
667 } | |
668 $info .= String::insert($tpl[$key], compact($key) + $insert, $insertOpts); | |
669 } | |
670 $links = join(' | ', $links); | |
671 unset($data['context']); | |
672 | |
673 echo String::insert($tpl['error'], compact('links', 'info') + $data, $insertOpts); | |
674 } | |
675 | |
676 /** | |
677 * Verifies that the application's salt and cipher seed value has been changed from the default value. | |
678 * | |
679 * @access public | |
680 * @static | |
681 */ | |
682 function checkSecurityKeys() { | |
683 if (Configure::read('Security.salt') == 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi') { | |
684 trigger_error(__('Please change the value of \'Security.salt\' in app/config/core.php to a salt value specific to your application', true), E_USER_NOTICE); | |
685 } | |
686 | |
687 if (Configure::read('Security.cipherSeed') === '76859309657453542496749683645') { | |
688 trigger_error(__('Please change the value of \'Security.cipherSeed\' in app/config/core.php to a numeric (digits only) seed value specific to your application', true), E_USER_NOTICE); | |
689 } | |
690 } | |
691 | |
692 /** | |
693 * Invokes the given debugger object as the current error handler, taking over control from the | |
694 * previous handler in a stack-like hierarchy. | |
695 * | |
696 * @param object $debugger A reference to the Debugger object | |
697 * @access public | |
698 * @static | |
699 * @link http://book.cakephp.org/view/1191/Using-the-Debugger-Class | |
700 */ | |
701 function invoke(&$debugger) { | |
702 set_error_handler(array(&$debugger, 'handleError')); | |
703 } | |
704 } | |
705 | |
706 if (!defined('DISABLE_DEFAULT_ERROR_HANDLING')) { | |
707 Debugger::invoke(Debugger::getInstance()); | |
708 } |