Logo Search packages:      
Sourcecode: cakephp1.2 version File versions  Download package

debugger.php

<?php
/* SVN FILE: $Id: debugger.php 5875 2007-10-23 00:25:51Z phpnut $ */
/**
 * Framework debugging and PHP error-handling class
 *
 * Provides enhanced logging, stack traces, and rendering debug views
 *
 * PHP versions 4 and 5
 *
 * CakePHP(tm) :  Rapid Development Framework <http://www.cakephp.org/>
 * Copyright 2005-2007, Cake Software Foundation, Inc.
 *                                              1785 E. Sahara Avenue, Suite 490-204
 *                                              Las Vegas, Nevada 89104
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @filesource
 * @copyright           Copyright 2005-2007, Cake Software Foundation, Inc.
 * @link                      http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
 * @package             cake
 * @subpackage          cake.cake.libs
 * @since               CakePHP(tm) v 1.2.4560
 * @version             $Revision: 5875 $
 * @modifiedby          $LastChangedBy: phpnut $
 * @lastmodified  $Date: 2007-10-22 19:25:51 -0500 (Mon, 22 Oct 2007) $
 * @license             http://www.opensource.org/licenses/mit-license.php The MIT License
 */
/**
 * Included libraries.
 *
 */
      if (!class_exists('Object')) {
             uses('object');
      }
      uses('cake_log');
/**
 * Provide custom logging and error handling.
 *
 * Debugger overrides PHP's default error handling to provide stack traces and enhanced logging
 *
 * @package       cake
 * @subpackage    cake.cake.libs
 */
00045 class Debugger extends Object {

/**
 * Holds a reference to errors generated by the application
 *
 * @var array
 * @access public
 */
      var $errors = array();
/**
 * Contains the base URL for error code documentation
 *
 * @var string
 * @access public
 */
      var $helpPath = null;
/**
 * Constructor
 *
 */
00065       function __construct() {
            $docRef = ini_get('docref_root');
            if (empty($docRef)) {
                  ini_set('docref_root', 'http://php.net/');
            }
            if (!defined('E_RECOVERABLE_ERROR')) {
                  define('E_RECOVERABLE_ERROR', 4096);
            }
      }
/**
 * Gets a reference to the Debugger object instance
 *
 * @return object
 * @access public
 */
00080       function &getInstance() {
            static $instance = array();

            if (!isset($instance[0]) || !$instance[0]) {
                  $instance[0] =& new Debugger();
                  if (Configure::read() > 0) {
                        Configure::version(); // Make sure the core config is loaded
                        $instance[0]->helpPath = Configure::read('Cake.Debugger.HelpPath');
                  }
            }
            return $instance[0];
      }
/**
 * Overrides PHP's default error handling
 *
 * @param integer $code Code of error
 * @param string $description Error description
 * @param string $file File on which error occurred
 * @param integer $line Line that triggered the error
 * @param array $context Context
 * @return boolean true if error was handled
 * @access public
 */
00103       function handleError($code, $description, $file = null, $line = null, $context = null) {
            if (error_reporting() == 0 || $code === 2048) {
                  return;
            }

            $_this = Debugger::getInstance();

            if (empty($file)) {
                  $file = '[internal]';
            }
            if (empty($line)) {
                  $line = '??';
            }
            $file = $_this->trimPath($file);

            $info = compact('code', 'description', 'file', 'line');
            if (!in_array($info, $_this->errors)) {
                  $_this->errors[] = $info;
            } else {
                  return;
            }

            $level = LOG_DEBUG;
            switch ($code) {
                  case E_PARSE:
                  case E_ERROR:
                  case E_CORE_ERROR:
                  case E_COMPILE_ERROR:
                        $error = 'Fatal Error';
                        $level = LOG_ERROR;
                  break;
                  case E_WARNING:
                  case E_USER_WARNING:
                  case E_COMPILE_WARNING:
                  case E_RECOVERABLE_ERROR:
                        $error = 'Warning';
                        $level = LOG_WARNING;
                  break;
                  case E_NOTICE:
                        $error = 'Notice';
                        $level = LOG_NOTICE;
                  break;
                  default:
                        return false;
                  break;
            }

            $helpCode = null;
            if (!empty($_this->helpPath) && preg_match('/.*\[([0-9]+)\]$/', $description, $codes)) {
                  if (isset($codes[1])) {
                        $helpCode = $codes[1];
                        $description = trim(preg_replace('/\[[0-9]+\]$/', '', $description));
                  }
            }

            $link = "document.getElementById(\"CakeStackTrace" . count($_this->errors) . "\").style.display = (document.getElementById(\"CakeStackTrace" . count($_this->errors) . "\").style.display == \"none\" ? \"\" : \"none\")";
            $out = "<a href='javascript:void(0);' onclick='{$link}'><b>{$error}</b> ({$code})</a>: {$description} [<b>{$file}</b>, line <b>{$line}</b>]";

            if (Configure::read() > 0) {
                  debug($out, false, false);
                  e('<div id="CakeStackTrace' . count($_this->errors) . '" class="cake-stack-trace" style="display: none;">');
                  if (!empty($context)) {
                        $link = "document.getElementById(\"CakeErrorContext" . count($_this->errors) . "\").style.display = (document.getElementById(\"CakeErrorContext" . count($_this->errors) . "\").style.display == \"none\" ? \"\" : \"none\")";
                        e("<a href='javascript:void(0);' onclick='{$link}'>Context</a> | ");
                        $link = "document.getElementById(\"CakeErrorCode" . count($_this->errors) . "\").style.display = (document.getElementById(\"CakeErrorCode" . count($_this->errors) . "\").style.display == \"none\" ? \"\" : \"none\")";
                        e("<a href='javascript:void(0);' onclick='{$link}'>Code</a>");

                        if (!empty($helpCode)) {
                              e(" | <a href='{$_this->helpPath}{$helpCode}' target='blank'>Help</a>");
                        }

                        e("<pre id=\"CakeErrorContext" . count($_this->errors) . "\" class=\"cake-context\" style=\"display: none;\">");
                        foreach ($context as $var => $value) {
                              e("\${$var}\t=\t" . $_this->exportVar($value, 1) . "\n");
                        }
                        e("</pre>");
                  }
            }

            $files = $_this->trace(array('start' => 1, 'format' => 'points'));
            $listing = Debugger::excerpt($files[0]['file'], $files[0]['line'] - 1, 2);

            if (Configure::read() > 0) {
                  e("<div id=\"CakeErrorCode" . count($_this->errors) . "\" class=\"cake-code-dump\" style=\"display: none;\">");
                  pr(implode("\n", $listing), false);
                  e('</div>');

                  pr($_this->trace(array('start' => 1)), false);
                  e('</div>');
            }

            if (Configure::read('log')) {
                  CakeLog::write($level, "{$error} ({$code}): {$description} in [{$file}, line {$line}]");
            }

            if ($error == 'Fatal Error') {
                  die();
            }
            return true;
      }
/**
 * Outputs a stack trace with the given options
 *
 * @param array $options Format for outputting stack trace
 * @return string Formatted stack trace
 * @access protected
 */
00210       function trace($options = array()) {
            $options = am(array(
                        'depth'           => 999,
                        'format'    => '',
                        'args'            => false,
                        'start'           => 0,
                        'scope'           => null,
                        'exclude'   => null
                  ),
                  $options
            );

            $backtrace = debug_backtrace();
            $back = array();

            for ($i = $options['start']; $i < count($backtrace) && $i < $options['depth']; $i++) {
                  $trace = am(
                        array(
                              'file' => '[internal]',
                              'line' => '??'
                        ),
                        $backtrace[$i]
                  );

                  if (isset($backtrace[$i + 1])) {
                        $next = am(
                              array(
                                    'line'            => '??',
                                    'file'            => '[internal]',
                                    'class'           => null,
                                    'function'  => '[main]'
                              ),
                              $backtrace[$i + 1]
                        );
                        $function = $next['function'];

                        if (!empty($next['class'])) {
                              $function = $next['class'] . '::' . $function . '(';
                              if ($options['args'] && isset($next['args'])) {
                                    $args = array();
                                    foreach ($next['args'] as $arg) {
                                          $args[] = Debugger::exportVar($arg);
                                    }
                                    $function .= join(', ', $args);
                              }
                              $function .= ')';
                        }
                  } else {
                        $function = '[main]';
                  }
                  if (in_array($function, array('call_user_func_array', 'trigger_error'))) {
                        continue;
                  }
                  if ($options['format'] == 'points' && $trace['file'] != '[internal]') {
                        $back[] = array('file' => $trace['file'], 'line' => $trace['line']);
                  } elseif (empty($options['format'])) {
                        $back[] = $function . ' - ' . Debugger::trimPath($trace['file']) . ', line ' . $trace['line'];
                  }
            }

            if ($options['format'] == 'array' || $options['format'] == 'points') {
                  return $back;
            }
            return join("\n", $back);
      }
/**
 * Shortens file paths by replacing the application base path with 'APP', and the CakePHP core
 * path with 'CORE'
 *
 * @param string $path Path to shorten
 * @return string Normalized path
 * @access protected
 */
00283       function trimPath($path) {
            if (!defined('CAKE_CORE_INCLUDE_PATH') || !defined('APP')) {
                  return $path;
            }

            if (strpos($path, CAKE_CORE_INCLUDE_PATH) === 0) {
                  $path = r(CAKE_CORE_INCLUDE_PATH, 'CORE', $path);
            } elseif (strpos($path, APP) === 0) {
                  $path = r(APP, 'APP' . DS, $path);
            } elseif (strpos($path, ROOT) === 0) {
                  $path = r(ROOT, 'ROOT' . DS, $path);
            }
            return $path;
      }
/**
 * Grabs an excerpt from a file and highlights a given line of code
 *
 * @param string $file Absolute path to a PHP file
 * @param integer $line Line number to highlight
 * @param integer $context Number of lines of context to extract above and below $line
 * @return array Set of lines highlighted
 * @access protected
 */
00306       function excerpt($file, $line, $context = 2) {
            $data = $lines = array();
            $data = @explode("\n", file_get_contents($file));

            if (empty($data) || !isset($data[$line])) {
                  return;
            }
            for ($i = $line - ($context + 1); $i < $line + $context; $i++) {
                  if (!isset($data[$i])) {
                        continue;
                  }
                  if ($i == $line) {
                        $lines[] = '<span class="code-highlight">' . highlight_string($data[$i], true) . '</span>';
                  } else {
                        $lines[] = highlight_string($data[$i], true);
                  }
            }
            return $lines;
      }
/**
 * Converts a variable to a string for debug output
 *
 * @param string $var Variable to convert
 * @return string Variable as a formatted string
 * @access protected
 */
00332       function exportVar($var, $recursion = 0) {
            switch(low(gettype($var))) {
                  case 'boolean':
                        return ife($var, 'true', 'false');
                  break;
                  case 'integer':
                  case 'double':
                        return $var;
                  break;
                  case 'string':
                        return '"' . $var . '"';
                  break;
                  case 'object':
                        $var = get_object_vars($var);
                  case 'array':
                        $out = 'array(';
                        if ($recursion !== 0) {
                              $vars = array();
                              foreach ($var as $key => $val) {
                                    $vars[] = Debugger::exportVar($key) . ' => ' . Debugger::exportVar($val, $recursion - 1);
                              }
                              return $out . join(', ', $vars) . ')';
                        } else {
                              return 'array';
                        }
                  break;
                  case 'resource':
                        return low(gettype($var));
                  break;
                  case 'null':
                        return 'null';
                  break;
            }
      }

      function __object($var) {
            static $history = array();
            $serialized = serialize($var);
            array_push($history, $serialized);
            echo "\n";

            if(is_object($var)) {
                  $className = get_class($var);
                  $objectVars = get_object_vars($var);
                  foreach($objectVars as $key => $value) {
                        $value = ife((!is_object($value) && !is_array($value) && trim($value) == ""), "[empty string]", $value);
                        if(strpos($key, '_', 0) !== 0) {
                              echo "$className::$key = ";
                        }

                        if(is_object($value) || is_array($value)) {
                              $serialized = serialize($value);

                              if(in_array($serialized, $history, true)) {
                                    $value = ife(is_object($value), "*RECURSION* -> " . get_class($value), "*RECURSION*");
                              }
                        }

                        if(in_array(gettype($value), array('boolean', 'integer', 'double', 'string', 'array', 'resource', 'object', 'null'))) {
                              if(is_array($value)) {
                                    foreach($value as $name => $output) {
                                          if(is_numeric($name)) {
                                                echo "$output ";
                                          } else {
                                                echo "$name => $output ";
                                          }
                                    }
                                    echo "\n";
                              } else {
                                    echo Debugger::exportVar($value) . "\n";
                              }
                        } else {
                              echo $value . "\n";
                        }
                  }

                  $objectMethods = get_class_methods($className);
                  foreach($objectMethods as $key => $value) {
                        if(strpos($value, '_', 0) !== 0) {
                              echo "$className::$value() \n";
                        }
                  }
            }
            array_pop($history);
      }
/**
 * Verify that the application's salt has been changed from the default value
 *
 * @access public
 */
00422       function checkSessionKey() {
            if (Configure::read('Security.salt') == 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi') {
                  trigger_error(__('Please change the value of \'Security.salt\' in app/config/core.php to a salt value specific to your application', true), E_USER_NOTICE);
            }
      }
/**
 * Invokes the given debugger object as the current error handler, taking over control from the previous handler
 * in a stack-like hierarchy.
 *
 * @param object $debugger A reference to the Debugger object
 * @access public
 */
00434       function invoke(&$debugger) {
            set_error_handler(array(&$debugger, 'handleError'));
      }
}

if (!defined('DISABLE_DEFAULT_ERROR_HANDLING')) {
      Debugger::invoke(Debugger::getInstance());
}

?>

Generated by  Doxygen 1.6.0   Back to index