/** * Shows the debugging console, <i>if</i> {@link debug} is TRUE and the viewer's IP address is in the * {@link debugger_ip} array (or <i>$debugger_ip</i> is an empty array). * * <i>This method must be called after all the queries in a script, preferably before </body>!</i> * * <b>You should ALWAYS have this method called at the end of your scripts and control whether the debugging console * will show or not with the {@link debug} property.</b> * * @param boolean $return (Optional) If set to TRUE, the output will be returned instead of being printed * to the screen. * * Default is FALSE. * * @return void */ function show_debug_console($return = false) { // if if ($this->debug && is_array($this->debugger_ip) && (empty($this->debugger_ip) || in_array($_SERVER['REMOTE_ADDR'], $this->debugger_ip))) { // include the SqlFormatter library require 'includes/SqlFormatter.php'; // set some properties for the formatter SqlFormatter::$number_attributes = SqlFormatter::$boundary_attributes = 'class="symbol"'; SqlFormatter::$quote_attributes = 'class="string"'; SqlFormatter::$reserved_attributes = 'class="keyword"'; SqlFormatter::$tab = ' '; // if warnings are not disabled if (!$this->disable_warnings) { // if there are any warning messages iterate through them foreach (array_keys($this->warnings) as $warning) { // add them to the debugging console $this->_log('warnings', array('message' => $this->language['warning_' . $warning]), false); } } // blocks to be shown in the debugging console $blocks = array('errors' => array('counter' => 0, 'identifier' => 'e', 'generated' => ''), 'successful-queries' => array('counter' => 0, 'identifier' => 'sq', 'generated' => ''), 'unsuccessful-queries' => array('counter' => 0, 'identifier' => 'uq', 'generated' => ''), 'warnings' => array('counter' => 0, 'identifier' => 'w', 'generated' => ''), 'globals' => array('generated' => '')); // there are no warnings $warnings = false; // prepare output for each block foreach (array_keys($blocks) as $block) { $output = ''; // if there is any information for the current block if (isset($this->debug_info[$block])) { // iterate through the error message foreach ($this->debug_info[$block] as $debug_info) { // increment the messages counter $counter = ++$blocks[$block]['counter']; $identifier = $blocks[$block]['identifier']; // if block is about queries if ($block == 'successful-queries' || $block == 'unsuccessful-queries') { // format and highlight query $debug_info['query'] = SqlFormatter::format($debug_info['query']); } // all blocks are enclosed in tables $output .= ' <table cellspacing="0" cellpadding="0" border="0" class="zdc-entry' . ($counter % 2 == 0 ? ' even' : '') . (isset($debug_info['highlight']) && $debug_info['highlight'] == 1 ? ' zdc-highlight' : '') . '"> <tr> <td class="zdc-counter" valign="top">' . str_pad($counter, 3, '0', STR_PAD_LEFT) . '</td> <td class="zdc-data"> '; // are there any error messages issued by the script? if (isset($debug_info['message']) && trim($debug_info['message']) != '') { $output .= ' <div class="zdc-box zdc-error"> ' . $debug_info['message'] . ' </div> '; } // are there any error messages issued by MySQL? if (isset($debug_info['error']) && trim($debug_info['error']) != '') { $output .= ' <div class="zdc-box zdc-error"> ' . $debug_info['error'] . ' </div> '; } // are there any warning messages issued by the script? if (isset($debug_info['warning']) && trim($debug_info['warning']) != '') { $output .= ' <div class="zdc-box zdc-error">' . $debug_info['warning'] . ' </div> '; // set a flag so that we show in the minimized debugging console that there are warnings $warnings = true; } // is there a query to be displayed? if (isset($debug_info['query'])) { $output .= ' <div class="zdc-box' . (isset($debug_info['transaction']) && $debug_info['transaction'] ? ' zdc-transaction' : '') . '">' . preg_replace('/^\\<br\\>/', '', html_entity_decode($debug_info['query'])) . ' </div> '; } // start generating the actions box $output .= ' <div class="zdc-box zdc-actions"> <ul> '; // actions specific to successful queries if ($block == 'successful-queries') { // info about whether the query results were taken from cache or not if ($debug_info['from_cache'] != 'nocache') { $output .= ' <li class="zdc-cache"> <strong>' . $this->language['from_cache'] . ' (' . $this->caching_method . ')</strong> </li> '; } // info about execution time $output .= ' <li class="zdc-time">' . $this->language['execution_time'] . ': ' . $this->_fix_pow($debug_info['execution_time']) . ' ' . $this->language['miliseconds'] . ' (<strong>' . number_format($this->total_execution_time != 0 ? $debug_info['execution_time'] * 100 / $this->total_execution_time : 0, 2, '.', ',') . '</strong>%) </li> '; // if not an action query if ($debug_info['affected_rows'] === false) { // button for reviewing returned rows $output .= ' <li class="zdc-records"> <a href="javascript:zdc_toggle(\'zdc-records-sq' . $counter . '\')">' . $this->language['returned_rows'] . ': <strong>' . $debug_info['returned_rows'] . '</strong> </a> </li> '; } else { // info about affected rows $output .= ' <li class="zdc-affected">' . $this->language['affected_rows'] . ': <strong>' . $debug_info['affected_rows'] . '</strong> </li> '; } // if EXPLAIN is available (only for SELECT queries) if (is_array($debug_info['explain'])) { // button for reviewing EXPLAIN results $output .= ' <li class="zdc-explain"> <a href="javascript:zdc_toggle(\'zdc-explain-sq' . $counter . '\')">' . $this->language['explain'] . ' </a> </li> '; } } // if backtrace information is available if (isset($debug_info['backtrace'])) { $output .= ' <li class="zdc-backtrace"> <a href="javascript:zdc_toggle(\'zdc-backtrace-' . $identifier . $counter . '\')">' . $this->language['backtrace'] . ' </a> </li> '; } // common actions (to top, close all) $output .= ' <li class="zdc-top"> <a href="' . preg_replace('/\\#zdc\\-top$/i', '', $_SERVER['REQUEST_URI']) . '#zdc-top">' . $this->language['to_top'] . ' </a> </li> <li class="zdc-close"> <a href="javascript:zdc_closeAll(\'\')">' . $this->language['close_all'] . ' </a> </li> '; // wrap up actions bar $output .= ' </ul> <div class="clear"></div> </div> '; // data tables (backtrace, returned rows, explain) // let's see what tables do we need to display $tables = array(); // if query did return records if (!empty($debug_info['records'])) { $tables[] = 'records'; } // if explain is available if (isset($debug_info['explain']) && is_array($debug_info['explain'])) { $tables[] = 'explain'; } // if backtrace is available if (isset($debug_info['backtrace'])) { $tables[] = 'backtrace'; } // let's display data foreach ($tables as $table) { // start generating output $output .= ' <div id="zdc-' . $table . '-' . $identifier . $counter . '" class="zdc-box zdc-' . $table . '-table"> <table cellspacing="0" cellpadding="0" border="0"> <tr> '; // print table headers foreach (array_keys($debug_info[$table][0]) as $header) { $output .= '<th>' . $header . '</th>'; } $output .= '</tr>'; // print table rows and columns foreach ($debug_info[$table] as $index => $row) { $output .= '<tr class="' . (($index + 1) % 2 == 0 ? 'even' : '') . '">'; foreach (array_values($row) as $column) { $output .= '<td valign="top">' . $column . '</td>'; } $output .= '</tr>'; } // wrap up data tables $output .= ' </table> </div> '; } // finish block $output .= ' </td> </tr> </table> '; } // if anything was generated for the current block // enclose generated output in a special div if ($counter > 0) { $blocks[$block]['generated'] = '<div id="zdc-' . $block . '">' . $output . '</div>'; } } elseif ($block == 'globals') { // globals to show $globals = array('POST', 'GET', 'SESSION', 'COOKIE', 'FILES', 'SERVER'); // start building output $output = ' <div id="zdc-globals-submenu"> <ul> '; // iterate through the superglobals to show foreach ($globals as $global) { // add button to submenu $output .= '<li> <a href="javascript:zdc_toggle(\'zdc-globals-' . strtolower($global) . '\')">$_' . $global . ' </a> </li> '; } // finish building the submenu $output .= ' </ul> <div class="clear"></div> </div> '; // iterate thought the superglobals to show foreach ($globals as $global) { // make the superglobal available global ${'_' . $global}; // add to the generated output $output .= ' <table cellspacing="0" cellpadding="0" border="0" id="zdc-globals-' . strtolower($global) . '" class="zdc-entry"> <tr> <td class="zdc-counter" valign="top">001</td> <td class="zdc-data"> <div class="zdc-box"> <strong>$_' . $global . '</strong> <pre>' . htmlentities(var_export(${'_' . $global}, true)) . '</pre> </div> </td> </tr> </table> '; } // enclose generated output in a special div $output = '<div id="zdc-globals">' . $output . '</div>'; $blocks[$block]['generated'] = $output; } } // if there's an error, show the console if ($blocks['unsuccessful-queries']['counter'] > 0 || $blocks['errors']['counter'] > 0) { $this->minimize_console = false; } // finalize output by enclosing the debugging console's menu and generated blocks in a container $output = ' <div id="zdc" style="display:' . ($this->minimize_console ? 'none' : 'block') . '"> <a name="zdc-top"></a> <ul class="zdc-main"> '; // are there any error messages? if ($blocks['errors']['counter'] > 0) { // button for reviewing errors $output .= ' <li> <a href="javascript:zdc_toggle(\'zdc-errors\')">' . $this->language['errors'] . ': <span>' . $blocks['errors']['counter'] . '</span> </a> </li> '; } // common buttons $output .= ' <li> <a href="javascript:zdc_toggle(\'zdc-successful-queries\')">' . $this->language['successful_queries'] . ': <span>' . $blocks['successful-queries']['counter'] . '</span> (' . $this->_fix_pow($this->total_execution_time) . ' ' . $this->language['miliseconds'] . ') </a> </li> <li> <a href="javascript:zdc_toggle(\'zdc-unsuccessful-queries\')">' . $this->language['unsuccessful_queries'] . ': <span>' . $blocks['unsuccessful-queries']['counter'] . '</span> </a> </li> '; if (isset($this->debug_info['warnings'])) { $output .= ' <li> <a href="javascript:zdc_toggle(\'zdc-warnings\')">' . $this->language['warnings'] . ': <span>' . count($this->warnings) . '</span> </a> </li> '; } $output .= ' <li> <a href="javascript:zdc_toggle(\'zdc-globals-submenu\')">' . $this->language['globals'] . ' </a> </li> '; // wrap up debugging console's menu $output .= ' </ul> <div class="clear"></div> '; foreach (array_keys($blocks) as $block) { $output .= $blocks[$block]['generated']; } // wrap up $output .= '</div>'; // add the minified version of the debugging console $output .= ' <div id="zdc-mini"> <a href="javascript:zdc_toggle(\'console\')">' . $blocks['successful-queries']['counter'] . ($warnings ? '<span>!</span>' : '') . ' / ' . $blocks['unsuccessful-queries']['counter'] . ' </a> </div> '; // use the provided resource path for stylesheets and javascript (if any) if (!is_null($this->resource_path)) { $path = rtrim(preg_replace('/\\\\/', '/', '//' . $_SERVER['SERVER_NAME'] . ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : '') . DIRECTORY_SEPARATOR . $this->resource_path), '/'); } else { // this is the url that will be used for automatically including // the CSS and the JavaScript files $path = rtrim(preg_replace('/\\\\/', '/', '//' . $_SERVER['SERVER_NAME'] . ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : '') . DIRECTORY_SEPARATOR . substr(dirname(__FILE__), strlen(realpath($_SERVER['DOCUMENT_ROOT'])))), '/'); } // link the required javascript $output = '<script type="text/javascript" src="' . $path . '/public/javascript/database.js"></script>' . $output; // link the required css file $output = '<link rel="stylesheet" href="' . $path . '/public/css/database.css" type="text/css">' . $output; // if output is to be returned rather than printed to the screen if ($return) { return $output; } // show generated output echo $output; } }
/** * Formats and/or highlights the given SQL statement. * * @param string $sql * @param bool $highlightOnly If true the query is not formatted, just highlighted * * @return string */ public function formatQuery($sql, $highlightOnly = false) { \SqlFormatter::$pre_attributes = 'class="highlight highlight-sql"'; \SqlFormatter::$quote_attributes = 'class="string"'; \SqlFormatter::$backtick_quote_attributes = 'class="string"'; \SqlFormatter::$reserved_attributes = 'class="keyword"'; \SqlFormatter::$boundary_attributes = 'class="symbol"'; \SqlFormatter::$number_attributes = 'class="number"'; \SqlFormatter::$word_attributes = 'class="word"'; \SqlFormatter::$error_attributes = 'class="error"'; \SqlFormatter::$comment_attributes = 'class="comment"'; \SqlFormatter::$variable_attributes = 'class="variable"'; if ($highlightOnly) { $html = \SqlFormatter::highlight($sql); $html = preg_replace('/<pre class=".*">([^"]*+)<\\/pre>/Us', '\\1', $html); } else { $html = \SqlFormatter::format($sql); $html = preg_replace('/<pre class="(.*)">([^"]*+)<\\/pre>/Us', '<div class="\\1"><pre>\\2</pre></div>', $html); } return $html; }