Skip to main content
Removed updated code and put original back on top
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

File Downloading-downloading, Unzippingunzipping and extracting Content -content with a PHP script and tests

EDIT. Here is the new version after bumperbox's very helpful suggestions.

I was thinking or renaming into Downloader or something but the problem is, I see downloading is performed at lower level of abstraction, followed by unzipping, then there are file opening and file handle caching, so I don't need to check for files again.

I want here a convenience method whom I tell "Gimme a row!" and he does all the work - downloading, unzipping, caching but it is not my problem anymore. Maybe DownloaderAndImporter but it looks too long for a class.

The echo statements are meant for logging - console here is only for me, no user interaction. Those messages are one time only - only once the file will be downloaded, only once cached, after that the cached handle will be used. So the idea was they wouldn't clatter the console.

I have removed the exception as I don't want to deal with them at higher level. I kept the "die" commands - they terminateam reading the process - if that happens we really have abook problemClean Code that I wouldn't know how to deal with beforehand. I wouldn't know what to do with exceptions here. Am I running against best practices here?

I got rid of getters - no need for them as I don't wantby Rob Martin and am trying to expose my private parts :)

And here iswrite the new cleaned up version - further critics most welcome!

  /** * File Downloading, Unzipping and extracting Content - PHP * * Usage: * * $fileImporter = new FileImporter($fileReference); * $nextRowAsArray = $fileImporter->readFileRowAsArray(); * * where $fileReference is File Name without Extension * $nextRowAsArray is associative Array representing File Entry * or empty array if number or entries does not match the header * * If $fileReference.zip is not found, it is downloaded using FILE_DOWNLOAD_PATH * The archiv $fileReference.zip is automatically extracted whenever needed, * and first archiv Entry $file.txt is taken * * The File $file.txt is expected of the form: * * field_name1|field_name2 * entry1_field1|entry1_field2 * entry2_field1|entry2_field2 * ... * entryN_field1|entryN_field2 * * Here FILE_ENTRY_SEPARATOR is '|' * * Then the returned arrays $nextRowAsArray are subsequently of the form: * * array( 'field_name1' => 'entry1_field1', 'field_name2' => 'entry1_field2', ) * array( 'field_name1' => 'entry2_field1', 'field_name2' => 'entry2_field2', ) * ... * array( 'field_name1' => 'entryN_field1', 'field_name2' => 'entryN_field2', ) */ class FileImporter { private $_fileReference; private $_downloadPath; private $_separator; private $_fileHandleCache = null; private $_fileHeadRow = array(); public function __construct ($fileReference, $downloadPath = FILE_DOWNLOAD_PATH, $separator = FILE_ENTRY_SEPARATOR) { $this->_fileReference = $fileReference; $this->_downloadPath = $downloadPath; $this->_separator = $separator; } public function readFileRowAsArray () { $this->_cacheFileHandle(); $fileEntryArray = $this->_getNextRowAsArray(); if ( $this->_fileHeadRow ) { $keys = $this->_fileHeadRow; $values = $fileEntryArray; } else { $this->_fileHeadRow = $fileEntryArray; $keys = $fileEntryArray; $values = $this->_getNextRowAsArray(); } if ( sizeof($keys) !== sizeof($values) ) return array(); return array_combine($keys, $values); } private function _cacheFileHandle () { if ( !$this->_fileHandleCache ) { $fileHandle = $this->_getNewFileHandle(); $this->_fileHandleCache = $fileHandle; } } private function _getNextRowAsArray () { $fileHandle = $this->_fileHandleCache; $fileNextLine = fgets($fileHandle); $fileNextLineTrimmed = trim($fileNextLine); return explode($this->_separator, $fileNextLineTrimmed); } private function _getNewFileHandle () { $zipFileName = $this->_getZipFileName(); if (!file_exists($zipFileName)) $this->_downloadFile($zipFileName); return $this->_unzipGetFileHandle($zipFileName); } private function _getZipFileName () { return "{$this->_fileReference}.zip"; } private function _downloadFile ($fileName) { echo "\n Downloading $fileName\n"; $sourceStream = fopen($this->_downloadPath . $fileName, 'r') or die("Could not download $fileName"); $destinationStream = fopen($fileName, 'w'); stream_copy_to_stream($sourceStream, $destinationStream); } private function _unzipGetFileHandle ($zipFileName) { $firstZipEntryName = $this->_getFirstZipEntryName($zipFileName); if ( !file_exists($firstZipEntryName) ) $this->_ZipExtract($zipFileName); $fileHandle = fopen($firstZipEntryName, "rt") or die("Can't Read File $firstZipEntryName"); return $fileHandle; } private function _getFirstZipEntryName ($zipFileName) { $zipArchiv = zip_open($zipFileName); $firstZipEntry = zip_read($zipArchiv); $firstZipEntryName = zip_entry_name($firstZipEntry); zip_close($zipArchiv); return $firstZipEntryName; } private function _zipExtract ($zipFileName) { echo "\n Begin extraction at ", date('r').", file $zipFileName"; $zipArchiv = new ZipArchive; $zipArchiv->open($zipFileName); $zipArchiv->extractTo("."); $zipArchiv->close(); } }  

And here are my tests, all passed :)cleanest possible code.

  /** * Testing FileImporter */ // case 0: both Zip and Text files exist - creating function createTextAndZipFiles ($fileRef, $textData) { $textFile = $fileRef . '.txt'; $zipFile = $fileRef . '.zip'; // creating text file file_put_contents($textFile, $textData); // creating zip file $zip = new ZipArchive; $zip->open($zipFile, ZipArchive::CREATE); $zip->addFile($textFile); $zip->close(); } $testFile = 'file-test'; $testText = readFileRowAsArray(); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); // empty row $testText = readFileRowAsArray(); assert( $rowArray['day'] === '10' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); // too long row $testText = readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); // too short row $testText = readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); // case 1: Zip exists but Text doesn't createTextAndZipFiles($testFile, $testText); // delete Text unlink($testFile . '.txt'); $importer_test = new FileImporter($testFile); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); // case 2: Text exists but Zip doesn't // faking download by using local subdirectory // creating subdirectory 'test' $subdirName = 'test'; // make sure directory exists and is not a file if ( file_exists($subdirName) ) { if ( !is_dir($subdirName) ) { unlink($subdirName); mkdir($subdirName); } } else { mkdir($subdirName); } createTextAndZipFiles($testFile, $testText); // now move zipfile into the subdirectory $zipFileName = $testFile . '.zip'; rename($zipFileName, $subdirName . '/' . $zipFileName); $importer_test = new FileImporter($testFile, $subdirName . '/'); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' );  

Below is the old question

I wrote this script as part of my project. Could you please criticise it and let me know how it could be improved?

I am reading the book by Rob Martin "Clean Code" and trying to write the cleanest possible code.

/** * File Downloading, Unzipping and extracting Content - PHP * * Usage: * * $fileImporter = new FileImporter($fileReference); * $nextRowAsArray = $fileImporter->readFileRowAsArray(); * * where $fileReference is File Name without Extension * $nextRowAsArray is associative Array representing File Entry * * If $fileReference.zip is not found, it is downloaded using FILE_DOWNLOAD_PATH * The archiv $fileReference.zip is automatically extracted whenever needed, * and first archiv Entry $file.txt is taken * * The File $file.txt is expected of the form: * * field_name1|field_name2 * entry1_field1|entry1_field2 * entry2_field1|entry2_field2 * ... * entryN_field1|entryN_field2 * * Here FILE_ENTRY_SEPARATOR is '|' * * Then the returned arrays $nextRowAsArray are subsequently of the form: * * array( 'field_name1' => 'entry1_field1', 'field_name2' => 'entry1_field2', ) * array( 'field_name1' => 'entry2_field1', 'field_name2' => 'entry2_field2', ) * ... * array( 'field_name1' => 'entryN_field1', 'field_name2' => 'entryN_field2', ) */ class FileImporter { private $_download_path = FILE_DOWNLOAD_PATH; private $_separator = FILE_ENTRY_SEPARATOR; private $_fileReference; private $_fileHandleCache = null; private $_fileHeadRow = array(); public function __construct ($fileReference) { $this->_fileReference = $fileReference; } public function readFileRowAsArray () { $fileHandle = $this->_getCachedOrNewFileHandle(); $fileEntryArray = $this->_getNextRowAsArray($fileHandle); if ( $this->_fileHeadRow ) { $keys = $this->_fileHeadRow; $values = $fileEntryArray; } else { $this->_fileHeadRow = $fileEntryArray; $keys = $fileEntryArray; $values = $this->_getNextRowAsArray($fileHandle); } return array_combine($keys, $values); } private function _getCachedOrNewFileHandle () { return $this->_fileHandleCache ? $this->_getCachedFileHandle() : $this->_getNewFileHandle(); } private function _getNextRowAsArray ($fileHandle) { $fileNextLine = fgets($fileHandle); if ( feof($fileHandle) ) return array(); $fileNextLineTrimmed = trim($fileNextLine); return explode($this->_separator, $fileNextLineTrimmed); } private function _getCachedFileHandle () { return $this->_fileHandleCache; } private function _getNewFileHandle () { $zipFileName = $this->_getZipFileName(); if (!file_exists($zipFileName)) $this->_downloadFile($zipFileName); return $this->_unzipAndGetFileHandle($zipFileName); } private function _getZipFileName () { // return "{$this->_fileReference . '.zip'; return "{$this->_fileReference}.zip"; } private function _downloadFile ($fileName) { $sourceStream = fopen($this->_downloadPath . $fileName, 'r') or die("Could not download $fileName"); $destinationStream = fopen($fileName, 'w'); echo "\n Downloading $fileName\n"; stream_copy_to_stream($sourceStream, $destinationStream); } private function _unzipAndGetFileHandle ($zipFileName) { $firstZipEntryName = $this->_getFirstZipEntryName($zipFileName); if ( !file_exists($firstZipEntryName) ) $this->_ZipExtract($zipFileName); $fileHandle = fopen($firstZipEntryName, "rt") or die(" Can't Read File $firstZipEntryName"); $this->_fileHandleCache = $fileHandle; return $fileHandle; } private function _getFirstZipEntryName ($zipFileName) { if ( !file_exists($zipFileName) ) { throw new Exception("Attempting to read non-existing Zip File $zipFileName, exitting ...."); } $zipArchiv = zip_open($zipFileName); $firstZipEntry = zip_read($zipArchiv); $firstZipEntryName = zip_entry_name($firstZipEntry); zip_close($zipArchiv); return $firstZipEntryName; } private function _zipExtract ($zipFileName) { echo "\n Begin extraction at ", date('r').", file $zipFileName"; $zipArchiv = new ZipArchive; $zipArchiv->open($zipFileName); $zipArchiv->extractTo("."); $zipArchiv->close(); } } 

I wrote this script as part ofHere are my project. Could you please criticise it and let me know how it could be improvedtests, which have all passed:

  /** * File Downloading, Unzipping and extracting Content -Testing PHPFileImporter * / // *case Usage0: *  * $fileImporter =both newZip FileImporter($fileReference); and *Text $nextRowAsArrayfiles =exist $fileImporter->readFileRowAsArray(); * * where $fileReference is File Name without Extensioncreating  * $nextRowAsArray is associative Array representing File Entry  * * If $fileReference.zip isfunction notcreateTextAndZipFiles found($fileRef, it is downloaded using$textData) FILE_DOWNLOAD_PATH{ * The archiv $fileReference.zip is$textFile automatically= extracted$fileRef whenever. needed,'.txt'; * and first$zipFile archiv= Entry$fileRef $file.txt is taken * * The File $file'.txt is expected of the form: * zip'; * field_name1|field_name2  *// entry1_field1|entry1_field2 creating *text entry2_field1|entry2_field2file  * ...  * entryN_field1|entryN_field2 file_put_contents($textFile, *$textData);  * Here FILE_ENTRY_SEPARATOR is// '|' creating *zip file  * Then the returned arrays $nextRowAsArray are subsequently$zip of= thenew form:ZipArchive; *  * array$zip->open( 'field_name1' => 'entry1_field1', 'field_name2' => 'entry1_field2'$zipFile, ZipArchive::CREATE); * array( 'field_name1' => 'entry2_field1', 'field_name2' => 'entry2_field2', $zip->addFile($textFile); * ... * array$zip->close( 'field_name1' => 'entryN_field1', 'field_name2' => 'entryN_field2', );  */} class FileImporter {  private $_download_path$testFile = FILE_DOWNLOAD_PATH;'file-test';  private $_separator$testText = FILE_ENTRY_SEPARATOR;<<<EOT  private $_fileReference;day|year  10|2011  private $_fileHandleCache = null;31|1843  private $_fileHeadRow = array();EOT;    public function __construct createTextAndZipFiles($fileReference)$testFile, {$testText);  $this->_fileReference$importer_test = $fileReference; } public function readFileRowAsArraynew FileImporter($testFile) {;  $fileHandle$rowArray = $this$importer_test->_getCachedOrNewFileHandle>readFileRowAsArray();  $fileEntryArray$rowArray = $this$importer_test->_getNextRowAsArray>readFileRowAsArray($fileHandle);   assert( if$rowArray['year'] (=== $this->_fileHeadRow'1843' ) {;  $keys = $this->_fileHeadRow;  // empty $valuesrow $testText = $fileEntryArray;<<<EOT  } else {day|year  $this->_fileHeadRow = $fileEntryArray;10|2011  $keys = $fileEntryArray;31|1843  $values = $this->_getNextRowAsArray($fileHandle);  }EOT;  return array_combine createTextAndZipFiles($keys$testFile, $values$testText); }   private$importer_test function= _getCachedOrNewFileHandlenew FileImporter($testFile) {;  return $this->_fileHandleCache ? $this->_getCachedFileHandle() :$rowArray = $this$importer_test->_getNewFileHandle>readFileRowAsArray(); }   assert( private$rowArray['day'] function=== _getNextRowAsArray'10' ($fileHandle) {;  $fileNextLine$rowArray = fgets$importer_test->readFileRowAsArray($fileHandle);  if assert( feof($fileHandle)$rowArray['year'] )=== return'1843' array();   $fileNextLineTrimmed$rowArray = trim$importer_test->readFileRowAsArray($fileNextLine);  assert( $rowArray return=== explodearray($this->_separator,) $fileNextLineTrimmed); }  private function// _getCachedFileHandletoo ()long {row  $testText return= $this->_fileHandleCache;<<<EOT  }day|year  10|2011|ha  31|1843 EOT; createTextAndZipFiles($testFile, private$testText); $importer_test function= _getNewFileHandlenew FileImporter($testFile) {;  $zipFileName$rowArray = $this$importer_test->_getZipFileName>readFileRowAsArray();  assert( $rowArray if=== (!file_existsarray($zipFileName)) $this->_downloadFile($zipFileName);   $rowArray return= $this$importer_test->_unzipAndGetFileHandle>readFileRowAsArray($zipFileName);  assert( $rowArray['year'] === '1843' );  $rowArray = } $importer_test->readFileRowAsArray();  privateassert( function$rowArray _getZipFileName=== array() {);  //  return "{$this->_fileReferencetoo .short '.zip';row  $testText return= "{$this->_fileReference}.zip";<<<EOT  }day|year 2011  31|1843 EOT; createTextAndZipFiles($testFile, private$testText); $importer_test function= _downloadFilenew FileImporter($fileName$testFile) {;  $sourceStream$rowArray = fopen($this$importer_test->_downloadPath . $fileName, 'r'>readFileRowAsArray(); assert( $rowArray or=== diearray("Could not download) $fileName"); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' $destinationStream); $rowArray = fopen$importer_test->readFileRowAsArray($fileName, 'w');  assert( echo$rowArray "\n=== Downloadingarray() $fileName\n";);  // case 1: Zip exists but stream_copy_to_streamText doesn't createTextAndZipFiles($sourceStream$testFile, $destinationStream$testText);  // delete } Text  unlink($testFile . private'.txt'); $importer_test function= _unzipAndGetFileHandlenew FileImporter($zipFileName$testFile) {;  $firstZipEntryName$rowArray = $this$importer_test->_getFirstZipEntryName>readFileRowAsArray($zipFileName);  assert( if$rowArray (=== !file_existsarray($firstZipEntryName) ); $rowArray $this= $importer_test->_ZipExtract>readFileRowAsArray($zipFileName);  assert( $rowArray['year'] === '1843' $fileHandle); $rowArray = fopen$importer_test->readFileRowAsArray($firstZipEntryName, "rt") or die; assert(" Can't$rowArray Read=== Filearray() $firstZipEntryName");   // case 2: Text exists $this->_fileHandleCachebut =Zip $fileHandle;doesn't  // faking download by using returnlocal $fileHandle;subdirectory // creating subdirectory } 'test'  $subdirName private= function'test'; // _getFirstZipEntryNamemake ($zipFileName)sure { directory exists and is not a file if ( !file_exists($zipFileName$subdirName) ) {   throw newif Exception("Attempting to read non-existing Zip File $zipFileName, exitting ...."!is_dir($subdirName);  ) }{   $zipArchiv = zip_openunlink($zipFileName$subdirName);   $firstZipEntry = zip_readmkdir($zipArchiv$subdirName);   $firstZipEntryName = zip_entry_name($firstZipEntry);}  } else {  zip_closemkdir($zipArchiv$subdirName);  return $firstZipEntryName; }  private function _zipExtract createTextAndZipFiles($zipFileName) { echo "\n Begin extraction at "$testFile, date('r'$testText).", file $zipFileName";; // now move zipfile into the $zipArchivsubdirectory $zipFileName = new$testFile ZipArchive; . '.zip'; rename($zipFileName, $subdirName . '/' . $zipArchiv->open($zipFileName); $importer_test = new FileImporter($testFile, $subdirName . '/');  $rowArray = $zipArchiv$importer_test->extractTo>readFileRowAsArray("."); assert( $rowArray === array() ); $rowArray = $zipArchiv$importer_test->close>readFileRowAsArray();  assert( $rowArray['year'] === } }'1843' ); 

File Downloading, Unzipping and extracting Content - PHP script and tests

EDIT. Here is the new version after bumperbox's very helpful suggestions.

I was thinking or renaming into Downloader or something but the problem is, I see downloading is performed at lower level of abstraction, followed by unzipping, then there are file opening and file handle caching, so I don't need to check for files again.

I want here a convenience method whom I tell "Gimme a row!" and he does all the work - downloading, unzipping, caching but it is not my problem anymore. Maybe DownloaderAndImporter but it looks too long for a class.

The echo statements are meant for logging - console here is only for me, no user interaction. Those messages are one time only - only once the file will be downloaded, only once cached, after that the cached handle will be used. So the idea was they wouldn't clatter the console.

I have removed the exception as I don't want to deal with them at higher level. I kept the "die" commands - they terminate the process - if that happens we really have a problem that I wouldn't know how to deal with beforehand. I wouldn't know what to do with exceptions here. Am I running against best practices here?

I got rid of getters - no need for them as I don't want to expose my private parts :)

And here is the new cleaned up version - further critics most welcome!

  /** * File Downloading, Unzipping and extracting Content - PHP * * Usage: * * $fileImporter = new FileImporter($fileReference); * $nextRowAsArray = $fileImporter->readFileRowAsArray(); * * where $fileReference is File Name without Extension * $nextRowAsArray is associative Array representing File Entry * or empty array if number or entries does not match the header * * If $fileReference.zip is not found, it is downloaded using FILE_DOWNLOAD_PATH * The archiv $fileReference.zip is automatically extracted whenever needed, * and first archiv Entry $file.txt is taken * * The File $file.txt is expected of the form: * * field_name1|field_name2 * entry1_field1|entry1_field2 * entry2_field1|entry2_field2 * ... * entryN_field1|entryN_field2 * * Here FILE_ENTRY_SEPARATOR is '|' * * Then the returned arrays $nextRowAsArray are subsequently of the form: * * array( 'field_name1' => 'entry1_field1', 'field_name2' => 'entry1_field2', ) * array( 'field_name1' => 'entry2_field1', 'field_name2' => 'entry2_field2', ) * ... * array( 'field_name1' => 'entryN_field1', 'field_name2' => 'entryN_field2', ) */ class FileImporter { private $_fileReference; private $_downloadPath; private $_separator; private $_fileHandleCache = null; private $_fileHeadRow = array(); public function __construct ($fileReference, $downloadPath = FILE_DOWNLOAD_PATH, $separator = FILE_ENTRY_SEPARATOR) { $this->_fileReference = $fileReference; $this->_downloadPath = $downloadPath; $this->_separator = $separator; } public function readFileRowAsArray () { $this->_cacheFileHandle(); $fileEntryArray = $this->_getNextRowAsArray(); if ( $this->_fileHeadRow ) { $keys = $this->_fileHeadRow; $values = $fileEntryArray; } else { $this->_fileHeadRow = $fileEntryArray; $keys = $fileEntryArray; $values = $this->_getNextRowAsArray(); } if ( sizeof($keys) !== sizeof($values) ) return array(); return array_combine($keys, $values); } private function _cacheFileHandle () { if ( !$this->_fileHandleCache ) { $fileHandle = $this->_getNewFileHandle(); $this->_fileHandleCache = $fileHandle; } } private function _getNextRowAsArray () { $fileHandle = $this->_fileHandleCache; $fileNextLine = fgets($fileHandle); $fileNextLineTrimmed = trim($fileNextLine); return explode($this->_separator, $fileNextLineTrimmed); } private function _getNewFileHandle () { $zipFileName = $this->_getZipFileName(); if (!file_exists($zipFileName)) $this->_downloadFile($zipFileName); return $this->_unzipGetFileHandle($zipFileName); } private function _getZipFileName () { return "{$this->_fileReference}.zip"; } private function _downloadFile ($fileName) { echo "\n Downloading $fileName\n"; $sourceStream = fopen($this->_downloadPath . $fileName, 'r') or die("Could not download $fileName"); $destinationStream = fopen($fileName, 'w'); stream_copy_to_stream($sourceStream, $destinationStream); } private function _unzipGetFileHandle ($zipFileName) { $firstZipEntryName = $this->_getFirstZipEntryName($zipFileName); if ( !file_exists($firstZipEntryName) ) $this->_ZipExtract($zipFileName); $fileHandle = fopen($firstZipEntryName, "rt") or die("Can't Read File $firstZipEntryName"); return $fileHandle; } private function _getFirstZipEntryName ($zipFileName) { $zipArchiv = zip_open($zipFileName); $firstZipEntry = zip_read($zipArchiv); $firstZipEntryName = zip_entry_name($firstZipEntry); zip_close($zipArchiv); return $firstZipEntryName; } private function _zipExtract ($zipFileName) { echo "\n Begin extraction at ", date('r').", file $zipFileName"; $zipArchiv = new ZipArchive; $zipArchiv->open($zipFileName); $zipArchiv->extractTo("."); $zipArchiv->close(); } }  

And here are my tests, all passed :)

  /** * Testing FileImporter */ // case 0: both Zip and Text files exist - creating function createTextAndZipFiles ($fileRef, $textData) { $textFile = $fileRef . '.txt'; $zipFile = $fileRef . '.zip'; // creating text file file_put_contents($textFile, $textData); // creating zip file $zip = new ZipArchive; $zip->open($zipFile, ZipArchive::CREATE); $zip->addFile($textFile); $zip->close(); } $testFile = 'file-test'; $testText = readFileRowAsArray(); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); // empty row $testText = readFileRowAsArray(); assert( $rowArray['day'] === '10' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); // too long row $testText = readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); // too short row $testText = readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); // case 1: Zip exists but Text doesn't createTextAndZipFiles($testFile, $testText); // delete Text unlink($testFile . '.txt'); $importer_test = new FileImporter($testFile); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); // case 2: Text exists but Zip doesn't // faking download by using local subdirectory // creating subdirectory 'test' $subdirName = 'test'; // make sure directory exists and is not a file if ( file_exists($subdirName) ) { if ( !is_dir($subdirName) ) { unlink($subdirName); mkdir($subdirName); } } else { mkdir($subdirName); } createTextAndZipFiles($testFile, $testText); // now move zipfile into the subdirectory $zipFileName = $testFile . '.zip'; rename($zipFileName, $subdirName . '/' . $zipFileName); $importer_test = new FileImporter($testFile, $subdirName . '/'); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' );  

Below is the old question

I am reading the book by Rob Martin "Clean Code" and trying to write the cleanest possible code.

I wrote this script as part of my project. Could you please criticise it and let me know how it could be improved:

  /** * File Downloading, Unzipping and extracting Content - PHP *  * Usage: *  * $fileImporter = new FileImporter($fileReference);  * $nextRowAsArray = $fileImporter->readFileRowAsArray(); * * where $fileReference is File Name without Extension  * $nextRowAsArray is associative Array representing File Entry  * * If $fileReference.zip is not found, it is downloaded using FILE_DOWNLOAD_PATH * The archiv $fileReference.zip is automatically extracted whenever needed, * and first archiv Entry $file.txt is taken * * The File $file.txt is expected of the form: *  * field_name1|field_name2  * entry1_field1|entry1_field2  * entry2_field1|entry2_field2  * ...  * entryN_field1|entryN_field2  *  * Here FILE_ENTRY_SEPARATOR is '|'  *  * Then the returned arrays $nextRowAsArray are subsequently of the form: *  * array( 'field_name1' => 'entry1_field1', 'field_name2' => 'entry1_field2', ) * array( 'field_name1' => 'entry2_field1', 'field_name2' => 'entry2_field2', ) * ... * array( 'field_name1' => 'entryN_field1', 'field_name2' => 'entryN_field2', )  */ class FileImporter {  private $_download_path = FILE_DOWNLOAD_PATH;  private $_separator = FILE_ENTRY_SEPARATOR;  private $_fileReference;    private $_fileHandleCache = null;  private $_fileHeadRow = array();    public function __construct ($fileReference) {  $this->_fileReference = $fileReference; } public function readFileRowAsArray () {  $fileHandle = $this->_getCachedOrNewFileHandle();  $fileEntryArray = $this->_getNextRowAsArray($fileHandle);    if ( $this->_fileHeadRow ) {  $keys = $this->_fileHeadRow;   $values = $fileEntryArray;  } else {  $this->_fileHeadRow = $fileEntryArray;  $keys = $fileEntryArray;  $values = $this->_getNextRowAsArray($fileHandle);  }  return array_combine($keys, $values); }   private function _getCachedOrNewFileHandle () {  return $this->_fileHandleCache ? $this->_getCachedFileHandle() : $this->_getNewFileHandle(); }    private function _getNextRowAsArray ($fileHandle) {  $fileNextLine = fgets($fileHandle);  if ( feof($fileHandle) ) return array();   $fileNextLineTrimmed = trim($fileNextLine);   return explode($this->_separator, $fileNextLineTrimmed); }  private function _getCachedFileHandle () {   return $this->_fileHandleCache;  }     private function _getNewFileHandle () {  $zipFileName = $this->_getZipFileName();   if (!file_exists($zipFileName)) $this->_downloadFile($zipFileName);    return $this->_unzipAndGetFileHandle($zipFileName);    }   private function _getZipFileName () { //  return "{$this->_fileReference . '.zip';   return "{$this->_fileReference}.zip";  }   private function _downloadFile ($fileName) {  $sourceStream = fopen($this->_downloadPath . $fileName, 'r') or die("Could not download $fileName"); $destinationStream = fopen($fileName, 'w');   echo "\n Downloading $fileName\n"; stream_copy_to_stream($sourceStream, $destinationStream);   }    private function _unzipAndGetFileHandle ($zipFileName) {  $firstZipEntryName = $this->_getFirstZipEntryName($zipFileName);   if ( !file_exists($firstZipEntryName) ) $this->_ZipExtract($zipFileName);   $fileHandle = fopen($firstZipEntryName, "rt") or die(" Can't Read File $firstZipEntryName");   $this->_fileHandleCache = $fileHandle;   return $fileHandle; }    private function _getFirstZipEntryName ($zipFileName) {  if ( !file_exists($zipFileName) ) {   throw new Exception("Attempting to read non-existing Zip File $zipFileName, exitting ....");  }   $zipArchiv = zip_open($zipFileName);   $firstZipEntry = zip_read($zipArchiv);   $firstZipEntryName = zip_entry_name($firstZipEntry);   zip_close($zipArchiv);  return $firstZipEntryName; }  private function _zipExtract ($zipFileName) { echo "\n Begin extraction at ", date('r').", file $zipFileName"; $zipArchiv = new ZipArchive;  $zipArchiv->open($zipFileName);   $zipArchiv->extractTo("."); $zipArchiv->close();  } } 

File-downloading, unzipping and extracting content with a PHP script and tests

I am reading the book Clean Code by Rob Martin and am trying to write the cleanest possible code.

I wrote this script as part of my project. Could you please criticise it and let me know how it could be improved?

/** * File Downloading, Unzipping and extracting Content - PHP * * Usage: * * $fileImporter = new FileImporter($fileReference); * $nextRowAsArray = $fileImporter->readFileRowAsArray(); * * where $fileReference is File Name without Extension * $nextRowAsArray is associative Array representing File Entry * * If $fileReference.zip is not found, it is downloaded using FILE_DOWNLOAD_PATH * The archiv $fileReference.zip is automatically extracted whenever needed, * and first archiv Entry $file.txt is taken * * The File $file.txt is expected of the form: * * field_name1|field_name2 * entry1_field1|entry1_field2 * entry2_field1|entry2_field2 * ... * entryN_field1|entryN_field2 * * Here FILE_ENTRY_SEPARATOR is '|' * * Then the returned arrays $nextRowAsArray are subsequently of the form: * * array( 'field_name1' => 'entry1_field1', 'field_name2' => 'entry1_field2', ) * array( 'field_name1' => 'entry2_field1', 'field_name2' => 'entry2_field2', ) * ... * array( 'field_name1' => 'entryN_field1', 'field_name2' => 'entryN_field2', ) */ class FileImporter { private $_download_path = FILE_DOWNLOAD_PATH; private $_separator = FILE_ENTRY_SEPARATOR; private $_fileReference; private $_fileHandleCache = null; private $_fileHeadRow = array(); public function __construct ($fileReference) { $this->_fileReference = $fileReference; } public function readFileRowAsArray () { $fileHandle = $this->_getCachedOrNewFileHandle(); $fileEntryArray = $this->_getNextRowAsArray($fileHandle); if ( $this->_fileHeadRow ) { $keys = $this->_fileHeadRow; $values = $fileEntryArray; } else { $this->_fileHeadRow = $fileEntryArray; $keys = $fileEntryArray; $values = $this->_getNextRowAsArray($fileHandle); } return array_combine($keys, $values); } private function _getCachedOrNewFileHandle () { return $this->_fileHandleCache ? $this->_getCachedFileHandle() : $this->_getNewFileHandle(); } private function _getNextRowAsArray ($fileHandle) { $fileNextLine = fgets($fileHandle); if ( feof($fileHandle) ) return array(); $fileNextLineTrimmed = trim($fileNextLine); return explode($this->_separator, $fileNextLineTrimmed); } private function _getCachedFileHandle () { return $this->_fileHandleCache; } private function _getNewFileHandle () { $zipFileName = $this->_getZipFileName(); if (!file_exists($zipFileName)) $this->_downloadFile($zipFileName); return $this->_unzipAndGetFileHandle($zipFileName); } private function _getZipFileName () { // return "{$this->_fileReference . '.zip'; return "{$this->_fileReference}.zip"; } private function _downloadFile ($fileName) { $sourceStream = fopen($this->_downloadPath . $fileName, 'r') or die("Could not download $fileName"); $destinationStream = fopen($fileName, 'w'); echo "\n Downloading $fileName\n"; stream_copy_to_stream($sourceStream, $destinationStream); } private function _unzipAndGetFileHandle ($zipFileName) { $firstZipEntryName = $this->_getFirstZipEntryName($zipFileName); if ( !file_exists($firstZipEntryName) ) $this->_ZipExtract($zipFileName); $fileHandle = fopen($firstZipEntryName, "rt") or die(" Can't Read File $firstZipEntryName"); $this->_fileHandleCache = $fileHandle; return $fileHandle; } private function _getFirstZipEntryName ($zipFileName) { if ( !file_exists($zipFileName) ) { throw new Exception("Attempting to read non-existing Zip File $zipFileName, exitting ...."); } $zipArchiv = zip_open($zipFileName); $firstZipEntry = zip_read($zipArchiv); $firstZipEntryName = zip_entry_name($firstZipEntry); zip_close($zipArchiv); return $firstZipEntryName; } private function _zipExtract ($zipFileName) { echo "\n Begin extraction at ", date('r').", file $zipFileName"; $zipArchiv = new ZipArchive; $zipArchiv->open($zipFileName); $zipArchiv->extractTo("."); $zipArchiv->close(); } } 

Here are my tests, which have all passed:

/** * Testing FileImporter */ // case 0: both Zip and Text files exist - creating function createTextAndZipFiles ($fileRef, $textData) { $textFile = $fileRef . '.txt'; $zipFile = $fileRef . '.zip'; // creating text file file_put_contents($textFile, $textData); // creating zip file $zip = new ZipArchive; $zip->open($zipFile, ZipArchive::CREATE); $zip->addFile($textFile); $zip->close(); } $testFile = 'file-test'; $testText = <<<EOT day|year 10|2011 31|1843 EOT; createTextAndZipFiles($testFile, $testText); $importer_test = new FileImporter($testFile); $rowArray = $importer_test->readFileRowAsArray(); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); // empty row $testText = <<<EOT day|year 10|2011 31|1843 EOT;  createTextAndZipFiles($testFile, $testText); $importer_test = new FileImporter($testFile); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['day'] === '10' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); // too long row $testText = <<<EOT day|year 10|2011|ha 31|1843 EOT; createTextAndZipFiles($testFile, $testText); $importer_test = new FileImporter($testFile); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() );  // too short row $testText = <<<EOT day|year 2011 31|1843 EOT; createTextAndZipFiles($testFile, $testText); $importer_test = new FileImporter($testFile); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() );  // case 1: Zip exists but Text doesn't createTextAndZipFiles($testFile, $testText); // delete Text unlink($testFile . '.txt'); $importer_test = new FileImporter($testFile); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() );  // case 2: Text exists but Zip doesn't // faking download by using local subdirectory // creating subdirectory 'test' $subdirName = 'test'; // make sure directory exists and is not a file if ( file_exists($subdirName) ) { if ( !is_dir($subdirName) ) { unlink($subdirName); mkdir($subdirName); } } else {  mkdir($subdirName); } createTextAndZipFiles($testFile, $testText); // now move zipfile into the subdirectory $zipFileName = $testFile . '.zip'; rename($zipFileName, $subdirName . '/' . $zipFileName); $importer_test = new FileImporter($testFile, $subdirName . '/'); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); 
added 3365 characters in body; edited title
Source Link
Dmitri Zaitsev
  • 1.3k
  • 1
  • 10
  • 26

File Downloading, Unzipping and extracting Content - PHP script and tests

And here are my tests, all passed :)

  /** * Testing FileImporter */ // case 0: both Zip and Text files exist - creating function createTextAndZipFiles ($fileRef, $textData) { $textFile = $fileRef . '.txt'; $zipFile = $fileRef . '.zip'; // creating text file file_put_contents($textFile, $textData); // creating zip file $zip = new ZipArchive; $zip->open($zipFile, ZipArchive::CREATE); $zip->addFile($textFile); $zip->close(); } $testFile = 'file-test'; $testText = readFileRowAsArray(); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); // empty row $testText = readFileRowAsArray(); assert( $rowArray['day'] === '10' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); // too long row $testText = readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); // too short row $testText = readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); // case 1: Zip exists but Text doesn't createTextAndZipFiles($testFile, $testText); // delete Text unlink($testFile . '.txt'); $importer_test = new FileImporter($testFile); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); // case 2: Text exists but Zip doesn't // faking download by using local subdirectory // creating subdirectory 'test' $subdirName = 'test'; // make sure directory exists and is not a file if ( file_exists($subdirName) ) { if ( !is_dir($subdirName) ) { unlink($subdirName); mkdir($subdirName); } } else { mkdir($subdirName); } createTextAndZipFiles($testFile, $testText); // now move zipfile into the subdirectory $zipFileName = $testFile . '.zip'; rename($zipFileName, $subdirName . '/' . $zipFileName); $importer_test = new FileImporter($testFile, $subdirName . '/'); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' );  

File Downloading, Unzipping and extracting Content - PHP script

File Downloading, Unzipping and extracting Content - PHP script and tests

And here are my tests, all passed :)

  /** * Testing FileImporter */ // case 0: both Zip and Text files exist - creating function createTextAndZipFiles ($fileRef, $textData) { $textFile = $fileRef . '.txt'; $zipFile = $fileRef . '.zip'; // creating text file file_put_contents($textFile, $textData); // creating zip file $zip = new ZipArchive; $zip->open($zipFile, ZipArchive::CREATE); $zip->addFile($textFile); $zip->close(); } $testFile = 'file-test'; $testText = readFileRowAsArray(); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); // empty row $testText = readFileRowAsArray(); assert( $rowArray['day'] === '10' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); // too long row $testText = readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); // too short row $testText = readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); // case 1: Zip exists but Text doesn't createTextAndZipFiles($testFile, $testText); // delete Text unlink($testFile . '.txt'); $importer_test = new FileImporter($testFile); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); // case 2: Text exists but Zip doesn't // faking download by using local subdirectory // creating subdirectory 'test' $subdirName = 'test'; // make sure directory exists and is not a file if ( file_exists($subdirName) ) { if ( !is_dir($subdirName) ) { unlink($subdirName); mkdir($subdirName); } } else { mkdir($subdirName); } createTextAndZipFiles($testFile, $testText); // now move zipfile into the subdirectory $zipFileName = $testFile . '.zip'; rename($zipFileName, $subdirName . '/' . $zipFileName); $importer_test = new FileImporter($testFile, $subdirName . '/'); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray === array() ); $rowArray = $importer_test->readFileRowAsArray(); assert( $rowArray['year'] === '1843' );  
added 5588 characters in body
Source Link
Dmitri Zaitsev
  • 1.3k
  • 1
  • 10
  • 26

EDIT. Here is the new version after bumperbox's very helpful suggestions.

I was thinking or renaming into Downloader or something but the problem is, I see downloading is performed at lower level of abstraction, followed by unzipping, then there are file opening and file handle caching, so I don't need to check for files again.

I want here a convenience method whom I tell "Gimme a row!" and he does all the work - downloading, unzipping, caching but it is not my problem anymore. Maybe DownloaderAndImporter but it looks too long for a class.

The echo statements are meant for logging - console here is only for me, no user interaction. Those messages are one time only - only once the file will be downloaded, only once cached, after that the cached handle will be used. So the idea was they wouldn't clatter the console.

I have removed the exception as I don't want to deal with them at higher level. I kept the "die" commands - they terminate the process - if that happens we really have a problem that I wouldn't know how to deal with beforehand. I wouldn't know what to do with exceptions here. Am I running against best practices here?

I got rid of getters - no need for them as I don't want to expose my private parts :)

And here is the new cleaned up version - further critics most welcome!

  /** * File Downloading, Unzipping and extracting Content - PHP * * Usage: * * $fileImporter = new FileImporter($fileReference); * $nextRowAsArray = $fileImporter->readFileRowAsArray(); * * where $fileReference is File Name without Extension * $nextRowAsArray is associative Array representing File Entry * or empty array if number or entries does not match the header * * If $fileReference.zip is not found, it is downloaded using FILE_DOWNLOAD_PATH * The archiv $fileReference.zip is automatically extracted whenever needed, * and first archiv Entry $file.txt is taken * * The File $file.txt is expected of the form: * * field_name1|field_name2 * entry1_field1|entry1_field2 * entry2_field1|entry2_field2 * ... * entryN_field1|entryN_field2 * * Here FILE_ENTRY_SEPARATOR is '|' * * Then the returned arrays $nextRowAsArray are subsequently of the form: * * array( 'field_name1' => 'entry1_field1', 'field_name2' => 'entry1_field2', ) * array( 'field_name1' => 'entry2_field1', 'field_name2' => 'entry2_field2', ) * ... * array( 'field_name1' => 'entryN_field1', 'field_name2' => 'entryN_field2', ) */ class FileImporter { private $_fileReference; private $_downloadPath; private $_separator; private $_fileHandleCache = null; private $_fileHeadRow = array(); public function __construct ($fileReference, $downloadPath = FILE_DOWNLOAD_PATH, $separator = FILE_ENTRY_SEPARATOR) { $this->_fileReference = $fileReference; $this->_downloadPath = $downloadPath; $this->_separator = $separator; } public function readFileRowAsArray () { $this->_cacheFileHandle(); $fileEntryArray = $this->_getNextRowAsArray(); if ( $this->_fileHeadRow ) { $keys = $this->_fileHeadRow; $values = $fileEntryArray; } else { $this->_fileHeadRow = $fileEntryArray; $keys = $fileEntryArray; $values = $this->_getNextRowAsArray(); } if ( sizeof($keys) !== sizeof($values) ) return array(); return array_combine($keys, $values); } private function _cacheFileHandle () { if ( !$this->_fileHandleCache ) { $fileHandle = $this->_getNewFileHandle(); $this->_fileHandleCache = $fileHandle; } } private function _getNextRowAsArray () { $fileHandle = $this->_fileHandleCache; $fileNextLine = fgets($fileHandle); $fileNextLineTrimmed = trim($fileNextLine); return explode($this->_separator, $fileNextLineTrimmed); } private function _getNewFileHandle () { $zipFileName = $this->_getZipFileName(); if (!file_exists($zipFileName)) $this->_downloadFile($zipFileName); return $this->_unzipGetFileHandle($zipFileName); } private function _getZipFileName () { return "{$this->_fileReference}.zip"; } private function _downloadFile ($fileName) { echo "\n Downloading $fileName\n"; $sourceStream = fopen($this->_downloadPath . $fileName, 'r') or die("Could not download $fileName"); $destinationStream = fopen($fileName, 'w'); stream_copy_to_stream($sourceStream, $destinationStream); } private function _unzipGetFileHandle ($zipFileName) { $firstZipEntryName = $this->_getFirstZipEntryName($zipFileName); if ( !file_exists($firstZipEntryName) ) $this->_ZipExtract($zipFileName); $fileHandle = fopen($firstZipEntryName, "rt") or die("Can't Read File $firstZipEntryName"); return $fileHandle; } private function _getFirstZipEntryName ($zipFileName) { $zipArchiv = zip_open($zipFileName); $firstZipEntry = zip_read($zipArchiv); $firstZipEntryName = zip_entry_name($firstZipEntry); zip_close($zipArchiv); return $firstZipEntryName; } private function _zipExtract ($zipFileName) { echo "\n Begin extraction at ", date('r').", file $zipFileName"; $zipArchiv = new ZipArchive; $zipArchiv->open($zipFileName); $zipArchiv->extractTo("."); $zipArchiv->close(); } }  

Below is the old question

EDIT. Here is the new version after bumperbox's very helpful suggestions.

I was thinking or renaming into Downloader or something but the problem is, I see downloading is performed at lower level of abstraction, followed by unzipping, then there are file opening and file handle caching, so I don't need to check for files again.

I want here a convenience method whom I tell "Gimme a row!" and he does all the work - downloading, unzipping, caching but it is not my problem anymore. Maybe DownloaderAndImporter but it looks too long for a class.

The echo statements are meant for logging - console here is only for me, no user interaction. Those messages are one time only - only once the file will be downloaded, only once cached, after that the cached handle will be used. So the idea was they wouldn't clatter the console.

I have removed the exception as I don't want to deal with them at higher level. I kept the "die" commands - they terminate the process - if that happens we really have a problem that I wouldn't know how to deal with beforehand. I wouldn't know what to do with exceptions here. Am I running against best practices here?

I got rid of getters - no need for them as I don't want to expose my private parts :)

And here is the new cleaned up version - further critics most welcome!

  /** * File Downloading, Unzipping and extracting Content - PHP * * Usage: * * $fileImporter = new FileImporter($fileReference); * $nextRowAsArray = $fileImporter->readFileRowAsArray(); * * where $fileReference is File Name without Extension * $nextRowAsArray is associative Array representing File Entry * or empty array if number or entries does not match the header * * If $fileReference.zip is not found, it is downloaded using FILE_DOWNLOAD_PATH * The archiv $fileReference.zip is automatically extracted whenever needed, * and first archiv Entry $file.txt is taken * * The File $file.txt is expected of the form: * * field_name1|field_name2 * entry1_field1|entry1_field2 * entry2_field1|entry2_field2 * ... * entryN_field1|entryN_field2 * * Here FILE_ENTRY_SEPARATOR is '|' * * Then the returned arrays $nextRowAsArray are subsequently of the form: * * array( 'field_name1' => 'entry1_field1', 'field_name2' => 'entry1_field2', ) * array( 'field_name1' => 'entry2_field1', 'field_name2' => 'entry2_field2', ) * ... * array( 'field_name1' => 'entryN_field1', 'field_name2' => 'entryN_field2', ) */ class FileImporter { private $_fileReference; private $_downloadPath; private $_separator; private $_fileHandleCache = null; private $_fileHeadRow = array(); public function __construct ($fileReference, $downloadPath = FILE_DOWNLOAD_PATH, $separator = FILE_ENTRY_SEPARATOR) { $this->_fileReference = $fileReference; $this->_downloadPath = $downloadPath; $this->_separator = $separator; } public function readFileRowAsArray () { $this->_cacheFileHandle(); $fileEntryArray = $this->_getNextRowAsArray(); if ( $this->_fileHeadRow ) { $keys = $this->_fileHeadRow; $values = $fileEntryArray; } else { $this->_fileHeadRow = $fileEntryArray; $keys = $fileEntryArray; $values = $this->_getNextRowAsArray(); } if ( sizeof($keys) !== sizeof($values) ) return array(); return array_combine($keys, $values); } private function _cacheFileHandle () { if ( !$this->_fileHandleCache ) { $fileHandle = $this->_getNewFileHandle(); $this->_fileHandleCache = $fileHandle; } } private function _getNextRowAsArray () { $fileHandle = $this->_fileHandleCache; $fileNextLine = fgets($fileHandle); $fileNextLineTrimmed = trim($fileNextLine); return explode($this->_separator, $fileNextLineTrimmed); } private function _getNewFileHandle () { $zipFileName = $this->_getZipFileName(); if (!file_exists($zipFileName)) $this->_downloadFile($zipFileName); return $this->_unzipGetFileHandle($zipFileName); } private function _getZipFileName () { return "{$this->_fileReference}.zip"; } private function _downloadFile ($fileName) { echo "\n Downloading $fileName\n"; $sourceStream = fopen($this->_downloadPath . $fileName, 'r') or die("Could not download $fileName"); $destinationStream = fopen($fileName, 'w'); stream_copy_to_stream($sourceStream, $destinationStream); } private function _unzipGetFileHandle ($zipFileName) { $firstZipEntryName = $this->_getFirstZipEntryName($zipFileName); if ( !file_exists($firstZipEntryName) ) $this->_ZipExtract($zipFileName); $fileHandle = fopen($firstZipEntryName, "rt") or die("Can't Read File $firstZipEntryName"); return $fileHandle; } private function _getFirstZipEntryName ($zipFileName) { $zipArchiv = zip_open($zipFileName); $firstZipEntry = zip_read($zipArchiv); $firstZipEntryName = zip_entry_name($firstZipEntry); zip_close($zipArchiv); return $firstZipEntryName; } private function _zipExtract ($zipFileName) { echo "\n Begin extraction at ", date('r').", file $zipFileName"; $zipArchiv = new ZipArchive; $zipArchiv->open($zipFileName); $zipArchiv->extractTo("."); $zipArchiv->close(); } }  

Below is the old question

Source Link
Dmitri Zaitsev
  • 1.3k
  • 1
  • 10
  • 26
Loading