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 of 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 cache as you're running PHP via the CLI, neither the opcode nor the key/value cache of APC 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) 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.

Looking for help?

Tired of fixing all these tech-problems yourself? We've got an excellent team at Nucleus, a top-class Belgian hosting provider, that can help you. Discover our Managed Hosting, where skilled engineers manage your servers and keep them up-to-date, so you can focus on your core business. We use a variety of Configuration Management Systems such as Puppet to make sure every config is reviewed, unit-tested and guaranteed to be working.

Want to get in touch? Find me as @mattiasgeniar on Twitter or via the contact-page on my blog.

Tagged with:
Posted in php
2 comments on “Debugging HTTP requests to PHP via the CLI
  1. Stéphan says:

    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. Stéphan says:

    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

Leave a Reply

Your email address will not be published. Required fields are marked *

*

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>