/** * Prints out the thrown exception in a more readable manner for a person using * a web browser. * * @param SpoonException $exception */ function exceptionHandler($exception) { // fetch trace stack $trace = $exception->getTrace(); // specific name $name = method_exists($exception, 'getName') ? $exception->getName() : get_class($exception); // spoon type exception if (method_exists($exception, 'getName') && strtolower(substr($exception->getName(), 0, 5)) == 'spoon' && $exception->getCode() != 0) { $documentation = '» <a href="http://www.spoon-library.com/exceptions/detail/' . $exception->getCode() . '">view documentation</a>'; } // request uri? if (!isset($_SERVER['HTTP_HOST'])) { $_SERVER['HTTP_HOST'] = ''; } if (!isset($_SERVER['REQUEST_URI'])) { $_SERVER['REQUEST_URI'] = ''; } if (!isset($_SERVER['REQUEST_METHOD'])) { $_SERVER['REQUEST_METHOD'] = ''; } // user agent $userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '<i>(Unknown)</i>'; // generate output $output = ' <html> <head> <title>' . $name . '</title> </head> <body style="background-color: #F2F2F2; color: #0000000, font-family: Verdana, Tahoma, Arial; font-size 10px; margin: 0; padding: 0;"> <table width="100%"> <tr> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;"> </td> <td style="width: 550px"> <table width="550px;"> <tr> <td style="background-color: #EEEEEE; border: 1px solid #B2B2B2;"> <h1 style="font-size: 12px; margin: 5px 5px 12px 5px; padding: 0 0 5px 0; color: #000000; font-family: Verdana, Tahoma, Arial; border-bottom: 1px solid #999999;">' . $name . ' » Main</h1> <table width="550px"> <tr> <th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Message</th> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . $exception->getMessage() . '</td> </tr> <tr> <th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">File</th> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . dimCommonPathPrefix($exception->getFile()) . '</td> </tr> <tr> <th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Line</th> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . $exception->getLine() . '</td> </tr> <tr> <th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Date</th> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . date('r') . '</td> </tr> <tr> <th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">URL</th> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . "\n"; // request URL $output .= ' <a href="http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . '">http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . '</a>' . "\n"; $output .= ' </td> </tr> <tr> <th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Referring URL</th> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . "\n"; // referring URL if (isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER'] != '') { $output .= ' <a href="' . $_SERVER['HTTP_REFERER'] . '">' . $_SERVER['HTTP_REFERER'] . '</a>' . "\n"; } else { $output .= ' <i>(Unknown)</i>' . "\n"; } $output .= ' </td> </tr> <tr> <th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Request Method</th> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . $_SERVER['REQUEST_METHOD'] . '</td> </tr> <tr> <th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">User-agent</th> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . $userAgent . '</td> </tr>'; // no documentation ? if (isset($documentation)) { $output .= ' <tr> <th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Documentation</th> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . $documentation . '</td> </tr>'; } // we know about the last error if (error_get_last() !== null) { // define message $error = error_get_last(); // show output $output .= ' <tr> <th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">PHP error</th> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . $error['message'] . '</td> </tr>'; } $output .= ' </table> </td> </tr> <tr> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;"> </td> </tr> <!-- stack --> <tr> <td style="background-color: #EEEEEE; border: 1px solid #B2B2B2;"> <h1 style="font-size: 12px; margin: 5px 5px 12px 5px; padding: 0 0 5px 0; color: #000000; font-family: Verdana, Tahoma, Arial; border-bottom: 1px solid #999999;">' . $name . ' » Trace</h1> <table width="550px;">' . "\n"; // trace has items if (count($exception->getTrace()) != 0) { // fetch entire stack $entireTraceStack = $exception->getTrace(); // loop elements foreach ($entireTraceStack as $traceStack) { // open defintion list $output .= ' <tr> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;"> <table width="550px;" style="border-top: 1px dotted; padding-top: 1ex;"> <tr> <th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">File</th> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . (isset($traceStack['file']) ? dimCommonPathPrefix($traceStack['file']) : '<i>(Unknown)</i>') . ' </td> </tr> <tr> <th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Line</th> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . (isset($traceStack['line']) ? $traceStack['line'] : '<i>(Unknown)</i>') . ' </td> </tr>'; // class & function if (isset($traceStack['class'])) { $docUrl = 'http://www.google.com/search?btnI=&ie=utf-8&sourceid=navclient&q=' . urlencode(sprintf('site:php.net/manual OR site:www.spoon-library.com/docs class "%s"', $traceStack['class'])); $link = sprintf('<a href="%s">%s</a>', htmlspecialchars($docUrl), htmlspecialchars($traceStack['class'])); $output .= ' <tr> <th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Class</th> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . $link . '</td> </tr>'; } if (isset($traceStack['function'])) { $docUrl = isset($traceStack['class']) ? 'http://www.google.com/search?btnI=&ie=utf-8&sourceid=navclient&q=' . urlencode(sprintf('site:php.net/manual OR site:www.spoon-library.com/docs "%s::%s"', $traceStack['class'], $traceStack['function'])) : 'http://www.google.com/search?btnI=&ie=utf-8&sourceid=navclient&q=' . urlencode(sprintf('site:php.net/manual OR site:www.spoon-library.com/docs "%s"', $traceStack['function'])); $link = sprintf('<a href="%s">%s</a>', htmlspecialchars($docUrl), htmlspecialchars($traceStack['function'])); $output .= ' <tr> <th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Function</th> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">' . $link . '</td> </tr>'; } // function arguments if (isset($traceStack['args']) && count($traceStack['args']) != 0) { // argument title $output .= ' <tr> <th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 0 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">Argument(s)</th> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;"> <pre style="font-family: Courier; margin-bottom: 10px;">' . exceptionHandlerDumper($traceStack['args']) . '</pre> </td> </tr>'; } // close defintion list $output .= ' </table> </td> </tr>'; } } else { $output .= ' <tr> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">No trace available.</td> </tr>'; } // output the superglobal variables, if any $hasVars = false; foreach (array('GET', 'POST', 'COOKIE', 'FILES') as $superGlobal) { $hasVars |= count($GLOBALS['_' . $superGlobal]); } if ($hasVars) { $output .= ' </table> </td> <tr> <tr> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;"> </td> </tr> <!-- variables --> <tr> <td style="background-color: #EEEEEE; border: 1px solid #B2B2B2;"> <h1 style="font-size: 12px; margin: 5px 5px 12px 5px; padding: 0 0 5px 0; color: #000000; font-family: Verdana, Tahoma, Arial; border-bottom: 1px solid #999999;">' . $name . ' » Variables</h1> <table width="550px;">' . "\n"; foreach (array('GET', 'POST', 'COOKIE', 'FILES') as $superGlobal) { if (!empty($GLOBALS['_' . $superGlobal])) { $output .= ' <tr> <th width="110px" style="vertical-align: top; text-align: left; font-weight: 700; padding: 0 10px 0 10px; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;">$_' . $superGlobal . '</th> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;"> <pre style="font-family: Courier; margin-bottom: 10px;">' . exceptionHandlerDumper($GLOBALS['_' . $superGlobal]) . '</pre> </td> </tr>' . "\n"; } } } // continue output generation $output .= ' </table> </td> </tr> </table> </td> <td style="vertical-align: top; font-family: Verdana, Tahoma, Arial; font-size: 10px; color: #000000;"> </td> </tr> </table> </body> </html> '; // obfuscate if (method_exists($exception, 'getObfuscate') && count($exception->getObfuscate()) != 0) { $output = str_replace($exception->getObfuscate(), '***', $output); } // custom callback? if (Spoon::getExceptionCallback() != '') { // function if (!strpos(Spoon::getExceptionCallback(), '::')) { // function actually has been defined if (function_exists(Spoon::getExceptionCallback())) { call_user_func_array(Spoon::getExceptionCallback(), array($exception, $output)); } else { exit('The exception callback function (' . Spoon::getExceptionCallback() . ') could not be found.'); } } else { // method $method = explode('::', Spoon::getExceptionCallback()); // 2 parameters and exists if (count($method) == 2 && is_callable(array($method[0], $method[1]))) { call_user_func_array(array($method[0], $method[1]), array($exception, $output)); } else { exit('The exception callback function (' . Spoon::getExceptionCallback() . ') cound not be found.'); } } } else { // on CLI we have no use for 2000 lines long report, show short info if (Spoon::inCli()) { echo $name . "\n"; echo 'Message: ' . $exception->getMessage() . "\n"; echo 'File: ' . $exception->getFile() . "\n"; echo 'Line: ' . $exception->getLine() . "\n"; } elseif (Spoon::getDebug()) { echo $output; } else { echo Spoon::getDebugMessage(); } } // mail it? if (Spoon::getDebugEmail() != '') { // e-mail headers $headers = "MIME-Version: 1.0\n"; $headers .= "Content-type: text/html; charset=iso-8859-15\n"; $headers .= "X-Priority: 3\n"; $headers .= "X-MSMail-Priority: Normal\n"; $headers .= "X-Mailer: SpoonLibrary Webmail\n"; $headers .= "From: Spoon Library <*****@*****.**>\n"; // send email @mail(Spoon::getDebugEmail(), 'Exception Occured', $output, $headers); } // stop script execution exit; }