1455d7ec |
1 | <?php |
4b4abf93 |
2 | |
1455d7ec |
3 | /** |
4 | * error.class.php |
5 | * |
1455d7ec |
6 | * This contains the custom error handler for SquirrelMail. |
7 | * |
c997cbe6 |
8 | * @copyright 2005-2021 The SquirrelMail Project Team |
4b4abf93 |
9 | * @license http://opensource.org/licenses/gpl-license.php GNU Public License |
1455d7ec |
10 | * @version $Id$ |
11 | * @package squirrelmail |
12 | */ |
13 | |
57311df7 |
14 | /** Used defines */ |
1455d7ec |
15 | define('SQM_NOTICE',0); |
16 | define('SQM_WARNING',1); |
17 | define('SQM_ERROR',2); |
1dbd1527 |
18 | define('SQM_STRICT',3); |
57311df7 |
19 | |
1dbd1527 |
20 | // php5 E_STRICT constant (compatibility with php4) |
21 | if (! defined('E_STRICT')) define('E_STRICT',2048); |
22 | // Set docref_root (fixes URLs that link to php manual) |
23 | if (ini_get('docref_root')=='') ini_set('docref_root','http://www.php.net/'); |
1455d7ec |
24 | |
25 | /** |
26 | * Error Handler class |
27 | * |
28 | * This class contains a custom error handler in order to display |
29 | * user notices/warnings/errors and php notices and warnings in a template |
30 | * |
31 | * @author Marc Groot Koerkamp |
32 | * @package squirrelmail |
33 | */ |
34 | class ErrorHandler { |
35 | |
36 | /** |
3741e45c |
37 | * Constructor (PHP5 style, required in some future version of PHP) |
1455d7ec |
38 | * @param object $oTemplate Template object |
39 | * @param string $sTemplateFile Template containing the error template |
40 | * @since 1.5.1 |
41 | */ |
3741e45c |
42 | function __construct(&$oTemplate, $sTemplateFile) { |
1d9716e4 |
43 | # echo 'init error handler...'; |
1455d7ec |
44 | $this->TemplateName = $sTemplateFile; |
45 | $this->Template =& $oTemplate; |
46 | $this->aErrors = array(); |
81de00c0 |
47 | $this->header_sent = false; |
1d9716e4 |
48 | $this->delayed_errors = false; |
49 | $this->Template->assign('delayed_errors', $this->delayed_errors); |
1455d7ec |
50 | } |
51 | |
3741e45c |
52 | /** |
53 | * Constructor (PHP4 style, kept for compatibility reasons) |
54 | * @param object $oTemplate Template object |
55 | * @param string $sTemplateFile Template containing the error template |
56 | * @since 1.5.1 |
57 | */ |
58 | function ErrorHandler(&$oTemplate, $sTemplateFile) { |
59 | self::__construct($oTemplate, $sTemplateFile); |
60 | } |
61 | |
1455d7ec |
62 | /** |
63 | * Sets the error template |
64 | * @since 1.5.1 |
65 | */ |
66 | function SetTemplateFile($sTemplateFile) { |
67 | $this->TemplateFile = $sTemplateFile; |
68 | } |
69 | |
81de00c0 |
70 | /** |
71 | * Sets if the page header is already sent |
72 | * @since 1.5.1 |
73 | */ |
74 | function HeaderSent() { |
75 | $this->header_sent = true; |
4ed31137 |
76 | $this->Template->assign('header_sent', true); |
81de00c0 |
77 | } |
78 | |
1d9716e4 |
79 | /** |
80 | * Turn on/off delayed error handling |
81 | * @since 1.5.2 |
82 | */ |
83 | function setDelayedErrors ($val = true) { |
84 | $this->delayed_errors = $val===true; |
85 | $this->Template->assign('delayed_errors', $this->delayed_errors); |
86 | } |
87 | |
81de00c0 |
88 | /** |
85a1f578 |
89 | * Store errors generated in a previous script but couldn't be displayed |
90 | * due to a header redirect. This requires storing of aDelayedErrors in the session |
91 | * @param array $aDelayedErrors array with errors stored in the $this->aErrors format. |
81de00c0 |
92 | * @since 1.5.1 |
93 | */ |
94 | function AssignDelayedErrors(&$aDelayedErrors) { |
95 | $aErrors = array_merge($this->aErrors,$aDelayedErrors); |
96 | $this->aErrors = $aErrors; |
97 | $this->Template->assign('aErrors',$this->aErrors); |
98 | $aDelayedErrors = false; |
99 | } |
100 | |
101 | |
1455d7ec |
102 | /** |
103 | * Custom Error handler (set with set_error_handler() ) |
104 | * @private |
105 | * @since 1.5.1 |
106 | */ |
771bae28 |
107 | function SquirrelMailErrorhandler($iErrNo, $sErrStr, $sErrFile, $iErrLine, $aContext=NULL) { |
1455d7ec |
108 | $aError = array( |
109 | 'type' => SQM_NOTICE,// Error type, notice, warning or fatal error; |
110 | 'category' => NULL, // SquirrelMail error category; |
111 | 'message' => NULL, // Error display message; |
112 | 'extra' => NULL, // Key value based array with extra error info; |
113 | 'link' => NULL, // Link to help location; |
114 | 'tip' => NULL // User tip. |
115 | ); |
116 | $iType = NULL; |
117 | $aErrorCategory = array(); |
1dbd1527 |
118 | |
6b00bba4 |
119 | /** |
120 | * Get current error reporting level. |
121 | * |
cbed20a4 |
122 | * PHP 4.1.2 does not return current error reporting level in ini_get (php 5.1b3 and |
123 | * 4.3.10 does). Retrieve current error reporting level while setting error reporting |
6b00bba4 |
124 | * to ini value and reset it to retrieved value. |
125 | */ |
126 | $iCurErrLevel = error_reporting(ini_get('error_reporting')); |
127 | error_reporting($iCurErrLevel); |
128 | |
1dbd1527 |
129 | /** |
130 | * Check error_reporting value before logging error. |
131 | * Don't log errors that are disabled by @ (error_reporting = 0). Some SquirrelMail scripts |
132 | * (sq_mb_list_encodings(), ldap function calls in functions/abook_ldap_server.php) |
133 | * handle errors themselves and @ is used to disable generic php error messages. |
1455d7ec |
134 | */ |
cbed20a4 |
135 | if ($iErrNo & $iCurErrLevel) { |
1dbd1527 |
136 | /* |
137 | * The following errors cannot be handled by a user defined error handler: |
138 | * E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING |
139 | */ |
140 | switch ($iErrNo) { |
141 | case E_STRICT: |
142 | $iType = (is_null($iType)) ? SQM_STRICT : $iType; |
1455d7ec |
143 | case E_NOTICE: |
144 | $iType = (is_null($iType)) ? SQM_NOTICE : $iType; |
145 | case E_WARNING: |
146 | $iType = (is_null($iType)) ? SQM_WARNING : $iType; |
147 | $aErrorCategory[] = 'PHP'; |
148 | $aError['message'] = $sErrStr; |
149 | $aError['extra'] = array( |
1dbd1527 |
150 | 'FILE' => $sErrFile, |
1d9716e4 |
151 | 'LINE' => $iErrLine) ; |
1455d7ec |
152 | // what todo with $aContext? |
153 | break; |
154 | case E_USER_ERROR: |
155 | $iType = (is_null($iType)) ? SQM_ERROR : $iType; |
156 | case E_USER_NOTICE: |
157 | $iType = (is_null($iType)) ? SQM_NOTICE : $iType; |
158 | case E_USER_WARNING: |
159 | $iType = (is_null($iType)) ? SQM_WARNING : $iType; |
160 | if ($sErrFile == __FILE__) { // Error is triggered in this file and probably by sqm_trigger_error |
161 | $aErrorTemp = @unserialize($sErrStr); |
162 | if (!is_array($aErrorTemp)) { |
163 | $aError['message'] = $sErrStr; |
164 | $aErrorCategory[] = 'UNDEFINED'; |
165 | } else { |
166 | $aError = array_merge($aError,$aErrorTemp); |
167 | // special error handling below |
168 | if ($aError['category'] & SQM_ERROR_IMAP) { |
1dbd1527 |
169 | $aErrorCategory[] = 'IMAP'; |
170 | // imap related error handling inside |
1455d7ec |
171 | } |
172 | if ($aError['category'] & SQM_ERROR_FS) { |
1dbd1527 |
173 | $aErrorCategory[] = 'FILESYSTEM'; |
174 | // filesystem related error handling inside |
1455d7ec |
175 | } |
176 | if ($aError['category'] & SQM_ERROR_SMTP) { |
1dbd1527 |
177 | $aErrorCategory[] = 'SMTP'; |
178 | // smtp related error handling inside |
1455d7ec |
179 | } |
180 | if ($aError['category'] & SQM_ERROR_LDAP) { |
1dbd1527 |
181 | $aErrorCategory[] = 'LDAP'; |
182 | // ldap related error handling inside |
1455d7ec |
183 | } |
184 | if ($aError['category'] & SQM_ERROR_DB) { |
1dbd1527 |
185 | $aErrorCategory[] = 'DATABASE'; |
186 | // db related error handling inside |
1455d7ec |
187 | } |
188 | if ($aError['category'] & SQM_ERROR_PLUGIN) { |
1dbd1527 |
189 | $aErrorCategory[] = 'PLUGIN'; |
d849b570 |
190 | do_hook('error_handler_plugin', $aError); |
1dbd1527 |
191 | // plugin related error handling inside |
1455d7ec |
192 | } |
193 | //if ($aError['category'] & SQM_ERROR_X) { |
194 | // $aErrorCategory[] = 'X'; |
195 | // place holder for a new category |
196 | //} |
197 | } |
198 | unset($aErrorTemp); |
199 | } else { |
200 | $aError['message'] = $sErrStr; |
201 | $aErrorCategory[] = 'SQM_NOTICE'; |
202 | } |
203 | break; |
204 | default: break; |
1dbd1527 |
205 | } |
206 | |
1d9716e4 |
207 | /** |
208 | * If delayed error handling is enabled, always record the location |
209 | * and tag the error is delayed to make debugging easier. |
210 | */ |
211 | if (isset($this->Template->values['delayed_errors']) && $this->Template->values['delayed_errors']) { |
212 | $aErrorCategory[] = 'Delayed'; |
213 | $aError['extra'] = array( |
214 | 'FILE' => $sErrFile, |
215 | 'LINE' => $iErrLine) ; |
216 | } |
217 | |
1dbd1527 |
218 | $aErrorTpl = array( |
219 | 'type' => $iType, |
220 | 'category' => $aErrorCategory, |
221 | 'message' => $aError['message'], |
222 | 'link' => $aError['link'], |
223 | 'tip' => $aError['tip'], |
224 | 'extra' => $aError['extra']); |
225 | // Add the notice/warning/error to the existing list of notices/warnings |
226 | $this->aErrors[] = $aErrorTpl; |
227 | $this->Template->assign('aErrors',$this->aErrors); |
1455d7ec |
228 | } |
1dbd1527 |
229 | |
1455d7ec |
230 | // Show the error immediate in case of fatal errors |
231 | if ($iType == SQM_ERROR) { |
20d30fc8 |
232 | if (isset($this->Template->values['header_sent']) && !$this->Template->values['header_sent']) { |
4803e9cd |
233 | // TODO replace this with template that can be assigned |
234 | // UPDATE: displayHtmlHeader() no longer sends anything |
235 | // directly to the browser itself and instead |
236 | // displays all output through the template file |
237 | // "protocol_header" as well as calls to the |
238 | // template's header() method, so perhaps the |
239 | // above TODO is alleviated?? (however, I don't fully |
240 | // understand the problem behind the TODO comment myself (Paul)) |
81de00c0 |
241 | displayHtmlHeader(_("Error"),'',false); |
242 | } |
1455d7ec |
243 | $this->DisplayErrors(); |
244 | exit(_("Terminating SquirrelMail due to a fatal error")); |
245 | } |
246 | } |
247 | |
20bcf334 |
248 | /** |
249 | * Force the delayed errors to be stored in the session in case |
250 | * $this->displayErrors() never gets called, e.g. in compose.php |
251 | */ |
252 | function saveDelayedErrors () { |
253 | if($this->delayed_errors) { |
254 | // Check for previous delayed errors... |
c758d786 |
255 | sqgetGlobalVar('delayed_errors', $delayed_errors, SQ_SESSION); |
256 | if (is_array($delayed_errors)) { |
257 | $this->AssignDelayedErrors($delayed_errors); |
258 | sqsession_unregister("delayed_errors"); |
20bcf334 |
259 | } |
260 | |
261 | if (count($this->aErrors) > 0) { |
262 | sqsession_register($this->aErrors,"delayed_errors"); |
263 | } |
264 | } |
265 | } |
266 | |
1455d7ec |
267 | /** |
268 | * Display the error array in the error template |
269 | * @return void |
270 | * @since 1.5.1 |
271 | */ |
272 | function DisplayErrors() { |
1d9716e4 |
273 | // Check for delayed errors... |
274 | if (!$this->delayed_errors) { |
275 | sqgetGlobalVar('delayed_errors', $delayed_errors, SQ_SESSION); |
276 | if (is_array($delayed_errors)) { |
277 | $this->AssignDelayedErrors($delayed_errors); |
278 | sqsession_unregister("delayed_errors"); |
279 | } |
280 | } |
281 | |
282 | if (isset($this->Template->values['aErrors']) && count($this->Template->values['aErrors']) > 0) { |
1d6c232c |
283 | foreach ($this->Template->values['aErrors'] as $err) { |
284 | if (!in_array($err, $this->aErrors, true)) { |
285 | $this->aErrors[] = $err; |
286 | } |
287 | } |
1d9716e4 |
288 | $this->Template->assign('aErrors',$this->aErrors); |
289 | } |
290 | |
291 | if (count($this->aErrors) > 0) { |
292 | if ($this->delayed_errors) { |
293 | sqsession_register($this->aErrors,"delayed_errors"); |
294 | } else { |
295 | $this->Template->display($this->TemplateName); |
296 | } |
1455d7ec |
297 | } |
298 | } |
299 | } |
300 | |
301 | /** |
302 | * Custom Error handler for PHP version < 4.3.0 (set with set_error_handler() ) |
303 | * @author Marc Groot Koerkamp |
304 | * @since 1.5.1 |
305 | */ |
306 | function SquirrelMailErrorhandler($iErrNo, $sErrStr, $sErrFile, $iErrLine, $aContext) { |
307 | global $oTemplate; |
308 | static $oErrorHandler; |
309 | if (!isset($oErrorHandler)) { |
310 | $oErrorHandler = new ErrorHandler($oTemplate,'error_message.tpl'); |
311 | } |
312 | $oErrorHandler->SquirrelMailErrorhandler($iErrNo, $sErrStr, $sErrFile, $iErrLine, $aContext); |
313 | } |
314 | |
315 | /** |
316 | * Triggers an imap error. Utility function for sqm_trigger_error() |
6d31e3a3 |
317 | * @param string $sErrNo error string defined in errors.php |
1455d7ec |
318 | * @param string $sRequest imap request string |
319 | * @param string $sResponse tagged imap response |
320 | * @param string $sMessage tagged imap response message |
321 | * @param array $aExtra optional associative array with extra error info |
322 | * @return void |
323 | * @author Marc Groot Koerkamp |
324 | * @since 1.5.1 |
325 | */ |
6d31e3a3 |
326 | function sqm_trigger_imap_error($sErrNo,$sRequest,$sResponse, $sMessage, $aExtra=array()) { |
1455d7ec |
327 | $aError = array( |
328 | 'REQUEST' => $sRequest, |
329 | 'RESPONSE' => $sResponse, |
330 | 'MESSAGE' => $sMessage); |
331 | $aError = array_merge($aExtra,$aError); |
6d31e3a3 |
332 | sqm_trigger_error($sErrNo,$aError); |
1455d7ec |
333 | } |
334 | |
335 | /** |
336 | * Trigger an error. |
6d31e3a3 |
337 | * @param string $sErrNo error string defined in errors.php |
1455d7ec |
338 | * @param array $aExtra optional associative array with extra error info |
339 | * @return void |
340 | * @author Marc Groot Koerkamp |
341 | * @since 1.5.1 |
342 | */ |
6d31e3a3 |
343 | function sqm_trigger_error($sErrNo,$aExtra=array()) { |
344 | static $aErrors; |
345 | if (!isset($aErrors)) { |
346 | // Include the error definition file. |
347 | include_once(SM_PATH.'include/errors.php'); |
348 | } |
349 | |
1455d7ec |
350 | $iPhpErr = E_USER_NOTICE; |
6d31e3a3 |
351 | if (is_array($aErrors) && isset($aErrors[$sErrNo]['level'])) { |
1455d7ec |
352 | if (is_array($aExtra) && count($aExtra)) { |
6d31e3a3 |
353 | $aErrors[$sErrNo]['extra'] = $aExtra; |
1455d7ec |
354 | } |
355 | // because trigger_error can only handle a string argument for the error description |
356 | // we serialize the result. |
6d31e3a3 |
357 | $sErrString = serialize($aErrors[$sErrNo]); |
358 | $iPhpErr = $aErrors[$sErrNo]['level']; |
1455d7ec |
359 | } else { |
6d31e3a3 |
360 | sm_print_r($aErrors); |
361 | $sErrString = "Error <$sErrNo> does not exist, fix the code or update the errors.php file"; |
1455d7ec |
362 | $iPhpErr = E_USER_ERROR; |
363 | } |
364 | trigger_error($sErrString, $iPhpErr); |
365 | } |