home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2005 June / PCpro_2005_06.ISO / files / opensource / xamp / xampp-win32.exe / xampp / Util.php < prev    next >
Encoding:
PHP Script  |  2004-03-24  |  19.9 KB  |  560 lines

  1. <?php
  2. /**
  3.  * Utility static class
  4.  * @package Error_Raise
  5.  * @version 0.2.2
  6.  * @author Greg Beaver cellog@php.net
  7.  */
  8. /**
  9.  * Error used if a class passed to initialize hasn't been defined yet
  10.  *
  11.  * {@link initialize()} allows
  12.  */
  13. define('ERROR_UTIL_ERROR_CLASS_DOESNT_EXIST', 1);
  14. /**
  15.  * Error used if a method doesn't exist in a callback passed in
  16.  */
  17. define('ERROR_UTIL_ERROR_METHOD_DOESNT_EXIST', 2);
  18. /**
  19.  * Error used if a function doesn't exist in a callback passed in
  20.  */
  21. define('ERROR_UTIL_ERROR_FUNCTION_DOESNT_EXIST', 3);
  22. /**
  23.  * Error used when parameters to functions don't match expected types
  24.  */
  25. define('ERROR_UTIL_ERROR_INVALID_INPUT', 4);
  26. /**
  27.  * Error used when an internal function is passed as a callback - this is never
  28.  * allowed.
  29.  */
  30. define('ERROR_UTIL_ERROR_INTERNAL_FUNCTION', 5);
  31. /**
  32.  * Utility functions for Error display
  33.  *
  34.  * This class is used for advanced retrieval of context information, and for
  35.  * callback validation.  It also has a few miscellaneous functions for processing
  36.  * display of variables.
  37.  * @package Error_Raise
  38.  * @version 0.2.2
  39.  * @author Greg Beaver cellog@php.net
  40.  * @static
  41.  */
  42. class Error_Util {
  43.     /**
  44.      * Extracted from {@link http://mojavelinux.com/forum/viewforum.php?f=4}
  45.      * originally by Dan Allen
  46.      * @param string full path to source file that triggered a PHP error
  47.      * @param string line number of error
  48.      * @static
  49.      */
  50.     function getErrorContext($file, $line, $contextLines = 5)
  51.     {
  52.         if (!file_exists($file) || !is_readable($file)) {
  53.             return array(
  54.                 'start'        => 0,
  55.                 'end'        => 0,
  56.                 'source'    => '',
  57.                 'variables'    => array(),
  58.             );
  59.         }
  60.  
  61.         $sourceLines = file($file);
  62.         $offset = max($line - 1 - $contextLines, 0);
  63.         $numLines = 2 * $contextLines + 1;
  64.         $sourceLines = array_slice($sourceLines, $offset, $numLines);
  65.         $numLines = count($sourceLines);
  66.         // add line numbers
  67.         foreach ($sourceLines as $index => $line) {
  68.             $sourceLines[$index] = ($offset + $index + 1)  . ': ' . $line;
  69.         }
  70.     
  71.         $source = Error_Util::_addPhpTags(join('', $sourceLines));
  72.         preg_match_all(';\$([[:alnum:]]+);', $source, $matches);
  73.         $variables = array_values(array_unique($matches[1]));
  74.         return array(
  75.             'start'        => $offset + 1,
  76.             'end'        => $offset + $numLines,
  77.             'source'    => $source,
  78.             'variables'    => $variables,
  79.         );
  80.     }
  81.  
  82.     /**
  83.      * Extracted from {@link http://mojavelinux.com/forum/viewforum.php?f=4}
  84.      * originally by Dan Allen
  85.      * @param array list of variables found in code context
  86.      * @param array list of variables from trigger_error context
  87.      * @param boolean if false, then all variables in $variables will be dumped
  88.      * @param array list of classes to exclude from var_export
  89.      * @param string line number of error
  90.      * @return string|false
  91.      * @static
  92.      */
  93.     function exportVariables($variables, $contextVariables, $strict = true,
  94.         $excludeClasses = array())
  95.     {
  96.         $variableString = '';
  97.         foreach ($variables as $name => $contents) {
  98.             // if we are using strict context and this variable is
  99.             // not in the context, skip it
  100.             if ($strict && !in_array($name, $contextVariables)) {
  101.                 continue;
  102.             }
  103.  
  104.             // if this is an object and the class is in the exclude list, skip it
  105.             if (is_object($contents) && in_array(get_class($contents),
  106.                   $excludeClasses)) {
  107.                 continue;
  108.             }
  109.  
  110.             $variableString .= '$' . $name . ' = ' .
  111.                 Error_Util::var_export2($contents, true) . ';' . "\n";
  112.         }
  113.  
  114.         if (empty($variableString)) {
  115.             return false;
  116.         } else {
  117.             return "\n" . $variableString;
  118.         }
  119.     }
  120.     
  121.  
  122.     /**
  123.      * Extracted from {@link http://mojavelinux.com/forum/viewforum.php?f=4}
  124.      * originally by Dan Allen
  125.      * @param string string that should be escaped for JS
  126.      * @return string
  127.      * @static
  128.      */
  129.     function escapeJavascript($string)
  130.     {
  131.         return strtr($string, array(
  132.             "\t" => '\\t',
  133.             "\n" => '\\n',
  134.             "\r" => '\\r',
  135.             '\\' => '\',
  136.             "'" => '''));
  137.     }
  138.  
  139.     /**
  140.      * Copied from {@link http://www.php.net/strrpos}, comment by
  141.      * DONT SPAM vardges at iqnest dot com
  142.      * @param string full string
  143.      * @param string search string
  144.      * @param integer offset from the start of the string to begin searching
  145.      *                from
  146.      * @static
  147.      */
  148.     function strrpos_str ($string, $searchFor, $startFrom = 0)
  149.     {
  150.         $addLen = strlen ($searchFor);
  151.         $endPos = $startFrom - $addLen;
  152.  
  153.         while (true) {
  154.             if (($newPos = strpos ($string, $searchFor,
  155.                   $endPos + $addLen)) === false) {
  156.                 break;
  157.             }
  158.             $endPos = $newPos;
  159.         }
  160.  
  161.         return ($endPos >= 0) ? $endPos : false;
  162.     }
  163.  
  164.     /**
  165.      * Add PHP Tags if necessary to variable context PHP for highlighting
  166.      *
  167.      * Extracted from {@link http://mojavelinux.com/forum/viewforum.php?f=4}
  168.      * originally by Dan Allen
  169.      * @param string source code for context around an error
  170.      * @static
  171.      */
  172.     function _addPhpTags($source)
  173.     {
  174.         $startTag  = '<?php';
  175.         $endTag = '?>';
  176.  
  177.         if (($pos = strpos($source, $startTag)) !== false) {
  178.             $firstStartPos = $pos;
  179.         } else {
  180.             $firstStartPos = -1;
  181.         }
  182.         if (($pos = strpos($source, $endTag)) !== false) {
  183.             $firstEndPos = $pos;
  184.         } else {
  185.             $firstEndPos = -1;
  186.         }
  187.  
  188.         // no tags found then it must be solid php since
  189.         // html can't throw a php error
  190.         if ($firstStartPos < 0 && $firstEndPos < 0) {
  191.             return $startTag . "\n" . $source . "\n" . $endTag;
  192.         }
  193.  
  194.         // found an end tag first, so we are missing a start tag
  195.         if ($firstEndPos >= 0 &&
  196.               ($firstStartPos < 0 || $firstStartPos > $firstEndPos)) {
  197.             $source = $startTag . "\n" . $source;
  198.         }
  199.  
  200.         $sourceLength = strlen($source);
  201.         if (($pos = Error_Util::strrpos_str($source, $startTag)) !== false) {
  202.             $lastStartPos = $pos;
  203.         } else {
  204.             $lastStartPos = $sourceLength + 1;
  205.         }
  206.         if (($pos = Error_Util::strrpos_str($source, $endTag)) !== false) {
  207.             $lastEndPos = $pos;
  208.         } else {
  209.             $lastEndPos = $sourceLength + 1;
  210.         }
  211.  
  212.         if ($lastEndPos < $lastStartPos || ($lastEndPos > $lastStartPos
  213.               && $lastEndPos > $sourceLength)) {
  214.             $source .= $endTag;
  215.         }
  216.  
  217.         return $source;
  218.     }
  219.  
  220.     /**
  221.      * More advanced var_export for HTML/Javascript, private recursive function
  222.      *
  223.      * Extracted from {@link http://mojavelinux.com/forum/viewforum.php?f=4}
  224.      * originally by Dan Allen
  225.      * @param mixed variable to var_export
  226.      * @param string indentation
  227.      * @param boolean is an array portion of the variable
  228.      * @param integer recursion level
  229.      * @access private
  230.      * @static
  231.      */
  232.     function &_var_export2(&$variable, $arrayIndent = '', $inArray = false,
  233.         $level = 0)
  234.     {
  235.         static $maxLevels = 5, $followObjectReferences = false;
  236.         if ($inArray != false) {
  237.             $leadingSpace = '';
  238.             $trailingSpace = ',' . "\n";
  239.         } else {
  240.             $leadingSpace = $arrayIndent;
  241.             $trailingSpace = '';
  242.         }
  243.  
  244.         $result = '';
  245.         switch (gettype($variable))
  246.         {
  247.             case 'object':
  248.                 if ($inArray && !$followObjectReferences)
  249.                 {
  250.                     $result = '*' . get_class($variable) . ' REFERENCE*';
  251.                     $trailingSpace = "\n";
  252.                     break;
  253.                 }
  254.             case 'array':
  255.                 if ($maxLevels && $level >= $maxLevels) {
  256.                     $result = '** truncated, too much recursion **';
  257.                 } else {
  258.                     $result = "\n" . $arrayIndent . 'array (' . "\n";
  259.                     foreach ($variable as $key => $value) {
  260.                         $result .= $arrayIndent . '  ' . (is_int($key)
  261.                           ? $key : ('\'' . 
  262.                           str_replace('\'', '\\\'', $key) . '\'')) . ' => ' . 
  263.                           Error_Util::_var_export2($value,
  264.                             $arrayIndent . '  ', true, $level + 1);
  265.                     }
  266.  
  267.                     $result .= $arrayIndent . ')';
  268.                 }
  269.             break;
  270.  
  271.             case 'string':
  272.                 $result = '\'' . str_replace('\'', '\\\'', $variable) . '\'';
  273.             break;
  274.  
  275.             case 'boolean':
  276.                 $result = $variable ? 'true' : 'false';
  277.             break;
  278.  
  279.             case 'NULL':
  280.                 $result = 'NULL';
  281.             break;
  282.  
  283.             case 'resource':
  284.                 $result = get_resource_type($variable);
  285.             break;
  286.  
  287.             default:
  288.                 $result = $variable;
  289.             break;
  290.         }
  291.  
  292.         return $leadingSpace . $result . $trailingSpace;
  293.     }
  294.  
  295.     /**
  296.      * More advanced var_export for HTML/Javascript, private recursive function
  297.      *
  298.      * Extracted from {@link http://mojavelinux.com/forum/viewforum.php?f=4}
  299.      * originally by Dan Allen
  300.      * @param mixed variable to var_export
  301.      * @param boolean prints output by default, set to true to return a string
  302.      * @static
  303.      */
  304.     function var_export2(&$variable, $return = false)
  305.     {
  306.         $result =& Error_Util::_var_export2($variable);
  307.         if ($return) {
  308.             return $result;
  309.         } else {
  310.             echo $result;
  311.         }
  312.     }
  313.     
  314.     /**
  315.      * calls {@link file_exists()} for each value in include_path,
  316.      * then calls {@link is_readable()} when it finds the file.
  317.      *
  318.      * This doesn't really belong here, but is useful
  319.      * @param string
  320.      * @return boolean
  321.      */
  322.     function isIncludeable($filename)
  323.     {
  324.         $ip = get_include_path();
  325.         if (substr(PHP_OS, 0, 3) == 'WIN') {
  326.             $ip = explode(';', $ip);
  327.         } else {
  328.             $ip = explode(':', $ip);
  329.         }
  330.         foreach($ip as $path) {
  331.             if ($a = realpath($path . DIRECTORY_SEPARATOR . $filename)) {
  332.                 if (is_readable($a)) {
  333.                     return true;
  334.                 }
  335.             }
  336.         }
  337.         return false;
  338.     }
  339.  
  340.     /**
  341.      * Default file/line number grabber function
  342.      *
  343.      * This function uses a backtrace generated from {@link debug_backtrace()}
  344.      * and so will not work at all in PHP < 4.3.0.  The frame should
  345.      * reference the frame that contains the source of the error.  See how
  346.      * raise() implements this in the source code for a very specific idea
  347.      * of how to do this in your own code, if you won't be using one of the
  348.      * standard error-throwing methods
  349.      * @return array|false either array('_file' => file, '_line' => line,
  350.      *         '_function' => function name, '_class' => class name) or
  351.      *         if this doesn't work, then false
  352.      * @param array Results of debug_backtrace()
  353.      * @param integer backtrace frame.
  354.      */
  355.     function _getFileLine($backtrace = null, $frame = 0, $functionframe = 1)
  356.     {
  357.         if (isset($backtrace) && is_array($backtrace) &&
  358.               isset($backtrace[$frame])) {
  359.             if (!isset($backtrace[$frame]['file'])) {
  360.                 $frame++;
  361.             }
  362.             $funcbacktrace = $backtrace[$functionframe];
  363.             $filebacktrace = $backtrace[$frame];
  364.             $ret = array('_file' => $filebacktrace['file'],
  365.                          '_line' => $filebacktrace['line']);
  366.             // rearrange for eval'd code or create function errors
  367.             if (preg_match(';^(.*?)\((\d+)\) : (.*?)$;', $filebacktrace['file'],
  368.                   $matches)) {
  369.                 $ret['_file'] = $matches[1];
  370.                 $ret['_line'] = $matches[2] + 0;
  371.             }
  372.             if (isset($funcbacktrace['function'])) {
  373.                 $ret['_function'] = $funcbacktrace['function'];
  374.             }
  375.             if (isset($funcbacktrace['class'])) {
  376.                 $ret['_class'] = $funcbacktrace['class'];
  377.             }
  378.             return $ret;
  379.         }
  380.         return false;
  381.     }
  382.     
  383.     function formatStackTrace($trace)
  384.     {
  385.         
  386.     }
  387.     
  388.     /**
  389.      * Parse a backtrace to retrieve the calling frame
  390.      *
  391.      * WARNING: do not attempt to use this in any code outside of
  392.      * Error_Raise::raise(), it just won't work at all
  393.      * @access private
  394.      * @param array debug_backtrace() output from {@link Error_Raise::raise()}
  395.      * @param string warning/error/notice/exception
  396.      * @param Error_Raise_Error error object
  397.      */
  398.     function _parseBacktrace($trace, $errorType, &$error)
  399.     {
  400.         if (!isset($trace[1])) {
  401.             return array(0, 0);
  402.         }
  403.         $functionframe = $frame = 1; // get calling function backtrace
  404.         if (isset($trace[1]['class'])) {
  405.             if (isset($trace[1]['function']) &&
  406.                   $trace[1]['function'] != $errorType) {
  407.                 // raise was called directly
  408.                 $frame = 0;
  409.             }
  410.             $testclass = $trace[$functionframe]['class'];
  411.             if (str_replace($error->getPackage(), '', $testclass) ==
  412.                 '_raise' && isset($trace[$functionframe])) {
  413.                 $functionframe++;
  414.             }
  415.         }
  416.         while (isset($trace[$functionframe]['function']) &&
  417.               in_array($trace[$functionframe]['function'],
  418.               array('eval', '__lambda_func')) &&
  419.               isset($trace[$functionframe + 1])) {
  420.             $functionframe++;
  421.         }
  422.         return array($frame, $functionframe);
  423.     }
  424.  
  425.     /**
  426.      * Verify that $callback is a valid function callback
  427.      *
  428.      * This is used to be absolutely sure a callback is valid before registering
  429.      * it, to avoid later errors on the throwing of an error
  430.      * @param string|array
  431.      * @return true|Error_Raise_Error
  432.      * @throws ERROR_UTIL_ERROR_FUNCTION_DOESNT_EXIST If the callback is a
  433.      *         string and isn't the name of any function
  434.      * @throws ERROR_UTIL_ERROR_INTERNAL_FUNCTION If the callback is the name
  435.      *         of an internal, pre-defined function like "function_exists"
  436.      * @throws ERROR_UTIL_ERROR_INVALID_INPUT If the callback is neither
  437.      *         a string, an array(classname, method), or an array(object, method)
  438.      * @throws ERROR_UTIL_ERROR_METHOD_DOESNT_EXIST if the callback is an
  439.      *         array, and the method is not a method of the class
  440.      * @access private
  441.      */
  442.     function _validCallback($callback)
  443.     {
  444.         static $init = false;
  445.         if (!$init) {
  446.             $init = true;
  447.             Error_Raise::setErrorMsgGenerator('Error_Util',
  448.                 array('Error_Util', 'genErrorMessage'));
  449.         }
  450.         if (is_string($callback)) {
  451.             if (!function_exists($callback)) {
  452.                 return Error_Raise::exception('Error_Util',
  453.                     ERROR_UTIL_ERROR_FUNCTION_DOESNT_EXIST,
  454.                     array('function' => $callback));
  455.             }
  456.             $a = get_defined_functions();
  457.             if (in_array($callback, $a['internal'])) {
  458.                 return Error_Raise::exception('Error_Util',
  459.                     ERROR_UTIL_ERROR_INTERNAL_FUNCTION,
  460.                     array('function' => $callback));
  461.             }
  462.             return true;
  463.         }
  464.         if (is_array($callback)) {
  465.             if (!isset($callback[0]) || !isset($callback[1])) {
  466.                 return Error_Raise::exception('Error_Util',
  467.                     ERROR_UTIL_ERROR_INVALID_INPUT,
  468.                     array('expected' => array(0, 1),
  469.                           'was' => array_keys($callback),
  470.                           'var' => 'array_keys($callback)',
  471.                           'paramnum' => 1));
  472.             }
  473.             if (is_string($callback[0])) {
  474.                 if (!is_string($callback[1])) {
  475.                     return Error_Raise::exception('Error_Util',
  476.                         ERROR_UTIL_ERROR_INVALID_INPUT,
  477.                         array('expected' => 'string',
  478.                               'was' => gettype($callback[1]),
  479.                               'var' => '$callback[1]',
  480.                               'paramnum' => 1));
  481.                 }
  482.                 if (!class_exists($callback[0])) {
  483.                     return Error_Raise::exception('Error_Util',
  484.                         ERROR_UTIL_ERROR_CLASS_DOESNT_EXIST,
  485.                         array('class' => $callback[0]));
  486.                 }
  487.                 if (!in_array(strtolower($callback[1]),
  488.                       get_class_methods($callback[0]))) {
  489.                     return Error_Raise::exception('Error_Util',
  490.                         ERROR_UTIL_ERROR_METHOD_DOESNT_EXIST,
  491.                         array('method' => $callback[1],
  492.                               'class' => $callback[0]));
  493.                 }
  494.                 return true;
  495.             } elseif (is_object($callback[0])) {
  496.                 if (!method_exists($callback[0], $callback[1])) {
  497.                     return Error_Raise::exception('Error_Util',
  498.                         ERROR_UTIL_ERROR_METHOD_DOESNT_EXIST,
  499.                         array('method' => $callback[1],
  500.                               'class' => get_class($callback[0])));
  501.                 }
  502.                 return true;
  503.             } else {
  504.                 return Error_Raise::exception('Error_Util',
  505.                     ERROR_UTIL_ERROR_INVALID_INPUT,
  506.                     array('expected' => array('array', 'string'),
  507.                           'was' => gettype($callback[0]),
  508.                           'var' => '$callback[0]',
  509.                           'paramnum' => 1));
  510.             }
  511.             // is a callback method
  512.             return true;
  513.         }
  514.         return Error_Raise::exception('error_util',
  515.                 ERROR_UTIL_ERROR_INVALID_INPUT,
  516.                 array('expected' => array('array', 'string'),
  517.                       'was' => gettype($callback),
  518.                       'var' => '$callback',
  519.                       'paramnum' => 1));;
  520.     }
  521.     
  522.     /**
  523.      * Get an error message for Error_Util errors
  524.      * @return string error message from error code
  525.      * @param integer
  526.      * @param array
  527.      * @static
  528.      */
  529.     function genErrorMessage($code, $args = array(), $state = ERROR_RAISE_TEXT)
  530.     {
  531.         if (!is_array($args)) {
  532.             return 'Error: $args passed to Error_Util::genErrorMessage is '.
  533.                 'not an array but a '.gettype($args);
  534.         }
  535.         $messages =
  536.         array(
  537.             ERROR_UTIL_ERROR_CLASS_DOESNT_EXIST =>
  538.                 'class "%cl%" does not exist',
  539.             ERROR_UTIL_ERROR_INVALID_INPUT =>
  540.                 'invalid input, parameter #%paramnum% '
  541.                     . '"%var%" was expecting '
  542.                     . '"%expected%", instead got "%was%"',
  543.             ERROR_UTIL_ERROR_METHOD_DOESNT_EXIST =>
  544.                 'method "%method%" doesn\'t exist in class "%class%"',
  545.             ERROR_UTIL_ERROR_FUNCTION_DOESNT_EXIST =>
  546.                 'function "%function%" doesn\'t exist',
  547.             ERROR_UTIL_ERROR_INTERNAL_FUNCTION =>
  548.                 'function "%function%" is an internal function, and '
  549.                     . 'cannot be used as a callback',
  550.              );
  551.         if (is_int($code) && isset($messages[$code])) {
  552.             $msg = $messages[$code];
  553.             return Error_Raise::sprintfErrorMessageWithState($msg,
  554.                 $args, $state);
  555.         } else {
  556.             return 'Error: code ' . $code . ' not found';
  557.         }
  558.     }
  559. }
  560. ?>