Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- class zipfile
- {
- /*
- zipfile class, for reading or writing .zip files
- See http://www.gamingg.net for more of my work
- Based on tutorial given by John Coggeshall at http://www.zend.com/zend/spotlight/creating-zip-files3.php
- Copyright (C) Joshua Townsend and licensed under the GPL
- Version 1.0
- */
- var $datasec = array(); // array to store compressed data
- var $files = array(); // array of uncompressed files
- var $dirs = array(); // array of directories that have been created already
- var $ctrl_dir = array(); // central directory
- var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00"; //end of Central directory record
- var $old_offset = 0;
- var $basedir = ".";
- function create_dir($name) // Adds a directory to the zip with the name $name
- {
- $name = str_replace("\\", "/", $name);
- $fr = "\x50\x4b\x03\x04";
- $fr .= "\x0a\x00"; // version needed to extract
- $fr .= "\x00\x00"; // general purpose bit flag
- $fr .= "\x00\x00"; // compression method
- $fr .= "\x00\x00\x00\x00"; // last mod time and date
- $fr .= pack("V",0); // crc32
- $fr .= pack("V",0); //compressed filesize
- $fr .= pack("V",0); //uncompressed filesize
- $fr .= pack("v",strlen($name)); //length of pathname
- $fr .= pack("v", 0); //extra field length
- $fr .= $name;
- // end of "local file header" segment
- // no "file data" segment for path
- // "data descriptor" segment (optional but necessary if archive is not served as file)
- $fr .= pack("V",0); //crc32
- $fr .= pack("V",0); //compressed filesize
- $fr .= pack("V",0); //uncompressed filesize
- // add this entry to array
- $this->datasec[] = $fr;
- $new_offset = strlen(implode("", $this->datasec));
- // ext. file attributes mirrors MS-DOS directory attr byte, detailed
- // at http://support.microsoft.com/support/kb/articles/Q125/0/19.asp
- // now add to central record
- $cdrec = "\x50\x4b\x01\x02";
- $cdrec .="\x00\x00"; // version made by
- $cdrec .="\x0a\x00"; // version needed to extract
- $cdrec .="\x00\x00"; // general purpose bit flag
- $cdrec .="\x00\x00"; // compression method
- $cdrec .="\x00\x00\x00\x00"; // last mod time and date
- $cdrec .= pack("V",0); // crc32
- $cdrec .= pack("V",0); //compressed filesize
- $cdrec .= pack("V",0); //uncompressed filesize
- $cdrec .= pack("v", strlen($name) ); //length of filename
- $cdrec .= pack("v", 0 ); //extra field length
- $cdrec .= pack("v", 0 ); //file comment length
- $cdrec .= pack("v", 0 ); //disk number start
- $cdrec .= pack("v", 0 ); //internal file attributes
- $cdrec .= pack("V", 16 ); //external file attributes - 'directory' bit set
- $cdrec .= pack("V", $this->old_offset); //relative offset of local header
- $this->old_offset = $new_offset;
- $cdrec .= $name;
- // optional extra field, file comment goes here
- // save to array
- $this->ctrl_dir[] = $cdrec;
- $this->dirs[] = $name;
- }
- function create_file($data, $name) // Adds a file to the path specified by $name with the contents $data
- {
- $name = str_replace("\\", "/", $name);
- $fr = "\x50\x4b\x03\x04";
- $fr .= "\x14\x00"; // version needed to extract
- $fr .= "\x00\x00"; // general purpose bit flag
- $fr .= "\x08\x00"; // compression method
- $fr .= "\x00\x00\x00\x00"; // last mod time and date
- $unc_len = strlen($data);
- $crc = crc32($data);
- $zdata = gzcompress($data);
- $zdata = substr($zdata, 2, -4); // fix crc bug
- $c_len = strlen($zdata);
- $fr .= pack("V",$crc); // crc32
- $fr .= pack("V",$c_len); //compressed filesize
- $fr .= pack("V",$unc_len); //uncompressed filesize
- $fr .= pack("v", strlen($name) ); //length of filename
- $fr .= pack("v", 0 ); //extra field length
- $fr .= $name;
- // end of "local file header" segment
- // "file data" segment
- $fr .= $zdata;
- // "data descriptor" segment (optional but necessary if archive is not served as file)
- $fr .= pack("V",$crc); // crc32
- $fr .= pack("V",$c_len); // compressed filesize
- $fr .= pack("V",$unc_len); // uncompressed filesize
- // add this entry to array
- $this->datasec[] = $fr;
- $new_offset = strlen(implode("", $this->datasec));
- // now add to central directory record
- $cdrec = "\x50\x4b\x01\x02";
- $cdrec .="\x00\x00"; // version made by
- $cdrec .="\x14\x00"; // version needed to extract
- $cdrec .="\x00\x00"; // general purpose bit flag
- $cdrec .="\x08\x00"; // compression method
- $cdrec .="\x00\x00\x00\x00"; // last mod time & date
- $cdrec .= pack("V",$crc); // crc32
- $cdrec .= pack("V",$c_len); //compressed filesize
- $cdrec .= pack("V",$unc_len); //uncompressed filesize
- $cdrec .= pack("v", strlen($name) ); //length of filename
- $cdrec .= pack("v", 0 ); //extra field length
- $cdrec .= pack("v", 0 ); //file comment length
- $cdrec .= pack("v", 0 ); //disk number start
- $cdrec .= pack("v", 0 ); //internal file attributes
- $cdrec .= pack("V", 32 ); //external file attributes - 'archive' bit set
- $cdrec .= pack("V", $this->old_offset); //relative offset of local header
- $this->old_offset = $new_offset;
- $cdrec .= $name;
- // optional extra field, file comment goes here
- // save to central directory
- $this->ctrl_dir[] = $cdrec;
- }
- function read_zip($name)
- {
- // Clear current file
- $this->datasec = array();
- // File information
- $this->name = $name;
- $this->mtime = filemtime($name);
- $this->size = filesize($name);
- // Read file
- $fh = fopen($name, "rb");
- $filedata = fread($fh, $this->size);
- fclose($fh);
- // Break into sections
- $filesecta = explode("\x50\x4b\x05\x06", $filedata);
- // ZIP Comment
- $unpackeda = unpack('x16/v1length', $filesecta[1]);
- $this->comment = substr($filesecta[1], 18, $unpackeda['length']);
- $this->comment = str_replace(array("\r\n", "\r"), "\n", $this->comment); // CR + LF and CR -> LF
- // Cut entries from the central directory
- $filesecta = explode("\x50\x4b\x01\x02", $filedata);
- $filesecta = explode("\x50\x4b\x03\x04", $filesecta[0]);
- array_shift($filesecta); // Removes empty entry/signature
- foreach($filesecta as $filedata)
- {
- // CRC:crc, FD:file date, FT: file time, CM: compression method, GPF: general purpose flag, VN: version needed, CS: compressed size, UCS: uncompressed size, FNL: filename length
- $entrya = array();
- $entrya['error'] = "";
- $unpackeda = unpack("v1version/v1general_purpose/v1compress_method/v1file_time/v1file_date/V1crc/V1size_compressed/V1size_uncompressed/v1filename_length", $filedata);
- // Check for encryption
- $isencrypted = (($unpackeda['general_purpose'] & 0x0001) ? true : false);
- // Check for value block after compressed data
- if($unpackeda['general_purpose'] & 0x0008)
- {
- $unpackeda2 = unpack("V1crc/V1size_compressed/V1size_uncompressed", substr($filedata, -12));
- $unpackeda['crc'] = $unpackeda2['crc'];
- $unpackeda['size_compressed'] = $unpackeda2['size_uncompressed'];
- $unpackeda['size_uncompressed'] = $unpackeda2['size_uncompressed'];
- unset($unpackeda2);
- }
- $entrya['name'] = substr($filedata, 26, $unpackeda['filename_length']);
- if(substr($entrya['name'], -1) == "/") // skip directories
- {
- continue;
- }
- $entrya['dir'] = dirname($entrya['name']);
- $entrya['dir'] = ($entrya['dir'] == "." ? "" : $entrya['dir']);
- $entrya['name'] = basename($entrya['name']);
- $filedata = substr($filedata, 26 + $unpackeda['filename_length']);
- if(strlen($filedata) != $unpackeda['size_compressed'])
- {
- $entrya['error'] = "Compressed size is not equal to the value given in header.";
- }
- if($isencrypted)
- {
- $entrya['error'] = "Encryption is not supported.";
- }
- else
- {
- switch($unpackeda['compress_method'])
- {
- case 0: // Stored
- // Not compressed, continue
- break;
- case 8: // Deflated
- $filedata = gzinflate($filedata);
- break;
- case 12: // BZIP2
- if(!extension_loaded("bz2"))
- {
- @dl((strtolower(substr(PHP_OS, 0, 3)) == "win") ? "php_bz2.dll" : "bz2.so");
- }
- if(extension_loaded("bz2"))
- {
- $filedata = bzdecompress($filedata);
- }
- else
- {
- $entrya['error'] = "Required BZIP2 Extension not available.";
- }
- break;
- default:
- $entrya['error'] = "Compression method ({$unpackeda['compress_method']}) not supported.";
- }
- if(!$entrya['error'])
- {
- if($filedata === false)
- {
- $entrya['error'] = "Decompression failed.";
- }
- elseif(strlen($filedata) != $unpackeda['size_uncompressed'])
- {
- $entrya['error'] = "File size is not equal to the value given in header.";
- }
- elseif(crc32($filedata) != $unpackeda['crc'])
- {
- $entrya['error'] = "CRC32 checksum is not equal to the value given in header.";
- }
- }
- $entrya['filemtime'] = mktime(($unpackeda['file_time'] & 0xf800) >> 11,($unpackeda['file_time'] & 0x07e0) >> 5, ($unpackeda['file_time'] & 0x001f) << 1, ($unpackeda['file_date'] & 0x01e0) >> 5, ($unpackeda['file_date'] & 0x001f), (($unpackeda['file_date'] & 0xfe00) >> 9) + 1980);
- $entrya['data'] = $filedata;
- }
- $this->files[] = $entrya;
- }
- return $this->files;
- }
- function add_file($file, $dir = ".", $file_blacklist = array(), $ext_blacklist = array())
- {
- $file = str_replace("\\", "/", $file);
- $dir = str_replace("\\", "/", $dir);
- if(strpos($file, "/") !== false)
- {
- $dira = explode("/", "{$dir}/{$file}");
- $file = array_shift($dira);
- $dir = implode("/", $dira);
- unset($dira);
- }
- while(substr($dir, 0, 2) == "./")
- {
- $dir = substr($dir, 2);
- }
- while(substr($file, 0, 2) == "./")
- {
- $file = substr($file, 2);
- }
- if(!in_array($dir, $this->dirs))
- {
- if($dir == ".")
- {
- $this->create_dir("./");
- }
- $this->dirs[] = $dir;
- }
- if(in_array($file, $file_blacklist))
- {
- return true;
- }
- foreach($ext_blacklist as $ext)
- {
- if(substr($file, -1 - strlen($ext)) == ".{$ext}")
- {
- return true;
- }
- }
- $filepath = (($dir && $dir != ".") ? "{$dir}/" : "").$file;
- if(is_dir("{$this->basedir}/{$filepath}"))
- {
- $dh = opendir("{$this->basedir}/{$filepath}");
- while(($subfile = readdir($dh)) !== false)
- {
- if($subfile != "." && $subfile != "..")
- {
- $this->add_file($subfile, $filepath, $file_blacklist, $ext_blacklist);
- }
- }
- closedir($dh);
- }
- else
- {
- $this->create_file(implode("", file("{$this->basedir}/{$filepath}")), $filepath);
- }
- return true;
- }
- function zipped_file() // return zipped file contents
- {
- $data = implode("", $this->datasec);
- $ctrldir = implode("", $this->ctrl_dir);
- return $data.
- $ctrldir.
- $this->eof_ctrl_dir.
- pack("v", sizeof($this->ctrl_dir)). // total number of entries "on this disk"
- pack("v", sizeof($this->ctrl_dir)). // total number of entries overall
- pack("V", strlen($ctrldir)). // size of central dir
- pack("V", strlen($data)). // offset to start of central dir
- "\x00\x00"; // .zip file comment length
- }
- }
- ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement