Tag Archives: Debugging

Remote Debugging with the Zend Debugger and PHPUnit

I’m trying to do some remote debugging with PHPUnit on a remote system.  I was following the rules I had written about in a previous article but for some reason I could not get path mapping to work.  So I figured I’d ping the Studio lead developer because as soon as I did that I’d get it to work.  Well, that’s what happened.  It turns out that some of the debugging URL parameters seem to mess up the remote path mapping feature in Studio when working over the CLI.  What I found works is this.

1
export QUERY_STRING="start_debug=1use_remote=1&debug_port=10137&debug_host=192.168.0.254&original_url=http%3A%2F%2Fremoteurl.com"

The original_url parameter is important because that’s how the path mapping maps the path to the proper project.

Debugging a PHP CLI script

I’m working on some code on the command line that I needed to debug.  It’s on a remote machine (well, a VM that doesn’t have a GUI) and so I needed to initiate a remote debugging session from the command line to go to my local copy of Zend Studio.  Thankfully, it’s pretty easy.  Since I need a place to store this command so I can copy and paste it onto the CLI I figured I’d simply blog about it.  Simply execute  this command prior to executing your PHP script.

export QUERY_STRING="start_debug=1&debug_stop=1&debug_fastfile=1&
debug_coverage=1&use_remote=1&send_sess_end=1&debug_session_id=2000&
debug_start_session=1&debug_port=10137&debug_host=192.168.0.254"

The only thing you will need to change is the debug_host setting and perhaps debug_port.  Run your CLI script and the debugger will attempt to connect to your local Zend Studio instance.  If you want to discontinue debugging you execute this command.

unset QUERY_STRING

Debugging a mobile app

I’m working on an example of mobile detection with the new Zend Framework 1.11 beta that was just released when I came upon an interesting problem.  That problem is; how do I debug requests coming in from the mobile phone?  The answer is actually relatively easy.  I’m doing this using a Zend Framework application, but the concepts that you’ll see here can be used quite easily across any type of framework.

The debugger in Zend Studio works by watching for certain cookies or GET parameters to be sent by the browser.  If they are detected then the Zend Debugger on the server will try to connect to the debugger in the IDE based off of the information provided in the cookie.  I typically do this using the Zend debugger toolbar, but I can’t get that on my Epic (Android).  Another option I have is to debug from the IDE but I’m not actually running from the phone so I will not have the same configuration.

The solution is similar to what I did with Debugging an RPC call in Zend Framework.  What this does is set the cookies from the remote browser to debug on the local instance of the Zend debugger.  To kick it off simply open up the URL to the debug kickoff page.  That will set the cookies in your mobile browser.  Then go to the page that you want to debug from your mobile phone and reload it.  Because you have the cookies set on the mobile browser the next request will debug in your local IDE.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class IndexController extends Zend_Controller_Action
{
 
    public function setdebugAction()
    {
        $cookies = array(
            'start_debug'            => '1',
            'debug_stop'             => '1',
            'debug_fastfile'         => '1',
            'debug_coverage'         => '1',   
            'use_remote'             => '1',
            'send_sess_end'         => '1',
            'debug_session_id'         => '2000',  
            'debug_start_session'     => '1',
            'debug_port'             => '10137',
            'debug_host'             => '127.0.0.1'
        );
        foreach ($cookies as $name => $value) {
            $this->_response->setHeader(
                'Set-Cookie',
                new Zend_Http_Cookie(
                    $name,
                    $value,
                    $this->_request->getHttpHost()
                    )
            );
        }
 
        $this->_helper->viewRenderer->setNoRender(true);
        echo "Debug set";
    }
}

 

 

Debugging an RPC call in Zend Framework

Just a quickie.  Do you ever want to debug an RPC call to XML-RPC or Soap or something like that using Zend Studio/PDT and the Zend Debugger?  What I mean is debug the RPC call, not the request making the RPC call.  Doing that is actually quite simple.  I have some code here to share that I recently (as in 5 minutes ago, used).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$options = Zend_Registry::get('Zend_Application')->getOption('xmlrpc');
        $this->_xmlrpc = new Zend_XmlRpc_Client(
           $options['server']. '/service'
        );
        if (false) {
            $http = $this->_xmlrpc->getHttpClient();
            $http->setCookie('start_debug', '1');
            $http->setCookie('debug_stop', '1');
            $http->setCookie('debug_fastfile' ,'1');
            $http->setCookie('debug_coverage' ,'1');   
            $http->setCookie('use_remote' ,'1');   
            $http->setCookie('send_sess_end' ,'1');
            $http->setCookie('debug_session_id' ,'2000');  
            $http->setCookie('debug_start_session' ,'1');
            $http->setCookie('debug_port', '10137');
            $http->setCookie('debug_host', '127.0.0.1');
        }

What this does is get the HTTP client from XML-RPC (or anything else that uses Zend_Http_Client) and adds a bunch of cookies as defined in the Zend Knowlege Base.  If I want to debug I just change the condition (if (false)) to true and re-run the request.  Since the Zend Debugger listens for cookies that are named like this, once it sees those cookies, the debug request will be initiated.

A few words on the ones you need to know:

  • start_debug – Tells the debugger to actually debug the request.  The debug session will not start without this.  Why not just run the request?  Because there’s also a start_profile which can be used to profile a request instead of debug it
  • debug_session_id – This is considered optional, but if you are getting an error saying that the protocol is wrong change this to a number that has not been used
  • debug_port – The port Zend Studio/PDT is listening on.  It’s probably 10137.
  • debug_host – The host that Zend Studio/PDT is on.  The debugger works by initiating a TCP connection back to Zend Studio and so this IP address ( or comma seperated list) is needed to tell the debugger where to go.

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.

The debugger toolbar

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.

@ini_set('zend_monitor.enable', 0);
if(@function_exists('output_cache_disable')) {
        @output_cache_disable();
}
if(isset($_GET['debugger_connect']) && $_GET['debugger_connect'] == 1) {
        if(function_exists('debugger_connect'))  {
                debugger_connect();
                exit();
        } else {
                echo "No connector is installed.";
        }
}
?>

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

Clicking the Server button

Step 2

Selecting the server

Step 3

Enabling the tunnel

Step 4

Enabling the tunnel.

Step 5.

All done

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.

Testing the connection

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.

httpd     3016     apache    7u  IPv6 4100269       TCP li114-69.members.linode.com:http->xxxxxxxxxx:news (ESTABLISHED)
httpd     3016     apache    8u  IPv4 4100270       TCP *:57192 (LISTEN)

All done.