I had been having a real problem tracking down a PHP error in Drupal which was passing an array to htmlspecialchars() in check_plain() instead of a string. I needed to use debug_backtrace() but the issue was related to Views which meant that the arguments being passed at higher levels were catastrophically huge.
It was a real problem, using krumo just resulted in out-of-memory errors. And the problem was also happening inside AJAX calls so any attempt to simply print the output was doomed.
I needed a way to get a function backtrace which was not too verbose, didn't crash the machine and would work in an AJAX call.
The solution is the following routine which takes a debug_backtrace() extracts only the information we need and outputs to a file. It's not Drupal-specific but you may need to set up the directory:
/**
* Backtrace to a file for when nothing else works
*/
function debug_backtrace_file($fname = 'backtrace') {
$file = fopen("c:\\tmp\\{$fname}.log", 'ab');
if (!$file) {
return;
}
fputs($file, '=============== ' . date('Y-m-d H:i:s') . " ===============\n");
$line = __LINE__;
foreach (debug_backtrace() as $entry) {
$function = $entry['function'];
if ($function!=__FUNCTION__) {
if (isset($entry['class']) && $entry['class']) {
$function = "{$entry['class']}::$function";
}
fputs($file, sprintf("function %s at line %d in file %s\n", $function, $line, isset($entry['file'])?$entry['file']:t('unknown')));
}
$line = $entry['line'];
}
fclose($file);
}
Happy bug hunting.
Showing posts with label PHP. Show all posts
Showing posts with label PHP. Show all posts
Monday, 30 January 2012
Thursday, 26 January 2012
Where the **** is it?
You know how it is? You have this complex and massive PHP structure with recursive elements and somewhere in all that is a value you're looking for. Views object I'm looking at you!
Here's a PHP routine, which is not Drupal specific, that will dig down into an object to find the property or array item you're looking for - and it avoids recursion by keeping a list of structures it's already searched by MD5ing the serialized version of the structure.
The parameters are the initial structure to search; the property you're looking for - it can be partial if you're not sure what the property is called; $id would usually be the identifier of the structure you're supplying and $depth should be ignored. It returns an array of strings that show the way into the structure to find the property. It's quite common to get multiple results.
One thing to watch out for: If your structure is recursive (like a Views object) and you start the search deeper into the structure with the idea that you'll shorten the search? Well you might, but if it's recursive you might also end up going into one of the recursed objects because the routine hasn't seen it before.
Anyway, with that in mind, here it is:
function common_locate($struct, $seek, $id = '', $depth = 0) {
static $structs = array(), $results = array();
if (is_array($struct) || is_object($struct)) {
$struct = (array) $struct;
foreach ($struct as $key => $value) {
if (strpos($key, $seek)!==FALSE) {
$results[] = "$id => $key = $value";
}
if (is_array($value)) {
$idx = str_replace('0', 'g', md5(serialize($value)));
if (!isset($structs[$idx])) {
$structs[$idx] = "$key:$depth";
common_locate($value, $seek, "{$id}[$key]", $depth+1);
}
}
elseif (is_object($value)) {
$idx = str_replace('0', 'g', md5(serialize($value)));
if (!isset($structs[$idx])) {
$structs[$idx] = "object:$key:$depth";
common_locate($value, $seek, "{$id}->$key", $depth+1);
}
}
}
}
return $results;
}
Here's a PHP routine, which is not Drupal specific, that will dig down into an object to find the property or array item you're looking for - and it avoids recursion by keeping a list of structures it's already searched by MD5ing the serialized version of the structure.
The parameters are the initial structure to search; the property you're looking for - it can be partial if you're not sure what the property is called; $id would usually be the identifier of the structure you're supplying and $depth should be ignored. It returns an array of strings that show the way into the structure to find the property. It's quite common to get multiple results.
One thing to watch out for: If your structure is recursive (like a Views object) and you start the search deeper into the structure with the idea that you'll shorten the search? Well you might, but if it's recursive you might also end up going into one of the recursed objects because the routine hasn't seen it before.
Anyway, with that in mind, here it is:
function common_locate($struct, $seek, $id = '', $depth = 0) {
static $structs = array(), $results = array();
if (is_array($struct) || is_object($struct)) {
$struct = (array) $struct;
foreach ($struct as $key => $value) {
if (strpos($key, $seek)!==FALSE) {
$results[] = "$id => $key = $value";
}
if (is_array($value)) {
$idx = str_replace('0', 'g', md5(serialize($value)));
if (!isset($structs[$idx])) {
$structs[$idx] = "$key:$depth";
common_locate($value, $seek, "{$id}[$key]", $depth+1);
}
}
elseif (is_object($value)) {
$idx = str_replace('0', 'g', md5(serialize($value)));
if (!isset($structs[$idx])) {
$structs[$idx] = "object:$key:$depth";
common_locate($value, $seek, "{$id}->$key", $depth+1);
}
}
}
}
return $results;
}
Subscribe to:
Posts (Atom)