/library/php_error.php
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
- <?php
- /**
- * @license
- *
- * PHP Error
- *
- * Copyright (c) 2012 Joseph Lenton
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the <organization> nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Uses:
- * JSMin-php https://github.com/rgrove/jsmin-php/
- * jQuery http://jquery.com/
- */
- /**
- * PHP Error
- *
- * --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
- *
- * WARNING! It is downright _DANGEROUS_ to use this in production, on
- * a live website. It should *ONLY* be used for development.
- *
- * PHP Error will kill your environment at will, clear the output
- * buffers, and allows HTML injection from exceptions.
- *
- * In future versions it plans to do far more then that.
- *
- * If you use it in development, awesome! If you use it in production,
- * you're an idiot.
- *
- * --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
- *
- * = Info
- *
- * A small API for replacing the standard PHP errors, with prettier
- * error reporting. This will change the error reporting level, and this
- * is deliberate, as I believe in strict development errors.
- *
- * simple usage:
- *
- * \php_error\reportErrors();
- *
- * Advanced example:
- *
- * There is more too it if you want more customized error handling. You
- * can pass in options, to customize the setup, and you get back a
- * handler you can alter at runtime.
- *
- * $handler = new \php_error\ErrorHandler( $myOptions );
- * $handler->turnOn();
- *
- * There should only ever be one handler! This is an (underdstandable)
- * limitation in PHP. It's because if an exception or error is raised,
- * then there is a single point of handling it.
- *
- * = INI Options
- *
- * - php_error.force_disabled When set to a true value (such as on),
- * this forces this to be off.
- * This is so you can disable this script
- * in your production servers ini file,
- * incase you accidentally upload this there.
- *
- * --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
- *
- * @author Joseph Lenton | https://github.com/josephlenton
- */
- namespace php_error;
- use \php_error\ErrorException,
- \php_error\FileLinesSet,
- \php_error\ErrorHandler,
- \php_error\JSMin,
- \php_error\JSMinException;
- use \Closure,
- \Exception,
- \InvalidArgumentException;
- use \ReflectionMethod,
- \ReflectionFunction,
- \ReflectionParameter;
- global $_php_error_already_setup,
- $_php_error_global_handler,
- $_php_error_is_ini_enabled;
- /*
- * Avoid being run twice.
- */
- if ( empty($_php_error_already_setup) ) {
- $_php_error_already_setup = true;
- /*
- * These are used as token identifiers by PHP.
- *
- * If they are missing, then they should never pop out of PHP,
- * so we just give them their future value.
- *
- * They are primarily here so I don't have to alter the 5.3
- * compliant code. Instead I can delete pre-5.3 code (this
- * code), in the future.
- *
- * As long as the value is unique, and does not clash with PHP,
- * then any number could be used. That is why they start counting
- * at 100,000.
- */
- if ( ! defined('T_DIR') ) {
- define( 'T_DIR', 100001 );
- }
- if ( ! defined('T_GOTO') ) {
- define( 'T_GOTO', 100002 );
- }
- if ( ! defined('T_NAMESPACE') ) {
- define( 'T_NAMESPACE', 100003 );
- }
- if ( ! defined('T_NS_C') ) {
- define( 'T_NS_C', 100004 );
- }
- if ( ! defined('T_NS_SEPARATOR') ) {
- define( 'T_NS_SEPARATOR', 100005 );
- }
- if ( ! defined('T_USE') ) {
- define( 'T_USE', 100006 );
- }
- /*
- * Check if it's empty, in case this file is loaded multiple times.
- */
- if ( ! isset($_php_error_global_handler) ) {
- $_php_error_global_handler = null;
- $_php_error_is_ini_enabled = false;
- /*
- * check both 'disable' and 'disabled' incase it's mispelt
- * check that display errors is on
- * and ensure we are *not* a command line script.
- */
- $_php_error_is_ini_enabled =
- ! @get_cfg_var( 'php_error.force_disabled' ) &&
- ! @get_cfg_var( 'php_error.force_disable' ) &&
- @ini_get('display_errors') === '1' &&
- PHP_SAPI !== 'cli'
- ;
- }
- /**
- * This is shorthand for turning off error handling,
- * calling a block of code, and then turning it on.
- *
- * However if 'reportErrors' has not been called,
- * then this will silently do nothing.
- *
- * @param callback A PHP function to call.
- * @return The result of calling the callback.
- */
- function withoutErrors( $callback ) {
- global $_php_error_global_handler;
- if ( $_php_error_global_handler !== null ) {
- return $_php_error_global_handler->withoutErrors( $callback );
- } else {
- return $callback();
- }
- }
- /**
- * Turns on error reporting, and returns the handler.
- *
- * If you just want error reporting on, then don't bother
- * catching the handler. If you're building something
- * clever, like a framework, then you might want to grab
- * and use it.
- *
- * Note that calling this a second time will replace the
- * global error handling with a new error handler.
- * The existing one will be turned off, and the new one
- * turned on.
- *
- * You can't use two at once!
- *
- * @param options Optional, options declaring how PHP Error should be setup and used.
- * @return The ErrorHandler used for reporting errors.
- */
- function reportErrors( $options=null ) {
- $handler = new ErrorHandler( $options );
- return $handler->turnOn();
- }
- /**
- * The actual handler. There can only ever be one.
- */
- class ErrorHandler
- {
- const REGEX_DOCTYPE = '/<( )*!( *)DOCTYPE([^>]+)>/';
- const REGEX_PHP_IDENTIFIER = '\b[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*';
- const REGEX_PHP_CONST_IDENTIFIER = '/\b[A-Z_\x7f-\xff][A-Z0-9_\x7f-\xff]*/';
- /**
- * Matches:
- * {closure}()
- * blah::foo()
- * foo()
- *
- * It is:
- * a closure
- * or a method or function
- * followed by parenthesis '()'
- *
- * a function is 'namespace function'
- * a method is 'namespace class::function', or 'namespace class->function'
- * the whole namespace is optional
- * namespace is made up of an '\' and then repeating 'namespace\'
- * both the first slash, and the repeating 'namespace\', are optional
- *
- * 'END' matches it at the end of a string, the other one does not.
- */
- 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]*)?)\\(\\)$/';
- 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]*)?)\\(\\)/';
- const REGEX_VARIABLE = '/\b[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/';
- const REGEX_MISSING_SEMI_COLON_FOLLOWING_LINE = '/^ *(return|}|if|while|foreach|for|switch)/';
- /**
- * The number of lines to take from the file,
- * where the error is reported. This is the number
- * of lines around the line in question,
- * including that line.
- *
- * So '9' will be the error line + 4 lines above + 4 lines below.
- */
- const NUM_FILE_LINES = 13;
- const FILE_TYPE_APPLICATION = 1;
- const FILE_TYPE_IGNORE = 2;
- const FILE_TYPE_ROOT = 3;
- const PHP_ERROR_MAGIC_HEADER_KEY = 'PHP_ERROR_MAGIC_HEADER';
- const PHP_ERROR_MAGIC_HEADER_VALUE = 'php_stack_error';
- const MAGIC_IS_PRETTY_ERRORS_MARKER = '<!-- __magic_php_error_is_a_stack_trace_constant__ -->';
- const PHP_ERROR_INI_PREFIX = 'php_error';
- /**
- * At the time of writing, scalar type hints are unsupported.
- * By scalar, I mean 'string' and 'integer'.
- *
- * If they do get added, this is here as a trap to turn scalar
- * type hint warnings on and off.
- */
- private static $IS_SCALAR_TYPE_HINTING_SUPPORTED = false;
- private static $SCALAR_TYPES = array(
- 'string', 'integer', 'float', 'boolean',
- 'bool', 'int', 'number'
- );
- /**
- * A mapping of PHP internal symbols,
- * mapped to descriptions of them.
- */
- private static $PHP_SYMBOL_MAPPINGS = array(
- '$end' => 'end of file',
- 'T_ABSTRACT' => 'abstract',
- 'T_AND_EQUAL' => "'&='",
- 'T_ARRAY' => 'array',
- 'T_ARRAY_CAST' => 'array cast',
- 'T_AS' => "'as'",
- 'T_BOOLEAN_AND' => "'&&'",
- 'T_BOOLEAN_OR' => "'||'",
- 'T_BOOL_CAST' => 'boolean cast',
- 'T_BREAK' => 'break',
- 'T_CASE' => 'case',
- 'T_CATCH' => 'catch',
- 'T_CLASS' => 'class',
- 'T_CLASS_C' => '__CLASS__',
- 'T_CLONE' => 'clone',
- 'T_CLOSE_TAG' => 'closing PHP tag',
- 'T_CONCAT_EQUAL' => "'.='",
- 'T_CONST' => 'const',
- 'T_CONSTANT_ENCAPSED_STRING' => 'string',
- 'T_CONTINUE' => 'continue',
- 'T_CURLY_OPEN' => '\'{$\'',
- 'T_DEC' => '-- (decrement)',
- 'T_DECLARE' => 'declare',
- 'T_DEFAULT' => 'default',
- 'T_DIR' => '__DIR__',
- 'T_DIV_EQUAL' => "'/='",
- 'T_DNUMBER' => 'number',
- 'T_DOLLAR_OPEN_CURLY_BRACES' => '\'${\'',
- 'T_DO' => "'do'",
- 'T_DOUBLE_ARROW' => "'=>'",
- 'T_DOUBLE_CAST' => 'double cast',
- 'T_DOUBLE_COLON' => "'::'",
- 'T_ECHO' => 'echo',
- 'T_ELSE' => 'else',
- 'T_ELSEIF' => 'elseif',
- 'T_EMPTY' => 'empty',
- 'T_ENCAPSED_AND_WHITESPACE' => 'non-terminated string',
- 'T_ENDDECLARE' => 'enddeclare',
- 'T_ENDFOR' => 'endfor',
- 'T_ENDFOREACH' => 'endforeach',
- 'T_ENDIF' => 'endif',
- 'T_ENDSWITCH' => 'endswitch',
- 'T_ENDWHILE' => 'endwhile',
- 'T_EVAL' => 'eval',
- 'T_EXIT' => 'exit call',
- 'T_EXTENDS' => 'extends',
- 'T_FILE' => '__FILE__',
- 'T_FINAL' => 'final',
- 'T_FOR' => 'for',
- 'T_FOREACH' => 'foreach',
- 'T_FUNCTION' => 'function',
- 'T_FUNC_C' => '__FUNCTION__',
- 'T_GLOBAL' => 'global',
- 'T_GOTO' => 'goto',
- 'T_HALT_COMPILER' => '__halt_compiler',
- 'T_IF' => 'if',
- 'T_IMPLEMENTS' => 'implements',
- 'T_INC' => '++ (increment)',
- 'T_INCLUDE' => 'include',
- 'T_INCLUDE_ONCE' => 'include_once',
- 'T_INSTANCEOF' => 'instanceof',
- 'T_INT_CAST' => 'int cast',
- 'T_INTERFACE' => 'interface',
- 'T_ISSET' => 'isset',
- 'T_IS_EQUAL' => "'=='",
- 'T_IS_GREATER_OR_EQUAL' => "'>='",
- 'T_IS_IDENTICAL' => "'==='",
- 'T_IS_NOT_EQUAL' => "'!=' or '<>'",
- 'T_IS_NOT_IDENTICAL' => "'!=='",
- 'T_IS_SMALLER_OR_EQUAL' => "'<='",
- 'T_LINE' => '__LINE__',
- 'T_LIST' => 'list',
- 'T_LNUMBER' => 'number',
- 'T_LOGICAL_AND' => "'and'",
- 'T_LOGICAL_OR' => "'or'",
- 'T_LOGICAL_XOR' => "'xor'",
- 'T_METHOD_C' => '__METHOD__',
- 'T_MINUS_EQUAL' => "'-='",
- 'T_MOD_EQUAL' => "'%='",
- 'T_MUL_EQUAL' => "'*='",
- 'T_NAMESPACE' => 'namespace',
- 'T_NEW' => 'new',
- 'T_NUM_STRING' => 'array index in a string',
- 'T_NS_C' => '__NAMESPACE__',
- 'T_NS_SEPARATOR' => 'namespace seperator',
- 'T_OBJECT_CAST' => 'object cast',
- 'T_OBJECT_OPERATOR' => "'->'",
- 'T_OLD_FUNCTION' => 'old_function',
- 'T_OPEN_TAG' => "'<?php' or '<?'",
- 'T_OPEN_TAG_WITH_ECHO' => "'<?php echo '",
- 'T_OR_EQUAL' => "'|='",
- 'T_PAAMAYIM_NEKUDOTAYIM' => "'::'",
- 'T_PLUS_EQUAL' => "'+='",
- 'T_PRINT' => 'print',
- 'T_PRIVATE' => 'private',
- 'T_PUBLIC' => 'public',
- 'T_PROTECTED' => 'protected',
- 'T_REQUIRE' => 'require',
- 'T_REQUIRE_ONCE' => 'require_once',
- 'T_RETURN' => 'return',
- 'T_SL' => "'<<'",
- 'T_SL_EQUAL' => "'<<='",
- 'T_SR' => "'>>'",
- 'T_SR_EQUAL' => "'>>='",
- 'T_START_HEREDOC' => "'<<<'",
- 'T_STATIC' => 'static',
- 'T_STRING' => 'string',
- 'T_STRING_CAST' => 'string cast',
- 'T_SWITCH' => 'switch',
- 'T_THROW' => 'throw',
- 'T_TRY' => 'try',
- 'T_UNSET' => 'unset',
- 'T_UNSET_CAST' => 'unset cast',
- 'T_USE' => 'use',
- 'T_VAR' => 'var',
- 'T_VARIABLE' => 'variable',
- 'T_WHILE' => 'while',
- 'T_WHITESPACE' => 'whitespace',
- 'T_XOR_EQUAL' => "'^='"
- );
- private static $syntaxMap = array(
- 'const' => 'syntax-literal',
- 'reference_ampersand' => 'syntax-function',
- T_COMMENT => 'syntax-comment',
- T_DOC_COMMENT => 'syntax-comment',
- T_ABSTRACT => 'syntax-keyword',
- T_AS => 'syntax-keyword',
- T_BREAK => 'syntax-keyword',
- T_CASE => 'syntax-keyword',
- T_CATCH => 'syntax-keyword',
- T_CLASS => 'syntax-keyword',
- T_CONST => 'syntax-keyword',
- T_CONTINUE => 'syntax-keyword',
- T_DECLARE => 'syntax-keyword',
- T_DEFAULT => 'syntax-keyword',
- T_DO => 'syntax-keyword',
-
- T_ELSE => 'syntax-keyword',
- T_ELSEIF => 'syntax-keyword',
- T_ENDDECLARE => 'syntax-keyword',
- T_ENDFOR => 'syntax-keyword',
- T_ENDFOREACH => 'syntax-keyword',
- T_ENDIF => 'syntax-keyword',
- T_ENDSWITCH => 'syntax-keyword',
- T_ENDWHILE => 'syntax-keyword',
- T_EXTENDS => 'syntax-keyword',
- T_FINAL => 'syntax-keyword',
- T_FOR => 'syntax-keyword',
- T_FOREACH => 'syntax-keyword',
- T_FUNCTION => 'syntax-keyword',
- T_GLOBAL => 'syntax-keyword',
- T_GOTO => 'syntax-keyword',
-
- T_IF => 'syntax-keyword',
- T_IMPLEMENTS => 'syntax-keyword',
- T_INSTANCEOF => 'syntax-keyword',
- T_INTERFACE => 'syntax-keyword',
- T_LOGICAL_AND => 'syntax-keyword',
- T_LOGICAL_OR => 'syntax-keyword',
- T_LOGICAL_XOR => 'syntax-keyword',
- T_NAMESPACE => 'syntax-keyword',
- T_NEW => 'syntax-keyword',
- T_PRIVATE => 'syntax-keyword',
- T_PUBLIC => 'syntax-keyword',
- T_PROTECTED => 'syntax-keyword',
- T_RETURN => 'syntax-keyword',
- T_STATIC => 'syntax-keyword',
- T_SWITCH => 'syntax-keyword',
- T_THROW => 'syntax-keyword',
- T_TRY => 'syntax-keyword',
- T_USE => 'syntax-keyword',
- T_VAR => 'syntax-keyword',
- T_WHILE => 'syntax-keyword',
- // __VAR__ type magic constants
- T_CLASS_C => 'syntax-literal',
- T_DIR => 'syntax-literal',
- T_FILE => 'syntax-literal',
- T_FUNC_C => 'syntax-literal',
- T_LINE => 'syntax-literal',
- T_METHOD_C => 'syntax-literal',
- T_NS_C => 'syntax-literal',
- T_DNUMBER => 'syntax-literal',
- T_LNUMBER => 'syntax-literal',
- T_CONSTANT_ENCAPSED_STRING => 'syntax-string',
- T_VARIABLE => 'syntax-variable',
- // this is for unescaped strings, which appear differently
- // this includes function names
- T_STRING => 'syntax-function',
- // in build keywords, which work like functions
- T_ARRAY => 'syntax-function',
- T_CLONE => 'syntax-function',
- T_ECHO => 'syntax-function',
- T_EMPTY => 'syntax-function',
- T_EVAL => 'syntax-function',
- T_EXIT => 'syntax-function',
- T_HALT_COMPILER => 'syntax-function',
- T_INCLUDE => 'syntax-function',
- T_INCLUDE_ONCE => 'syntax-function',
- T_ISSET => 'syntax-function',
- T_LIST => 'syntax-function',
- T_REQUIRE_ONCE => 'syntax-function',
- T_PRINT => 'syntax-function',
- T_REQUIRE => 'syntax-function',
- T_UNSET => 'syntax-function'
- );
- /**
- * A list of methods which are known to call the autoloader,
- * but should not error, if the class is not found.
- *
- * They are allowed to fail, so we don't store a class not
- * found exception if they do.
- */
- private static $SAFE_AUTOLOADER_FUNCTIONS = array(
- 'class_exists',
- 'interface_exists',
- 'method_exists',
- 'property_exists',
- 'is_subclass_of'
- );
- /**
- * When returning values, if a mime type is set,
- * then PHP Error should only output if the mime type
- * is one of these.
- */
- private static $ALLOWED_RETURN_MIME_TYPES = array(
- 'text/html',
- 'application/xhtml+xml'
- );
- private static function isIIS() {
- return (
- isset($_SERVER['SERVER_SOFTWARE']) &&
- strpos($_SERVER['SERVER_SOFTWARE'], 'IIS/') !== false
- ) || (
- isset($_SERVER['_FCGI_X_PIPE_']) &&
- strpos($_SERVER['_FCGI_X_PIPE_'], 'IISFCGI') !== false
- );
- }
-
- /**
- * This attempts to state if this is *not* a PHP request,
- * but it cannot say if it *is* a PHP request. It achieves
- * this by looking for a mime type.
- *
- * For example if the mime type is JavaScript, then we
- * know it's not PHP. However there is no "yes, this is
- * definitely a normal HTML response" flag we can check.
- */
- private static function isNonPHPRequest() {
- /*
- * Check if we are a mime type that isn't allowed.
- *
- * Anything other than 'text/html' or similar will cause
- * this to turn off.
- */
- $response = ErrorHandler::getResponseHeaders();
- foreach ( $response as $key => $value ) {
- if ( strtolower($key) === 'content-type' ) {
- $found = true;
- foreach ( ErrorHandler::$ALLOWED_RETURN_MIME_TYPES as $type ) {
- if ( stripos($value, $type) !== false ) {
- $found = true;
- break;
- }
- }
- if ( ! $found ) {
- return true;
- }
- break;
- }
- }
- return false;
- }
- /**
- * Looks up a description for the symbol given,
- * and if found, it is returned.
- *
- * If it's not found, then the symbol given is returned.
- */
- private static function phpSymbolToDescription( $symbol ) {
- if ( isset(ErrorHandler::$PHP_SYMBOL_MAPPINGS[$symbol]) ) {
- return ErrorHandler::$PHP_SYMBOL_MAPPINGS[$symbol];
- } else {
- return "'$symbol'";
- }
- }
- /**
- * Attempts to syntax highlight the code snippet done.
- *
- * This is then returned as HTML, ready to be dumped to the screen.
- *
- * @param code An array of code lines to syntax highlight.
- * @return HTML version of the code given, syntax highlighted.
- */
- private static function syntaxHighlight( $code ) {
- $syntaxMap = ErrorHandler::$syntaxMap;
- // @supress invalid code raises a warning
- $tokens = @token_get_all( "<?php " . $code . " ?" . ">" );
- $html = array();
- $len = count($tokens)-1;
- $inString = false;
- $stringBuff = null;
- $skip = false;
- for ( $i = 1; $i < $len; $i++ ) {
- $token = $tokens[$i];
- if ( is_array($token) ) {
- $type = $token[0];
- $code = $token[1];
- } else {
- $type = null;
- $code = $token;
- }
- // work out any whitespace padding
- if ( strpos($code, "\n") !== false && trim($code) === '' ) {
- if ( $inString ) {
- $html[]= "<span class='syntax-string'>" . join('', $stringBuff);
- $stringBuff = array();
- }
- } else if ( $code === '&' ) {
- if ( $i < $len ) {
- $next = $tokens[$i+1];
- if ( is_array($next) && $next[0] === T_VARIABLE ) {
- $type = 'reference_ampersand';
- }
- }
- } else if ( $code === '"' || $code === "'" ) {
- if ( $inString ) {
- $html[]= "<span class='syntax-string'>" . join('', $stringBuff) . htmlspecialchars($code) . "</span>";
- $stringBuff = null;
- $skip = true;
- } else {
- $stringBuff = array();
- }
- $inString = !$inString;
- } else if ( $type === T_STRING ) {
- $matches = array();
- preg_match(ErrorHandler::REGEX_PHP_CONST_IDENTIFIER, $code, $matches);
- if ( $matches && strlen($matches[0]) === strlen($code) ) {
- $type = 'const';
- }
- }
- if ( $skip ) {
- $skip = false;
- } else {
- $code = htmlspecialchars( $code );
- if ( $type !== null && isset($syntaxMap[$type]) ) {
- $class = $syntaxMap[$type];
- if ( $type === T_CONSTANT_ENCAPSED_STRING && strpos($code, "\n") !== false ) {
- $append = "<span class='$class'>" .
- join(
- "</span>\n<span class='$class'>",
- explode( "\n", $code )
- ) .
- "</span>" ;
- } else if ( strrpos($code, "\n") === strlen($code)-1 ) {
- $append = "<span class='$class'>" . substr($code, 0, strlen($code)-1) . "</span>\n";
- } else {
- $append = "<span class='$class'>$code</span>";
- }
- } else if ( $inString && $code !== '"' ) {
- $append = "<span class='syntax-string'>$code</span>";
- } else {
- $append = $code;
- }
- if ( $inString ) {
- $stringBuff[]= $append;
- } else {
- $html[]= $append;
- }
- }
- }
- if ( $stringBuff !== null ) {
- $html[]= "<span class='syntax-string'>" . join('', $stringBuff) . '</span>';
- $stringBuff = null;
- }
- return join( '', $html );
- }
- /**
- * Splits a given function name into it's 'class, function' parts.
- * If there is no class, then null is returned.
- *
- * It also returns these parts in an array of: array( $className, $functionName );
- *
- * Usage:
- *
- * list( $class, $function ) = ErrorHandler::splitFunction( $name );
- *
- * @param name The function name to split.
- * @return An array containing class and function name.
- */
- private static function splitFunction( $name ) {
- $name = preg_replace( '/\\(\\)$/', '', $name );
- if ( strpos($name, '::') !== false ) {
- $parts = explode( '::', $name );
- $className = $parts[0];
- $type = '::';
- $functionName = $parts[1];
- } else if ( strpos($name, '->') !== false ) {
- $parts = explode( '->', $name );
- $className = $parts[0];
- $type = '->';
- $functionName = $parts[1];
- } else {
- $className = null;
- $type = null;
- $functionName = $name;
- }
- return array( $className, $type, $functionName );
- }
- private static function newArgument( $name, $type=false, $isPassedByReference=false, $isOptional=false, $optionalValue=null, $highlight=false ) {
- if ( $name instanceof ReflectionParameter ) {
- $highlight = func_num_args() > 1 ?
- $highlight = $type :
- false;
- $klass = $name->getDeclaringClass();
- $functionName = $name->getDeclaringFunction()->name;
- if ( $klass !== null ) {
- $klass = $klass->name;
- }
- $export = ReflectionParameter::export(
- ( $klass ?
- array( "\\$klass", $functionName ) :
- $functionName ),
- $name->name,
- true
- );
- $paramType = preg_replace('/.*?(\w+)\s+\$'.$name->name.'.*/', '\\1', $export);
- if ( strpos($paramType, '[') !== false || strlen($paramType) === 0 ) {
- $paramType = null;
- }
- return ErrorHandler::newArgument(
- $name->name,
- $paramType,
- $name->isPassedByReference(),
- $name->isDefaultValueAvailable(),
- ( $name->isDefaultValueAvailable() ?
- var_export( $name->getDefaultValue(), true ) :
- null ),
- ( func_num_args() > 1 ?
- $type :
- false )
- );
- } else {
- return array(
- 'name' => $name,
- 'has_type' => ( $type !== false ),
- 'type' => $type,
- 'is_reference' => $isPassedByReference,
- 'has_default' => $isOptional,
- 'default_val' => $optionalValue,
- 'is_highlighted' => $highlight
- );
- }
- }
- private static function syntaxHighlightFunctionMatch( $match, &$stackTrace, $highlightArg=null, &$numHighlighted=0 ) {
- list( $className, $type, $functionName ) = ErrorHandler::splitFunction( $match );
- // is class::method()
- if ( $className !== null ) {
- $reflectFun = new ReflectionMethod( $className, $functionName );
- // is a function
- } else if ( $functionName === '{closure}' ) {
- return '<span class="syntax-variable">$closure</span>';
- } else {
- $reflectFun = new ReflectionFunction( $functionName );
- }
- if ( $reflectFun ) {
- $params = $reflectFun->getParameters();
- if ( $params ) {
- $args = array();
- $min = 0;
- foreach( $params as $i => $param ) {
- $arg = ErrorHandler::newArgument( $param );
- if ( ! $arg['has_default'] ) {
- $min = $i;
- }
- $args[]= $arg;
- }
- if ( $highlightArg !== null ) {
- for ( $i = $highlightArg; $i <= $min; $i++ ) {
- $args[$i]['is_highlighted'] = true;
- }
- $numHighlighted = $min-$highlightArg;
- }
- if ( $className !== null ) {
- if ( $stackTrace && isset($stackTrace[1]) && isset($stackTrace[1]['type']) ) {
- $type = htmlspecialchars( $stackTrace[1]['type'] );
- }
- } else {
- $type = null;
- }
- return ErrorHandler::syntaxHighlightFunction( $className, $type, $functionName, $args );
- }
- }
- return null;
- }
- /**
- * Returns the values given, as HTML, syntax highlighted.
- * It's a shorter, slightly faster, more no-nonsense approach
- * then 'syntaxHighlight'.
- *
- * This is for syntax highlighting:
- * - fun( [args] )
- * - class->fun( [args] )
- * - class::fun( [args] )
- *
- * Class and type can be null, to denote no class, but are not optional.
- */
- private static function syntaxHighlightFunction( $class, $type, $fun, &$args=null ) {
- $info = array();
- // set the info
- if ( isset($class) && $class && isset($type) && $type ) {
- if ( $type === '->' ) {
- $type = '->';
- }
- $info []= "<span class='syntax-class'>$class</span>$type";
- }
- if ( isset($fun) && $fun ) {
- $info []= "<span class='syntax-function'>$fun</span>";
- }
- if ( $args ) {
- $info []= '( ';
- foreach ($args as $i => $arg) {
- if ( $i > 0 ) {
- $info[]= ', ';
- }
- if ( is_string($arg) ) {
- $info[]= $arg;
- } else {
- $highlight = $arg['is_highlighted'];
- $name = $arg['name'];
- if ( $highlight ) {
- $info[]= '<span class="syntax-higlight-variable">';
- }
- if ( $name === '_' ) {
- $info[]= '<span class="syntax-variable-not-important">';
- }
- if ( $arg['has_type'] ) {
- $info []= "<span class='syntax-class'>";
- $info []= $arg['type'];
- $info []= '</span> ';
- }
- if ( $arg['is_reference'] ) {
- $info []= '<span class="syntax-function">&</span>';
- }
- $info []= "<span class='syntax-variable'>\$$name</span>";
- if ( $arg['has_default'] ) {
- $info []= '=<span class="syntax-literal">' . $arg['default_val'] . '</span>';
- }
- if ( $name === '_' ) {
- $info[]= '</span>';
- }
- if ( $highlight ) {
- $info[]= '</span>';
- }
- }
- }
- $info []= ' )';
- } else {
- $info []= '()';
- }
- return join( '', $info );
- }
- /**
- * Checks if the item is in options, and if it is, then it is removed and returned.
- *
- * If it is not found, or if options is not an array, then the alt is returned.
- */
- private static function optionsPop( &$options, $key, $alt=null ) {
- if ( $options && isset($options[$key]) ) {
- $val = $options[$key];
- unset( $options[$key] );
- return $val;
- } else {
- $iniAlt = @get_cfg_var( ErrorHandler::PHP_ERROR_INI_PREFIX . '.' . $key );
- if ( $iniAlt !== false ) {
- return $iniAlt;
- } else {
- return $alt;
- }
- }
- }
- private static function folderTypeToCSS( $type ) {
- if ( $type === ErrorHandler::FILE_TYPE_ROOT ) {
- return 'file-root';
- } else if ( $type === ErrorHandler::FILE_TYPE_IGNORE ) {
- return 'file-ignore';
- } else if ( $type === ErrorHandler::FILE_TYPE_APPLICATION ) {
- return 'file-app';
- } else {
- return 'file-common';
- }
- }
- private static function isFolderType( &$folders, $longest, $file ) {
- $parts = explode( '/', $file );
- $len = min( count($parts), $longest );
- for ( $i = $len; $i > 0; $i-- ) {
- if ( isset($folders[$i]) ) {
- $folderParts = &$folders[ $i ];
- $success = false;
- for ( $j = 0; $j < count($folderParts); $j++ ) {
- $folderNames = $folderParts[$j];
- for ( $k = 0; $k < count($folderNames); $k++ ) {
- if ( $folderNames[$k] === $parts[$k] ) {
- $success = true;
- } else {
- $success = false;
- break;
- }
- }
- }
- if ( $success ) {
- return true;
- }
- }
- }
- return false;
- }
- private static function setFolders( &$origFolders, &$longest, $folders ) {
- $newFolders = array();
- $newLongest = 0;
- if ( $folders ) {
- if ( is_array($folders) ) {
- foreach ( $folders as $folder ) {
- ErrorHandler::setFoldersInner( $newFolders, $newLongest, $folder );
- }
- } else if ( is_string($folders) ) {
- ErrorHandler::setFoldersInner( $newFolders, $newLongest, $folders );
- } else {
- throw new Exception( "Unknown value given for folder: " . $folders );
- }
- }
- $origFolders = $newFolders;
- $longest = $newLongest;
- }
- private static function setFoldersInner( &$newFolders, &$newLongest, $folder ) {
- $folder = str_replace( '\\', '/', $folder );
- $folder = preg_replace( '/(^\\/+)|(\\/+$)/', '', $folder );
- $parts = explode( '/', $folder );
- $count = count( $parts );
- $newLongest = max( $newLongest, $count );
-
- if ( isset($newFolders[$count]) ) {
- $folds = &$newFolders[$count];
- $folds[]= $parts;
- } else {
- $newFolders[$count] = array( $parts );
- }
- }
- private static function getRequestHeaders() {
- if ( function_exists('getallheaders') ) {
- return getallheaders();
- } else {
- $headers = array();
-
- foreach ( $_SERVER as $key => $value ) {
- if ( strpos($key, 'HTTP_') === 0 ) {
- $key = str_replace( " ", "-", ucwords(strtolower( str_replace("_", " ", substr($key, 5)) )) );
- $headers[ $key ] = $value;
- }
- }
- return $headers;
- }
- }
- private static function getResponseHeaders() {
- $headers = function_exists('apache_response_headers') ?
- apache_response_headers() :
- array() ;
- /*
- * Merge the headers_list into apache_response_headers.
- *
- * This is because sometimes things are in one, which are
- * not present in the other.
- */
- if ( function_exists('headers_list') ) {
- $hList = headers_list();
- foreach ($hList as $header) {
- $header = explode(":", $header);
- $headers[ array_shift($header) ] = trim( implode(":", $header) );
- }
- }
- return $headers;
- }
- public static function identifyTypeHTML( $arg, $recurseLevels=1 ) {
- if ( ! is_array($arg) && !is_object($arg) ) {
- if ( is_string($arg) ) {
- return "<span class='syntax-string'>"" . htmlentities($arg) . ""</span>";
- } else {
- return "<span class='syntax-literal'>" . var_export( $arg, true ) . '</span>';
- }
- } else if ( is_array($arg) ) {
- if ( count($arg) === 0 ) {
- return "[]";
- } else if ( $recurseLevels > 0 ) {
- $argArr = array();
- foreach ($arg as $ag) {
- $argArr[]= ErrorHandler::identifyTypeHTML( $ag, $recurseLevels-1 );
- }
- if ( ($recurseLevels % 2) === 0 ) {
- return "[" . join(', ', $argArr) . "]";
- } else {
- return "[ " . join(', ', $argArr) . " ]";
- }
- } else {
- return "[...]";
- }
- } else if ( get_class($arg) === 'Closure' ) {
- return '<span class="syntax-variable">$Closure</span>()';
- } else {
- $argKlass = get_class( $arg );
- if ( preg_match(ErrorHandler::REGEX_PHP_CONST_IDENTIFIER, $argKlass) ) {
- return '<span class="syntax-literal">$' . $argKlass . '</span>';
- } else {
- return '<span class="syntax-variable">$' . $argKlass . '</span>';
- }
- }
- }
- private $cachedFiles;
- private $isShutdownRegistered;
- private $isOn;
- private $ignoreFolders = array();
- private $ignoreFoldersLongest = 0;
- private $applicationFolders = array();
- private $applicationFoldersLongest = 0;
- private $defaultErrorReportingOn;
- private $defaultErrorReportingOff;
- private $applicationRoot;
- private $serverName;
- private $catchClassNotFound;
- private $catchSurpressedErrors;
- private $catchAjaxErrors;
- private $backgroundText;
- private $numLin…
Large files files are truncated, but you can click here to view the full file