diff --git a/lib/SimpleSAML/Utilities.php b/lib/SimpleSAML/Utilities.php index aafa280bddfa7253b90be31f20d6e222f1b39c30..9cf6953a57392f88c0c3906e09b43c5125645da8 100644 --- a/lib/SimpleSAML/Utilities.php +++ b/lib/SimpleSAML/Utilities.php @@ -270,64 +270,70 @@ class SimpleSAML_Utilities { return $results; } - - - /* This function dumps a backtrace to the error log. + /** + * Build a backtrace. * - * The log is in the following form: - * BT: (0) <filename>:<line> (<current function>) - * BT: (1) <filename>:<line> (<previous fucntion>) - * ... - * BT: (N) <filename>:<line> (N/A) + * This function takes in an exception and optionally a start depth, and + * builds a backtrace from that depth. The backtrace is returned as an + * array of strings, where each string represents one level in the stack. * - * The log starts at the function which calls logBacktrace(). + * @param Exception $exception The exception. + * @param int $startDepth The depth we should print the backtrace from. + * @return array The backtrace as an array of strings. */ - public static function logBacktrace() { + public static function buildBacktrace(Exception $exception, $startDepth = 0) { - /* Get the backtrace. */ - $bt = debug_backtrace(); + assert('is_int($startDepth)'); - /* Variable to hold the stack depth. */ - $depth = 0; + $bt = array(); - /* PHP stores the backtrace as a list of function calls. - * This means that $bt[0]['function'] contains the function - * which is called, while $bt[0]['line'] contains the line - * the function was called from. - * - * To get the form of bactrace we want, we are going to use - * $bt[i+1] to get the function and $bt[i] to get the file - * name and the line number. - */ + /* Position in the top function on the stack. */ + $pos = $exception->getFile() . ':' . $exception->getLine(); - for($i = 0; $i < count($bt); $i++) { - $file = $bt[$i]['file']; - $line = $bt[$i]['line']; + foreach($exception->getTrace() as $t) { - /* We can't get a function name or class for the source - * of the first call. - */ - if($i == count($bt) - 1) { - $function = 'N/A'; - $class = NULL; - } else { - $function = $bt[$i+1]['function']; - $class = $bt[$i+1]['class']; + $function = $t['function']; + if(array_key_exists('class', $t)) { + $function = $t['class'] . '::' . $function; } - /* Attach the class name to the function name if - * we have a class name. - */ - if($class !== NULL) { - $function = $class . '::' . $function; + $bt[] = $pos . ' (' . $function . ')'; + + if(array_key_exists('file', $t)) { + $pos = $t['file'] . ':' . $t['line']; + } else { + $pos = '[builtin]'; } + } + $bt[] = $pos . ' (N/A)'; + + /* Remove $startDepth elements from the top of the backtrace. */ + $bt = array_slice($bt, $startDepth); + + return $bt; + } + + + /** + * This function dumps a backtrace to the error log. + * + * The log is in the following form: + * BT: (0) <filename>:<line> (<current function>) + * BT: (1) <filename>:<line> (<previous fucntion>) + * ... + * BT: (N) <filename>:<line> (N/A) + * + * The log starts at the function which calls logBacktrace(). + */ + public static function logBacktrace() { - error_log('BT: (' . $depth . ') ' . $file . ':' . - $line . ' (' . $function . ')'); + $e = new Exception(); - $depth++; + $bt = self::buildBackTrace($e, 1); + foreach($bt as $depth => $t) { + error_log('BT: (' . $depth . ') ' . $t); } }