/code/php/functions/gunzip.php
PHP | 451 lines | 270 code | 45 blank | 136 comment | 70 complexity | 8a48d96b1fe7bcb0915051c8ea609bbd MD5 | raw file
- <?php
-
- function gunzip($file,$path='./') {
- //$path=realpath($path);
- if (!file_exists($file)) { user_error("'$file' does not exist."); return; }
- if (!is_writable($path)) { user_error("'$path' is not writable."); return; }
- if (!function_exists('gzopen')) { user_error("gzopen() function does not exist."); return; }
-
- $tar = new ArchiveTar($file);
- $contentList = $tar->getContentList();
- if (!count($contentList)) {
- user_error("Can not unpack '$file'. File is corrupt.");
- return;
- }
- //print_r($contentList); //debug
-
- $status=1;
- foreach ($contentList as $file) {
- if ($file['type'] != 'folder') {
- if (!is_dir(dirname($path.$file['filename']))) {
- $status=rmkdir(dirname($path.$file['filename']));
- }
- $status=$tar->extract($file['index'], $path.$file['filename']);
- }
- if (!$status) { return $status; }
- }
-
- $tar->close();
- return $status;
- }
-
- /**
- * Opens tar or tar.gz archives.
- *
- * $tar = new ArchiveTar('archive.tar');
- * $contentList = $tar->getContentList();
- * foreach ($contentList as $key => $val) {
- * $tar->extract($key, DESTINATION);
- * }
- */
- class ArchiveTar {
- protected $archiveName = '';
- protected $contentList = array();
- protected $opened = false;
- protected $read = false;
- protected $file = null;
- protected $isZipped = false;
- protected $mode = 'rb';
-
- /**
- * Creates a new ArchiveTar object.
- * archiveName must be tarball or gzipped tarball
- *
- * @param string $archiveName
- */
- public function __construct($archiveName) {
- $match = array();
- if (!is_file($archiveName)) {
- user_error("unable to find tar archive '".$archiveName."'");
- }
-
- $this->archiveName = $archiveName;
- $this->open();
- $this->readContent();
- }
-
- /**
- * Destructor of this class, closes tar archive.
- */
- public function __destruct() {
- $this->close();
- }
-
- /**
- * Opens the tar archive and stores filehandle.
- */
- public function open() {
- if (!$this->opened) {
- if ($this->isZipped) $this->file = new ArchiveZipFile($this->archiveName, $this->mode);
- else {
- // test compression
- $this->file = new ArchiveFile($this->archiveName, $this->mode);
- if ($this->file->read(2) == "\37\213") {
- $this->file->close();
- $this->isZipped = true;
- $this->file = new ArchiveZipFile($this->archiveName, $this->mode);
- }
- else {
- $this->file->seek(0);
- }
- }
- $this->opened = true;
- }
- }
-
- /**
- * Closes the opened file.
- */
- public function close() {
- if ($this->opened) {
- $this->file->close();
- $this->opened = false;
- }
- }
-
- /**
- * Returns the table of contents (TOC) list for this tar archive.
- *
- * @return array list of content
- */
- public function getContentList() {
- if (!$this->read) {
- $this->open();
- $this->readContent();
- }
- return $this->contentList;
- }
-
- /**
- * Returns an associative array with information
- * about a specific file in the archive.
- *
- * @param mixed $fileindex index or name of the requested file
- * @return array $fileInfo
- */
- public function getFileInfo($fileIndex) {
- if (!is_int($fileIndex)) {
- $fileIndex = $this->getIndexByFilename($fileIndex);
- }
-
- if (!isset($this->contentList[$fileIndex])) {
- user_error("Tar: could find file '$index' in archive");
- }
- return $this->contentList[$fileIndex];
- }
-
- /**
- * Searchs a file in the tar archive
- * and returns the numeric fileindex.
- * Returns false if not found.
- *
- * @param string $filename
- * @return integer index of the requested file
- */
- public function getIndexByFilename($filename) {
- foreach ($this->contentList as $index => $file) {
- if ($file['filename'] == $filename) {
- return $index;
- }
- }
- return false;
- }
-
- /**
- * Extracts a specific file and returns the content as string.
- * Returns false if extraction failed.
- *
- * @param mixed $index index or name of the requested file
- * @return string content of the requested file
- */
- public function extractToString($index) {
- if (!$this->read) {
- $this->open();
- $this->readContent();
- }
- $header = $this->getFileInfo($index);
-
- // can not extract a folder
- if ($header['type'] != 'file') {
- return false;
- }
-
- // seek to offset
- $this->file->seek($header['offset']);
-
- // read data
- $content = '';
- $n = floor($header['size'] / 512);
- for($i = 0; $i < $n; $i++) {
- $content .= $this->file->read(512);
- }
- if(($header['size'] % 512) != 0) {
- $buffer = $this->file->read(512);
- $content .= substr($buffer, 0, ($header['size'] % 512));
- }
-
- return $content;
- }
-
- /**
- * Extracts a specific file and writes it's content
- * to the file specified with $destination.
- *
- * @param mixed $index index or name of the requested file
- * @param string $destination
- * @return boolean $success
- */
- public function extract($index, $destination) {
- if (!$this->read) {
- $this->open();
- $this->readContent();
- }
- $header = $this->getFileInfo($index);
-
- // can not extract a folder
- if ($header['type'] != 'file') {
- return false;
- }
-
- // seek to offset
- $this->file->seek($header['offset']);
-
- $targetFile = new ArchiveFile($destination);
-
- // read data
- $n = floor($header['size'] / 512);
- for ($i = 0; $i < $n; $i++) {
- $content = $this->file->read(512);
- $targetFile->write($content, 512);
- }
- if (($header['size'] % 512) != 0) {
- $content = $this->file->read(512);
- $targetFile->write($content, ($header['size'] % 512));
- }
-
- $targetFile->close();
- if (function_exists('apache_get_version') || !@$targetFile->is_writable()) {
- @$targetFile->chmod(0777);
- }
- else {
- @$targetFile->chmod(0755);
- }
-
- if ($header['mtime']) {
- @$targetFile->touch($header['mtime']);
- }
-
- // check filesize
- if (filesize($destination) != $header['size']) {
- user_error("Could not untar file '".$header['filename']."' to '".$destination."'. Maybe disk quota exceeded in folder '".dirname($destination)."'.");
- }
-
- return true;
- }
-
- /**
- * Reads table of contents (TOC) from tar archive.
- * This does not get the entire to memory but only parts of it.
- */
- protected function readContent() {
- $this->contentList = array();
- $this->read = true;
- $i = 0;
-
- // Read the 512 bytes header
- while (strlen($binaryData = $this->file->read(512)) != 0) {
- // read header
- $header = $this->readHeader($binaryData);
- if ($header === false) {
- continue;
- }
- $this->contentList[$i] = $header;
- $this->contentList[$i]['index'] = $i;
- $i++;
-
- $this->file->seek($this->file->tell() + (512 * ceil(($header['size'] / 512))));
- }
- }
-
- /**
- * Unpacks file header for one file entry.
- *
- * @param string $binaryData
- * @return array $fileheader
- */
- protected function readHeader($binaryData) {
- if (strlen($binaryData) != 512) {
- return false;
- }
-
- $header = array();
- $checksum = 0;
- // First part of the header
- for ($i = 0; $i < 148; $i++) {
- $checksum += ord(substr($binaryData, $i, 1));
- }
- // Calculate the checksum
- // Ignore the checksum value and replace it by ' ' (space)
- for ($i = 148; $i < 156; $i++) {
- $checksum += ord(' ');
- }
- // Last part of the header
- for ($i = 156; $i < 512; $i++) {
- $checksum += ord(substr($binaryData, $i, 1));
- }
-
- // Extract the values
- $data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155prefix", $binaryData);
-
- // Extract the properties
- $header['checksum'] = octDec(trim($data['checksum']));
- if ($header['checksum'] == $checksum) {
- $header['filename'] = trim($data['filename']);
- $header['mode'] = octDec(trim($data['mode']));
- $header['uid'] = octDec(trim($data['uid']));
- $header['gid'] = octDec(trim($data['gid']));
- $header['size'] = octDec(trim($data['size']));
- $header['mtime'] = octDec(trim($data['mtime']));
- $header['prefix'] = trim($data['prefix']);
- if ($header['prefix']) {
- $header['filename'] = $header['prefix'].'/'.$header['filename'];
- }
- if (($header['typeflag'] = $data['typeflag']) == '5') {
- $header['size'] = 0;
- $header['type'] = 'folder';
- }
- else {
- $header['type'] = 'file';
- }
- $header['offset'] = $this->file->tell();
-
- return $header;
- }
- else {
- return false;
- }
- }
- }
- /**
- * The File class handles all file operations.
- *
- * Example:
- * using php functions:
- * $fp = fopen('filename', 'wb');
- * fwrite($fp, '...');
- * fclose($fp);
- *
- * using this class:
- * $file = new ArchiveFile('filename');
- * $file->write('...');
- * $file->close();
- */
- class ArchiveFile {
- protected $resource = null;
- protected $filename;
-
- /**
- * Opens a new file.
- *
- * @param string $filename
- * @param string $mode
- */
- public function __construct($filename, $mode = 'wb') {
- $this->filename = $filename;
- $this->resource = fopen($filename, $mode);
- if ($this->resource === false) {
- user_error('Can not open file ' . $filename);
- }
- }
-
- /**
- * Calls the specified function on the open file.
- * Do not call this function directly. Use $file->write('') instead.
- *
- * @param string $function
- * @param array $arguments
- */
- public function __call($function, $arguments) {
- if (function_exists('f' . $function)) {
- array_unshift($arguments, $this->resource);
- return call_user_func_array('f' . $function, $arguments);
- }
- else if (function_exists($function)) {
- array_unshift($arguments, $this->filename);
- return call_user_func_array($function, $arguments);
- }
- else {
- user_error('Can not call file method ' . $function);
- }
- }
- }
-
- /**
- * The File class handles all file operations on a zipped file.
- *
- */
- class ArchiveZipFile extends ArchiveFile {
- /**
- * Opens a new zipped file.
- *
- * @param string $filename
- * @param string $mode
- */
- public function __construct($filename, $mode = 'wb') {
- $this->filename = $filename;
- if (!function_exists('gzopen')) {
- user_error('Can not find functions of the zlib extension');
- }
- $this->resource = @gzopen($filename, $mode);
- if ($this->resource === false) {
- user_error('Can not open file ' . $filename);
- }
- }
-
- /**
- * Calls the specified function on the open file.
- *
- * @param string $function
- * @param array $arguments
- */
- public function __call($function, $arguments) {
- if (function_exists('gz' . $function)) {
- array_unshift($arguments, $this->resource);
- return call_user_func_array('gz' . $function, $arguments);
- }
- else if (function_exists($function)) {
- array_unshift($arguments, $this->filename);
- return call_user_func_array($function, $arguments);
- }
- else {
- user_error('Can not call method ' . $function);
- }
- }
-
- /**
- * Returns the filesize of the unzipped file
- */
- public function getFileSize() {
- $byteBlock = 1<<14;
- $eof = $byteBlock;
-
- // the correction is for zip files that are too small
- // to get in the first while loop
- $correction = 1;
- while ($this->seek($eof) == 0) {
- $eof += $byteBlock;
- $correction = 0;
- }
-
- while ($byteBlock > 1) {
- $byteBlock >>= 1;
- $eof += $byteBlock * ($this->seek($eof) ? -1 : 1);
- }
-
- if ($this->seek($eof) == -1) $eof -= 1;
-
- $this->rewind();
- return $eof - $correction;
- }
- }
- //EOF