PageRenderTime 62ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 1ms

/library/php_error.php

https://bitbucket.org/ethanal/tj-career-center-database-manager
PHP | 4411 lines | 3120 code | 475 blank | 816 comment | 387 complexity | 5b5f8a1b50def9bab175cf8a583a7e3e MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * @license
  4. *
  5. * PHP Error
  6. *
  7. * Copyright (c) 2012 Joseph Lenton
  8. * All rights reserved.
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions are met:
  12. * * Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * * Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. * * Neither the name of the <organization> nor the
  18. * names of its contributors may be used to endorse or promote products
  19. * derived from this software without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  22. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  23. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  24. * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  25. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  26. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  27. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  28. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  30. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. *
  32. * Uses:
  33. * JSMin-php https://github.com/rgrove/jsmin-php/
  34. * jQuery http://jquery.com/
  35. */
  36. /**
  37. * PHP Error
  38. *
  39. * --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
  40. *
  41. * WARNING! It is downright _DANGEROUS_ to use this in production, on
  42. * a live website. It should *ONLY* be used for development.
  43. *
  44. * PHP Error will kill your environment at will, clear the output
  45. * buffers, and allows HTML injection from exceptions.
  46. *
  47. * In future versions it plans to do far more then that.
  48. *
  49. * If you use it in development, awesome! If you use it in production,
  50. * you're an idiot.
  51. *
  52. * --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
  53. *
  54. * = Info
  55. *
  56. * A small API for replacing the standard PHP errors, with prettier
  57. * error reporting. This will change the error reporting level, and this
  58. * is deliberate, as I believe in strict development errors.
  59. *
  60. * simple usage:
  61. *
  62. * \php_error\reportErrors();
  63. *
  64. * Advanced example:
  65. *
  66. * There is more too it if you want more customized error handling. You
  67. * can pass in options, to customize the setup, and you get back a
  68. * handler you can alter at runtime.
  69. *
  70. * $handler = new \php_error\ErrorHandler( $myOptions );
  71. * $handler->turnOn();
  72. *
  73. * There should only ever be one handler! This is an (underdstandable)
  74. * limitation in PHP. It's because if an exception or error is raised,
  75. * then there is a single point of handling it.
  76. *
  77. * = INI Options
  78. *
  79. * - php_error.force_disabled When set to a true value (such as on),
  80. * this forces this to be off.
  81. * This is so you can disable this script
  82. * in your production servers ini file,
  83. * incase you accidentally upload this there.
  84. *
  85. * --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
  86. *
  87. * @author Joseph Lenton | https://github.com/josephlenton
  88. */
  89. namespace php_error;
  90. use \php_error\ErrorException,
  91. \php_error\FileLinesSet,
  92. \php_error\ErrorHandler,
  93. \php_error\JSMin,
  94. \php_error\JSMinException;
  95. use \Closure,
  96. \Exception,
  97. \InvalidArgumentException;
  98. use \ReflectionMethod,
  99. \ReflectionFunction,
  100. \ReflectionParameter;
  101. global $_php_error_already_setup,
  102. $_php_error_global_handler,
  103. $_php_error_is_ini_enabled;
  104. /*
  105. * Avoid being run twice.
  106. */
  107. if ( empty($_php_error_already_setup) ) {
  108. $_php_error_already_setup = true;
  109. /*
  110. * These are used as token identifiers by PHP.
  111. *
  112. * If they are missing, then they should never pop out of PHP,
  113. * so we just give them their future value.
  114. *
  115. * They are primarily here so I don't have to alter the 5.3
  116. * compliant code. Instead I can delete pre-5.3 code (this
  117. * code), in the future.
  118. *
  119. * As long as the value is unique, and does not clash with PHP,
  120. * then any number could be used. That is why they start counting
  121. * at 100,000.
  122. */
  123. if ( ! defined('T_DIR') ) {
  124. define( 'T_DIR', 100001 );
  125. }
  126. if ( ! defined('T_GOTO') ) {
  127. define( 'T_GOTO', 100002 );
  128. }
  129. if ( ! defined('T_NAMESPACE') ) {
  130. define( 'T_NAMESPACE', 100003 );
  131. }
  132. if ( ! defined('T_NS_C') ) {
  133. define( 'T_NS_C', 100004 );
  134. }
  135. if ( ! defined('T_NS_SEPARATOR') ) {
  136. define( 'T_NS_SEPARATOR', 100005 );
  137. }
  138. if ( ! defined('T_USE') ) {
  139. define( 'T_USE', 100006 );
  140. }
  141. /*
  142. * Check if it's empty, in case this file is loaded multiple times.
  143. */
  144. if ( ! isset($_php_error_global_handler) ) {
  145. $_php_error_global_handler = null;
  146. $_php_error_is_ini_enabled = false;
  147. /*
  148. * check both 'disable' and 'disabled' incase it's mispelt
  149. * check that display errors is on
  150. * and ensure we are *not* a command line script.
  151. */
  152. $_php_error_is_ini_enabled =
  153. ! @get_cfg_var( 'php_error.force_disabled' ) &&
  154. ! @get_cfg_var( 'php_error.force_disable' ) &&
  155. @ini_get('display_errors') === '1' &&
  156. PHP_SAPI !== 'cli'
  157. ;
  158. }
  159. /**
  160. * This is shorthand for turning off error handling,
  161. * calling a block of code, and then turning it on.
  162. *
  163. * However if 'reportErrors' has not been called,
  164. * then this will silently do nothing.
  165. *
  166. * @param callback A PHP function to call.
  167. * @return The result of calling the callback.
  168. */
  169. function withoutErrors( $callback ) {
  170. global $_php_error_global_handler;
  171. if ( $_php_error_global_handler !== null ) {
  172. return $_php_error_global_handler->withoutErrors( $callback );
  173. } else {
  174. return $callback();
  175. }
  176. }
  177. /**
  178. * Turns on error reporting, and returns the handler.
  179. *
  180. * If you just want error reporting on, then don't bother
  181. * catching the handler. If you're building something
  182. * clever, like a framework, then you might want to grab
  183. * and use it.
  184. *
  185. * Note that calling this a second time will replace the
  186. * global error handling with a new error handler.
  187. * The existing one will be turned off, and the new one
  188. * turned on.
  189. *
  190. * You can't use two at once!
  191. *
  192. * @param options Optional, options declaring how PHP Error should be setup and used.
  193. * @return The ErrorHandler used for reporting errors.
  194. */
  195. function reportErrors( $options=null ) {
  196. $handler = new ErrorHandler( $options );
  197. return $handler->turnOn();
  198. }
  199. /**
  200. * The actual handler. There can only ever be one.
  201. */
  202. class ErrorHandler
  203. {
  204. const REGEX_DOCTYPE = '/<( )*!( *)DOCTYPE([^>]+)>/';
  205. const REGEX_PHP_IDENTIFIER = '\b[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*';
  206. const REGEX_PHP_CONST_IDENTIFIER = '/\b[A-Z_\x7f-\xff][A-Z0-9_\x7f-\xff]*/';
  207. /**
  208. * Matches:
  209. * {closure}()
  210. * blah::foo()
  211. * foo()
  212. *
  213. * It is:
  214. * a closure
  215. * or a method or function
  216. * followed by parenthesis '()'
  217. *
  218. * a function is 'namespace function'
  219. * a method is 'namespace class::function', or 'namespace class->function'
  220. * the whole namespace is optional
  221. * namespace is made up of an '\' and then repeating 'namespace\'
  222. * both the first slash, and the repeating 'namespace\', are optional
  223. *
  224. * 'END' matches it at the end of a string, the other one does not.
  225. */
  226. const REGEX_METHOD_OR_FUNCTION_END = '/(\\{closure\\})|(((\\\\)?(\b[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\\\\)*)?\b[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(::[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)?)\\(\\)$/';
  227. const REGEX_METHOD_OR_FUNCTION = '/(\\{closure\\})|(((\\\\)?(\b[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\\\\)*)?\b[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(::[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)?)\\(\\)/';
  228. const REGEX_VARIABLE = '/\b[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/';
  229. const REGEX_MISSING_SEMI_COLON_FOLLOWING_LINE = '/^ *(return|}|if|while|foreach|for|switch)/';
  230. /**
  231. * The number of lines to take from the file,
  232. * where the error is reported. This is the number
  233. * of lines around the line in question,
  234. * including that line.
  235. *
  236. * So '9' will be the error line + 4 lines above + 4 lines below.
  237. */
  238. const NUM_FILE_LINES = 13;
  239. const FILE_TYPE_APPLICATION = 1;
  240. const FILE_TYPE_IGNORE = 2;
  241. const FILE_TYPE_ROOT = 3;
  242. const PHP_ERROR_MAGIC_HEADER_KEY = 'PHP_ERROR_MAGIC_HEADER';
  243. const PHP_ERROR_MAGIC_HEADER_VALUE = 'php_stack_error';
  244. const MAGIC_IS_PRETTY_ERRORS_MARKER = '<!-- __magic_php_error_is_a_stack_trace_constant__ -->';
  245. const PHP_ERROR_INI_PREFIX = 'php_error';
  246. /**
  247. * At the time of writing, scalar type hints are unsupported.
  248. * By scalar, I mean 'string' and 'integer'.
  249. *
  250. * If they do get added, this is here as a trap to turn scalar
  251. * type hint warnings on and off.
  252. */
  253. private static $IS_SCALAR_TYPE_HINTING_SUPPORTED = false;
  254. private static $SCALAR_TYPES = array(
  255. 'string', 'integer', 'float', 'boolean',
  256. 'bool', 'int', 'number'
  257. );
  258. /**
  259. * A mapping of PHP internal symbols,
  260. * mapped to descriptions of them.
  261. */
  262. private static $PHP_SYMBOL_MAPPINGS = array(
  263. '$end' => 'end of file',
  264. 'T_ABSTRACT' => 'abstract',
  265. 'T_AND_EQUAL' => "'&='",
  266. 'T_ARRAY' => 'array',
  267. 'T_ARRAY_CAST' => 'array cast',
  268. 'T_AS' => "'as'",
  269. 'T_BOOLEAN_AND' => "'&&'",
  270. 'T_BOOLEAN_OR' => "'||'",
  271. 'T_BOOL_CAST' => 'boolean cast',
  272. 'T_BREAK' => 'break',
  273. 'T_CASE' => 'case',
  274. 'T_CATCH' => 'catch',
  275. 'T_CLASS' => 'class',
  276. 'T_CLASS_C' => '__CLASS__',
  277. 'T_CLONE' => 'clone',
  278. 'T_CLOSE_TAG' => 'closing PHP tag',
  279. 'T_CONCAT_EQUAL' => "'.='",
  280. 'T_CONST' => 'const',
  281. 'T_CONSTANT_ENCAPSED_STRING' => 'string',
  282. 'T_CONTINUE' => 'continue',
  283. 'T_CURLY_OPEN' => '\'{$\'',
  284. 'T_DEC' => '-- (decrement)',
  285. 'T_DECLARE' => 'declare',
  286. 'T_DEFAULT' => 'default',
  287. 'T_DIR' => '__DIR__',
  288. 'T_DIV_EQUAL' => "'/='",
  289. 'T_DNUMBER' => 'number',
  290. 'T_DOLLAR_OPEN_CURLY_BRACES' => '\'${\'',
  291. 'T_DO' => "'do'",
  292. 'T_DOUBLE_ARROW' => "'=>'",
  293. 'T_DOUBLE_CAST' => 'double cast',
  294. 'T_DOUBLE_COLON' => "'::'",
  295. 'T_ECHO' => 'echo',
  296. 'T_ELSE' => 'else',
  297. 'T_ELSEIF' => 'elseif',
  298. 'T_EMPTY' => 'empty',
  299. 'T_ENCAPSED_AND_WHITESPACE' => 'non-terminated string',
  300. 'T_ENDDECLARE' => 'enddeclare',
  301. 'T_ENDFOR' => 'endfor',
  302. 'T_ENDFOREACH' => 'endforeach',
  303. 'T_ENDIF' => 'endif',
  304. 'T_ENDSWITCH' => 'endswitch',
  305. 'T_ENDWHILE' => 'endwhile',
  306. 'T_EVAL' => 'eval',
  307. 'T_EXIT' => 'exit call',
  308. 'T_EXTENDS' => 'extends',
  309. 'T_FILE' => '__FILE__',
  310. 'T_FINAL' => 'final',
  311. 'T_FOR' => 'for',
  312. 'T_FOREACH' => 'foreach',
  313. 'T_FUNCTION' => 'function',
  314. 'T_FUNC_C' => '__FUNCTION__',
  315. 'T_GLOBAL' => 'global',
  316. 'T_GOTO' => 'goto',
  317. 'T_HALT_COMPILER' => '__halt_compiler',
  318. 'T_IF' => 'if',
  319. 'T_IMPLEMENTS' => 'implements',
  320. 'T_INC' => '++ (increment)',
  321. 'T_INCLUDE' => 'include',
  322. 'T_INCLUDE_ONCE' => 'include_once',
  323. 'T_INSTANCEOF' => 'instanceof',
  324. 'T_INT_CAST' => 'int cast',
  325. 'T_INTERFACE' => 'interface',
  326. 'T_ISSET' => 'isset',
  327. 'T_IS_EQUAL' => "'=='",
  328. 'T_IS_GREATER_OR_EQUAL' => "'>='",
  329. 'T_IS_IDENTICAL' => "'==='",
  330. 'T_IS_NOT_EQUAL' => "'!=' or '<>'",
  331. 'T_IS_NOT_IDENTICAL' => "'!=='",
  332. 'T_IS_SMALLER_OR_EQUAL' => "'<='",
  333. 'T_LINE' => '__LINE__',
  334. 'T_LIST' => 'list',
  335. 'T_LNUMBER' => 'number',
  336. 'T_LOGICAL_AND' => "'and'",
  337. 'T_LOGICAL_OR' => "'or'",
  338. 'T_LOGICAL_XOR' => "'xor'",
  339. 'T_METHOD_C' => '__METHOD__',
  340. 'T_MINUS_EQUAL' => "'-='",
  341. 'T_MOD_EQUAL' => "'%='",
  342. 'T_MUL_EQUAL' => "'*='",
  343. 'T_NAMESPACE' => 'namespace',
  344. 'T_NEW' => 'new',
  345. 'T_NUM_STRING' => 'array index in a string',
  346. 'T_NS_C' => '__NAMESPACE__',
  347. 'T_NS_SEPARATOR' => 'namespace seperator',
  348. 'T_OBJECT_CAST' => 'object cast',
  349. 'T_OBJECT_OPERATOR' => "'->'",
  350. 'T_OLD_FUNCTION' => 'old_function',
  351. 'T_OPEN_TAG' => "'<?php' or '<?'",
  352. 'T_OPEN_TAG_WITH_ECHO' => "'<?php echo '",
  353. 'T_OR_EQUAL' => "'|='",
  354. 'T_PAAMAYIM_NEKUDOTAYIM' => "'::'",
  355. 'T_PLUS_EQUAL' => "'+='",
  356. 'T_PRINT' => 'print',
  357. 'T_PRIVATE' => 'private',
  358. 'T_PUBLIC' => 'public',
  359. 'T_PROTECTED' => 'protected',
  360. 'T_REQUIRE' => 'require',
  361. 'T_REQUIRE_ONCE' => 'require_once',
  362. 'T_RETURN' => 'return',
  363. 'T_SL' => "'<<'",
  364. 'T_SL_EQUAL' => "'<<='",
  365. 'T_SR' => "'>>'",
  366. 'T_SR_EQUAL' => "'>>='",
  367. 'T_START_HEREDOC' => "'<<<'",
  368. 'T_STATIC' => 'static',
  369. 'T_STRING' => 'string',
  370. 'T_STRING_CAST' => 'string cast',
  371. 'T_SWITCH' => 'switch',
  372. 'T_THROW' => 'throw',
  373. 'T_TRY' => 'try',
  374. 'T_UNSET' => 'unset',
  375. 'T_UNSET_CAST' => 'unset cast',
  376. 'T_USE' => 'use',
  377. 'T_VAR' => 'var',
  378. 'T_VARIABLE' => 'variable',
  379. 'T_WHILE' => 'while',
  380. 'T_WHITESPACE' => 'whitespace',
  381. 'T_XOR_EQUAL' => "'^='"
  382. );
  383. private static $syntaxMap = array(
  384. 'const' => 'syntax-literal',
  385. 'reference_ampersand' => 'syntax-function',
  386. T_COMMENT => 'syntax-comment',
  387. T_DOC_COMMENT => 'syntax-comment',
  388. T_ABSTRACT => 'syntax-keyword',
  389. T_AS => 'syntax-keyword',
  390. T_BREAK => 'syntax-keyword',
  391. T_CASE => 'syntax-keyword',
  392. T_CATCH => 'syntax-keyword',
  393. T_CLASS => 'syntax-keyword',
  394. T_CONST => 'syntax-keyword',
  395. T_CONTINUE => 'syntax-keyword',
  396. T_DECLARE => 'syntax-keyword',
  397. T_DEFAULT => 'syntax-keyword',
  398. T_DO => 'syntax-keyword',
  399. T_ELSE => 'syntax-keyword',
  400. T_ELSEIF => 'syntax-keyword',
  401. T_ENDDECLARE => 'syntax-keyword',
  402. T_ENDFOR => 'syntax-keyword',
  403. T_ENDFOREACH => 'syntax-keyword',
  404. T_ENDIF => 'syntax-keyword',
  405. T_ENDSWITCH => 'syntax-keyword',
  406. T_ENDWHILE => 'syntax-keyword',
  407. T_EXTENDS => 'syntax-keyword',
  408. T_FINAL => 'syntax-keyword',
  409. T_FOR => 'syntax-keyword',
  410. T_FOREACH => 'syntax-keyword',
  411. T_FUNCTION => 'syntax-keyword',
  412. T_GLOBAL => 'syntax-keyword',
  413. T_GOTO => 'syntax-keyword',
  414. T_IF => 'syntax-keyword',
  415. T_IMPLEMENTS => 'syntax-keyword',
  416. T_INSTANCEOF => 'syntax-keyword',
  417. T_INTERFACE => 'syntax-keyword',
  418. T_LOGICAL_AND => 'syntax-keyword',
  419. T_LOGICAL_OR => 'syntax-keyword',
  420. T_LOGICAL_XOR => 'syntax-keyword',
  421. T_NAMESPACE => 'syntax-keyword',
  422. T_NEW => 'syntax-keyword',
  423. T_PRIVATE => 'syntax-keyword',
  424. T_PUBLIC => 'syntax-keyword',
  425. T_PROTECTED => 'syntax-keyword',
  426. T_RETURN => 'syntax-keyword',
  427. T_STATIC => 'syntax-keyword',
  428. T_SWITCH => 'syntax-keyword',
  429. T_THROW => 'syntax-keyword',
  430. T_TRY => 'syntax-keyword',
  431. T_USE => 'syntax-keyword',
  432. T_VAR => 'syntax-keyword',
  433. T_WHILE => 'syntax-keyword',
  434. // __VAR__ type magic constants
  435. T_CLASS_C => 'syntax-literal',
  436. T_DIR => 'syntax-literal',
  437. T_FILE => 'syntax-literal',
  438. T_FUNC_C => 'syntax-literal',
  439. T_LINE => 'syntax-literal',
  440. T_METHOD_C => 'syntax-literal',
  441. T_NS_C => 'syntax-literal',
  442. T_DNUMBER => 'syntax-literal',
  443. T_LNUMBER => 'syntax-literal',
  444. T_CONSTANT_ENCAPSED_STRING => 'syntax-string',
  445. T_VARIABLE => 'syntax-variable',
  446. // this is for unescaped strings, which appear differently
  447. // this includes function names
  448. T_STRING => 'syntax-function',
  449. // in build keywords, which work like functions
  450. T_ARRAY => 'syntax-function',
  451. T_CLONE => 'syntax-function',
  452. T_ECHO => 'syntax-function',
  453. T_EMPTY => 'syntax-function',
  454. T_EVAL => 'syntax-function',
  455. T_EXIT => 'syntax-function',
  456. T_HALT_COMPILER => 'syntax-function',
  457. T_INCLUDE => 'syntax-function',
  458. T_INCLUDE_ONCE => 'syntax-function',
  459. T_ISSET => 'syntax-function',
  460. T_LIST => 'syntax-function',
  461. T_REQUIRE_ONCE => 'syntax-function',
  462. T_PRINT => 'syntax-function',
  463. T_REQUIRE => 'syntax-function',
  464. T_UNSET => 'syntax-function'
  465. );
  466. /**
  467. * A list of methods which are known to call the autoloader,
  468. * but should not error, if the class is not found.
  469. *
  470. * They are allowed to fail, so we don't store a class not
  471. * found exception if they do.
  472. */
  473. private static $SAFE_AUTOLOADER_FUNCTIONS = array(
  474. 'class_exists',
  475. 'interface_exists',
  476. 'method_exists',
  477. 'property_exists',
  478. 'is_subclass_of'
  479. );
  480. /**
  481. * When returning values, if a mime type is set,
  482. * then PHP Error should only output if the mime type
  483. * is one of these.
  484. */
  485. private static $ALLOWED_RETURN_MIME_TYPES = array(
  486. 'text/html',
  487. 'application/xhtml+xml'
  488. );
  489. private static function isIIS() {
  490. return (
  491. isset($_SERVER['SERVER_SOFTWARE']) &&
  492. strpos($_SERVER['SERVER_SOFTWARE'], 'IIS/') !== false
  493. ) || (
  494. isset($_SERVER['_FCGI_X_PIPE_']) &&
  495. strpos($_SERVER['_FCGI_X_PIPE_'], 'IISFCGI') !== false
  496. );
  497. }
  498. /**
  499. * This attempts to state if this is *not* a PHP request,
  500. * but it cannot say if it *is* a PHP request. It achieves
  501. * this by looking for a mime type.
  502. *
  503. * For example if the mime type is JavaScript, then we
  504. * know it's not PHP. However there is no "yes, this is
  505. * definitely a normal HTML response" flag we can check.
  506. */
  507. private static function isNonPHPRequest() {
  508. /*
  509. * Check if we are a mime type that isn't allowed.
  510. *
  511. * Anything other than 'text/html' or similar will cause
  512. * this to turn off.
  513. */
  514. $response = ErrorHandler::getResponseHeaders();
  515. foreach ( $response as $key => $value ) {
  516. if ( strtolower($key) === 'content-type' ) {
  517. $found = true;
  518. foreach ( ErrorHandler::$ALLOWED_RETURN_MIME_TYPES as $type ) {
  519. if ( stripos($value, $type) !== false ) {
  520. $found = true;
  521. break;
  522. }
  523. }
  524. if ( ! $found ) {
  525. return true;
  526. }
  527. break;
  528. }
  529. }
  530. return false;
  531. }
  532. /**
  533. * Looks up a description for the symbol given,
  534. * and if found, it is returned.
  535. *
  536. * If it's not found, then the symbol given is returned.
  537. */
  538. private static function phpSymbolToDescription( $symbol ) {
  539. if ( isset(ErrorHandler::$PHP_SYMBOL_MAPPINGS[$symbol]) ) {
  540. return ErrorHandler::$PHP_SYMBOL_MAPPINGS[$symbol];
  541. } else {
  542. return "'$symbol'";
  543. }
  544. }
  545. /**
  546. * Attempts to syntax highlight the code snippet done.
  547. *
  548. * This is then returned as HTML, ready to be dumped to the screen.
  549. *
  550. * @param code An array of code lines to syntax highlight.
  551. * @return HTML version of the code given, syntax highlighted.
  552. */
  553. private static function syntaxHighlight( $code ) {
  554. $syntaxMap = ErrorHandler::$syntaxMap;
  555. // @supress invalid code raises a warning
  556. $tokens = @token_get_all( "<?php " . $code . " ?" . ">" );
  557. $html = array();
  558. $len = count($tokens)-1;
  559. $inString = false;
  560. $stringBuff = null;
  561. $skip = false;
  562. for ( $i = 1; $i < $len; $i++ ) {
  563. $token = $tokens[$i];
  564. if ( is_array($token) ) {
  565. $type = $token[0];
  566. $code = $token[1];
  567. } else {
  568. $type = null;
  569. $code = $token;
  570. }
  571. // work out any whitespace padding
  572. if ( strpos($code, "\n") !== false && trim($code) === '' ) {
  573. if ( $inString ) {
  574. $html[]= "<span class='syntax-string'>" . join('', $stringBuff);
  575. $stringBuff = array();
  576. }
  577. } else if ( $code === '&' ) {
  578. if ( $i < $len ) {
  579. $next = $tokens[$i+1];
  580. if ( is_array($next) && $next[0] === T_VARIABLE ) {
  581. $type = 'reference_ampersand';
  582. }
  583. }
  584. } else if ( $code === '"' || $code === "'" ) {
  585. if ( $inString ) {
  586. $html[]= "<span class='syntax-string'>" . join('', $stringBuff) . htmlspecialchars($code) . "</span>";
  587. $stringBuff = null;
  588. $skip = true;
  589. } else {
  590. $stringBuff = array();
  591. }
  592. $inString = !$inString;
  593. } else if ( $type === T_STRING ) {
  594. $matches = array();
  595. preg_match(ErrorHandler::REGEX_PHP_CONST_IDENTIFIER, $code, $matches);
  596. if ( $matches && strlen($matches[0]) === strlen($code) ) {
  597. $type = 'const';
  598. }
  599. }
  600. if ( $skip ) {
  601. $skip = false;
  602. } else {
  603. $code = htmlspecialchars( $code );
  604. if ( $type !== null && isset($syntaxMap[$type]) ) {
  605. $class = $syntaxMap[$type];
  606. if ( $type === T_CONSTANT_ENCAPSED_STRING && strpos($code, "\n") !== false ) {
  607. $append = "<span class='$class'>" .
  608. join(
  609. "</span>\n<span class='$class'>",
  610. explode( "\n", $code )
  611. ) .
  612. "</span>" ;
  613. } else if ( strrpos($code, "\n") === strlen($code)-1 ) {
  614. $append = "<span class='$class'>" . substr($code, 0, strlen($code)-1) . "</span>\n";
  615. } else {
  616. $append = "<span class='$class'>$code</span>";
  617. }
  618. } else if ( $inString && $code !== '"' ) {
  619. $append = "<span class='syntax-string'>$code</span>";
  620. } else {
  621. $append = $code;
  622. }
  623. if ( $inString ) {
  624. $stringBuff[]= $append;
  625. } else {
  626. $html[]= $append;
  627. }
  628. }
  629. }
  630. if ( $stringBuff !== null ) {
  631. $html[]= "<span class='syntax-string'>" . join('', $stringBuff) . '</span>';
  632. $stringBuff = null;
  633. }
  634. return join( '', $html );
  635. }
  636. /**
  637. * Splits a given function name into it's 'class, function' parts.
  638. * If there is no class, then null is returned.
  639. *
  640. * It also returns these parts in an array of: array( $className, $functionName );
  641. *
  642. * Usage:
  643. *
  644. * list( $class, $function ) = ErrorHandler::splitFunction( $name );
  645. *
  646. * @param name The function name to split.
  647. * @return An array containing class and function name.
  648. */
  649. private static function splitFunction( $name ) {
  650. $name = preg_replace( '/\\(\\)$/', '', $name );
  651. if ( strpos($name, '::') !== false ) {
  652. $parts = explode( '::', $name );
  653. $className = $parts[0];
  654. $type = '::';
  655. $functionName = $parts[1];
  656. } else if ( strpos($name, '->') !== false ) {
  657. $parts = explode( '->', $name );
  658. $className = $parts[0];
  659. $type = '->';
  660. $functionName = $parts[1];
  661. } else {
  662. $className = null;
  663. $type = null;
  664. $functionName = $name;
  665. }
  666. return array( $className, $type, $functionName );
  667. }
  668. private static function newArgument( $name, $type=false, $isPassedByReference=false, $isOptional=false, $optionalValue=null, $highlight=false ) {
  669. if ( $name instanceof ReflectionParameter ) {
  670. $highlight = func_num_args() > 1 ?
  671. $highlight = $type :
  672. false;
  673. $klass = $name->getDeclaringClass();
  674. $functionName = $name->getDeclaringFunction()->name;
  675. if ( $klass !== null ) {
  676. $klass = $klass->name;
  677. }
  678. $export = ReflectionParameter::export(
  679. ( $klass ?
  680. array( "\\$klass", $functionName ) :
  681. $functionName ),
  682. $name->name,
  683. true
  684. );
  685. $paramType = preg_replace('/.*?(\w+)\s+\$'.$name->name.'.*/', '\\1', $export);
  686. if ( strpos($paramType, '[') !== false || strlen($paramType) === 0 ) {
  687. $paramType = null;
  688. }
  689. return ErrorHandler::newArgument(
  690. $name->name,
  691. $paramType,
  692. $name->isPassedByReference(),
  693. $name->isDefaultValueAvailable(),
  694. ( $name->isDefaultValueAvailable() ?
  695. var_export( $name->getDefaultValue(), true ) :
  696. null ),
  697. ( func_num_args() > 1 ?
  698. $type :
  699. false )
  700. );
  701. } else {
  702. return array(
  703. 'name' => $name,
  704. 'has_type' => ( $type !== false ),
  705. 'type' => $type,
  706. 'is_reference' => $isPassedByReference,
  707. 'has_default' => $isOptional,
  708. 'default_val' => $optionalValue,
  709. 'is_highlighted' => $highlight
  710. );
  711. }
  712. }
  713. private static function syntaxHighlightFunctionMatch( $match, &$stackTrace, $highlightArg=null, &$numHighlighted=0 ) {
  714. list( $className, $type, $functionName ) = ErrorHandler::splitFunction( $match );
  715. // is class::method()
  716. if ( $className !== null ) {
  717. $reflectFun = new ReflectionMethod( $className, $functionName );
  718. // is a function
  719. } else if ( $functionName === '{closure}' ) {
  720. return '<span class="syntax-variable">$closure</span>';
  721. } else {
  722. $reflectFun = new ReflectionFunction( $functionName );
  723. }
  724. if ( $reflectFun ) {
  725. $params = $reflectFun->getParameters();
  726. if ( $params ) {
  727. $args = array();
  728. $min = 0;
  729. foreach( $params as $i => $param ) {
  730. $arg = ErrorHandler::newArgument( $param );
  731. if ( ! $arg['has_default'] ) {
  732. $min = $i;
  733. }
  734. $args[]= $arg;
  735. }
  736. if ( $highlightArg !== null ) {
  737. for ( $i = $highlightArg; $i <= $min; $i++ ) {
  738. $args[$i]['is_highlighted'] = true;
  739. }
  740. $numHighlighted = $min-$highlightArg;
  741. }
  742. if ( $className !== null ) {
  743. if ( $stackTrace && isset($stackTrace[1]) && isset($stackTrace[1]['type']) ) {
  744. $type = htmlspecialchars( $stackTrace[1]['type'] );
  745. }
  746. } else {
  747. $type = null;
  748. }
  749. return ErrorHandler::syntaxHighlightFunction( $className, $type, $functionName, $args );
  750. }
  751. }
  752. return null;
  753. }
  754. /**
  755. * Returns the values given, as HTML, syntax highlighted.
  756. * It's a shorter, slightly faster, more no-nonsense approach
  757. * then 'syntaxHighlight'.
  758. *
  759. * This is for syntax highlighting:
  760. * - fun( [args] )
  761. * - class->fun( [args] )
  762. * - class::fun( [args] )
  763. *
  764. * Class and type can be null, to denote no class, but are not optional.
  765. */
  766. private static function syntaxHighlightFunction( $class, $type, $fun, &$args=null ) {
  767. $info = array();
  768. // set the info
  769. if ( isset($class) && $class && isset($type) && $type ) {
  770. if ( $type === '->' ) {
  771. $type = '-&gt;';
  772. }
  773. $info []= "<span class='syntax-class'>$class</span>$type";
  774. }
  775. if ( isset($fun) && $fun ) {
  776. $info []= "<span class='syntax-function'>$fun</span>";
  777. }
  778. if ( $args ) {
  779. $info []= '( ';
  780. foreach ($args as $i => $arg) {
  781. if ( $i > 0 ) {
  782. $info[]= ', ';
  783. }
  784. if ( is_string($arg) ) {
  785. $info[]= $arg;
  786. } else {
  787. $highlight = $arg['is_highlighted'];
  788. $name = $arg['name'];
  789. if ( $highlight ) {
  790. $info[]= '<span class="syntax-higlight-variable">';
  791. }
  792. if ( $name === '_' ) {
  793. $info[]= '<span class="syntax-variable-not-important">';
  794. }
  795. if ( $arg['has_type'] ) {
  796. $info []= "<span class='syntax-class'>";
  797. $info []= $arg['type'];
  798. $info []= '</span> ';
  799. }
  800. if ( $arg['is_reference'] ) {
  801. $info []= '<span class="syntax-function">&amp;</span>';
  802. }
  803. $info []= "<span class='syntax-variable'>\$$name</span>";
  804. if ( $arg['has_default'] ) {
  805. $info []= '=<span class="syntax-literal">' . $arg['default_val'] . '</span>';
  806. }
  807. if ( $name === '_' ) {
  808. $info[]= '</span>';
  809. }
  810. if ( $highlight ) {
  811. $info[]= '</span>';
  812. }
  813. }
  814. }
  815. $info []= ' )';
  816. } else {
  817. $info []= '()';
  818. }
  819. return join( '', $info );
  820. }
  821. /**
  822. * Checks if the item is in options, and if it is, then it is removed and returned.
  823. *
  824. * If it is not found, or if options is not an array, then the alt is returned.
  825. */
  826. private static function optionsPop( &$options, $key, $alt=null ) {
  827. if ( $options && isset($options[$key]) ) {
  828. $val = $options[$key];
  829. unset( $options[$key] );
  830. return $val;
  831. } else {
  832. $iniAlt = @get_cfg_var( ErrorHandler::PHP_ERROR_INI_PREFIX . '.' . $key );
  833. if ( $iniAlt !== false ) {
  834. return $iniAlt;
  835. } else {
  836. return $alt;
  837. }
  838. }
  839. }
  840. private static function folderTypeToCSS( $type ) {
  841. if ( $type === ErrorHandler::FILE_TYPE_ROOT ) {
  842. return 'file-root';
  843. } else if ( $type === ErrorHandler::FILE_TYPE_IGNORE ) {
  844. return 'file-ignore';
  845. } else if ( $type === ErrorHandler::FILE_TYPE_APPLICATION ) {
  846. return 'file-app';
  847. } else {
  848. return 'file-common';
  849. }
  850. }
  851. private static function isFolderType( &$folders, $longest, $file ) {
  852. $parts = explode( '/', $file );
  853. $len = min( count($parts), $longest );
  854. for ( $i = $len; $i > 0; $i-- ) {
  855. if ( isset($folders[$i]) ) {
  856. $folderParts = &$folders[ $i ];
  857. $success = false;
  858. for ( $j = 0; $j < count($folderParts); $j++ ) {
  859. $folderNames = $folderParts[$j];
  860. for ( $k = 0; $k < count($folderNames); $k++ ) {
  861. if ( $folderNames[$k] === $parts[$k] ) {
  862. $success = true;
  863. } else {
  864. $success = false;
  865. break;
  866. }
  867. }
  868. }
  869. if ( $success ) {
  870. return true;
  871. }
  872. }
  873. }
  874. return false;
  875. }
  876. private static function setFolders( &$origFolders, &$longest, $folders ) {
  877. $newFolders = array();
  878. $newLongest = 0;
  879. if ( $folders ) {
  880. if ( is_array($folders) ) {
  881. foreach ( $folders as $folder ) {
  882. ErrorHandler::setFoldersInner( $newFolders, $newLongest, $folder );
  883. }
  884. } else if ( is_string($folders) ) {
  885. ErrorHandler::setFoldersInner( $newFolders, $newLongest, $folders );
  886. } else {
  887. throw new Exception( "Unknown value given for folder: " . $folders );
  888. }
  889. }
  890. $origFolders = $newFolders;
  891. $longest = $newLongest;
  892. }
  893. private static function setFoldersInner( &$newFolders, &$newLongest, $folder ) {
  894. $folder = str_replace( '\\', '/', $folder );
  895. $folder = preg_replace( '/(^\\/+)|(\\/+$)/', '', $folder );
  896. $parts = explode( '/', $folder );
  897. $count = count( $parts );
  898. $newLongest = max( $newLongest, $count );
  899. if ( isset($newFolders[$count]) ) {
  900. $folds = &$newFolders[$count];
  901. $folds[]= $parts;
  902. } else {
  903. $newFolders[$count] = array( $parts );
  904. }
  905. }
  906. private static function getRequestHeaders() {
  907. if ( function_exists('getallheaders') ) {
  908. return getallheaders();
  909. } else {
  910. $headers = array();
  911. foreach ( $_SERVER as $key => $value ) {
  912. if ( strpos($key, 'HTTP_') === 0 ) {
  913. $key = str_replace( " ", "-", ucwords(strtolower( str_replace("_", " ", substr($key, 5)) )) );
  914. $headers[ $key ] = $value;
  915. }
  916. }
  917. return $headers;
  918. }
  919. }
  920. private static function getResponseHeaders() {
  921. $headers = function_exists('apache_response_headers') ?
  922. apache_response_headers() :
  923. array() ;
  924. /*
  925. * Merge the headers_list into apache_response_headers.
  926. *
  927. * This is because sometimes things are in one, which are
  928. * not present in the other.
  929. */
  930. if ( function_exists('headers_list') ) {
  931. $hList = headers_list();
  932. foreach ($hList as $header) {
  933. $header = explode(":", $header);
  934. $headers[ array_shift($header) ] = trim( implode(":", $header) );
  935. }
  936. }
  937. return $headers;
  938. }
  939. public static function identifyTypeHTML( $arg, $recurseLevels=1 ) {
  940. if ( ! is_array($arg) && !is_object($arg) ) {
  941. if ( is_string($arg) ) {
  942. return "<span class='syntax-string'>&quot;" . htmlentities($arg) . "&quot;</span>";
  943. } else {
  944. return "<span class='syntax-literal'>" . var_export( $arg, true ) . '</span>';
  945. }
  946. } else if ( is_array($arg) ) {
  947. if ( count($arg) === 0 ) {
  948. return "[]";
  949. } else if ( $recurseLevels > 0 ) {
  950. $argArr = array();
  951. foreach ($arg as $ag) {
  952. $argArr[]= ErrorHandler::identifyTypeHTML( $ag, $recurseLevels-1 );
  953. }
  954. if ( ($recurseLevels % 2) === 0 ) {
  955. return "[" . join(', ', $argArr) . "]";
  956. } else {
  957. return "[ " . join(', ', $argArr) . " ]";
  958. }
  959. } else {
  960. return "[...]";
  961. }
  962. } else if ( get_class($arg) === 'Closure' ) {
  963. return '<span class="syntax-variable">$Closure</span>()';
  964. } else {
  965. $argKlass = get_class( $arg );
  966. if ( preg_match(ErrorHandler::REGEX_PHP_CONST_IDENTIFIER, $argKlass) ) {
  967. return '<span class="syntax-literal">$' . $argKlass . '</span>';
  968. } else {
  969. return '<span class="syntax-variable">$' . $argKlass . '</span>';
  970. }
  971. }
  972. }
  973. private $cachedFiles;
  974. private $isShutdownRegistered;
  975. private $isOn;
  976. private $ignoreFolders = array();
  977. private $ignoreFoldersLongest = 0;
  978. private $applicationFolders = array();
  979. private $applicationFoldersLongest = 0;
  980. private $defaultErrorReportingOn;
  981. private $defaultErrorReportingOff;
  982. private $applicationRoot;
  983. private $serverName;
  984. private $catchClassNotFound;
  985. private $catchSurpressedErrors;
  986. private $catchAjaxErrors;
  987. private $backgroundText;
  988. private $numLin

Large files files are truncated, but you can click here to view the full file