Running php-cgi scripts via the CLI as a webserver would (by faking them)

Want to help support this blog? Try out Oh Dear, the best all-in-one monitoring tool for your entire website, co-founded by me (the guy that wrote this blogpost). Start with a 10-day trial, no strings attached.

We offer uptime monitoring, SSL checks, broken links checking, performance & cronjob monitoring, branded status pages & so much more. Try us out today!

Profile image of Mattias Geniar

Mattias Geniar, June 29, 2012

Follow me on Twitter as @mattiasgeniar

You normally wouldn’t run php-cgi scripts via a command line. After all, they’re a Common Gateway Interface used by webservers (such as Apache) to execute PHP-scripts. However, for debugging purposes, it may be useful to be able to run those php-cgi scripts via your command line instead of calling them directly via your web browser.

The way Apache (or any other webserver) passes a request on to a CGI is by creating environment variables that further describe the request. In those environment variables, you’ll commonly find the URL that is being requested, the path to the script, etc …

If you’re used to running scripts via CLI, you would normally use the ‘php’ command and give the script-name as an argument (such as ‘php mydir/script.php'). The same works for php-cgi as well, but the problem starts when you’re running applications via Zend Framework and rely on the routing-engine to map certain URLs to PHP code. If you just execute php-cgi, it would look like this.

$ php-cgi htdocs/index.php 
X-Powered-By: PHP/5.3.13
Content-type: text/html

<HTML>...

So it gets tricky when you actually want to make a request to ‘http://site.tld/nl/page', since you can’t just simply call the PHP-script as the URL is an important factor. But that’s where environment variables come in.

To translate your request to a valid CGI request, call it as such.

$ REDIRECT_STATUS=200 REQUEST_METHOD=GET SCRIPT_FILENAME=htdocs/index.php SCRIPT_NAME=/index.php PATH_INFO=/ SERVER_NAME=site.tld SERVER_PROTOCOL=HTTP/1.1 REQUEST_URI=/nl/page HTTP_HOST=site.tld /usr/bin/php-cgi 
X-Powered-By: PHP/5.3.13

Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-type: text/html

<HTML>...

In the example above, a few important environment variables come into play that are seperated by spaces. After the environment variables, the full path to the php-cgi binary is included (you can find this out with the ‘which php-cgi’ command at the CLI).

  • REDIRECT_STATUS=200: this is important because most php-cgi’s are compiled with extra protection that won’t work without that variable.
  • REQUEST_METHOD=GET: the HTTP method you’re using, for simulating POST requests you can of course change that.
  • SCRIPT_FILENAME=htdocs/index.php: this needs to the path to the script that will process your request. For Zend Framework-like applications, that will be public/index.php most likely.
  • SCRIPT_NAME=/index.php: the relative full path to the script according to the ‘document root’.
  • PATH_INFO=/
  • SERVER_NAME=site.tld: not really that relevant in this example.
  • SERVER_PROTOCOL=HTTP/1.1: which HTTP protocol you want to support, can be HTTP/1.0 or HTTP/1.1.
  • REQUEST_URI=**/nl/page**: the URL a browser would normally call, this triggers the routing in Zend Framework projects.
  • HTTP_HOST=site.tld: the domain name of the URL you want, in the example of ‘http://site.tld/nl/page' this would be site.tld, the FQDN.

By calling the script as such, you can trigger “HTTP requests” via the CLI by pre-filling the environment variables. That example listed a few paragraphs higher is the CLI equivalent of browsing to ‘http://site.tld/nl/page' via a webserver that would pass along the request to php-cgi.



Want to subscribe to the cron.weekly newsletter?

I write a weekly-ish newsletter on Linux, open source & webdevelopment called cron.weekly.

It features the latest news, guides & tutorials and new open source projects. You can sign up via email below.

No spam. Just some good, practical Linux & open source content.