00001 <?php
00002 
00003 
00011 
00012 
00013 
00014 
00015 
00016 set_error_handler('_drupal_error_handler');
00017 set_exception_handler('_drupal_exception_handler');
00018 
00033 function _drupal_error_handler($error_level, $message, $filename, $line, $context) {
00034   if ($error_level & error_reporting()) {
00035     
00036     $types = array(
00037       E_ERROR => 'Error',
00038       E_WARNING => 'Warning',
00039       E_PARSE => 'Parse error',
00040       E_NOTICE => 'Notice',
00041       E_CORE_ERROR => 'Core error',
00042       E_CORE_WARNING => 'Core warning',
00043       E_COMPILE_ERROR => 'Compile error',
00044       E_COMPILE_WARNING => 'Compile warning',
00045       E_USER_ERROR => 'User error',
00046       E_USER_WARNING => 'User warning',
00047       E_USER_NOTICE => 'User notice',
00048       E_STRICT => 'Strict warning',
00049       E_RECOVERABLE_ERROR => 'Recoverable fatal error'
00050     );
00051     $backtrace = debug_backtrace();
00052 
00053     $caller = _drupal_get_last_caller(debug_backtrace());
00054 
00055     
00056     _drupal_log_error(array(
00057       '%type' => isset($types[$error_level]) ? $types[$error_level] : 'Unknown error',
00058       '%message' => $message,
00059       '%function' => $caller['function'],
00060       '%file' => $caller['file'],
00061       '%line' => $caller['line'],
00062     ), $error_level == E_RECOVERABLE_ERROR);
00063   }
00064 }
00065 
00076 function _drupal_exception_handler($exception) {
00077   
00078   _drupal_log_error(_drupal_decode_exception($exception), TRUE);
00079 }
00080 
00088 function _drupal_decode_exception($exception) {
00089   $backtrace = $exception->getTrace();
00090   
00091   array_unshift($backtrace, array('line' => $exception->getLine(), 'file' => $exception->getFile()));
00092 
00093   
00094   
00095   if ($exception instanceof PDOException) {
00096     
00097     
00098     
00099 
00100     $db_functions = array('db_query', '_db_query', 'pager_query', 'db_query_range', 'db_query_temporary', 'update_sql');
00101     while (!empty($backtrace[1]) && ($caller = $backtrace[1]) &&
00102          ((isset($caller['class']) && (strpos($caller['class'], 'Query') !== FALSE || strpos($caller['class'], 'Database') !== FALSE)) ||
00103          in_array($caller['function'], $db_functions))) {
00104       
00105       array_shift($backtrace);
00106     }
00107   }
00108   $caller = _drupal_get_last_caller($backtrace);
00109 
00110   return array(
00111     '%type' => get_class($exception),
00112     '%message' => $exception->getMessage(),
00113     '%function' => $caller['function'],
00114     '%file' => $caller['file'],
00115     '%line' => $caller['line'],
00116   );
00117 }
00118 
00127 function _drupal_log_error($error, $fatal = FALSE) {
00128   
00129   
00130   if ($fatal && (drupal_get_bootstrap_phase() != DRUPAL_BOOTSTRAP_FULL)) {
00131     unset($GLOBALS['theme']);
00132     if (!defined('MAINTENANCE_MODE')) {
00133       define('MAINTENANCE_MODE', 'error');
00134     }
00135     drupal_maintenance_theme();
00136   }
00137 
00138   
00139   
00140   if (preg_match("/^simpletest\d+/", $_SERVER['HTTP_USER_AGENT']) && !headers_sent() && (!defined('SIMPLETEST_COLLECT_ERRORS') || SIMPLETEST_COLLECT_ERRORS)) {
00141     static $number = 0;
00142     $assertion = array(
00143       $error['%message'],
00144       $error['%type'],
00145       array(
00146         'function' => $error['%function'],
00147         'file' => $error['%file'],
00148         'line' => $error['%line'],
00149       ),
00150     );
00151     header('X-Drupal-Assertion-' . $number . ': ' . rawurlencode(serialize($assertion)));
00152     $number++;
00153   }
00154 
00155   
00156   
00157   $error_level = variable_get('error_level', 2);
00158   if ($error_level == 2 || ($error_level == 1 && $error['%type'] != 'Notice') || (defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'update')) {
00159     drupal_set_message(t('%type: %message in %function (line %line of %file).', $error), 'error');
00160   }
00161 
00162   try {
00163     watchdog('php', '%type: %message in %function (line %line of %file).', $error, WATCHDOG_ERROR);
00164   }
00165   catch (Exception $e) {
00166     $new_error = _drupal_decode_exception($e);
00167     drupal_set_message(t('%type: %message in %function (line %line of %file).', $new_error), 'error');
00168   }
00169 
00170   if ($fatal) {
00171     drupal_set_header('503 Service unavailable');
00172     drupal_set_title(t('Error'));
00173     if (!defined('MAINTENANCE_MODE') && drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL) {
00174       
00175       $page = drupal_get_page(t('The website encountered an unexpected error. Please try again later.'));
00176       $page['#show_blocks'] = FALSE;
00177       print drupal_render_page($page);
00178     }
00179     else {
00180       print theme('maintenance_page', t('The website encountered an unexpected error. Please try again later.'), FALSE);
00181     }
00182     exit;
00183   }
00184 }
00185 
00194 function _drupal_get_last_caller($backtrace) {
00195   
00196   
00197   while ($backtrace && !isset($backtrace[0]['line'])) {
00198     array_shift($backtrace);
00199   }
00200 
00201   
00202   
00203   $call = $backtrace[0];
00204 
00205   
00206   if (isset($backtrace[1])) {
00207     if (isset($backtrace[1]['class'])) {
00208       $call['function'] = $backtrace[1]['class'] . $backtrace[1]['type'] . $backtrace[1]['function'] . '()';
00209     }
00210     else {
00211       $call['function'] = $backtrace[1]['function'] . '()';
00212     }
00213   }
00214   else {
00215     $call['function'] = 'main()';
00216   }
00217   return $call;
00218 }