289 lines
9.8 KiB
PHP
289 lines
9.8 KiB
PHP
<?PHP
|
|
/** SS_ZIP class is designed to work with ZIP archives
|
|
@author Yuriy Horobey, smiledsoft.com
|
|
@email info@smiledsoft.com
|
|
|
|
Added zipDirTree function to add a directory recursively
|
|
|
|
*/
|
|
class ss_zip{
|
|
/** contains whole zipfile
|
|
@see ss_zip::archive()
|
|
@see ss_zip::ss_zip()
|
|
*/
|
|
var $zipfile="";
|
|
/** compression level */
|
|
var $complevel=6;
|
|
/** entry counter */
|
|
var $cnt=0;
|
|
/** current offset in zipdata segment */
|
|
var $offset=0;
|
|
/** index of current entry
|
|
@see ss_zip::read()
|
|
*/
|
|
var $idx=0;
|
|
/**
|
|
ZipData segment, each element of this array contains local file header plus zipped data
|
|
*/
|
|
var $zipdata=array();
|
|
/** central directory array */
|
|
var $cdir=array();
|
|
/** constructor
|
|
@param string zipfile if not empty must contain path to valid zip file, ss_zip will try to open and parse it.
|
|
If this parameter is empty, the new empty zip archive is created. This parameter has no meaning in LIGHT verion, please upgrade to PROfessional version.
|
|
@param int complevel compression level, 1-minimal compression, 9-maximal, default is 6
|
|
*/
|
|
function ss_zip($zipfile="",$complevel=6){
|
|
$this->clear();
|
|
if($complevel<1)$complevel=1;
|
|
if($complevel>9)$complevel=9;
|
|
$this->complevel=$complevel;
|
|
$this->open($zipfile);
|
|
}
|
|
|
|
function zipDirTree($dir, $baseDir) {
|
|
$d = dir($dir);
|
|
while (false !== ($entry = $d->read())) {
|
|
//If entry is a directory zip this directory
|
|
if($entry != '.' && $entry != '..' && is_dir($dir.$entry)) {
|
|
//$arDir[$entry] = $this->zipDirTree($dir.$entry."/",$baseDir);
|
|
$this->zipDirTree($dir.$entry."/",$baseDir);
|
|
}
|
|
//Add file to zip
|
|
if($entry!="." and $entry!=".." and !is_dir($dir.$entry)) {
|
|
//print "Addding file $dir$entry to zip under name " . str_replace($baseDir, "/", $dir.$entry) . "<br>";
|
|
$this -> add_file($dir.$entry, str_replace($baseDir, "/", $dir.$entry));
|
|
}
|
|
}
|
|
$d->close();
|
|
return;
|
|
}
|
|
|
|
/**Resets the objec, clears all the structures
|
|
*/
|
|
function clear(){
|
|
$this->zipfile="";
|
|
$this->complevel=6;
|
|
$this->cnt=0;
|
|
$this->offset=0;
|
|
$this->idx=0;
|
|
$this->zipdata=array();
|
|
$this->cdir=array();
|
|
}
|
|
/**opens zip file.
|
|
<center><hr nashade>*** This functionality is available in PRO version only. ***<br><a href='http://smiledsoft.com/demos/phpzip/' target='_blank'>please upgrade </a><hr nashade></center>
|
|
This function opens file pointed by zipfile parameter and creates all necessary structures
|
|
@param str zipfile path to the file
|
|
@param bool append if true the newlly opened archive will be appended to existing object structure
|
|
*/
|
|
function open($zipfile, $append=false){}
|
|
|
|
|
|
/**saves to the disc or sends zipfile to the browser.
|
|
@param str zipfile path under which to store the file on the server or file name under which the browser will receive it.
|
|
If you are saving to the server, you are responsible to obtain appropriate write permissions for this operation.
|
|
@param char where indicates where should the file be sent
|
|
<ul>
|
|
<li>'f' -- filesystem </li>
|
|
<li>'b' -- browser</li>
|
|
</ul>
|
|
Please remember that there should not be any other output before you call this function. The only exception is
|
|
that other headers may be sent. See <a href='http://php.net/header' target='_blank'>http://php.net/header</a>
|
|
*/
|
|
function save($zipfile, $where='f'){
|
|
if(!$this->zipfile)$this->archive();
|
|
$zipfile=trim($zipfile);
|
|
|
|
if(strtolower(trim($where))=='f'){
|
|
$this->_write($zipfile,$this->zipfile);
|
|
}else{
|
|
$zipfile = basename($zipfile);
|
|
header("Content-type: application/octet-stream");
|
|
header("Content-disposition: attachment; filename=\"$zipfile\"");
|
|
print $this->archive();
|
|
}
|
|
}
|
|
|
|
/** adds data to zip file
|
|
@param str filename path under which the content of data parameter will be stored into the zip archive
|
|
@param str data content to be stored under name given by path parameter
|
|
@see ss_zip::add_file()
|
|
*/
|
|
function add_data($filename,$data=null){
|
|
|
|
$filename=trim($filename);
|
|
$filename=str_replace('\\', '/', $filename);
|
|
if($filename[0]=='/') $filename=substr($filename,1);
|
|
|
|
if( ($attr=(($datasize = strlen($data))?32:16))==32 ){
|
|
$crc = crc32($data);
|
|
$gzdata = gzdeflate($data,$this->complevel);
|
|
$gzsize = strlen($gzdata);
|
|
$dir=dirname($filename);
|
|
// if($dir!=".") $this->add_data("$dir/");
|
|
}else{
|
|
$crc = 0;
|
|
$gzdata = "";
|
|
$gzsize = 0;
|
|
|
|
}
|
|
$fnl=strlen($filename);
|
|
$fh = "\x14\x00"; // ver needed to extract
|
|
$fh .= "\x00\x00"; // gen purpose bit flag
|
|
$fh .= "\x08\x00"; // compression method
|
|
$fh .= "\x00\x00\x00\x00"; // last mod time and date
|
|
$fh .=pack("V3v2",
|
|
$crc, //crc
|
|
$gzsize,//c size
|
|
$datasize,//unc size
|
|
$fnl, //fname lenght
|
|
0 //extra field length
|
|
);
|
|
|
|
|
|
//local file header
|
|
$lfh="PK\x03\x04";
|
|
$lfh .= $fh.$filename;
|
|
$zipdata = $lfh;
|
|
$zipdata .= $gzdata;
|
|
$zipdata .= pack("V3",$crc,$gzsize,$datasize);
|
|
$this->zipdata[]=$zipdata;
|
|
//Central Directory Record
|
|
$cdir="PK\x01\x02";
|
|
$cdir.=pack("va*v3V2",
|
|
0,
|
|
$fh,
|
|
0, // file comment length
|
|
0, // disk number start
|
|
0, // internal file attributes
|
|
$attr, // external file attributes - 'archive/directory' bit set
|
|
$this->offset
|
|
).$filename;
|
|
|
|
$this->offset+= 42+$fnl+$gzsize;
|
|
$this->cdir[]=$cdir;
|
|
$this->cnt++;
|
|
$this->idx = $this->cnt-1;
|
|
}
|
|
/** adds a file to the archive
|
|
@param str filename contains valid path to file to be stored in the arcive.
|
|
@param str storedasname the path under which the file will be stored to the archive. If empty, the file will be stored under path given by filename parameter
|
|
@see ss_zip::add_data()
|
|
*/
|
|
function add_file($filename, $storedasname=""){
|
|
$fh= fopen($filename,"r");
|
|
// print filesize($filename);
|
|
$data=fread($fh,filesize($filename));
|
|
if(!trim($storedasname))$storedasname=$filename;
|
|
return $this->add_data($storedasname, $data);
|
|
}
|
|
/** compile the arcive.
|
|
This function produces ZIP archive and returns it.
|
|
@return str string with zipfile
|
|
*/
|
|
function archive(){
|
|
if(!$this->zipdata) return "";
|
|
$zds=implode('',$this->zipdata);
|
|
$cds=implode('',$this->cdir);
|
|
$zdsl=strlen($zds);
|
|
$cdsl=strlen($cds);
|
|
$this->zipfile=
|
|
$zds
|
|
.$cds
|
|
."PK\x05\x06\x00\x00\x00\x00"
|
|
.pack('v2V2v'
|
|
,$this->cnt // total # of entries "on this disk"
|
|
,$this->cnt // total # of entries overall
|
|
,$cdsl // size of central dir
|
|
,$zdsl // offset to start of central dir
|
|
,0); // .zip file comment length
|
|
return $this->zipfile;
|
|
}
|
|
/** changes pointer to current entry.
|
|
Most likely you will always use it to 'rewind' the archive and then using read()
|
|
Checks for bopundaries, so will not allow index to be set to values < 0 ro > last element
|
|
@param int idx the new index to which you want to rewind the archive curent pointer
|
|
@return int idx the index to which the curent pointer was actually set
|
|
@see ss_zip::read()
|
|
*/
|
|
function seek_idx($idx){
|
|
if($idx<0)$idx=0;
|
|
if($idx>=$this->cnt)$idx=$this->cnt-1;
|
|
$this->idx=$idx;
|
|
return $idx;
|
|
}
|
|
/** Reads an entry from the arcive which is pointed by inner index pointer.
|
|
<center><hr nashade>*** This functionality is available in PRO version only. ***<br><a href='http://smiledsoft.com/demos/phpzip/' target='_blank'>please upgrade </a><hr nashade></center>
|
|
The curent index can be changed by seek_idx() method.
|
|
@return array Returns associative array of the following structure
|
|
<ul>
|
|
<li>'idx'=> index of the entry </li>
|
|
<li>'name'=>full path to the entry </li>
|
|
<li>'attr'=>integer file attribute of the entry </li>
|
|
<li>'attrstr'=>string file attribute of the entry <br>
|
|
This can be:
|
|
<ul>
|
|
<li>'file' if the integer attribute was 32</li>
|
|
<li>'dir' if the integer attribute was 16 or 48</li>
|
|
<li>'unknown' for other values</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
@see ss_zip::seek_idx()
|
|
*/
|
|
function read(){}
|
|
|
|
|
|
|
|
/** Removes entry from the archive.
|
|
please be very carefull with this function, there is no undo after you save the archive
|
|
@return bool true on success or false on failure
|
|
@param int idx
|
|
*/
|
|
function remove($idx){}
|
|
|
|
|
|
|
|
/** extracts data from the archive and return it as a string.
|
|
<center><hr nashade>*** This functionality is available in PRO version only. ***<br><a href='http://smiledsoft.com/demos/phpzip/' target='_blank'>please upgrade </a><hr nashade></center>
|
|
This function returns data identified by idx parameter.
|
|
@param int idx index of the entry
|
|
@return array returns associative array of the folloving structure:
|
|
<ul>
|
|
<li>'file' path under which the entry is stored in the archive</li>
|
|
<li>'data' In case if the entry was file, contain its data. For directory entry this is empty</li>
|
|
<li>'size' size of the data</li>
|
|
<li>'error' the error if any has happened. The bit 0 indicates incorect datasize, bit 1 indicates CRC error</li>
|
|
</ul>
|
|
@see ss_zip::extract_file
|
|
*/
|
|
function extract_data($idx){}
|
|
|
|
|
|
/** extracts the entry and creates it in the file system.
|
|
<center><hr nashade>*** This functionality is available in PRO version only. ***<br><a href='http://smiledsoft.com/demos/phpzip/' target='_blank'>please upgrade </a><hr nashade></center>
|
|
@param int idx Index of the entry
|
|
@param string path the first part of the path where the entry will be stored. So if this
|
|
is '/my/server/path' and entry is arhived/file/path/file.txt then the function will attempt to
|
|
store it under /my/server/path/arhived/file/path/file.txt You are responsible to ensure that you
|
|
have write permissions for this operation under your operation system.
|
|
*/
|
|
function extract_file($idx,$path="."){}
|
|
|
|
|
|
function _check_idx($idx){
|
|
return $idx>=0 and $idx<$this->cnt;
|
|
}
|
|
function _write($name,$data){
|
|
$fp=fopen($name,"w");
|
|
fwrite($fp,$data);
|
|
fclose($fp);
|
|
}
|
|
}
|
|
|
|
/** debug helper.
|
|
the only job for this function is take parameter $v and ouput it with print_r() preceding with < xmp > etc
|
|
The $l is a label like l=myvar
|
|
*/
|
|
function dbg($v,$l='var'){echo"<xmp>$l=";print_r($v);echo"</xmp>";}
|
|
?>
|