JavaScript Powered PHP Debugging
Intended Audience
Overview
Learning Objectives
Background Information
Prerequisites
How it Works
• Opening a Debug window
• Printing a Debug Message
• Printing a Debug Variable
The Script
Example Use
Tips
About the Author
Intended Audience
This tutorial is intended for PHP programmers who want a more transparent way to debug PHP applications. Experience with JavaScript window functions is assumed.If you want to read more about the JavaScript techniques used in this tutorial, I suggest the following pages at CNet’s Builder.com:
Overview
Debugging in a scripting language can be problematic. There are several PHP debugging options that are growing in both functionality and popularity. However, these options generally require server access and special configuration. Most programmers revert to simply printing variables to the browser via clumsy print() or print_r() statements. Neither of these solutions is ideal. Both can interfere with page layout and the results can be interspersed throughout the page and be difficult to find. With this tutorial, you will be able to create a library that will alleviate these issues.Learning Objectives
You will learn to use PHP to write JavaScript. This will allow you to write messages to a remote debugging window without interrupting your site layout. You will learn to apply basic string substitution, and briefly examine a method of capturing data on PHP’s STDOUT via output buffering.Background Information
JavaScript will allow you to open a blank child browser window. This is a window that has no URL location. You may then use JavaScript to write text to this window. Internet browsers will track child windows across the browser session. This will allow you to write text to this window as you move from page to page on your site. You will be able to open a remote window, and write debug information to that window on each page load of your site, tracking variables as they are manipulated.Prerequisites
This script requires Output Control. This has been present in PHP since 4.0 and does not require an extension. In addition, your client browser must have JavaScript enabled.How it Works
Opening a Debug window
This library uses a private function to open a remote window. You should never need to call this function directly. The function uses a static variable to track whether or not a remote window has been opened. Static variables will persist across multiple requests to a function. This will allow the script to determine if a window is currently open. If the window opening JavaScript has not been printed, this function will do so.
function debug_open_window()
{
static $window_opened = FALSE;
if(!$window_opened)
{
?>
<script language="JavaScript">
debugWindow = window.open("","debugWin","toolbar=no,scrollbars,width=600,height=400");
debugWindow.document.writeln('<html>');
debugWindow.document.writeln('<head>');
debugWindow.document.writeln('<title>PHP Remote Debug Window</title>');
debugWindow.document.writeln('</head>');
debugWindow.document.writeln('<body><font face="verdana,arial">');
debugWindow.document.writeln('<hr size=1 width="100%">');
</script>
<?
$window_opened = TRUE;
}
}
Printing a Debug Message
A call todebug_msg() will print a message to the remote window. This function first calls the
debug_open_window() function to assure that the remote debug window is present, and then prints JavaScript
code that will write text to the remote window.
<?php function debug_msg($mesg)
{
debug_open_window();
print "<script language='JavaScript'>\n";
print "debugWindow.document.writeln('".trim(nl2br($mesg))."<br>');\n";
print "self.focus();\n";
print "</script>\n";
}
writeln() method of the remote window document, we can add new text to the debug window.
The debug_msg() function converts any newline characters to html linebreaks to assure that the script
output is uninterrupted.Printing a Debug Variable
Printing a debug variable with thedebug_var() function is very similar to the debug_msg() function.
The debug_msg() function takes two parameters; $name, a string name of the variable or a message to print,
and $data, an unknown variable, which is typically an array. PHP has supplied the
print_r() function for printing array data in a
human readable way. However, print_r() prints directly to STDOUT. In order to direct this to the debug window, the script must
capture the output, and then write it to the remote window via JavaScript. The script uses the PHP
output buffering functions to capture the output
of the print_r() function. The private function debug_capture_print_r() will return the output of print_r() as a string.
<?php function debug_capture_print_r($data)
{
ob_start();
print_r($data);
$result = ob_get_contents();
ob_end_clean();
return $result;
}
<?php function debug_colorize_string($string)
{
/* turn array indexes to red */
$string = str_replace('[','[<font color="red">',$string);
$string = str_replace(']','</font>]',$string);
/* turn the word Array blue */
$string = str_replace('Array','<font color="blue">Array</font>',$string);
/* turn arrows graygreen */
$string = str_replace('=>','<font color="#556F55">=></font>',$string);
return $string;
}
print_r() function spans multiple lines. The JavaScript writeln() method cannot
accept strings with newline characters. The captured results of the print_r() statement will be processed with the
explode() statement to separate the output lines.
The debug_var() function will use a JavaScript writeln() method call to write each of these output lines. Additionally, the HTML
<pre> tag will be used to preserve spacing and layout.
<?php function debug_var($name,$data)
{
debug_open_window();
$captured = explode("\n",debug_capture_print_r($data));
print "<script language='JavaScript'>\n";
print "debugWindow.document.writeln('<b>$Name</b>');\n";
print "debugWindow.document.writeln('<pre>');\n";
foreach($captured as $line)
{
print "debugWindow.document.writeln('".debug_colorize_string($line)."');\n";
}
print "debugWindow.document.writeln('</pre>');\n";
print "self.focus();\n";
print "</script>\n";
}
The Script
This script uses the PHPDoc commenting system from http://phpdoc.de/. It is intended as an included library file.
<?php
/**
* print debug information to the current debug window
*
* @access public
* @param $name string variable name
* @param $data unknown variable
* @return null
* @global
*/
function debug_var($name,$data)
{
debug_open_window();
$captured = explode("\n",debug_capture_print_r($data));
print "<script language='JavaScript'>\n";
print "debugWindow.document.writeln('<b>$sName</b>');\n";
print "debugWindow.document.writeln('<pre>');\n";
foreach($captured as $line)
{
print "debugWindow.document.writeln('".debug_colorize_string($line)."');\n";
}
print "debugWindow.document.writeln('</pre>');\n";
print "self.focus();\n";
print "</script>\n";
}
/**
* print a message to the debug window
*
* @access public
* @param $mesg string message to display
* @return null
* @global
*/
function debug_msg($mesg)
{
debug_open_window();
print "<script language='JavaScript'>\n";
print "debugWindow.document.writeln('".trim(nl2br($mesg))."<br>');\n";
print "self.focus();\n";
print "</script>\n";
}
/**
* open a debug window for display
*
* this function may be called multiple times
* it will only print the code to open the
* remote window the first time that it is called.
*
* @access private
* @return null
* @global
*/
function debug_open_window()
{
static $window_opened = FALSE;
if(!$window_opened)
{
?>
<script language="JavaScript">
debugWindow = window.open("","debugWin","toolbar=no,scrollbars,width=600,height=400");
debugWindow.document.writeln('<html>');
debugWindow.document.writeln('<head>');
debugWindow.document.writeln('<title>PHP Remote Debug Window</title>');
debugWindow.document.writeln('</head>');
debugWindow.document.writeln('<body><font face="verdana,arial">');
debugWindow.document.writeln('<hr size=1 width="100%">');
</script>
<?
$window_opened = TRUE;
}
}
/**
* catch the contents of a print_r into a string
*
* @access private
* @param $data unknown variable
* @return string print_r results
* @global
*/
function debug_capture_print_r($data)
{
ob_start();
print_r($data);
$result = ob_get_contents();
ob_end_clean();
return $result;
}
/**
* colorize a string for pretty display
*
* @access private
* @param $string string info to colorize
* @return string HTML colorized
* @global
*/
function debug_colorize_string($string)
{
/* turn array indexes to red */
$string = str_replace('[','[<font color="red">',$string);
$string = str_replace(']','</font>]',$string);
/* turn the word Array blue */
$string = str_replace('Array','<font color="blue">Array</font>',$string);
/* turn arrows graygreen */
$string = str_replace('=>','<font color="#556F55">=></font>',$string);
return $string;
}
?>
Example Use
To use these function, include() this library into your script. Then you may call bothdebug_msg() and debug_var() anywhere within your script.
A simple way to examine incoming URL parameters would be to examine the superglobal array $_GET.
debug_var('Get Parameters', $_GET);
for($i = 0; $i < 10; $i++){
$j = $i * 10;
debug_msg("$i => $j");
}
debug_msg() command to determine progress through a long running script. This example will use
flush() to push the output to the browser and
attempt to present this in real time.
$start_time = time();
debug_msg('Starting query');
flush();
/* long running query */
debug_msg('Finished query in '. (time() - $start_time). ' seconds');
flush();

Comments
I have been wondering how to get a debug environment for php since I been
program php. I would like to use your example, but I am not so sure how...
1. for "function debug_open_window() "
should I put this in a php file in server side?
2.should I put the rest of the functions in the same file?
function debug_msg($mesg)
function debug_capture_print_r($data)
function debug_colorize_string($string)
function debug_var($name,$data)
3. and then put the script function in another php file in server side?
4. how to use output control?
5. how to use these function?
Could you give a step by step example?
Many thanks,
Ruichen
"Printing a debug variable with the debug_var() function is very similar to the debug_msg() function. The debug_msg() function takes two parameters;"
Should be:
"Printing a debug variable with the debug_var() function is very similar to the debug_msg() function. The debug_var() function takes two parameters;"
I'm going to give all this a try. thanks!
print "debugWindow.scrollBy(0,10000);";
This will keep the debug window scrolled to the bottom, until
you hit ten thousand pixels of backlog.
The FirePHP tool gets around this limitation by sending the debug data in the response headers instead of the page content.
The debug data is then displayed in the Firebug Console.
You can find more information at: http://www.firephp.org/