forked from extern/egroupware
250 lines
9.6 KiB
PHP
250 lines
9.6 KiB
PHP
|
<?php
|
|||
|
// **************************
|
|||
|
// * Ziplib 0.3.1 *
|
|||
|
// * Created by: Seven *
|
|||
|
// **************************
|
|||
|
//
|
|||
|
// Simple set of functions to create a zipfile
|
|||
|
// according to the PKWare specifications, which
|
|||
|
// can be found on:
|
|||
|
// http://www.pkware.com/products/enterprise/white_papers/
|
|||
|
// <20>1989-2003, PKWARE Inc.
|
|||
|
|
|||
|
// functions in here start with zl, which comes from ZipLib ;)
|
|||
|
|
|||
|
// requires dostime.php
|
|||
|
$settings['offset'] = 1; // Holland ;)
|
|||
|
|
|||
|
class Ziplib {
|
|||
|
|
|||
|
var $archive;
|
|||
|
var $archive_fileinfo = array();
|
|||
|
var $archive_filecount;
|
|||
|
var $compr_lvl_last;
|
|||
|
|
|||
|
private function zl_compress($data,$level = "",$type = "") {
|
|||
|
if($type != "g" && $type != "b" && $type != "n") {
|
|||
|
// Darnit, they forgot to set the type. Assuming gZip if any compression
|
|||
|
if($level >= 1 && $level <= 9) $type = "g";
|
|||
|
elseif($level > 9) die("Compression level set too high");
|
|||
|
else $type = "n";
|
|||
|
}
|
|||
|
|
|||
|
if($type == "g") {
|
|||
|
$this->compr_lvl_last = 8;
|
|||
|
RETURN gzdeflate($data,$level);
|
|||
|
} elseif($type == "b") {
|
|||
|
$this->compr_lvl_last = 12;
|
|||
|
RETURN bzcompress($data,$level);
|
|||
|
} else {
|
|||
|
$this->compr_lvl_last = 0;
|
|||
|
RETURN $data;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public function zl_add_file($data,$filename,$comp = "") {
|
|||
|
global $settings;
|
|||
|
// if we already created a file, we'll make sure it'll be there in the coming zipfile ;)
|
|||
|
|
|||
|
// first, checking some data
|
|||
|
if(strlen($filename) > pow(2,16)-1) die("Filename $filename too long"); // ooh, dirty... dieing, will change later
|
|||
|
if(strlen($data) > pow(2,32)-1) die("File $filename larger then 2GB, cannot continue"); // another one, naughty me ;)
|
|||
|
|
|||
|
// $comp has a special format. the first character tells me about the compression, the second one represents the level
|
|||
|
if(strlen($comp) == 1) {
|
|||
|
// they still use the old method, assuming gzip
|
|||
|
|
|||
|
$comp_type = "n";
|
|||
|
$comp_lvl = 0;
|
|||
|
if($comp >= 1 && $comp <= 9) {
|
|||
|
$comp_type = "g";
|
|||
|
$comp_lvl = $comp;
|
|||
|
}
|
|||
|
} else {
|
|||
|
$comp_lvl = 5;
|
|||
|
$comp_type = "n";
|
|||
|
// hmmm, the new method. Is it valid?
|
|||
|
if ($comp[0] == "b" OR $comp[0] == "g" OR $comp[0] == "n") $comp_type = $comp[0];
|
|||
|
if (preg_match("/[0-9]/i",$comp[1])) $comp_lvl = $comp[1];
|
|||
|
}
|
|||
|
|
|||
|
// ok, let's get this bitch tidy:
|
|||
|
// first adding a file
|
|||
|
$compressed = $this->zl_compress($data,$comp_lvl,$comp_type);
|
|||
|
$uncompressed = strlen($data);
|
|||
|
|
|||
|
$newfile = "\x50\x4b\x03\x04"; // Header
|
|||
|
$newfile .="\x00\x00"; // Version needed to extract
|
|||
|
$newfile .="\x00\x00"; // general purpose bit flag
|
|||
|
$newfile .=pack("v",$this->compr_lvl_last); // compression method
|
|||
|
$newfile .=pack("v",dostime_get($settings['offset'])); // last mod file time
|
|||
|
$newfile .=pack("v",dosdate_get($settings['offset'])); // last mod file date
|
|||
|
$newfile .=pack("V",crc32($data)); // CRC32
|
|||
|
$newfile .=pack("V",strlen($compressed)); // compressed filesize
|
|||
|
$newfile .=pack("V",$uncompressed); // uncompressed filesize
|
|||
|
$newfile .=pack("v",strlen($filename)); // length of filename
|
|||
|
$newfile .="\x00\x00"; // some sort of extra field ;)
|
|||
|
$newfile .=$filename;
|
|||
|
$newfile .=$compressed;
|
|||
|
|
|||
|
$this->archive .= $newfile;
|
|||
|
|
|||
|
|
|||
|
// some 'statistics' for this file ;)
|
|||
|
$this->archive_filecount++;
|
|||
|
$idf = $this->archive_filecount - 1;
|
|||
|
$this->archive_fileinfo[$this->archive_filecount]['comp_type'] = $this->compr_lvl_last;
|
|||
|
$this->archive_fileinfo[$this->archive_filecount]['size'] = strlen($data);
|
|||
|
$this->archive_fileinfo[$this->archive_filecount]['size_comp'] = strlen($compressed);
|
|||
|
$this->archive_fileinfo[$this->archive_filecount]['pkg_size'] = strlen($newfile);
|
|||
|
if(!empty($this->archive_fileinfo[$idf]['local_stats_pointer'])) {
|
|||
|
$this->archive_fileinfo[$this->archive_filecount]['local_stats_pointer'] =
|
|||
|
$this->archive_fileinfo[$idf]['local_stats_pointer'] +
|
|||
|
$this->archive_fileinfo[$idf]['pkg_size'] + 1; // HACKERDIEHACK! only way to get local_stats_pointer to '0' (for now) in zl_pack
|
|||
|
} else {
|
|||
|
$this->archive_fileinfo[$this->archive_filecount]['local_stats_pointer'] = 1;
|
|||
|
}
|
|||
|
$this->archive_fileinfo[$this->archive_filecount]['name'] = $filename;
|
|||
|
$this->archive_fileinfo[$this->archive_filecount]['crc32'] = crc32($data);
|
|||
|
unset($file,$compressed); // to avoid having data in our memory double ;)
|
|||
|
RETURN TRUE;
|
|||
|
}
|
|||
|
|
|||
|
public function zl_pack($comment) {
|
|||
|
global $settings;
|
|||
|
if(strlen($comment) > pow(2,16)-1) die("Comment too long"); // that's 3
|
|||
|
|
|||
|
// now the central directory structure start
|
|||
|
for($x=1;$x <= $this->archive_filecount;$x++) {
|
|||
|
$file_stats = $this->archive_fileinfo[$x];
|
|||
|
$cdss .= "\x50\x4b\x01\x02"; // Header
|
|||
|
$cdss .="\x00\x00"; // version made by
|
|||
|
$cdss .="\x00\x00"; // version needed to extract
|
|||
|
$cdss .="\x00\x00"; // general purpose bit flag
|
|||
|
$cdss .=pack("v",$file_stats['comp_type']); // compression method
|
|||
|
$cdss .=pack("v",dostime_get($settings['offset'])); // last mod file time
|
|||
|
$cdss .=pack("v",dosdate_get($settings['offset'])); // last mod file date
|
|||
|
$cdss .=pack("V",$file_stats['crc32']); // CRC32
|
|||
|
$cdss .=pack("V",$file_stats['size_comp']); // compressed size
|
|||
|
$cdss .=pack("V",$file_stats['size']); // uncompressed size
|
|||
|
$cdss .=pack("v",strlen($file_stats['name'])); // file name length
|
|||
|
$cdss .="\x00\x00"; // extra field length
|
|||
|
$cdss .="\x00\x00"; // file comment length
|
|||
|
$cdss .="\x00\x00"; // disk number start
|
|||
|
$cdss .="\x00\x00"; // internal file attributes
|
|||
|
$cdss .="\x00\x00\x00\x00"; // external file attributes
|
|||
|
$cdss .=pack("V",$file_stats['local_stats_pointer']-$x); // relative offset of local header
|
|||
|
// aka: The local_stats_pointer hack: part 2, see above
|
|||
|
$cdss .=$file_stats['name'];
|
|||
|
}
|
|||
|
|
|||
|
// and final, the ending central directory structure! "WHOO HOOW!" (<28>Blur, 1998)
|
|||
|
$cdse = "\x50\x4b\x05\x06"; // Header
|
|||
|
$cdse .="\x00\x00"; // number of this disk
|
|||
|
$cdse .="\x00\x00"; // number of the disk with the start of the central directory
|
|||
|
$cdse .=pack("v",$this->archive_filecount); // total number of entries in the central directory on this disk
|
|||
|
$cdse .=pack("v",$this->archive_filecount); // total number of entries in the central directory
|
|||
|
$cdse .=pack("V",strlen($cdss)); // size of the central directory
|
|||
|
$cdse .=pack("V",strlen($this->archive)); // offset of start of central directory with respect to the starting disk number
|
|||
|
$cdse .=pack("v",strlen($comment)); // .ZIP file comment length
|
|||
|
$cdse .=$comment;
|
|||
|
|
|||
|
return $this->archive.$cdss.$cdse;
|
|||
|
}
|
|||
|
|
|||
|
public function zl_index_file($file) {
|
|||
|
$fp = @fopen($file,"rb");
|
|||
|
// ok, as we don't know what the exact position of everything is, we'll have to "guess" using the default sizes
|
|||
|
//and set values in the zipfile. Basicly this means I have to go through the entire file, could take some time.
|
|||
|
//Let's see if I can create an algorithm powerful enough.
|
|||
|
if(!$fp) die("File empty");
|
|||
|
$continue = 1;
|
|||
|
$file_count = 0;
|
|||
|
|
|||
|
while($continue) {
|
|||
|
$content = fread($fp,30);
|
|||
|
$id = substr($content,0,4);
|
|||
|
if ($id == "\x50\x4b\x03\x04") {
|
|||
|
// the method used is quite simple, load a file in the memory, and walk through several parts of it using substr
|
|||
|
// As the PKZip format uses mostly fixed sizes for information, this isn't too hard to implement
|
|||
|
// First I want everything tested, before I start giving this function a nice place in the class
|
|||
|
$temp[$file_count]['file-size'] = ascii2dec(substr($content,18,4));
|
|||
|
$temp[$file_count]['filename-size'] = ascii2dec(substr($content,26,2));
|
|||
|
$temp[$file_count]['compression-type'] = ascii2dec(substr($content,8,2));
|
|||
|
$temp[$file_count]['crc'] = ascii2dec(substr($content,14,4));
|
|||
|
$temp[$file_count]['dostime'] = dostime_return(substr($content,10,2));
|
|||
|
$temp[$file_count]['dosdate'] = dosdate_return(substr($content,12,2));
|
|||
|
|
|||
|
$temp[$file_count]['filename'] = fread($fp,$temp[$file_count]['filename-size']);
|
|||
|
|
|||
|
// As the Zip format does not include Content type headers, I'll create a nice little array with
|
|||
|
// extension/content type, and a small function to retreive it
|
|||
|
$temp[$file_count]['file-type'] = ext2cth($temp[$file_count]['filename']);
|
|||
|
$temp[$file_count]['content'] = fread($fp,$temp[$file_count]['file-size']);
|
|||
|
|
|||
|
if ($temp[$file_count]['compression-type'] != 0 AND $temp[$file_count]['compression-type'] != 8 AND $temp[$file_count]['compression-type'] != 12) {
|
|||
|
$temp[$file_count]['lasterror'] = "Compression type not supported";
|
|||
|
} else {
|
|||
|
if($temp[$file_count]['compression-type'] == 8) {
|
|||
|
$temp[$file_count]['content'] = gzinflate($temp[$file_count]['content']);
|
|||
|
} elseif ($temp[$file_count]['compression-type'] == 12) {
|
|||
|
$temp[$file_count]['content'] = bzdecompress($temp[$file_count]['content']);
|
|||
|
}
|
|||
|
$verify = crc32($temp[$file_count]['content']);
|
|||
|
if ($verify != $temp[$file_count]['crc']) {
|
|||
|
$temp[$file_count]['lasterror'] = "CRC did not match, possibly this zipfile is damaged";
|
|||
|
}
|
|||
|
}
|
|||
|
$file_count++;
|
|||
|
} else {
|
|||
|
$continue = 0;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
fclose($fp);
|
|||
|
unset($fp,$content,$file_count);
|
|||
|
return $temp;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function zipImgsFiles($source,$zip)
|
|||
|
{
|
|||
|
|
|||
|
$folder = opendir($source==""?"./":$source);
|
|||
|
while($file = readdir($folder))
|
|||
|
{
|
|||
|
if ($file == '.' || $file == '..') {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if(is_dir($source.$file))
|
|||
|
{
|
|||
|
zipImgsFiles($source.$file."/",$zip);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
$zip->zl_add_file(file_get_contents($source.$file),$source.$file,"g0");
|
|||
|
}
|
|||
|
}
|
|||
|
closedir($folder);
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
function zipFromLocation($location,$name="dhtmlx"){
|
|||
|
//echo $location;
|
|||
|
chdir($location);
|
|||
|
$zip = new Ziplib;
|
|||
|
$zip->zl_add_file(file_get_contents("dhtmlx.js"),$name.'.js',"g9");
|
|||
|
$zip->zl_add_file(file_get_contents("dhtmlx.css"),$name.'.css',"g9");
|
|||
|
$zip->zl_add_file(file_get_contents("manifest.txt"),'manifest.txt',"g9");
|
|||
|
zipImgsFiles("imgs/",$zip);
|
|||
|
$files = @scandir("./types");
|
|||
|
if (count($files) > 2)
|
|||
|
zipImgsFiles("types/",$zip);
|
|||
|
|
|||
|
$outZip = $zip->zl_pack("");
|
|||
|
|
|||
|
return $outZip;
|
|||
|
}
|
|||
|
?>
|