Overview

Packages

  • Onion::Controllers
  • Onion::Core
  • Onion::UI
  • Onion::Utils

Classes

  • Authenticator
  • Controller
  • Database
  • DatabaseResult
  • Log
  • Model
  • Onion
  • Request
  • Response
  • User
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: 
  3: /**
  4:  * Onion Framework - Spracovanie chýb
  5:  *
  6:  * Copyright (c) 2011 Jano Gašpar (http://webstranky.net)
  7:  *
  8:  * @author    Jano Gašpar
  9:  * @copyright Copyright (c) 2011 Jano Gašpar
 10:  * @package   Onion::Core
 11:  **/
 12: 
 13: class Log
 14: {
 15:     const
 16:         DEVELOPMENT = FALSE,
 17:         PRODUCTION  = TRUE;
 18: 
 19:     public static $log_level = 0;
 20: 
 21: 
 22:     public static $templates_dir = './templates';
 23: 
 24: 
 25:     public static $logs_dir = './logs';
 26: 
 27: 
 28:     public static $development_mode = FALSE;
 29: 
 30: 
 31:     public static $email;
 32: 
 33: 
 34:     private $tokens_classes = array(
 35:         'php-keyword' => array(
 36:             T_ARRAY, T_NEW, T_PUBLIC, T_PROTECTED, T_PRIVATE, T_CLASS, T_CLONE,
 37:             T_EXTENDS, T_VAR, T_STATIC, T_FUNCTION, T_AS, T_BREAK, T_CASE,
 38:             T_CATCH, T_CONTINUE, T_DECLARE, T_DEFAULT, T_ECHO, T_ELSE, T_ELSEIF,
 39:             T_EMPTY, T_EVAL, T_EXIT, T_EXTENDS, T_ENDDECLARE, T_ENDFOR,
 40:             T_ENDFOREACH, T_ENDIF, T_ENDSWITCH, T_ENDWHILE, T_END_HEREDOC,
 41:             T_FINAL, T_FOR, T_FOREACH, T_GLOBAL, T_GOTO, T_IF, T_IMPLEMENTS,
 42:             T_INCLUDE, T_INCLUDE_ONCE, T_INSTANCEOF, T_INTERFACE, T_ISSET,
 43:             T_LIST, T_NAMESPACE, T_PRINT, T_REQUIRE, T_REQUIRE_ONCE, T_RETURN,
 44:             T_SWITCH, T_THROW, T_TRY, T_UNSET, T_USE, T_VAR),
 45:         'php-name' => array(T_STRING),
 46:         'php-variable' => array(T_VARIABLE),
 47:         'php-comment' => array(T_COMMENT),
 48:         'php-strings' => array(T_CONSTANT_ENCAPSED_STRING),
 49:         );
 50: 
 51: 
 52:     private $titles = array(
 53:             0 => 'Unknown Error',
 54:             E_ERROR => 'Fatal Error',
 55:             E_WARNING => 'Warning',
 56:             E_COMPILE_WARNING => 'Warning',
 57:             E_COMPILE_WARNING => 'Compile Error',
 58:             E_USER_WARNING => 'Warning',
 59:             E_NOTICE => 'Notice',
 60:             E_USER_NOTICE => 'Notice',
 61:             E_STRICT => 'Strict standards',
 62:             E_DEPRECATED => 'Deprecated',
 63:             E_USER_DEPRECATED => 'Deprecated',
 64:             E_USER_ERROR => 'Fatal Error',
 65:         );
 66: 
 67: 
 68:     public static function enable($mode = NULL)
 69:     {
 70:         $logger = new self;
 71: 
 72:         if ($mode === NULL) {
 73:             $mode = '';
 74:         }
 75: 
 76:         if (is_string($mode) === TRUE
 77:             AND isset($_SERVER['REMOTE_ADDR']) === TRUE) {
 78: 
 79:             $whitelist = explode(',', $mode . '127.0.0.1,::1');
 80:             $mode =  in_array($_SERVER['REMOTE_ADDR'], $whitelist);
 81:         }
 82: 
 83:         $logger->development_mode = $mode;
 84: 
 85:         set_error_handler(array($logger, 'handle_error'));
 86:         set_exception_handler(array($logger, 'handle_exception'));
 87:         register_shutdown_function(array($logger, 'handle_fatal_error'));
 88:     }
 89: 
 90: 
 91:     /**
 92:      * Spracovanie chýb
 93:      *
 94:      * @param int $errno, string $errstr, string $errfile, int $errline, array $errcontext
 95:      */
 96:     public function handle_error($errno, $errstr, $errfile, $errline, $errcontext)
 97:     {
 98:         if ($errno === E_DEPRECATED) {
 99:             return NULL;
100:         }
101: 
102:         $backtrace = debug_backtrace();
103: 
104:         $this->log_error($errno, $errstr, $errfile, $errline, $backtrace, $errcontext);
105:     }
106: 
107: 
108:     /**
109:      * Spracovanie výnimiek
110:      */
111:     public function handle_exception($e)
112:     {
113:         $backtrace = $e->getTrace();
114:         array_shift($backtrace);
115:         $this->log_error($e->getCode(), $e->getMessage(), $e->getFile(), $e->getLine(), $backtrace);
116:     }
117: 
118: 
119:     /**
120:      * Spracovanie chýb
121:      *
122:      * @param int $errno, string $errstr, string $errfile, int $errline, array $errcontext
123:      */
124:     public function handle_fatal_error()
125:     {
126:         $last_error = error_get_last();
127:         if ($last_error['type'] === E_ERROR
128:             OR $last_error['type'] === E_PARSE) {
129: 
130:             $this->log_error(E_ERROR, $last_error['message'], $last_error['file'], $last_error['line'], array());
131:         }
132:     }
133: 
134: 
135:     public function hilight_file($file, $hilight_line = NULL, $range = NULL)
136:     {
137:         $source = file_get_contents($file);
138:         $source = preg_split('/(\n|\r)/', trim($source));
139: 
140:         if ($hilight_line !== NULL
141:             AND $range !== NULL) {
142: 
143:             $offset = floor($hilight_line  - ($range / 2));
144:             if ($offset < 1) {
145:                 $offset = 1;
146:             }
147: 
148:             $source = array_slice($source, $offset, $range);
149: 
150:         } elseif ($range === NULL) {
151:             $offset = 1;
152:         }
153: 
154:         return $this->hilight_source($source, $hilight_line, $offset);
155:     }
156: 
157: 
158:     public function hilight_source($source, $hilight_line = NULL, $offset)
159:     {
160:         if (is_array($source) === FALSE) {
161:             $source = preg_split('/(\n|\r)/', trim($source));
162:         }
163: 
164:         $hilighted_source = Html::element();
165: 
166:         foreach ($source as $relative_line_number => $line) {
167:             $relative_line_number++;
168: 
169:             $line_number = $relative_line_number + $offset;
170: 
171:             $hilighted_line = $hilighted_source->create('span');
172:             $hilighted_line->class[] = 'source-line';
173: 
174:             if ($hilight_line == $line_number) {
175:                 $hilighted_line->class[] = 'hilight-line';
176:             }
177: 
178:             if ($relative_line_number % 2 === 0) {
179:                 $hilighted_line->class[] = 'even-line';
180: 
181:             } else {
182:                 $hilighted_line->class[] = 'odd-line';
183:             }
184: 
185:             $hilighted_line->create('span')
186:                 ->class('line-number')
187:                 ->set_text(sprintf('%5s ', $line_number));
188: 
189:             $tmp = trim($line);
190:             if (empty($tmp) === TRUE) {
191:                 $hilighted_line->add(chr(10));
192:                 continue;
193:             }
194: 
195:             if (in_array($tmp, array('*', '/*', '*/')) === TRUE
196:                 OR substr($tmp, 0, 1) === '*') {
197: 
198:                 $hilighted_line->create('span')
199:                     ->class('php-comment')
200:                     ->set_text($line);
201:                 continue;
202:             }
203: 
204:             if (substr($line, 0, 2) !== '<?') {
205:                 $line = '<?php ' . $line;
206:             }
207: 
208:             $tokens = @token_get_all($line);
209: 
210:             foreach ($tokens as $key => $token) {
211:                 if (is_array($token) === FALSE) {
212:                     $hilighted_line->add($token);
213:                     continue;
214:                 }
215: 
216:                 if ($token[0] === T_OPEN_TAG
217:                     AND $key === 0) {
218: 
219:                     continue;
220:                 }
221: 
222:                 $found = FALSE;
223:                 foreach ($this->tokens_classes as $class => $token_codes) {
224:                     if (in_array($token[0], $token_codes) === TRUE) {
225:                         $found = TRUE;
226: 
227:                         $hilighted_line->create('span')
228:                             ->set_text($token[1])
229:                             ->class($class);
230:                     }
231:                 }
232: 
233:                 if ($found === FALSE) {
234:                     $hilighted_line->add($token[1]);
235:                 }
236:             }
237: 
238:             $hilighted_line->add(chr(10));
239:         }
240: 
241:         return $hilighted_source;
242:     }
243: 
244:     private function log_error($errno, $errstr, $errfile, $errline, $backtrace, $errcontext = array())
245:     {
246:         header('HTTP/1.1 500 Internal Server Error');
247: 
248:         $log = $this->create_log($errno, $errstr, $errfile, $errline, $backtrace);
249:         if ($this->development_mode === TRUE) {
250:             die($log);
251:         }
252: 
253:         file_put_contents(self::$logs_dir . '/errors/' . date('Y-m-d-H-i-s', time()) . '.html', $log);
254: 
255:         if (empty(self::$email) === FALSE) {
256:             foreach ((array) self::$email as $address) {
257:                 $this->send_log($address, 'Error', $log);
258:             }
259:         }
260: 
261:         readfile(self::$templates_dir . '/Error.html');
262:         exit;
263:     }
264: 
265: 
266:     public function create_log($errno, $errstr, $errfile, $errline, $backtrace, $errcontext = array())
267:     {
268:         ob_clean();
269:         restore_error_handler();
270:         restore_exception_handler();
271: 
272:         $template = self::$templates_dir . '/DevError.php';
273: 
274:         $data['code'] = $this->hilight_file($errfile, $errline, 30);
275:         $data['title'] = $this->titles[$errno];
276:         $data['error_message'] = $errstr;
277:         $data['file'] = $errfile;
278:         $data['context'] = $errcontext;
279:         $data['current_uri'] = $this->current_uri();
280:         if (isset($_SERVER['REQUEST_METHOD']) === TRUE) {
281:             $data['method'] = $_SERVER['REQUEST_METHOD'];
282: 
283:         } else {
284:             $data['method'] = '???';
285:         }
286: 
287:         $css  = '<style type="text/css">' . chr(10);
288:         $css .= file_get_contents(self::$templates_dir . '/css/reset.css') . chr(10);
289:         $css .= file_get_contents(self::$templates_dir . '/css/dev-error.css') . chr(10);
290:         $css .= '</style>' . chr(10) . chr(10);
291: 
292:         $js  = '<script type="text/javascript">' . chr(10);
293:         $js .= file_get_contents(self::$templates_dir . '/js/jquery.min.js') . chr(10);
294:         $js .= file_get_contents(self::$templates_dir . '/js/logger.js') . chr(10);
295:         $js .= '</script>' . chr(10) . chr(10);
296: 
297:         $data['assets'] = $css . $js;
298: 
299:         $backtrace_tmp = $backtrace;;
300:         $backtrace = array();
301:         foreach($backtrace_tmp  as $step_tmp) {
302:             $step = array();
303: 
304:             if (isset($step_tmp['file']) === FALSE) {
305:                 continue;
306:             }
307: 
308:             $step['file'] = $step_tmp['file'];
309: 
310:             $function = '';
311:             if (isset($step_tmp['class']) === TRUE) {
312:                 if ($step_tmp['class'] === 'Log') {
313:                     continue;
314:                 }
315: 
316:                 $function = $step_tmp['class'];
317:                 $function .= $step_tmp['type'];
318:             }
319:             $function .= $step_tmp['function'];
320:             $step['function'] = $function;
321: 
322:             if (isset($step_tmp['args']) === FALSE) {
323:                 $step_tmp['args'] = array();
324:             }
325: 
326:             $step['args'] = print_r(self::convert_bool($step_tmp['args']), TRUE);
327:             $step['line'] = $step_tmp['line'];
328: 
329:             $step['source'] = $this->hilight_file($step_tmp['file'], $step_tmp['line'], 16);
330: 
331:             $backtrace[] = $step;
332:         }
333:         $data['backtrace'] = $backtrace;
334: 
335:         return $this->render($template, $data);
336:     }
337: 
338: 
339:     public function render($template, $data) {
340:         extract($data);
341:         ob_start();
342:         include($template);
343:         $contents = ob_get_contents();
344:         ob_end_clean();
345:         return $contents;
346:     }
347: 
348: 
349:     public static function info()
350:     {
351:         $data = func_get_args();
352: 
353:         foreach ($data as $line) {
354:             self::write_log_line('Info', $line);
355:         }
356:     }
357: 
358: 
359:     public static function warning()
360:     {
361:         $data = func_get_args();
362: 
363:         foreach ($data as $line) {
364:             self::write_log_line('Warnnig', $line);
365:         }
366:     }
367: 
368: 
369:     public static function error($message, $data = '')
370:     {
371:         self::write_log_line('Error', $message, $data);
372:     }
373: 
374: 
375:     public static function debug($message, $data = '')
376:     {
377:         self::write_log_line('Debug', $message, $data);
378:     }
379: 
380: 
381:     public static function write_log_line($level, $message, $data = '')
382:     {
383:         $datetime = time();
384: 
385:         if (is_object($data) === TRUE) {
386:             ob_start();
387:             var_dump($data);
388:             $data = ob_get_clean();
389: 
390:         } elseif (is_array($data) === TRUE) {
391:             $data = self::convert_bool($data);
392:             $data = print_r($data, TRUE);
393:         }
394: 
395:         $backtrace = debug_backtrace();
396:         if (isset($backtrace[2]['class']) === TRUE) {
397:             $from = $backtrace[2]['class'] . '::' . $backtrace[2]['function'];
398: 
399:         } else {
400:             $from = $backtrace[2]['function'];
401:         }
402: 
403:         $line  = '"';
404:         $line .= $level;
405:         $line .= '","';
406:         $line .= $datetime;
407:         $line .= '","';
408:         $line .= $from;
409:         $line .= '","';
410:         $line .= base64_encode($message);
411:         $line .= '","';
412:         $line .= base64_encode($data);
413:         $line .= '"';
414:         $line .= chr(10);
415: 
416:         $log_file = self::$logs_dir . '/' . $_SERVER['REQUEST_TIME'];
417: 
418:         $handle = file_put_contents($log_file, $line, FILE_APPEND | LOCK_EX);
419:     }
420: 
421: 
422:     public static function convert_bool($data) {
423:         foreach ($data as &$value) {
424:             if (is_array($value) === TRUE) {
425:                 $value = self::convert_bool($value);
426:                 continue;
427:             }
428: 
429:             if ($value === TRUE) {
430:                 $value = 'TRUE';
431:                 continue;
432:             }
433: 
434:             if ($value === FALSE) {
435:                 $value = 'FALSE';
436:                 continue;
437:             }
438: 
439:             if ($value === NULL) {
440:                 $value = 'NULL';
441:                 continue;
442:             }
443:         }
444: 
445:         return $data;
446:     }
447: 
448: 
449:     private static function send_log($address, $message, $log)
450:     {
451:         $host = '?!';
452:         if (isset($_SERVER['HTTP_HOST']) === TRUE) {
453:             $host = $_SERVER['HTTP_HOST'];
454: 
455:         } elseif (isset($_SERVER['SERVER_NAME']) === TRUE) {
456:             $host = $_SERVER['HTTP_HOST'];
457:         }
458: 
459:         $attachment = chunk_split(base64_encode($log));
460: 
461:         $mail_message  = '--PHP-mixed-onionlogger' . chr(10);
462:         $mail_message .= 'Content-Type: multipart/alternative; boundary="PHP-alt-onionlogger"' . chr(10) . chr(10);
463: 
464:         $mail_message .= '--PHP-alt-onionlogger' . chr(10);
465:         $mail_message .= 'Content-type: text/plain; charset=UTF-8' . chr(10) . chr(10);
466: 
467:         $mail_message .= trim($message) . chr(10) . chr(10);
468: 
469:         $mail_message .= '--PHP-alt-onionlogger' . chr(10);
470:         $mail_message .= 'Content-type: text/html; charset=UTF-8' . chr(10) . chr(10);
471: 
472:         $mail_message .= trim($log) . chr(10) . chr(10);
473: 
474:         $mail_message .= '--PHP-alt-onionlogger--' . chr(10) . chr(10);
475: 
476:         $mail_message .= '--PHP-mixed-onionlogger' . chr(10);
477:         $mail_message .= 'Content-Type: text/html; name="log.html"' . chr(10);
478:         $mail_message .= 'Content-Transfer-Encoding: base64' . chr(10);
479:         $mail_message .= 'Content-Disposition: attachment' . chr(10) . chr(10);
480: 
481:         $mail_message .= $attachment . chr(10) . chr(10);
482:         $mail_message .= '--PHP-mixed-onionlogger--' . chr(10) . chr(10);
483: 
484:         $headers   = array();
485:         $headers[] = 'From: noreply@' . $host;
486:         $headers[] = 'X-Mailer: Onion Framework';
487:         $headers[] = 'Content-Type: multipart/mixed; boundary="PHP-mixed-onionlogger"';
488:         $headers[] = 'MIME-Version: 1.0';
489: 
490:         $subject = 'PHP: An error occurred on the server ' . $host;
491: 
492:         mail($address, '=?UTF-8?B?'.base64_encode($subject).'?=', $mail_message, implode(chr(10) ,$headers));
493:     }
494: 
495: 
496:     private function current_uri()
497:     {
498:         if (empty($_SERVER['HTTPS']) === TRUE
499:             OR $_SERVER['HTTPS'] === 'off') {
500: 
501:             $uri = 'http';
502: 
503:         } else {
504:             $uri = 'https';
505:         }
506: 
507:         $uri .= '://';
508: 
509:         if (isset($_SERVER['HTTP_HOST']) === TRUE) {
510:             $uri .= $_SERVER['HTTP_HOST'];
511: 
512:         } else {
513:             $uri .= $_SERVER['SERVER_NAME'];
514:         }
515: 
516:         if (empty($_SERVER['REQUEST_URI']) === FALSE) {
517:             $uri .= $_SERVER['REQUEST_URI'];
518:         }
519: 
520:         return $uri;
521:     }
522: }
523: 
524: 
525: 
526: /**
527:  * Onion Framework - Spracovanie chýb - kontroler
528:  *
529:  * Copyright (c) 2011 Jano Gašpar (http://webstranky.net)
530:  *
531:  * @author    Jano Gašpar
532:  * @copyright Copyright (c) 2011 Jano Gašpar
533:  * @package   Onion::Controllers
534:  **/
535: 
536: class LogController extends Controller
537: {
538:     /**
539:      * Zobrazenie posledného logu
540:      */
541:     public function show_log()
542:     {
543:         $logs = scandir(Log::$logs_dir, 1);
544:         $log_file = array_shift($logs);
545:         $log_file = array_shift($logs);
546:         if ($_SERVER['REQUEST_TIME'] == $log_file) {
547:             unlink(Log::$logs_dir . '/' . $log_file);
548:             $log_file = array_shift($logs);
549:         }
550: 
551:         $log_file = Log::$logs_dir . '/' . $log_file;
552: 
553:         $log = file_get_contents($log_file);
554:         $log = explode(chr(10), trim($log));
555:         $log = array_reverse($log);
556: 
557:         $out  = '<h2>' . $log_file . '</h2>';
558: 
559:         $out .= '<table>';
560: 
561:         $out .= '<tr>';
562:         $out .= '<th>Level</th>';
563:         $out .= '<th>Time</th>';
564:         $out .= '<th>From</th>';
565:         $out .= '<th>Message</th>';
566:         $out .= '<th>Data</th>';
567:         $out .= '</tr>';
568: 
569:         foreach ($log as $line) {
570:             if (empty($line) === TRUE) {
571:                 continue;
572:             }
573: 
574:             $line = substr($line, 1, -1);
575:             $line = explode('","', $line);
576: 
577:             $out .= '<tr>';
578:             $out .= '<td>' . $line[0] . '</td>';
579:             $out .= '<td>' . date('Y-m-d H:i:s', $line[1]) . '</td>';
580:             $out .= '<td>' . $line[2] . '</td>';
581:             $out .= '<td><code>' . base64_decode($line[3]) . '</code></td>';
582:             $out .= '<td><pre>' . base64_decode($line[4]) . '</pre></td>';
583:             $out .= '</tr>';
584:         }
585: 
586:         $out .= '</table>';
587: 
588:         die($out);
589:     }
590: }
591: 
Onion API documentation generated by ApiGen.
Generated using the TokenReflection library.