Two tricks for debugging a Drupal WSoD
When working on custom Drupal modules in PHP, one commonly experiences the dreaded White Screen of Death (WSoD). The Drupal community has documented the Drupal WSoD extensively at http://drupal.org/node/158043.
Typically, everything seems fine, and then the Drupal-based web site you are working on (on your local machine) suddenly becomes completely broken, it gives a blank page for any request. Usually I cannot remember even what inconsequential-seeming things I have just changed. The tricks of this post are for directly tracking the down the error with a debugger, by watching it occur. [There is an even better method for this example, described at the end of this post.]
Recently I was working on the versus module and had to track down such an error. I came to a section of Drupal 6.17 code in drupal_load() in bootstrap.inc that looks like this
if ($filename) { include_once "./$filename"; $files[$type][$name] = TRUE; return TRUE; }
After tracking the crash down to roughly here with the debugger, I wanted to set a breakpoint that was only hit when the versus module was the next to be included with include_once and verify that the crash occurred when the module was included.
A conditional breakpoint would do the trick, but conditional breakpoints do not work for me in Eclipse Ganymede with PDT. [And they don't work in other PHP debugging environments for other developers I have asked].
So the first trick is to add code so that you can set a breakpoint that is only hit in the case you care about. Basically, if conditional breakpoints don't work in your environment, then add the condition to the code.
if ($filename) {
if ($name == 'versus') {
$i = 0;
}
include_once "./$filename";
$files[$type][$name] = TRUE;
return TRUE;
}
[Since this debugging change to core is destined to be overwritten, and does not effect code function, it is not "hacking core".]
So, after placing a breakpoint on the bogus
$i = 0;
line, running the code, and then stepping past the breakpoint, I learned that PHP was indeed crashing on the line
include_once "./$filename";
when $filename was sites/all/modules/versus/versus.module.
Then what?
Here's the second trick: Use command line PHP to read the file in question and tell you the error, with a command like:
php < sites/all/modules/versus/versus.module
when you are in the Drupal site's root directory.
You get something like
Fatal error: Cannot redeclare versus_voting_form_submit() (previously declared in /Applications/MAMP/htdocs/drupal6x/sites/all/modules/versus/-:195) in /Applications/MAMP/htdocs/drupal6x/sites/all/modules/versus/- on line 221
which tells you exactly what the error is and lets you fix it and move on quickly.
As I was researching this post, I found http://drupal.org/node/158043 again and studied it carefully. It turns out if you turn on error reporting at the start of index.php as described there you see this page, in the example above. This technique essentially replaces the WSoD with a page containing the fatal PHP error.
So I recommend always pre-pending the index.php for a development site with the three lines of code that turn PHP error reporting on. I'm sure that skills at direct tracking of bugs will still be necessary for difficult debugging tasks, but they are not necessary in the above example.
