Last active
March 26, 2025 20:23
-
-
Save oranblackwell/8ee78c36d7bccf523682 to your computer and use it in GitHub Desktop.
Procedural debug
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
if ( !function_exists ( 'debug' ) ) { | |
/** | |
* | |
* A set of procedural debug tools designed for universal compatibility across a wide range of environments, | |
* including legacy systems running end-of-life (EOL) versions of software. | |
* | |
* @author Oran Blackwell | |
* @internal This function is for internal use only | |
* @version 3.6.1 | |
*/ | |
/* Since PHP 5.1.0 using date_default_timezone_set() prevents: | |
* Warning: date() [function.date]: It is not safe to rely on the system's timezone settings.*/ | |
if ( function_exists ( 'date_default_timezone_set' ) ) { | |
date_default_timezone_set ( "Europe/Dublin" ); | |
} | |
function DEFINE_debug_allowed_IP() { | |
/** | |
* Simple function which maintains the list of allowed IPs for this set of debug functions | |
* | |
* @param bool|string $ip optional | |
* | |
* @return boolean TRUE | FALSE | |
*/ | |
function debug_allowed_IP( $ip = false ) { | |
if ( $ip == false ) { | |
$ip = $_SERVER['REMOTE_ADDR']; | |
} | |
$allowedIPs = array ( | |
"172.27.103.70", | |
"::1", | |
"127.0.0.1" | |
); | |
if ( in_array ( $ip, $allowedIPs ) ) { | |
return true; | |
} | |
return false; | |
} | |
} | |
function DEFINE_debug() { | |
/** | |
* Recursive Function which attempts to parse anything passed to it and return the formated details | |
* @since debug version 1.0.0 | |
* | |
* @param mixed $args mandatory | |
* @param string $title optional | |
* @param boolean $toOutput optional default TRUE - Should the result be echod or returned | |
* @param mixed $isDebugMail optional default FALSE - debug_mail() has slightly exceptional behaviour | |
* @param mixed $indent optional default NULL - ability to modify the indentation | |
* | |
* @return string $toReturn | |
*/ | |
function debug( $args, $title = '', $toOutput = true, $isDebugMail = false, $indent = null ) { | |
if ( debug_allowed_IP ( debug_getuserip () ) || $isDebugMail == true ) { | |
$indenter = " "; //$indenter = "\t"; | |
$recursive_indent = "<span style='color:#AAAAAA;'>:</span>$indenter"; | |
$doc_root = str_replace ( '\\', '/', $_SERVER['DOCUMENT_ROOT'] ); | |
$backtrace = debug_backtrace (); | |
$line = htmlspecialchars ( $backtrace[0]['line'] ); | |
$file = htmlspecialchars ( str_replace ( array ( '\\', $doc_root ), array ( '/', '' ), $backtrace[0]['file'] ) ); | |
$class = !empty( $backtrace[1]['class'] ) ? htmlspecialchars ( $backtrace[1]['class'] ).'::' : ''; | |
$function = !empty( $backtrace[1]['function'] ) ? htmlspecialchars ( $backtrace[1]['function'] ).'() ' | |
: ''; | |
$output = '<strong>'.$class.$function.' => '.$file.' #'.$line."</strong>\r\n"; | |
$toReturn = ''; | |
if ( is_object ( $args ) ) { | |
$type = get_class ( $args ); | |
$toReturn .= $indent.$title.' <span style="color:#666">'.$type.'</span><br />'.$indent.'(<br />'; | |
foreach ( $args as $name => $value ) { | |
$toReturn .= debug ( $value, $name, false, true, $indent.$recursive_indent ); | |
} | |
ob_start (); | |
var_dump ( $args ); | |
$toReturn .= ob_get_clean (); | |
$toReturn .= $indent.')<br />'; | |
} elseif ( is_array ( $args ) ) { | |
$count = count ( $args ); | |
$type = 'Array'; | |
$toReturn .= $indent.$title.' = <span style="color:#666">'.$type.' ('.$count.')</span><br />'.$indent.'(<br />'; | |
$keys = array_keys ( $args ); | |
if ( array_keys ( $args ) == range ( 0, count ( $args ) ) ) { | |
$isAssoc = false; | |
} else { | |
$isAssoc = true; | |
} | |
foreach ( $keys as $name ) { | |
$value = $args[$name]; | |
$toReturn .= debug ( | |
$value, | |
( $isAssoc == true ? '['.$name.']' : '---'.$name ), | |
false, | |
true, | |
$indent.$recursive_indent | |
); | |
} | |
$toReturn .= $indent.')<br />'; | |
} elseif ( is_string ( $args ) ) { | |
$args = str_replace ( "\t", " ", $args ); | |
$type = 'String'; | |
$type_color = '<span style="color:#008000">'; | |
$toReturn .= $indent.$title.' = <span style="color:#666">'.$type.'('.strlen ( | |
$args | |
).')</span> ' | |
.$type_color.htmlentities ( $args ).'</span><br />'; | |
} elseif ( is_int ( $args ) ) { | |
$type = 'Integer'; | |
$type_color = '<span style="color:red">'; | |
$toReturn .= $indent.$title.' = <span style="color:#666">'.$type.'('.strlen ( | |
$args | |
).')</span> ' | |
.$type_color.htmlentities ( $args ).'</span><br />'; | |
} elseif ( is_null ( $args ) ) { | |
$type = 'NULL'; | |
$type_color = '<span style="color:#666">'; | |
$toReturn .= $indent.$title.'= <span style="color:#666">'.$type.'('.strlen ( | |
$args | |
).')</span>' | |
.$type_color.' -NULL-</span><br />'; | |
} elseif ( is_bool ( $args ) ) { | |
$type = 'boolean'; | |
$type_color = '<span style="color:#92008d">'; | |
$toReturn .= $indent.$title.'= <span style="color:#666">'.$type.'('.strlen ( | |
$args | |
).')</span>' | |
.$type_color.( $args == 1 ? 'TRUE' : 'FALSE' ).'</span><br />'; | |
} elseif ( is_float ( $args ) ) { | |
$type = 'Float'; | |
$type_color = '<span style="color:#0099c5">'; | |
$toReturn .= $indent.$title.' = <span style="color:#666">'.$type.'('.strlen ( | |
$args | |
).')</span> ' | |
.$type_color.htmlentities ( $args ).'</span><br />'; | |
} elseif ( is_resource ( $args ) ) { | |
//for things like myConnection | |
$type = 'Resource'; | |
$type_color = '<span style="color:#FF8000">'; | |
ob_start (); | |
var_dump ( $args ); | |
$output = ob_get_clean (); | |
$toReturn .= $indent.$title.' = <span style="color:#666">'.$type.' => '.$output.'</span> ' | |
.$type_color.htmlentities ( $args ).'</span><br />'; | |
} | |
if ( $toOutput === true ) { | |
echo '<div style="text-align:left; background-color:white; font: 100% monospace; color:black;">'; | |
if ( $title != '' ) { | |
echo '<strong>'.$title.': </strong>'; | |
} | |
echo '<pre>'.$output.$toReturn.'</pre></div>'; | |
} else { | |
return $toReturn; | |
} | |
} | |
} | |
} | |
function DEFINE_debug_mail() { | |
function debug_mail( $args, $subject = 'debug' ) { | |
$doc_root = str_replace ( '\\', '/', $_SERVER['DOCUMENT_ROOT'] ); | |
$backtrace = debug_backtrace (); | |
$line = htmlspecialchars ( $backtrace[0]['line'] ); | |
$file = htmlspecialchars ( str_replace ( array ( '\\', $doc_root ), array ( '/', '' ), $backtrace[0]['file'] ) ); | |
$class = !empty( $backtrace[1]['class'] ) ? htmlspecialchars ( $backtrace[1]['class'] ).'::' : ''; | |
$function = !empty( $backtrace[1]['function'] ) ? htmlspecialchars ( $backtrace[1]['function'] ).'() ' : ''; | |
$output = "<strong>$class$function => $file #$line</strong>\r\n"; | |
$from = '[email protected]'; | |
$headers = 'MIME-Version: 1.0'."\r\n"; | |
$headers .= 'Content-type: text/html; charset=iso-8859-1'."\r\n"; | |
$headers .= 'From: '.$from."\r\n". | |
'Reply-To: '.$from."\r\n". | |
'X-Mailer: PHP/'.phpversion (); | |
mail ( | |
"[email protected]", | |
$subject.' '.date ( 'Y-m-d H:i:s' ), | |
$output.debug ( $args, $subject, false, true ), | |
$headers | |
); | |
} | |
} | |
/** | |
* | |
*/ | |
function DEFINE_mysql_query_log() { | |
function mysql_query_log( $q, $message, $username, $file ) { | |
if ( !mysql_query ( $q ) ) { | |
$status = "ERROR"; | |
$message = mysql_error (); | |
// array for storing errors querying database | |
global $mysql_query_log_errors; | |
$mysql_query_log_errors[] = array ( | |
"file" => $file, | |
"error" => $message, | |
"when" => date ( 'Y/m/d H:i:s' ), | |
"query" => $q | |
); | |
$status = "ERROR (DISPLAYED)"; | |
} else { | |
$status = "OK"; | |
global $mysql_insert_id; | |
$mysql_insert_id = mysql_insert_id (); | |
} | |
$q = 'INSERT INTO query_log (username, status, file, query, message) VALUES | |
("'.$username.'", "'.$status.'", "'.$file.'", "'.mysql_real_escape_string ( | |
$q | |
).'","'.$message.'")'; | |
mysql_query ( $q ); | |
} | |
} | |
function DEFINE_check_mysql_errors() { | |
function check_mysql_errors( &$errorContent = null ) { | |
$mysql_query_log_errors = $GLOBALS['mysql_query_log_errors']; | |
$count = count ( $mysql_query_log_errors ); | |
// check if sql errors occured | |
if ( $count > 0 ) { | |
$errorContent .= ' | |
<div id="errorsHolder"> | |
<div id="errorsClicker"><a href="#">Error Log: Show / Hide </a></div> | |
<h1>WARNING: '.$count.' error(s) occured:</h1> | |
<div id="errorsHidable"> | |
<table border="1" width=100%>'; | |
foreach ( $mysql_query_log_errors AS $key => $value ) { | |
$errorContent .= '<tr><td colspan=2 class="error"> | |
Error '.++$key.':</td></td>'; | |
foreach ( $value AS $k => $v ) { | |
$errorContent .= '<tr> | |
<td class="errorHeader">'; | |
if ( $k != 'query' ) { | |
$errorContent .= $k.'</td> | |
<td style="padding: 5px;">'; | |
$errorContent .= nl2br ( $v ); | |
} else { | |
$errorContent .= '<a href="#error_'.$key.'" class="showHide">'.$k.'</a></td> | |
<td class="hiddenError" id="error_'.$key.'">'; | |
$errorContent .= nl2br ( $v ); | |
} | |
$errorContent .= '</td> | |
</tr>'; | |
} | |
} | |
$errorContent .= ' | |
</table> | |
</div> | |
</div>'; | |
return $errorContent; | |
} | |
} | |
} | |
function DEFINE_debug_mysql_query() { | |
function debug_mysql_query( $q ) { | |
//@todo why do I check the IP twice? | |
if ( mysql_error () && debug_allowed_IP ( debug_getuserip () ) ) { | |
debug ( array ( mysql_error (), $q ) ); | |
} else { | |
debug ( $q ); | |
} | |
} | |
} | |
function DEFINE_debug_function_declaration() { | |
function debug_function_declaration( $args ) { | |
if ( debug_allowed_IP ( debug_getuserip () ) ) { | |
$r = new ReflectionFunction( $args ); | |
$file = $r->getFileName (); | |
$startLine = $r->getStartLine (); | |
debug ( array ( "Filename" => $file, "Start Line" => $startLine ) ); | |
} | |
} | |
} | |
function DEFINE_debug_log_query() { | |
function debug_log_query( $q ) { | |
if ( mysql_error () ) { | |
debug_log ( array ( mysql_error (), $q ) ); | |
} else { | |
debug_log ( $q ); | |
} | |
} | |
} | |
function DEFINE_debug_log() { | |
function debug_log( $args, $subject = "debug_log" ) { | |
$doc_root = str_replace ( '\\', '/', $_SERVER['DOCUMENT_ROOT'] ); | |
$backtrace = debug_backtrace (); | |
$line = htmlspecialchars ( $backtrace[0]['line'] ); | |
$file = htmlspecialchars ( str_replace ( array ( '\\', $doc_root ), array ( '/', '' ), $backtrace[0]['file'] ) ); | |
$class = !empty( $backtrace[1]['class'] ) ? htmlspecialchars ( $backtrace[1]['class'] ).'::' : ''; | |
$function = !empty( $backtrace[1]['function'] ) ? htmlspecialchars ( $backtrace[1]['function'] ).'() ' : ''; | |
$output = "<br /><strong>$class$function => $file #$line</strong><br />"; | |
$logFile = "logs/log-".date ( "Y-m-d" ).".html"; | |
$newContent = '<div class="likeXML"><ul><li class="collapseXML"><div><<span class="start-tag">' | |
.date ( "Y-m-d H:i:s" ) | |
.'</span>></div> | |
'.debug ( $args, $subject, false, true ).' | |
<div><<span class="end-tag">' | |
.date ( "Y-m-d H:i:s" ) | |
.'</span>></div></li></ul></div> | |
'; | |
if ( is_writable ( $logFile ) ) { | |
if ( !$handle = fopen ( $logFile, 'a' ) ) { | |
/* To be handled: Cannot open file ($logFile)*/ | |
} | |
fwrite ( $handle, $newContent ); | |
/*Prepend as opposed to append the data | |
* @~todo Doesnt seem to work on windows 7 for some reason | |
*/ | |
/*$len = strlen($newContent); | |
$final_len = filesize($file) + $len; | |
$cache_old = fread($handle, $len); | |
rewind($handle); | |
$i = 1; | |
while (ftell($handle) < $final_len) { | |
fwrite($handle, $newContent); | |
$newContent = $cache_old; | |
$cache_old = fread($handle, $len); | |
fseek($handle, $i * $len); | |
$i++; | |
}*/ | |
fclose ( $handle ); | |
} else { | |
/* @~todo Handle this, the file $logFile is not writable*/ | |
} | |
} | |
} | |
function DEFINE_debug_exit() { | |
function debug_exit( $exitOthers = false ) { | |
if ( $_GET['secret'] == "2894124" && debug_allowed_IP ( debug_getuserip () ) ) { | |
if ( $exitOthers == false ) { | |
exit(); | |
} | |
} elseif ( $exitOthers == true ) { | |
exit(); | |
} | |
} | |
} | |
function DEFINE_debug_getuserip() { | |
function debug_getuserip() { | |
if ( isset( $_SERVER ) ) { | |
if ( isset( $_SERVER["HTTP_X_FORWARDED_FOR"] ) ) { | |
return $_SERVER["HTTP_X_FORWARDED_FOR"]; | |
} | |
if ( isset( $_SERVER["HTTP_CLIENT_IP"] ) ) { | |
return $_SERVER["HTTP_CLIENT_IP"]; | |
} | |
return $_SERVER["REMOTE_ADDR"]; | |
} | |
if ( getenv ( 'HTTP_X_FORWARDED_FOR' ) ) { | |
return getenv ( 'HTTP_X_FORWARDED_FOR' ); | |
} | |
if ( getenv ( 'HTTP_CLIENT_IP' ) ) { | |
return getenv ( 'HTTP_CLIENT_IP' ); | |
} | |
return getenv ( 'REMOTE_ADDR' ); | |
} | |
} | |
function DEFINE_debug_keepsecret() { | |
function debug_keepsecret( $arg = '?', $toOutput = true ) { | |
if ( isset( $_GET['secret'] ) && $_GET['secret'] != '' ) { | |
$toReturn = $arg.'secret='.$_GET['secret']; | |
if ( $toOutput == true ) { | |
echo $toReturn; | |
} else { | |
return $toReturn; | |
} | |
} | |
} | |
} | |
/** I use this method of declaration as some versions of PHP parse the script for | |
* defined functions/classes first | |
* So if(!function_exists('debug')) wasn't working on a couple of servers. | |
*/ | |
DEFINE_debug (); | |
DEFINE_debug_mail (); | |
DEFINE_debug_mysql_query (); | |
DEFINE_debug_log_query (); | |
DEFINE_mysql_query_log (); | |
DEFINE_check_mysql_errors (); | |
DEFINE_debug_function_declaration (); | |
DEFINE_debug_log (); | |
DEFINE_debug_exit (); | |
DEFINE_debug_getuserip (); | |
DEFINE_debug_keepsecret (); | |
DEFINE_debug_allowed_ip (); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment