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>";}
							 | 
						||
| 
								 | 
							
								?>
							 |