2. Understanding the CLI SAPI, and why you need to
As we mentioned in Chapter 2, most systems programming you do will involve using the PHP CLI SAPI. It’s therefore important to have a good grasp of how to use it, the options for configuring and running it, and how it differs from the web based SAPIs you are used to. Luckily the differences are minimal, and many are intuitive, although it’s still worth having a thorough read of this chapter as the CLI SAPI forms the basis upon which most of your code will run.
2.1 What’s different about the CLI SAPI?
The following is a list of the main differences between the CLI SAPI and the standard web implementation :
2.2 CLI SAPI installation
To use the PHP CLI SAPI, you may need to install it first. Appendix A gives details on installing (and compiling, where necessary) PHP. However you may find that it is already installed if you have PHP installed (often in a folder called sapi/cli in the PHP program folders), and if not it is usually available in modern OS software repositories (e.g. in Ubuntu a package called php5-cli exists and can be installed from any package manager or via the command line with sudo apt-get install php5-cli). If it is installed in the command line search path, typing php -v on the command line will print the version details, confirming it is indeed installed.
2.3 PHP command line options
The PHP binary will accept a number of command line options/switches/arguments which affect its operation. A full list can be seen by typing php -h. Although some apply only to the CGI SAPI, the following are some of the more interesting and common ones used when interacting with the CLI SAPI:
-
-for--file
This allows you to specify the filename of the script to be run, and is optional. The -f option exists to allow compatibility with software and scripts such as automation software which can programmatically call command line programs but require filename arguments to be formed in this way. It also allows default filetype handlers to be easily set on Windows for PHP scripts. The only real difference in usage between the two versions of the command above come when interpreting command line arguments passed to the script, which we look at in the “Command line arguments for your script” section below. In most cases, the two following lines are mostly equivalent :
1 ~$ php -f myscript.php
2 ~$ php myscript.php
-
-aor--interactive
Runs PHP interactively. This allows you to type in PHP code, line by line, rather than executing a saved PHP script. This mode of operation is often called a “REPL” (Read-Eval-Print-Loop). As well as providing an interactive interface for testing and developing code, it can also act as an enhanced PHP enabled shell or command-line, and in the next chapter on development tools we’ll look at this and other third party PHP REPLs more closely.
-
-cor--php-ini
Specifies the PHP ini file that PHP will use for this application. This is particularly useful if you are also running web services using PHP on the same machine, as if it is not specified PHP will look in various default locations for php.ini and may end up using the same one as your web service. By providing one specifically for your CLI applications you can “open up” various restrictions that make more sense for offline applications. Note that by using the CLI SAPI, PHP will automatically override several php.ini settings regardless of whether you specify a custom ini file using this option. These overridden settings are those that affect the behaviour outlined in the “Whats different about the CLI SAPI?” above, and while the php.ini file is ignored in these cases you can revert or change these settings directly in your code using ini_set() function or similar. You can also use the -d or --define option to set options (e.g. php -d max_execution_time=2000 myscript.php). If you are deploying software onto machines that you do not control (e.g. if you are selling software for users to install on their own machines), it makes sense to use one of these mechanisms to ensure that PHP will be running with the settings you expect, not the settings the user may happen to have. See -n below as well.
2.4 Command line arguments for your script
As we’ve seen above, passing arguments to PHP itself is straightforward and done in the normal way. However passing arguments for use by your PHP script is a little more complicated, as PHP needs to know where its own arguments stop and where your script’s start. The best way to examine how PHP deals with this is through some examples. Consider the following PHP script:
1 <?
2
3 echo "Number of arguments given :".$argc."\n";
4
5 echo "List of arguments given :\n";
6
7 print_r($argv);
There are two special variables in the script above :
-
$argc: This records the number of command line arguments passed to the script -
$argv: This is an array of the actual arguments passed.
Lets save the script as arguments.php. Now lets call it as follows :
1 ~$ php -e arguments.php -i -b=big -l red white "and blue"
You will get the following output :
1 Number of arguments given :7
2 List of arguments given :
3 Array
4 (
5 [0] => arguments.php
6 [1] => -i
7 [2] => -b=big
8 [3] => -l
9 [4] => red
10 [5] => white
11 [6] => and blue
12 )
As you can see, all of the arguments given from the filename onwards in the command are passed to the script. The first, -e, which is used by PHP itself is not passed through. So, as a general rule, everything after the filename is treated as an argument to the script, anything before the filename is treated as an argument for PHP itself, and the filename is shared between the two.
There is, of course, an exception. As we learned above, in addition to specifying the filename of your script on its own, we can also pass it as part of the -f flag. So if we execute the following command:
1 ~$ php -e -f arguments.php -i -b=big -l red white "and blue"
we get the following unexpected output :
1 phpinfo()
2 PHP Version => 5.4.6-1ubuntu1.3
3
4 System => Linux dev-system 3.5.0-37-generic #58-Ubuntu SMP Mon Jul 8 22:10:2\
5 8 U
6 TC 2013 i686
7 Build Date => Jul 15 2013 18:23:34
8 Server API => Command Line Interface
9 Virtual Directory Support => disabled
10 Configuration File (php.ini) Path => /etc/php5/cli
11 <rest of output removed for brevity>
You may recognise this as the output of calling php -i. Rather than treating arguments after the filename as belonging to the script, PHP has treated the -f argument as one of it’s own, and continued to “own” all of the following arguments. As -i is a valid PHP argument, it decides that it was what you wanted and invokes its “information” mode. If you need to pass the filename as part of the -f flag rather than as an argument on it’s own, you will need to separate your scripts arguments using --. So, for the command above to work as expected, we need to alter it to read: