Location: PHPKode > projects > WEB-PA > spider/include/classes/zipfile.class.php
<?php
/****************************************************************/
/* ATutor														*/
/****************************************************************/
/* Copyright (c) 2002-2004 by Greg Gay & Joel Kronenberg        */
/* Adaptive Technology Resource Centre / University of Toronto  */
/* http://atutor.ca												*/
/*                                                              */
/* This program is free software. You can redistribute it and/or*/
/* modify it under the terms of the GNU General Public License  */
/* as published by the Free Software Foundation.				*/
/****************************************************************/
// $Id: zipfile.class.php,v 1.1.1.1 2007/10/30 10:30:59 cleoni Exp $

/* 

for the specs:
http://www.pkware.com/products/enterprise/white_papers/appnote.html

*/ 

class zipfile
{
	var $files_data;
	var $central_directory_headers;
	var $num_entries = 0;

	var $zip_file;

	var $is_closed; // private

	function zipfile() {
		$this->files_data = '';
		$this->central_directory_headers = '';
		$this->num_entries = 0;
		$this->is_closed = false;
	}

	/* public interface to adding a dir and its contents recursively */
	/* $dir: the real system directory that contains the files to add to the zip */
	/* $zip_prefix_dir: the zip dir where the contents of $dir will be put in */
	/* $pre_pend_dir: used during the recursion to keep track of the path */
	function add_dir ( $dir, $zip_prefix_dir, $pre_pend_dir='' ) {
		if (!($dh = @opendir($dir.$pre_pend_dir))) {
			echo 'cant open dir: '.$dir.$pre_pend_dir;
			exit;
		}

		while (($file = readdir($dh)) !== false) {
			/* skip directories */
			if ($file == '.' || $file == '..') {
				continue;
			}
			/* skip potential harmful files/directories */
			if ( (strpos($file, '..') !== false) || (strpos($file, '/') !== false)) {
				continue;
			}

			$file_info = stat( $dir . $pre_pend_dir . $file );

			if (is_dir( $dir . $pre_pend_dir . $file )) {
				/* create this dir in the zip */
				$this->priv_add_dir( $zip_prefix_dir . $pre_pend_dir . $file . '/',
									 $file_info['mtime'] );

				/* continue recursion, going down this dir */
				$this->add_dir(	$dir,
								$zip_prefix_dir,
								$pre_pend_dir . $file . '/' );

			} else {
				/* add this file to the zip */
				$this-> add_file( file_get_contents($dir . $pre_pend_dir . $file),
								  $zip_prefix_dir . $pre_pend_dir . $file,
								  $file_info['mtime'] );
			}
		}
		closedir($dh);
	}

	// private add_dir
    function priv_add_dir($name, $timestamp = '')    
    {   
        $name = str_replace("\\", "/", $name);   
		$old_offset = strlen($this->files_data);

        $local_file_header  = "\x50\x4b\x03\x04";												// local file header signature 4 bytes (0x04034b50) 
        $local_file_header .= "\x0a\x00";    // ver needed to extract							// version needed to extract 2 bytes
        $local_file_header .= "\x00\x00";    // gen purpose bit flag							// general purpose bit flag 2 bytes
        $local_file_header .= "\x00\x00";    // compression method								// compression method 2 bytes
        $local_file_header .= "\x00\x00\x00\x00"; // last mod time and date					// last mod file time 2 bytes & last mod file date 2 bytes 
        $local_file_header .= pack("V",0); // crc32											// crc-32 4 bytes
        $local_file_header .= pack("V",0); //compressed filesize								// compressed size 4 bytes 
        $local_file_header .= pack("V",0); //uncompressed filesize								// uncompressed size 4 bytes
        $local_file_header .= pack("v", strlen($name) ); //length of pathname					// file name length 2 bytes 
        $local_file_header .= pack("v", 0 ); //extra field length								// extra field length 2 bytes		
        $local_file_header .= $name;															// file name (variable size)  & extra field (variable size)
        // end of "local file header" segment 

        // no "file data" segment for path 

        // add this entry to array 
        $this->files_data .= $local_file_header;

        // ext. file attributes mirrors MS-DOS directory attr byte, detailed 
        // at http://support.microsoft.com/support/kb/articles/Q125/0/19.asp 

		if ($timestamp) {
			$v_date = getdate($timestamp);
		} else {
			$v_date = getdate();
		}
		$time = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
		$date = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];

        // now add to central record 
        $central_directory = "\x50\x4b\x01\x02";											// central file header signature 4 bytes (0x02014b50)
        $central_directory .="\x14\x00";    // version made by								// version made by 2 bytes
        $central_directory .="\x14\x00";    // version needed to extract					// version needed to extract 2 bytes
        $central_directory .="\x00\x00";    // gen purpose bit flag							// general purpose bit flag 2 bytes
        $central_directory .="\x00\x00";    // compression method							// compression method 2 bytes
		$central_directory .= pack("v",$time); // time										// last mod file time 2 bytes
        $central_directory .= pack("v",$date); // date										// last mod file date 2 bytes
        $central_directory .= pack("V", 0); // crc32										// crc-32 4 bytes
        $central_directory .= pack("V", 0); // compressed filesize							// compressed size 4 bytes
        $central_directory .= pack("V", 0); // uncompressed filesize						// uncompressed size 4 bytes
        $central_directory .= pack("v", strlen($name) ); //length of filename				// file name length 2 bytes
        $central_directory .= pack("v", 0); // extra field length							// extra field length 2 bytes
        $central_directory .= pack("v", 0); // file comment length							// file comment length 2 bytes 
        $central_directory .= pack("v", 0); // disk number start							// disk number start 2 bytes
        $central_directory .= pack("v", 0); // internal file attributes						// internal file attributes 2 bytes
        $central_directory .= pack("V", 16+32); //external file attributes  - 'directory' 'archive' bit set // external file attributes 4 bytes
        $central_directory .= pack("V", $old_offset); //relative offset of local header // relative offset of local header 4 bytes
        $central_directory .= $name;														// file name (variable size)

    	$this->central_directory_headers .= $central_directory;

		$this->num_entries++;
    } 

	// public interface to create a directory in the zip file
	function create_dir($name, $timestamp='') {
		$name = trim($name);

		if (substr($name, -1) != '/') {
			/* add the trailing slash */
			$name .= '/';
		}
		$this->priv_add_dir($name, $timestamp = '');
	}

    // adds "file" to archive    
    // $data - file contents 
    // $name - name of file in archive. Add path if your want 
    function add_file($file_data, $name, $timestamp = '')    
    {
        $name = str_replace("\\", "/", $name);   
        $crc = crc32($file_data);
        $uncompressed_size = strlen($file_data);
		$file_data = substr(gzcompress($file_data, 9), 2, -4);
        $compressed_size = strlen($file_data);
		$old_offset = strlen($this->files_data);

		/* local file header */
        $local_file_header = "\x50\x4b\x03\x04";								// local file header signature 4 bytes (0x04034b50) 
        $local_file_header .= "\x14\x00";    // ver needed to extract			// version needed to extract 2 bytes 
        $local_file_header .= "\x00\x00";    // gen purpose bit flag			// general purpose bit flag 2 bytes 
        $local_file_header .= "\x08\x00";    // compression method				// compression method 2 bytes 
        $local_file_header .= "\x00\x00\x00\x00"; // last mod time and date	// last mod file time 2 bytes & last mod file date 2 bytes 
        $local_file_header .= pack("V",$crc); // crc32							// crc-32 4 bytes 
        $local_file_header .= pack("V",$compressed_size); //compressed filesize			// compressed size 4 bytes 
        $local_file_header .= pack("V",$uncompressed_size); //uncompressed filesize		// uncompressed size 4 bytes 
        $local_file_header .= pack("v", strlen($name) ); //length of filename  // file name length 2 bytes 
        $local_file_header .= "\x00\x00"; //extra field length				// extra field length 2 bytes 
        $local_file_header .= $name;											// file name (variable size)  & extra field (variable size) 
		/* end of local file header */
          
		$this->files_data .= $local_file_header . $file_data; // . $data_descriptor;;

		/* create the central directory */
		$central_directory = '';
		if ($timestamp) {
			$v_date = getdate($timestamp);
		} else {
			$v_date = getdate();
		}
		$time = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
		$date = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];

        // now add to central directory record 
        $central_directory = "\x50\x4b\x01\x02";											// central file header signature 4 bytes (0x02014b50)
        $central_directory .="\x14\x00";    // version made by								// version made by 2 bytes 
        $central_directory .="\x14\x00";    // version needed to extract					// version needed to extract 2 bytes 
        $central_directory .="\x00\x00";    // gen purpose bit flag							// general purpose bit flag 2 bytes 
        $central_directory .="\x08\x00";    // compression method							// compression method 2 bytes         
        $central_directory .= pack("v",$time); // time										// last mod file time 2 bytes 
		$central_directory .= pack("v",$date); // date										// last mod file date 2 bytes 
		$central_directory .= pack("V",$crc); // crc32										// crc-32 4 bytes 
        $central_directory .= pack("V",$compressed_size); //compressed filesize						// compressed size 4 bytes 
        $central_directory .= pack("V",$uncompressed_size); //uncompressed filesize					// uncompressed size 4 bytes 
        $central_directory .= pack("v", strlen($name) ); //length of filename				// file name length 2 bytes 
        $central_directory .= "\x00\x00"; //extra field length							// extra field length 2 bytes 
        $central_directory .= "\x00\x00"; //file comment length							// file comment length 2 bytes 
        $central_directory .= "\x00\x00"; //disk number start							// disk number start 2 bytes 
        $central_directory .= "\x00\x00"; //internal file attributes						// internal file attributes 2 bytes 
        $central_directory .= pack("V", 32); //external file attributes - 'archive' bit set // external file attributes 4 bytes 
		$central_directory .= pack("V", $old_offset);

        $central_directory .= $name;														// file name (variable size)

		$this->central_directory_headers .= $central_directory;
	
		$this->num_entries++;
    } 

	function close() {
		$this->files_data .= $this->central_directory_headers . "\x50\x4b\x05\x06\x00\x00\x00\x00" .   
            pack("v", $this->num_entries).     // total # of entries "on this disk" 
            pack("v", $this->num_entries).     // total # of entries overall 
            pack("V", strlen($this->central_directory_headers)).             // size of central dir 
            pack("V", strlen($this->files_data)).                 // offset to start of central dir 
            "\x00\x00"; 

		unset($this->central_directory_headers);
		unset($this->num_entries);

		$this->zip_file =& $this->files_data;
		$this->is_closed = true;
	}

	// only call this after calling close()
	// return false if the zip wasn't close()d yet
	function get_size() {
		if (!$this->is_closed) {
			return false;
		}
		return strlen($this->zip_file);
	}

    function get_file() {
		return $this->zip_file;
    }

	function send_file($file_name) {
		if (!$this->is_closed) {
			$this->close();
		}
		$file_name = str_replace(array('"', '<', '>'), '', $file_name);

		header('Content-Type: application/octet-stream');
		header('Content-transfer-encoding: binary'); 
		header('Content-Disposition: attachment; filename="'.escapeshellcmd(htmlspecialchars($file_name)).'.zip"');
		header('Expires: 0');
		header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
		header('Pragma: public');
		header('Content-Length: '.$this->get_size());

		echo $this->get_file();

		exit;
	}
}

?>
Return current item: WEB-PA