dumper.php
1 <?php
2
/**
3  * Dump variable, based on dBug at http://dbug.ospinto.com
4  *
5  * Dumps/Displays the contents of a variable in a colored tabular format
6  * Based on the idea, javascript and css code of Macromedia's ColdFusion cfdump tag
7  * A much better presentation of a variable's contents than PHP's var_dump and print_r functions
8  *
9  * Direct Usage
10  * =============
11  * new Dumper( $myVariable );
12  *
13  * 
14  * if the optional "force_type" string is given, the variable supplied to the 
15  * function is forced to have that force_type type. 
16  * example: new dBug( $myVariable , "array" );
17  * will force $myVariable to be treated and dumped as an array type, 
18  * even though it might originally have been a string type, etc.
19  *
20  * NOTE!
21  * ==============
22  * force_type is REQUIRED for dumping an xml string or xml file
23  * new Dump($str_xml, 'xml');
24  * 
25  * @author Zhou Yuan <yuanzhou19@gmail.com>
26  * @link http://www.infopotato.com/
27  * Original code from {@link http://dbug.ospinto.com}
28  * @copyright Copyright &copy; 2009-2011 Zhou Yuan
29  * @license http://www.opensource.org/licenses/mit-license.php MIT Licence
30  */
31  
32
class Dumper {
33     
34     public static 
$xml_CDATA;
35     public static 
$xml_SDATA;
36     public static 
$xml_DDATA;
37     public static 
$xml_count;
38     public static 
$xml_attrib;
39     public static 
$xml_name;
40     public static 
$arr_type;
41     public static 
$collapsed;
42     public static 
$initialized;
43     public static 
$arr_history;
44     
45     public static function 
dump($var$force_type ''$collapsed FALSE) {
46         
// Reseet the settings each time dump() is called
47         
self::$xml_count 0;
48         
self::$arr_type = array('array''object''resource''boolean''NULL');
49         
self::$collapsed FALSE;
50         
self::$initialized FALSE;
51         
self::$arr_history = array();
52
53         
// Enable collapse of tables when initiated.
54         
self::$collapsed $collapsed;
55         
56         
// Include js and css scripts only once if DUMP_INIT is TRUE
57         
if ( ! defined('DUMP_INIT')) {
58             
define('DUMP_INIT'TRUE);
59             
self::init_js_and_css();
60         }
61         
62         if (
$force_type === '') {
63             
self::check_type($var);
64         } else {
65             
// $force_type is REQUIRED for dumping an xml string or xml file
66             
if (strtolower($force_type) === 'xml') {
67                 
self::var_is_xml_resource($var);
68             } else {
69                 die(
'Only xml is allowed as force type');
70             }
71         }
72     }
73
74     
// Get variable info
75     
public static function get_var_info() {
76         
$var_info = array();
77         
78         
$trace debug_backtrace();
79         
$cnt count($trace);
80         
81         
// Possible 'included' functions
82         
$include = array('include''include_once''require''require_once');
83         
84         
// Check for any included/required files. if found, get array of the last included file (they contain the right line numbers)
85         
for ($i $cnt 1$i >= 0$i--) {
86             
$current $trace[$i];
87             if (
array_key_exists('function'$current) && (in_array($current['function'], $include) || (!= strcasecmp($current['function'], 'dump')))) {
88                 continue;
89             }
90             
91             
$file $current;
92             break;
93         }
94         
95         if (isset(
$file)) {
96             
$lines file($file['file']);
97             
$code $lines[($file['line'] - 1)];
98     
99             
// Find call to dump()
100             
preg_match('/\bdump\s*\(\s*(.+)\s*\);/i'$code$matches);
101             
102             
// Returned var info: var_name, file_name, line_number
103             
$var_info['var_name'] = $matches[1];
104             
$var_info['file_name'] = str_replace('\\''/'$file['file']);
105             
$var_info['line_number'] = $file['line'];
106         }
107         
108         return 
$var_info;
109     }
110     
111     
// Create the main table header, can't show the variable name
112     
public static function make_table_header($type$header$colspan 2) {
113         
$var_info self::get_var_info();
114         if (
$var_info !== array()) {
115             if( ! 
self::$initialized) {
116                 
$header $var_info['var_name'].' ('.$header.') <span class="dump_file_n_line">'.$var_info['file_name'].' - line '.$var_info['line_number'].'</span>';
117                 
self::$initialized TRUE;
118             }
119         }
120
121         
$str_i = (self::$collapsed) ? 'style="font-style:italic" ' ''
122         
123         echo 
'<table cellspacing="1" cellpadding="2" class="dump_'.$type.'"><tr><td '.$str_i.'class="dump_'.$type.'_header" colspan="'.$colspan.'" onClick="dump_toggle_table(this)">'.$header.'</td></tr>';
124     }
125     
126     
// Create the table row header
127     
public static function make_td_header($type$header) {
128         
$str_d = (self::$collapsed) ? ' style="display:none"' '';
129         echo 
'<tr'.$str_d.'><td valign="top" onClick="dump_toggle_row(this)" class="dump_'.$type.'_key">'.$header.'</td><td>';
130     }
131     
132     
// Close table row
133     
public static function close_td_row() {
134         echo 
'</td></tr>';
135     }
136     
137     
// Display error
138     
public static function  error($type) {
139         return 
'Error: Variable cannot be '.$type.' type';
140     }
141
142     
// Check variable type
143     
public static function check_type($var) {
144         
// Never use gettype() to test for a certain type, 
145         // since the returned string may be subject to change in a future version. 
146         // In addition, it is slow too, as it involves string comparison.
147         // Instead, use the is_* functions.
148         
if (is_resource($var)) {
149             
self::var_is_resource($var);
150         } elseif (
is_object($var)) {
151             
self::var_is_object($var);
152         } elseif (
is_array($var)) {
153             
self::var_is_array($var);
154         } elseif (
is_null($var)) {
155             
self::var_is_null();
156         } elseif (
is_bool($var)) {
157             
self::var_is_bool($var);
158         } elseif (
is_string($var)) {
159             
self::var_is_string($var);
160         } elseif (
is_int($var)) {
161             
self::var_is_int($var);
162         } elseif (
is_double($var)) {
163             
self::var_is_double($var);
164         }
165     }
166     
167     
168     public static function 
var_is_null() {
169         
self::make_table_header('object''NULL');
170         
self::make_td_header('object''NULL');
171         
self::close_td_row();
172     }
173     
174     public static function 
var_is_string($var) {
175         
$var = ($var == '') ? '[empty string]' $var;
176         
self::make_table_header('object''string ['.strlen($var).']');
177         
self::make_td_header('object'$var);
178         
self::close_td_row();
179     }
180     
181     public static function 
var_is_int($var) {
182         
self::make_table_header('object''integer');
183         
self::make_td_header('object'$var);
184         
self::close_td_row();
185     }
186     
187     public static function 
var_is_double($var) {
188         
self::make_table_header('object''double');
189         
self::make_td_header('object'$var);
190         
self::close_td_row();
191     }
192     
193     public static function 
var_is_bool($var) {
194         
$var = ($var === TRUE) ? 'TRUE' 'FALSE';
195         
self::make_table_header('object''bool');
196         
self::make_td_header('object'$var);
197         
self::close_td_row();
198     }
199             
200     
// If variable is an array type
201     
public static function var_is_array($var) {
202         
$var_ser serialize($var);
203         
array_push(self::$arr_history$var_ser);
204         
205         
self::make_table_header('array''array');
206         if (
is_array($var)) {
207             foreach (
$var as $key => $value) {
208                 
self::make_td_header('array'$key);
209                 
210                 
// Check for recursion
211                 
if (is_array($value)) {
212                     
$var_ser serialize($value);
213                     if (
in_array($var_serself::$arr_historyTRUE))
214                         
$value "*RECURSION*";
215                 }
216                 
217                 if (
in_array(gettype($value), self::$arr_type)) {
218                     
self::check_type($value);
219                 } else {
220                     
$value = (trim($value) == '') ? '[empty string]' $value;
221                     echo 
$value;
222                 }
223                 
self::close_td_row();
224             }
225         } else {
226             echo 
'<tr><td>'.self::error('array');
227             
self::close_td_row();
228         }
229         
array_pop(self::$arr_history);
230         echo 
'</table>';
231     }
232     
233     
// If variable is an object type
234     
public static function var_is_object($var) {
235         
$var_ser serialize($var);
236         
array_push(self::$arr_history$var_ser);
237         
self::make_table_header('object''object');
238         
239         if (
is_object($var)) {
240             
$arr_obj_vars get_object_vars($var);
241             foreach (
$arr_obj_vars as $key => $value) {
242                 
$value = ( ! is_object($value) && ! is_array($value) && trim($value) == '') ? '[empty string]' $value;
243                 
self::make_td_header('object'$key);
244                 
245                 
// Check for recursion
246                 
if (is_object($value) || is_array($value)) {
247                     
$var_ser serialize($value);
248                     if (
in_array($var_serself::$arr_historyTRUE)) {
249                         
$value = (is_object($value)) ? "*RECURSION* -> $".get_class($value) : "*RECURSION*";
250                     }
251                 }
252                 if (
in_array(gettype($value), self::$arr_type)) {
253                     
self::check_type($value);
254                 } else {
255                     echo 
$value;
256                 }
257                 
self::close_td_row();
258             }
259             
$arr_obj_methods get_class_methods(get_class($var));
260             foreach (
$arr_obj_methods as $key => $value) {
261                 
self::make_td_header('object'$value);
262                 echo 
'[method]';
263                 
self::close_td_row();
264             }
265         } else {
266             echo 
'<tr><td>'.self::error('object');
267             
self::close_td_row();
268         }
269         
array_pop(self::$arr_history);
270         echo 
'</table>';
271     }
272
273     
// If variable is a resource type
274     
public static function var_is_resource($var) {
275         
self::make_table_header('resourceC''resource'1);
276         echo 
'<tr><td>';
277         switch (
get_resource_type($var)) {
278             case 
'mysql result':
279             case 
'pgsql result':
280                 
$db current(explode(' 'get_resource_type($var)));
281                 
self::var_is_db_resource($var$db);
282                 break;
283             
284             case 
'gd':
285                 
self::var_is_gd_resource($var);
286                 break;
287             
288             case 
'xml':
289                 
self::var_is_xml_resource($var);
290                 break;
291         }
292         
self::close_td_row();
293         echo 
'</table>';
294     }
295     
296     
//if variable is a database resource type
297     
public static function var_is_db_resource($var$db 'mysql') {
298         if (
$db == 'pgsql') {
299             
$db 'pg';
300         }
301         
$arr_fields = array('name''type''flags');    
302         
$num_rows call_user_func($db.'_num_rows'$var);
303         
$num_fields call_user_func($db.'_num_fields'$var);
304         
self::make_table_header("resource"$db." result"$num_fields 1);
305         echo 
'<tr><td class="dump_resource_key">&nbsp;</td>';
306         for (
$i 0$i $num_fields$i++) {
307             
$field_header '';
308             for (
$j 0$j count($arr_fields); $j++) {
309                 
$db_func $db.'_field_'.$arr_fields[$j];
310                 if (
function_exists($db_func)) {
311                     
$fheader call_user_func($db_func$var$i). ' ';
312                     if (
$j == 0) {
313                         
$field_name $fheader;
314                     } else {
315                         
$field_header .= $fheader;
316                     }
317                 }
318             }
319             
$field[$i] = call_user_func($db.'_fetch_field'$var$i);
320             echo 
'<td class="dump_resource_key" title="'.$field_header.'">'.$field_name.'</td>';
321         }
322         echo 
'</tr>';
323         for (
$i 0$i $num_rows$i++) {
324             
$row call_user_func($db.'_fetch_array'$varconstant(strtoupper($db).'_ASSOC'));
325             
$out .= '<tr><td class="dump_resource_key">'.($i+1).'</td>'
326             for (
$k 0$k $num_fields$k++) {
327                 
$tempField $field[$k]->name;
328                 
$field_row $row[($field[$k]->name)];
329                 
$field_row = ($field_row == '') ? "[empty string]" $field_row;
330                 echo 
'<td>'.$field_row.'</td>';
331             }
332             echo 
'</tr>';
333         }
334         echo 
'</table>';
335         if (
$num_rows 0) {
336             
call_user_func($db.'_data_seek'$var0);
337         }
338     }
339     
340     
// If variable is an image/gd resource type
341     
public static function var_is_gd_resource($var) {
342         
self::make_table_header('resource''gd'2);
343         
self::make_td_header('resource''Width');
344         
imagesx($var).self::close_td_row();
345         
self::make_td_header('resource''Height');
346         
imagesy($var).self::close_td_row();
347         
self::make_td_header('resource''Colors');
348         
imagecolorstotal($var).self::close_td_row();
349         echo 
'</table>';
350     }
351
352     
// If variable is an xml resource type
353     
public static function var_is_xml_resource($var) {
354         
$xml_parser xml_parser_create();
355         
xml_parser_set_option($xml_parserXML_OPTION_CASE_FOLDING0); 
356         
xml_set_element_handler($xml_parser, array('Dumper''xml_start_element'), array('Dumper''xml_end_element')); 
357         
xml_set_character_data_handler($xml_parser, array('Dumper''xml_character_data'));
358         
xml_set_default_handler($xml_parser, array('Dumper''xml_default_handler')); 
359         
360         
self::make_table_header('xml''XML Document'2);
361         
self::make_td_header('xml''Root');
362         
363         
// Attempt to open xml file
364         
$xml_file = ( ! ($fp = @fopen($var'r'))) ? FALSE TRUE;
365         
366         
// Read xml file, if xml is not a file, attempt to read it as a string
367         
if ($xml_file) {
368             while (
$data str_replace("\n"''fread($fp4096))) {
369                 
self::xml_parse($xml_parser$datafeof($fp));
370             }
371         } else {
372             if ( ! 
is_string($var)) {
373                 echo 
self::error('xml');
374                 
self::close_td_row();
375                 echo 
'</table>';
376                 return;
377             }
378             
$data $var;
379             
self::xml_parse($xml_parser$data1);
380         }
381         
382         
self::close_td_row();
383         echo 
'</table>';
384     }
385     
386     
// Parse xml
387     
public static function xml_parse($xml_parser$data$final) {
388         if ( ! 
xml_parse($xml_parser$data$final)) { 
389             die(
sprintf("XML error: %s at line %d\n"
390                 
xml_error_string(xml_get_error_code($xml_parser)), 
391                 
xml_get_current_line_number($xml_parser)));
392         }
393     }
394     
395     
// xml: inititiated when a start tag is encountered
396     
public static function xml_start_element($parser$name$attribs) {
397         
self::$xml_attrib[self::$xml_count] = $attribs;
398         
self::$xml_name[self::$xml_count] = $name;
399         
self::$xml_SDATA[self::$xml_count] = 'self::make_table_header("xml", "Element", 2);';
400         
self::$xml_SDATA[self::$xml_count] .= 'self::make_td_header("xml", "Name");';
401         
self::$xml_SDATA[self::$xml_count] .= 'echo "<strong>'.self::$xml_name[self::$xml_count].'</strong>";';
402         
self::$xml_SDATA[self::$xml_count] .= 'self::close_td_row();';
403         
self::$xml_SDATA[self::$xml_count] .= 'self::make_td_header("xml", "Attributes");';
404         if (
count($attribs) > 0) {
405             
self::$xml_SDATA[self::$xml_count] .= 'self::var_is_array(self::$xml_attrib['.self::$xml_count.']);';
406         } else {
407             
self::$xml_SDATA[self::$xml_count] .= 'echo "&nbsp;";';
408         }
409         
self::$xml_SDATA[self::$xml_count] .= 'self::close_td_row();';
410         
self::$xml_count++;
411     } 
412     
413     
// xml: initiated when an end tag is encountered
414     
public static function xml_end_element($parser$name) {
415         for (
$i 0$i self::$xml_count$i++) {
416             eval(
self::$xml_SDATA[$i]);
417             
self::make_td_header('xml''Text');
418             echo empty(
self::$xml_CDATA[$i]) ? '&nbsp;' self::$xml_CDATA[$i];
419             
self::close_td_row();
420             
self::make_td_header('xml''Comment');
421             echo empty(
self::$xml_DDATA[$i]) ? '&nbsp;' self::$xml_DDATA[$i];
422             
self::close_td_row();
423             
self::make_td_header('xml''Children');
424             unset(
self::$xml_CDATA[$i], self::$xml_DDATA[$i]);
425         }
426         
self::close_td_row();
427         echo 
'</table>';
428         
self::$xml_count 0;
429     } 
430     
431     
//xml: initiated when text between tags is encountered
432     
public static function xml_character_data($parser,$data) {
433         
$count self::$xml_count 1;
434         if ( ! empty(
self::$xml_CDATA[$count])) {
435             
self::$xml_CDATA[$count] .= $data;
436         } else {
437             
self::$xml_CDATA[$count] = $data;
438         }
439     } 
440     
441     
//xml: initiated when a comment or other miscellaneous texts is encountered
442     
public static function xml_default_handler($parser$data) {
443         
//strip '<!--' and '-->' off comments
444         
$data str_replace(array("&lt;!--""--&gt;"), ''htmlspecialchars($data));
445         
$count self::$xml_count 1;
446         if ( ! empty(
self::$xml_DDATA[$count])) {
447             
self::$xml_DDATA[$count] .= $data;
448         } else {
449             
self::$xml_DDATA[$count] = $data;
450         }
451     }
452
453     public static function 
init_js_and_css() {
454         
$out =
455 <<<SCRIPTS
456
            <script language="JavaScript">
457             /* code modified from ColdFusion's cfdump code */
458                 function dump_toggle_row(source) {
459                     var target = (document.all) ? source.parentElement.cells[1] : source.parentNode.lastChild;
460                     dump_toggle_target(target, dump_toggle_source(source));
461                 }
462                 
463                 function dump_toggle_source(source) {
464                     if (source.style.fontStyle == 'italic') {
465                         source.style.fontStyle = 'normal';
466                         source.title='click to collapse';
467                         return 'open';
468                     } else {
469                         source.style.fontStyle = 'italic';
470                         source.title = 'click to expand';
471                         return 'closed';
472                     }
473                 }
474             
475                 function dump_toggle_target(target, switchToState) {
476                     target.style.display = (switchToState == 'open') ? '' : 'none';
477                 }
478             
479                 function dump_toggle_table(source) {
480                     var switchToState = dump_toggle_source(source);
481                     if(document.all) {
482                         var table = source.parentElement.parentElement;
483                         for(var i=1; i<table.rows.length; i++) {
484                             target = table.rows[i];
485                             dump_toggle_target(target, switchToState);
486                         }
487                     }
488                     else {
489                         var table = source.parentNode.parentNode;
490                         for (var i=1; i<table.childNodes.length; i++) {
491                             target = table.childNodes[i];
492                             if(target.style) {
493                                 dump_toggle_target(target,switchToState);
494                             }
495                         }
496                     }
497                 }
498             </script>
499             
500             <style type="text/css">
501                 table.dump_array,
502                 table.dump_object,
503                 table.dump_resource,
504                 table.dump_resourceC,
505                 table.dump_xml {
506                 font-family:Verdana, Arial, Helvetica, sans-serif; 
507                 color:#000; 
508                 font-size:12px;
509                 margin:10px;
510                 }
511                 
512                 table.dump_array td,
513                 table.dump_object td,
514                 table.dump_resource td,
515                 table.dump_resourceC td,
516                 table.dump_xml td {
517                 font-family:Verdana, Arial, Helvetica, sans-serif; 
518                 color:#000; 
519                 }
520                 
521                 .dump_array_header,
522                 .dump_object_header,
523                 .dump_resource_header,
524                 .dump_resourceC_header,
525                 .dump_xml_header { 
526                 font-weight:bold; 
527                 color:#fff; 
528                 cursor:pointer; 
529                 }
530                     
531                 .dump_file_n_line {
532                 font-weight:normal;
533                 }
534                 
535                 .dump_array_key,
536                 .dump_object_key,
537                 .dump_xml_key { 
538                 cursor:pointer; 
539                 }
540                     
541                 /* array */
542                 table.dump_array { 
543                 background:#00A000; 
544                 }
545                 
546                 table.dump_array td { 
547                 background:#fff; 
548                 }
549                 
550                 table.dump_array td.dump_array_header { 
551                 background:#90FF90; 
552                 }
553                 
554                 table.dump_array td.dump_array_key { 
555                 background:#CCFFCC; 
556                 }
557                 
558                 /* object */
559                 table.dump_object { 
560                 background:#4040FF; 
561                 }
562                 
563                 table.dump_object td { 
564                 background:#fff; 
565                 }
566                 
567                 table.dump_object td.dump_object_header { 
568                 background:#C0C0FF; 
569                 }
570                 
571                 table.dump_object td.dump_object_key { 
572                 background:#CCDDFF; 
573                 }
574                 
575                 /* resource */
576                 table.dump_resource, 
577                 table.dump_resourceC { 
578                 background:#884488; 
579                 }
580                 
581                 table.dump_resource td, 
582                 table.dump_resourceC td { 
583                 background:#fff; 
584                 }
585                 
586                 table.dump_resource td.dump_resource_header, 
587                 table.dump_resourceC td.dump_resourceC_header { 
588                 background:#AA66AA; 
589                 }
590                 
591                 table.dump_resource td.dump_resource_key, 
592                 table.dump_resourceC td.dump_resourceC_key { 
593                 background:#FFDDFF; 
594                 }
595                 
596                 /* xml */
597                 table.dump_xml { 
598                 background:#888; 
599                 }
600                 
601                 table.dump_xml td { 
602                 background:#fff; 
603                 }
604                 
605                 table.dump_xml td.dump_xml_header { 
606                 background-color:#aaa; 
607                 }
608                 
609                 table.dump_xml td.dump_xml_key { 
610                 background-color:#ddd; 
611                 }
612             </style>
613
SCRIPTS;
614         
$out str_replace("\n"' '$out);
615         
$out str_replace("\r"' '$out);
616         echo 
$out;
617     }
618
619 }
620
621
// End of file: ./system/core/dumper.php 

Page URI: http://www.infopotato.com/index.php/code/core/dumper/