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 © 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) || (0 != 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_ser, self::$arr_history, TRUE))
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_ser, self::$arr_history, TRUE)) {
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"> </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', $var, constant(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', $var, 0);
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_parser, XML_OPTION_CASE_FOLDING, 0);
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($fp, 4096))) {
369
self::xml_parse($xml_parser, $data, feof($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, $data, 1);
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 " ";';
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]) ? ' ' : self::$xml_CDATA[$i];
419
self::close_td_row();
420
self::make_td_header('xml', 'Comment');
421
echo empty(self::$xml_DDATA[$i]) ? ' ' : 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("<!--", "-->"), '', 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/
