Debugging CLI PHP with Zend Server and PDT on Linux and Mac

I’m working on a small PHP application and a big part of it are some CLI scripts which will be executed in the background. Some of these scripts are quite complex, and I got to a point where I need to use a debugger in order to figure out what’s going on.

I started hacking around with my locally-installed Zend Server CE and Zend Studio. I always knew how to manually start CLI debug sessions with Zend Studio (well, I knew, but forgot ;-) ), but then I figured, why not write a small shell script to automate the process, and learn a little about the Zend Debugger protocol on the way?

Here is what I did:

First, create the following shell script. I placed it at /usr/local/zend/bin/php-dbg (alongside the other Zend Server executables, which if you use Mac OS X will be at /Applications/ZendServer/bin):

#!/bin/sh

# Wrapper script for debugging PHP CLI scripts with Zend Studio
# Tested with Zend Server 4.0.0 Beta and Zend Studio for Eclipse 6.1.1
# Shahar Evron [shahar.e at zend], 2009-02-20

# Defaults
DFLT_PORT="10137"
DFLT_HOST="127.0.0.1"
DFLT_PARAMS="debug_fastfile=1&use_tunneling=0"

# Load Zend Server environment variables
. /etc/zce.rc

# Did the user specify the debug host / port?
if test "x$DEBUG_HOST" != "x"; then
  if test "x$DEBUG_PORT" != "x"; then
    QUERY_STRING="&debug_port=$DEBUG_PORT"
  else
    QUERY_STRING="&debug_port=$DFLT_PORT"
  fi

  QUERY_STRING="$QUERY_STRING&debug_host=$DEBUG_HOST&$DFLT_PARAMS"

# If no host/port were specified, try to auto-detect
else
  QUERY_STRING=`wget http://localhost:20080/ -O - 2> /dev/null`
  if test $? -ne 0; then
    # Fall back to defaults
    echo "Unable to auto-detect Zend Studio settings, using defaults" >&2
    QUERY_STRING="&debug_port=$DFLT_PORT&debug_host=$DFLT_HOST&$DFLT_PARAMS"
  fi
fi

DBG_SESS_ID=`date +%s`
QUERY_STRING="start_debug=1&debug_stop=1$QUERY_STRING&debug_session_id=$DBG_SESS_ID" 

QUERY_STRING=$QUERY_STRING $ZCE_PREFIX/bin/php -c $ZCE_PREFIX/etc/php.ini $@

Going over this code might teach you some surprising things about how Zend Debugger and Zend Studio talk to each other ;) I’m not going to go into the details now, but if you have questions feel free to ask.

Next, make this script executable – just run ‘chmod +x <path-to-script>‘ – and you’re good to go.

Here is how to use it:

  • If you have PDT or Zend Studio running locally (on the same machine as the server), just run:

    # /usr/local/zend/bin/php-dbg <script you want to debug>

    That would just work in most cases – if it works you can stop reading now ;-)
  • If you are running the script on a server, but your PDT / Zend Studio is on a different machine (in the same LAN – no NAT or firewall!) you can simply specify the IP address or host name of the machine that runs PDT / Zend Studio as the DEBUG_HOST environment variable. For example:

    # DEBUG_HOST=10.1.2.3 /usr/local/zend/bin/php-dbg <script you want to debug>
  • If you are running the script on a remote machine (as above) and your Zend Studio listens on a port other than 10137, you can also pass the DEBUG_PORT environment variable to override the default port.
  • Also, don’t forget to make sure that the machine that runs your Zend Studio is in the list of allowed debugging clients. You can check it at the Zend Server GUI on Server Setup -> Debugger.
  • If you are running the script on a remote host and there’s a firewall / NAT between you and the server (e.g. you are in an office LAN, trying to debug a script on a remote production machine which is not in your subnet) you’ll probably need to use SSH remote port forwarding to forward connections to your PDT / Zend Studio. I won’t get into how to do it right here – unless you insist.
  • If you want to only type ‘php-dbg’ when running instead of the full path, you can place the file in your $PATH (e.g. in /usr/local/bin) or even better, Add /usr/local/zend/bin (or /Applications/ZendServer/bin) to your $PATH – you can do that by adding the following line to ~/.bashrc:

    PATH=$PATH:/usr/local/zend/bin

Upon running the script, a debug session should simply pop-up in your PDT / Studio and you’ll be able to debug. How cool is that?

BTW: This has been tested with Zend Server 4.0.0 beta1 and Zend Studio 6.1.1. It should work with other versions of Studio as well. In fact, it can also work without Zend Server as long as you have Zend Debugger installed – but why ruin a perfectly good plug?

If you improve the script or find bugs, let me know! Also, if you know how to get the same thing going with xDebug, let me know and I’ll add it to the script.