The best part about working with talented PHP Developers in the workplace is learning techniques to make us better developers.
Last week I was required to create an automated PHP script to convert a data file of a legacy application into a newly created internal web app. After completing it, a workmate of mine; Tom McDonnell informed me of a script he had developed which accepted command line arguments and provided great feedback of the status of the running script.
With Tom’s permission to publish components of his source code, I would like to share these tips in this two part article.
The first step is creating a common cron class called class.my_cron.php
We do not want the class to be cloned or instantiated, we merely wish to use it’s methods freely.
In this example we will offer the user to add three possible parameters to the script via the command line. These are -actual, -hypothetical, -verbose.
Actual = Commit the changes
Hypothetical = Do not commit the changes, but still perform all the correct sql queries prior
Verbose = Display detailed descriptions of anything you believe is relevant for debugging purposes.
<?php /** * This class is to define a common library file to include to help with common cron scripting tasks. */ class my_cron { // No cloning or instantiating allowed. final private function __construct(){} final private function __clone(){} } ?>
We require a function that will validate the parameters added to class.my_cron.php via the command line and then return an array of two values:
- Is the query going to commit or rollback at the end of the process?
- What kind level of debugging do we wish to output in the command line?
If one argument is passed (really none), then we display an ASCII header for fun and the usage message from our original PHP script which calls this method.
If two or three arguments are passed (really one/two), then we continue through.
If anything else, we print an incorrect number of arguments error. Combined with an ASCII header for fun and the usage message from our original PHP script which calls this method.
public static function validateArgvArgumentsAndDieWithErrorMessageIfInvalid($usageMessage) { // Declare PHP Super globals // http://www.php.net/manual/en/reserved.variables.php global $argv; //Array of CLI arguments global $argc; //Count of CLI arguments $header = self::cronMsgHeader(); switch ($argc) { case 1: echo "$header\n$usageMessage"; exit(0); case 2: // Fall through. case 3: // Expected number of arguments. Do nothing here, but proceed to next step. break; default: echo "Incorrect number of arguments.\n$header\n$usageMessage"; exit(0); } $boolActuallyUpdateDatabase = null; $boolVerboseOutput = false; $errorString = 'Only one option of -hypothetical or -actual may be used.'; $header = self::cronMsgHeader(); for ($i = 1; $i < $argc; ++$i) { switch ($argv[$i]) { case '-hypothetical': if ($boolActuallyUpdateDatabase !== null) { echo "$errorString\n\n$header\n$usageMessage"; exit(0); } echo "\n$header\n"; $boolActuallyUpdateDatabase = false; break; case '-actual': if ($boolActuallyUpdateDatabase !== null) { echo "$errorString\n\n$header\n$usageMessage"; exit(0); } echo "\n$header\n"; $boolActuallyUpdateDatabase = true; break; case '-verbose': if ($argc < 3) { echo "$errorString\n\n$header\n$usageMessage"; exit(0); } echo "\n$header\n"; $boolVerboseOutput = true; break; default: echo "Incorrect argument '{$argv[1]}'.\n$usageMessage"; exit(0); } } return array($boolActuallyUpdateDatabase, $boolVerboseOutput); }
/** * Create a header usageMessage * @return string */ public static function cronMsgHeader() { $usageMessage = <<<STRHEADR ****************************************************************************** * * * MM MM YY YY CCCCCCC RRRRR OOOOOOO NN N * * M M M M YY YY C R R O O N N N * * M M M M Y Y C R R O O N N N * * M M M Y C RRRRR O O N N N * * M M Y C R R O O N N N * * M M Y C R R O O N N N * * M M Y CCCCCCC R R OOOOOOO N NN * * M M Y * ****************************************************************************** STRHEADR; return $usageMessage; }
/** * Echo's a disclaimer to the end user if running in hypothetical mode * @param $boolActuallyUpdateDatabase * @return void */ public static function runInHypotheticalMode($boolActuallyUpdateDatabase) { if (!$boolActuallyUpdateDatabase) { echo "\nNote Regarding Hypothetical Mode\n"; echo "--------------------------------\n"; echo 'The script is running in hypothetical mode. All database changes referred to'; echo ' in the output below will be rolled back before the script completes. The changes'; echo " will also be rolled back should the script be interrupted part way through.\n"; } }
So that’s all for now, in the next instalment I’ll show you how to implement these features into your code that will run the cron file via command line.
The entire cron class should now look like this.
<?php /** * This class is to define a common library file to include to help with common cron scripting tasks. */ class my_cron { // No cloning or instantiating allowed. final private function __construct() { // } final private function __clone() { // } /** * Handles the command line arguments and makes sure they contain valid parameters * * @param $usageMessage * * @return array */ public static function validateArgvArgumentsAndDieWithErrorMessageIfInvalid($usageMessage) { // Declare PHP Super globals // http://www.php.net/manual/en/reserved.variables.php global $argv; //Array of CLI arguments global $argc; //Count of CLI arguments $header = self::cronMsgHeader(); switch ($argc) { case 1: echo "$header\n$usageMessage"; exit(0); case 2: // Fall through. case 3: // Expected number of arguments. Do nothing here, but proceed to next step. break; default: echo "Incorrect number of arguments.\n$header\n$usageMessage"; exit(0); } $boolActuallyUpdateDatabase = null; $boolVerboseOutput = FALSE; $errorString = 'Only one option of -hypothetical or -actual may be used.'; $header = self::cronMsgHeader(); for ($i = 1; $i < $argc; ++$i) { switch ($argv[$i]) { case '-hypothetical': if ($boolActuallyUpdateDatabase !== null) { echo "$errorString\n\n$header\n$usageMessage"; exit(0); } echo "\n$header\n"; $boolActuallyUpdateDatabase = FALSE; break; case '-actual': if ($boolActuallyUpdateDatabase !== null) { echo "$errorString\n\n$header\n$usageMessage"; exit(0); } echo "\n$header\n"; $boolActuallyUpdateDatabase = TRUE; break; case '-verbose': if ($argc < 3) { echo "$errorString\n\n$header\n$usageMessage"; exit(0); } echo "\n$header\n"; $boolVerboseOutput = TRUE; break; default: echo "Incorrect argument '{$argv[1]}'.\n$usageMessage"; exit(0); } } return array($boolActuallyUpdateDatabase, $boolVerboseOutput); } /** * Create a header usageMessage * * @return string */ public static function cronMsgHeader() { $usageMessage = <<<STRHEADR ****************************************************************************** * * * MM MM YY YY CCCCCCC RRRRR OOOOOOO NN N * * M M M M YY YY C R R O O N N N * * M M M M Y Y C R R O O N N N * * M M M Y C RRRRR O O N N N * * M M Y C R R O O N N N * * M M Y C R R O O N N N * * M M Y CCCCCCC R R OOOOOOO N NN * * M M Y * ****************************************************************************** STRHEADR; return $usageMessage; } /** * Echo's a disclaimer to the end user if running in hypothetical mode * * @param $boolActuallyUpdateDatabase * @return void */ public static function runInHypotheticalMode($boolActuallyUpdateDatabase) { if (!$boolActuallyUpdateDatabase) { echo "\nNote Regarding Hypothetical Mode\n"; echo "--------------------------------\n"; echo 'The script is running in hypothetical mode. All database changes referred to'; echo ' in the output below will be rolled back before the script completes. The changes'; echo " will also be rolled back should the script be interrupted part way through.\n"; } } }