Debugging HTTP requests to PHP via the CLI

You're a sysadmin. You love the CLI. You use PHP. Surely, you should be able to troubleshoot PHP applications that are normally run via an HTTP server through the CLI as well, right? Well good news; you can -- with a few caveats.

This is in follow-up of a blogpost I made in 2012 titled "Running php-cgi scripts via the CLI as a webserver would (by faking them)". If you can run your PHP applications via the CLI, you can use tools such as strace to debug the PHP app's behaviour.

TL;DR: you can fake pretty much any HTTP request by setting the correct environment variables before you call the PHP binary.

First, the caveats.

  • Your PHP settings may be altered or overwritten in the webserver (Apache/PHP-FPM daemon), the PHP binary you run via CLI may not have a correct representation as the PHP(-FPM) binary used via that HTTP server -- so check your PHP settings;
  • You won't be using the APC or OPcache as you're running PHP via the CLI, neither the opcode nor the key/value cache of APC/OPcache is used;
  • Your $_SERVER environment variables will be different than via an HTTP webserver, keep that in mind if your application depends on it;

Now. On with it.

Basic web application

If you have a simple PHP application you will most likely be able to run it simply via the CLI.

$ cd /path/to/your/docroot
$ php index.php

The output can (but is not necessarily the case) be the same as if it were called via the web.

Using environment variables to determine dev/staging/prod

Just like you can specify environment variables in Nginx or Apache, to allow your code to use different users/passwords/settings, it can be used via the CLI as well. If your application depends on an environment variable called APPLICATION_ENV to distinguish environments, you can add it to your request.

$ cd /path/to/your/docroot
$ APPLICATION_ENV=development \
  php index.php

A framework which uses routes

If you're using a framework that has a routing controller, to map URI's directly to the index.php file, you can add environment variables to make the PHP app think you're requesting a specific URI.

$ cd /path/to/your/docroot
$ REQUEST_URI=/your-test-page \
  php index.php

Multi-domain PHP application

If you're running your PHP application as a multi-site app, meaning your content and code behaviour can differ depending on the hostname being used in the request, you can also pass those along as environment variables.

$ cd /path/to/your/docroot
$ SERVER_NAME=www.yoursite.tld \
  HTTP_HOST=www.yoursite.tld \
  REQUEST_URI=/your-test-page \
  php index.php

Sending POST requests at CLI

The HTTP method is just a environment variable -- so it's changeable.

$ cd /path/to/your/docroot
$ REQUEST_METHOD=POST \
  CONTENT_TYPE=application/www-form-urlencoded \
  REQUEST_URI=/your-test-page php index.php

Conclusion

Running these PHP commands via the CLI allows you to troubleshoot applications more easily, as you can now reproduce specific HTTP requests on demand. The main benefit comes from the ability to attach a debugger (such as gdb or strace, sysdig) to that process.

You can see all low-level system calls as well as all network traffic (such as MySQL queries, memcached requests, MongoDB traffic, ...) as your application is sending and receiving it.

The Social Box

You can sign up for more updates via Twitter or Facebook below. On Twitter, I regularly talk about technology or tweet about interesting stories. Topics that don't necessarily make it to this blog. Facebook contains a steady update of blogposts and some more lightweight stories.


Write a Comment

Do you care about the markup if your comment? You can use the following HTML tags:

<code>command</code>: command highlighting
<pre>text</pre>: pre-formatted code, can be multi-line (black background, white letters)

example <pre> tag
<blockquote>text</blockquote> quoted text
quoted example


None of this is needed of course, it's all optional!

Comment

*

  1. Still a golden post!
    Just thought I’d weigh in here.

    When using php instead of php-cgi, the application is sometimes able to detect this.

    eg:

    with php:

    # SERVER_NAME='www.site.tld' HTTP_HOST='www.site.tld' REQUEST_URI='/2014/06/30/generic-title-page' php index.php
    ...
    
    Page Caching using apc (Console mode)
    Database Caching using apc
    

    with php-cgi:

    # REDIRECT_STATUS=200 REQUEST_METHOD=GET SERVER_NAME='www.site.tld' SCRIPT_FILENAME='/var/www/vhosts/site.tld/httpdocs/index.php' SCRIPT_NAME='/index.php' PATH_INFO='/' HTTP_HOST='www.site.tld' SERVER_PROTOCOL='HTTP/1.1' REQUEST_URI='/2014/06/30/generic-title-page' $(which php-cgi)
    
    ...
    
    Page Caching using apc
    Database Caching 27/90 queries in 0.078 seconds using apc

    When using php-cgi, more info is given, and it more closely represents the actual call going from apache (or nginx) to php-cgi .

  2. If you’d like to run strace against sites (like WordPress):

    strace -r -E REDIRECT_STATUS=200 -E REQUEST_METHOD=GET -E SERVER_NAME='www.site.tld' -E SCRIPT_FILENAME='/var/www/vhosts/site.tld/httpdocs/index.php' -E SCRIPT_NAME='/index.php' -E PATH_INFO='/index.php' -E HTTP_HOST='www.site.tld' -E SERVER_PROTOCOL='HTTP/1.1' -E REQUEST_URI='/2014/06/30/generic-title-page' $(which php-cgi)
    

    This will output nice timestamps relative to each request.
    You can increase output by using -s 10240
    And enable logging by using -o /path/filename