From a065bab0fb0fdd6c0012db137ab8e065b131a2e9 Mon Sep 17 00:00:00 2001
From: Derek Allard
Date: Tue, 13 May 2008 13:31:18 +0000
Subject: The Zip class has undergone a substantial re-write for speed and
clarity
---
system/libraries/Zip.php | 221 +++++++++++++++++++++-------------------------
user_guide/changelog.html | 1 +
2 files changed, 102 insertions(+), 120 deletions(-)
diff --git a/system/libraries/Zip.php b/system/libraries/Zip.php
index 97695a07f..ed476ab48 100644
--- a/system/libraries/Zip.php
+++ b/system/libraries/Zip.php
@@ -32,9 +32,10 @@
*/
class CI_Zip {
- var $zipfile = '';
- var $zipdata = array();
- var $directory = array();
+ var $zipdata = '';
+ var $directory = '';
+ var $entries = 0;
+ var $file_num = 0;
var $offset = 0;
function CI_Zip()
@@ -61,7 +62,7 @@ class CI_Zip {
{
$dir .= '/';
}
-
+
$this->_add_dir($dir);
}
}
@@ -78,35 +79,36 @@ class CI_Zip {
function _add_dir($dir)
{
$dir = str_replace("\\", "/", $dir);
-
- $this->zipdata[] = "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- .pack('V', 0)
- .pack('V', 0)
- .pack('V', 0)
- .pack('v', strlen($dir))
- .pack('v', 0)
- .$dir
- .pack('V', 0)
- .pack('V', 0)
- .pack('V', 0);
-
- $newoffset = strlen(implode('', $this->zipdata));
-
- $record = "\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- .pack('V',0)
- .pack('V',0)
- .pack('V',0)
- .pack('v', strlen($dir))
- .pack('v', 0)
- .pack('v', 0)
- .pack('v', 0)
- .pack('v', 0)
- .pack('V', 16)
- .pack('V', $this->offset)
- .$dir;
-
- $this->offset = $newoffset;
- $this->directory[] = $record;
+
+ $this->zipdata .=
+ "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ .pack('V', 0) // crc32
+ .pack('V', 0) // compressed filesize
+ .pack('V', 0) // uncompressed filesize
+ .pack('v', strlen($dir)) // length of pathname
+ .pack('v', 0) // extra field length
+ .$dir
+ // below is "data descriptor" segment
+ .pack('V', 0) // crc32
+ .pack('V', 0) // compressed filesize
+ .pack('V', 0); // uncompressed filesize
+
+ $this->directory .=
+ "\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ .pack('V',0) // crc32
+ .pack('V',0) // compressed filesize
+ .pack('V',0) // uncompressed filesize
+ .pack('v', strlen($dir)) // length of pathname
+ .pack('v', 0) // extra field length
+ .pack('v', 0) // file comment length
+ .pack('v', 0) // disk number start
+ .pack('v', 0) // internal file attributes
+ .pack('V', 16) // external file attributes - 'directory' bit set
+ .pack('V', $this->offset) // relative offset of local header
+ .$dir;
+
+ $this->offset = strlen($this->zipdata);
+ $this->entries++;
}
// --------------------------------------------------------------------
@@ -137,7 +139,7 @@ class CI_Zip {
$this->_add_data($filepath, $data);
}
}
-
+
// --------------------------------------------------------------------
/**
@@ -149,41 +151,43 @@ class CI_Zip {
* @return void
*/
function _add_data($filepath, $data)
- {
+ {
$filepath = str_replace("\\", "/", $filepath);
-
- $oldlen = strlen($data);
- $crc32 = crc32($data);
-
+
+ $uncompressed_size = strlen($data);
+ $crc32 = crc32($data);
+
$gzdata = gzcompress($data);
$gzdata = substr($gzdata, 2, -4);
- $newlen = strlen($gzdata);
-
- $this->zipdata[] = "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00\x00\x00\x00\x00"
- .pack('V', $crc32)
- .pack('V', $newlen)
- .pack('V', $oldlen)
- .pack('v', strlen($filepath))
- .pack('v', 0)
- .$filepath
- .$gzdata;
-
- $newoffset = strlen(implode("", $this->zipdata));
-
- $record = "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00\x00\x00\x00\x00"
- .pack('V', $crc32)
- .pack('V', $newlen)
- .pack('V', $oldlen)
- .pack('v', strlen($filepath))
- .pack('v', 0)
- .pack('v', 0)
- .pack('v', 0)
- .pack('v', 0)
- .pack('V', 32)
- .pack('V', $this->offset);
-
- $this->offset = $newoffset;
- $this->directory[] = $record.$filepath;
+ $compressed_size = strlen($gzdata);
+
+ $this->zipdata .=
+ "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00\x00\x00\x00\x00"
+ .pack('V', $crc32)
+ .pack('V', $compressed_size)
+ .pack('V', $uncompressed_size)
+ .pack('v', strlen($filepath)) // length of filename
+ .pack('v', 0) // extra field length
+ .$filepath
+ .$gzdata; // "file data" segment
+
+ $this->directory .=
+ "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00\x00\x00\x00\x00"
+ .pack('V', $crc32)
+ .pack('V', $compressed_size)
+ .pack('V', $uncompressed_size)
+ .pack('v', strlen($filepath)) // length of filename
+ .pack('v', 0) // extra field length
+ .pack('v', 0) // file comment length
+ .pack('v', 0) // disk number start
+ .pack('v', 0) // internal file attributes
+ .pack('V', 32) // external file attributes - 'archive' bit set
+ .pack('V', $this->offset) // relative offset of local header
+ .$filepath;
+
+ $this->offset = strlen($this->zipdata);
+ $this->entries++;
+ $this->file_num++;
}
// --------------------------------------------------------------------
@@ -200,7 +204,7 @@ class CI_Zip {
{
return FALSE;
}
-
+
if (FALSE !== ($data = file_get_contents($path)))
{
$name = str_replace("\\", "/", $path);
@@ -209,7 +213,7 @@ class CI_Zip {
{
$name = preg_replace("|.*/(.+)|", "\\1", $name);
}
-
+
$this->add_data($name, $data);
return TRUE;
}
@@ -261,30 +265,21 @@ class CI_Zip {
*/
function get_zip()
{
- // We cache the zip data so multiple calls
- // do not require recompiling
- if ($this->zipfile != '')
- {
- return $this->zipfile;
- }
-
// Is there any data to return?
- if (count($this->zipdata) == 0)
+ if ($this->entries == 0)
{
return FALSE;
}
-
- $data = implode('', $this->zipdata);
- $dir = implode('', $this->directory);
-
- $this->zipfile = $data.$dir."\x50\x4b\x05\x06\x00\x00\x00\x00"
- .pack('v', sizeof($this->directory))
- .pack('v', sizeof($this->directory))
- .pack('V', strlen($dir))
- .pack('V', strlen($data))
- ."\x00\x00";
-
- return $this->zipfile;
+
+ $zip_data = $this->zipdata;
+ $zip_data .= $this->directory."\x50\x4b\x05\x06\x00\x00\x00\x00";
+ $zip_data .= pack('v', $this->entries); // total # of entries "on this disk"
+ $zip_data .= pack('v', $this->entries); // total # of entries overall
+ $zip_data .= pack('V', strlen($this->directory)); // size of central dir
+ $zip_data .= pack('V', strlen($this->zipdata)); // offset to start of central dir
+ $zip_data .= "\x00\x00"; // .zip file comment length
+
+ return $zip_data;
}
// --------------------------------------------------------------------
@@ -305,7 +300,7 @@ class CI_Zip {
{
return FALSE;
}
-
+
flock($fp, LOCK_EX);
fwrite($fp, $this->get_zip());
flock($fp, LOCK_UN);
@@ -323,35 +318,20 @@ class CI_Zip {
* @param string the file name
* @param string the data to be encoded
* @return bool
- */
+ */
function download($filename = 'backup.zip')
{
- if ( ! preg_match("|.+?\.zip$|", $filename))
- {
- $filename .= '.zip';
- }
-
- if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE"))
- {
- header('Content-Type: application/x-zip');
- header('Content-Disposition: inline; filename="'.$filename.'"');
- header('Expires: 0');
- header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
- header("Content-Transfer-Encoding: binary");
- header('Pragma: public');
- header("Content-Length: ".strlen($this->get_zip()));
- }
- else
- {
- header('Content-Type: application/x-zip');
- header('Content-Disposition: attachment; filename="'.$filename.'"');
- header("Content-Transfer-Encoding: binary");
- header('Expires: 0');
- header('Pragma: no-cache');
- header("Content-Length: ".strlen($this->get_zip()));
- }
-
- exit($this->get_zip());
+ if ( ! preg_match("|.+?\.zip$|", $filename))
+ {
+ $filename .= '.zip';
+ }
+
+ $zip_content =& $this->get_zip();
+
+ $CI =& get_instance();
+ $CI->load->helper('download');
+
+ force_download($filename, $zip_content);
}
// --------------------------------------------------------------------
@@ -367,10 +347,11 @@ class CI_Zip {
*/
function clear_data()
{
- $this->zipfile = '';
- $this->zipdata = array();
- $this->directory = array();
- $this->offset = array();
+ $this->zipdata = '';
+ $this->directory = '';
+ $this->entries = 0;
+ $this->file_num = 0;
+ $this->offset = 0;
}
}
diff --git a/user_guide/changelog.html b/user_guide/changelog.html
index 3d0772147..ffa400ca8 100644
--- a/user_guide/changelog.html
+++ b/user_guide/changelog.html
@@ -97,6 +97,7 @@ SVN Revision: 1145
Unit Testing results are now colour coded, and a change was made to the default template of results.
Added a valid_emails rule to the Validation class.
The Zip class now exits within download().
+ The Zip class has undergone a substantial re-write for speed and clarity (thanks stanleyxu for the hard work and code contribution!)
Helpers
--
cgit v1.2.3-24-g4f1b