Seagull PHP Cross Reference Content Management Systems

Source: /lib/SGL/ErrorHandler.php - 284 lines - 11959 bytes - Summary - Text - Print

   1  <?php
   2  /* Reminder: always indent with 4 spaces (no tabs). */
   3  // +---------------------------------------------------------------------------+
   4  // | Copyright (c) 2010, Demian Turner                                         |
   5  // | All rights reserved.                                                      |
   6  // |                                                                           |
   7  // | Redistribution and use in source and binary forms, with or without        |
   8  // | modification, are permitted provided that the following conditions        |
   9  // | are met:                                                                  |
  10  // |                                                                           |
  11  // | o Redistributions of source code must retain the above copyright          |
  12  // |   notice, this list of conditions and the following disclaimer.           |
  13  // | o Redistributions in binary form must reproduce the above copyright       |
  14  // |   notice, this list of conditions and the following disclaimer in the     |
  15  // |   documentation and/or other materials provided with the distribution.    |
  16  // | o The names of the authors may not be used to endorse or promote          |
  17  // |   products derived from this software without specific prior written      |
  18  // |   permission.                                                             |
  19  // |                                                                           |
  20  // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       |
  21  // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT         |
  22  // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR     |
  23  // | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT      |
  24  // | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,     |
  25  // | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT          |
  26  // | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     |
  27  // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY     |
  28  // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT       |
  29  // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE     |
  30  // | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.      |
  31  // |                                                                           |
  32  // +---------------------------------------------------------------------------+
  33  // | Seagull 1.0                                                               |
  34  // +---------------------------------------------------------------------------+
  35  // | ErrorHandler.php                                                          |
  36  // +---------------------------------------------------------------------------+
  37  // | Authors:   Peter James <petej@shaman.ca>                                  |
  38  // |            Demian Turner <demian@phpkitchen.com>                          |
  39  // +---------------------------------------------------------------------------+
  40  // $Id: ErrorHandler.php,v 1.8 2005/05/28 19:32:12 demian Exp $
  41  
  42  //  This class is based on Peter James' class of the same name, for more info
  43  //  see http://php.shaman.ca/
  44  
  45  /**
  46   * Global error handler class, modifies behaviour for PHP errors, not PEAR.
  47   *
  48   * @package SGL
  49   * @author  Demian Turner <demian@phpkitchen.com>
  50   * @author  Peter James
  51   * @version $Revision: 1.8 $
  52   */
  53  class SGL_ErrorHandler
  54  {
  55      var $errorType = array();
  56      var $sourceContextOptions = array();
  57  
  58      /**
  59       * Constructor.
  60       *
  61       * @access  public
  62       * @return  void
  63       */
  64      function __construct()
  65      {
  66          //  first dimension elements are PHP error types
  67          //  2nd dimension elements are roughly PEAR Log's equivalents
  68  
  69          //  nb: comment out Notice for equivalent of
  70          //  error_reporting(E_ALL ^ E_NOTICE);
  71          $this->errorType = array (
  72             1   =>  array('Error', 3),
  73             2   =>  array('Warning', 4),
  74             4   =>  array('Parsing Error', 3),
  75             8   =>  array('Notice', 5),
  76             16  =>  array('Core Error', 3),
  77             32  =>  array('Core Warning', 4),
  78             64  =>  array('Compile Error', 3),
  79             128 =>  array('Compile Warning', 4),
  80             256 =>  array('User Error', 3),
  81             512 =>  array('User Warning', 4),
  82             1024=>  array('User Notice', 5),
  83             2047=>  array('All', 7)
  84              );
  85          $this->sourceContextOptions = array('lines' => 5);
  86      }
  87  
  88      /**
  89       * BC hack to assign custom error handler in a method.
  90       *
  91       * @access  public
  92       * @return  void
  93       */
  94      function startHandler()
  95      {
  96          $GLOBALS['_SGL']['ERROR_HANDLER_OBJECT'] =  & $this;
  97          $GLOBALS['_SGL']['ERROR_HANDLER_METHOD'] =  'errHandler';
  98  
  99          //  inner function to handle redirection to a class method
 100          function eh($errNo, $errStr, $file, $line, $context)
 101          {
 102              call_user_func(array(
 103                 &$GLOBALS['_SGL']['ERROR_HANDLER_OBJECT'],
 104                  $GLOBALS['_SGL']['ERROR_HANDLER_METHOD']),
 105                  $errNo, $errStr, $file, $line, $context
 106              );
 107          }
 108          //  start handling errors
 109          set_error_handler('eh');
 110      }
 111  
 112      /**
 113       * Enhances PHP's default error handling.
 114       *
 115       *  o overrides notices in certain cases
 116       *  o obeys @muffled errors,
 117       *  o error logged to selected target
 118       *  o context info presented for developer
 119       *  o error data emailed to admin if threshold passed
 120       *
 121       * @access  public
 122       * @param   int     $errNo      PHP's error number
 123       * @param   string  $errStr     PHP's error message
 124       * @param   string  $file       filename where error occurred
 125       * @param   int     $line       line number where error occurred
 126       * @param   string  $context    contextual info
 127       * @return  void
 128       */
 129      function errHandler($errNo, $errStr, $file, $line, $context)
 130      {
 131          //  if an @ error suppression operator has been detected (0) return null
 132          if (error_reporting() == 0) {
 133              return null;
 134          }
 135          //  or if notices are temporarily being suppressed, return null
 136          if ($GLOBALS['_SGL']['ERROR_OVERRIDE'] == true) {
 137              if (error_reporting() == E_ALL ^ E_NOTICE) {
 138                  return null;
 139              }
 140          }
 141          if (in_array($errNo, array_keys($this->errorType))) {
 142              $c = SGL_Config::singleton();
 143              $conf = $c->getAll();
 144              //  final param is 2nd dimension element from errorType array,
 145              //  representing PEAR error codes mapped to PHP's
 146  
 147              //  also, error obj is stored in $GLOBALS['_SGL']['ERRORS']
 148              //  in the logMessage method
 149              SGL::logMessage($errStr, $file, $line, $this->errorType[$errNo][1]);
 150  
 151              //  if a debug sesssion has been started, or the site in in
 152              //  development mode, send error info to screen
 153              if (!$conf['debug']['production'] || SGL_Session::get('adminMode')) {
 154                  $source = $this->_getSourceContext($file, $line);
 155                  //  generate screen debug html
 156                  //  type is 1st dimension element from $errorType array, ie,
 157                  //  PHP error code
 158                  $output = <<<EOF
 159  <hr />
 160  <div id="errorWrapper" class="errorContent">
 161          <strong>MESSAGE</strong>: $errStr<br />
 162          <strong>TYPE:</strong> {$this->errorType[$errNo][0]}<br />
 163          <strong>FILE:</strong> $file<br />
 164          <strong>LINE:</strong> $line<br />
 165          <strong>DEBUG INFO:</strong>
 166          <p>$source</p>
 167  </div>
 168  <hr />
 169  EOF;
 170                  if (SGL::runningFromCLI()) {
 171                      $output = <<<EOL
 172  MESSAGE: $errStr
 173  TYPE: {$this->errorType[$errNo][0]}
 174  FILE: $file
 175  LINE: $line
 176  
 177   --
 178  EOL;
 179                  }
 180                  if (!empty($conf['log']['showErrors']) && $conf['log']['showErrors'] == true) {
 181                      echo $output;
 182                  }
 183  
 184              } else {
 185                  //  we're in production mode, suppress any errors from being displayed
 186                  @ini_set('display_errors', 0);
 187              }
 188              //  email the error to admin if threshold reached
 189              if ($this->errorType[$errNo][1] <= SGL_EMAIL_ADMIN_THRESHOLD) {
 190  
 191                  //  get extra info
 192                  $dbh =  SGL_DB::singleton();
 193  
 194                  $aExtraInfo['callingURL'] = $_SERVER['SCRIPT_NAME'];
 195                  $aExtraInfo['lastSQL'] = isset($dbh->last_query) ?
 196                      $dbh->last_query : null;
 197                  $aExtraInfo['userID'] = SGL_Session::get('uid');
 198                  $aExtraInfo['clientData']['HTTP_REFERER'] = isset($_SERVER['HTTP_REFERER'])
 199                      ? $_SERVER['HTTP_REFERER']
 200                      : null;
 201                  $aExtraInfo['clientData']['HTTP_USER_AGENT'] = isset($_SERVER['HTTP_USER_AGENT'])
 202                      ? $_SERVER['HTTP_USER_AGENT']
 203                      : null;
 204                  $aExtraInfo['clientData']['REMOTE_ADDR'] = isset($_SERVER['REMOTE_ADDR'])
 205                      ? $_SERVER['REMOTE_ADDR']
 206                      : null;
 207                  $aExtraInfo['clientData']['SERVER_PORT'] = isset($_SERVER['SERVER_PORT'])
 208                      ? $_SERVER['SERVER_PORT']
 209                      : null;
 210  
 211                  //  store formatted output
 212                  $info = print_r($aExtraInfo, true);
 213  
 214                  //  rebuild error output w/out html
 215                  $crlf = SGL_String::getCrlf();
 216                  $output = $errStr . $crlf .
 217                      'type: ' . $this->errorType[$errNo][0] . $crlf .
 218                      'file: ' . $file . $crlf .
 219                      'line: ' . $line . $crlf . $crlf;
 220                  $message = $output . $info;
 221                  @mail($conf['email']['admin'], 'ERROR OUTPUT FROM ' .
 222                      $conf['site']['name'], $message);
 223              }
 224          }
 225      }
 226  
 227      /**
 228       * Provides enhanced error info for developer.
 229       *
 230       * Gives 10 lines before and after error occurred, hightlight erroroneous
 231       * line in red.
 232       *
 233       * @access  private
 234       * @param   string  $file       filename where error occurred
 235       * @param   int     $line       line number where error occurred
 236       * @param   string  $context    contextual info
 237       * @return  string  contextual error info
 238       */
 239      function _getSourceContext($file, $line)
 240      {
 241          $sourceContext = null;
 242  
 243          //  check that file exists
 244          if (!is_file($file)) {
 245              $sourceContext = "Context cannot be shown - ($file) does not exist";
 246  
 247          //  check if line number is valid
 248          } elseif ((!is_int($line)) || ($line <= 0)) {
 249              $sourceContext = "Context cannot be shown - ($line) is an invalid line number";
 250          } else {
 251              $lines = file($file);
 252  
 253              //  get the source ## core dump in windows, scrap colour highlighting :-(
 254              //  $source = highlight_file($file, true);
 255              //  $lines = split("<br />", $source);
 256              //  get line numbers
 257              $start = $line - $this->sourceContextOptions['lines'] - 1;
 258              $finish = $line + $this->sourceContextOptions['lines'];
 259  
 260              //  get lines
 261              if ($start < 0) {
 262                  $start = 0;
 263              }
 264  
 265              if ($start >= count($lines)) {
 266                  $start = count($lines) -1;
 267              }
 268  
 269              for ($i = $start; $i < $finish; $i++) {
 270                  //  highlight line in question
 271                  if ($i == ($line - 1)) {
 272                      $context_lines[] = '<div class="error"><strong>' . ($i + 1) .
 273                          "\t" . strip_tags($lines[$line -1]) . '</strong></div>';
 274                  } else {
 275                      $context_lines[] = '<strong>' . ($i + 1) .
 276                          "</strong>\t" . @$lines[$i];
 277                  }
 278              }
 279              $sourceContext = trim(join("<br />\n", $context_lines)) . "<br />\n";
 280          }
 281          return $sourceContext;
 282      }
 283  }
 284  ?>

title

Description

title

Description

title

Description

title

title

Body