Debug Tunneling

Debugging is one of the things that every single PHP developer in the world needs to know how to do. Unless you are simply learning the language, learning how to debug will save you countless hours and save you loads of money in anti-anxiety medications. var_dump() or print_r() is not debugging. At least, it's not debugging in a way that is very useful, or safe.

There are two primary debuggers in the PHP world. XDebug and the Zend Debugger. I am not an expert in XDebug (though I really need to learn it better) so I will leave those discussions to someone else.

Debugging on a local workstation is really quite simple. I use the Zend Debugger Toolbar in my browser when I'm not debugging a Unit Test (how I usually test functional components, as opposed to visual components). The reason I do this is because it's much easier to debug a certain context, such as a logged in admin user, than using the internal browser in Eclipse. The toolbar is installed when you install Zend Studio or you can download it seperately and install it in Firefox manually.

This works very easily when you are working in an environment with very few restrictions, such as a debug environment. However, say you run into a problem in your testing or staging environments? (I could also add your production environment, but you should actually never have the debugger installed on a production environment for security reasons.) The way the debugger works is that Zend Studio opens up a port on the local machine so that when a debug session is kicked off, the debugger in PHP will open up a TCP connection back to Zend Studio and start the debug session. The problem is that testing and staging environments often have outbound port restrictions, for good reason. But that makes debugging an issue in one of those environments a little tricky.

The solution is the debug tunnel. What Zend Studio does is instead of waiting passively on the local machine for a connection to come in, it will open up an HTTP connection to the remote server. Then when a debug session occurs the debugger extension will communicate over a local port, which then forwards the debug information back to Zend Studio over HTTP. The data is the same, it's just being tunneled over HTTP. Because there is no outbound connection initiated and because the communication is occuring over port 80, if you can connect to the web server you can debug on it. It should, however, be noted, that tunneling does not work on Windows systems. I don't know the exact reason, but I would venture to say that it is due to PHP on Windows running as a FastCGI instance. This would likely conflict with the long running request required to facilitate a debug tunnel.

The way this is done is by Zend Studio making a connection to a debug file. That file is usually called dummy.php and contains the following code.

This code turns off all of the timers in monitoring, disables the cache and then checks to see if a debug tunnel is being requested. If so, it basically sites on the debugger_connect() function. This function will open up a port on the local interface and wait for connections to come in. This file does not need to be on the domain name of the web site you are trying to debug. In fact, just so you are sure that you don't accidentally deploy the dummy.php file it would be a good idea to have a seperate virtual host on the Apache server where it would reside.

On the Zend Studio side what you now need to do is set up the tunneling. That is done by clicking on the arrow next to the tunneling button and clicking on "Servers".

Step 1

Step 2

Step 3

Step 4

Step 5.

With that, you should be golden. Or in this case, green.

If you are using the Zend Studio toolbar you can test to actually see this working. Simply go to Extra Stuff -> Settings and click on "Test". You should see something similar to this.

Go to your Linux server and then type in "lsof -i | grep |PORT|" replacing |PORT| with the port in the window. In my case, 57192.

httpd 3016 apache 8u IPv4 4100270 TCP *:57192 (LISTEN)

As you can see we have a connection setting there. If we now do the same thing, but grep for the PID (3016) you can see our connection via our tunnel.