Video icon 64
Learning to code? Skill up faster with our practical video courses. Start your free trial today.
Advertisement

The Joy of FirePHP: A Crash-Course

by

FirePHP is a Firefox plugin and server-side library combination which allows you to send all sorts of juicy info out of your web application to your browser, much like the console.log() functionality with JavaScript. In this PLUS tutorial and companion screencast, we’ll teach you how to get started from the very beginning!

This tutorial includes a screencast available to Tuts+ Premium members.

So you think you're a great web developer, huh? Don't read on until you pass the first challenge: answer (honestly) "true" or "false" about yourself to the following statements:

  1. You use Firefox for web development
  2. You've got the famous Firebug extension installed
  3. You develop in PHP

If you answered all three with a resounding "true," give yourself a pat on the back. I'll forgive you for not getting number three, but if you're not using Firefox with Firebug... where have you been!?

You'll need this winning combo to complete this tutorial. The last thing you'll need - to become that grand-master, uber-developer, code-slayer of your dreams - is the most important part: FirePHP.


What is FirePHP?

FirePHP is a Firefox plugin and server-side library combination which allows you to send all sorts of juicy info out of your web application to your browser, in a nicer fashion than the usual:

 
echo $variable;

This code is so common. Sometimes it seems the quickest way to just splat out the value of $variable so you know what it is at a given point of code execution.

But what if $variable isn't a string or an integer; what if it's a complex datatype like an array or an object? In PHP, the above code wouldn't be so helpful:


"Just use print_r($variable);" I hear you say. Alright smarty pants, but that's not very elegant. Trying to find the value of an array item in that mess is a pain. And it still doesn't sort out objects!

When you see what FirePHP can do, you'll change your mind! It turns debugging into a surprisingly enjoyable process and results in much more portable code.

In this tutorial I'm going to show you how to set up FirePHP in your app and some great ways to use it to speed up development and debugging.


Step 1: Setting Up The Server-Side

If you haven't got the FirePHP extension installed, install it now.

The FirePHP extension (which I will refer to as FirePHP from now on) is wholly reliant upon Firebug, so you'll need that too. The server-side classes (which I will call FirePHPCore) are available as a standalone library. There are also a number of plugins for the popular PHP frameworks and CMSs.

Simon says:

Although the name suggests otherwise, FirePHP isn't just for PHP developers. It uses its own set of HTTP headers to send information from your application to the browser, so it can easily be ported to other languages. There are server-side libraries available for ASP, Ruby, Python and more. If there's not one for your language, you could always challenge yourself and write your own.

This also makes it ideal for AJAX debugging as it means asynchronous responses are clean content containing only the output you want to see - not the debugging code.

Go ahead and download your preferred server-side library. In this tutorial, I will focus on using the standalone core library. Instructions for setting up other libraries can be found on the FirePHP wiki.

Simon says:

If you have PEAR setup and prefer to use that, simply type the following two lines at the command line:

 
pear channel-discover pear.firephp.org 
pear install firephp/FirePHPCore

Once you've unzipped the package, go into the lib folder and copy the FirePHPCore folder to your web server or app include folder.


Companion Screencast


Simon says:

One of the great things about the standalone FirePHPCore is its support for PHP4. So you can even plug it into some of those retro sites you're still running!


Step 2: Hello, FirePHP

As with all good coding tutorials, we'll start with a basic example, the "Hello, World" of FirePHP.

Create a new, blank PHP document. I'll call mine test.php. Save it to the root of your app.

For FirePHPCore to do its work, we need to enable output buffering. Read up more about this if you've not used it before, it's a good habit to get into anyway.

 
<php 
ob_start('ob_gzhandler'); 
 
ob_end_flush(); 
?>

Of course, we mustn't forget to include the FirePHPCore library. If you're running on PHP5, add this to the top of the file:

 
include_once ('includes/FirePHPCore/fb.php');

If you're running PHP4, include the fb.php4 file instead.

Simon says:

We don't need to include the class file as this is included in the fb.php file.

Now we can start outputting to the Firebug console. Type the following after ob_start() and before ob_end_flush():

 
FB::info('Hello, FirePHP');

Simon says:

FirePHPCore has a procedural and an object-oriented API. There's really no difference between the two and you can use whichever you prefer.

It also uses the singleton pattern to save memory and comes with a completely static helper class, which I prefer to use as it requires less coding.

Open Firefox, start Firebug and go to this page. You should get something like this:


How cool is that!? Well, that's not a very exciting demo, so let's try something a little more complicated.


Step 3: Sending Complex Variables

Let's see what happens when we pass in a complex variable. We'll build an array and see what we get. Add the following code just after the last FB::info() call:

 
$array['key1'] = 'some content'; 
$array['anotherKey'][] = 1234; 
$array['anotherKey'][] = 5678; 
$array['anotherKey'][] = 9012; 
$array[] = null; 
 
FB::info($array, 'My Array Test');

Now save, go to Firefox and refresh.


Ok, looks good... but, hang on, where is all the output? Hover your cursor over that new line.


Wow. The Firebug frame shows us all of the data in our array - not just first-level array elements, but down-level ones too - and in a neat, legible fashion.

It gets even more interesting with objects! FirePHPCore makes full use of reflection to inspect an object's properties - even private ones.

Simon says:

FirePHPCore has a number of options that can be set to limit the level of inspection into arrays and objects. You can even create a filter for object properties that you don't want it to pass to the user agent.

You can find out more about the FirePHPCore API at the FirePHP Headquarters.


Practical Uses

It should be obvious to you already that this can help with general debugging, but now I'm going to look at some inventive ways to use FirePHP.

1) A PHP Profiling Tool

If you use a single front controller to route all requests for and bootstrap your app, you could time how long each request to your application takes to process on the server.

Something like this would do it:

 
<php 
ob_start('ob_gzhandler'); 
$requestStart = microtime(); 
 
/** 
 * Application runs code, includes, functions and all that... 
 */ 
 
$requestEnd = microtime(); 
 
// Calculate the time taken 
$executionTime = $requestEnd - $requestStart; 
 
FB::info($executionTime, 'This request took (seconds)'); 
 
ob_end_flush(); 
?>

Bear in mind that this isn't a representation of response time, only code execution time - how quick your server executes the code before sending it to the user agent. Output still has to travel from your server to the client across the network.

Simon says:

You could use the YSlow extension for Firebug to track overall page load times and app responsiveness.

2) A Simple SQL Query Inspection Tool

If you use a central query function or extend a database connector class (such as mysqli), you can wrap a timer around any synchronous queries and check how long each one takes.

You could also make a note of the SQL queries themselves. In fact, you could put these two bits of data together. And wouldn't it be nice to display that in a well structured table?

Well Firebug has a table structure and FirePHPCore has a wrapper for that too:

 
<php 
// This assumes you've already included the fb.php file 
 
/** 
 * File: myDb.class.php 
 * You would instantiate this class to run queries 
 */ 
class myDb extends mysqli { 
	public static $queries; 
	public static $totalQueryTime; 
	 
	public function query ( $query ) { 
		// Start query timer 
		$startTime = microtime(); 
		 
		$result = parent::query ( $query ); 
		 
		// End query timer 
		$endTime = microtime(); 
 
		$execTime = $endTime - $startTime; 
 
		// Increment the total query time 
		self::$totalQueryTime += $execTime; 
 
		if ( $result ) { 
			// Notice that for each query we record the query string itself and the time it took to execute 
			self::$queries[] = array ( $query, $execTime ); 
		} 
		else { 
			FB::error ( $query, 'Error in Query: ' . mysqli_error ( $this ) ); 
			FB::trace ( 'Stack Trace' ); 
		} 
 
		return $result; 
	} 
} 
 
 
/** 
 * File: debug.php 
 * Include this file at the very end of your application 
 */ 
if ( is_array ( DB::$queries ) ) { 
	$header = array('SQL Query', 'Execution Time (s)'); 
		 
	$footer = array('Total Execution Time:', DB::$totalQueryTime); 
		 
	$table = array_merge($header, DB::$queries, $footer); 
} 
 
FB::table( count(DB::$queries) . ' SQL queries executed', $table); 
?>

Simon says:

I've thrown a couple of extras in here. In the myDb.class.php file, if the $result variable comes back false, it means this query failed. So I'm using FB::error() to flag this as an error in Firebug and show me the query as well as FB::trace() to show me the process stack leading up to the bad query.

The key thing here is the FB::table() method. This makes creating structured debugging information dead easy.

Now when you instantiate your myDb class and execute a query, it pops the details of that query into an array. We then access that array later on to build our FirePHP table of all the queries you executed for that request, how long each one took, and the total execution time of all the queries.


What you've done here, with just few lines of code, would have been impossible with just echo. You couldn't hope to get something so useful in such a short period of time. That makes for some rapid debugging.

3) An AJAX Debugger

Using FirePHPCore for AJAX requests is no different than using it for synchronous requests. Simply use the functions as you would normally. When your app makes an AJAX requests, the extra FirePHP header information comes through and the client side extension processes it into Firebug's console. Let's try it.

Create a new file called ajax.php in the root of your app. Put the following code in there:

 
<php 
include_once('includes/FirePHPCore/fb.php'); 
ob_start('ob_gzhandler'); 
 
FB::info($_GET['str'], 'My AJAX Test'); 
 
echo 'My clean AJAX response'; 
 
ob_end_flush(); 
?>

Now in your test.php file, add the following after your last FB::info() call:

 
?> 
 
<script src="http://www.google.com/jsapi"></script> 
 
<script type="text/javascript"> 
	google.load('jquery', '1.3'); 
</script> 
 
<script type="text/javascript"> 
	$(document).ready(function(){ 
		$('#button').click(function(){ 
			// Notice the GET parameter we're passing. This is what we look for in our ajax responder 
			$('#ajaxContainer').load('ajax.php?str=I+love+jQuery'); 
		}); 
	}); 
</script> 
 
<input type="button" value="Click Me!" id="button" /> 
<div id="ajaxContainer"></div> 
 
<php

Refreshing test.php in Firefox should show you your 'Click Me!' button. When you click it, the browser should perform an AJAX request and load the response (in this case plain text) into the <div id="ajaxContainer">.


More importantly, FirePHP adds a new node to Firebug that shows us any FirePHP messages we logged in the ajax.php file.

4) Default Error Handler

Stick this at the start of your app and even nasty old PHP errors get dumped to Firebug!

 
set_error_handler('myErrorHandler'); 
 
// You could add optional parameters $errfile, $errline and $errcontext for more detail 
function myErrorHandler($errno, $errstr) { 
	FB::error($errstr, 'Error number' . $errno); 
} 
 
// Continue with normal execution

This is a much cleaner and safer way to report errors. It gets even better if you demonstrate your apps to clients while they're in development (and at risk of producing non-critical errors) - if they're not using Firefox, with Firebug and FirePHP, they won't see those hideous errors, but you will... in Firebug. No more changing your error reporting levels just to keep things tidy! Now that's faster development.


Security

While FirePHP is a great tool for debugging during development and testing, it shouldn't be left on when an app goes into production. It can potentially reveal way too much information about your app making life even easier for hackers.

Of course, if you connect to a site over HTTPS, all header information is encrypted as standard. Otherwise it is sent as plain text.

It also adds an overhead to your app that could cause a serious reduction in performance and a dent in your bandwidth.

This brings me to another great point about FirePHPCore: you can leave the FirePHP code in place, but it won't send any data if it is disabled or if the requesting user agent string doesn't contain the specific FirePHP reference.

If you absolutely must enable FirePHP on production sites, for example for remote debugging, make sure it's on a switch and don't forget to switch it off when you’re done. Something like:

 
define('DEBUG_MODE', true); 
FB::setEnabled(false); 
 
if ( DEBUG && $_SESSION['userIsAdmin'] ) { 
	FB::setEnabled(true); 
}

This makes sure that even if your DEBUG_MODE is set to 'true' (i.e. 'on'), only an authenticated administrator session using a user agent with FirePHP installed will trigger the debugging code and receive the extra header information.


Conclusion

FirePHP is a brilliant tool. It has slotted perfectly into my workflow. Because it's always there, bolted onto the tools I already use on a daily basis, it has become second nature to use.

More importantly, it has saved my skin more than a few times. I have been able to debug sites in production without having to take the sites down. It has made AJAX debugging a very real possibility and because it's open-source and free to use, the cost of adoption is extremely low.

Add to this the fact that my apps are now more portable, I have a better insight into them, and I've learned a few new tricks along the way, what's not to like?

More and more web developers are using the browser as their primary development tool. And why not? It's where our applications are intended to work. So it seems somehow more natural to put profiling and debugging right in the browser; where we spend most of our time debugging anyway!

Think it's time to stop using echo now? Congratulations, Super-Dev!


FirePHP was created by Christoph Dorn. Version 0.3.1 is the current stable version. The 1.0 version is in development and promises some exciting new features.

Advertisement