Join files together into a single file and expand out

Again as with the previous post (simple calculator) this was another question to answer, which was fun to do.

“Write a class containing 2 functions. One function to merge 2 or more images into a single binary file. Write a counterpart function to this,which can extract the original files from the single binary, and write them out as single images, using their original filenames. Compression is not necessary, as the exercise is only designed to show an
understanding of using binary files with PHP, filesystem error handling, and planning a simple file format.”

Since we needed to have a simply file structure, so I decided to have a file structure of

Filename: <filename>
Size: <size in bytes>
<data>

where the filename, size in bytes and data (of the file itself) is filled in when the program runs.

So to start with I created a directory structure to pick up files from within one directory and place into another

/images
/newimages

and placed some images into the images directory.

To scan within a directory there is a iterator within PHP called DirectoryIterator which will do what it says on the tin, it will give you files within a directory and since being a iterator you can use a foreach to go through each file. Here is the syntax for DirectoryIterator to loop with a foreach (the $fileDirectory is the directory to scan and the $fileDetails is the files that are within the directory.

foreach (new DirectoryIterator($fileDirectory) as $fileDetails)

So what happens is that the program will loop through each file in the directory and open the single to write to, whilst looping through directory output the Filename to the single file and the Filesize, then read the actual file into a object to write to the single file within a binary format, and loop until no more files in that directory.

Then to un-single the file, I read the single file and find out the filename and filesize, open a file to write to in the new directory and read from the single file bits with the size of the filesize information from the single file, this was the actual file data, place this file data into the new file within the new directory. (kinder how tar works, builds all files into a single file from a directory and then expand then afterwards).

Here is the full code, it is small enough to hopefully follow.

<?php
  class imageBuilder 
  {
    /* read files into one file */
    /* file format 
      Filename: <filename>
      Size: <size in bytes>
      <data>
    */
    function readFiles($fileDirectory,$outputName)
    {
      $fHandle = fopen($outputName, "wb");
      if ($fHandle == false) throw new Exception("Error open file to write to");
      foreach (new DirectoryIterator($fileDirectory) as $fileDetails)
      {
	$filesize = filesize($fileDirectory."/".$fileDetails);
	if ($filesize > 0 && $fileDetails !="..")
	{
	  $rHandle = fopen($fileDirectory."/".$fileDetails, "rb");
	  if ($rHandle == false) throw new Exception("Error open file to read from");
	  $readInFile = fread($rHandle,$filesize);
	  if ($readInFile==false) throw new Exception("Error on reading file to read from");
	  fclose($rHandle);
	  if (fwrite($fHandle, "Filename: $fileDetails\n")==false) throw new Exception("Error writting data");
	  if (fwrite($fHandle, "Size : $filesize\n")==false) throw new Exception("Error writting data");
	  if (fwrite($fHandle,$readInFile)==false) throw new Exception("Error writting data");
	}
      }
      fclose($fHandle);
    }
 
    /* write files back out from the single file*/
    function writeFiles($fileDriectoryToWrite, $fileToReadFrom)
    {
      $rHandle = fopen($fileToReadFrom,"rb");
      if ($rHandle==false) throw new Exception("Error opening file to read");
      while (!feof($rHandle))
      {
	$filename = fgets($rHandle);
	$filename = trim(substr($filename, stripos($filename, ":")+1));
	if (strlen($filename) == 0) break;
	if ($filename == false) throw new Exception("Error reading the filename from file");
	$filesize = fgets($rHandle);
	if ($filesize ==false) throw new Exception("Error reading the filesize from the file");
	$filesize = trim(substr($filesize, stripos($filesize,":")+1));
	$readFileInfo = fread($rHandle, $filesize);
	if ($readFileInfo == false) throw new Exception("Error reading data from file to read from");
	$fHandle = fopen($fileDriectoryToWrite."/".$filename,"wb");
	if ($fHandle == false) throw new Exception("Error opening writing to file");
	if (fwrite($fHandle, $readFileInfo) == false) throw new Exception("Error writing to file");
	fclose($fHandle);
      }
      fclose($rHandle);
    }
  }
 
  $imageB = new imageBuilder();
  try {
    $imageB->readFiles("images","filetogether");
  }
  catch (Exception $ex)
  {
    echo "Error building the one file : $ex";
  }
 
  try {
    $imageB->writeFiles("newimages","filetogether");
  }
  catch (Exception $ex)
  {
    echo "Error writing files back out : $ex";
  }
 
?>

and you need to do is place some files within the /images directory and then run the program and it will create a single file called “filetogether” and also expand that file into the /newimages directory.

Leave a Reply

Your email address will not be published. Required fields are marked *