Simpele Debug class (veilige print_r)
Auteur: Thomas - 01 januari 2014 - 20:53 - Gekeurd door: Wijnand - Hits: 6691 - Aantal punten: 5.00 (2 stemmen)
Noot 2014-03-05:
Let op bij het gebruik van de htmlspecialchars() aanroep in de static methode escape(). Hier is geen encoding (3e parameter) opgegeven. Wellicht doe je er verstandig aan deze expliciet op te geven. Afhankelijk van je PHP versie kan de default waarde van deze parameter verschillen.
Bij het lezen van de tutorial over debugging zag ik dat voor het dumpen van variabelen print_r() werd gebruikt. Nu is dit een eenvoudige manier, maar niet altijd handig, want de waarden kunnen HTML / JavaScript bevatten. Daarmee is het dus ook niet veilig.
Ook bij het dumpen van variabelen mag je veiligheid niet uit het oog verliezen, in de variabelen die je dumpt kan immers user input zitten! Voor extra toelichting zie de user comments van bovenstaande tutorial.
Ik heb even zitten prutten en heb een Debug klasse in elkaar gefietst, een soort van veilige print_r() zeg maar, die zowel keys als values escaped en tevens wat informatie over het type variabele retourneert.
Je kunt natuurlijk ook altijd je eigen ding bouwen, eventueel in combinatie met var_dump() ofzo. Denk daarbij dus wel aan output escaping.
|
Code: |
De klasse:
<?php
class Debug
{
protected static function escape($text) {
return htmlspecialchars($text, ENT_QUOTES);
}
protected static function clean($in) {
if (is_array($in)) {
// Because we might introduce new (or overwrite existing) keys when we escape them,
// we build a new array $out instead of overwriting $in.
$out = array();
foreach ($in as $k => $v) {
$out[self::escape($k)] = self::clean($v); // $v might be anything, call clean() again
}
$in = $out;
} elseif (is_numeric($in)) {
$in = '(<span style="color: #ff0000;">numeric</span>) '.$in; // no cleaning necessary
} elseif (is_bool($in)) {
$in = '(<span style="color: #ff0000;">bool</span>) '.($in ? 'true' : 'false'); // print boolean value as string
} elseif (is_object($in)) {
// Convert object to string using print_r.
$in = '(<span style="color: #ff0000;">object</span>) <span style="color: #009900;">'.self::escape(print_r($in, true)).'</span>';
} elseif (is_null($in)) {
$in = '(<span style="color: #ff0000;">null</span>)';
} elseif (is_resource($in)) {
$in = '(<span style="color: #ff0000;">resource</span>)'; // @todo add more info?
} elseif (is_string($in)) {
$in = '(<span style="color: #ff0000;">string</span>) '.self::escape($in);
} else {
// something we missed
$in = '(<span style="color: #ff0000;">something</span>)';
}
return $in;
}
public static function dump($in, $file='', $line='') {
if (!empty($line) && !empty($file)) {
echo '<b>variable dump in file '.$file.' on line '.$line.'</b>';
} else {
echo '<b>variable dump</b>';
}
if (is_array($in)) {
echo '<pre>'.print_r(self::clean($in), true).'</pre>';
} else {
echo '<pre>'.self::clean($in).'</pre>';
}
}
} // class
?>
<?php class Debug { protected static function escape ($text) { } protected static function clean ($in) { // Because we might introduce new (or overwrite existing) keys when we escape them, // we build a new array $out instead of overwriting $in. foreach ($in as $k => $v) { $out[self::escape($k)] = self::clean($v); // $v might be anything, call clean() again } $in = $out; $in = '(<span style="color: #ff0000;">numeric</span>) '.$in; // no cleaning necessary $in = '(<span style="color: #ff0000;">bool</span>) '.($in ? 'true' : 'false'); // print boolean value as string // Convert object to string using print_r. $in = '(<span style="color: #ff0000;">object</span>) <span style="color: #009900;">'.self::escape(print_r($in, true)).'</span>'; $in = '(<span style="color: #ff0000;">null</span>)'; $in = '(<span style="color: #ff0000;">resource</span>)'; // @todo add more info? $in = '(<span style="color: #ff0000;">string</span>) '.self::escape($in); } else { // something we missed $in = '(<span style="color: #ff0000;">something</span>)'; } return $in; } public static function dump ($in, $file='', $line='') { echo '<b>variable dump in file '.$file.' on line '.$line.'</b>'; } else { echo '<b>variable dump</b>'; } } else { echo '<pre>'.self::clean($in).'</pre>'; } } } // class ?>
De klasse heeft één publieke methode (dump) die je op twee manieren kunt aanroepen: ofwel met één parameter, waarbij je de te dumpen variabele meegeeft, ofwel met drie parameters, waarbij de tweede en derde parameters (respectievelijk) de "magische constanten" __FILE__ en __LINE__ bevatten. Hiermee kun je zien waar (in welk script) en op welke regel de dump methode is aangeroepen. Dit kan handig zijn als je op een moment meerdere dumps in je code hebt staan om te zien welke wordt uitgevoerd.
Voorbeeld:
<?php
// Test class.
class Test
{
protected $test;
public function __construct($test) {
$this->test = $test;
}
}
// Test variable.
$test = array(
'a' => array( // subarray
1 => "<script>alert('hoi')</script>", // nasty code
2 => false, // a boolean
77 => true, // another boolean
3 => '5.6666667', // a numeric value stored as string
'object' => new Test('<b>hallo</b>'), // an object
4 => 1.2, // a numeric value (float)
5 => 7, // a numeric value (integer)
6 => array( // subsubarray
'z' => '<b>bold</b>', // more nasty code
'a' => 'asdf', // a string
'<la' => 'hai', // nasty key
),
9 => null,
),
'<b>' => 'lala<br />', // key with code in it
'<b>' => 'hoi', // escaped variant of previous key, which should not be overwritten by your dump functionality...
);
// Dump the evil code in a safe way.
Debug::dump($test, __FILE__, __LINE__);
?>
<?php // Test class. class Test { protected $test; public function __construct($test) { $this->test = $test; } } // Test variable. 'a' => array( // subarray 1 => "<script>alert('hoi')</script>", // nasty code 2 => false, // a boolean 77 => true, // another boolean 3 => '5.6666667', // a numeric value stored as string 'object' => new Test('<b>hallo</b>'), // an object 4 => 1.2, // a numeric value (float) 5 => 7, // a numeric value (integer) 6 => array( // subsubarray 'z' => '<b>bold</b>', // more nasty code 'a' => 'asdf', // a string '<la' => 'hai', // nasty key ), 9 => null, ), '<b>' => 'lala<br />', // key with code in it '<b>' => 'hoi', // escaped variant of previous key, which should not be overwritten by your dump functionality... ); // Dump the evil code in a safe way. Debug::dump($test, __FILE__, __LINE__); ?>
Download code (.txt)
|
|
Stemmen |
Niet ingelogd. |
|