Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F726740
in-portal
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Mon, Jan 6, 12:02 AM
Size
36 KB
Mime Type
text/x-diff
Expires
Wed, Jan 8, 12:02 AM (1 d, 4 h ago)
Engine
blob
Format
Raw Data
Handle
536833
Attached To
rINP In-Portal
in-portal
View Options
Index: branches/5.2.x/LICENSE
===================================================================
--- branches/5.2.x/LICENSE (revision 16425)
+++ branches/5.2.x/LICENSE (revision 16426)
Property changes on: branches/5.2.x/LICENSE
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x/LICENSE:r16334
Index: branches/5.2.x/robots.txt
===================================================================
--- branches/5.2.x/robots.txt (revision 16425)
+++ branches/5.2.x/robots.txt (revision 16426)
Property changes on: branches/5.2.x/robots.txt
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x/robots.txt:r16334
Index: branches/5.2.x/core/kernel/utility/logger.php
===================================================================
--- branches/5.2.x/core/kernel/utility/logger.php (revision 16425)
+++ branches/5.2.x/core/kernel/utility/logger.php (revision 16426)
@@ -1,1346 +1,1401 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2012 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
/**
* Class for logging system activity
*/
class kLogger extends kBase {
/**
* Prefix of all database related errors
*/
const DB_ERROR_PREFIX = 'SQL Error:';
/**
* Logger state: logging of errors and user-defined messages
*/
const STATE_ENABLED = 1;
/**
* Logger state: logging of user-defined messages only
*/
const STATE_USER_ONLY = 2;
/**
* Logger state: don't log anything
*/
const STATE_DISABLED = 0;
/**
* Log store: automatically determine where log should be written
*/
const LS_AUTOMATIC = 1;
/**
* Log store: always write log to database
*/
const LS_DATABASE = 2;
/**
* Log store: always write log to disk
*/
const LS_DISK = 3;
/**
* Log level: system is unusable
*/
const LL_EMERGENCY = 0;
/**
* Log level: action must be taken immediately
*/
const LL_ALERT = 1;
/**
* Log level: the system is in a critical condition
*/
const LL_CRITICAL = 2;
/**
* Log level: there is an error condition
*/
const LL_ERROR = 3;
/**
* Log level: there is a warning condition
*/
const LL_WARNING = 4;
/**
* Log level: a normal but significant condition
*/
const LL_NOTICE = 5;
/**
* Log level: a purely informational message
*/
const LL_INFO = 6;
/**
* Log level: messages generated to debug the application
*/
const LL_DEBUG = 7;
/**
* Log type: PHP related activity
*/
const LT_PHP = 1;
/**
* Log type: database related activity
*/
const LT_DATABASE = 2;
/**
* Log type: custom activity
*/
const LT_OTHER = 3;
/**
* Log interface: Front
*/
const LI_FRONT = 1;
/**
* Log interface: Admin
*/
const LI_ADMIN = 2;
/**
* Log interface: Cron (Front)
*/
const LI_CRON_FRONT = 3;
/**
* Log interface: Cron (Admin)
*/
const LI_CRON_ADMIN = 4;
/**
* Log interface: API
*/
const LI_API = 5;
/**
* Log notification status: disabled
*/
const LNS_DISABLED = 0;
/**
* Log notification status: pending
*/
const LNS_PENDING = 1;
/**
* Log notification status: sent
*/
const LNS_SENT = 2;
/**
* List of error/exception handlers
*
* @var Array
* @access protected
*/
protected $_handlers = Array ();
/**
* Long messages are saved here, because "trigger_error" doesn't support error messages over 1KB in size
*
* @var Array
* @access protected
*/
protected static $_longMessages = Array ();
/**
* Log record being worked on
*
* @var Array
* @access protected
*/
protected $_logRecord = Array ();
/**
* Maximal level of a message, that can be logged
*
* @var int
* @access protected
*/
protected $_maxLogLevel = self::LL_NOTICE;
/**
* State of the logger
*
* @var int
* @access protected
*/
protected $_state = self::STATE_DISABLED;
/**
* Caches state of debug mode
*
* @var bool
* @access protected
*/
protected $_debugMode = false;
/**
* Ignores backtrace record where following files are mentioned
*
* @var Array
* @access protected
*/
protected $_ignoreInTrace = Array ('logger.php', 'db_connection.php', 'db_load_balancer.php');
/**
* Create event log
*
* @param Array $methods_to_call List of invokable kLogger class method with their parameters (if any)
* @access public
*/
public function __construct($methods_to_call = Array ())
{
parent::__construct();
$vars = kUtil::getConfigVars();
$this->_debugMode = $this->Application->isDebugMode();
$this->setState(isset($vars['EnableSystemLog']) ? $vars['EnableSystemLog'] : self::STATE_DISABLED);
$this->_maxLogLevel = isset($vars['SystemLogMaxLevel']) ? (int)$vars['SystemLogMaxLevel'] : self::LL_NOTICE;
foreach ($methods_to_call as $method_to_call) {
call_user_func_array(Array ($this, $method_to_call[0]), $method_to_call[1]);
}
if ( !kUtil::constOn('DBG_ZEND_PRESENT') && !$this->Application->isDebugMode() ) {
// don't report error on screen if debug mode is turned off
error_reporting(0);
ini_set('display_errors', 0);
}
register_shutdown_function(Array ($this, 'catchLastError'));
}
/**
* Sets state of the logged (enabled/user-only/disabled)
*
* @param $new_state
* @return void
* @access public
*/
public function setState($new_state = null)
{
if ( isset($new_state) ) {
$this->_state = (int)$new_state;
}
if ( $this->_state === self::STATE_ENABLED ) {
$this->_enableErrorHandling();
}
elseif ( $this->_state === self::STATE_DISABLED ) {
$this->_disableErrorHandling();
}
}
/**
* Enable error/exception handling capabilities
*
* @return void
* @access protected
*/
protected function _enableErrorHandling()
{
$this->_disableErrorHandling();
$this->_handlers[self::LL_ERROR] = new kErrorHandlerStack($this);
$this->_handlers[self::LL_CRITICAL] = new kExceptionHandlerStack($this);
}
/**
* Disables error/exception handling capabilities
*
* @return void
* @access protected
*/
protected function _disableErrorHandling()
{
foreach ($this->_handlers as $index => $handler) {
$this->_handlers[$index]->__destruct();
unset($this->_handlers[$index]);
}
}
/**
* Initializes new log record. Use "kLogger::write" to save to db/disk
*
* @param string $message
* @param int $code
* @return kLogger
* @access public
*/
public function prepare($message = '', $code = null)
{
$this->_logRecord = Array (
'LogUniqueId' => kUtil::generateId(),
'LogMessage' => $message,
'LogLevel' => self::LL_INFO,
'LogCode' => $code,
'LogType' => self::LT_OTHER,
'LogHostname' => $_SERVER['HTTP_HOST'],
'LogRequestSource' => php_sapi_name() == 'cli' ? 2 : 1,
'LogRequestURI' => php_sapi_name() == 'cli' ? implode(' ', $GLOBALS['argv']) : $_SERVER['REQUEST_URI'],
'LogUserId' => USER_GUEST,
'IpAddress' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '',
'LogSessionKey' => 0,
'LogProcessId' => getmypid(),
'LogUserData' => '',
'LogNotificationStatus' => self::LNS_DISABLED,
);
if ( $this->Application->isAdmin ) {
$this->_logRecord['LogInterface'] = defined('CRON') && CRON ? self::LI_CRON_ADMIN : self::LI_ADMIN;
}
else {
$this->_logRecord['LogInterface'] = defined('CRON') && CRON ? self::LI_CRON_FRONT : self::LI_FRONT;
}
if ( $this->Application->InitDone ) {
$this->_logRecord['LogUserId'] = $this->Application->RecallVar('user_id');
$this->_logRecord['LogSessionKey'] = $this->Application->GetSID();
$this->_logRecord['IpAddress'] = $this->Application->getClientIp();
}
return $this;
}
/**
* Sets one or more fields of log record
*
* @param string|Array $field_name
* @param string|null $field_value
* @return kLogger
* @access public
* @throws UnexpectedValueException
*/
public function setLogField($field_name, $field_value = null)
{
if ( isset($field_value) ) {
$this->_logRecord[$field_name] = $field_value;
}
elseif ( is_array($field_name) ) {
$this->_logRecord = array_merge($this->_logRecord, $field_name);
}
else {
throw new UnexpectedValueException('Invalid arguments');
}
return $this;
}
/**
* Sets user data
*
* @param string $data
* @param bool $as_array
* @return kLogger
* @access public
*/
public function setUserData($data, $as_array = false)
{
if ( $as_array ) {
$data = serialize((array)$data);
}
return $this->setLogField('LogUserData', $data);
}
/**
* Add user data
*
* @param string $data
* @param bool $as_array
* @return kLogger
* @access public
*/
public function addUserData($data, $as_array = false)
{
$new_data = $this->_logRecord['LogUserData'];
if ( $as_array ) {
$new_data = $new_data ? unserialize($new_data) : Array ();
$new_data[] = $data;
$new_data = serialize($new_data);
}
else {
$new_data .= ($new_data ? PHP_EOL : '') . $data;
}
return $this->setLogField('LogUserData', $new_data);
}
/**
* Adds event to log record
*
* @param kEvent $event
* @return kLogger
* @access public
*/
public function addEvent(kEvent $event)
{
$this->_logRecord['LogEventName'] = (string)$event;
return $this;
}
/**
* Adds log source file & file to log record
*
* @param string|Array $file_or_trace file path
* @param int $line file line
* @return kLogger
* @access public
*/
public function addSource($file_or_trace = '', $line = 0)
{
if ( is_array($file_or_trace) ) {
$trace_info = $file_or_trace[0];
$this->_logRecord['LogSourceFilename'] = $trace_info['file'];
$this->_logRecord['LogSourceFileLine'] = $trace_info['line'];
}
else {
$this->_logRecord['LogSourceFilename'] = $file_or_trace;
$this->_logRecord['LogSourceFileLine'] = $line;
}
return $this;
}
/**
* Adds session contents to log record
*
* @param bool $include_optional Include optional session variables
* @return kLogger
* @access public
*/
public function addSessionData($include_optional = false)
{
if ( $this->Application->InitDone ) {
$this->_logRecord['LogSessionData'] = serialize($this->Application->Session->getSessionData($include_optional));
}
return $this;
}
/**
* Adds user request information to log record
*
* @return kLogger
* @access public
*/
public function addRequestData()
{
$request_data = Array ();
$request_variables = Array ('_GET' => $_GET, '_POST' => $_POST, '_COOKIE' => $_COOKIE);
foreach ($request_variables as $title => $data) {
if ( !$data ) {
continue;
}
$request_data[$title] = $data;
}
$this->_logRecord['LogRequestData'] = serialize($request_data);
return $this;
}
/**
* Adds trace to log record
*
* @param Array $trace
* @param int $skip_levels
* @param Array $skip_files
* @return kLogger
* @access public
*/
public function addTrace($trace = null, $skip_levels = 1, $skip_files = null)
{
$trace = $this->createTrace($trace, $skip_levels, $skip_files);
foreach ($trace as $trace_index => $trace_info) {
if ( isset($trace_info['args']) ) {
$trace[$trace_index]['args'] = $this->_implodeObjects($trace_info['args']);
}
}
$this->_logRecord['LogBacktrace'] = serialize($this->_removeObjectsFromTrace($trace));
return $this;
}
/**
* Remove objects from trace, since before PHP 5.2.5 there wasn't possible to remove them initially
*
* @param Array $trace
* @return Array
* @access protected
*/
protected function _removeObjectsFromTrace($trace)
{
if ( version_compare(PHP_VERSION, '5.3', '>=') ) {
return $trace;
}
$trace_indexes = array_keys($trace);
foreach ($trace_indexes as $trace_index) {
unset($trace[$trace_index]['object']);
}
return $trace;
}
/**
* Implodes object to prevent memory leaks
*
* @param Array $array
* @return Array
* @access protected
*/
protected function _implodeObjects($array)
{
$ret = Array ();
foreach ($array as $key => $value) {
if ( is_array($value) ) {
$ret[$key] = $this->_implodeObjects($value);
}
elseif ( is_object($value) ) {
if ( $value instanceof kEvent ) {
$ret[$key] = 'Event: ' . (string)$value;
}
elseif ( $value instanceof kBase ) {
$ret[$key] = (string)$value;
}
else {
$ret[$key] = 'Class: ' . get_class($value);
}
}
elseif ( strlen($value) > 200 ) {
$ret[$key] = substr($value, 0, 50) . ' ...';
}
else {
$ret[$key] = $value;
}
}
return $ret;
}
/**
* Removes first N levels from trace
*
* @param Array $trace
* @param int $levels
* @param Array $files
* @return Array
* @access public
*/
public function createTrace($trace = null, $levels = null, $files = null)
{
if ( !isset($trace) ) {
$trace = debug_backtrace(false);
}
if ( !$trace ) {
// no trace information
return $trace;
}
if ( isset($levels) && is_numeric($levels) ) {
for ($i = 0; $i < $levels; $i++) {
array_shift($trace);
}
}
if ( isset($files) && is_array($files) ) {
while (true) {
$trace_info = $trace[0];
$file = isset($trace_info['file']) ? basename($trace_info['file']) : '';
if ( !in_array($file, $files) ) {
break;
}
array_shift($trace);
}
}
return $trace;
}
/**
* Adds PHP error to log record
*
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
* @return kLogger
* @access public
*/
public function addError($errno, $errstr, $errfile = null, $errline = null)
{
$errstr = self::expandMessage($errstr, !$this->_debugMode);
$this->_logRecord['LogLevel'] = $this->_getLogLevelByErrorNo($errno);
if ( $this->isLogType(self::LT_DATABASE, $errstr) ) {
list ($errno, $errstr, $sql) = self::parseDatabaseError($errstr);
$this->_logRecord['LogType'] = self::LT_DATABASE;
$this->_logRecord['LogUserData'] = $sql;
$trace = $this->createTrace(null, 4, $this->_ignoreInTrace);
$this->addSource($trace);
$this->addTrace($trace, 0);
}
else {
$this->_logRecord['LogType'] = self::LT_PHP;
$this->addSource((string)$errfile, $errline);
$this->addTrace(null, 4);
}
$this->_logRecord['LogCode'] = $errno;
$this->_logRecord['LogMessage'] = $errstr;
return $this;
}
/**
* Adds PHP exception to log record
*
* @param Exception $exception
* @return kLogger
* @access public
*/
public function addException($exception)
{
$errstr = self::expandMessage($exception->getMessage(), !$this->_debugMode);
$this->_logRecord['LogLevel'] = self::LL_CRITICAL;
+ $exception_trace = $exception->getTrace();
+
+ array_unshift($exception_trace, array(
+ 'function' => '',
+ 'file' => $exception->getFile() !== null ? $exception->getFile() : 'n/a',
+ 'line' => $exception->getLine() !== null ? $exception->getLine() : 'n/a',
+ 'args' => array(),
+ ));
+
if ( $this->isLogType(self::LT_DATABASE, $errstr) ) {
list ($errno, $errstr, $sql) = self::parseDatabaseError($errstr);
$this->_logRecord['LogType'] = self::LT_DATABASE;
$this->_logRecord['LogUserData'] = $sql;
- $trace = $this->createTrace($exception->getTrace(), null, $this->_ignoreInTrace);
+ $trace = $this->createTrace($exception_trace, null, $this->_ignoreInTrace);
$this->addSource($trace);
$this->addTrace($trace, 0);
}
else {
$this->_logRecord['LogType'] = self::LT_PHP;
$errno = $exception->getCode();
$this->addSource((string)$exception->getFile(), $exception->getLine());
- $this->addTrace($exception->getTrace(), 0);
+ $this->addTrace($exception_trace, 0);
}
$this->_logRecord['LogCode'] = $errno;
$this->_logRecord['LogMessage'] = $errstr;
return $this;
}
/**
* Allows to map PHP error numbers to syslog log level
*
* @param int $errno
* @return int
* @access protected
*/
protected function _getLogLevelByErrorNo($errno)
{
$error_number_mapping = Array (
self::LL_ERROR => Array (E_RECOVERABLE_ERROR, E_USER_ERROR, E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE),
self::LL_WARNING => Array (E_WARNING, E_USER_WARNING, E_CORE_WARNING, E_COMPILE_WARNING),
self::LL_NOTICE => Array (E_NOTICE, E_USER_NOTICE, E_STRICT),
);
if ( version_compare(PHP_VERSION, '5.3.0', '>=') ) {
$error_number_mapping[self::LL_NOTICE][] = E_DEPRECATED;
$error_number_mapping[self::LL_NOTICE][] = E_USER_DEPRECATED;
}
foreach ($error_number_mapping as $log_level => $error_numbers) {
if ( in_array($errno, $error_numbers) ) {
return $log_level;
}
}
return self::LL_ERROR;
}
/**
* Changes log level of a log record
*
* @param int $log_level
* @return kLogger
* @access public
*/
public function setLogLevel($log_level)
{
$this->_logRecord['LogLevel'] = $log_level;
return $this;
}
/**
* Writes prepared log to database or disk, when database isn't available
*
* @param int $storage_medium
* @return bool|int
* @access public
* @throws InvalidArgumentException
*/
public function write($storage_medium = self::LS_AUTOMATIC)
{
if ( !$this->_logRecord || $this->_logRecord['LogLevel'] > $this->_maxLogLevel || $this->_state == self::STATE_DISABLED ) {
// nothing to save OR less detailed logging requested OR disabled
return true;
}
$this->_logRecord['LogMemoryUsed'] = memory_get_usage();
$this->_logRecord['LogTimestamp'] = adodb_mktime();
$this->_logRecord['LogDate'] = adodb_date('Y-m-d H:i:s');
if ( $storage_medium == self::LS_AUTOMATIC ) {
$storage_medium = $this->Conn->connectionOpened() ? self::LS_DATABASE : self::LS_DISK;
}
if ( $storage_medium == self::LS_DATABASE ) {
$result = $this->Conn->doInsert($this->_logRecord, TABLE_PREFIX . 'SystemLog');
}
elseif ( $storage_medium == self::LS_DISK ) {
$result = $this->_saveToFile(RESTRICTED . '/system.log');
}
else {
throw new InvalidArgumentException('Unknown storage medium "' . $storage_medium . '"');
}
$unique_id = $this->_logRecord['LogUniqueId'];
if ( $this->_logRecord['LogNotificationStatus'] == self::LNS_SENT ) {
$this->_sendNotification($unique_id);
}
$this->_logRecord = Array ();
return $result ? $unique_id : false;
}
/**
* Catches last error happened before script ended
*
* @return void
* @access public
*/
public function catchLastError()
{
$this->write();
$last_error = error_get_last();
if ( !is_null($last_error) && isset($this->_handlers[self::LL_ERROR]) ) {
$handler = $this->_handlers[self::LL_ERROR];
/* @var $handler kErrorHandlerStack */
$handler->handle($last_error['type'], $last_error['message'], $last_error['file'], $last_error['line']);
}
}
/**
* Deletes log with given id from database or disk, when database isn't available
*
* @param int $unique_id
* @param int $storage_medium
* @return void
* @access public
* @throws InvalidArgumentException
*/
public function delete($unique_id, $storage_medium = self::LS_AUTOMATIC)
{
if ( $storage_medium == self::LS_AUTOMATIC ) {
$storage_medium = $this->Conn->connectionOpened() ? self::LS_DATABASE : self::LS_DISK;
}
if ( $storage_medium == self::LS_DATABASE ) {
$sql = 'DELETE FROM ' . TABLE_PREFIX . 'SystemLog
WHERE LogUniqueId = ' . $unique_id;
$this->Conn->Query($sql);
}
elseif ( $storage_medium == self::LS_DISK ) {
// TODO: no way to delete a line from a file
}
else {
throw new InvalidArgumentException('Unknown storage medium "' . $storage_medium . '"');
}
}
/**
* Send notification (delayed or instant) about log record to e-mail from configuration
*
* @param bool $instant
* @return kLogger
* @access public
*/
public function notify($instant = false)
{
$this->_logRecord['LogNotificationStatus'] = $instant ? self::LNS_SENT : self::LNS_PENDING;
return $this;
}
/**
* Sends notification e-mail about message with given $unique_id
*
* @param int $unique_id
* @return void
* @access protected
*/
protected function _sendNotification($unique_id)
{
$notification_email = $this->Application->ConfigValue('SystemLogNotificationEmail');
if ( !$notification_email ) {
trigger_error('System Log notification E-mail not specified', E_USER_NOTICE);
return;
}
$send_params = Array (
'to_name' => $notification_email,
'to_email' => $notification_email,
);
// initialize list outside of e-mail event with right settings
$this->Application->recallObject('system-log.email', 'system-log_List', Array ('unique_id' => $unique_id));
$this->Application->emailAdmin('SYSTEM.LOG.NOTIFY', null, $send_params);
$this->Application->removeObject('system-log.email');
}
/**
* Adds error/exception handler
*
* @param string|Array $handler
* @param bool $is_exception
* @return void
* @access public
*/
public function addErrorHandler($handler, $is_exception = false)
{
$this->_handlers[$is_exception ? self::LL_CRITICAL : self::LL_ERROR]->add($handler);
}
/**
* SQL Error Handler
*
* When not debug mode, then fatal database query won't break anything.
*
* @param int $code
* @param string $msg
* @param string $sql
* @return bool
* @access public
* @throws RuntimeException
*/
public function handleSQLError($code, $msg, $sql)
{
$error_msg = self::shortenMessage(self::DB_ERROR_PREFIX . ' #' . $code . ' - ' . $msg . '. SQL: ' . trim($sql));
if ( isset($this->Application->Debugger) ) {
if ( kUtil::constOn('DBG_SQL_FAILURE') && !defined('IS_INSTALL') ) {
throw new RuntimeException($error_msg);
}
else {
$this->Application->Debugger->appendTrace();
}
}
// next line also trigger attached error handlers
trigger_error($error_msg, E_USER_WARNING);
return true;
}
/**
* Packs information about error into a single line
*
* @param string $errno
* @param bool $strip_tags
* @return string
* @access public
*/
public function toString($errno = null, $strip_tags = false)
{
if ( !isset($errno) ) {
$errno = $this->_logRecord['LogCode'];
}
$errstr = $this->_logRecord['LogMessage'];
$errfile = $this->_logRecord['LogSourceFilename'];
$errline = $this->_logRecord['LogSourceFileLine'];
- $result = '<strong>' . $errno . ': </strong>' . "{$errstr} in {$errfile} on line {$errline}";
+ if ( PHP_SAPI === 'cli' ) {
+ $result = sprintf(' [%s] ' . PHP_EOL . ' %s', $errno, $errstr);
+
+ if ( $this->_logRecord['LogBacktrace'] ) {
+ $result .= $this->printBacktrace(unserialize($this->_logRecord['LogBacktrace']));
+ }
+ }
+ else {
+ $result = '<strong>' . $errno . ': </strong>' . "{$errstr} in {$errfile} on line {$errline}";
+ }
return $strip_tags ? strip_tags($result) : $result;
}
/**
+ * Prints backtrace result
+ *
+ * @param array $trace Trace.
+ *
+ * @return string
+ */
+ protected function printBacktrace(array $trace)
+ {
+ if ( !$trace ) {
+ return '';
+ }
+
+ $ret = PHP_EOL . PHP_EOL . PHP_EOL . 'Exception trace:' . PHP_EOL;
+
+ foreach ( $trace as $trace_info ) {
+ $class = isset($trace_info['class']) ? $trace_info['class'] : '';
+ $type = isset($trace_info['type']) ? $trace_info['type'] : '';
+ $function = $trace_info['function'];
+ $args = isset($trace_info['args']) && $trace_info['args'] ? '...' : '';
+ $file = isset($trace_info['file']) ? $trace_info['file'] : 'n/a';
+ $line = isset($trace_info['line']) ? $trace_info['line'] : 'n/a';
+
+ $ret .= sprintf(' %s%s%s(%s) at %s:%s' . PHP_EOL, $class, $type, $function, $args, $file, $line);
+ }
+
+ return $ret;
+ }
+
+ /**
* Saves log to file (e.g. when not possible to save into database)
*
* @param $filename
* @return bool
* @access protected
*/
protected function _saveToFile($filename)
{
$time = adodb_date('Y-m-d H:i:s');
$log_file = new SplFileObject($filename, 'a');
return $log_file->fwrite('[' . $time . '] #' . $this->toString(null, true) . PHP_EOL) > 0;
}
/**
* Checks if log type of current log record matches given one
*
* @param int $log_type
* @param string $log_message
* @return bool
* @access public
*/
public function isLogType($log_type, $log_message = null)
{
if ( $this->_logRecord['LogType'] == $log_type ) {
return true;
}
if ( $log_type == self::LT_DATABASE ) {
if ( !isset($log_message) ) {
$log_message = $this->_logRecord['LogMessage'];
}
return strpos($log_message, self::DB_ERROR_PREFIX) !== false;
}
return false;
}
/**
* Shortens message
*
* @param string $message
* @return string
* @access public
*/
public static function shortenMessage($message)
{
$max_len = ini_get('log_errors_max_len');
if ( strlen($message) > $max_len ) {
$long_key = kUtil::generateId();
self::$_longMessages[$long_key] = $message;
return mb_substr($message, 0, $max_len - strlen($long_key) - 2) . ' #' . $long_key;
}
return $message;
}
/**
* Expands shortened message
*
* @param string $message
* @param bool $clear_cache Allow debugger to expand message after it's been expanded by kLogger
* @return string
* @access public
*/
public static function expandMessage($message, $clear_cache = true)
{
if ( preg_match('/(.*)#([\d]+)$/', $message, $regs) ) {
$long_key = $regs[2];
if ( isset(self::$_longMessages[$long_key]) ) {
$message = self::$_longMessages[$long_key];
if ( $clear_cache ) {
unset(self::$_longMessages[$long_key]);
}
}
}
return $message;
}
/**
* Parses database error message into error number, error message and sql that caused that error
*
* @static
* @param string $message
* @return Array
* @access public
*/
public static function parseDatabaseError($message)
{
$regexp = '/' . preg_quote(self::DB_ERROR_PREFIX) . ' #(.*?) - (.*?)\. SQL: (.*?)$/s';
if ( preg_match($regexp, $message, $regs) ) {
// errno, errstr, sql
return Array ($regs[1], $regs[2], $regs[3]);
}
return Array (0, $message, '');
}
}
/**
* Base class for error or exception handling
*/
abstract class kHandlerStack extends kBase {
/**
* List of added handlers
*
* @var Array
* @access protected
*/
protected $_handlers = Array ();
/**
* Reference to event log, which created this object
*
* @var kLogger
* @access protected
*/
protected $_logger;
/**
* Remembers if handler is activated
*
* @var bool
* @access protected
*/
protected $_enabled = false;
public function __construct(kLogger $logger)
{
parent::__construct();
$this->_logger = $logger;
if ( !kUtil::constOn('DBG_ZEND_PRESENT') ) {
$this->attach();
$this->_enabled = true;
}
}
/**
* Detaches from error handling routines on class destruction
*
* @return void
* @access public
*/
public function __destruct()
{
if ( !$this->_enabled ) {
return;
}
$this->detach();
$this->_enabled = false;
}
/**
* Attach to error handling routines
*
* @abstract
* @return void
* @access protected
*/
abstract protected function attach();
/**
* Detach from error handling routines
*
* @abstract
* @return void
* @access protected
*/
abstract protected function detach();
/**
* Adds new handler to the stack
*
* @param callable $handler
* @return void
* @access public
*/
public function add($handler)
{
$this->_handlers[] = $handler;
}
protected function _handleFatalError($errno)
{
$debug_mode = defined('DEBUG_MODE') && DEBUG_MODE;
$skip_reporting = defined('DBG_SKIP_REPORTING') && DBG_SKIP_REPORTING;
if ( !$this->_handlers || ($debug_mode && $skip_reporting) ) {
// when debugger absent OR it's present, but we actually can't see it's error report (e.g. during ajax request)
if ( $this->_isFatalError($errno) ) {
$this->_displayFatalError($errno);
}
if ( !$this->_handlers ) {
return true;
}
}
return null;
}
/**
* Determines if given error is a fatal
*
* @abstract
* @param Exception|int $errno
* @return bool
*/
abstract protected function _isFatalError($errno);
/**
* Displays div with given error message
*
* @param string $errno
* @return void
* @access protected
*/
protected function _displayFatalError($errno)
{
$errno = $this->_getFatalErrorTitle($errno);
$margin = $this->Application->isAdmin ? '8px' : 'auto';
- echo '<div style="background-color: #FEFFBF; margin: ' . $margin . '; padding: 10px; border: 2px solid red; text-align: center">' . $this->_logger->toString($errno) . '</div>';
+ $error_msg = $this->_logger->toString($errno, PHP_SAPI === 'cli');
+
+ if ( PHP_SAPI === 'cli' ) {
+ echo $error_msg;
+ }
+ else {
+ echo '<div style="background-color: #FEFFBF; margin: ' . $margin . '; padding: 10px; border: 2px solid red; text-align: center">' . $error_msg . '</div>';
+ }
+
exit;
}
/**
* Returns title to show for a fatal
*
* @abstract
* @param Exception|int $errno
* @return string
*/
abstract protected function _getFatalErrorTitle($errno);
}
/**
* Class, that handles errors
*/
class kErrorHandlerStack extends kHandlerStack {
/**
* Attach to error handling routines
*
* @return void
* @access protected
*/
protected function attach()
{
// set as error handler
$error_handler = set_error_handler(Array ($this, 'handle'));
if ( $error_handler ) {
// wrap around previous error handler, if any was set
$this->_handlers[] = $error_handler;
}
}
/**
* Detach from error handling routines
*
* @return void
* @access protected
*/
protected function detach()
{
restore_error_handler();
}
/**
* Determines if given error is a fatal
*
* @param int $errno
* @return bool
* @access protected
*/
protected function _isFatalError($errno)
{
$fatal_errors = Array (E_USER_ERROR, E_RECOVERABLE_ERROR, E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE);
return in_array($errno, $fatal_errors);
}
/**
* Returns title to show for a fatal
*
* @param int $errno
* @return string
* @access protected
*/
protected function _getFatalErrorTitle($errno)
{
return 'Fatal Error';
}
/**
* Default error handler
*
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
* @param Array $errcontext
* @return bool
* @access public
*/
public function handle($errno, $errstr, $errfile = null, $errline = null, $errcontext = Array ())
{
$log = $this->_logger->prepare()->addError($errno, $errstr, $errfile, $errline);
if ( $this->_handleFatalError($errno) ) {
$log->write();
return true;
}
$log->write();
$res = false;
foreach ($this->_handlers as $handler) {
$res = call_user_func($handler, $errno, $errstr, $errfile, $errline, $errcontext);
}
return $res;
}
}
/**
* Class, that handles exceptions
*/
class kExceptionHandlerStack extends kHandlerStack {
/**
* Attach to error handling routines
*
* @return void
* @access protected
*/
protected function attach()
{
// set as exception handler
$exception_handler = set_exception_handler(Array ($this, 'handle'));
if ( $exception_handler ) {
// wrap around previous exception handler, if any was set
$this->_handlers[] = $exception_handler;
}
}
/**
* Detach from error handling routines
*
* @return void
* @access protected
*/
protected function detach()
{
restore_exception_handler();
}
/**
* Determines if given error is a fatal
*
* @param Exception $errno
* @return bool
*/
protected function _isFatalError($errno)
{
return true;
}
/**
* Returns title to show for a fatal
*
* @param Exception $errno
* @return string
*/
protected function _getFatalErrorTitle($errno)
{
return get_class($errno);
}
/**
* Handles exception
*
* @param Exception $exception
* @return bool
* @access public
*/
public function handle($exception)
{
$log = $this->_logger->prepare()->addException($exception);
if ( $exception instanceof kRedirectException ) {
/* @var $exception kRedirectException */
$exception->run();
}
if ( $this->_handleFatalError($exception) ) {
$log->write();
return true;
}
$log->write();
$res = false;
foreach ($this->_handlers as $handler) {
$res = call_user_func($handler, $exception);
}
return $res;
}
}
Index: branches/5.2.x/CREDITS
===================================================================
--- branches/5.2.x/CREDITS (revision 16425)
+++ branches/5.2.x/CREDITS (revision 16426)
Property changes on: branches/5.2.x/CREDITS
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x/CREDITS:r16334
Index: branches/5.2.x/README
===================================================================
--- branches/5.2.x/README (revision 16425)
+++ branches/5.2.x/README (revision 16426)
Property changes on: branches/5.2.x/README
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x/README:r16334
Index: branches/5.2.x/index.php
===================================================================
--- branches/5.2.x/index.php (revision 16425)
+++ branches/5.2.x/index.php (revision 16426)
Property changes on: branches/5.2.x/index.php
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x/index.php:r16334
Index: branches/5.2.x/LICENSES
===================================================================
--- branches/5.2.x/LICENSES (revision 16425)
+++ branches/5.2.x/LICENSES (revision 16426)
Property changes on: branches/5.2.x/LICENSES
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x/LICENSES:r16334
Index: branches/5.2.x/INSTALL
===================================================================
--- branches/5.2.x/INSTALL (revision 16425)
+++ branches/5.2.x/INSTALL (revision 16426)
Property changes on: branches/5.2.x/INSTALL
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x/INSTALL:r16334
Index: branches/5.2.x/COPYRIGHT
===================================================================
--- branches/5.2.x/COPYRIGHT (revision 16425)
+++ branches/5.2.x/COPYRIGHT (revision 16426)
Property changes on: branches/5.2.x/COPYRIGHT
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x/COPYRIGHT:r16334
Index: branches/5.2.x/.htaccess
===================================================================
--- branches/5.2.x/.htaccess (revision 16425)
+++ branches/5.2.x/.htaccess (revision 16426)
Property changes on: branches/5.2.x/.htaccess
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x/.htaccess:r16334
Index: branches/5.2.x
===================================================================
--- branches/5.2.x (revision 16425)
+++ branches/5.2.x (revision 16426)
Property changes on: branches/5.2.x
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /in-portal/branches/5.3.x:r16334
Event Timeline
Log In to Comment