With this optional parameter, that is false by default, you can trigger the init of the JS and CSS. This is needed if you want to use dBug multiple time to e.g. create multiple files (using ob_start etc. ). Until now it would only generate those sections on the first constructor call.
544 lines
17 KiB
PHP
Executable file
544 lines
17 KiB
PHP
Executable file
<?php
|
|
/*********************************************************************************************************************\
|
|
* LAST UPDATE
|
|
* ============
|
|
* August 6th, 2012
|
|
*
|
|
*
|
|
* AUTHOR
|
|
* =============
|
|
* Kwaku Otchere
|
|
* ospinto@hotmail.com
|
|
*
|
|
* AFTERMARKET HACKER
|
|
* ==================
|
|
* Josh Sherman
|
|
* josh@crowdsavings.com
|
|
*
|
|
* Thanks to Andrew Hewitt (rudebwoy@hotmail.com) for the idea and suggestion
|
|
*
|
|
* All the credit goes to ColdFusion's brilliant cfdump tag
|
|
* Hope the next version of PHP can implement this or have something similar
|
|
* I love PHP, but var_dump BLOWS!!!
|
|
*
|
|
* FOR DOCUMENTATION AND MORE EXAMPLES: VISIT http://dbug.ospinto.com
|
|
*
|
|
*
|
|
* PURPOSE
|
|
* =============
|
|
* Dumps/Displays the contents of a variable in a colored tabular format
|
|
* Based on the idea, javascript and css code of Macromedia's ColdFusion cfdump tag
|
|
* A much better presentation of a variable's contents than PHP's var_dump and print_r functions
|
|
*
|
|
*
|
|
* USAGE
|
|
* =============
|
|
* new dBug ( variable [,forceType] );
|
|
* example:
|
|
* new dBug ( $myVariable );
|
|
*
|
|
*
|
|
* if the optional "forceType" string is given, the variable supplied to the
|
|
* function is forced to have that forceType type.
|
|
* example: new dBug( $myVariable , "array" );
|
|
* will force $myVariable to be treated and dumped as an array type,
|
|
* even though it might originally have been a string type, etc.
|
|
*
|
|
* NOTE!
|
|
* ==============
|
|
* forceType is REQUIRED for dumping an xml string or xml file
|
|
* new dBug ( $strXml, "xml" );
|
|
*
|
|
\*********************************************************************************************************************/
|
|
|
|
class dBug {
|
|
|
|
var $xmlDepth=array();
|
|
var $xmlCData;
|
|
var $xmlSData;
|
|
var $xmlDData;
|
|
var $xmlCount=0;
|
|
var $xmlAttrib;
|
|
var $xmlName;
|
|
var $arrType=array("array","object","resource","boolean","NULL");
|
|
var $bInitialized = false;
|
|
var $bCollapsed = false;
|
|
var $arrHistory = array();
|
|
|
|
//constructor
|
|
function dBug($var,$forceType="",$bCollapsed=false, $reinit = false) {
|
|
//include js and css scripts
|
|
if(!defined('BDBUGINIT') || $reinit) {
|
|
if(!defined('BDBUGINIT')){
|
|
define("BDBUGINIT", TRUE);
|
|
}
|
|
$this->initJSandCSS();
|
|
}
|
|
$arrAccept=array("array","object","xml"); //array of variable types that can be "forced"
|
|
$this->bCollapsed = $bCollapsed;
|
|
if(in_array($forceType,$arrAccept))
|
|
$this->{"varIs".ucfirst($forceType)}($var);
|
|
else
|
|
$this->checkType($var);
|
|
}
|
|
|
|
//get variable name
|
|
function getVariableName() {
|
|
$arrBacktrace = debug_backtrace();
|
|
|
|
//possible 'included' functions
|
|
$arrInclude = array("include","include_once","require","require_once");
|
|
|
|
//check for any included/required files. if found, get array of the last included file (they contain the right line numbers)
|
|
for($i=count($arrBacktrace)-1; $i>=0; $i--) {
|
|
$arrCurrent = $arrBacktrace[$i];
|
|
if(array_key_exists("function", $arrCurrent) &&
|
|
(in_array($arrCurrent["function"], $arrInclude) || (0 != strcasecmp($arrCurrent["function"], "dbug"))))
|
|
continue;
|
|
|
|
$arrFile = $arrCurrent;
|
|
|
|
break;
|
|
}
|
|
|
|
if(isset($arrFile)) {
|
|
$arrLines = file($arrFile["file"]);
|
|
$code = $arrLines[($arrFile["line"]-1)];
|
|
|
|
//find call to dBug class
|
|
preg_match('/\bnew dBug\s*\(\s*(.+)\s*\);/i', $code, $arrMatches);
|
|
|
|
return $arrMatches[1];
|
|
}
|
|
return "";
|
|
}
|
|
|
|
//create the main table header
|
|
function makeTableHeader($type,$header,$colspan=2) {
|
|
if(!$this->bInitialized) {
|
|
$header = $this->getVariableName() . " (" . $header . ")";
|
|
$this->bInitialized = true;
|
|
}
|
|
$str_i = ($this->bCollapsed) ? "style=\"font-style:italic\" " : "";
|
|
|
|
echo "<table cellspacing=2 cellpadding=3 class=\"dBug_".$type."\">
|
|
<tr>
|
|
<td ".$str_i."class=\"dBug_".$type."Header\" colspan=".$colspan." onClick='dBug_toggleTable(this)'>".$header."</td>
|
|
</tr>";
|
|
}
|
|
|
|
//create the table row header
|
|
function makeTDHeader($type,$header) {
|
|
$str_d = ($this->bCollapsed) ? " style=\"display:none\"" : "";
|
|
echo "<tr".$str_d.">
|
|
<td valign=\"top\" onClick='dBug_toggleRow(this)' class=\"dBug_".$type."Key\">".$header."</td>
|
|
<td>";
|
|
}
|
|
|
|
//close table row
|
|
function closeTDRow() {
|
|
return "</td></tr>\n";
|
|
}
|
|
|
|
//error
|
|
function error($type) {
|
|
$error="Error: Variable cannot be a";
|
|
// this just checks if the type starts with a vowel or "x" and displays either "a" or "an"
|
|
if(in_array(substr($type,0,1),array("a","e","i","o","u","x")))
|
|
$error.="n";
|
|
return ($error." ".$type." type");
|
|
}
|
|
|
|
//check variable type
|
|
function checkType($var) {
|
|
switch(gettype($var)) {
|
|
case "resource":
|
|
$this->varIsResource($var);
|
|
break;
|
|
case "object":
|
|
$this->varIsObject($var);
|
|
break;
|
|
case "array":
|
|
$this->varIsArray($var);
|
|
break;
|
|
case "NULL":
|
|
$this->varIsNULL();
|
|
break;
|
|
case "boolean":
|
|
$this->varIsBoolean($var);
|
|
break;
|
|
default:
|
|
$var=($var=="") ? "[empty string]" : $var;
|
|
echo "<table cellspacing=0><tr>\n<td>".$var."</td>\n</tr>\n</table>\n";
|
|
break;
|
|
}
|
|
}
|
|
|
|
//if variable is a NULL type
|
|
function varIsNULL() {
|
|
echo "NULL";
|
|
}
|
|
|
|
//if variable is a boolean type
|
|
function varIsBoolean($var) {
|
|
$var=($var==1) ? "TRUE" : "FALSE";
|
|
echo $var;
|
|
}
|
|
|
|
//if variable is an array type
|
|
function varIsArray($var) {
|
|
$var_ser = serialize($var);
|
|
array_push($this->arrHistory, $var_ser);
|
|
|
|
$this->makeTableHeader("array","array");
|
|
if(is_array($var)) {
|
|
foreach($var as $key=>$value) {
|
|
$this->makeTDHeader("array",$key);
|
|
|
|
//check for recursion
|
|
if(is_array($value)) {
|
|
$var_ser = serialize($value);
|
|
if(in_array($var_ser, $this->arrHistory, TRUE))
|
|
$value = "*RECURSION*";
|
|
}
|
|
|
|
if(in_array(gettype($value),$this->arrType))
|
|
$this->checkType($value);
|
|
else {
|
|
$value=(trim($value)=="") ? "[empty string]" : $value;
|
|
echo $value;
|
|
}
|
|
echo $this->closeTDRow();
|
|
}
|
|
}
|
|
else echo "<tr><td>".$this->error("array").$this->closeTDRow();
|
|
array_pop($this->arrHistory);
|
|
echo "</table>";
|
|
}
|
|
|
|
//if variable is an object type
|
|
function varIsObject($var) {
|
|
$var_ser = serialize($var);
|
|
array_push($this->arrHistory, $var_ser);
|
|
$this->makeTableHeader("object","object");
|
|
|
|
if(is_object($var)) {
|
|
$arrObjVars=get_object_vars($var);
|
|
foreach($arrObjVars as $key=>$value) {
|
|
|
|
$value=(!is_object($value) && !is_array($value) && trim($value)=="") ? "[empty string]" : $value;
|
|
$this->makeTDHeader("object",$key);
|
|
|
|
//check for recursion
|
|
if(is_object($value)||is_array($value)) {
|
|
$var_ser = serialize($value);
|
|
if(in_array($var_ser, $this->arrHistory, TRUE)) {
|
|
$value = (is_object($value)) ? "*RECURSION* -> $".get_class($value) : "*RECURSION*";
|
|
|
|
}
|
|
}
|
|
if(in_array(gettype($value),$this->arrType))
|
|
$this->checkType($value);
|
|
else echo $value;
|
|
echo $this->closeTDRow();
|
|
}
|
|
$arrObjMethods=get_class_methods(get_class($var));
|
|
foreach($arrObjMethods as $key=>$value) {
|
|
$this->makeTDHeader("object",$value);
|
|
echo "[function]".$this->closeTDRow();
|
|
}
|
|
}
|
|
else echo "<tr><td>".$this->error("object").$this->closeTDRow();
|
|
array_pop($this->arrHistory);
|
|
echo "</table>";
|
|
}
|
|
|
|
//if variable is a resource type
|
|
function varIsResource($var) {
|
|
$this->makeTableHeader("resourceC","resource",1);
|
|
echo "<tr>\n<td>\n";
|
|
switch(get_resource_type($var)) {
|
|
case "fbsql result":
|
|
case "mssql result":
|
|
case "msql query":
|
|
case "pgsql result":
|
|
case "sybase-db result":
|
|
case "sybase-ct result":
|
|
case "mysql result":
|
|
$db=current(explode(" ",get_resource_type($var)));
|
|
$this->varIsDBResource($var,$db);
|
|
break;
|
|
case "gd":
|
|
$this->varIsGDResource($var);
|
|
break;
|
|
case "xml":
|
|
$this->varIsXmlResource($var);
|
|
break;
|
|
default:
|
|
echo get_resource_type($var).$this->closeTDRow();
|
|
break;
|
|
}
|
|
echo $this->closeTDRow()."</table>\n";
|
|
}
|
|
|
|
//if variable is a database resource type
|
|
function varIsDBResource($var,$db="mysql") {
|
|
if($db == "pgsql")
|
|
$db = "pg";
|
|
if($db == "sybase-db" || $db == "sybase-ct")
|
|
$db = "sybase";
|
|
$arrFields = array("name","type","flags");
|
|
$numrows=call_user_func($db."_num_rows",$var);
|
|
$numfields=call_user_func($db."_num_fields",$var);
|
|
$this->makeTableHeader("resource",$db." result",$numfields+1);
|
|
echo "<tr><td class=\"dBug_resourceKey\"> </td>";
|
|
for($i=0;$i<$numfields;$i++) {
|
|
$field_header = "";
|
|
for($j=0; $j<count($arrFields); $j++) {
|
|
$db_func = $db."_field_".$arrFields[$j];
|
|
if(function_exists($db_func)) {
|
|
$fheader = call_user_func($db_func, $var, $i). " ";
|
|
if($j==0)
|
|
$field_name = $fheader;
|
|
else
|
|
$field_header .= $fheader;
|
|
}
|
|
}
|
|
$field[$i]=call_user_func($db."_fetch_field",$var,$i);
|
|
echo "<td class=\"dBug_resourceKey\" title=\"".$field_header."\">".$field_name."</td>";
|
|
}
|
|
echo "</tr>";
|
|
for($i=0;$i<$numrows;$i++) {
|
|
$row=call_user_func($db."_fetch_array",$var,constant(strtoupper($db)."_ASSOC"));
|
|
echo "<tr>\n";
|
|
echo "<td class=\"dBug_resourceKey\">".($i+1)."</td>";
|
|
for($k=0;$k<$numfields;$k++) {
|
|
$tempField=$field[$k]->name;
|
|
$fieldrow=$row[($field[$k]->name)];
|
|
$fieldrow=($fieldrow=="") ? "[empty string]" : $fieldrow;
|
|
echo "<td>".$fieldrow."</td>\n";
|
|
}
|
|
echo "</tr>\n";
|
|
}
|
|
echo "</table>";
|
|
if($numrows>0)
|
|
call_user_func($db."_data_seek",$var,0);
|
|
}
|
|
|
|
//if variable is an image/gd resource type
|
|
function varIsGDResource($var) {
|
|
$this->makeTableHeader("resource","gd",2);
|
|
$this->makeTDHeader("resource","Width");
|
|
echo imagesx($var).$this->closeTDRow();
|
|
$this->makeTDHeader("resource","Height");
|
|
echo imagesy($var).$this->closeTDRow();
|
|
$this->makeTDHeader("resource","Colors");
|
|
echo imagecolorstotal($var).$this->closeTDRow();
|
|
echo "</table>";
|
|
}
|
|
|
|
//if variable is an xml type
|
|
function varIsXml($var) {
|
|
$this->varIsXmlResource($var);
|
|
}
|
|
|
|
//if variable is an xml resource type
|
|
function varIsXmlResource($var) {
|
|
$xml_parser=xml_parser_create();
|
|
xml_parser_set_option($xml_parser,XML_OPTION_CASE_FOLDING,0);
|
|
xml_set_element_handler($xml_parser,array(&$this,"xmlStartElement"),array(&$this,"xmlEndElement"));
|
|
xml_set_character_data_handler($xml_parser,array(&$this,"xmlCharacterData"));
|
|
xml_set_default_handler($xml_parser,array(&$this,"xmlDefaultHandler"));
|
|
|
|
$this->makeTableHeader("xml","xml document",2);
|
|
$this->makeTDHeader("xml","xmlRoot");
|
|
|
|
//attempt to open xml file
|
|
$bFile=(!($fp=@fopen($var,"r"))) ? false : true;
|
|
|
|
//read xml file
|
|
if($bFile) {
|
|
while($data=str_replace("\n","",fread($fp,4096)))
|
|
$this->xmlParse($xml_parser,$data,feof($fp));
|
|
}
|
|
//if xml is not a file, attempt to read it as a string
|
|
else {
|
|
if(!is_string($var)) {
|
|
echo $this->error("xml").$this->closeTDRow()."</table>\n";
|
|
return;
|
|
}
|
|
$data=$var;
|
|
$this->xmlParse($xml_parser,$data,1);
|
|
}
|
|
|
|
echo $this->closeTDRow()."</table>\n";
|
|
|
|
}
|
|
|
|
//parse xml
|
|
function xmlParse($xml_parser,$data,$bFinal) {
|
|
if (!xml_parse($xml_parser,$data,$bFinal)) {
|
|
die(sprintf("XML error: %s at line %d\n",
|
|
xml_error_string(xml_get_error_code($xml_parser)),
|
|
xml_get_current_line_number($xml_parser)));
|
|
}
|
|
}
|
|
|
|
//xml: inititiated when a start tag is encountered
|
|
function xmlStartElement($parser,$name,$attribs) {
|
|
$this->xmlAttrib[$this->xmlCount]=$attribs;
|
|
$this->xmlName[$this->xmlCount]=$name;
|
|
$this->xmlSData[$this->xmlCount]='$this->makeTableHeader("xml","xml element",2);';
|
|
$this->xmlSData[$this->xmlCount].='$this->makeTDHeader("xml","xmlName");';
|
|
$this->xmlSData[$this->xmlCount].='echo "<strong>'.$this->xmlName[$this->xmlCount].'</strong>".$this->closeTDRow();';
|
|
$this->xmlSData[$this->xmlCount].='$this->makeTDHeader("xml","xmlAttributes");';
|
|
if(count($attribs)>0)
|
|
$this->xmlSData[$this->xmlCount].='$this->varIsArray($this->xmlAttrib['.$this->xmlCount.']);';
|
|
else
|
|
$this->xmlSData[$this->xmlCount].='echo " ";';
|
|
$this->xmlSData[$this->xmlCount].='echo $this->closeTDRow();';
|
|
$this->xmlCount++;
|
|
}
|
|
|
|
//xml: initiated when an end tag is encountered
|
|
function xmlEndElement($parser,$name) {
|
|
for($i=0;$i<$this->xmlCount;$i++) {
|
|
eval($this->xmlSData[$i]);
|
|
$this->makeTDHeader("xml","xmlText");
|
|
echo (!empty($this->xmlCData[$i])) ? $this->xmlCData[$i] : " ";
|
|
echo $this->closeTDRow();
|
|
$this->makeTDHeader("xml","xmlComment");
|
|
echo (!empty($this->xmlDData[$i])) ? $this->xmlDData[$i] : " ";
|
|
echo $this->closeTDRow();
|
|
$this->makeTDHeader("xml","xmlChildren");
|
|
unset($this->xmlCData[$i],$this->xmlDData[$i]);
|
|
}
|
|
echo $this->closeTDRow();
|
|
echo "</table>";
|
|
$this->xmlCount=0;
|
|
}
|
|
|
|
//xml: initiated when text between tags is encountered
|
|
function xmlCharacterData($parser,$data) {
|
|
$count=$this->xmlCount-1;
|
|
if(!empty($this->xmlCData[$count]))
|
|
$this->xmlCData[$count].=$data;
|
|
else
|
|
$this->xmlCData[$count]=$data;
|
|
}
|
|
|
|
//xml: initiated when a comment or other miscellaneous texts is encountered
|
|
function xmlDefaultHandler($parser,$data) {
|
|
//strip '<!--' and '-->' off comments
|
|
$data=str_replace(array("<!--","-->"),"",htmlspecialchars($data));
|
|
$count=$this->xmlCount-1;
|
|
if(!empty($this->xmlDData[$count]))
|
|
$this->xmlDData[$count].=$data;
|
|
else
|
|
$this->xmlDData[$count]=$data;
|
|
}
|
|
|
|
function initJSandCSS() {
|
|
echo <<<SCRIPTS
|
|
<script language="JavaScript">
|
|
/* code modified from ColdFusion's cfdump code */
|
|
function dBug_toggleRow(source) {
|
|
var target = (document.all) ? source.parentElement.cells[1] : source.parentNode.lastChild;
|
|
dBug_toggleTarget(target,dBug_toggleSource(source));
|
|
}
|
|
|
|
function dBug_toggleSource(source) {
|
|
if (source.style.fontStyle=='italic') {
|
|
source.style.fontStyle='normal';
|
|
source.title='click to collapse';
|
|
return 'open';
|
|
} else {
|
|
source.style.fontStyle='italic';
|
|
source.title='click to expand';
|
|
return 'closed';
|
|
}
|
|
}
|
|
|
|
function dBug_toggleTarget(target,switchToState) {
|
|
target.style.display = (switchToState=='open') ? '' : 'none';
|
|
}
|
|
|
|
function dBug_toggleTable(source) {
|
|
var switchToState=dBug_toggleSource(source);
|
|
if(document.all) {
|
|
var table=source.parentElement.parentElement;
|
|
for(var i=1;i<table.rows.length;i++) {
|
|
target=table.rows[i];
|
|
dBug_toggleTarget(target,switchToState);
|
|
}
|
|
}
|
|
else {
|
|
var table=source.parentNode.parentNode;
|
|
for (var i=1;i<table.childNodes.length;i++) {
|
|
target=table.childNodes[i];
|
|
if(target.style) {
|
|
dBug_toggleTarget(target,switchToState);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style type="text/css">
|
|
table.dBug_array,table.dBug_object,table.dBug_resource,table.dBug_resourceC,table.dBug_xml
|
|
{ font-family:Verdana, Arial, Helvetica, sans-serif; color:#000000; font-size:12px; border-spacing:2px; display:table; border-collapse:separate; }
|
|
|
|
table.dBug_array td,
|
|
table.dBug_object td,
|
|
table.dBug_resource td,
|
|
table.dBug_resourceC td,
|
|
table.dBug_xml td
|
|
{ line-height:1.3; padding:3px; vertical-align:top; }
|
|
|
|
.dBug_arrayHeader,
|
|
.dBug_objectHeader,
|
|
.dBug_resourceHeader,
|
|
.dBug_resourceCHeader,
|
|
.dBug_xmlHeader
|
|
{ font-weight:bold; color:#FFFFFF; cursor:pointer; }
|
|
|
|
.dBug_arrayKey,
|
|
.dBug_objectKey,
|
|
.dBug_xmlKey
|
|
{ cursor:pointer; }
|
|
|
|
/* array */
|
|
table.dBug_array { background-color:#006600; }
|
|
table.dBug_array td { background-color:#FFFFFF; }
|
|
table.dBug_array td.dBug_arrayHeader { background-color:#009900; }
|
|
table.dBug_array td.dBug_arrayKey { background-color:#CCFFCC; }
|
|
|
|
/* object */
|
|
table.dBug_object { background-color:#0000CC; }
|
|
table.dBug_object td { background-color:#FFFFFF; }
|
|
table.dBug_object td.dBug_objectHeader { background-color:#4444CC; }
|
|
table.dBug_object td.dBug_objectKey { background-color:#CCDDFF; }
|
|
|
|
/* resource */
|
|
table.dBug_resourceC { background-color:#884488; }
|
|
table.dBug_resourceC td { background-color:#FFFFFF; }
|
|
table.dBug_resourceC td.dBug_resourceCHeader { background-color:#AA66AA; }
|
|
table.dBug_resourceC td.dBug_resourceCKey { background-color:#FFDDFF; }
|
|
|
|
/* resource */
|
|
table.dBug_resource { background-color:#884488; }
|
|
table.dBug_resource td { background-color:#FFFFFF; }
|
|
table.dBug_resource td.dBug_resourceHeader { background-color:#AA66AA; }
|
|
table.dBug_resource td.dBug_resourceKey { background-color:#FFDDFF; }
|
|
|
|
/* xml */
|
|
table.dBug_xml { background-color:#888888; }
|
|
table.dBug_xml td { background-color:#FFFFFF; }
|
|
table.dBug_xml td.dBug_xmlHeader { background-color:#AAAAAA; }
|
|
table.dBug_xml td.dBug_xmlKey { background-color:#DDDDDD; }
|
|
</style>
|
|
SCRIPTS;
|
|
}
|
|
|
|
}
|
|
?>
|