Merge pull request #268 from kijin/pr/debugger

편리한 디버그 기능 추가
This commit is contained in:
Kijin Sung 2016-02-16 14:33:44 +09:00
commit e1341584d3
42 changed files with 1693 additions and 730 deletions

View file

@ -331,9 +331,9 @@ class Context
{
ob_start();
$this->setCacheControl(-1, true);
register_shutdown_function(array($this, 'checkSessionStatus'));
$_SESSION = array();
}
register_shutdown_function('Context::close');
// set authentication information in Context and session
if(self::isInstalled())
@ -411,7 +411,7 @@ class Context
{
if(self::getSessionStatus())
{
return;
return true;
}
if($force_start || (count($_SESSION) && !headers_sent()))
{
@ -419,7 +419,9 @@ class Context
unset($_SESSION);
session_start();
$_SESSION = $tempSession;
return true;
}
return false;
}
/**
@ -429,7 +431,11 @@ class Context
*/
public static function close()
{
session_write_close();
// Check session status and close it if open.
if (self::checkSessionStatus())
{
session_write_close();
}
}
/**
@ -1468,18 +1474,39 @@ class Context
}
else
{
self::setBrowserTitle(self::getSiteTitle());
$oMessageObject = getView('message');
$oMessageObject->setHttpStatusCode(503);
$oMessageObject->setError(-1);
$oMessageObject->setMessage(_XE_SITELOCK_TITLE_);
$oMessageObject->dispMessage();
$oModuleHandler = new ModuleHandler;
$oModuleHandler->displayContent($oMessageObject);
self::displayErrorPage(_XE_SITELOCK_TITLE_, _XE_SITELOCK_MESSAGE_, 503);
}
exit;
}
/**
* Display a generic error page and exit.
*
* @param string $title
* @param string $message
* @return void
*/
public static function displayErrorPage($title = 'Error', $message = '', $status = 500)
{
// Change current directory to the Rhymix installation path.
chdir(\RX_BASEDIR);
// Set the title.
self::setBrowserTitle(self::getSiteTitle());
self::addBrowserTitle($title);
// Set the message.
$oMessageObject = getView('message');
$oMessageObject->setError(-1);
$oMessageObject->setHttpStatusCode($status);
$oMessageObject->setMessage($title);
$oMessageObject->dispMessage($message);
// Display the message.
$oModuleHandler = new ModuleHandler;
$oModuleHandler->displayContent($oMessageObject);
}
/**
* Return request method
* @return string Request method type. (Optional - GET|POST|XMLRPC|JSON)

View file

@ -364,55 +364,47 @@ class DB
$log['module'] = $site_module_info->module;
$log['act'] = Context::get('act');
$log['time'] = date('Y-m-d H:i:s');
$log['backtrace'] = array();
$bt = version_compare(PHP_VERSION, '5.3.6', '>=') ? debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS) : debug_backtrace();
foreach($bt as $no => $call)
if (config('debug.enabled') && config('debug.log_queries'))
{
if($call['function'] == 'executeQuery' || $call['function'] == 'executeQueryArray')
$bt = defined('DEBUG_BACKTRACE_IGNORE_ARGS') ? debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS) : debug_backtrace();
foreach($bt as $no => $call)
{
$call_no = $no;
$call_no++;
$log['called_file'] = $bt[$call_no]['file'].':'.$bt[$call_no]['line'];
$log['called_file'] = str_replace(_XE_PATH_ , '', $log['called_file']);
$call_no++;
$log['called_method'] = $bt[$call_no]['class'].$bt[$call_no]['type'].$bt[$call_no]['function'];
break;
}
}
// leave error log if an error occured (if __DEBUG_DB_OUTPUT__ is defined)
if($this->isError())
{
$log['result'] = 'Failed';
$log['errno'] = $this->errno;
$log['errstr'] = $this->errstr;
if(__DEBUG_DB_OUTPUT__ == 1)
{
$debug_file = _XE_PATH_ . "files/_debug_db_query.php";
$buff = array();
if(!file_exists($debug_file))
if($call['function'] == 'executeQuery' || $call['function'] == 'executeQueryArray')
{
$buff[] = '<?php exit(); ?' . '>';
$call_no = $no;
$call_no++;
$log['called_file'] = $bt[$call_no]['file'];
$log['called_line'] = $bt[$call_no]['line'];
$call_no++;
$log['called_method'] = $bt[$call_no]['class'].$bt[$call_no]['type'].$bt[$call_no]['function'];
$log['backtrace'] = array_slice($bt, $call_no, 1);
break;
}
$buff[] = print_r($log, TRUE);
@file_put_contents($log_file, implode("\n", $buff) . "\n\n", FILE_APPEND|LOCK_EX);
}
}
else
{
$log['result'] = 'Success';
$log['called_file'] = $log['called_line'] = $log['called_method'] = null;
$log['backtrace'] = array();
}
// leave error log if an error occured
if($this->isError())
{
$log['result'] = 'error';
$log['errno'] = $this->errno;
$log['errstr'] = $this->errstr;
}
else
{
$log['result'] = 'success';
$log['errno'] = null;
$log['errstr'] = null;
}
$this->setQueryLog($log);
$log_args = new stdClass;
$log_args->query = $this->query;
$log_args->query_id = $this->query_id;
$log_args->caller = $log['called_method'] . '() in ' . $log['called_file'];
$log_args->connection = $log['connection'];
writeSlowlog('query', $elapsed_time, $log_args);
}
/**
@ -422,7 +414,7 @@ class DB
*/
public function setQueryLog($log)
{
$GLOBALS['__db_queries__'][] = $log;
Rhymix\Framework\Debug::addQuery($log);
}
/**
@ -868,7 +860,7 @@ class DB
{
$this->_connect($type);
}
$this->connection = 'Master ' . $this->master_db['host'];
$this->connection = 'master (' . $this->master_db['host'] . ')';
return $this->master_db["resource"];
}
@ -883,7 +875,7 @@ class DB
{
$this->_connect($type);
}
$this->connection = 'Master ' . $this->master_db['host'];
$this->connection = 'master (' . $this->master_db['host'] . ')';
return $this->master_db["resource"];
}
@ -891,7 +883,7 @@ class DB
{
$this->_connect($type, $indx);
}
$this->connection = 'Slave ' . $this->slave_db[$indx]['host'];
$this->connection = 'slave (' . $this->slave_db[$indx]['host'] . ')';
return $this->slave_db[$indx]["resource"];
}
@ -1148,7 +1140,7 @@ class DB
$connection["is_connected"] = TRUE;
// Save connection info for db logs
$this->connection = ucfirst($type) . ' ' . $connection['host'];
$this->connection = $type . ' (' . $connection['host'] . ')';
// regist $this->close callback
register_shutdown_function(array($this, "close"));

View file

@ -971,8 +971,6 @@ class DBCubrid extends DB
return;
}
$query .= (__DEBUG_QUERY__ & 1 && $this->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : '';
$result = $this->_query($query);
if($result && !$this->transaction_started)
{
@ -1002,8 +1000,6 @@ class DBCubrid extends DB
return;
}
$query .= (__DEBUG_QUERY__ & 1 && $this->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : '';
$result = $this->_query($query);
if($result && !$this->transaction_started)
@ -1034,8 +1030,6 @@ class DBCubrid extends DB
return;
}
$query .= (__DEBUG_QUERY__ & 1 && $this->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : '';
$result = $this->_query($query);
if($result && !$this->transaction_started)
@ -1077,7 +1071,6 @@ class DBCubrid extends DB
return;
}
$query .= (__DEBUG_QUERY__ & 1 && $this->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : '';
$result = $this->_query($query, $connection);
if($this->isError())
@ -1147,7 +1140,6 @@ class DBCubrid extends DB
$count_query = sprintf('select count(*) as "count" from (%s) xet', $count_query);
}
$count_query .= (__DEBUG_QUERY__ & 1 && $queryObject->queryID) ? sprintf(' ' . $this->comment_syntax, $queryObject->queryID) : '';
$result = $this->_query($count_query, $connection);
$count_output = $this->_fetch($result);
$total_count = (int) (isset($count_output->count) ? $count_output->count : NULL);
@ -1195,7 +1187,6 @@ class DBCubrid extends DB
$start_count = ($page - 1) * $list_count;
$query = $this->getSelectPageSql($queryObject, $with_values, $start_count, $list_count);
$query .= (__DEBUG_QUERY__ & 1 && $queryObject->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : '';
$result = $this->_query($query, $connection);
if($this->isError())
{

View file

@ -943,8 +943,6 @@ class DBMssql extends DB
// TODO Decide if we continue to pass parameters like this
$this->param = $queryObject->getArguments();
$query .= (__DEBUG_QUERY__ & 1 && $output->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : '';
$result = $this->_query($query, $connection);
if($this->isError())
@ -1024,7 +1022,6 @@ class DBMssql extends DB
$count_query = sprintf('select count(*) as "count" from (%s) xet', $count_query);
}
$count_query .= (__DEBUG_QUERY__ & 1 && $queryObject->queryID) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : '';
$this->param = $queryObject->getArguments();
$result_count = $this->_query($count_query, $connection);
$count_output = $this->_fetch($result_count);

View file

@ -689,7 +689,6 @@ class DBMysql extends DB
function _executeInsertAct($queryObject, $with_values = true)
{
$query = $this->getInsertSql($queryObject, $with_values, true);
$query .= (__DEBUG_QUERY__ & 1 && $this->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : '';
if(is_a($query, 'Object'))
{
return;
@ -711,10 +710,6 @@ class DBMysql extends DB
if(!$query->toBool()) return $query;
else return;
}
$query .= (__DEBUG_QUERY__ & 1 && $this->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : '';
return $this->_query($query);
}
@ -727,7 +722,6 @@ class DBMysql extends DB
function _executeDeleteAct($queryObject, $with_values = true)
{
$query = $this->getDeleteSql($queryObject, $with_values, true);
$query .= (__DEBUG_QUERY__ & 1 && $this->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : '';
if(is_a($query, 'Object'))
{
return;
@ -759,7 +753,6 @@ class DBMysql extends DB
{
return;
}
$query .= (__DEBUG_QUERY__ & 1 && $queryObject->queryID) ? sprintf(' ' . $this->comment_syntax, $queryObject->queryID) : '';
$result = $this->_query($query, $connection);
if($this->isError())
@ -880,7 +873,6 @@ class DBMysql extends DB
$count_query = sprintf('select count(*) as "count" from (%s) xet', $count_query);
}
$count_query .= (__DEBUG_QUERY__ & 1 && $queryObject->queryID) ? sprintf(' ' . $this->comment_syntax, $queryObject->queryID) : '';
$result_count = $this->_query($count_query, $connection);
$count_output = $this->_fetch($result_count);
$total_count = (int) (isset($count_output->count) ? $count_output->count : NULL);
@ -927,7 +919,6 @@ class DBMysql extends DB
$query = $this->getSelectPageSql($queryObject, $with_values, $start_count, $list_count);
$query .= (__DEBUG_QUERY__ & 1 && $queryObject->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : '';
$result = $this->_query($query, $connection);
if($this->isError())
{

View file

@ -11,7 +11,7 @@
*/
class DisplayHandler extends Handler
{
public static $response_size = 0;
var $content_size = 0; // /< The size of displaying contents
var $gz_enabled = FALSE; // / <a flog variable whether to call contents after compressing by gzip
var $handler = NULL;
@ -78,10 +78,9 @@ class DisplayHandler extends Handler
}
// Start the session if $_SESSION was touched
Context::getInstance()->checkSessionStatus();
Context::checkSessionStatus();
// header output
$httpStatusCode = $oModule->getHttpStatusCode();
if($httpStatusCode && $httpStatusCode != 200)
{
@ -119,201 +118,118 @@ class DisplayHandler extends Handler
ini_set('zlib.output_compression', true);
}
// results directly output
print $output;
// debugOutput output
$this->content_size = strlen($output);
print $this->_debugOutput();
// call a trigger after display
self::$response_size = $this->content_size = strlen($output);
ModuleHandler::triggerCall('display', 'after', $output);
flushSlowlog();
// Output the page content and debug data.
$debug = $this->getDebugInfo($output);
print $output;
print $debug;
}
/**
* Print debugging message to designated output source depending on the value set to __DEBUG_OUTPUT_. \n
* This method only functions when __DEBUG__ variable is set to 1.
* __DEBUG_OUTPUT__ == 0, messages are written in ./files/_debug_message.php
* @return void
* Get debug information.
*
* @return string
*/
public function _debugOutput()
public function getDebugInfo(&$output)
{
if(!__DEBUG__)
// Check if debugging is enabled for this request.
if (!config('debug.enabled') || !Rhymix\Framework\Debug::isEnabledForCurrentUser())
{
return;
}
$end = microtime(true);
// Firebug console output
if(__DEBUG_OUTPUT__ == 2 && version_compare(PHP_VERSION, '6.0.0') === -1)
// Print debug information.
switch ($display_type = config('debug.display_type'))
{
static $firephp;
if(!isset($firephp))
{
$firephp = FirePHP::getInstance(true);
}
if(__DEBUG_PROTECT__ == 1 && __DEBUG_PROTECT_IP__ != $_SERVER['REMOTE_ADDR'])
{
$firephp->fb('Change the value of __DEBUG_PROTECT_IP__ into your IP address in config/config.user.inc.php or config/config.inc.php', 'The IP address is not allowed.');
return;
}
// display total execution time and Request/Response info
if(__DEBUG__ & 2)
{
$firephp->fb(
array(
'Request / Response info >>> ' . $_SERVER['REQUEST_METHOD'] . ' / ' . Context::getResponseMethod(),
array(
array('Request URI', 'Request method', 'Response method', 'Response contents size', 'Memory peak usage'),
array(
sprintf("%s:%s%s%s%s", $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $_SERVER['PHP_SELF'], $_SERVER['QUERY_STRING'] ? '?' : '', $_SERVER['QUERY_STRING']),
$_SERVER['REQUEST_METHOD'],
Context::getResponseMethod(),
$this->content_size . ' byte',
FileHandler::filesize(memory_get_peak_usage())
)
)
),
'TABLE'
);
$firephp->fb(
array(
'Elapsed time >>> Total : ' . sprintf('%0.5f sec', $end - RX_MICROTIME),
array(array('DB queries', 'class file load', 'Template compile', 'XmlParse compile', 'PHP', 'Widgets', 'Trans Content'),
array(
sprintf('%0.5f sec', $GLOBALS['__db_elapsed_time__']),
sprintf('%0.5f sec', $GLOBALS['__elapsed_class_load__']),
sprintf('%0.5f sec (%d called)', $GLOBALS['__template_elapsed__'], $GLOBALS['__TemplateHandlerCalled__']),
sprintf('%0.5f sec', $GLOBALS['__xmlparse_elapsed__']),
sprintf('%0.5f sec', $end - RX_MICROTIME - $GLOBALS['__template_elapsed__'] - $GLOBALS['__xmlparse_elapsed__'] - $GLOBALS['__db_elapsed_time__'] - $GLOBALS['__elapsed_class_load__']),
sprintf('%0.5f sec', $GLOBALS['__widget_excute_elapsed__']),
sprintf('%0.5f sec', $GLOBALS['__trans_content_elapsed__'])
)
)
),
'TABLE'
);
}
// display DB query history
if((__DEBUG__ & 4) && $GLOBALS['__db_queries__'])
{
$queries_output = array(array('Result/'.PHP_EOL.'Elapsed time', 'Query ID', 'Query'));
foreach($GLOBALS['__db_queries__'] as $query)
case 'panel':
$data = Rhymix\Framework\Debug::getDebugData();
if ($data->entries)
{
$queries_output[] = array($query['result'] . PHP_EOL . sprintf('%0.5f', $query['elapsed_time']), str_replace(_XE_PATH_, '', $query['called_file']) . PHP_EOL . $query['called_method'] . '()' . PHP_EOL . $query['query_id'], $query['query']);
}
$firephp->fb(
array(
'DB Queries >>> ' . count($GLOBALS['__db_queries__']) . ' Queries, ' . sprintf('%0.5f sec', $GLOBALS['__db_elapsed_time__']),
$queries_output
),
'TABLE'
);
}
// dislpay the file and HTML comments
}
else
{
$buff = array();
// display total execution time and Request/Response info
if(__DEBUG__ & 2)
{
if(__DEBUG_PROTECT__ == 1 && __DEBUG_PROTECT_IP__ != $_SERVER['REMOTE_ADDR'])
{
return;
}
// Request/Response information
$buff[] = "\n- Request/ Response info";
$buff[] = sprintf("\tRequest URI \t\t\t: %s:%s%s%s%s", $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $_SERVER['PHP_SELF'], $_SERVER['QUERY_STRING'] ? '?' : '', $_SERVER['QUERY_STRING']);
$buff[] = sprintf("\tRequest method \t\t\t: %s", $_SERVER['REQUEST_METHOD']);
$buff[] = sprintf("\tResponse method \t\t: %s", Context::getResponseMethod());
$buff[] = sprintf("\tResponse contents size\t: %d byte", $this->content_size);
// total execution time
$buff[] = sprintf("\n- Total elapsed time : %0.5f sec", $end - RX_MICROTIME);
$buff[] = sprintf("\tclass file load elapsed time \t: %0.5f sec", $GLOBALS['__elapsed_class_load__']);
$buff[] = sprintf("\tTemplate compile elapsed time\t: %0.5f sec (%d called)", $GLOBALS['__template_elapsed__'], $GLOBALS['__TemplateHandlerCalled__']);
$buff[] = sprintf("\tXmlParse compile elapsed time\t: %0.5f sec", $GLOBALS['__xmlparse_elapsed__']);
$buff[] = sprintf("\tPHP elapsed time \t\t\t\t: %0.5f sec", $end - RX_MICROTIME - $GLOBALS['__template_elapsed__'] - $GLOBALS['__xmlparse_elapsed__'] - $GLOBALS['__db_elapsed_time__'] - $GLOBALS['__elapsed_class_load__']);
$buff[] = sprintf("\tDB class elapsed time \t\t\t: %0.5f sec", $GLOBALS['__dbclass_elapsed_time__'] - $GLOBALS['__db_elapsed_time__']);
// widget execution time
$buff[] = sprintf("\tWidgets elapsed time \t\t\t: %0.5f sec", $GLOBALS['__widget_excute_elapsed__']);
// layout execution time
$buff[] = sprintf("\tLayout compile elapsed time \t: %0.5f sec", $GLOBALS['__layout_compile_elapsed__']);
// Widgets, the editor component replacement time
$buff[] = sprintf("\tTrans Content \t\t\t\t\t: %0.5f sec", $GLOBALS['__trans_content_elapsed__']);
}
// DB Logging
if(__DEBUG__ & 4)
{
if(__DEBUG_PROTECT__ == 1 && __DEBUG_PROTECT_IP__ != $_SERVER['REMOTE_ADDR'])
{
return;
}
if($GLOBALS['__db_queries__'])
{
$buff[] = sprintf("\n- DB Queries : %d Queries. %0.5f sec", count($GLOBALS['__db_queries__']), $GLOBALS['__db_elapsed_time__']);
$num = 0;
foreach($GLOBALS['__db_queries__'] as $query)
foreach ($data->entries as &$entry)
{
if($query['result'] == 'Success')
if (is_scalar($entry->message))
{
$query_result = "Query Success";
$entry->message = var_export($entry->message, true);
}
else
{
$query_result = sprintf("Query $s : %d\n\t\t\t %s", $query['result'], $query['errno'], $query['errstr']);
$entry->message = trim(print_r($entry->message, true));
}
$buff[] = sprintf("\t%02d. %s\n\t\t%0.6f sec. %s.", ++$num, $query['query'], $query['elapsed_time'], $query_result);
$buff[] = sprintf("\t\tConnection: %s.", $query['connection']);
$buff[] = sprintf("\t\tQuery ID: %s", $query['query_id']);
$buff[] = sprintf("\t\tCalled: %s. %s()", str_replace(_XE_PATH_, '', $query['called_file']), $query['called_method']);
}
}
}
// Output in HTML comments
if($buff && __DEBUG_OUTPUT__ == 1 && Context::getResponseMethod() == 'HTML')
{
$buff = implode("\r\n", $buff);
$buff = sprintf("[%s %s:%d]\r\n%s", date('Y-m-d H:i:s'), $file_name, $line_num, print_r($buff, true));
if(__DEBUG_PROTECT__ == 1 && __DEBUG_PROTECT_IP__ != $_SERVER['REMOTE_ADDR'])
switch (Context::getResponseMethod())
{
$buff = 'The IP address is not allowed. Change the value of __DEBUG_PROTECT_IP__ into your IP address in config/config.user.inc.php or config/config.inc.php';
case 'HTML':
$json_options = defined('JSON_PRETTY_PRINT') ? (JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) : 0;
$panel_script = sprintf('<script src="%s%s?%s"></script>', RX_BASEURL, 'common/js/debug.js', filemtime(RX_BASEDIR . 'common/js/debug.js'));
if (isset($_SESSION['_rx_debug_previous']))
{
$panel_script .= "\n<script>\nvar rhymix_debug_previous = " . json_encode($_SESSION['_rx_debug_previous'], $json_options) . ";\n</script>";
unset($_SESSION['_rx_debug_previous']);
}
$panel_script .= "\n<script>\nvar rhymix_debug_content = " . json_encode($data, $json_options) . ";\n</script>";
$body_end_position = strrpos($output, '</body>') ?: strlen($output);
$output = substr($output, 0, $body_end_position) . "\n$panel_script\n" . substr($output, $body_end_position);
return;
case 'JSON':
if (RX_POST && preg_match('/^proc/', Context::get('act')))
{
$data->ajax_module = Context::get('module');
$data->ajax_act = Context::get('act');
$_SESSION['_rx_debug_previous'] = $data;
}
else
{
unset($_SESSION['_rx_debug_previous']);
}
if (preg_match('/^(.+)\}$/', $output, $matches))
{
$output = $matches[1] . ',"_rx_debug":' . json_encode($data) . '}';
}
return;
default:
return;
}
return "<!--\r\n" . $buff . "\r\n-->";
}
// Output to a file
if($buff && __DEBUG_OUTPUT__ == 0)
{
$debug_file = _XE_PATH_ . 'files/_debug_message.php';
$buff = implode(PHP_EOL, $buff);
$buff = sprintf("[%s]\n%s", date('Y-m-d H:i:s'), print_r($buff, true));
$buff = str_repeat('=', 80) . "\n" . $buff . "\n" . str_repeat('-', 80);
$buff = "\n<?php\n/*" . $buff . "*/\n?>\n";
if (!@file_put_contents($debug_file, $buff, FILE_APPEND|LOCK_EX))
case 'comment':
case 'file':
default:
if ($display_type === 'comment' && Context::getResponseMethod() !== 'HTML')
{
return;
}
}
ob_start();
$data = Rhymix\Framework\Debug::getDebugData();
include RX_BASEDIR . 'common/tpl/debug_comment.html';
$content = ob_get_clean();
if ($display_type === 'file')
{
$log_filename = config('debug.log_filename') ?: 'files/debug/YYYYMMDD.php';
$log_filename = str_replace(array('YYYY', 'YY', 'MM', 'DD'), array(
getInternalDateTime(RX_TIME, 'Y'),
getInternalDateTime(RX_TIME, 'y'),
getInternalDateTime(RX_TIME, 'm'),
getInternalDateTime(RX_TIME, 'd'),
), $log_filename);
$log_filename = RX_BASEDIR . $log_filename;
if (!file_exists($log_filename) || !filesize($log_filename))
{
$phpheader = '<?php exit; ?>' . "\n";
}
else
{
$phpheader = '';
}
FileHandler::writeFile($log_filename, $phpheader . $content, 'a');
return '';
}
else
{
return '<!--' . PHP_EOL . $content . PHP_EOL . '-->';
}
}
}

View file

@ -86,10 +86,7 @@ class HTMLDisplayHandler
if(Context::get('layout') != 'none')
{
if(__DEBUG__ == 3)
{
$start = microtime(true);
}
$start = microtime(true);
Context::set('content', $output, false);
@ -142,10 +139,7 @@ class HTMLDisplayHandler
$pathInfo = pathinfo($layout_file);
$onlyLayoutFile = $pathInfo['filename'];
if(__DEBUG__ == 3)
{
$GLOBALS['__layout_compile_elapsed__'] = microtime(true) - $start;
}
$GLOBALS['__layout_compile_elapsed__'] = microtime(true) - $start;
if(stripos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE && (Context::get('_use_ssl') == 'optional' || Context::get('_use_ssl') == 'always'))
{
@ -168,10 +162,7 @@ class HTMLDisplayHandler
return;
}
if(__DEBUG__ == 3)
{
$start = microtime(true);
}
$start = microtime(true);
// move <style ..></style> in body to the header
$output = preg_replace_callback('!<style(.*?)>(.*?)<\/style>!is', array($this, '_moveStyleToHeader'), $output);
@ -218,10 +209,7 @@ class HTMLDisplayHandler
$output = preg_replace_callback('@<textarea[^>]*\sname="' . $keys . '".+</textarea>@isU', array(&$this, '_preserveTextAreaValue'), $output);
}
if(__DEBUG__ == 3)
{
$GLOBALS['__trans_content_elapsed__'] = microtime(true) - $start;
}
$GLOBALS['__trans_content_elapsed__'] = microtime(true) - $start;
// Remove unnecessary information
$output = preg_replace('/member\_\-([0-9]+)/s', 'member_0', $output);

View file

@ -750,7 +750,6 @@ class ModuleHandler extends Handler
$message = $oModule->getMessage();
$messageType = $oModule->getMessageType();
$redirectUrl = $oModule->getRedirectUrl();
if($messageType == 'error') debugPrint($message, 'ERROR');
if(!$procResult)
{
@ -885,10 +884,6 @@ class ModuleHandler extends Handler
if($_SESSION['XE_VALIDATOR_RETURN_URL'])
{
$display_handler = new DisplayHandler();
$display_handler->_debugOutput();
Context::getInstance()->checkSessionStatus();
header('location:' . $_SESSION['XE_VALIDATOR_RETURN_URL']);
return;
}
@ -1066,12 +1061,6 @@ class ModuleHandler extends Handler
* */
public static function getModuleInstance($module, $type = 'view', $kind = '')
{
if(__DEBUG__ == 3)
{
$start_time = microtime(true);
}
$parent_module = $module;
$kind = strtolower($kind);
$type = strtolower($type);
@ -1135,11 +1124,6 @@ class ModuleHandler extends Handler
$GLOBALS['_loaded_module'][$module][$type][$kind] = $oModule;
}
if(__DEBUG__ == 3)
{
$GLOBALS['__elapsed_class_load__'] += microtime(true) - $start_time;
}
// return the instance
return $GLOBALS['_loaded_module'][$module][$type][$kind];
}
@ -1199,11 +1183,7 @@ class ModuleHandler extends Handler
}
//store before trigger call time
$before_trigger_time = NULL;
if(__LOG_SLOW_TRIGGER__> 0)
{
$before_trigger_time = microtime(true);
}
$before_trigger_time = microtime(true);
foreach($triggers as $item)
{
@ -1219,17 +1199,20 @@ class ModuleHandler extends Handler
}
$before_each_trigger_time = microtime(true);
$output = $oModule->{$called_method}($obj);
$after_each_trigger_time = microtime(true);
$elapsed_time_trigger = $after_each_trigger_time - $before_each_trigger_time;
$slowlog = new stdClass;
$slowlog->caller = $trigger_name . '.' . $called_position;
$slowlog->called = $module . '.' . $called_method;
$slowlog->called_extension = $module;
if($trigger_name != 'XE.writeSlowlog') writeSlowlog('trigger', $elapsed_time_trigger, $slowlog);
if ($trigger_name !== 'common.flushDebugInfo')
{
$trigger_target = $module . ($type === 'class' ? '' : $type) . '.' . $called_method;
Rhymix\Framework\Debug::addTrigger(array(
'name' => $trigger_name . '.' . $called_position,
'target' => $trigger_target,
'target_plugin' => $module,
'elapsed_time' => $after_each_trigger_time - $before_each_trigger_time,
));
}
if(is_object($output) && method_exists($output, 'toBool') && !$output->toBool())
{
@ -1241,7 +1224,39 @@ class ModuleHandler extends Handler
$trigger_functions = $oModuleModel->getTriggerFunctions($trigger_name, $called_position);
foreach($trigger_functions as $item)
{
$before_each_trigger_time = microtime(true);
$item($obj);
$after_each_trigger_time = microtime(true);
if ($trigger_name !== 'common.writeSlowlog')
{
if (is_string($item))
{
$trigger_target = $item;
}
elseif (is_array($item) && count($item))
{
if (is_object($item[0]))
{
$trigger_target = get_class($item[0]) . '.' . strval($item[1]);
}
else
{
$trigger_target = implode('.', $item);
}
}
else
{
$trigger_target = 'closure';
}
Rhymix\Framework\Debug::addTrigger(array(
'name' => $trigger_name . '.' . $called_position,
'target' => $trigger_target,
'target_plugin' => null,
'elapsed_time' => $after_each_trigger_time - $before_each_trigger_time,
));
}
if(is_object($output) && method_exists($output, 'toBool') && !$output->toBool())
{

View file

@ -384,7 +384,6 @@ class ModuleObject extends Object
// pass if stop_proc is true
if($this->stop_proc)
{
debugPrint($this->message, 'ERROR');
return FALSE;
}

View file

@ -42,16 +42,13 @@ class TemplateHandler
{
static $oTemplate = NULL;
if(__DEBUG__ == 3)
if(!isset($GLOBALS['__TemplateHandlerCalled__']))
{
if(!isset($GLOBALS['__TemplateHandlerCalled__']))
{
$GLOBALS['__TemplateHandlerCalled__'] = 1;
}
else
{
$GLOBALS['__TemplateHandlerCalled__']++;
}
$GLOBALS['__TemplateHandlerCalled__'] = 1;
}
else
{
$GLOBALS['__TemplateHandlerCalled__']++;
}
if(!$oTemplate)
@ -118,10 +115,7 @@ class TemplateHandler
public function compile($tpl_path, $tpl_filename, $tpl_file = '')
{
// store the starting time for debug information
if(__DEBUG__ == 3)
{
$start = microtime(true);
}
$start = microtime(true);
// initiation
$this->init($tpl_path, $tpl_filename, $tpl_file);
@ -155,10 +149,7 @@ class TemplateHandler
}
// store the ending time for debug information
if(__DEBUG__ == 3)
{
$GLOBALS['__template_elapsed__'] += microtime(true) - $start;
}
$GLOBALS['__template_elapsed__'] += microtime(true) - $start;
return $output;
}

View file

@ -89,10 +89,7 @@ class XmlParser
function parse($input = '', $arg1 = NULL, $arg2 = NULL)
{
// Save the compile starting time for debugging
if(__DEBUG__ == 3)
{
$start = microtime(true);
}
$start = microtime(true);
$this->lang = Context::getLangType();
@ -141,10 +138,7 @@ class XmlParser
$output = array_shift($this->output);
// Save compile starting time for debugging
if(__DEBUG__ == 3)
{
$GLOBALS['__xmlparse_elapsed__'] += microtime(true) - $start;
}
$GLOBALS['__xmlparse_elapsed__'] += microtime(true) - $start;
return $output;
}

View file

@ -3,7 +3,7 @@
/**
* Set error reporting rules.
*/
error_reporting(E_ALL ^ E_WARNING ^ E_NOTICE ^ E_STRICT ^ E_DEPRECATED);
error_reporting(E_ALL ^ E_NOTICE ^ E_STRICT ^ E_DEPRECATED);
/**
* Suppress date/time errors until the internal time zone is set (see below).
@ -42,11 +42,6 @@ if(file_exists(RX_BASEDIR . 'config/config.user.inc.php'))
require_once RX_BASEDIR . 'config/config.user.inc.php';
}
/**
* Load legacy debug settings.
*/
require_once __DIR__ . '/debug.php';
/**
* Define the list of legacy class names for the autoloader.
*/
@ -198,6 +193,11 @@ require_once RX_BASEDIR . 'vendor/autoload.php';
*/
Rhymix\Framework\Config::init();
/**
* Install the debugger.
*/
Rhymix\Framework\Debug::registerErrorHandlers(error_reporting());
/**
* Set the internal timezone.
*/

View file

@ -133,6 +133,8 @@ define('_XE_PACKAGE_', 'XE');
define('_XE_LOCATION_', 'en');
define('_XE_LOCATION_SITE_', 'https://www.xpressengine.com/');
define('_XE_DOWNLOAD_SERVER_', 'https://download.xpressengine.com/');
define('__PROXY_SERVER__', null);
define('__DEBUG__', 0);
/**
* Other useful constants.

View file

@ -290,3 +290,142 @@ button.btn {
.btn-group>.btn.active {
z-index: 2;
}
/* Debug */
#rhymix_debug_button {
position: fixed;
left: 0; bottom: 40px;
background: #eeeeee;
background: linear-gradient(to bottom, #f4f4f4 0%, #eaeaea 100%);
border: 1px solid #ccc; border-left: 0;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
box-shadow: 0 0 3px 0 rgba(0, 0, 0, 0.18), 0 0 6px 0 rgba(0, 0, 0, 0.12);
z-index: 1073741824;
}
#rhymix_debug_button:hover {
background: #dddddd;
background: linear-gradient(to bottom, #e8e8e8 0%, #d9d9d9 100%);
}
#rhymix_debug_button a {
display: block;
font: bold 12px/14px Arial, sans-serif;
color: #444;
text-decoration: none;
padding: 4px 8px;
}
#rhymix_debug_button a.has_errors {
color: #f44336;
}
#rhymix_debug_panel {
display: none;
position: fixed;
left: 0; top: 0;
max-width: 100%;
height: 100%;
overflow-y: scroll;
background: #fcfcfc;
box-sizing: border-box;
border-right: 1px solid #ccc;
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.18), 0 0 8px 0 rgba(0, 0, 0, 0.12);
z-index: 1073741824;
}
#rhymix_debug_panel .debug_header {
clear: both;
width: 100%;
height: 36px;
background: #444444;
background: linear-gradient(to right, #222222 0%, #444444 40%, #eeeeee 100%);
position: relative;
}
#rhymix_debug_panel .debug_header h2 {
font: bold 16px/20px Arial, sans-serif;
color: #fcfcfc;
position: absolute;
left: 10px; top: 10px;
margin: 0; padding: 0;
}
#rhymix_debug_panel .debug_header .debug_maximize {
font: normal 20px/24px Arial, sans-serif;
text-decoration: none;
color: #444444;
position: absolute;
right: 32px; top: 6px;
}
#rhymix_debug_panel .debug_header .debug_close {
font: normal 28px/28px Arial, sans-serif;
text-decoration: none;
color: #444444;
position: absolute;
right: 10px; top: 4px;
}
#rhymix_debug_panel .debug_header .debug_close:hover {
color: #f44336;
}
#rhymix_debug_panel .debug_page {
clear: both;
margin: 12px 10px;
font: normal 12px/16px Arial, NanumBarunGothic, NanumGothic, "Malgun Gothic", sans-serif;
}
#rhymix_debug_panel .debug_page .debug_page_header {
padding-bottom: 8px;
border-bottom: 1px solid #ddd;
position: relative;
cursor: pointer;
}
#rhymix_debug_panel .debug_page .debug_page_header h3 {
color: #444;
font: inherit;
font-size: 14px;
font-weight: bold;
margin: 0;
padding: 0;
}
#rhymix_debug_panel .debug_page .debug_page_collapse {
display: block;
position: absolute;
right: 0; top: 0;
color: #999;
font-size: 10px;
line-height: 12px;
text-decoration: none;
padding: 2px 2px;
}
#rhymix_debug_panel .debug_page .debug_page_body {
margin: 8px 4px 8px 10px;
}
#rhymix_debug_panel .debug_page .debug_page_body h4 {
color: #444;
font: inherit;
font-size: 13px;
font-weight: bold;
margin: 0 0 8px 0;
padding: 0;
}
#rhymix_debug_panel .debug_page .debug_entry {
font-family: Consolas, "Courier New", monospace;
color: #444;
margin-left: 38px;
margin-bottom: 8px;
text-indent: -28px;
word-wrap: break-word;
word-break: break-all;
}
#rhymix_debug_panel .debug_page .debug_entry.pre_wrap {
white-space: pre-wrap;
}
#rhymix_debug_panel .debug_page .debug_entry ul.debug_metadata {
margin: 0 0 0 -16px; padding: 0;
}
#rhymix_debug_panel .debug_page .debug_entry ul.debug_metadata li {
list-style: disc;
margin: 0; padding: 0; text-indent: 0;
}
#rhymix_debug_panel .debug_page .debug_entry ul.debug_backtrace {
margin: 4px 0 0 16px; padding: 0;
}
#rhymix_debug_panel .debug_page .debug_entry ul.debug_backtrace li {
list-style: disc;
margin: 0; padding: 0; text-indent: 0;
color: #888;
}

View file

@ -1,149 +0,0 @@
<?php
/**
* Legacy debug settings for XE Compatibility
*
* Copyright (c) NAVER <http://www.navercorp.com>
*/
/**
* output debug message (bit value)
*
* 0: generate debug messages/not display
* 1: display messages through debugPrint() function
* 2: output execute time, Request/Response info
* 4: output DB query history
*/
if(!defined('__DEBUG__'))
{
define('__DEBUG__', 0);
}
/**
* output location of debug message
*
* 0: connect to the files/_debug_message.php and output
* 1: HTML output as a comment on the bottom (when response method is the HTML)
* 2: Firebug console output (PHP 4 & 5. Firebug/FirePHP plug-in required)
*/
if(!defined('__DEBUG_OUTPUT__'))
{
define('__DEBUG_OUTPUT__', 0);
}
/**
* output comments of the firePHP console and browser
*
* 0: No limit (not recommended)
* 1: Allow only specified IP addresses
*/
if(!defined('__DEBUG_PROTECT__'))
{
define('__DEBUG_PROTECT__', 1);
}
/**
* Set a ip address to allow debug
*/
if(!defined('__DEBUG_PROTECT_IP__'))
{
define('__DEBUG_PROTECT_IP__', '127.0.0.1');
}
/**
* DB error message definition
*
* 0: No output
* 1: files/_debug_db_query.php connected to the output
*/
if(!defined('__DEBUG_DB_OUTPUT__'))
{
define('__DEBUG_DB_OUTPUT__', 0);
}
/**
* Query log for only timeout query among DB queries
*
* 0: Do not leave a log
* > 0: leave a log when the slow query takes over specified seconds
* Log file is saved as ./files/_slowlog_query.php file
*/
if(!defined('__LOG_SLOW_QUERY__'))
{
define('__LOG_SLOW_QUERY__', 0);
}
/**
* Trigger excute time log
*
* 0: Do not leave a log
* > 0: leave a log when the trigger takes over specified milliseconds
* Log file is saved as ./files/_slowlog_trigger.php
*/
if(!defined('__LOG_SLOW_TRIGGER__'))
{
define('__LOG_SLOW_TRIGGER__', 0);
}
/**
* Addon excute time log
*
* 0: Do not leave a log
* > 0: leave a log when the trigger takes over specified milliseconds
* Log file is saved as ./files/_slowlog_addon.php
*/
if(!defined('__LOG_SLOW_ADDON__'))
{
define('__LOG_SLOW_ADDON__', 0);
}
/**
* Widget excute time log
*
* 0: Do not leave a log
* > 0: leave a log when the widget takes over specified milliseconds
* Log file is saved as ./files/_slowlog_widget.php
*/
if(!defined('__LOG_SLOW_WIDGET__'))
{
define('__LOG_SLOW_WIDGET__', 0);
}
/**
* output comments of the slowlog files
*
* 0: No limit (not recommended)
* 1: Allow only specified IP addresses
*/
if(!defined('__LOG_SLOW_PROTECT__'))
{
define('__LOG_SLOW_PROTECT__', 1);
}
/**
* Set a ip address to allow slowlog
*/
if(!defined('__LOG_SLOW_PROTECT_IP__'))
{
define('__LOG_SLOW_PROTECT_IP__', '127.0.0.1');
}
/**
* Leave DB query information
*
* 0: Do not add information to the query
* 1: Comment the XML Query ID
*/
if(!defined('__DEBUG_QUERY__'))
{
define('__DEBUG_QUERY__', 0);
}
/**
* __PROXY_SERVER__ has server information to request to the external through the target server
* FileHandler:: getRemoteResource uses the constant
*/
if(!defined('__PROXY_SERVER__'))
{
define('__PROXY_SERVER__', NULL);
}

View file

@ -89,9 +89,10 @@ return array(
'enabled' => true,
'log_errors' => true,
'log_queries' => false,
'log_slow_queries' => 1,
'log_slow_triggers' => 1,
'log_slow_widgets' => 1,
'log_slow_queries' => 0,
'log_slow_triggers' => 0,
'log_slow_widgets' => 0,
'log_filename' => null,
'display_type' => 'comment',
'display_to' => 'admin',
'allow' => array(),

View file

@ -216,14 +216,6 @@ class ConfigParser
}
$config['lock']['allow'] = array_values($db_info->sitelock_whitelist);
// Convert debug configuration.
$config['debug']['enabled'] = true;
$config['debug']['log_errors'] = true;
$config['debug']['log_queries'] = (\__DEBUG__ & 4) ? true : false;
$config['debug']['log_slow_queries'] = floatval(\__LOG_SLOW_QUERY__);
$config['debug']['log_slow_triggers'] = floatval(\__LOG_SLOW_TRIGGER__ * 1000);
$config['debug']['log_slow_widgets'] = floatval(\__LOG_SLOW_WIDGET__ * 1000);
// Convert embed filter configuration.
if (is_array($db_info->embed_white_iframe))
{

564
common/framework/debug.php Normal file
View file

@ -0,0 +1,564 @@
<?php
namespace Rhymix\Framework;
/**
* The debug class.
*/
class Debug
{
/**
* Store log entries here.
*/
protected static $_aliases = array();
protected static $_entries = array();
protected static $_errors = array();
protected static $_queries = array();
protected static $_slow_queries = array();
protected static $_triggers = array();
protected static $_slow_triggers = array();
protected static $_widgets = array();
protected static $_slow_widgets = array();
/**
* Also write to error log.
*/
public static $write_to_error_log = true;
/**
* Get all entries.
*
* @return array
*/
public static function getEntries()
{
return self::$_entries;
}
/**
* Get all errors.
*
* @return array
*/
public static function getErrors()
{
return self::$_errors;
}
/**
* Get all queries.
*
* @return array
*/
public static function getQueries()
{
return self::$_queries;
}
/**
* Get all slow queries.
*
* @return array
*/
public static function getSlowQueries()
{
return self::$_slow_queries;
}
/**
* Get all triggers.
*
* @return array
*/
public static function getTriggers()
{
return self::$_triggers;
}
/**
* Get all slow triggers.
*
* @return array
*/
public static function getSlowTriggers()
{
return self::$_slow_triggers;
}
/**
* Get all widgets.
*
* @return array
*/
public static function getWidgets()
{
return self::$_widgets;
}
/**
* Get all slow widgets.
*
* @return array
*/
public static function getSlowWidgets()
{
return self::$_slow_widgets;
}
/**
* Add a filename alias.
*
* @param string $display_filename
* @param string $real_filename
* @return void
*/
public static function addFilenameAlias($display_filename, $real_filename)
{
self::$_aliases[$real_filename] = $display_filename;
}
/**
* Add an arbitrary entry to the log.
*
* @param string $message
* @return void
*/
public static function addEntry($message)
{
// Get the backtrace.
$backtrace_args = defined('\DEBUG_BACKTRACE_IGNORE_ARGS') ? \DEBUG_BACKTRACE_IGNORE_ARGS : 0;
$backtrace = debug_backtrace($backtrace_args);
if (count($backtrace) > 1 && $backtrace[1]['function'] === 'debugPrint' && !$backtrace[1]['class'])
{
array_shift($backtrace);
}
// Create a log entry.
$entry = (object)array(
'type' => 'Debug',
'time' => microtime(true),
'message' => $message,
'file' => isset($backtrace[0]['file']) ? $backtrace[0]['file'] : null,
'line' => isset($backtrace[0]['line']) ? $backtrace[0]['line'] : 0,
'backtrace' => $backtrace,
);
self::$_entries[] = $entry;
// Add the entry to the error log.
if (self::$write_to_error_log)
{
$log_entry = str_replace("\0", '', sprintf('Rhymix Debug: %s in %s on line %d',
var_export($message, true), $entry->file, $entry->line));
error_log($log_entry);
}
}
/**
* Add a PHP error to the log.
*
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
* @param array $errcontext
* @return void
*/
public static function addError($errno, $errstr, $errfile, $errline, $errcontext)
{
// Do not handle error types that we were told to ignore.
if (!($errno & error_reporting()))
{
return;
}
// Rewrite the error message with relative paths.
$message = str_replace(array(
' called in ' . RX_BASEDIR,
' defined in ' . RX_BASEDIR,
), array(
' called in ',
' defined in ',
), $errstr);
// Get the backtrace.
$backtrace_args = defined('\DEBUG_BACKTRACE_IGNORE_ARGS') ? \DEBUG_BACKTRACE_IGNORE_ARGS : 0;
$backtrace = debug_backtrace($backtrace_args);
// Prepare the error entry.
self::$_errors[] = $errinfo = (object)array(
'type' => self::getErrorType($errno),
'time' => microtime(true),
'message' => $message,
'file' => $errfile,
'line' => $errline,
'backtrace' => $backtrace,
);
// Add the entry to the error log.
if (self::$write_to_error_log)
{
$log_entry = str_replace("\0", '', sprintf('PHP %s: %s in %s on line %d',
$errinfo->type, $errstr, $errfile, intval($errline)));
error_log($log_entry);
}
}
/**
* Add a query to the log.
*
* @return void
*/
public static function addQuery($query)
{
$query_object = (object)array(
'type' => 'Query',
'time' => microtime(true),
'message' => $query['result'] === 'success' ? 'success' : $query['errstr'],
'error_code' => $query['result'] === 'success' ? 0 : $query['errno'],
'query_id' => $query['query_id'],
'query_connection' => $query['connection'],
'query_string' => $query['query'],
'query_time' => $query['elapsed_time'],
'file' => $query['called_file'],
'line' => $query['called_line'],
'method' => $query['called_method'],
'backtrace' => $query['backtrace'],
);
self::$_queries[] = $query_object;
if ($query_object->query_time && $query_object->query_time >= config('debug.log_slow_queries'))
{
self::$_slow_queries[] = $query_object;
}
}
/**
* Add a trigger to the log.
*
* @return bool
*/
public static function addTrigger($trigger)
{
$trigger_object = (object)array(
'type' => 'Trigger',
'time' => microtime(true),
'message' => null,
'file' => null,
'line' => null,
'backtrace' => array(),
'trigger_name' => $trigger['name'],
'trigger_target' => $trigger['target'],
'trigger_plugin' => $trigger['target_plugin'],
'trigger_time' => $trigger['elapsed_time'],
);
self::$_triggers[] = $trigger_object;
if ($trigger_object->trigger_time && $trigger_object->trigger_time >= config('debug.log_slow_triggers'))
{
self::$_slow_triggers[] = $trigger_object;
}
}
/**
* Add a widget to the log.
*
* @return bool
*/
public static function addWidget($widget)
{
$widget_object = (object)array(
'type' => 'Widget',
'time' => microtime(true),
'message' => null,
'file' => null,
'line' => null,
'backtrace' => array(),
'widget_name' => $widget['name'],
'widget_time' => $widget['elapsed_time'],
);
self::$_widgets[] = $widget_object;
if ($widget_object->widget_time && $widget_object->widget_time >= config('debug.log_slow_widgets'))
{
self::$_slow_widgets[] = $widget_object;
}
}
/**
* The default handler for catching exceptions.
*
* @param Exception $e
* @return void
*/
public static function exceptionHandler($e)
{
// Find out the file where the error really occurred.
$errfile = self::translateFilename($e->getFile());
// If the exception was thrown in a Rhymix Framework class, find out where that class was called.
$backtrace = $e->getTrace();
$caller_errfile = $errfile;
$caller_errline = $e->getLine();
while (preg_match('#^(classes|common)/#i', $caller_errfile))
{
$trace = array_shift($backtrace);
if (!$trace)
{
$caller_errfile = $caller_errline = null;
}
else
{
$caller_errfile = self::translateFilename($trace['file']);
$caller_errline = $trace['line'];
}
}
// Add the exception to the error log.
if ($caller_errfile && $caller_errfile !== $errfile)
{
$log_entry = str_replace("\0", '', sprintf('%s #%d "%s" in %s on line %d (via %s on line %d)',
get_class($e), $e->getCode(), $e->getMessage(), $caller_errfile, $caller_errline, $errfile, $e->getLine()));
}
else
{
$log_entry = str_replace("\0", '', sprintf('%s #%d "%s" in %s on line %d',
get_class($e), $e->getCode(), $e->getMessage(), $errfile, $e->getLine()));
}
error_log('PHP Exception: ' . $log_entry . "\n" . str_replace("\0", '', $e->getTraceAsString()));
// Display the error screen.
self::displayErrorScreen($log_entry);
exit;
}
/**
* The default handler for catching fatal errors.
*
* @return void
*/
public static function shutdownHandler()
{
// Check if we are exiting because of a fatal error.
$errinfo = error_get_last();
if ($errinfo === null || ($errinfo['type'] !== 1 && $errinfo['type'] !== 4))
{
return;
}
// Find out the file where the error really occurred.
$errinfo['file'] = self::translateFilename($errinfo['file']);
// Add the entry to the error log.
$message = sprintf('%s in %s on line %d', $errinfo['message'], $errinfo['file'], intval($errinfo['line']));
$log_entry = str_replace("\0", '', 'PHP ' . self::getErrorType($errinfo['type']) . ': ' . $message);
error_log($log_entry);
// Display the error screen.
self::displayErrorScreen($log_entry);
}
/**
* Translate filenames.
*
* @param string $filename
* @return string
*/
public static function translateFilename($filename)
{
if (isset(self::$_aliases[$filename]))
{
$filename = self::$_aliases[$filename];
}
if (!strncmp($filename, \RX_BASEDIR, strlen(\RX_BASEDIR)))
{
$filename = substr($filename, strlen(\RX_BASEDIR));
}
return $filename;
}
/**
* Register all error handlers.
*
* @return void
*/
public static function registerErrorHandlers($error_types)
{
if (Config::get('debug.enabled'))
{
set_error_handler('\\Rhymix\\Framework\\Debug::addError', $error_types);
}
set_exception_handler('\\Rhymix\\Framework\\Debug::exceptionHandler');
register_shutdown_function('\\Rhymix\\Framework\\Debug::shutdownHandler');
}
/**
* Display a fatal error screen.
*
* @param string $message
* @return void
*/
public static function displayErrorScreen($message)
{
// Disable output buffering.
while (ob_get_level())
{
ob_end_clean();
}
// Localize the error title.
$title = \Context::getLang('msg_server_error');
if ($title === 'msg_server_error')
{
$message = 'Server Error';
}
// Localize the error message.
$message = ini_get('display_errors') ? $message : \Context::getLang('msg_server_error_see_log');
if ($message === 'msg_server_error_see_log')
{
$message = 'Your server is configured to hide error messages. Please see your server\'s error log for details.';
}
// Display a generic error page.
\Context::displayErrorPage($title, $message, 500);
}
/**
* Check if debugging is enabled for the current user.
*
* @return bool
*/
public static function isEnabledForCurrentUser()
{
static $cache = null;
if ($cache !== null)
{
return $cache;
}
if (!Config::get('debug.enabled'))
{
return $cache = false;
}
$display_to = Config::get('debug.display_to');
switch ($display_to)
{
case 'everyone':
return $cache = true;
case 'ip':
$allowed_ip = Config::get('debug.allow');
foreach ($allowed_ip as $range)
{
if (IpFilter::inRange(RX_CLIENT_IP, $range))
{
return $cache = true;
}
}
return $cache = false;
case 'admin':
default:
$logged_info = \Context::get('logged_info');
if ($logged_info && $logged_info->is_admin === 'Y')
{
return $cache = true;
}
return $cache = false;
}
}
/**
* Get all debug information as an object.
*
* @return object
*/
public static function getDebugData()
{
// Collect debug information.
$data = (object)array(
'timestamp' => DateTime::formatTimestamp('Y-m-d H:i:s', RX_TIME),
'url' => getCurrentPageUrl(),
'request' => (object)array(
'method' => $_SERVER['REQUEST_METHOD'] . ($_SERVER['REQUEST_METHOD'] !== \Context::getRequestMethod() ? (' (' . \Context::getRequestMethod() . ')') : ''),
'size' => intval($_SERVER['CONTENT_LENGTH']),
),
'response' => (object)array(
'method' => \Context::getResponseMethod(),
'size' => \DisplayHandler::$response_size,
),
'timing' => (object)array(
'total' => sprintf('%0.4f sec', microtime(true) - \RX_MICROTIME),
'template' => sprintf('%0.4f sec (count: %d)', $GLOBALS['__template_elapsed__'], $GLOBALS['__TemplateHandlerCalled__']),
'xmlparse' => sprintf('%0.4f sec', $GLOBALS['__xmlparse_elapsed__']),
'db_query' => sprintf('%0.4f sec (count: %d)', $GLOBALS['__db_elapsed_time__'], count(self::$_queries)),
'db_class' => sprintf('%0.4f sec', $GLOBALS['__dbclass_elapsed_time__'] - $GLOBALS['__db_elapsed_time__']),
'layout' => sprintf('%0.4f sec', $GLOBALS['__layout_compile_elapsed__']),
'widget' => sprintf('%0.4f sec', $GLOBALS['__widget_excute_elapsed__']),
'trans' => sprintf('%0.4f sec', $GLOBALS['__trans_content_elapsed__']),
),
'entries' => self::$_entries,
'errors' => config('debug.log_errors') ? self::$_errors : null,
'queries' => config('debug.log_queries') ? self::$_queries : null,
'slow_queries' => self::$_slow_queries,
'slow_triggers' => self::$_slow_triggers,
'slow_widgets' => self::$_slow_widgets,
);
// Clean up the backtrace.
foreach (array('entries', 'errors', 'queries', 'slow_queries') as $key)
{
if (!$data->$key)
{
continue;
}
foreach ($data->$key as &$entry)
{
if (isset($entry->file))
{
$entry->file = self::translateFilename($entry->file);
}
if (isset($entry->backtrace) && is_array($entry->backtrace))
{
foreach ($entry->backtrace as &$backtrace)
{
$backtrace['file'] = self::translateFilename($backtrace['file']);
unset($backtrace['object'], $backtrace['args']);
}
}
}
}
return $data;
}
/**
* Convert a PHP error number to the corresponding error name.
*
* @param int $errno
* @return string
*/
public static function getErrorType($errno)
{
switch ($errno)
{
case \E_ERROR: return 'Fatal Error';
case \E_WARNING: return 'Warning';
case \E_NOTICE: return 'Notice';
case \E_CORE_ERROR: return 'Core Error';
case \E_CORE_WARNING: return 'Core Warning';
case \E_COMPILE_ERROR: return 'Compile-time Error';
case \E_COMPILE_WARNING: return 'Compile-time Warning';
case \E_USER_ERROR: return 'User Error';
case \E_USER_WARNING: return 'User Warning';
case \E_USER_NOTICE: return 'User Notice';
case \E_STRICT: return 'Strict Standards';
case \E_PARSE: return 'Parse Error';
case \E_DEPRECATED: return 'Deprecated';
case \E_USER_DEPRECATED: return 'User Deprecated';
case \E_RECOVERABLE_ERROR: return 'Catchable Fatal Error';
default: return 'Error';
}
}
}

View file

@ -28,6 +28,9 @@
}
});
/* Array for pending debug data */
window.rhymix_debug_pending_data = [];
/**
* @brief XE 공용 유틸리티 함수
* @namespace XE

200
common/js/debug.js Normal file
View file

@ -0,0 +1,200 @@
/**
* Client-side script for manipulating the debug panel on Rhymix.
*
* @file debug.js
* @author Kijin Sung <kijin@kijinsung.com>
*/
$(function() {
"use strict";
// Find debug panel elements.
var panel = $("#rhymix_debug_panel");
var button = $("#rhymix_debug_button");
// Initialize the debug button.
var button_link = $('<a href="#"></a>').text("DEBUG").appendTo(button).click(function(event) {
event.preventDefault();
var max_width = Math.min(540, $(window).width());
panel.css({ width: max_width, left: max_width * -1 }).show().animate({ left: 0 }, 200);
button.hide();
});
// Initialize the debug panel.
var header = $('<div class="debug_header"></div>').appendTo(panel);
header.append('<h2>RHYMIX DEBUG</h2>');
header.append($('<a class="debug_maximize" href="#">+</a>').click(function(event) {
panel.animate({ width: "100%" }, 300);
}));
header.append($('<a class="debug_close" href="#">&times;</a>').click(function(event) {
event.preventDefault();
panel.animate({ left: panel.width() * -1 }, 200, function() {
panel.hide();
button.show();
});
}));
// Define a function for adding debug data to the panel.
window.rhymix_debug_add_data = function(data, open) {
// Define loop variables.
var i, j, entry, num, backtrace, description;
// New pages are open by default.
if (open !== true && open !== false)
{
open = true;
}
// Create the page.
var page = $('<div class="debug_page"></div>').appendTo(panel);
var page_body = $('<div class="debug_page_body"></div>').appendTo(page);
if (!open)
{
page_body.hide();
}
// Create the page header.
var page_header = $('<div class="debug_page_header"></div>').prependTo(page).click(function() {
$(this).find("a.debug_page_collapse").triggerHandler("click");
});
page_header.append($('<h3></h3>').text(data.page_title).attr("title", data.url));
page_header.append($('<a class="debug_page_collapse" href="#"></a>').text(open ? "▲" : "▼").click(function(event) {
event.preventDefault();
event.stopPropagation();
if (page_body.is(":visible")) {
page_body.slideUp(200);
$(this).text("▼");
} else {
page_body.slideDown(200);
$(this).text("▲");
}
}));
// Add general information.
page_body.append($('<h4></h4>').text('General Information'));
entry = $('<div class="debug_entry"></div>').appendTo(page_body);
var metadata = $('<ul class="debug_metadata"></ul>').appendTo(entry);
metadata.append($('<li></li>').text('Request: ' + data.request.method + (data.request.method !== "GET" ? (' - ' + data.request.size + ' bytes') : "")));
metadata.append($('<li></li>').text('Response: ' + data.response.method + ' - ' + data.response.size + ' bytes'));
metadata.append($('<li></li>').text('Total Time: ' + data.timing.total));
metadata.append($('<li></li>').text('Query Time: ' + data.timing.db_query));
// Add debug entries.
if (data.entries && data.entries.length) {
page_body.append($('<h4></h4>').text('Debug Entries (' + data.entries.length + ')'));
for (i in data.entries) {
entry = $('<div class="debug_entry pre_wrap"></div>').appendTo(page_body);
num = parseInt(i) + 1; if (num < 10) num = "0" + num;
entry.text(num + ". " + data.entries[i].message);
backtrace = $('<ul class="debug_backtrace"></ul>').appendTo(entry);
for (j in data.entries[i].backtrace) {
if (data.entries[i].backtrace[j].file) {
backtrace.append($('<li></li>').text(data.entries[i].backtrace[j].file + ":" + data.entries[i].backtrace[j].line));
}
}
}
}
// Add errors.
if (data.errors && data.errors.length) {
page_body.append($('<h4></h4>').text('Errors (' + data.errors.length + ')'));
for (i in data.errors) {
entry = $('<div class="debug_entry"></div>').appendTo(page_body);
num = parseInt(i) + 1; if (num < 10) num = "0" + num;
entry.text(num + ". " + data.errors[i].type + ": " + data.errors[i].message);
backtrace = $('<ul class="debug_backtrace"></ul>').appendTo(entry);
for (j in data.errors[i].backtrace) {
if (data.errors[i].backtrace[j].file) {
backtrace.append($('<li></li>').text(data.errors[i].backtrace[j].file + ":" + data.errors[i].backtrace[j].line));
}
}
}
}
// Add queries.
if (data.queries && data.queries.length) {
page_body.append($('<h4></h4>').text('Queries (' + data.queries.length + ')'));
for (i in data.queries) {
entry = $('<div class="debug_entry"></div>').appendTo(page_body);
num = parseInt(i) + 1; if (num < 10) num = "0" + num;
entry.text(num + ". " + data.queries[i].query_string);
description = $('<ul class="debug_backtrace"></ul>').appendTo(entry);
if (data.queries[i].file && data.queries[i].line) {
description.append($('<li></li>').text("Caller: " + data.queries[i].file + ":" + data.queries[i].line).append("<br>(" + data.queries[i].method + ")"));
description.append($('<li></li>').text("Connection: " + data.queries[i].query_connection));
description.append($('<li></li>').text("Query ID: " + data.queries[i].query_id));
description.append($('<li></li>').text("Query Time: " + (data.queries[i].query_time ? (data.queries[i].query_time.toFixed(4) + " sec") : "")));
}
description.append($('<li></li>').text("Result: " + ((data.queries[i].message === "success" || !data.queries[i].message) ? "success" : ("error " + data.queries[i].error_code + " " + data.queries[i].message))));
}
}
// Add slow queries.
if (data.slow_queries && data.slow_queries.length) {
page_body.append($('<h4></h4>').text('Slow Queries (' + data.slow_queries.length + ')'));
for (i in data.slow_queries) {
entry = $('<div class="debug_entry"></div>').appendTo(page_body);
num = parseInt(i) + 1; if (num < 10) num = "0" + num;
entry.text(num + ". " + data.slow_queries[i].query_string);
description = $('<ul class="debug_backtrace"></ul>').appendTo(entry);
if (data.slow_queries[i].file && data.slow_queries[i].line) {
description.append($('<li></li>').text("Caller: " + data.slow_queries[i].file + ":" + data.slow_queries[i].line).append("<br>(" + data.slow_queries[i].method + ")"));
description.append($('<li></li>').text("Connection: " + data.slow_queries[i].query_connection));
description.append($('<li></li>').text("Query ID: " + data.slow_queries[i].query_id));
description.append($('<li></li>').text("Query Time: " + (data.slow_queries[i].query_time ? (data.slow_queries[i].query_time.toFixed(4) + " sec") : "")));
}
description.append($('<li></li>').text("Result: " + ((data.slow_queries[i].message === "success" || !data.slow_queries[i].message) ? "success" : ("error " + data.slow_queries[i].error_code + " " + data.slow_queries[i].message))));
}
}
// Add slow triggers.
if (data.slow_triggers && data.slow_triggers.length) {
page_body.append($('<h4></h4>').text('Slow Triggers (' + data.slow_triggers.length + ')'));
for (i in data.slow_triggers) {
entry = $('<div class="debug_entry"></div>').appendTo(page_body);
num = parseInt(i) + 1; if (num < 10) num = "0" + num;
entry.text(num + ". " + data.slow_triggers[i].trigger_name);
description = $('<ul class="debug_backtrace"></ul>').appendTo(entry);
description.append($('<li></li>').text("Target: " + data.slow_triggers[i].trigger_target));
description.append($('<li></li>').text("Exec Time: " + (data.slow_triggers[i].trigger_time ? (data.slow_triggers[i].trigger_time.toFixed(4) + " sec") : "")));
}
}
// Add slow widgets.
if (data.slow_widgets && data.slow_widgets.length) {
page_body.append($('<h4></h4>').text('Slow Widgets (' + data.slow_widgets.length + ')'));
for (i in data.slow_widgets) {
entry = $('<div class="debug_entry"></div>').appendTo(page_body);
num = parseInt(i) + 1; if (num < 10) num = "0" + num;
entry.text(num + ". " + data.slow_widgets[i].widget_name);
description = $('<ul class="debug_backtrace"></ul>').appendTo(entry);
description.append($('<li></li>').text("Exec Time: " + (data.slow_widgets[i].widget_time ? (data.slow_widgets[i].widget_time.toFixed(4) + " sec") : "")));
}
}
// If there are errors, turn the button text red.
if (data.errors && data.errors.length) {
button_link.addClass("has_errors");
}
};
// Add debug data from the previous request.
if (window.rhymix_debug_previous) {
window.rhymix_debug_previous.page_title = 'PREVIOUS POST : ' + window.rhymix_debug_previous.ajax_module + "." + window.rhymix_debug_previous.ajax_act;
rhymix_debug_add_data(window.rhymix_debug_previous, false);
}
// Add debug data from the current request.
if (window.rhymix_debug_content) {
window.rhymix_debug_content.page_title = 'MAIN PAGE';
rhymix_debug_add_data(window.rhymix_debug_content, true);
}
// Add debug data from pending AJAX requests.
if (window.rhymix_debug_pending_data) {
while (window.rhymix_debug_pending_data.length) {
rhymix_debug_add_data(window.rhymix_debug_pending_data.shift());
}
}
});

View file

@ -77,6 +77,16 @@
}
});
// Add debug information.
if (data._rx_debug) {
data._rx_debug.page_title = "AJAX : " + params.module + "." + params.act;
if (window.rhymix_debug_add_data) {
window.rhymix_debug_add_data(data._rx_debug);
} else {
window.rhymix_debug_pending_data.push(data._rx_debug);
}
}
// If the response contains an error, display the error message.
if (data.error != "0") {
// This way of calling an error handler is deprecated. Do not use it.
@ -176,6 +186,16 @@
clearTimeout(wfsr_timeout);
waiting_obj.hide().trigger("cancel_confirm");
// Add debug information.
if (data._rx_debug) {
data._rx_debug.page_title = "AJAX : " + params.module + "." + params.act;
if (window.rhymix_debug_add_data) {
window.rhymix_debug_add_data(data._rx_debug);
} else {
window.rhymix_debug_pending_data.push(data._rx_debug);
}
}
// If the response contains an error, display the error message.
if(data.error != "0" && data.error > -1000) {
if(data.error == -1 && data.message == "msg_is_not_administrator") {

View file

@ -225,6 +225,8 @@ $lang->msg_module_is_not_exists = 'Cannot find the page you requested. Ask your
$lang->msg_module_is_not_standalone = 'Requested page cannot be executed independently.';
$lang->msg_empty_search_target = 'Cannot find the Search target.';
$lang->msg_empty_search_keyword = 'Cannot find the Keyword.';
$lang->msg_server_error = 'Server Error';
$lang->msg_server_error_see_log = 'Your server is configured to hide error messages. Please see your server\'s error log for details.';
$lang->comment_to_be_approved = 'Your comment must be approved by admin before being published.';
$lang->success_registed = 'Registered successfully.';
$lang->success_declared = 'Reported successfully.';

View file

@ -225,6 +225,8 @@ $lang->msg_module_is_not_exists = 'モジュールが見つかりません。
$lang->msg_module_is_not_standalone = 'このモジュールはスタンドアローンでは作動しません。';
$lang->msg_empty_search_target = '検索対象がありません。';
$lang->msg_empty_search_keyword = 'キーワードがありません。';
$lang->msg_server_error = 'サーバーエラー';
$lang->msg_server_error_see_log = 'エラーメッセージを表示しないように設定されています。サーバーのエラーログで詳細を確認してください。';
$lang->comment_to_be_approved = '管理者の確認が必要なコメントです。';
$lang->success_registed = '登録しました。';
$lang->success_declared = '通報しました。';

View file

@ -225,6 +225,8 @@ $lang->msg_module_is_not_exists = '요청한 페이지를 찾을 수 없습니
$lang->msg_module_is_not_standalone = '요청한 페이지는 독립적으로 동작할 수 없습니다.';
$lang->msg_empty_search_target = '검색대상이 없습니다.';
$lang->msg_empty_search_keyword = '검색어가 없습니다.';
$lang->msg_server_error = '서버 오류';
$lang->msg_server_error_see_log = '오류 메시지를 표시하지 않도록 설정되어 있습니다. 서버의 에러 로그에서 자세한 내용을 확인해 주십시오.';
$lang->comment_to_be_approved = '관리자의 확인이 필요한 댓글입니다.';
$lang->success_registed = '등록했습니다.';
$lang->success_declared = '신고했습니다.';

View file

@ -695,100 +695,14 @@ function getEncodeEmailAddress($email)
}
/**
* Prints debug messages
* Add an entry to the debug log.
*
* Display $buff contents into the file ./files/_debug_message.php.
* You can see the file on your prompt by command: tail-f./files/_debug_message.php
*
* @param mixed $debug_output Target object to be printed
* @param bool $display_option boolean Flag whether to print seperator (default:true)
* @param string $file Target file name
* @param mixed $entry Target object to be printed
* @return void
*/
function debugPrint($debug_output = NULL, $display_option = TRUE, $file = '_debug_message.php')
function debugPrint($entry = null)
{
static $debug_file;
static $debug_file_exist;
if(!(__DEBUG__ & 1))
{
return;
}
static $firephp;
$bt = debug_backtrace();
if(is_array($bt))
{
$bt_debug_print = array_shift($bt);
$bt_called_function = array_shift($bt);
}
$file_name = str_replace(_XE_PATH_, '', $bt_debug_print['file']);
$line_num = $bt_debug_print['line'];
$function = $bt_called_function['class'] . $bt_called_function['type'] . $bt_called_function['function'];
if(__DEBUG_OUTPUT__ == 2 && version_compare(PHP_VERSION, '6.0.0') === -1)
{
if(!isset($firephp))
{
$firephp = FirePHP::getInstance(TRUE);
}
$type = FirePHP::INFO;
$label = sprintf('[%s:%d] %s() (Memory usage: current=%s, peak=%s)', $file_name, $line_num, $function, FileHandler::filesize(memory_get_usage()), FileHandler::filesize(memory_get_peak_usage()));
// Check a FirePHP option
if($display_option === 'TABLE')
{
$label = $display_option;
}
if($display_option === 'ERROR')
{
$type = $display_option;
}
// Check if the IP specified by __DEBUG_PROTECT__ option is same as the access IP.
if(__DEBUG_PROTECT__ === 1 && __DEBUG_PROTECT_IP__ != $_SERVER['REMOTE_ADDR'])
{
$debug_output = 'The IP address is not allowed. Change the value of __DEBUG_PROTECT_IP__ into your IP address in config/config.user.inc.php or config/config.inc.php';
$label = NULL;
}
$firephp->fb($debug_output, $label, $type);
}
else
{
if(__DEBUG_PROTECT__ === 1 && __DEBUG_PROTECT_IP__ != $_SERVER['REMOTE_ADDR'])
{
return;
}
$print = array();
if($debug_file_exist === NULL) $print[] = '<?php exit() ?>';
if(!$debug_file) $debug_file = _XE_PATH_ . 'files/' . $file;
if(!$debug_file_exist) $debug_file_exist = file_exists($debug_file);
if($display_option === TRUE || $display_option === 'ERROR')
{
$print[] = str_repeat('=', 80);
}
$print[] = sprintf("[%s %s:%d] %s() - mem(%s)", date('Y-m-d H:i:s'), $file_name, $line_num, $function, FileHandler::filesize(memory_get_usage()));
$type = gettype($debug_output);
if(!in_array($type, array('array', 'object', 'resource')))
{
if($display_option === 'ERROR') $print[] = 'ERROR : ' . var_export($debug_output, TRUE);
else $print[] = $type . '(' . var_export($debug_output, TRUE) . ')';
$print[] = PHP_EOL.PHP_EOL;
}
else
{
$print[] = print_r($debug_output, TRUE);
$print[] = PHP_EOL;
}
@file_put_contents($debug_file, implode(PHP_EOL, $print), FILE_APPEND|LOCK_EX);
}
Rhymix\Framework\Debug::addEntry($entry);
}
/**
@ -798,64 +712,7 @@ function debugPrint($debug_output = NULL, $display_option = TRUE, $file = '_debu
*/
function writeSlowlog($type, $elapsed_time, $obj)
{
if(!__LOG_SLOW_TRIGGER__ && !__LOG_SLOW_ADDON__ && !__LOG_SLOW_WIDGET__ && !__LOG_SLOW_QUERY__) return;
if(__LOG_SLOW_PROTECT__ === 1 && __LOG_SLOW_PROTECT_IP__ != $_SERVER['REMOTE_ADDR']) return;
static $log_filename = array(
'query' => 'files/_slowlog_query.php',
'trigger' => 'files/_slowlog_trigger.php',
'addon' => 'files/_slowlog_addon.php',
'widget' => 'files/_slowlog_widget.php'
);
$write_file = true;
$log_file = _XE_PATH_ . $log_filename[$type];
$buff = array();
$buff[] = '<?php exit(); ?>';
$buff[] = date('c');
if($type == 'trigger' && __LOG_SLOW_TRIGGER__ > 0 && $elapsed_time > __LOG_SLOW_TRIGGER__)
{
$buff[] = "\tCaller : " . $obj->caller;
$buff[] = "\tCalled : " . $obj->called;
}
else if($type == 'addon' && __LOG_SLOW_ADDON__ > 0 && $elapsed_time > __LOG_SLOW_ADDON__)
{
$buff[] = "\tAddon : " . $obj->called;
$buff[] = "\tCalled position : " . $obj->caller;
}
else if($type == 'widget' && __LOG_SLOW_WIDGET__ > 0 && $elapsed_time > __LOG_SLOW_WIDGET__)
{
$buff[] = "\tWidget : " . $obj->called;
}
else if($type == 'query' && __LOG_SLOW_QUERY__ > 0 && $elapsed_time > __LOG_SLOW_QUERY__)
{
$buff[] = $obj->query;
$buff[] = "\tQuery ID : " . $obj->query_id;
$buff[] = "\tCaller : " . $obj->caller;
$buff[] = "\tConnection : " . $obj->connection;
}
else
{
$write_file = false;
}
if($write_file)
{
$buff[] = sprintf("\t%0.6f sec", $elapsed_time);
$buff[] = PHP_EOL . PHP_EOL;
file_put_contents($log_file, implode(PHP_EOL, $buff), FILE_APPEND);
}
if($type != 'query')
{
$trigger_args = $obj;
$trigger_args->_log_type = $type;
$trigger_args->_elapsed_time = $elapsed_time;
ModuleHandler::triggerCall('XE.writeSlowlog', 'after', $trigger_args);
}
// no-op
}
/**
@ -863,10 +720,7 @@ function writeSlowlog($type, $elapsed_time, $obj)
*/
function flushSlowlog()
{
$trigger_args = new stdClass();
$trigger_args->_log_type = 'flush';
$trigger_args->_elapsed_time = 0;
ModuleHandler::triggerCall('XE.writeSlowlog', 'after', $trigger_args);
// no-op
}
/**
@ -918,7 +772,7 @@ function getDestroyXeVars($vars)
}
/**
* Change error_handing to debugPrint on php5 higher
* Legacy error handler
*
* @param int $errno
* @param string $errstr
@ -926,22 +780,9 @@ function getDestroyXeVars($vars)
* @param int $line
* @return void
*/
function handleError($errno, $errstr, $file, $line)
function handleError($errno, $errstr, $file, $line, $context)
{
if(!__DEBUG__)
{
return;
}
$errors = array(E_USER_ERROR, E_ERROR, E_PARSE);
if(!in_array($errno, $errors))
{
return;
}
$output = sprintf("Fatal error : %s - %d", $file, $line);
$output .= sprintf("%d - %s", $errno, $errstr);
debugPrint($output);
Rhymix\Framework\Debug::addError($errno, $errstr, $file, $line, $context);
}
/**

View file

@ -71,7 +71,9 @@ xe.msg_select_menu = "{$lang->msg_select_menu}";
{$content}
{Context::getHtmlFooter()}
<!-- ETC -->
<div class="wfsr"></div>
<div id="rhymix_waiting" class="wfsr"></div>
<div id="rhymix_debug_panel"></div>
<div id="rhymix_debug_button"></div>
{@ $js_body_files = Context::getJsFile('body') }
<block loop="$js_body_files => $key, $js_file">
<block cond="$js_file['targetie']"><!--[if {$js_file['targetie']}]></block><script src="{$js_file['file']}"></script><block cond="$js_file['targetie']"><![endif]--></block>

View file

@ -0,0 +1,152 @@
<?php if (!defined('RX_BASEDIR')) exit; ?>
<?php echo '[' . $data->timestamp . ']' . "\n"; ?>
Request / Response
==================
Request URL: <?php echo $data->url . "\n"; ?>
Request Method: <?php echo $data->request->method . "\n" ?>
Request Body Size: <?php echo $data->request->size . "\n" ?>
Response Method: <?php echo $data->response->method . "\n"; ?>
Response Body Size: <?php echo $data->response->size . "\n"; ?>
Page Generation Time
====================
Total Time: <?php echo $data->timing->total . "\n"; ?>
Template Compile Time: <?php echo $data->timing->template . "\n"; ?>
XML Parsing Time: <?php echo $data->timing->xmlparse . "\n"; ?>
DB Query Time: <?php echo $data->timing->db_query . "\n"; ?>
DB Processing Time: <?php echo $data->timing->db_class . "\n"; ?>
Layout Processing Time: <?php echo $data->timing->layout . "\n"; ?>
Widget Processing Time: <?php echo $data->timing->widget . "\n"; ?>
Content Transform Time: <?php echo $data->timing->trans . "\n"; ?>
Resource Usage
==============
Peak Memory Usage: <?php echo sprintf('%0.1f MB', memory_get_peak_usage(true) / 1024 / 1024) . "\n"; ?>
Included Files: <?php echo count(get_included_files()) . "\n"; ?>
Debug Entries
=============
<?php
$entry_count = 0;
if (!count($data->entries))
{
echo 'None' . "\n";
}
foreach ($data->entries as $entry)
{
if (is_scalar($entry->message))
{
$entry->message = var_export($entry->message, true);
}
else
{
$entry->message = trim(preg_replace('/\r?\n/', "\n" . ' ', print_r($entry->message, true)));
}
echo sprintf('%02d. %s', ++$entry_count, $entry->message) . "\n";
foreach ($entry->backtrace as $key => $backtrace)
{
echo sprintf(' - %s line %d', $backtrace['file'], $backtrace['line']) . "\n";
}
}
?>
PHP Errors and Warnings
=======================
<?php if ($data->errors === null): ?>
Error logging is disabled.
<?php else: ?>
<?php
$error_count = 0;
if (!count($data->errors))
{
echo 'None' . "\n";
}
foreach ($data->errors as $error)
{
echo sprintf('%02d. %s: %s', ++$error_count, $error->type, $error->message) . "\n";
foreach ($error->backtrace as $key => $backtrace)
{
echo sprintf(' - %s line %d', $backtrace['file'], $backtrace['line']) . "\n";
}
}
?>
<?php endif; ?>
Database Queries
================
<?php if ($data->queries === null): ?>
Query logging is disabled.
<?php else: ?>
<?php
$query_count = 0;
if (!count($data->queries))
{
echo 'None'. "\n";
}
foreach ($data->queries as $query)
{
$query_caller = sprintf('%s line %d (%s)', $query->file, $query->line, $query->method);
$query_result = ($query->message === 'success') ? 'success' : sprintf('error %d %s', $query->error_code, $query->message);
echo sprintf('%02d. %s', ++$query_count, $query->query_string) . "\n";
echo sprintf(' - Caller: %s', $query_caller) . "\n";
echo sprintf(' - Connection: %s', $query->query_connection) . "\n";
echo sprintf(' - Query ID: %s', $query->query_id) . "\n";
echo sprintf(' - Query Time: %0.4f sec', $query->query_time) . "\n";
echo sprintf(' - Result: %s', $query_result) . "\n";
}
?>
<?php endif; ?>
Slow Queries
============
<?php
$query_count = 0;
if (!count($data->slow_queries))
{
echo 'None'. "\n";
}
foreach ($data->slow_queries as $query)
{
$query_caller = sprintf('%s line %d (%s)', $query->file, $query->line, $query->method);
$query_result = ($query->message === 'success') ? 'success' : sprintf('error %d %s', $query->error_code, $query->message);
echo sprintf('%02d. %s', ++$query_count, $query->query_string) . "\n";
echo sprintf(' - Caller: %s', $query_caller) . "\n";
echo sprintf(' - Connection: %s', $query->query_connection) . "\n";
echo sprintf(' - Query ID: %s', $query->query_id) . "\n";
echo sprintf(' - Query Time: %0.4f sec', $query->query_time) . "\n";
echo sprintf(' - Result: %s', $query_result) . "\n";
}
?>
Slow Triggers
=============
<?php
$trigger_count = 0;
if (!count($data->slow_triggers))
{
echo 'None'. "\n";
}
foreach ($data->slow_triggers as $trigger)
{
echo sprintf('%02d. %s', ++$trigger_count, $trigger->trigger_name) . "\n";
echo sprintf(' - Target: %s', $trigger->trigger_target) . "\n";
echo sprintf(' - Exec Time: %0.4f sec', $trigger->trigger_time) . "\n";
}
?>
Slow Widgets
============
<?php
$widget_count = 0;
if (!count($data->slow_widgets))
{
echo 'None'. "\n";
}
foreach ($data->slow_widgets as $widget)
{
echo sprintf('%02d. %s', ++$widget_count, $widget->widget_name) . "\n";
echo sprintf(' - Exec Time: %0.4f sec', $widget->widget_time) . "\n";
}
?>

View file

@ -60,7 +60,8 @@ var default_url = "{Context::getDefaultUrl()}";
{Context::getBodyHeader()}
{$content}
{Context::getHtmlFooter()}
<div id="rhymix_debug_panel"></div>
<div id="rhymix_debug_button"></div>
<!--// ETC -->
{@ $js_body_files = Context::getJsFile('body') }
<!--@foreach($js_body_files as $key => $js_file)-->

View file

@ -53,22 +53,11 @@ if($oContext->checkSSO())
{
$oModuleHandler = new ModuleHandler();
try
if($oModuleHandler->init())
{
if($oModuleHandler->init())
{
$oModuleHandler->displayContent($oModuleHandler->procModule());
}
}
catch(Exception $e)
{
htmlHeader();
echo Context::getLang($e->getMessage());
htmlFooter();
$oModuleHandler->displayContent($oModuleHandler->procModule());
}
}
$oContext->close();
/* End of file index.php */
/* Location: ./index.php */

View file

@ -34,8 +34,8 @@ class addonController extends addon
$site_module_info = Context::get('site_module_info');
$site_srl = $site_module_info->site_srl;
$addon_path = _XE_PATH_ . 'files/cache/addons/';
$addon_file = $addon_path . $site_srl . $type . '.acivated_addons.cache.php';
$addon_path = RX_BASEDIR . 'files/cache/addons/';
$addon_file = $addon_path . 'addons.' . intval($site_srl) . '.' . $type . '.php';
if($this->addon_file_called)
{
@ -46,7 +46,7 @@ class addonController extends addon
FileHandler::makeDir($addon_path);
if(!file_exists($addon_file))
if(!file_exists($addon_file) || filemtime($addon_file) < filemtime(__FILE__))
{
$this->makeCacheFile($site_srl, $type);
}
@ -88,57 +88,78 @@ class addonController extends addon
|| ($type == "pc" && $val->is_used != 'Y')
|| ($type == "mobile" && $val->is_used_m != 'Y')
|| ($gtype == 'global' && $val->is_fixed != 'Y')
|| !is_dir(_XE_PATH_ . 'addons/' . $addon))
|| !is_dir(RX_BASEDIR . 'addons/' . $addon))
{
continue;
}
$extra_vars = unserialize($val->extra_vars);
if(!$extra_vars)
{
$extra_vars = new stdClass;
}
$mid_list = $extra_vars->mid_list;
if(!is_array($mid_list) || count($mid_list) < 1)
if(!is_array($mid_list))
{
$mid_list = NULL;
$mid_list = array();
}
// Initialize
$buff[] = '$before_time = microtime(true);';
$buff[] = '$rm = \'' . $extra_vars->xe_run_method . "';";
$buff[] = '$ml = array(';
if($mid_list)
// Run method and mid list
$run_method = $extra_vars->xe_run_method ?: 'run_selected';
$buff[] = '$rm = \'' . $run_method . "';";
$buff[] = '$ml = ' . var_export(array_fill_keys($mid_list, true), true) . ';';
// Addon filename
$buff[] = sprintf('$addon_file = RX_BASEDIR . \'addons/%s/%s.addon.php\';', $addon, $addon);
// Addon configuration
$buff[] = '$addon_info = unserialize(' . var_export(serialize($extra_vars), true) . ');';
// Decide whether to run in this mid
if ($run_method === 'no_run_selected')
{
foreach($mid_list as $mid)
{
$buff[] = "'$mid' => 1,";
}
$buff[] = '$run = !isset($ml[$_m]);';
}
$buff[] = ');';
$buff[] = sprintf('$addon_file = \'./addons/%s/%s.addon.php\';', $addon, $addon);
if($val->extra_vars)
elseif (!count($mid_list))
{
unset($extra_vars);
$extra_vars = base64_encode($val->extra_vars);
$buff[] = '$run = true;';
}
$addon_include = sprintf('unset($addon_info); $addon_info = unserialize(base64_decode(\'%s\')); @include($addon_file);', $extra_vars);
$buff[] = 'if(file_exists($addon_file)){';
$buff[] = 'if($rm === \'no_run_selected\'){';
$buff[] = 'if(!isset($ml[$_m])){';
$buff[] = $addon_include;
$buff[] = '}}else{';
$buff[] = 'if(isset($ml[$_m]) || count($ml) === 0){';
$buff[] = $addon_include;
$buff[] = '}}}';
$buff[] = '$after_time = microtime(true);';
$buff[] = '$addon_time_log = new stdClass();';
$buff[] = '$addon_time_log->caller = $called_position;';
$buff[] = '$addon_time_log->called = "' . $addon . '";';
$buff[] = '$addon_time_log->called_extension = "' . $addon . '";';
$buff[] = 'writeSlowlog("addon",$after_time-$before_time,$addon_time_log);';
else
{
$buff[] = '$run = isset($ml[$_m]);';
}
// Write debug info
$buff[] = 'if ($run && file_exists($addon_file)):';
$buff[] = ' include($addon_file);';
$buff[] = ' $after_time = microtime(true);';
$buff[] = ' if (class_exists("Rhymix\\\\Framework\\\\Debug")):';
$buff[] = ' Rhymix\\Framework\\Debug::addTrigger(array(';
$buff[] = ' "name" => "addon." . $called_position,';
$buff[] = ' "target" => "' . $addon . '",';
$buff[] = ' "target_plugin" => "' . $addon . '",';
$buff[] = ' "elapsed_time" => $after_time - $before_time,';
$buff[] = ' ));';
$buff[] = ' endif;';
$buff[] = 'endif;';
$buff[] = '';
}
$addon_path = _XE_PATH_ . 'files/cache/addons/';
FileHandler::makeDir($addon_path);
$addon_file = $addon_path . ($gtype == 'site' ? $site_srl : '') . $type . '.acivated_addons.cache.php';
// Write file in new location
$addon_path = RX_BASEDIR . 'files/cache/addons/';
$addon_file = $addon_path . 'addons.' . ($gtype == 'site' ? intval($site_srl) : 'G') . '.' . $type . '.php';
FileHandler::writeFile($addon_file, join(PHP_EOL, $buff));
// Remove file from old location
$old_addon_file = $addon_path . ($gtype == 'site' ? $site_srl : '') . $type . '.acivated_addons.cache.php';
if (file_exists($old_addon_file))
{
FileHandler::removeFile($old_addon_file);
}
}
/**
@ -176,12 +197,17 @@ class addonController extends addon
*/
function removeAddonConfig($site_srl)
{
$addon_path = _XE_PATH_ . 'files/cache/addons/';
$addon_file = $addon_path . $site_srl . '.acivated_addons.cache.php';
$addon_path = RX_BASEDIR . 'files/cache/addons/';
$addon_file = $addon_path . 'addons.' . intval($site_srl) . '.' . $type . '.php';
if(file_exists($addon_file))
{
FileHandler::removeFile($addon_file);
}
$old_addon_file = $addon_path . ($gtype == 'site' ? $site_srl : '') . $type . '.acivated_addons.cache.php';
if (file_exists($old_addon_file))
{
FileHandler::removeFile($old_addon_file);
}
$args = new stdClass();
$args->site_srl = $site_srl;

View file

@ -693,6 +693,62 @@ class adminAdminController extends admin
$this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl('', 'act', 'dispAdminConfigAdvanced'));
}
/**
* Update debug configuration.
*/
function procAdminUpdateDebug()
{
$vars = Context::getRequestVars();
// Debug settings
Rhymix\Framework\Config::set('debug.enabled', $vars->debug_enabled === 'Y');
Rhymix\Framework\Config::set('debug.log_errors', $vars->debug_log_errors === 'Y');
Rhymix\Framework\Config::set('debug.log_queries', $vars->debug_log_queries === 'Y');
Rhymix\Framework\Config::set('debug.log_slow_queries', max(0, floatval($vars->debug_log_slow_queries)));
Rhymix\Framework\Config::set('debug.log_slow_triggers', max(0, floatval($vars->debug_log_slow_triggers)));
Rhymix\Framework\Config::set('debug.log_slow_widgets', max(0, floatval($vars->debug_log_slow_widgets)));
Rhymix\Framework\Config::set('debug.display_type', strval($vars->debug_display_type) ?: 'comment');
Rhymix\Framework\Config::set('debug.display_to', strval($vars->debug_display_to) ?: 'admin');
// Log filename
$log_filename = strval($vars->debug_log_filename);
$log_filename_today = str_replace(array('YYYY', 'YY', 'MM', 'DD'), array(
getInternalDateTime(RX_TIME, 'Y'),
getInternalDateTime(RX_TIME, 'y'),
getInternalDateTime(RX_TIME, 'm'),
getInternalDateTime(RX_TIME, 'd'),
), $log_filename);
if (file_exists(RX_BASEDIR . $log_filename_today) && !is_writable(RX_BASEDIR . $log_filename_today))
{
return new Object(-1, 'msg_debug_log_filename_not_writable');
}
if (!file_exists(dirname(RX_BASEDIR . $log_filename)) && !FileHandler::makeDir(dirname(RX_BASEDIR . $log_filename)))
{
return new Object(-1, 'msg_debug_log_filename_not_writable');
}
if (!is_writable(dirname(RX_BASEDIR . $log_filename)))
{
return new Object(-1, 'msg_debug_log_filename_not_writable');
}
Rhymix\Framework\Config::set('debug.log_filename', $log_filename);
// IP access control
$allowed_ip = array_map('trim', preg_split('/[\r\n]/', $vars->debug_allowed_ip));
$allowed_ip = array_unique(array_filter($allowed_ip, function($item) {
return $item !== '';
}));
if (!IpFilter::validate($whitelist)) {
return new Object(-1, 'msg_invalid_ip');
}
Rhymix\Framework\Config::set('debug.allow', array_values($allowed_ip));
// Save
Rhymix\Framework\Config::save();
$this->setMessage('success_updated');
$this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl('', 'act', 'dispAdminConfigDebug'));
}
/**
* Update sitelock configuration.
*/

View file

@ -483,6 +483,31 @@ class adminAdminView extends admin
$this->setTemplateFile('config_advanced');
}
/**
* Display Debug Settings page
* @return void
*/
function dispAdminConfigDebug()
{
// Load debug settings.
Context::set('debug_enabled', Rhymix\Framework\Config::get('debug.enabled'));
Context::set('debug_log_errors', Rhymix\Framework\Config::get('debug.log_errors'));
Context::set('debug_log_queries', Rhymix\Framework\Config::get('debug.log_queries'));
Context::set('debug_log_slow_queries', Rhymix\Framework\Config::get('debug.log_slow_queries'));
Context::set('debug_log_slow_triggers', Rhymix\Framework\Config::get('debug.log_slow_triggers'));
Context::set('debug_log_slow_widgets', Rhymix\Framework\Config::get('debug.log_slow_widgets'));
Context::set('debug_log_filename', Rhymix\Framework\Config::get('debug.log_filename') ?: 'files/debug/YYYYMMDD.php');
Context::set('debug_display_type', Rhymix\Framework\Config::get('debug.display_type'));
Context::set('debug_display_to', Rhymix\Framework\Config::get('debug.display_to'));
// IP access control
$allowed_ip = Rhymix\Framework\Config::get('debug.allow');
Context::set('debug_allowed_ip', implode(PHP_EOL, $allowed_ip));
Context::set('remote_addr', RX_CLIENT_IP);
$this->setTemplateFile('config_debug');
}
/**
* Display Sitelock Settings page
* @return void

View file

@ -7,6 +7,7 @@
<action name="dispAdminConfigGeneral" type="view" menu_name="adminConfigurationGeneral" menu_index="true" />
<action name="dispAdminConfigSecurity" type="view" menu_name="adminConfigurationGeneral" />
<action name="dispAdminConfigAdvanced" type="view" menu_name="adminConfigurationGeneral" />
<action name="dispAdminConfigDebug" type="view" menu_name="adminConfigurationGeneral" />
<action name="dispAdminConfigSitelock" type="view" menu_name="adminConfigurationGeneral" />
<action name="dispAdminConfigFtp" type="view" menu_name="adminConfigurationFtp" menu_index="true" />
<action name="dispAdminSetup" type="view" menu_name="adminMenuSetup" menu_index="true" />
@ -24,6 +25,7 @@
<action name="procAdminUpdateConfigGeneral" type="controller" />
<action name="procAdminUpdateSecurity" type="controller" />
<action name="procAdminUpdateAdvanced" type="controller" />
<action name="procAdminUpdateDebug" type="controller" />
<action name="procAdminUpdateSitelock" type="controller" />
<action name="procAdminUpdateFTPInfo" type="controller" />
<action name="procAdminRemoveFTPInfo" type="controller" />

View file

@ -4,6 +4,7 @@ $lang->cmd_configure = 'Configure';
$lang->subtitle_primary = 'General Settings';
$lang->subtitle_security = 'Security Settings';
$lang->subtitle_advanced = 'Advanced Settings';
$lang->subtitle_debug = 'Debug Settings';
$lang->subtitle_etc = 'Other Settings';
$lang->current_state = 'Current state';
$lang->latest_documents = 'Latest Documents';
@ -108,6 +109,25 @@ $lang->use_ftp_passive_mode = 'Use FTP Passive Mode';
$lang->use_sftp_support = 'Use SFTP';
$lang->disable_sftp_support = 'You should install ssh2 PHP module to use SFTP.';
$lang->msg_self_restart_cache_engine = 'Please restart Memcached or cache daemon.';
$lang->debug_enabled = 'Enable Debugging';
$lang->debug_log_errors = 'Log Errors';
$lang->debug_log_queries = 'Log Queries';
$lang->debug_log_slow_queries = 'Log Slow Queries';
$lang->debug_log_slow_triggers = 'Log Slow Triggers';
$lang->debug_log_slow_widgets = 'Log Slow Widgets';
$lang->debug_seconds = 'seconds or longer';
$lang->debug_display_type = 'Display Debug Info As';
$lang->debug_display_type_comment = 'HTML source comment';
$lang->debug_display_type_panel = 'On-screen panel';
$lang->debug_display_type_file = 'Write to file';
$lang->debug_display_to = 'Display Debug Info To';
$lang->debug_display_to_admin = 'Administrator only';
$lang->debug_display_to_ip = 'Visitors from IP adresses listed below';
$lang->debug_display_to_everyone = 'Everyone';
$lang->debug_log_filename = 'Log filename';
$lang->about_debug_log_filename = 'YYYYMMDD in the filename will be replaced with the current date.<br>It is recommended to split the log file by date to prevent it from getting too large.';
$lang->msg_debug_log_filename_not_writable = 'Rhymix cannot write log files in the specified path.';
$lang->debug_allowed_ip = 'Allowed IP addresses';
$lang->autoinstall = 'EasyInstall';
$lang->last_week = 'Last Week';
$lang->this_week = 'This Week';

View file

@ -4,6 +4,7 @@ $lang->cmd_configure = '설정하기';
$lang->subtitle_primary = '기본 설정';
$lang->subtitle_security = '보안 설정';
$lang->subtitle_advanced = '고급 설정';
$lang->subtitle_debug = '디버그 설정';
$lang->subtitle_etc = '기타';
$lang->current_state = '현황';
$lang->latest_documents = '최근 글';
@ -105,6 +106,25 @@ $lang->use_ftp_passive_mode = 'Passive 모드 사용';
$lang->use_sftp_support = 'SFTP 사용';
$lang->disable_sftp_support = 'SFTP를 사용하려면 PHP에 ssh2 모듈이 설치되어 있어야 합니다.';
$lang->msg_self_restart_cache_engine = 'Memcached 또는 캐시 서비스를 재시작해 주세요.';
$lang->debug_enabled = '디버그 기능 사용';
$lang->debug_log_errors = '에러 기록';
$lang->debug_log_queries = '쿼리 기록';
$lang->debug_log_slow_queries = '느린 쿼리 기록';
$lang->debug_log_slow_triggers = '느린 트리거 기록';
$lang->debug_log_slow_widgets = '느린 위젯 기록';
$lang->debug_seconds = '초 이상 소요시 기록';
$lang->debug_display_type = '디버그 정보 표시 방법';
$lang->debug_display_type_comment = 'HTML 소스에 표시 (주석)';
$lang->debug_display_type_panel = '화면에 표시 (패널)';
$lang->debug_display_type_file = '파일에 기록';
$lang->debug_display_to = '디버그 정보 표시 대상';
$lang->debug_display_to_admin = '관리자에게만 표시';
$lang->debug_display_to_ip = '아래 IP의 방문자에게만 표시';
$lang->debug_display_to_everyone = '모두에게 표시';
$lang->debug_log_filename = '디버그 정보 기록 파일';
$lang->about_debug_log_filename = '파일명에 YYYYMMDD가 포함된 경우 날짜별로 파일을 분리하여 기록합니다.<br>파일을 분리하지 않으면 용량이 매우 커질 수 있으니 주의하십시오.';
$lang->msg_debug_log_filename_not_writable = '지정한 경로에 로그 파일을 작성할 수 없습니다.';
$lang->debug_allowed_ip = '디버그 허용 IP';
$lang->autoinstall = '쉬운 설치';
$lang->last_week = '지난주';
$lang->this_week = '이번주';

View file

@ -0,0 +1,87 @@
<include target="config_header.html" />
<div cond="$XE_VALIDATOR_MESSAGE && $XE_VALIDATOR_ID == 'modules/admin/tpl/config_debug/1'" class="message {$XE_VALIDATOR_MESSAGE_TYPE}">
<p>{$XE_VALIDATOR_MESSAGE}</p>
</div>
<section class="section">
<form action="./" method="post" class="x_form-horizontal">
<input type="hidden" name="module" value="admin" />
<input type="hidden" name="act" value="procAdminUpdateDebug" />
<input type="hidden" name="xe_validator_id" value="modules/admin/tpl/config_debug/1" />
<div class="x_control-group">
<label class="x_control-label">{$lang->debug_enabled}</label>
<div class="x_controls">
<label for="debug_enabled_y" class="x_inline"><input type="radio" name="debug_enabled" id="debug_enabled_y" value="Y" checked="checked"|cond="$debug_enabled" /> {$lang->cmd_yes}</label>
<label for="debug_enabled_n" class="x_inline"><input type="radio" name="debug_enabled" id="debug_enabled_n" value="N" checked="checked"|cond="!$debug_enabled" /> {$lang->cmd_no}</label>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label">{$lang->debug_log_errors}</label>
<div class="x_controls">
<label for="debug_log_errors_y" class="x_inline"><input type="radio" name="debug_log_errors" id="debug_log_errors_y" value="Y" checked="checked"|cond="$debug_log_errors" /> {$lang->cmd_yes}</label>
<label for="debug_log_errors_n" class="x_inline"><input type="radio" name="debug_log_errors" id="debug_log_errors_n" value="N" checked="checked"|cond="!$debug_log_errors" /> {$lang->cmd_no}</label>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label">{$lang->debug_log_queries}</label>
<div class="x_controls">
<label for="debug_log_queries_y" class="x_inline"><input type="radio" name="debug_log_queries" id="debug_log_queries_y" value="Y" checked="checked"|cond="$debug_log_queries" /> {$lang->cmd_yes}</label>
<label for="debug_log_queries_n" class="x_inline"><input type="radio" name="debug_log_queries" id="debug_log_queries_n" value="N" checked="checked"|cond="!$debug_log_queries" /> {$lang->cmd_no}</label>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="debug_log_slow_queries">{$lang->debug_log_slow_queries}</label>
<div class="x_controls">
<input type="text" name="debug_log_slow_queries" id="debug_log_slow_queries" size="5" value="{$debug_log_slow_queries}" />
&nbsp;{$lang->debug_seconds}
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="debug_log_slow_triggers">{$lang->debug_log_slow_triggers}</label>
<div class="x_controls">
<input type="text" name="debug_log_slow_triggers" id="debug_log_slow_triggers" size="5" value="{$debug_log_slow_triggers}" />
&nbsp;{$lang->debug_seconds}
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="debug_log_slow_widgets">{$lang->debug_log_slow_widgets}</label>
<div class="x_controls">
<input type="text" name="debug_log_slow_widgets" id="debug_log_slow_widgets" size="5" value="{$debug_log_slow_widgets}" />
&nbsp;{$lang->debug_seconds}
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="debug_log_slow_widgets">{$lang->debug_display_type}</label>
<div class="x_controls">
<label for="debug_display_type_comment" class="x_inline"><input type="radio" name="debug_display_type" id="debug_display_type_comment" value="comment" checked="checked"|cond="$debug_display_type=='comment'" /> {$lang->debug_display_type_comment}</label>
<label for="debug_display_type_panel" class="x_inline"><input type="radio" name="debug_display_type" id="debug_display_type_panel" value="panel" checked="checked"|cond="$debug_display_type=='panel'" /> {$lang->debug_display_type_panel}</label>
<label for="debug_display_type_file" class="x_inline"><input type="radio" name="debug_display_type" id="debug_display_type_file" value="file" checked="checked"|cond="$debug_display_type=='file'" /> {$lang->debug_display_type_file}</label>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="debug_log_filename">{$lang->debug_log_filename}</label>
<div class="x_controls">
<input type="text" name="debug_log_filename" id="debug_log_filename" value="{$debug_log_filename}" />
<p class="x_help-block">{$lang->about_debug_log_filename}</p>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="debug_log_slow_widgets">{$lang->debug_display_to}</label>
<div class="x_controls">
<label for="debug_display_to_admin" class="x_inline"><input type="radio" name="debug_display_to" id="debug_display_to_admin" value="admin" checked="checked"|cond="$debug_display_to=='admin'" /> {$lang->debug_display_to_admin}</label>
<label for="debug_display_to_ip" class="x_inline"><input type="radio" name="debug_display_to" id="debug_display_to_ip" value="ip" checked="checked"|cond="$debug_display_to=='ip'" /> {$lang->debug_display_to_ip}</label>
<label for="debug_display_to_everyone" class="x_inline"><input type="radio" name="debug_display_to" id="debug_display_to_everyone" value="everyone" checked="checked"|cond="$debug_display_to=='everyone'" /> {$lang->debug_display_to_everyone}</label>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="debug_allowed_ip">{$lang->debug_allowed_ip}</label>
<div class="x_controls">
<textarea name="debug_allowed_ip" id="debug_allowed_ip" rows="4" cols="42" placeholder="{$remote_addr} ({$lang->local_ip_address})" style="margin-right:10px">{$debug_allowed_ip}</textarea>
</div>
</div>
<div class="x_clearfix btnArea">
<div class="x_pull-right">
<button type="submit" class="x_btn x_btn-primary">{$lang->cmd_save}</button>
</div>
</div>
</form>
</section>

View file

@ -7,5 +7,6 @@
<li class="x_active"|cond="$act == 'dispAdminConfigGeneral'"><a href="{getUrl('', 'module', 'admin', 'act', 'dispAdminConfigGeneral')}">{$lang->subtitle_primary}</a></li>
<li class="x_active"|cond="$act == 'dispAdminConfigSecurity'"><a href="{getUrl('', 'module', 'admin', 'act', 'dispAdminConfigSecurity')}">{$lang->subtitle_security}</a></li>
<li class="x_active"|cond="$act == 'dispAdminConfigAdvanced'"><a href="{getUrl('', 'module', 'admin', 'act', 'dispAdminConfigAdvanced')}">{$lang->subtitle_advanced}</a></li>
<li class="x_active"|cond="$act == 'dispAdminConfigDebug'"><a href="{getUrl('', 'module', 'admin', 'act', 'dispAdminConfigDebug')}">{$lang->subtitle_debug}</a></li>
<li class="x_active"|cond="$act == 'dispAdminConfigSitelock'"><a href="{getUrl('', 'module', 'admin', 'act', 'dispAdminConfigSitelock')}">{$lang->subtitle_sitelock}</a></li>
</ul>

View file

@ -17,7 +17,7 @@ class messageView extends message
/**
* @brief Display messages
*/
function dispMessage()
function dispMessage($detail = null)
{
// Get configurations (using module model object)
$oModuleModel = getModel('module');
@ -58,9 +58,10 @@ class messageView extends message
{
if(strncasecmp('https://', Context::getRequestUri(), 8) === 0) $ssl_mode = true;
}
Context::set('ssl_mode',$ssl_mode);
Context::set('ssl_mode', $ssl_mode);
Context::set('system_message', nl2br($this->getMessage()));
Context::set('system_message_detail', nl2br($detail));
$this->setTemplateFile('system_message');
}

View file

@ -8,7 +8,7 @@
<div id="access">
<div class="login-header">
<h1><i class="icon-user"></i> {$system_message}</h1>
<div class="message" cond="defined('_XE_SITELOCK_MESSAGE_')">{constant('_XE_SITELOCK_MESSAGE_')}</div>
<div class="message" cond="$system_message_detail">{$system_message_detail}</div>
</div>
<div class="login-body">
<div cond="$XE_VALIDATOR_MESSAGE && $XE_VALIDATOR_ID == 'modules/message/skins/default/system_message/1'" class="message {$XE_VALIDATOR_MESSAGE_TYPE}">

View file

@ -5,7 +5,7 @@
<div id="access">
<div class="login-header">
<h1>{$system_message}</h1>
<div class="message" cond="defined('_XE_SITELOCK_MESSAGE_')">{constant('_XE_SITELOCK_MESSAGE_')}</div>
<div class="message" cond="$system_message_detail">{$system_message_detail}</div>
</div>
<div cond="!$is_logged">
<div class="login-body">
@ -21,13 +21,13 @@
<input type="text" name="user_id" id="uid" title="{$lang->user_id}" placeholder="{$lang->user_id}" required autofocus cond="$member_config->identifier != 'email_address'" />
<input type="email" name="user_id" id="uid" title="{$lang->email_address}" placeholder="{$lang->email_address}" required autofocus cond="$member_config->identifier == 'email_address'" />
<input type="password" name="password" id="upw" title="{$lang->password}" placeholder="{$lang->password}" required />
<label for="keepid" cond="!defined('_XE_SITELOCK_MESSAGE_')">
<label for="keepid" cond="!$system_message_detail">
<input type="checkbox" name="keep_signed" id="keepid" class="inputCheck" value="Y" onclick="jQuery('#warning')[(jQuery('#keepid:checked').size()&gt;0?'addClass':'removeClass')]('open');" />
{$lang->keep_signed}
</label>
</div>
<p><button type="submit" class="button" href="#" onclick="$('#message_login_form').submit()">
<!--@if(defined('_XE_SITELOCK_MESSAGE_'))-->
<!--@if($system_message_detail)-->
{$lang->msg_administrator_login}
<!--@else-->
{$lang->cmd_login}
@ -35,7 +35,7 @@
</button></p>
</form>
</div>
<div class="login-footer" cond="!defined('_XE_SITELOCK_MESSAGE_')">
<div class="login-footer" cond="!$system_message_detail">
<a href="{getUrl('', 'act', 'dispMemberFindAccount')}">{$lang->cmd_find_member_account}</a>
<span class="bar">|</span>
<a href="{getUrl('', 'act', 'dispMemberSignUpForm')}">{$lang->cmd_signup}</a>

View file

@ -442,8 +442,8 @@ class widgetController extends widget
function execute($widget, $args, $javascript_mode = false, $escaped = true)
{
// Save for debug run-time widget
if(__DEBUG__==3) $start = microtime(true);
$before = microtime(true);
$start = microtime(true);
// urldecode the value of args haejum
$object_vars = get_object_vars($args);
if(count($object_vars))
@ -640,18 +640,14 @@ class widgetController extends widget
if($args->widgetstyle) $widget_content_body = $this->compileWidgetStyle($args->widgetstyle,$widget, $widget_content_body, $args, $javascript_mode);
$output = $widget_content_header . $widget_content_body . $widget_content_footer;
// Debug widget creation time information added to the results
if(__DEBUG__==3) $GLOBALS['__widget_excute_elapsed__'] += microtime(true) - $start;
$after = microtime(true);
$elapsed_time = $after - $before;
$slowlog = new stdClass;
$slowlog->caller = "widget.execute";
$slowlog->called = $widget;
$slowlog->called_extension = $widget;
writeSlowlog('widget', $elapsed_time, $slowlog);
$elapsed_time = microtime(true) - $start;
$GLOBALS['__widget_excute_elapsed__'] += $elapsed_time;
Rhymix\Framework\Debug::addWidget(array(
'name' => $widget,
'elapsed_time' => $elapsed_time,
));
// Return result
return $output;

View file

@ -0,0 +1,65 @@
<?php
class DebugTest extends \Codeception\TestCase\Test
{
public function testDebugEntry()
{
$file = __FILE__;
$line = __LINE__ + 2;
Rhymix\Framework\Debug::$write_to_error_log = false;
Rhymix\Framework\Debug::addEntry('foobar entry');
$entries = Rhymix\Framework\Debug::getEntries();
$this->assertEquals(1, count($entries));
$this->assertEquals('foobar entry', $entries[0]->message);
$this->assertEquals($file, $entries[0]->file);
$this->assertEquals($line, $entries[0]->line);
}
public function testDebugError()
{
$file = __FILE__;
$line = __LINE__ + 2;
Rhymix\Framework\Debug::$write_to_error_log = false;
Rhymix\Framework\Debug::addError(~0, 'Rhymix', $file, $line, null);
$errors = Rhymix\Framework\Debug::getErrors();
$this->assertEquals(1, count($errors));
$this->assertContains('Rhymix', $errors[0]->message);
$this->assertEquals($file, $errors[0]->file);
$this->assertEquals($line, $errors[0]->line);
}
public function testDebugQuery()
{
Rhymix\Framework\Debug::addQuery(array(
'result' => 'fail',
'errno' => 1234,
'errstr' => 'This is a unit test',
'connection' => 'foobar',
'query_id' => 'rhymix.unitTest',
'query' => 'SELECT foo FROM bar',
'elapsed_time' => 0.1234,
'called_file' => __FILE__,
'called_line' => __LINE__,
'called_method' => 'rhymix.unitTest',
'backtrace' => array(),
));
$queries = Rhymix\Framework\Debug::getQueries();
$this->assertEquals(1, count($queries));
$this->assertEquals('SELECT foo FROM bar', $queries[0]->query_string);
$this->assertEquals('This is a unit test', $queries[0]->message);
$this->assertEquals(1234, $queries[0]->error_code);
}
public function testDebugTranslateFilename()
{
$original_filename = __FILE__;
$trans_filename = substr($original_filename, strlen(\RX_BASEDIR));
$this->assertEquals($trans_filename, Rhymix\Framework\Debug::translateFilename($original_filename));
$original_filename = __FILE__;
$alias_filename = $original_filename . '.foobar';
$trans_filename = substr($alias_filename, strlen(\RX_BASEDIR));
Rhymix\Framework\Debug::addFilenameAlias($alias_filename, $original_filename);
$this->assertEquals($trans_filename, Rhymix\Framework\Debug::translateFilename($original_filename));
}
}