Tuesday, November 30, 2021, 10:10 PM
PHP’s usefulness as a server-side web scripting language is impressive with regard to utility and versatility, but too many power users do not look beyond web applications. Much like C#, PHP can be a powerful and capable systems administration tool, in addition to just being a web scripting language.The first major advantage that PHP brings to the table in the realm of system administration is “almost true” platform independence. Unlike conventional system administration scripting tools, such as bash for Linux or batch files and Visual Basic scripts for Windows, PHP scripts can be easily ported from one operating system to the next without the need for significant amounts of re-coding. All that is needed is to maintain compatibility with the PHP interpreter and add in any required extensions.
How to Install PHP on Linux and Windows
It is almost too easy to say that “There’s no Step 1” with regards to using PHP for system administration tasks, but in most cases, if PHP is present as a web scripting language on a server, then command line capability already exists.
However, the lack of a web server daemon does not mean that PHP cannot be installed as a standalone package. If this is the case, then one must follow the operating system-specific process for installing PHP.
Installing PHP on Linux
Without getting into distribution-specific package management quirks, the only module that needs to be directly installed is php-cli. The “cli” stands for “Command Line Interface.”
Installing php-cli will install any and all needed dependencies for PHP, including the PHP engine itself.
Installing PHP on Windows
Typically, there is no PHP installer for Windows and even if IIS is installed, PHP is usually not included as part of a standard installation. The entire PHP package needs to be downloaded and manually copied into a separate directory, usually c:\php or something similar.
Once PHP is installed, the various extensions which are to be used would need to be enabled in the php.ini file.
PHP Programming Basics and Examples
Consider the following listing:
<?php
if (isset ($_GET))
print "There are [" . count($_GET) . "] parameters in _GET.\n";
if (isset ($_POST))
print "There are [" . count($_POST) . "] parameters in _POST.\n";
if (isset ($argc) && isset ($argv))
{
for ($x = 0; $x < $argc; $x++)
{
print "Parameter [" . $x . "] is [" . $argv[$x] . "]\n";
}
}
?>
Observe how each print statement requires an intentionally specified newline character. This script simply iterates through any command-line parameters which may be provided. The script is invoked using the following PHP syntax:
$ php test.php param1 param2
There are [0] parameters in _GET.
There are [0] parameters in _POST.
Parameter [0] is [test.php]
Parameter [1] is [param1]
Parameter [2] is [param2]
In general, PHP scripts do not work that much differently than their web-based counterparts. Both have input variables, but instead of HTML inputs provided via the GET or POST methods, command line PHP scripts would accept command line parameters using the provided $argc and $argv variables, which represent the argument count, including the filename of the script itself, and the values of those parameters, respectively.
Note that, as a best practice, especially if the goal is to use the same code in both a web-based and command line environment, is to check if any variable like $_GET, $_POST, $argc or $argv is populated and set before reading it.
Read: How to Manage Linux Users from the Terminal.
How to Backup Up MySQL Databases with PHP
The real strength in using PHP scripts for system administration is that it is possible to leverage all of the extendable functionality that PHP offers with other tools that may not be readily available in other shell scripting environments. For example, the only way a bash shell script or a Windows Batch file could interact with a MySQL (or really any) database would be to use piping and intermediate files to pass SQL statements into the MySQL command line tool. Results would then have to be redirected to an intermediate file and parsed out by the script. This is about as practical as using a wrench as a hammer. PHP, of course, provides all sorts of rich, robust and more importantly (almost) built-in tools to work with many different kinds of databases and other technologies.
The scenario being explored here involves backing up all of the non-system MySQL databases to SQL dump files, and then compressing them. These files are only kept for 2 weeks with each file that ages out being deleted. PHP provides built-in support for all of these things.
Consider the code below, showing how to work with MySQL databases in PHP:
<?PHP
define ("DB_TYPE", "MYSQLI");
define ("DB_HOST", "localhost");
define ("DB_NAME", "mysql");
define ("DB_USER", "nonadmin_readonly");
define ("DB_PASS", "XXXXXX");
// Get the database list.
$commands = array();
$conn = "";
if ($conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME))
{
$x = 0;
$sql0 = "show databases;";
$rs0 = $conn->query($sql0);
while ($row0 = $rs0->fetch_array(MYSQLI_BOTH))
{
$dbName = trim ($row0[0]);
// Exclude system dbs.
if ( ("mysql" != $dbName) && ("information_schema" != $dbName) &&
("test" != $dbName ) && ("performance_schema" != $dbName))
{
//print "Found [" . $dbName . "]\n";
$dateStr = date ("Y-m-d");
//print $dateStr . "\n";
$cmd = "/usr/bin/mysqldump --user=" . DB_USER. " --password="
. DB_PASS . " " . $dbName . " > /home/dba/database_backups/"
. $dateStr . "_" . $dbName . ".sql";
//print $cmd . "\n";
$commands[$x] = $cmd;
$x++;
$commands[$x] =
"/usr/bin/bzip2 --force /home/dba/database_backups/"
. $dateStr . "_" . $dbName . ".sql";
$x++;
}
}
$conn->close();
}
for ($x = 0; $x < count($commands); $x++)
{
print $commands[$x] . "\n";
if (1 == $x % 2)
print "\n";
//system ($item);
}
// DELETION CODE GOES HERE.
?>
Using some relatively simple native PHP commands it is possible to generate timestamped backup filenames, along with the system commands needed to perform MySQL database dumps, as well as to compress the files generated. This example runs on Linux and assumes that the user’s home directory is /home/dba, but can easily be adapted to Windows as the syntax for the MySQL tools is the same as in Linux, and a Windows-specific compression tool can be substituted for bzip2.
This PHP code example generates the following output:
$ php backup_databases_native.php
/usr/bin/mysqldump --user=nonadmin_readonly --password=XXXXXX wordpress_db1 > ↩︎ /home/dba/database_backups/2021-10-21_wordpress_db1.sql
/usr/bin/bzip2 --force /home/dba/database_backups/2021-10-21_wordpress_db1.sql
/usr/bin/mysqldump --user=nonadmin_readonly --password=XXXXXX wordpress_db2_blog > ↩︎ /home/dba/database_backups/2021-10-21_wordpress_db2.sql
/usr/bin/bzip2 --force /home/dba/database_backups/2021-10-21_wordpress_db2.sql
/usr/bin/mysqldump --user=nonadmin_readonly --password=XXXXXX app_db > ↩︎ /home/dba/database_backups/2021-10-21_app_db.sql
/usr/bin/bzip2 --force /home/dba/database_backups/2021-10-21_app_db.sql
/usr/bin/mysqldump --user=nonadmin_readonly --password=XXXXXX udc1_db > ↩︎ /home/dba/database_backups/2021-10-21_udc1_db.sql
/usr/bin/bzip2 --force /home/dba/database_backups/2021-10-21_udc1_db.sql
Note:↩︎ indicates that the command continues on the current line, but had to be broken up for spacing reason.
One best practice to observe is to use the full path to each external command that is being executed. The reason for this is that if this code is run within a Linux crontab or as a Windows Scheduled Task, then the system file path cannot be guaranteed. Using the full path ensures that no “command not found” errors occur. Likewise, the use of the full path to the target directory in the commands themselves ensures that files generated are stored in the intended directories.
To complete this code, the functionality to delete the old backup files needs to be added, as shown in the PHP code below:
<?PHP
// .. Previous listing code goes here.
// Delete files older than 2 weeks.
$dir = "/home/dba/database_backups";
$maxAge = 14 * 86400;
if ($dh = opendir ($dir))
{
$currentTime = time();
while (($file = readdir($dh)) !== false)
{
if (("." != $file) && (".." != $file))
{
$fullPath = $dir . "/" . $file;
$age = $currentTime - filemtime($fullPath);
echo "filename: " . $fullPath . " - Age is [" . $age
. "] seconds. Max age is [" . $maxAge . "] seconds.\n";
if ($age > $maxAge)
{
print "MUST DELETE [" . $fullPath . "]\n\n";
unlink ($fullPath);
}
else
print "Keep it.\n\n";
}
}
closedir ($dh);
}
?>
This code is not “anything special” in terms of what PHP can do. This listing is an adaptation of long-existing PHP functionality.
One “bonus” of the print statements in this code is that, if this code is executed within a crontab and the MAILTO option is set, the outputs of these statements will show up in the emails generated by the crontab when it runs.
Read: How to Manage Linux Groups Using Command Line.
PHP Database Backup Code for Sysadmins
This simple example of an existing PHP-driven database backup and cleanup process is the tip of the iceberg in terms of what PHP can do for a system administrator. The added upside of using PHP in such a manner is that the administrator who is already fluent in PHP does not have to learn an OS-specific scripting language, and even more importantly, “re-learn” it when the code has been long-forgotten and something ends up breaking in that language. This compounds the other major upsides of OS neutrality and portability of scripts between web and command line environments.