Saturday, May 28, 2011

File System Management with PHP

I blogged previously on using PHP on the command line, but I did not cover using PHP to access the file system in that post in the interest of blog post size. I use this post to cover some of the basics of PHP file system management.

Many of us who write and use scripts do so for functions related to the file system. We script actions we commonly perform in the file system. Specifically, we often find ourselves needing to copy files, rename files, remove files, and open and close files. We often need to perform certain logic based on certain characteristics of files and directories. It'd be difficult to seriously consider a language as a scripting language without decent file system support. Fortunately, PHP has built-in support for file system management. This support can be used in conjunction with command line PHP.

W3Schools.com is a proven valuable resource for learning about web technologies and their coverage of PHP Filesystem Functions is another example of that. The page reminds us that the PHP filesystem functions "are part of the PHP core" and "allow you to access and manipulate the filesystem." More importantly, this page also summarizes PHP file system configuration details, PHP file system functions, and PHP file system constants. Clicking on a function name leads to a page with more details on that function as well as a PHP code example using that function. Because I'll only cover a subset of these in this post, I wanted to make sure to reference this W3Schools page early.

The following script, demoPhpFileSystemManagement.php, demonstrates several of PHP's functions for determining file information. I list the whole script here and then reproduce portions of the script again as I discuss them.

demoPhpFileSystemManagement.php
#!/usr/bin/php
<?php
//
// demoPhpFileSystemManagement.php
//

do
{
   echo "\nWhich PHP File System Operation Do You Want To Run?\n\n";
   echo "1. Parse File Path Information\n";
   echo "2. Acquire an Absolute Path\n";
   echo "3. Get File Size\n";
   echo "4. Get Disk Size and Free Space\n";
   echo "5. Get File Times\n";
   echo "\nEnter 0 to Exit\n";
   echo "\n\nYour Choice: ";
   $selection = trim(fgets(STDIN));
}
while (!(   ($selection == "0") || ($selection == "1") || ($selection == "2")
         || ($selection == "3") || ($selection == "4") || ($selection == "5")));


switch ($selection)
{
   case "1":
      echo "Enter a file path: ";
      $filePath = trim(fgets(STDIN));
      $filePathInfo = parseFilePath($filePath);
      echo $filePathInfo;
      break;
   case "2":
      echo "Enter path: ";
      $filePath = trim(fgets(STDIN));
      $realPath = convertPathToAbsolute($filePath);
      echo $realPath;
      break;
   case "3":
      echo "Enter path and name of file: ";
      $filePath = trim(fgets(STDIN));
      $sizeOfFile = getSizeOfFile($filePath);
      echo "File ".$filePath." has a size of ".$sizeOfFile." bytes.";
      break;
   case "4":
      echo "Enter disk label: ";
      $diskLabel = trim(fgets(STDIN));
      $diskSpace = getDiskSizeAndFreeSpace($diskLabel);
      $percentageFree = $diskSpace[1] / $diskSpace[0];
      echo "Disk ".$diskLabel." has ".$diskSpace[1]." of ".$diskSpace[0]
          ." bytes free (".round($percentageFree*100)."%).";
      break;
   case "5":
      echo "Enter a file who access/changed/modified times are desired: ";
      $filePath = trim(fgets(STDIN));
      $fileTimes = getFileTimes($filePath);
      echo "File ".$filePath." was last accessed on ".$fileTimes[0]
          .", was last changed on ".$fileTimes[1]
          .", and was last modified on ".$fileTimes[2];
      break;
   case "0":
   default:
   echo "\n\n";
   exit();
}


/**
 * Parse the provided file path. Demonstrates the following PHP functions:
 *
 *  - basename() : Provides base portion of file path (file name).
 *  - dirname()  : Directory name portion of file path.
 *  - pathinfo() : All components of path (basename, directory name, extension).
 *
 * @param $filePath File path to be parsed.
 * @return File path information in a single String.
 */
function parseFilePath($filePath)
{
   echo "Parsing file path ...", $filePath, "\n";
   $fileBaseName = basename($filePath);
   $fileDirectoryName = dirname($filePath);
   $pathInfo = pathinfo($filePath);
   return "File Name: ".$fileBaseName."\nDirectory Name: ".$fileDirectoryName
         ."\nFileName: ".$pathInfo['basename']."\nDirectory Name: "
         .$pathInfo['dirname']."\nFile Extension: ".$pathInfo['extension']
         ."\nFile name without extension: ".$pathInfo['filename'];
}


/**
 * Convert the provided path to an absolute path.
 *
 * @param $filePath File path to be made absolute.
 * @return Absolute version of provided file path.
 */
function convertPathToAbsolute($filePath)
{
   echo "Converting file path ", $filePath, " to absolute path...\n";
   return realpath($filePath);
}


/**
 * Determine size of provided file.
 *
 * @param? $filePath Path and name of file whose size is needed.
 * @return Size of file indicated by provided file path and name (in bytes).
 */
function getSizeOfFile($filePath)
{
   echo "Getting size of file ", $filePath, "...\n";
   return filesize($filePath);
}


/**
 * Provide disk size and free space on disk for provided disk.
 *
 * @param $diskLabel Label of disk whose total size and free space are to be
 *    provided.
 * @return Array of two elements, first of which is total disk space (in bytes)
 *    and second of which is free disk space (in bytes).
 */
function getDiskSizeAndFreeSpace($diskLabel)
{
   return array(disk_total_space($diskLabel), disk_free_space($diskLabel));
}


/**
 * Provide access, changed, and modified times for given file path.
 *
 * @param filePath Path and name of file whose times are desired.
 * @return Array of three elements with first being the file's access time,
 *    second being the file's changed time, and third being the file's modified
 *    time.
 */
function getFileTimes($filePath)
{
   $dateTimeFormat = "d-m-y g:i:sa";
   $fileAccessTime = fileatime($filePath);
   $fileChangedTime = filectime($filePath);
   $fileModifiedTime = filemtime($filePath);
   return array(date($dateTimeFormat, $fileAccessTime),
                date($dateTimeFormat, $fileChangedTime),
                date($dateTimeFormat, $fileModifiedTime));
}
?>

Before going into more detailed coverage of the PHP file system functions used in the above example, I have observed my Java background in that PHP code. For example, I used Javadoc-style comments for the functions in the code. Fortunately, PHPDocumentor respects Javadoc-style comments when generating code documentation. The above code also demonstrates the difference of naming conventions I'm accustomed to in Java (camel case) and the naming conventions of PHP (all lowercase names with words separated by underscores) as shown by the PHP functions invoked.

The first part of the PHP script provides a simple text command-line menu that prompts the user to enter choices and file names and paths. This snippet of code does not do anything itself with the PHP file system functions, but it does demonstrate PHP standard input and output and the PHP switch statement. That first portion is reproduced here.

Command Line Menu and Input Processing
do
{
   echo "\nWhich PHP File System Operation Do You Want To Run?\n\n";
   echo "1. Parse File Path Information\n";
   echo "2. Acquire an Absolute Path\n";
   echo "3. Get File Size\n";
   echo "4. Get Disk Size and Free Space\n";
   echo "5. Get File Times\n";
   echo "\nEnter 0 to Exit\n";
   echo "\n\nYour Choice: ";
   $selection = trim(fgets(STDIN));
}
while (!(   ($selection == "0") || ($selection == "1") || ($selection == "2")
         || ($selection == "3") || ($selection == "4") || ($selection == "5")));


switch ($selection)
{
   case "1":
      echo "Enter a file path: ";
      $filePath = trim(fgets(STDIN));
      $filePathInfo = parseFilePath($filePath);
      echo $filePathInfo;
      break;
   case "2":
      echo "Enter path: ";
      $filePath = trim(fgets(STDIN));
      $realPath = convertPathToAbsolute($filePath);
      echo $realPath;
      break;
   case "3":
      echo "Enter path and name of file: ";
      $filePath = trim(fgets(STDIN));
      $sizeOfFile = getSizeOfFile($filePath);
      echo "File ".$filePath." has a size of ".$sizeOfFile." bytes.";
      break;
   case "4":
      echo "Enter disk label: ";
      $diskLabel = trim(fgets(STDIN));
      $diskSpace = getDiskSizeAndFreeSpace($diskLabel);
      $percentageFree = $diskSpace[1] / $diskSpace[0];
      echo "Disk ".$diskLabel." has ".$diskSpace[1]." of ".$diskSpace[0]
          ." bytes free (".round($percentageFree*100)."%).";
      break;
   case "5":
      echo "Enter a file who access/changed/modified times are desired: ";
      $filePath = trim(fgets(STDIN));
      $fileTimes = getFileTimes($filePath);
      echo "File ".$filePath." was last accessed on ".$fileTimes[0]
          .", was last changed on ".$fileTimes[1]
          .", and was last modified on ".$fileTimes[2];
      break;
   case "0":
   default:
   echo "\n\n";
   exit();
}

The remainder of the PHP script contains functions that use and demonstrate the PHP file system management functions.

PHP provides functions for easy access to file path details such as the directory of the file, the full name of the file itself, the file's extension, and the name of the file without extension. Some of these are demonstrated in the above example in the parseFilePath function, which is reproduced next. The function shows off PHP's basename, dirname, and pathinfo functions.

PHP Provides File Path Information
/**
 * Parse the provided file path. Demonstrates the following PHP functions:
 *
 *  - basename() : Provides base portion of file path (file name).
 *  - dirname()  : Directory name portion of file path.
 *  - pathinfo() : All components of path (basename, directory name, extension).
 *
 * @param $filePath File path to be parsed.
 * @return File path information in a single String.
 */
function parseFilePath($filePath)
{
   echo "Parsing file path ...", $filePath, "\n";
   $fileBaseName = basename($filePath);
   $fileDirectoryName = dirname($filePath);
   $pathInfo = pathinfo($filePath);
   return "File Name: ".$fileBaseName."\nDirectory Name: ".$fileDirectoryName
         ."\nFileName: ".$pathInfo['basename']."\nDirectory Name: "
         .$pathInfo['dirname']."\nFile Extension: ".$pathInfo['extension']
         ."\nFile name without extension: ".$pathInfo['filename'];
}

The output from running the above against an example file is now shown.



PHP provide a useful realpath function that provides an absolute version of a provided path. For example, it will resolve soft links and relative directories to return the absolute path. This is demonstrated in the convertPathToAbsolute function in my example (and reproduced in the next code listing).

Demonstrating Absolute Paths via realpath
/**
 * Convert the provided path to an absolute path.
 *
 * @param $filePath File path to be made absolute.
 * @return Absolute version of provided file path.
 */
function convertPathToAbsolute($filePath)
{
   echo "Converting file path ", $filePath, " to absolute path...\n";
   return realpath($filePath);
}

The above portion of the script produces the following output.



PHP makes it easy to determine the size of a file with the aptly named filesize function. My getSizeOfFile function demonstrates this and is listed on its own in the next code listing.

Getting File Size in PHP
/**
 * Determine size of provided file.
 *
 * @param? $filePath Path and name of file whose size is needed.
 * @return Size of file indicated by provided file path and name (in bytes).
 */
function getSizeOfFile($filePath)
{
   echo "Getting size of file ", $filePath, "...\n";
   return filesize($filePath);
}

The code leads to the output shown in the next image.


PHP also makes it easy to get disk space information. PHP's disk_total_space and disk_free_space functions are demonstrated in the code listing below for my getDiskSizeAndFreeSpace function.

PHP Disk Size and Free Space
/**
 * Provide disk size and free space on disk for provided disk.
 *
 * @param $diskLabel Label of disk whose total size and free space are to be
 *    provided.
 * @return Array of two elements, first of which is total disk space (in bytes)
 *    and second of which is free disk space (in bytes).
 */
function getDiskSizeAndFreeSpace($diskLabel)
{
   return array(disk_total_space($diskLabel), disk_free_space($diskLabel));
}

The above example is not only demonstrates PHP's disk_total_space and disk_free_space functions, but it also demonstrates using PHP's array function to create an array and place elements within the array in a single statement.

The output of this portion of the script is shown next.


The final function in my script is getFileTimes and its purpose is to demonstrate three PHP methods for accessing dates/times associated with files. Specifically, the fileatime, filectime, and filemtime functions are demonstrated.

PHP File Times
/**
 * Provide access, changed, and modified times for given file path.
 *
 * @param filePath Path and name of file whose times are desired.
 * @return Array of three elements with first being the file's access time,
 *    second being the file's changed time, and third being the file's modified
 *    time.
 */
function getFileTimes($filePath)
{
   $dateTimeFormat = "d-m-y g:i:sa";
   $fileAccessTime = fileatime($filePath);
   $fileChangedTime = filectime($filePath);
   $fileModifiedTime = filemtime($filePath);
   return array(date($dateTimeFormat, $fileAccessTime),
                date($dateTimeFormat, $fileChangedTime),
                date($dateTimeFormat, $fileModifiedTime));
}

The above code demonstrates the three methods fileatime, filectime, and filemtime. One of my first questions when running across these methods was, "What is the difference between 'changed time' and 'modified time'?" The answer is available in the PHP Manual which differentiate filemtime returning the last time the contents of the file were changed versus filectime which returns the "inode change time" of the file.

The output from running the above piece of the script is shown next.



Conclusion

PHP provides an impressive set of built-in functions for determining information about files, directories, and the file system in general. These functions can be very important in different types of scripts.

No comments: