Overview

Packages

  • Jyxo_Beholder
  • Jyxo_Charset
  • Jyxo_Color
  • Jyxo_Css
  • Jyxo_ErrorHandling
  • Jyxo_FirePhp
  • Jyxo_Gettext
    • Parser
  • Jyxo_Html
  • Jyxo_Input
    • Chain
    • Filter
    • Validator
  • Jyxo_Mail
    • Email
    • Parser
    • Sender
  • Jyxo_Rpc
    • Json
    • Xml
  • Jyxo_Shell
  • Jyxo_SpamFilter
  • Jyxo_Spl
  • Jyxo_String
  • Jyxo_Svn
  • Jyxo_Time
  • Jyxo_Timer
  • Jyxo_Webdav
  • Jyxo_XmlReader
  • PHP

Classes

  • Jyxo_ErrorHandler
  • Jyxo_ErrorMail

Exceptions

  • Jyxo_Exception
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * Jyxo PHP Library
  5:  *
  6:  * LICENSE
  7:  *
  8:  * This source file is subject to the new BSD license that is bundled
  9:  * with this package in the file license.txt.
 10:  * It is also available through the world-wide-web at this URL:
 11:  * https://github.com/jyxo/php/blob/master/license.txt
 12:  */
 13: 
 14: /**
 15:  * Error and exception handler.
 16:  *
 17:  * @category Jyxo
 18:  * @package Jyxo_ErrorHandling
 19:  * @copyright Copyright (c) 2005-2011 Jyxo, s.r.o.
 20:  * @license https://github.com/jyxo/php/blob/master/license.txt
 21:  * @author Jaroslav HanslĂ­k
 22:  */
 23: class Jyxo_ErrorHandler
 24: {
 25:     /**
 26:      * Notice.
 27:      *
 28:      * @var string
 29:      */
 30:     const NOTICE = 'notice';
 31: 
 32:     /**
 33:      * Warning.
 34:      *
 35:      * @var string
 36:      */
 37:     const WARNING = 'warning';
 38: 
 39:     /**
 40:      * Error.
 41:      *
 42:      * @var string
 43:      */
 44:     const ERROR = 'error';
 45: 
 46:     /**
 47:      * Fatal error.
 48:      *
 49:      * @var string
 50:      */
 51:     const FATAL = 'fatal';
 52: 
 53:     /**
 54:      * Exception.
 55:      *
 56:      * @var string
 57:      */
 58:     const EXCEPTION = 'exception';
 59: 
 60:     /**
 61:      * Strict rules warning.
 62:      *
 63:      * @var string
 64:      */
 65:     const STRICT = 'strict';
 66: 
 67:     /**
 68:      * Deprecated code usage warning.
 69:      *
 70:      * @var string
 71:      */
 72:     const DEPRECATED = 'deprecated';
 73: 
 74:     /**
 75:      * Is debug enabled?
 76:      *
 77:      * @var boolean
 78:      */
 79:     private static $debug = false;
 80: 
 81:     /**
 82:      * Jyxo_ErrorMail instance for sending fatal error emails (used by the shutdown function and error handler).
 83:      *
 84:      * @var Jyxo_ErrorMail
 85:      */
 86:     private static $errorMail;
 87: 
 88:     /**
 89:      * Constructor preventing from creating class instances.
 90:      *
 91:      * @throws LogicException When trying to create an instance
 92:      */
 93:     public final function __construct()
 94:     {
 95:         throw new LogicException(sprintf('It is forbidden to create instances of %s class.', get_class($this)));
 96:     }
 97: 
 98:     /**
 99:      * Initializes error handling.
100:      *
101:      * @param boolean $debug Turn debugging on?
102:      */
103:     public static function init($debug = false)
104:     {
105:         // Sets debugging
106:         self::$debug = (bool) $debug;
107: 
108:         // Registers handlers
109:         set_error_handler(array(__CLASS__, 'handleError'));
110:         set_exception_handler(array(__CLASS__, 'handleException'));
111:         register_shutdown_function(array(__CLASS__, 'handleFatalError'));
112:     }
113: 
114:     /**
115:      * Sets Jyxo_ErrorMail instance for sending fatal error emails (used by the shutdown function and error handler).
116:      *
117:      * @param Jyxo_ErrorMail $errorMail
118:      */
119:     public static function setErrorMail(Jyxo_ErrorMail $errorMail)
120:     {
121:         self::$errorMail = $errorMail;
122:     }
123: 
124:     /**
125:      * Handles errors and logs them.
126:      *
127:      * @param integer $type Error type
128:      * @param string $message Error message
129:      * @param string $file File where the error occurred
130:      * @param integer $line Line on which the error occurred
131:      * @param array $context Error context variables
132:      * @return boolean Was the error processed?
133:      */
134:     public static function handleError($type, $message, $file, $line, $context)
135:     {
136:         // 0 means the error was blocked by prepending "@" to the command or by error_reporting settings
137:         if (0 === ($type & error_reporting())) {
138:             return true;
139:         }
140: 
141:         static $types = array(
142:             E_RECOVERABLE_ERROR => self::ERROR,
143:             E_USER_ERROR => self::ERROR,
144:             E_WARNING => self::WARNING,
145:             E_USER_WARNING => self::WARNING,
146:             E_NOTICE => self::NOTICE,
147:             E_USER_NOTICE => self::NOTICE,
148:             E_STRICT => self::STRICT,
149:             E_DEPRECATED => self::DEPRECATED,
150:             E_USER_DEPRECATED => self::DEPRECATED
151:         );
152: 
153:         // On false, the standard error handler will be used
154:         return self::log(
155:             array(
156:                 'type' => $types[$type],
157:                 'text' => $message,
158:                 'file' => $file,
159:                 'line' => $line,
160:                 'context' => $context,
161:                 'trace' => array_slice(debug_backtrace(), 1) // Removes the error handler call from trace
162:             )
163:         );
164:     }
165: 
166:     /**
167:      * Catches exceptions and logs them.
168:      *
169:      * @param Exception $exception Uncaught exception
170:      */
171:     public static function handleException(Exception $exception)
172:     {
173:         self::exception($exception);
174:         if (self::$errorMail) {
175:             self::$errorMail->send($exception);
176:         }
177:     }
178: 
179:     /**
180:      * Handles critical errors and logs them.
181:      */
182:     public static function handleFatalError()
183:     {
184:         // List of critical errors
185:         static $fatalErrors = array(
186:             E_ERROR => true,
187:             E_CORE_ERROR => true,
188:             E_COMPILE_ERROR => true,
189:             E_PARSE => true,
190:         );
191: 
192:         // If the last error was critical
193:         $error = error_get_last();
194:         if (isset($fatalErrors[$error['type']])) {
195:             self::log(
196:                 array(
197:                     'type' => self::FATAL,
198:                     'text' => $error['message'],
199:                     'file' => $error['file'],
200:                     'line' => $error['line']
201:                 )
202:             );
203:             if (self::$errorMail) {
204:                 $ex = new ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line']);
205:                 self::$errorMail->send($ex);
206:             }
207:         }
208:     }
209: 
210:     /**
211:      * Adds a caught exception.
212:      *
213:      * @param Exception $exception Caught exception
214:      * @param boolean $fire Shall we use FirePHP?
215:      */
216:     public static function exception(Exception $exception, $fire = true)
217:     {
218:         self::log(
219:             array(
220:                 'type' => self::EXCEPTION,
221:                 'text' => $exception->getMessage() . ' [' . $exception->getCode() . ']',
222:                 'file' => $exception->getFile(),
223:                 'line' => $exception->getLine(),
224:                 'trace' => $exception->getTrace(),
225:                 'previous' => self::getAllPreviousExceptions($exception)
226:             ),
227:             $fire
228:         );
229:     }
230: 
231:     /**
232:      * Logs a message.
233:      *
234:      * @param array $message Message definition
235:      * @param boolean $fire Shall we use FirePHP?
236:      * @return boolean Was logging successful?
237:      */
238:     public static function log(array $message, $fire = true)
239:     {
240:         // Adds default values if missing
241:         if (!isset($message['file'])) {
242:             $message['file'] = null;
243:         }
244:         if (!isset($message['line'])) {
245:             $message['line'] = null;
246:         }
247:         if (!isset($message['trace'])) {
248:             $message['trace'] = array();
249:         }
250:         if (!isset($message['previous'])) {
251:             $message['previous'] = array();
252:         }
253: 
254:         // We don't want HTML tags and entities in the log
255:         if (ini_get('html_errors')) {
256:             $message['text'] = html_entity_decode(strip_tags($message['text']));
257:         }
258: 
259:         // Request type
260:         if (!empty($_SERVER['argv'])) {
261:             // CLI
262:             $request = implode(' ', $_SERVER['argv']);
263:         } else {
264:             // Apache
265:             $request = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
266:             $request .= $_SERVER['REQUEST_URI'];
267:         }
268: 
269:         // Base text
270:         $text = sprintf('%s [Request: %s]', $message['text'], $request);
271:         if (isset($message['file'], $message['line'])) {
272:             $text .= sprintf(' [%s: %s]', $message['file'], $message['line']);
273:         }
274:         $log = sprintf("%s: %s\n", strtoupper($message['type']), $text);
275: 
276:         // Trace
277:         $log .= self::getTraceLog($message['trace']);
278: 
279:         // Previous exceptions
280:         $previousTrace = $message['trace'];
281:         foreach ($message['previous'] as $previous) {
282:             // Throw away trace parts that have already been processed
283:             $trace = array_reverse(array_diff_key(array_reverse($previous->getTrace()), array_reverse($previousTrace)));
284:             $previousTrace = $previous->getTrace();
285: 
286:             $log .= sprintf("Previous: %s [%s] [%s: %s]\n", $previous->getMessage(), $previous->getCode(), $previous->getFile(), $previous->getLine());
287:             $log .= self::getTraceLog($trace);
288:         }
289: 
290:         // FirePHP log for debugging
291:         if (self::$debug && $fire) {
292:             self::firephp($message);
293:         }
294: 
295:         // Logging
296:         return error_log(trim($log));
297:     }
298: 
299:     /**
300:      * Sends a message to FirePHP.
301:      *
302:      * @param array $message Message definition
303:      * @return boolean Was sending successful?
304:      */
305:     private static function firephp($message)
306:     {
307:         static $labels = array(
308:             self::EXCEPTION => 'Exception',
309:             self::FATAL => 'Fatal Error',
310:             self::ERROR => 'Error',
311:             self::WARNING => 'Warning',
312:             self::NOTICE => 'Notice',
313:             self::STRICT => 'Strict',
314:             self::DEPRECATED => 'Deprecated'
315:         );
316: 
317:         // Adds to FirePHP
318:         return Jyxo_FirePhp::trace(
319:             sprintf('%s: %s', $labels[$message['type']], $message['text']),
320:             $message['file'],
321:             $message['line'],
322:             $message['trace']
323:         );
324:     }
325: 
326:     /**
327:      * Returns trace log.
328:      *
329:      * @param array $trace Trace definition
330:      * @return string
331:      */
332:     private static function getTraceLog(array $trace)
333:     {
334:         $log = '';
335:         foreach ($trace as $levelNo => $level) {
336:             if (!isset($level['file'])) {
337:                 $level['file'] = 0;
338:             }
339:             if (!isset($level['line'])) {
340:                 $level['line'] = 0;
341:             }
342:             if (!isset($level['class'])) {
343:                 $level['class'] = '';
344:             }
345:             if (!isset($level['type'])) {
346:                 $level['type'] = '';
347:             }
348:             if (!isset($level['function'])) {
349:                 $level['function'] = '';
350:             }
351:             $log .= sprintf("\t%s\t%s\t%s\t%s\n", $levelNo, $level['file'], $level['line'], $level['class'] . $level['type'] . $level['function']);
352:         }
353:         return $log;
354:     }
355: 
356:     /**
357:      * Returns all exception's previous exceptions.
358:      *
359:      * @param Exception $exception Exception to process
360:      * @return array
361:      */
362:     private static function getAllPreviousExceptions(Exception $exception)
363:     {
364:         $stack = array();
365:         $previous = $exception->getPrevious();
366:         while (null !== $previous) {
367:             $stack[] = $previous;
368:             $previous = $previous->getPrevious();
369:         }
370:         return $stack;
371:     }
372: }
373: 
Jyxo PHP Library API documentation generated by ApiGen 2.3.0