*/ /** * @class DisplayHandler * @author NAVER (developers@xpressengine.com) * DisplayHandler is responsible for displaying the execution result. \n * Depending on the request type, it can display either HTML or XML content.\n * Xml content is simple xml presentation of variables in oModule while html content * is the combination of the variables of oModue and template files/. */ class DisplayHandler extends Handler { var $content_size = 0; // /< The size of displaying contents var $gz_enabled = FALSE; // / gzhandler_enable) { $this->gz_enabled = TRUE; } // Extract contents to display by the request method if(Context::get('xeVirtualRequestMethod') == 'xml') { $handler = new VirtualXMLDisplayHandler(); } elseif(Context::getRequestMethod() == 'JSON' || isset($_POST['_rx_ajax_compat'])) { $handler = new JSONDisplayHandler(); } elseif(Context::getRequestMethod() == 'JS_CALLBACK') { $handler = new JSCallbackDisplayHandler(); } elseif(Context::getRequestMethod() == 'XMLRPC') { $handler = new XMLDisplayHandler(); if(strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE) { $this->gz_enabled = FALSE; } } else { $handler = new HTMLDisplayHandler(); } $output = $handler->toDoc($oModule); // call a trigger before display ModuleHandler::triggerCall('display', 'before', $output); $original_output = $output; // execute add-on $called_position = 'before_display_content'; $oAddonController = getController('addon'); $addon_file = $oAddonController->getCacheFilePath(Mobile::isFromMobilePhone() ? "mobile" : "pc"); if(file_exists($addon_file)) include($addon_file); if($output === false || $output === null || $output instanceof Object) { $output = $original_output; } if(method_exists($handler, "prepareToPrint")) { $handler->prepareToPrint($output); } // Start the session if $_SESSION was touched Context::getInstance()->checkSessionStatus(); // header output $httpStatusCode = $oModule->getHttpStatusCode(); if($httpStatusCode && $httpStatusCode != 200) { self::_printHttpStatusCode($httpStatusCode); } else { if(Context::getResponseMethod() == 'JSON' || Context::getResponseMethod() == 'JS_CALLBACK') { if(strpos($_SERVER['HTTP_ACCEPT'], 'json') !== false) { self::_printJSONHeader(); } } else if(Context::getResponseMethod() != 'HTML') { self::_printXMLHeader(); } else { self::_printHTMLHeader(); } } // disable gzip if output already exists ob_flush(); if(headers_sent()) { $this->gz_enabled = FALSE; } // enable gzip using zlib extension if($this->gz_enabled) { ini_set('zlib.output_compression', true); } // results directly output print $output; // debugOutput output $this->content_size = strlen($output); print $this->getDebugInfo(); // call a trigger after display ModuleHandler::triggerCall('display', 'after', $output); flushSlowlog(); } /** * Get debug information. * * @return string */ public function getDebugInfo() { // Check if debugging is enabled for this request. if (!config('debug.enabled')) { return; } $display_to = config('debug.display_to'); switch ($display_to) { case 'everyone': break; case 'ip': $allowed_ip = config('debug.allow'); foreach ($allowed_ip as $range) { if (Rhymix\Framework\IpFilter::inRange(RX_CLIENT_IP, $range)) { break 2; } } return; case 'admin': default: $logged_info = Context::get('logged_info'); if ($logged_info && $logged_info->is_admin === 'Y') { break; } return; } // Set some useful variables. $basedir_len = strlen(RX_BASEDIR); $timestamp = sprintf('[%s]', Rhymix\Framework\DateTime::formatTimestampForCurrentUser('Y-m-d H:i:s P', RX_TIME)); // Collect debug information. $entries = Rhymix\Framework\Debug::getEntries(); $errors = config('debug.log_errors') ? Rhymix\Framework\Debug::getErrors() : null; $queries = config('debug.log_queries') ? Rhymix\Framework\Debug::getQueries() : null; // Print debug information. switch ($display_type = config('debug.display_type')) { case 'panel': break; case 'comment': case 'file': default: if ($display_type === 'comment' && Context::getResponseMethod() !== 'HTML') { return; } $buff = array($timestamp, ''); $buff[] = 'Request / Response'; $buff[] = '=================='; $buff[] = 'Request URL: ' . getCurrentPageUrl(); $buff[] = 'Request Method: ' . $_SERVER['REQUEST_METHOD'] . ($_SERVER['REQUEST_METHOD'] !== Context::getRequestMethod() ? (' (' . Context::getRequestMethod() . ')') : ''); $buff[] = 'Request Body Size: ' . intval($_SERVER['CONTENT_LENGTH']); $buff[] = 'Response Method: ' . Context::getResponseMethod(); $buff[] = 'Response Body Size: ' . $this->content_size; $buff[] = ''; $buff[] = 'Page Generation Time'; $buff[] = '===================='; $buff[] = 'Total Time: ' . sprintf('%0.4f sec', microtime(true) - RX_MICROTIME); $buff[] = 'Template Compile Time: ' . sprintf('%0.4f sec (count: %d)', $GLOBALS['__template_elapsed__'], $GLOBALS['__TemplateHandlerCalled__']); $buff[] = 'XML Parsing Time: ' . sprintf('%0.4f sec', $GLOBALS['__xmlparse_elapsed__']); $buff[] = 'DB Query Time: ' . sprintf('%0.4f sec (count: %d)', $GLOBALS['__db_elapsed_time__'], count($queries)); $buff[] = 'DB Processing Time: ' . sprintf('%0.4f sec', $GLOBALS['__dbclass_elapsed_time__'] - $GLOBALS['__db_elapsed_time__']); $buff[] = 'Layout Processing Time: ' . sprintf('%0.4f sec', $GLOBALS['__layout_compile_elapsed__']); $buff[] = 'Widget Processing Time: ' . sprintf('%0.4f sec', $GLOBALS['__widget_excute_elapsed__']); $buff[] = 'Content Transform Time: ' . sprintf('%0.4f sec', $GLOBALS['__trans_content_elapsed__']); $buff[] = ''; $buff[] = 'Resource Usage'; $buff[] = '=============='; $buff[] = 'Peak Memory Usage: ' . sprintf('%0.1f MB', memory_get_peak_usage(true) / 1024 / 1024); $buff[] = 'Included Files: ' . count(get_included_files()); $buff[] = ''; if (count($entries)) { $buff[] = 'Debug Entries'; $buff[] = '============='; $entry_count = 0; foreach ($entries as $entry) { if (is_scalar($entry->message)) { $entry->message = var_export($entry->message, true); } else { $entry->message = trim(preg_replace('/\r?\n/', PHP_EOL . ' ', print_r($entry->message, true))); } $buff[] = sprintf('%02d. %s', ++$entry_count, $entry->message); foreach ($entry->backtrace as $key => $backtrace) { if (!strncmp($backtrace['file'], RX_BASEDIR, $basedir_len)) { $backtrace['file'] = substr($backtrace['file'], $basedir_len); } if (isset($error->backtrace[$key + 1])) { $next_backtrace = $error->backtrace[$key + 1]; $called_function = sprintf(' (%s%s%s)', $next_backtrace['class'], $next_backtrace['type'], $next_backtrace['function']); } else { $called_function = ''; } $buff[] = sprintf(' - %s line %d%s', $backtrace['file'], $backtrace['line'], $called_function); } } } $buff[] = 'PHP Errors'; $buff[] = '=========='; if ($errors === null) { $buff[] = 'Error logging is disabled.'; } else { $error_count = 0; if (!count($errors)) { $buff[] = 'No Errors'; } foreach ($errors as $error) { $buff[] = sprintf('%02d. %s: %s', ++$error_count, $error->type, $error->message); foreach ($error->backtrace as $key => $backtrace) { if (!strncmp($backtrace['file'], RX_BASEDIR, $basedir_len)) { $backtrace['file'] = substr($backtrace['file'], $basedir_len); } if (isset($error->backtrace[$key + 1])) { $next_backtrace = $error->backtrace[$key + 1]; $called_function = sprintf(' (%s%s%s)', $next_backtrace['class'], $next_backtrace['type'], $next_backtrace['function']); } else { $called_function = ''; } $buff[] = sprintf(' - %s line %d%s', $backtrace['file'], $backtrace['line'], $called_function); } } } $buff[] = ''; $buff[] = 'DB Queries'; $buff[] = '=========='; if ($queries === null) { $buff[] = 'Query logging is disabled.'; } else { $query_count = 0; if (!count($queries)) { $buff[] = 'No Queries'; } foreach ($queries as $query) { if (!strncmp($query['called_file'], RX_BASEDIR, $basedir_len)) { $query['called_file'] = substr($query['called_file'], $basedir_len); } $query_caller = sprintf('%s line %d (%s)', $query['called_file'], $query['called_line'], $query['called_method']); $query_result = ($query['result'] === 'success') ? 'success' : sprintf('error %d %s', $query['errno'], $query['errstr']); $buff[] = sprintf('%02d. %s', ++$query_count, $query['query']); $buff[] = sprintf(' - Caller: %s', $query_caller); $buff[] = sprintf(' - Connection: %s', $query['connection']); $buff[] = sprintf(' - Query Time: %0.4f sec', $query['elapsed_time']); $buff[] = sprintf(' - Result: %s', $query_result); } } $buff[] = ''; if ($display_type === 'file') { $debug_file = RX_BASEDIR . 'files/_debug_message.php'; FileHandler::writeFile($debug_file, implode(PHP_EOL, $buff), 'a'); return ''; } else { return ''; } } } /** * print a HTTP HEADER for XML, which is encoded in UTF-8 * @return void */ public static function _printXMLHeader() { header("Content-Type: text/xml; charset=UTF-8"); } /** * print a HTTP HEADER for HTML, which is encoded in UTF-8 * @return void */ public static function _printHTMLHeader() { header("Content-Type: text/html; charset=UTF-8"); } /** * print a HTTP HEADER for JSON, which is encoded in UTF-8 * @return void */ public static function _printJSONHeader() { header("Content-Type: text/javascript; charset=UTF-8"); } /** * print a HTTP HEADER for HTML, which is encoded in UTF-8 * @return void */ public static function _printHttpStatusCode($code) { $statusMessage = Context::get('http_status_message'); header("HTTP/1.0 $code $statusMessage"); } } /* End of file DisplayHandler.class.php */ /* Location: ./classes/display/DisplayHandler.class.php */