euromark 12 years ago
parent
commit
6152da9690
2 changed files with 352 additions and 0 deletions
  1. 224 0
      Lib/ZipLib.php
  2. 128 0
      Test/Case/Lib/ZipLibTest.php

+ 224 - 0
Lib/ZipLib.php

@@ -0,0 +1,224 @@
+<?php
+
+/**
+ * A Zip reader class - mainly for reading and extracing Zip archives.
+ *
+ * To write to Zip use pclzip instead
+ * @see http://www.php.net/manual/de/class.ziparchive.php
+ *
+ * @author Mark Scherer
+ * @license MIT
+ * 2010-08-23 ms
+ */
+class ZipLib {
+
+	protected $Zip = null;
+
+	protected $filename = null;
+
+	protected $path = null;
+
+	protected $error = null;
+
+	public function __construct($path = null, $create = false) {
+		if (!function_exists('zip_open')) {
+			throw new CakeException('Zip not available (enable php extension "zip")');
+		}
+
+		if ($path !== null) {
+			$this->open($path, $create);
+		}
+	}
+
+	public function __destruct() {
+		$this->close();
+	}
+
+	/**
+	 * 2010-08-25 ms
+	 */
+	public function filename() {
+		return $this->filename;
+	}
+
+	/**
+	 * All files (not folders) - works recursive
+	 *
+	 * @return integer Size or false on failure
+	 * 2010-08-25 ms
+	 */
+	public function numFiles() {
+		if (!$this->Zip) {
+			return false;
+		}
+
+		$size = 0;
+		while ($dir_resource = zip_read($this->Zip)) {
+			$size++;
+		}
+		return $size;
+	}
+
+	/**
+	 * Size in bytes
+	 *
+	 * @return integer Size or false on failure
+	 * 2010-08-25 ms
+	 */
+	public function size() {
+		if (!$this->Zip) {
+			return false;
+		}
+
+		$size = 0;
+		while ($dir_resource = zip_read($this->Zip)) {
+			$size += zip_entry_filesize($dir_resource);
+		}
+		return $size;
+	}
+
+	/**
+	* Open a file.
+	*
+	* @params string, boolean
+	*	@return boolean Success
+	* 2010-08-25 ms
+	*/
+	public function open($path = null, $create = false) {
+		$this->filename = basename($path);
+
+		$path = str_replace('\\','/', $path);
+
+		$this->path = $path;
+		$zip = zip_open($path);
+		if (is_resource($zip)) {
+			$this->Zip = $zip;
+			return true;
+		}
+		$this->error = $zip;
+		return false;
+	}
+
+	/**
+	 * Close the Zip
+	 *
+	 * @return boolean Success
+	 */
+	public function close() {
+		if ($this->Zip !== null) {
+			zip_close($this->Zip);
+			$this->Zip = null;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Unzip to a specific location or the current path
+	 *
+	 * @param string $location
+	 * @param boolean $flatten
+	 * @return boolean Success
+	 * 2010-08-23 ms
+	 */
+	public function unzip($location = null, $flatten = false) {
+		if (!$this->Zip) {
+			return false;
+		}
+
+		$file = $this->path;
+		if (empty($location)) {
+			$location = dirname($file) . DS;
+		} else {
+			if (substr($location, 0, -1) !== DS) {
+				$location .= DS;
+			}
+			if (!file_exists($location)) {
+				if (!mkdir($location, 0777, true)) {
+					return false;
+				}
+			}
+		}
+
+		while ($zipEntry = zip_read($this->Zip)) {
+			$x = str_replace('\\','/', $location).zip_entry_name($zipEntry);
+			if ($flatten) {
+				$x = str_replace('\\','/', $location).basename(zip_entry_name($zipEntry));
+			}
+
+			if (!file_exists($l = dirname($x))) {
+				if (!mkdir($l, 0777, true)) {
+					return false;
+				}
+			}
+
+			$fp = fopen($x, "w");
+			if (zip_entry_open($this->Zip, $zipEntry, "r")) {
+				$buf = zip_entry_read($zipEntry, zip_entry_filesize($zipEntry));
+				fwrite($fp,"$buf");
+				zip_entry_close($zipEntry);
+				fclose($fp);
+			}
+		}
+		return true;
+	}
+
+	/**
+	 * returns the error string, if no error, it will return empty string ''
+	 *
+	 * @return string
+	 * 2010-08-08 ms
+	 */
+	public function getError($text = false) {
+		if ($this->error === null) {
+			return '';
+		}
+		if ($text) {
+			return $this->errMsg($this->error);
+		}
+		return $this->error;
+	}
+
+	/**
+	 * ZipLib::errMsg()
+	 *
+	 * @param mixed $errno
+	 * @return string
+	 */
+	public function errMsg($errno) {
+		// using constant name as a string to make this function PHP4 compatible
+		$zipFileFunctionsErrors = array(
+			'ZIPARCHIVE::ER_MULTIDISK' => 'Multi-disk zip archives not supported.',
+			'ZIPARCHIVE::ER_RENAME' => 'Renaming temporary file failed.',
+			'ZIPARCHIVE::ER_CLOSE' => 'Closing zip archive failed',
+			'ZIPARCHIVE::ER_SEEK' => 'Seek error',
+			'ZIPARCHIVE::ER_READ' => 'Read error',
+			'ZIPARCHIVE::ER_WRITE' => 'Write error',
+			'ZIPARCHIVE::ER_CRC' => 'CRC error',
+			'ZIPARCHIVE::ER_ZIPCLOSED' => 'Containing zip archive was closed',
+			'ZIPARCHIVE::ER_NOENT' => 'No such file.',
+			'ZIPARCHIVE::ER_EXISTS' => 'File already exists',
+			'ZIPARCHIVE::ER_OPEN' => 'Can\'t open file',
+			'ZIPARCHIVE::ER_TMPOPEN' => 'Failure to create temporary file.',
+			'ZIPARCHIVE::ER_ZLIB' => 'Zlib error',
+			'ZIPARCHIVE::ER_MEMORY' => 'Memory allocation failure',
+			'ZIPARCHIVE::ER_CHANGED' => 'Entry has been changed',
+			'ZIPARCHIVE::ER_COMPNOTSUPP' => 'Compression method not supported.',
+			'ZIPARCHIVE::ER_EOF' => 'Premature EOF',
+			'ZIPARCHIVE::ER_INVAL' => 'Invalid argument',
+			'ZIPARCHIVE::ER_NOZIP' => 'Not a zip archive',
+			'ZIPARCHIVE::ER_INTERNAL' => 'Internal error',
+			'ZIPARCHIVE::ER_INCONS' => 'Zip archive inconsistent',
+			'ZIPARCHIVE::ER_REMOVE' => 'Can\'t remove file',
+			'ZIPARCHIVE::ER_DELETED' => 'Entry has been deleted',
+		);
+		$errmsg = 'unknown';
+		foreach ($zipFileFunctionsErrors as $constName => $errorMessage) {
+			if (defined($constName) and constant($constName) === $errno) {
+				return 'Zip File Function error: '.$errorMessage;
+			}
+		}
+		return 'Zip File Function error: unknown';
+	}
+
+}

+ 128 - 0
Test/Case/Lib/ZipLibTest.php

@@ -0,0 +1,128 @@
+<?php
+App::uses('ZipLib', 'Tools.Lib');
+App::uses('MyCakeTestCase', 'Tools.TestSuite');
+
+class ZipLibTest extends MyCakeTestCase {
+
+	public $ZipLib;
+
+	public function setUp() {
+		parent::setUp();
+
+		if (isset($this->ZipLib)) {
+			return;
+		}
+		$this->ZipLib = new ZipLib();
+
+		//$x = base64_encode(file_get_contents(TMP.'test4.zip')); die(returns($x));
+
+		foreach ($this->testFiles as $file => $content) {
+			$this->_createTestFile($file, $content);
+		}
+	}
+
+	public function tearDown() {
+		$this->ZipLib->close();
+
+		foreach ($this->testFiles as $file => $content) {
+			unlink(TMP . $file);
+		}
+		$this->_rrmdir(TMP . 'xyz');
+		$this->_rrmdir(TMP . 'xyz2');
+
+		parent::tearDown();
+	}
+
+	public function testOpen() {
+		$is = $this->ZipLib->open(TMP . 'test_one_folder.zip');
+		$this->assertTrue($is);
+
+		$is = $this->ZipLib->getError();
+		$this->assertTrue(empty($is));
+
+		$is = $this->ZipLib->open(TMP . 'test_invalid.zip');
+		$this->assertFalse($is);
+
+		$is = $this->ZipLib->getError();
+		$this->out($is);
+		$this->assertTrue(!empty($is));
+
+		$is = $this->ZipLib->getError(true);
+		$this->out($is);
+		$this->assertTrue(!empty($is));
+	}
+
+	public function testFilename() {
+		$is = $this->ZipLib->open(TMP . 'test_one_folder.zip');
+		$this->assertEquals($this->ZipLib->filename(), 'test_one_folder.zip');
+	}
+
+	public function testSize() {
+		$this->ZipLib->open(TMP.'test_folder_and_file.zip');
+		$is = $this->ZipLib->size();
+		$this->out($is);
+		$this->assertEquals(5, $is);
+
+	}
+
+	public function testNum() {
+		$this->ZipLib->open(TMP . 'test_one_folder.zip');
+		$res = $this->ZipLib->numFiles();
+		$this->assertEquals(1, $res);
+
+		$this->ZipLib->open(TMP . 'test_folder_and_file.zip');
+		$res = $this->ZipLib->numFiles();
+		$this->assertEquals(2, $res);
+
+	}
+
+	public function testUnzip() {
+
+		$this->ZipLib->open(TMP . 'test_folder_and_file.zip');
+		$res = $this->ZipLib->unzip(TMP . 'xyz');
+		$this->assertTrue($res);
+		$this->assertTrue(file_exists(TMP . 'xyz' . DS . 'folder' . DS . 'file.txt'));
+		$this->assertSame('test', file_get_contents(TMP.'xyz' . DS . 'folder' . DS . 'file.txt'));
+
+		$this->ZipLib->open(TMP . 'test_folder_and_file.zip');
+		$res = $this->ZipLib->unzip(TMP . 'xyz2', true);
+		$this->assertTrue($res);
+		$this->assertTrue(file_exists(TMP . 'xyz2' . DS . 'e.txt'));
+		$this->assertTrue(file_exists(TMP . 'xyz2' . DS . 'file.txt'));
+		$this->assertSame('test', file_get_contents(TMP . 'xyz2' . DS . 'file.txt'));
+	}
+
+	/**
+	 * Helper method to recursively remove a directory
+	 */
+	protected function _rrmdir($dir) {
+		if (!is_dir($dir)) {
+			return;
+		}
+		foreach (glob($dir . '/*') as $file) {
+			if (is_dir($file)) {
+				$this->_rrmdir($file);
+			} else {
+				unlink($file);
+			}
+		}
+		rmdir($dir);
+	}
+
+	/**
+	 * Helper method to create zip test files
+	 */
+	public function _createTestFile($file, $content = null) {
+		if ($content === null) {
+			$content = $this->testFiles[$file];
+		}
+		file_put_contents(TMP . $file, base64_decode($content));
+	}
+
+	public $testFiles = array(
+		'test_one_folder.zip' => 'UEsDBBQAAAAAABIdFz2DFtyMAQAAAAEAAAAFAAAAZS50eHR4UEsBAhQAFAAAAAAAEh0XPYMW3IwBAAAAAQAAAAUAAAAAAAAAAQAgAAAAAAAAAGUudHh0UEsFBgAAAAABAAEAMwAAACQAAAAAAA==',
+		'test_folder_and_file.zip' => 'UEsDBBQAAAAAABIdFz2DFtyMAQAAAAEAAAAFAAAAZS50eHR4UEsDBBQAAAAAAEsjFz0Mfn/YBAAAAAQAAAAPAAAAZm9sZGVyL2ZpbGUudHh0dGVzdFBLAQIUABQAAAAAABIdFz2DFtyMAQAAAAEAAAAFAAAAAAAAAAEAIAAAAAAAAABlLnR4dFBLAQIUABQAAAAAAEsjFz0Mfn/YBAAAAAQAAAAPAAAAAAAAAAEAIAAAACQAAABmb2xkZXIvZmlsZS50eHRQSwUGAAAAAAIAAgBwAAAAVQAAAAAA',
+		'test_invalid.zip' => 'UEsDBBQAAAAAABIdFz2DFtyMAQAAAAEAAAAFAAAsS50eHR4UEsDBBQAAAAAAEsjFz0Mfn/YBAAAAAQAAAAPAAAAZm9sZGVyL2ZpbGUudHh0dGVzdFBLAQIUABQAAAAAABIdFz2DFtyMAQAAAAEAAAAFAAAAAAAAAAEAIAAAAAAAAABlLnR4dFBLAQIUABQAAAAAAEsjFz0Mfn/YBAAAAAQAAAAPAAAAAAAAAAEAIAAAACQAAABmb2xkZXIvZmlsZS50eHRQSwUGAAAAAAIAAgBwAAAAVQAAAAAA',
+	);
+
+}