Maintaining your Server with Command Line PHP

More and more in the Information Technology field are we asked to put on various hats and fill multiple roles in our daily jobs. Not only are many of us given the task to create and maintain a web site, but also to maintain the server its hosted on. Usually when maintaining a server you need to know how to write scripts and small programs to automate tasks. A lot of these scripts are written in Perl, Bash, or some other scripting language. Now I’m not against learning new programming languages at all, but did you know that not only can you use PHP to write great web applications, but you can use PHP from the command line as well? You can use the PHP that you already know and love to keep that server running great, all from the command line!

In this article we’ll look at the advantages of using PHP CLI. I’ll show you how to test PHP’s Command Line Interface / Interpreter (CLI) on your server, and then we’ll look at some of the options available for PHP CLI including the interactive shell and how to create executable scripts. Finally, I’ll give you a couple of examples of scripts to use to maintain your server written in PHP.

One of the biggest advantages of using PHP CLI instead of some other scripting language is the ability to reuse code from previous projects in your script. Whether it be a database class or a function that you created or maybe a file parsing program, with PHP CLI you don’t have to rewrite any of your code.

You can also automate many tasks written with PHP CLI with CRON. If you have never used CRON before, it’s a daemon program that runs specified scripts at specific times on your server. Need to generate a report for the sales department on Mondays, Wednesdays, and Fridays? Write a PHP script to do it, throw it into a CRON job, and sit back and relax while PHP and CRON do the work for you.

Running PHP CLI Scripts

If you are running a recent version of PHP, chances are you already have PHP CLI installed on your system. If the examples in this article don’t work for you, then you’ll probably need to recompile PHP with the --enable-cli option or reinstall a PHP package that contains that option. The easiest way to test to see if everything is working is to open up a new terminal window or SSH session to your server or computer and from the command line type in php -v.

Stephens-Laptop:~ sthorpe$ php -v
PHP 5.3.8 (cli) (built: Dec  5 2011 21:24:09)
Copyright (c) 1997-2011 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2011 Zend Technologies

Let’s try a quick example where we will run an actual PHP file from the command line. Create a file called test.php with the following code using your favorite editor:

<?php
$str = "SitePoint is the best!";
echo $str . "n";

To execute the script, all you have to do is type in php test.php and you’ll see the output on the command line.

Stephens-Laptop:~ sthorpe$ php test.php
SitePoint is the best!

A more preferred method of running PHP scripts on the command-line is to change the permissions mode of the script and place #!/usr/bin/php at the top of the file before the opening <?php tag (your path to PHP may be different depending on your system’s configuration). To accomplish this, you’ll use the chmod command on UNIX-based systems.

#!/usr/bin/php
<?php
$filepath = exec("pwd");
echo "You are in the $filepath directory.n";
Stephens-Laptop:~ sthorpe$ chmod +x pwd.php
Stephens-Laptop:~ sthorpe$ ./pwd.php
You are in the ~ directory.

CLI Options and the Interactive Shell

I’ve already shown you one of PHP’s command-line options earlier, -v which gives you the version number of PHP installed on your system, but there are more options available. For example, if you wanted to share the code from a script you wrote with someone as web page and have it syntax highlighted for better readability, you can use the -s option. PHP will output the appropriate HTML code.

Stephens-Laptop:~ sthorpe$ php -s test.php < test.html

When viewed in a web browser, the resulting test.html presents the highlighted code:

Another helpful option is -l to check your scripts for any syntax errors. If no errors are found in the file, PHP will report back there were no syntax errors. Otherwise PHP will report the error it found and on which line it occurred.

Stephens-Laptop:~ sthorpe$ php -l broken.php
PHP Parse error:  syntax error, unexpected T_VARIABLE in broken.php on line 3
Errors parsing broken.php

In addition to the numerous options available, with PHP CLI you can test out ideas in PHP code right from the shell without having to create any files at all! This is useful when you want to see what the results of a function might be. To run PHP’s interactive shell use -a. PHP will report back “Interactive shell” and the prompt will change to php >. From this point forward you can just type your code and PHP will execute it immediately. To exit the shell, you can either press CTRL + D or call exit.

Stephens-Laptop:~ sthorpe$ php -a
Interactive shell

php > echo 2 + 2;
4
php > exit;

Getting Input

With CLI programming, you have two options for input functionality. The first option is to pass arguments to your script directly from the command line. The second option is reading the input from the keyboard (standard input) from the user running the script.

To accept arguments into your script, you’ll use the predefined superglobal variables $_SERVER["argc"] and $_SERVER["arvc"]. Create a file called arguments.php containing the code below:

#!/usr/bin/php
<?php
echo "There are " . $_SERVER["argc"] . " arguments:n";
foreach($_SERVER["argv"] $arv) {
   echo "t" . $arv . "n";
}

$_SERVER["argc"] contains the number of arguments that were passed to the script, and $_SERVER["argv"] is an array containing all the values of those arguments. You will always have at least one argument since the file name itself is considered the first argument.

Make the file executable and pass in a few arguments with a space in between each one. The script will display the total number of arguments and list each one.

Stephens-Laptop:~ sthorpe$ php arguments.php SitePoint Rocks
There are 3 arguments
   arguments.php
   SitePoint
   Rocks

Accepting input from standard input lets you create interactive scripts which can prompt for specific information. Create a file called keyboard.php with the following code:

#!/usr/bin/php
<?php
echo "Hi There! what is your favorite web site?n";
$site = fread(STDIN, 80);
$site = trim($site);

if ($site != "SitePoint") {
   echo "Are you sure that one is your favorite?n";
}
else {
   echo "I knew it! Me too!n";
}

In this example we are using the fread() function just as we would to read in a file, but in this case the handle is the PHP predefined constant STDIN. Once again make the file executable and run the file; hopefully your output will be the same as mine.

Stephens-Laptop:~ sthorpe$ php keyboard.php
Hi There! what is your favorite web site?
SitePoint
I knew it! Me too!

Some PHP CLI Examples

When monitoring a server, one thing worth keeping track of is your available disk space. These days hard drives are so huge that you wouldn’t think that there was a way you could possibly fill up all that space, but trust me… it can happen when you least expect it. Maybe your log rotation process broke and you didn’t realize it, or your temp directory grew out of control. Here’s an example you can use to keep an eye on your server’s disk space:

#!/usr/bin/php
<?php
// config options
$disk = "/dev/disk0s2";
$threshold = 90;
$emailAddr = "you@example.com";
$emailName = "Your Name Here";

exec("df -h " . $disk, $output);
foreach($output as $line){
    $info = strstr($line, $disk);
    if ($info != "") {
        break;
    }
}
$pos = stripos($info, "%");
$pos = $pos - 3;
$used = substr($info, $pos, 3);

if ($used >= $threshold) {
    mail($emailAddr, "System HD Notification", "Main disk is at " . $used . "%" , "From: $emailName");
}

The function exec() executes a command in the command line and accepts two parameters: the first is the actual command (in this case df which displays disk space information), and the second is an array reference that is filled with the command’s output. The $disk variable holds the path of the disk you want to monitor (in my case it’s /dev/disk0s2). The df command outputs various other data than just disk space used, so we’ll only be looking for specific information from the $output array.

The code continues by looping through the array and using the strstr() function to find the desired disk and break out of the loop once it’s been found. I strip out the part of the string that contains the percentage of disk space left with using substr() and compare it to a predetermined value, in this case if the hard drive usage reaches 90% or more. If so, the script sends an email alerting me with the information.

You could have this quick script run as a cron job every 30 minutes or so and it should give you some peace of mind.

Another common task when maintaining a server is to insure that you have a constant backup of files and folders. If some sort of version control of back-up service isn’t available for whatever reason, this next script can be used to back up some folders and a database and send them to an off-site SFTP server.

#!/usr/bin/php
<?php
// remote SFTP connection credentials
$sftpServerIP = "10.0.0.1";
$sftpUsername  = "sftpuser";
$sftpPassword = "hushhush";
$sftpTarget   = "/home/sftpuser";

// mail notification config
$emailAddr = "you@example.com";
$emailName = "Your Name Here";

// MySQL database connection credentials
$mysqlUsername = "dbuser";
$mysqlPassword = "secret";
$mysqlDatabase = "myDatabase";

// list of directories and files to back up
$files = array(
    "/home/username/important-file.txt",
    "/home/username/special-folder",
    "/var/spool/another-folder");

// create temporary directory and copy files/directories to it
$tmpFolder = "/tmp/" . uniqid();
mkdir($tmpFolder, 0700);
foreach ($files as $f) {
    exec("cp -r $f $tmpFolder/");
}

// dump the database content
exec("mysqldump -u $mysqlUsername -p$mysqlPassword $mysqlDatabase > $tmpFolder/backup.sql");

// compress the backup
exec("tar -czf $tmpFolder.tgz $tmpFolder/*");

// establish the sftp connection
$session = ssh2_connect($sftpServerIP, 22);
if ($session === false) {
    mail($emailAddr, "System Backup", "Could not connect to SFTP server", "From: $emailName");
    exit;
}
$result = ssh2_auth_password($session, $sftpUsername, $sftpPassword);
if ($result === false) {
    mail($emailAddr, "System Backup", "Could not authenticate to SFTP server", "From: $emailName");
    exit;
}
$sftp = ssh2_sftp($session);
if ($sftp === false) {
    mail($emailAddr, "System Backup", "Could not initialize SFTP subsystem", "From: $emailName");
    exit;
}

// transfer the backup file
$date = date("D");
$upload = file_put_contents(
    "ssh2.sftp://" . $sftp . $sftpTargetDir . "/backup-$date.tgz", 
    file_get_contents("$tmpFolder.tgz"));

if ($upload) {
    mail($emailAddr, "System Backup", "Your files has been backed up successfully", "From: $emailName");
}
else {
    mail($emailAddr, "System Backup", "Something went wrong with the upload of the backup", "From: $emailName");
}

// clean up the local temp backups
exec("rm -r $tmpFolder $tmpFolder.tgz");

Again we use the exec() function to execute other programs and commands from within our PHP script, such as mysqldump to dump the database content and tar to compress the backup folder into an archive. into the variable we defined before. Connecting to the SFTP server uses PHP’s SSH2 extension, so you’ll need to have that extension installed. A good write up can be found in Kevin van Zonneveld’s blog. The code shouldn’t be too difficult to modify if you want to use a pure solution like phpseclib or even an older (and insecure) protocol like FTP. Regardless of your approach, the sample highlights some of the benefits of scripting such tasks with PHP.

Summary

In this article we explored using PHP from the command line to write server maintenance scripts. I talked about the advantages of using PHP CLI, including the ability to automate your scripts. We went over some neat options available, like the ability to test your scripts for syntax errors and using interactive mode. We also learned about the different input functionality available, including accepting input straight from the keyboard. I then gave you two real world examples of scripts to use to maintain your own servers which included a hard drive monitoring script and a backup script.

I hope this article has given you some ideas and knowledge that will help you in the future when you are given the task to maintain that server, and I hope you can also use these CLI example scripts as a bases to create your own maintenance scripts.

Image via Chengyuan Yang / Shutterstock

Win an Annual Membership to Learnable,

SitePoint's Learning Platform

  • http://davidreagan.net David

    Good article. I do something similar for several of the web apps my College runs. Though I recently ran into a problem, sometimes the tar command doesn’t tar all my files. It exits with an error status, and I log that. But I haven’t figured out how to log what actually went wrong. Any suggestions on how to log any errors from tar?

    • Jonathan

      Assuming you are using exec() to run tar, as in the example, you could redirect standard error to a file.
      tarerror.log”, $output, $return);
      ?>

  • http://About.me/MarcusBarnes Marcus Emmanuel Barnes

    Hi, Stephen,
    Thank you for the nice article – I’m still going through it. I spotted a small typo. The angle bracket in the line:
    php -s test.php test.html
    Correct?
    Thank you!

  • http://About.me/MarcusBarnes Marcus Emmanuel Barnes

    Hi, Stephen,
    Another small typo – in the example for arguments.php the foreach construct is missing an “as”.

    I noticed that the angle brackets where removed from my previous comment. What’s the best way of including code snippets in comments on PHPMaster?

    Have a great day!

  • Greg

    We do a lot of basic site maintenance, mailing reports, database cleanup, etc. using PHP-CLI scripts. It’s very handy to be able to not have to switch languages in the middle of the development processes.

  • Jonathan

    Assuming you are using exec() to run tar, as in the example, you could redirect standard error to a file.
    <?php
    $output = array();
    exec(“tar -czf $tmpFolder.tgz $tmpFolder/* 2> tarerror.log”, $output, $return);
    ?>

  • Sirhan

    When error_reporting and display_errors are set to off and is trying to find where the code fails ? The php -l option is a must and a handy one…
    To a syntax check for all of the php files in the folder, cd to the folder in Terminal and do
    for i in *.php;do php -l $i;done;

    Note: For Unix/Linux systems

  • Sebastiaan Stok

    For people that have PHP5.3, and doing a lot of command-line stuff. Take a look at http://symfony.com/doc/current/components/console.html
    A few of the things included: coloring of result, arguments parsing and promt input.

  • Paul Freeland

    Excellent article with a couple of tips that I hadn’t come across before – thank you

  • Dave

    I’m having trouble with this – I have a php script that I run through the cli, the script echoes various debug info and stdout is redirected to a log file.

    But when I check the log file, some (long) lines are there fully, while other (shorter) lines have been truncated.