## Last changed : 31.03.2009 10:15:13 ## Revision : 45 ## Website : http://phpdebuglib.de ############################################################ /* * Copyright (C) 2004-2009 by Thomas Schüßler * Written by Thomas Schüßler * All Rights Reserved * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ if(function_exists('print_a')): return; // debuglib was already included before else: if(!defined('USE_DEBUGLIB')) define('USE_DEBUGLIB', TRUE); if(!array_key_exists('DEBUGLIB_LVL', $GLOBALS)) $GLOBALS['DEBUGLIB_LVL'] = 99; // 99 debug levels should be enough for everyone if(!array_key_exists('DEBUGLIB_MAX_Y', $GLOBALS)) $GLOBALS['DEBUGLIB_MAX_Y'] = 50; // how much items per level should get displayed (max_y) if(!array_key_exists('DEBUGLIB_MAIL_ENCODING', $GLOBALS)) $GLOBALS['DEBUGLIB_MAIL_ENCODING'] = 'utf-8'; // encoding for the mail option if(!array_key_exists('USE_DEBUGLIB', $GLOBALS)) $GLOBALS['USE_DEBUGLIB'] = USE_DEBUGLIB; // you can set this to TRUE if you have to overwrite the setting in a live environment $GLOBALS['DbugL_Globals'] = array(); $GLOBALS['DbugL_Globals']['microtime_start'] = microtime(TRUE); $GLOBALS['DbugL_Globals']['initial_globals_count'] = count($GLOBALS); class DbugL { public static $first_call = TRUE; // shortcuts for the pros public static $alt_parameter_names = array( 'trim_tabs' => array('tt'), 'label' => array('l'), 'max_y' => array('y'), 'return' => array('r'), 'window' => array('w'), 'window_link' => array('wl'), 'debug_level' => array('lvl'), 'show_objects' => array('so'), 'pickle' => array('p'), 'mail' => array('m'), 'mail_encoding'=> array('me'), 'escape_html' => array('e'), ); public static function help($return_mode = FALSE) { $html = '
print_a(mixed input [, string option_string])


The function you will use most often, prints a colorful representation of your PHP data

$option_string must be in the CSS like syntax:

e.g. "max_y:5;window:1;label:my_array"

If there is no ":" in the options string, the whole string will be used as the text for the label. new

Valid options:
return: (0|1) Do not print the output and instead return it as a string.
label: (string) Draw a fieldset/legend around the output.
max_y: (1-n) Maximum number of items on the same level. [...] (defaults to 50)
pickle: (0|1) Print a serialized representation of the array instead of printing it as a table.
export: (0|1) Print PHP sourcecode of the array. new
trim_tabs: (0-n) Trim the leading tabs in multiline strings and pad with n tabs.
window: (string) The output should open in a new window (javascript), the parameter is also the title for the window.
window_link: (0|1) Don\'t open a window, just print a link which opens one when clicked. new
debug_level: (0-99) Only do something if the debug level value is <= the global debug level ($GLOBALS[\'DEBUGLIB_LVL\'] default 99) new
You can also set it to an array with the levels you want to display e.g. $GLOBALS[\'DEBUGLIB_LVL\'] = array(3,5)
avoid@: (0|1) If a key starts with the character "@", assume it is a recursive reference and don\'t follow it.
mail: (string) Mail the ouput as HTML mail to the supplied email address. new
mail_encoding: (string) encoding for the HTML mail. (defaults to "utf-8")

'.print_a(self::$alt_parameter_names, 'return:1;label:You can also use these
short parameter names:').'
show_vars([string option_string])


Prints all superglobals like $_GET, $_POST, $_SESSION etc. in a big table.
Good for printing at the bottom of a page.

Options are the same as for print_a + the following options:
verbose: also show $_SERVER and $_ENV

script_runtime([bool return_mode [, string title [, string css_style]]] )


Prints the passed time since the start of the script (or the last script_runtime call) in seconds.

pre(string string [, string option_string])


Print a string so the whitespaces are visible in HTML.

option_string must be in the CSS like syntax:

eg. "r:1;trim_tabs:0;"

Possible options:
return: (0|1) return the output instead of printing it
trim_tabs: (0-n) same as in print_a()

You can disable the output of all the functions in a production environment by setting $GLOBALS[\'USE_DEBUGLIB\'] to FALSE (e.g. trough auto_prepend in your php.ini).

And if you have to do some online debugging you can enable it again somewhere in your script by setting it to TRUE.
'; if($return_mode) { return $html; } else { print $html; } } public $window_open_tracker = array(); private $default_options = array( 'label' => NULL, 'window' => NULL, 'window_link' => FALSE, 'max_y' => 0, 'test_for_recursions' => FALSE, 'show_objects' => TRUE, 'trim_tabs' => NULL, 'avoid@' => FALSE, 'return' => FALSE, 'pickle' => FALSE, 'export' => FALSE, 'escape_html' => 2, 'mail' => NULL, 'mail_encoding' => 'utf-8', // iso-8859-1 'debug_level' => 0, ); public $options = array(); public $single_value_flag = FALSE; private $element_counter = 0; private $window_html; private $color_cache = array(); # cache the gradient colors private $open_windows = array(); const runtime_precision = 6; # used for the seconds output of script_runtime() const object_key_marker = '<:~!OBJECT_KEY!~:>'; #TODO# hackish // default colors for the gradient start const key_bg_color_default = '00456A'; const key_bg_color_array = '10187E'; const key_bg_color_object = '60008F'; const key_bg_color_object_data = '60008F'; const color_step_width = 10; public static $css = ' '; public function __construct() { $this->window_html = ' '.self::$css.' '; } public static function escape_js($string) { $string = str_replace(array("\r\n", "\n", "\r"), '\n', $string); $string = str_replace('options['label'])) { if($this->options['pickle'] == TRUE || $this->options['export'] == TRUE) { $html = '
'.$this->options['label'].''.$html.'
'; } else { $html = '
'.$this->options['label'].''.$html.'
'; } } $html = '
'.$html.'
'; return $html; } // used by show_vars to get all globals defined in a script (minus the core PHP stuff) public static function script_globals() { $varcount = 0; $script_globals = array(); foreach($GLOBALS as $variable_name => $variable_value) { if(++$varcount > $GLOBALS['DbugL_Globals']['initial_globals_count']) { /* die wollen wir nicht! */ if ($variable_name != 'HTTP_SESSION_VARS' && $variable_name != '_SESSION') { $script_globals[$variable_name] = $variable_value; } } } unset($GLOBALS['DbugL_Globals']['initial_globals_count']); return $script_globals; } } // DbugL // ------------------------------- here come the global user functions ------------------------------- // function pre($string, $options_string = NULL) { if(!$GLOBALS['USE_DEBUGLIB']) return; $options = DbugL::parse_options($options_string); if(isset($options['debug_level']) && $options['debug_level'] > $GLOBALS['DEBUGLIB_LVL'] ) return; if(isset($options['trim_tabs'])) { $string = DbugL::trim_leading_tabs($string, $options['trim_tabs']); } $html = DbugL::html_prefix().'
'.DbugL::format_string($string).'
'; if(isset($options['return']) && $options['return'] == '1') { return $html; } else { print $html; } } function pre_die($string, $options_string = NULL) { if(!$GLOBALS['USE_DEBUGLIB']) return; pre($string, $options_string); die; } // shows time elapsed since last call function script_runtime($label = '', $style = '', $return_mode = FALSE) { $bt = debug_backtrace(); $bt = $bt[1]; $title = "({$bt['line']}) {$bt['file']}"; if($label != '') $label = '['.$label.'] '; if(!$GLOBALS['USE_DEBUGLIB']) return; $now_time = microtime(TRUE); if(isset($GLOBALS['DbugL_Globals']['last_microtime'])) { $step_time = $now_time - $GLOBALS['DbugL_Globals']['last_microtime']; } $GLOBALS['DbugL_Globals']['last_microtime'] = $now_time; $elapsed_time = sprintf('%01.'.DbugL::runtime_precision.'f', $now_time - $GLOBALS['DbugL_Globals']['microtime_start']); $html = DbugL::html_prefix().'
'.$label.' time: '.$elapsed_time.(isset($step_time) ? ' ('.sprintf('%01.'.DbugL::runtime_precision.'f', $step_time).' since last call)' : '').'
'; if($return_mode) { return $html; } else { print $html; } } // the interface function for Debuglib::_print_a() function print_a($input, $options_string = NULL) { if(!$GLOBALS['USE_DEBUGLIB']) return; static $DbugL; if(!$DbugL) $DbugL = new DbugL; $DbugL->set_options($options_string); if(!is_array($input) && !is_object($input) || (is_array($input) && count($input) == 0)) { $DbugL->single_value_flag = TRUE; #hackish $input = array('('.gettype($input).')' => $input); } if(! Dbugl::test_level($DbugL->options['debug_level'])) return; $html = ''; // use print_r() to check for a recursion in the structure if($DbugL->options['test_for_recursions'] && strpos(print_r($input, 1), '*RECURSION*') !== FALSE) { $html = 'RECURSION detected!'; } else { $DbugL->print_a($input, $html); } // open a window for the output? if(isset($DbugL->options['window'])){ if($DbugL->options['pickle'] == TRUE) { $pickled_input = serialize($input); $pickled_input = str_replace("'", "\\\'", $pickled_input ); $pickled_input = ''; $html = $DbugL->js_for_popup($DbugL->get_html($pickled_input)); } elseif($DbugL->options['export'] == TRUE) { $export_input = var_export($input, TRUE); $export_input = ''; $html = $DbugL->js_for_popup($DbugL->get_html($export_input)); } else { $html = $DbugL->js_for_popup($DbugL->get_html($html)); } } else { $html = DbugL::html_prefix().$DbugL->get_html($html); } if(isset($DbugL->options['help'])) { $html = DbugL::help($DbugL->options['return']); } if($DbugL->options['mail']) { $headers = 'MIME-Version: 1.0' . "\r\nContent-type: text/html; charset=".$DbugL->options['mail_encoding']."\r\nFrom: debuglib\r\n"; $message = 'debuglib.php @ '.$_SERVER['HTTP_HOST'].''.DbugL::$css.$html.''; mail($DbugL->options['mail'], 'debuglib.php @ '.$_SERVER['HTTP_HOST'], $message, $headers); } elseif($DbugL->options['return'] == '1') { return $html; } else { print $html; } } // call print_a() and die (RIP) function print_a_die($input, $options_string = NULL) { if(!$GLOBALS['USE_DEBUGLIB']) return; print_a($input, $options_string); die; } // deprecated function die_a($input, $options_string = NULL) { if(!$GLOBALS['USE_DEBUGLIB']) return; print_a($input, $options_string); die; } // good for printing all kind of superglobals at the bottom of a page function show_vars($options_string = NULL) { if(!$GLOBALS['USE_DEBUGLIB']) return; $options = DbugL::parse_options($options_string, DbugL::$alt_parameter_names); $print_a_options = $options_string.';return:1;'; $superglobals = array( 'Script $GLOBALS' => DbugL::script_globals(), '$_GET' => $_GET, '$_POST' => $_POST, '$_FILES' => $_FILES, '$_SESSION' => $_SESSION, '$_COOKIE' => $_COOKIE, ); if(isset($options['verbose']) && $options['verbose'] == '1') { $superglobals['$_SERVER'] = $_SERVER; $superglobals['$_ENV'] = $_ENV; } $html = DbugL::html_prefix().script_runtime('before show_vars','background:#BBB;',TRUE,TRUE); $html .= ''; foreach($superglobals as $name => $reference) { if(empty($reference)) continue; $class_name = $name == 'Script $GLOBALS' ? 'globals' : strtolower(str_replace('$_', '', $name)); $html .= ''; } $html .= '
'.$name.'
'; $html .= print_a($reference, $print_a_options); $html .= '
'.script_runtime('after show_vars','background:#BBB;',TRUE,TRUE); if(@$options['return'] == '1') { return $html; } else { print $html; } } // prints out a mysql result.. work in progress.. use at your own risk function print_mysql_result($mysql_result, $return_mode = FALSE) { if(!$GLOBALS['USE_DEBUGLIB']) return; if(!$mysql_result || mysql_num_rows($mysql_result) < 1) return; $field_count = mysql_num_fields($mysql_result); $tables = array(); for($i=0; $i<$field_count; $i++) { if(isset($tables[mysql_field_table($mysql_result, $i)])) { $tables[mysql_field_table($mysql_result, $i)]++; } else { $tables[mysql_field_table($mysql_result, $i)] = 1; } } $html = ' '; $html .= ''; $html .= ''; foreach($tables as $tableName => $tableCount) { (!isset($col) || $col == '#006F05') ? $col = '#00A607' : $col = '#006F05'; $html .= ''; } $html .= ''; $html .= ''; for($i=0;$i < mysql_num_fields($mysql_result);$i++) { $field = mysql_field_name($mysql_result, $i); $col == '#0054A6' ? $col = '#003471' : $col = '#0054A6'; $html .= ''; } $html .= ''; mysql_data_seek($mysql_result, 0); $toggle = FALSE; $pointer = 0; $table_id = str_replace('.', '', microtime(TRUE)); while($db_row = mysql_fetch_array($mysql_result, MYSQL_NUM)) { $pointer++; if($toggle) { $col1 = "#E6E6E6"; $col2 = "#DADADA"; } else { $col1 = "#E1F0FF"; $col2 = "#DAE8F7"; } $toggle = !$toggle; $id = 'DbugL_'.$table_id.'_'.$pointer; $html .= ''; foreach($db_row as $i => $value) { $col == $col1 ? $col = $col2 : $col = $col1; $flags = mysql_field_flags($mysql_result, $i); $primary_flag = strpos($flags, 'primary_key') !== FALSE; $html .= ''; } $html .= ''; } $html .= '
'.$tableName.'
'.$field.'
'.nl2br($value).'
'; mysql_data_seek($mysql_result, 0); if($return_mode) { return $html; } else { print $html; } } endif; #TODO# /* inject css through javascript (inline style is bad... m'kay?) unify options parsing debuglevel and default parameter arrays for every function fix fieldset width in IEx debug backtrace issues write a C extension that can test for reference recursions start from scratch :) */