error handler improvements
[simplicity.git] / source / lib / simplicity / core / error / error.php
blobb71f0df331e53488f09e739d5aa8632fd3b6d055
1 <?php
2 /**
3 * Error Module
5 * The Simplicity Error module provides advanced error handling.
7 * @author John Le Drew <jp@antz29.com>
8 * @copyright Copyright (c) 2009, John Le Drew
9 * @license http://www.opensource.org/licenses/mit-license.php MIT License
10 * @version 2.0.0-alpha
12 * @smp_core
14 class smp_ErrorModule extends smp_Module
17 private $_handled = false;
19 /**
20 * @inherited
22 protected function init()
24 $this->setDefault('enabled',true);
25 $this->setDefault('chain',array('Basic'));
27 $this->createExtensionPoint('smp_ErrorHandler');
28 $this->registerPluginPrefix('smp_');
31 /**
32 * @inherited
33 */
34 public function exec($args=array())
36 error_reporting(-1);
38 if ($this->getConfig('enabled')) {
39 ini_set('display_errors',0);
40 register_shutdown_function(array($this,'shutdown'));
41 set_error_handler(array($this,'error'));
42 set_exception_handler(array($this,'exception'));
46 /**
47 * @internal
49 public function error($errno,$errstr,$errfile,$errline)
51 restore_error_handler();
52 $this->_handled = true;
53 $this->handle(new smp_Exception($errstr,$errline,$errno,$errfile));
56 /**
57 * @internal
58 */
59 public function shutdown()
61 restore_error_handler();
62 restore_exception_handler();
64 if ($this->_handled) return false;
66 $e = error_get_last();
68 if (!is_null($e)) {
69 $e = new smp_FatalException('Fatal error: '.$e['message'],$e['line'],$e['type'],$e['file'],$GLOBALS,array());
70 $this->handle($e);
74 /**
75 * @internal
76 */
77 public function exception(Exception $e)
79 restore_error_handler();
80 restore_exception_handler();
82 $this->_handled = true;
84 if (!($e instanceof smp_Exception)) {
85 $e = new smp_Exception($e->getMessage(),$e->getLine(),$e->getCode(),$e->getFile());
88 $this->handle($e);
91 public function getErrorReport($ref)
93 $ref = (int) $ref;
95 $cnf = $this->getConfig('logging');
96 $realpath = realpath($cnf['path']);
98 if (!$realpath) return false;
100 $realpath .= DS;
102 $dsn = "sqlite:{$realpath}errorlog.sq3";
104 $p = new PDO($dsn,null,null,array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
105 $p->sqliteCreateFunction('crc32', 'crc32', 1);
107 try {
108 $qry = "create table if not exists error_log ( id integer primary key, timestamp default CURRENT_TIMESTAMP, message, trace, context, request, response )";
109 $p->exec($qry);
112 $qry = "select crc32(id || timestamp) as ref1,? as ref2,* from error_log";
113 $stm = $p->prepare($qry);
114 $stm->execute(array($ref));
115 var_dump($stm->fetchAll(PDO::FETCH_ASSOC));die();
118 $qry = "select * from error_log where crc32(id || timestamp) like ?";
119 $stm = $p->prepare($qry);
120 $stm->execute(array($ref));
121 $error = $stm->fetch(PDO::FETCH_ASSOC);
122 return $error;
124 catch (Exception $e) {
125 var_dump($e);
126 die();
129 return false;
132 private function logException(smp_Exception $e)
134 $msg = $e->getMessage() . ' on line ' . $e->getLine() . ' in file ' . $e->getFile();
136 $session = Simplicity::getInstance()->getModule('Session');
138 if ($last = $session->get('last_exception')) {
139 if ($last['error']['message'] == $msg) return $last['ref'];
142 $cnf = $this->getConfig('logging');
144 $realpath = realpath($cnf['path']);
146 if (!$realpath) return false;
148 $realpath .= DS;
150 $dsn = "sqlite:{$realpath}errorlog.sq3";
151 $p = new PDO($dsn,null,null,array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
153 try {
154 $qry = "create table if not exists error_log ( id integer primary key, timestamp default CURRENT_TIMESTAMP, message, trace, context, request, response )";
155 $p->exec($qry);
157 $qry = "insert into error_log (message,trace,context,request,response) values (?,?,?,?,?)";
158 $stm = $p->prepare($qry);
160 $trace = $e->getTraceAsString();
161 $context = print_r($e->getContext(),true);
163 $request = print_r(array(
164 'method' => smp_Request::getInstance()->getMethod(),
165 'uri' => smp_Request::getInstance()->getUri(),
166 'request_data' => smp_Request::getInstance()->getData(),
167 'headers' => smp_Request::getInstance()->getHeaders()
168 ),true);
170 $response = print_r(array(
171 'status' => smp_Response::getInstance()->getStatus(),
172 'encoding' => smp_Response::getInstance()->getContentEncoding(),
173 'headers' => smp_Response::getInstance()->getHeaders(),
174 'content' => smp_Response::getInstance()->getContent()
175 ),true);
177 $stm->execute(array($msg,$trace,$context,$request,$response));
179 catch (Exception $e) {
180 return false;
183 $id = $p->lastInsertId();
184 $error = $p->query("select * from error_log where id = {$id}")->fetch(PDO::FETCH_ASSOC);
186 $ref = crc32($id.$error['timestamp']);
188 $session->set('last_exception',array('ref'=>$ref,'error' => $error));
190 $file = date('Ymdhis',strtotime($error['timestamp'])).'_'.$ref;
191 $file = $realpath."{$file}.log";
193 file_put_contents($file,print_r($error,true));
195 return $ref;
198 private function handle(smp_Exception $e)
200 $chain = $this->getConfig('chain');
202 while ($module = array_shift($chain)) {
203 $cls = $this->getModuleClass($module);
204 $mod = new $cls($this,$e,$module);
205 $mod->handle();
206 $e = $mod->getException();
209 $this->getSimplicity()->clearCurrentChain();