| | 947 | |
| | 948 | class MuErrorHandler { |
| | 949 | |
| | 950 | private static $errorType = array ( |
| | 951 | E_ERROR => 'ERROR', |
| | 952 | E_WARNING => 'WARNING', |
| | 953 | E_PARSE => 'PARSING ERROR', |
| | 954 | E_NOTICE => 'NOTICE', |
| | 955 | E_CORE_ERROR => 'CORE ERROR', |
| | 956 | E_CORE_WARNING => 'CORE WARNING', |
| | 957 | E_COMPILE_ERROR => 'COMPILE ERROR', |
| | 958 | E_COMPILE_WARNING => 'COMPILE WARNING', |
| | 959 | E_USER_ERROR => 'USER ERROR', |
| | 960 | E_USER_WARNING => 'USER WARNING', |
| | 961 | E_USER_NOTICE => 'USER NOTICE', |
| | 962 | E_STRICT => 'STRICT NOTICE', |
| | 963 | E_RECOVERABLE_ERROR => 'RECOVERABLE ERROR' |
| | 964 | ); |
| | 965 | |
| | 966 | // error page html |
| | 967 | const BACKTRACE_HTML = ' |
| | 968 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> |
| | 969 | <html lang="en"> |
| | 970 | <head> |
| | 971 | <meta http-equiv="content-type" content="text/html; charset=utf-8" /> |
| | 972 | <meta name="robots" content="NONE,NOARCHIVE" /> |
| | 973 | <title>{{ error_type }}</title> |
| | 974 | <style type="text/css"> |
| | 975 | html * { padding:0; margin:0; } |
| | 976 | body * { padding:10px 20px; } |
| | 977 | body * * { padding:0; } |
| | 978 | body { font:small sans-serif; } |
| | 979 | body>div { border-bottom:1px solid #ddd; } |
| | 980 | h1 { font-weight:normal; } |
| | 981 | h2 { margin-bottom:.8em; } |
| | 982 | h2 span { font-size:80%; color:#666; font-weight:normal; } |
| | 983 | h3 { margin:1em 0 .5em 0; } |
| | 984 | h4 { margin:0 0 .5em 0; font-weight: normal; } |
| | 985 | table { border:1px solid #ccc; border-collapse: collapse; width:100%; background:white; } |
| | 986 | tbody td, tbody th { vertical-align:top; padding:2px 3px; } |
| | 987 | thead th { padding:1px 6px 1px 3px; background:#fefefe; text-align:left; font-weight:normal; font-size:11px; border:1px solid #ddd; } |
| | 988 | tbody th { width:12em; text-align:right; color:#666; padding-right:.5em; } |
| | 989 | table.vars { margin:5px 0 2px 40px; } |
| | 990 | table.vars td, table.req td { font-family:monospace; } |
| | 991 | table td.code { width:100%; } |
| | 992 | table td.code div { overflow:hidden; } |
| | 993 | table.source th { color:#666; } |
| | 994 | table.source td { font-family:monospace; white-space:pre; border-bottom:1px solid #eee; } |
| | 995 | ul.traceback { list-style-type:none; } |
| | 996 | ul.traceback li.frame { margin-bottom:1em; } |
| | 997 | div.context { margin: 10px 0; } |
| | 998 | div.context ol { padding-left:30px; margin:0 10px; list-style-position: inside; } |
| | 999 | div.context ol li { font-family:monospace; white-space:pre; color:#666; cursor:pointer; } |
| | 1000 | div.context ol.context-line li { color:black; background-color:#ccc; } |
| | 1001 | div.context ol.context-line li span { float: right; } |
| | 1002 | div.commands { margin-left: 40px; } |
| | 1003 | div.commands a { color:black; text-decoration:none; } |
| | 1004 | #summary { background: #ffc; } |
| | 1005 | #summary h2 { font-weight: normal; color: #666; } |
| | 1006 | #explanation { background:#eee; } |
| | 1007 | #template, #template-not-exist { background:#f6f6f6; } |
| | 1008 | #template-not-exist ul { margin: 0 0 0 20px; } |
| | 1009 | #traceback { background:#eee; } |
| | 1010 | #requestinfo { background:#f6f6f6; padding-left:120px; } |
| | 1011 | #summary table { border:none; background:transparent; } |
| | 1012 | #requestinfo h2, #requestinfo h3 { position:relative; margin-left:-100px; } |
| | 1013 | #requestinfo h3 { margin-bottom:-1em; } |
| | 1014 | .error { background: #ffc; } |
| | 1015 | .specific { color:#cc3300; font-weight:bold; } |
| | 1016 | </style> |
| | 1017 | <script type="text/javascript"> |
| | 1018 | //<!-- |
| | 1019 | function getElementsByClassName(oElm, strTagName, strClassName){ |
| | 1020 | // Written by Jonathan Snook, http://www.snook.ca/jon; Add-ons by Robert Nyman, http://www.robertnyman.com |
| | 1021 | var arrElements = (strTagName == "*" && document.all)? document.all : |
| | 1022 | oElm.getElementsByTagName(strTagName); |
| | 1023 | var arrReturnElements = new Array(); |
| | 1024 | strClassName = strClassName.replace(/\-/g, "\-"); |
| | 1025 | var oRegExp = new RegExp("(^|\s)" + strClassName + "(\s|$)"); |
| | 1026 | var oElement; |
| | 1027 | for(var i=0; i<arrElements.length; i++){ |
| | 1028 | oElement = arrElements[i]; |
| | 1029 | if(oRegExp.test(oElement.className)){ |
| | 1030 | arrReturnElements.push(oElement); |
| | 1031 | } |
| | 1032 | } |
| | 1033 | return (arrReturnElements) |
| | 1034 | } |
| | 1035 | function hideAll(elems) { |
| | 1036 | for (var e = 0; e < elems.length; e++) { |
| | 1037 | elems[e].style.display = \'none\'; |
| | 1038 | } |
| | 1039 | } |
| | 1040 | window.onload = function() { |
| | 1041 | hideAll(getElementsByClassName(document, \'table\', \'vars\')); |
| | 1042 | hideAll(getElementsByClassName(document, \'ol\', \'pre-context\')); |
| | 1043 | hideAll(getElementsByClassName(document, \'ol\', \'post-context\')); |
| | 1044 | hideAll(getElementsByClassName(document, \'div\', \'pastebin\')); |
| | 1045 | } |
| | 1046 | function toggle() { |
| | 1047 | for (var i = 0; i < arguments.length; i++) { |
| | 1048 | var e = document.getElementById(arguments[i]); |
| | 1049 | if (e) { |
| | 1050 | e.style.display = e.style.display == \'none\' ? \'block\' : \'none\'; |
| | 1051 | } |
| | 1052 | } |
| | 1053 | return false; |
| | 1054 | } |
| | 1055 | function varToggle(link, id) { |
| | 1056 | toggle(\'v\' + id); |
| | 1057 | var s = link.getElementsByTagName(\'span\')[0]; |
| | 1058 | var uarr = String.fromCharCode(0x25b6); |
| | 1059 | var darr = String.fromCharCode(0x25bc); |
| | 1060 | s.innerHTML = s.innerHTML == uarr ? darr : uarr; |
| | 1061 | return false; |
| | 1062 | } |
| | 1063 | function switchPastebinFriendly(link) { |
| | 1064 | s1 = "Switch to copy-and-paste view"; |
| | 1065 | s2 = "Switch back to interactive view"; |
| | 1066 | link.innerHTML = link.innerHTML == s1 ? s2 : s1; |
| | 1067 | toggle(\'browserTraceback\', \'pastebinTraceback\'); |
| | 1068 | return false; |
| | 1069 | } |
| | 1070 | //--> |
| | 1071 | </script> |
| | 1072 | </head> |
| | 1073 | <body> |
| | 1074 | <div id="summary"> |
| | 1075 | <h1>{{ error_type|escape }}</h1> |
| | 1076 | <h2>{{ error_str|escape }}</h2> |
| | 1077 | <table class="meta"> |
| | 1078 | <!--tr> |
| | 1079 | <th>Request Method:</th> |
| | 1080 | <td>{{ request.method|escape }}</td> |
| | 1081 | </tr> |
| | 1082 | <tr> |
| | 1083 | <th>Request URL:</th> |
| | 1084 | <td>{{ request.url|escape }}</td> |
| | 1085 | </tr> |
| | 1086 | <tr> |
| | 1087 | <th>Exception Type:</th> |
| | 1088 | <td>{{ exception.type }}</td> |
| | 1089 | </tr--> |
| | 1090 | <tr> |
| | 1091 | <th>Exception Value:</th> |
| | 1092 | <td>{{ error_str }}</td> |
| | 1093 | </tr> |
| | 1094 | <tr> |
| | 1095 | <th>Exception Location:</th> |
| | 1096 | <td>{{ error_file|escape }}, line {{ error_line }}</td> |
| | 1097 | <!-- TODO: get function name --> |
| | 1098 | </tr> |
| | 1099 | </table> |
| | 1100 | </div> |
| | 1101 | |
| | 1102 | |
| | 1103 | </body> |
| | 1104 | '; |
| | 1105 | |
| | 1106 | static public function getArguments(&$args) |
| | 1107 | { |
| | 1108 | $pargs = array(); |
| | 1109 | foreach($args as $arg) { |
| | 1110 | array_push($pargs, self::getArgument($arg)); |
| | 1111 | } |
| | 1112 | return $pargs; |
| | 1113 | } |
| | 1114 | |
| | 1115 | static public function getArgument($arg, $recursion = true) |
| | 1116 | { |
| | 1117 | switch (strtolower(gettype($arg))) { |
| | 1118 | case 'string': |
| | 1119 | return '"'.$arg.'"'; |
| | 1120 | case 'boolean': |
| | 1121 | return (bool)$arg; |
| | 1122 | case 'object': |
| | 1123 | return 'object('. get_class($arg) . ')'; |
| | 1124 | case 'array': |
| | 1125 | $pargs = array(); |
| | 1126 | foreach ($arg as $key => $value) { |
| | 1127 | if (!$recursion) { |
| | 1128 | array_push($pargs, self::getArgument($key, false). ' => '. self::getArgument($value, false)); |
| | 1129 | } |
| | 1130 | } |
| | 1131 | return 'array('. implode(', ', $pargs) . ')'; |
| | 1132 | case 'resource': |
| | 1133 | return 'resource('. get_resource_type($arg). ')'; |
| | 1134 | default: |
| | 1135 | return var_export($arg, true); |
| | 1136 | } |
| | 1137 | } |
| | 1138 | |
| | 1139 | static public function handler($errno, $errstr = '', $errfile = '', $errline = '', $errcontext = null) |
| | 1140 | { |
| | 1141 | $p = array('backtrace' => array()); |
| | 1142 | if (error_reporting() == 0) { |
| | 1143 | return; |
| | 1144 | } |
| | 1145 | if (func_num_args() == 5) { |
| | 1146 | // error |
| | 1147 | list($p['errno'], $p['error_str'], $p['error_file'], $p['error_line']) = func_get_args(); |
| | 1148 | $backtrace = array_reverse(debug_backtrace()); |
| | 1149 | } else { |
| | 1150 | // exception |
| | 1151 | $exc = func_get_arg(0); |
| | 1152 | $p['errno'] = $exc->getCode(); |
| | 1153 | $p['error_str'] = $exc->getMessage(); |
| | 1154 | $p['error_file'] = $exc->getFile(); |
| | 1155 | $p['error_line'] = $exc->getLine(); |
| | 1156 | $backtrace = $exc->getTrace(); |
| | 1157 | } |
| | 1158 | array_pop($backtrace); // remove handler self |
| | 1159 | if (array_key_exists($errno, self::$errorType)) { |
| | 1160 | $p['error_type'] = self::$errorType[$p['errno']]; |
| | 1161 | } else { |
| | 1162 | $p['error_type'] = 'CAUGHT EXCEPTION'; |
| | 1163 | } |
| | 1164 | foreach ($backtrace as $bt) { |
| | 1165 | if (isset($bt['class'])) { |
| | 1166 | $trace = 'in class '. $bt['class'].'::'.$v['function'].'('; |
| | 1167 | if (isset($bt['args'])) { |
| | 1168 | $trace .= implode(', ', self::getArguments($bt['args'])); |
| | 1169 | } |
| | 1170 | $trace .= ')'; |
| | 1171 | array_push($p['backtrace'], $trace); |
| | 1172 | } elseif (isset($bt['function'])) { |
| | 1173 | $trace = 'in function '.$bt['function'].'('; |
| | 1174 | if (isset($bt['args'])) { |
| | 1175 | $trace .= implode(', ', self::getArguments($bt['args'])); |
| | 1176 | } |
| | 1177 | $trace .= ')'; |
| | 1178 | array_push($p['backtrace'], $trace); |
| | 1179 | } else { |
| | 1180 | array_push($p['backtrace'], 'unknown'); |
| | 1181 | } |
| | 1182 | } |
| | 1183 | switch ($p['errno']) { |
| | 1184 | case E_NOTICE: |
| | 1185 | case E_USER_NOTICE: |
| | 1186 | case E_STRICT: |
| | 1187 | return; |
| | 1188 | break; |
| | 1189 | default: |
| | 1190 | echo MuParser::parse(self::BACKTRACE_HTML)->render($p); |
| | 1191 | } |
| | 1192 | exit(1); |
| | 1193 | } |
| | 1194 | } |