Nov 16

Command Line Scripts with PHP

Well, it never ceases to amaze me how much I don’t know about the technologies I use every day as part of my job. No, I’m not saying that I don’t know how to do my job, but I’m rather saying that there are realms of possibilities the likes of which I’ve never imagined could be accomplished with such ease. I have always enjoyed learning bits and pieces of *NIX command line, shell scripting and other functionality that lies beneath – or rather, behind – my everyday web work, but I have never really looked into writing command line scripts.

To some of you, this will be very basic, and you may already be dismissing me as an ignoramus, but I beg you to stay with me here and apprecieate the excitement we all experience when the proverbial lighbulb turns on in your head. That is what happened this week as I began working on a script that was to be run in order to scrape images from within an FTP directory (or any directory, for that matter) for insertion into our CMS system for clients. Without the risk of breaching any NDAs, suffice to say that the script, in theory, will allow people to FTP images into a directory and still be able to have full use of them within the CMS as a whole.

I have written CRON scripts in the past, as this will be, but I have always just used full PHP functions and still had a web mindset behind all the ones I have done. In this case, I needed something a bit more flexible, since the script would need to be able to be run on a single server as multiple CRON tasks for multiple users — each with their own arguments. This brought me to the first of my discoveries, and it was simply a lack of reading the manual that kept me from finding this gem out before: the PHP get_opt() function. Combining this function with the standard $argv array, it became very quickly clear to me just how powerful a tool PHP could be for creating this type of script.

Soon, I was able to define my arguments (both required and optional) with a little light reading, and I came up with something similar to this:

#!/usr/local/bin/php
ini_set('memory_limit', '100M');
$a_args = getopt('s:d:vh');
define('DEBUG', isset($a_args['v']));

define('SOURCE', isset($a_args['s']) ? $a_args['s'] : FALSE);
define('DESTINATION', isset($a_args['d']) ? $a_args['d'] : FALSE);
// ...

This was an incredible breakthrough for me, because I was able to pass information in directly through the command line and alter the course of the script. Likewise, I was able to set up this same script to handle multiple CRON tasks and simply changing the arguments passed in through the CRON and altering the output location, this one script can handle all the client crawls.

One other thing that I really wanted to share was a tidbit of code that a friend wrote that allows for altering the actual output that a command line script runs. These next couple functions allow for coloring code as well as justifying code to aid in relieving the mundane of gray that typically meets you at the prompt:

/**
 * Color text with ANSI Power.
 * @param string $text
 * @param string $color black|red|green|yellow|magenta|cyan
 * @return string
 */
function colorText($text, $color)
{
  if (!COLOR)
  {
    return $text;
  }

  $value = 37;
  switch ($color)
  {
    case 'black':   --$value;
    case 'red':     --$value;
    case 'green':   --$value;
    case 'yellow':  --$value;
    case 'blue'  :  --$value;
    case 'magenta': --$value;
    case 'cyan':    --$value;
  }

  return "\x1B[{$value}m{$text}\x1B[0m";
}

/**
 * Prints the message and a timestamp if debug is on.
 * @param string $text
 * @return true
 */
function debug($text)
{
  if (DEBUG)
  {
    echo date('r - ') . $text . "\n";
  }

  return TRUE;
}

With these functions in play, we are easily able to output numbers of color variations as well as restrict output by whether or not the user has selected to have verbose (debug) mode turned on. Additionally, setting up help screens for your script is rather easy as well. A final tidbit that really helped me is that by default, echo or print spit the data out to STDOUT, but with using fwrite(), you can define errors to print to STDERR instead, and if you know anything about handling command line returns, you can choose to log errors separately from the regular output for logging purposes as well.

As I said, this may be very old hat to some, but the beauty and simplicity of figuring this out gave me pause enough to write up a quick article about it. I only hope that this little information is of as much help to someone else as it was to me.

No Comments

Leave a comment