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