QR Code contains TinyURL of this article.PHP from the Command Line

I’ve been working on a PHP project that provides for execution via either the web-browser or the command-line (CLI). I wanted my program to be able to accept a command-line option. I also wanted to be able to use it inside a Bash script. This meant that it needed to be able to exit meaningfully, so that the Bash script could “know” whether or not its execution was successful.

The majority of the PHP code I write runs from the web-browser via the CGI. So I was unfamiliar with some of the subtleties of designing for CLI execution. I thought I’d better make some notes about what I have learned.

Executing a PHP Script from the CLI

The most common way of executing a PHP script from the command-line is to pass the path of the script to the PHP interpreter:

php /path/to/my_script.php

Now I started my career as a web-developer writing Perl applications. The first line of most Perl scripts usually looks something like this:

#!/usr/bin/perl

That’s known as the shebang line, it tells the operating system to load the interpreter at /usr/bin/perl and execute the script using that interpreter. The shebang is available to all the major scripting languages and PHP is no exception.

This means that we can have, as the first line of a PHP script, the following:

#!/usr/bin/env php

If we then make our script executable:

chmod a+x /path/to/my_script.php

we can run the script without having to pass it as an argument to the PHP binary:

/path/to/my_script.php

At this point, depending on the utility of the script, we could move it into one of the system’s $PATH directories, or add its directory to the $PATH. Doing so enables us to execute the script, from any directory, just by typing its filename: my_script.php

Alternatively, we can simply add an alias to our ~/.bash_profile, which would achieve the same thing:

alias my_script="/path/to/my_script.php"

Determining Whether or Not a Script Ran from the Command-line

In your PHP script, you can determine whether or not the script is running from the command-line with the following code:

<?php
if (php_sapi_name() === 'cli') {
  echo 'Running from the command line!';
} else {
  echo 'Running from the browser!';
}
?>

Command-line Options

How about if you want to set some command-line options as you execute the script? You can access these in PHP with the getopt() function:

<?php
$options = getopt('a:b:');
var_dump($options);
?>

Running the above script like this: php my_script.php -aCat -bDog will result in the following output:

array(2) {
  ["a"] => string(3) "Cat"
  ["b"] => string(3) "Dog"
}

PHP allows you to configure required, optional and no-value command-line options via the getopt() function. You can also configure your script to accept long options as input, i.e.:

php my_script.php --firstanimal=Cat --secondanimal=Dog

Exit Codes

When our PHP script exits we should set an exit code so that we can meaningfully determine whether or not it terminated normally, or with an error.

According to the Bash Bible, otherwise know as the Advanced Bash-Scripting Guide, an exit code should be a value between 0-255 inclusive.

Bash reserves some codes for specific conditions. 0, for example, is generally used to indicated that a script completed successfully. The Advanced Bash-Scripting Guide also lists these:

Bash Script Exit Codes
Exit Code Meaning Example Comments
1 Catchall for general errors let “var1 = 1/0” Miscellaneous errors, such as “divide by zero” and other impermissible operations
2 Misuse of shell built-ins (according to Bash documentation) empty_function() {} Missing keyword or command
126 Command invoked cannot execute /dev/null Permission problem or command is not an executable
127 Command not found illegal_command Possible problem with $PATH or a typo
128 Invalid argument to exit exit 3.14159 exit takes only integer args in the range 0-255
128+n Fatal error signal ‘n’ kill -9 $PPID of script $? returns 137 (128 + 9)
130 Script terminated by Control-C Ctrl-C Control-C is fatal error signal 2, (130 = 128 + 2, see above)
255* Exit status out of range exit -1 exit takes only integer args in the range 0-255

The author of the Advanced Bash-Scripting Guide proposes restricting user-defined exit codes to the range 64-113 (in addition to 0, for success), to conform with the C/C++ standard. This means that we’ve got 50 exit codes available to us, which should be more than enough for expressing the outcome of most scripts.

So how do we use them? With PHP’s exit() command of course:

<?php
echo 'Exiting now!';
exit(0);
?>

These exit codes are then available to us in Bash by querying the variable $?. For example:

echo $?

Or, if we want the exit status of our PHP script to determine the flow of the Bash script that called it:

#!/bin/bash
php my_script.php
if [ $? -eq 0 ];
then
  # exited successfully, do something
else
  # exited with errors, do something else
fi

Final Thoughts

As a general purpose language PHP is ideal for writing concise scripts that can accomplish significant tasks. Being able to configure those scripts so that they can run from and interact with the CLI is cool. Command-line tools are useful within automation, system administration and system maintenance roles. PHP, with its extensive lexicon of file-system, text-processing, networking and database commands, is the ideal scripting language for building such tools.

So what are you waiting for? Fire up your editor and get scripting!