summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpabs <pabs@pablotron.org>2007-08-23 03:17:11 -0400
committerpabs <pabs@pablotron.org>2007-08-23 03:17:11 -0400
commitc3a6497713aa6fd6ba90540f734cad25fbcbb23a (patch)
tree752c29798b811649124ae584d12e41dbf758c68f
parent86382ea71cf242b15efd86b6bc2555ede8f451c0 (diff)
downloadzipstream-php-c3a6497713aa6fd6ba90540f734cad25fbcbb23a.tar.bz2
zipstream-php-c3a6497713aa6fd6ba90540f734cad25fbcbb23a.zip
api cleanup. added full documentation.
-rw-r--r--zipstream.php216
1 files changed, 162 insertions, 54 deletions
diff --git a/zipstream.php b/zipstream.php
index 9323569..39173ec 100644
--- a/zipstream.php
+++ b/zipstream.php
@@ -6,27 +6,96 @@
#
# Usage:
#
+# Streaming zip archives is a simple, three-step process:
+#
+# 1. Create the zip stream:
+#
+# $zip = new ZipStream('example.zip');
+#
+# 2. Add one or more files to the archive:
+#
+# # add first file
+# $data = file_get_contents('some_file.gif');
+# $zip->add_file('some_file.gif', $data);
+#
+# # add second file
+# $data = file_get_contents('some_file.gif');
+# $zip->add_file('another_file.png', $data);
+#
+# 3. Finish the zip stream:
+#
+# $zip->finish();
+#
+# You can also add an archive comment, add comments to individual files,
+# and adjust the timestamp of files. See the API documentation below
+# for additional information.
+#
+# Example:
+#
# # create a new zip stream object
-# $zs = new ZipStream();
+# $zip = new ZipStream('some_files.zip');
#
# # list of local files
# $files = array('foo.txt', 'bar.jpg');
#
# # read and add each file to the archive
# foreach ($files as $path)
-# $zs->add_file($path, file_get_contents($path));
+# $zip->add_file($path, file_get_contents($path));
#
# # write archive footer to stream
-# $zs->finish();
+# $zip->finish();
#
class ZipStream {
- var $files = array(),
+ var $opt = array(),
+ $files = array(),
$cdr_ofs = 0,
$ofs = 0;
- function ZipStream($name = 'untitled.zip', $send_http_headers = false) {
+ #
+ # Create a new ZipStream object.
+ #
+ # Parameters:
+ #
+ # $name - Name of output file (optional).
+ # $opt - Hash of archive options (optional, see "Archive Options"
+ # below).
+ #
+ # Archive Options:
+ #
+ # comment - Comment for this archive.
+ # content_type - HTTP Content-Type. Defaults to 'application/x-zip'.
+ # content_disposition - HTTP Content-Disposition. Defaults to
+ # 'attachment; filename=\"FILENAME\"', where
+ # FILENAME is the specified filename.
+ # send_http_headers - Boolean indicating whether or not to send
+ # the HTTP headers for this file.
+ #
+ # Note that content_type and content_disposition do nothing if you are
+ # not sending HTTP headers.
+ #
+ # Examples:
+ #
+ # # create a new zip file named 'foo.zip'
+ # $zip = new ZipStream('foo.zip');
+ #
+ # # create a new zip file named 'bar.zip' with a comment
+ # $zip = new ZipStream('bar.zip', array(
+ # 'comment' => 'this is a comment for the zip file.',
+ # ));
+ #
+ # Notes:
+ #
+ # If you do not set a filename, then this library _DOES NOT_ send HTTP
+ # headers by default. This behavior is to allow software to send its
+ # own headers (including the filename), and still use this library.
+ #
+ function ZipStream($name = null, $opt = array()) {
+ # save options
+ $this->opt = $opt;
+
$this->output_name = $name;
- $this->need_headers = $send_http_headers;
+ if ($name || $opt['send_http_headers'])
+ $this->need_headers = true;
}
#
@@ -36,16 +105,30 @@ class ZipStream {
#
# $name - path of file in archive (including directory).
# $data - contents of file
- # $time - last-modified timestamp of file (optional)
+ # $opt - Hash of options for file (optional, see "File Options"
+ # below).
#
- # Example:
+ # File Options:
+ # time - Last-modified timestamp (seconds since the epoch) of
+ # this file. Defaults to the current time.
+ # comment - Comment related to this file.
+ #
+ # Examples:
#
+ # # add a file named 'foo.txt'
# $data = file_get_contents('foo.txt');
- # $zs->add_file('foo.txt', $data);
+ # $zip->add_file('foo.txt', $data);
#
- function add_file($name, $data, $time = 0) {
+ # # add a file named 'bar.jpg' with a comment and a last-modified
+ # # time of two hours ago
+ # $data = file_get_contents('bar.jpg');
+ # $zip->add_file('bar.jpg', $data, array(
+ # 'time' => time() - 2 * 3600,
+ # 'comment' => 'this is a comment about bar.jpg',
+ # ));
+ #
+ function add_file($name, $data, $opt = array()) {
# compress data
- # $zdata = substr(gzcompress($data), 2, -4);
$zdata = gzdeflate($data);
# calculate header attributes
@@ -55,8 +138,8 @@ class ZipStream {
$len = strlen($data);
# create dos timestamp
- $time = $time ? $time : time();
- $dts = $this->dostime($time);
+ $opt['time'] = $opt['time'] ? $opt['time'] : time();
+ $dts = $this->dostime($opt['time']);
# build file header
$fields = array( # (from V.A of APPNOTE.TXT)
@@ -76,7 +159,7 @@ class ZipStream {
$ret = $this->pack_fields($fields) . $name . $zdata;
# add to central directory record and increment offset
- $this->add_to_cdr($name, $time, $crc, $zlen, $len, strlen($ret));
+ $this->add_to_cdr($name, $opt, $crc, $zlen, $len, strlen($ret));
# print data
$this->send($ret);
@@ -90,63 +173,55 @@ class ZipStream {
# # add a list of files to the archive
# $files = array('foo.txt', 'bar.jpg');
# foreach ($files as $path)
- # $zs->add_file($path, file_get_contents($path));
+ # $zip->add_file($path, file_get_contents($path));
#
# # write footer to stream
- # $zs->finish();
+ # $zip->finish();
#
- function finish($opt = null) {
- $this->add_cdr($opt);
+ function finish() {
+ $this->add_cdr($this->opt);
$this->clear();
}
- function send_http_headers($name = 'untitled.zip') {
- $headers = array(
- 'Content-Type' => 'application/x-zip',
- 'Content-Disposition' => "attachment; filename=\"{$name}\"",
- 'Pragma' => 'public',
- 'Cache-Control' => 'public, must-revalidate',
- 'Content-Transfer-Encoding' => 'binary',
- );
-
- foreach ($headers as $key => $val)
- header("$key: $val");
- }
-
###################
# PRIVATE METHODS #
###################
- function add_to_cdr($name, $time, $crc, $zlen, $len, $rec_len) {
- $this->files[] = array($name, $time, $crc, $zlen, $len, $this->ofs);
+ function add_to_cdr($name, $opt, $crc, $zlen, $len, $rec_len) {
+ $this->files[] = array($name, $opt, $crc, $zlen, $len, $this->ofs);
$this->ofs += $rec_len;
}
function add_cdr_file($args) {
- list ($name, $time, $crc, $zlen, $len, $ofs) = $args;
- $dts = $this->dostime($time);
+ list ($name, $opt, $crc, $zlen, $len, $ofs) = $args;
+
+ # get attributes
+ $comment = $opt['comment'] ? $opt['comment'] : '';
+
+ # get dos timestamp
+ $dts = $this->dostime($opt['time']);
$fields = array( # (from V,F of APPNOTE.TXT)
- array('V', 0x02014b50), # central file header signature
- array('v', 0x00), # version made by
- array('v', 0x14), # version needed to extract
- array('v', 0x00), # general purpose bit flag
- array('v', 0x08), # compresion method (deflate)
- array('V', $dts), # dos timestamp
- array('V', $crc), # crc32 of data
- array('V', $zlen), # compressed data length
- array('V', $len), # uncompressed data length
- array('v', strlen($name)), # filename length
- array('v', 0), # extra data len
- array('v', 0), # file comment length
- array('v', 0), # disk number start
- array('v', 0), # internal file attributes
- array('V', 32), # external file attributes
- array('V', $ofs), # relative offset of local header
+ array('V', 0x02014b50), # central file header signature
+ array('v', 0x00), # version made by
+ array('v', 0x14), # version needed to extract
+ array('v', 0x00), # general purpose bit flag
+ array('v', 0x08), # compresion method (deflate)
+ array('V', $dts), # dos timestamp
+ array('V', $crc), # crc32 of data
+ array('V', $zlen), # compressed data length
+ array('V', $len), # uncompressed data length
+ array('v', strlen($name)), # filename length
+ array('v', 0), # extra data len
+ array('v', strlen($comment)), # file comment length
+ array('v', 0), # disk number start
+ array('v', 0), # internal file attributes
+ array('V', 32), # external file attributes
+ array('V', $ofs), # relative offset of local header
);
- # pack fields and append name
- $ret = $this->pack_fields($fields) . $name;
+ # pack fields, then append name and comment
+ $ret = $this->pack_fields($fields) . $name . $comment;
$this->send($ret);
@@ -191,9 +266,42 @@ class ZipStream {
$this->cdr_ofs = 0;
}
+ ###########################
+ # PRIVATE UTILITY METHODS #
+ ###########################
+
+ function send_http_headers() {
+ # grab options
+ $opt = $this->opt;
+
+ # grab content type from options
+ $content_type = 'application/x-zip',
+ if ($opt['content_type'])
+ $content_type = $this->opt['content_type'];
+
+ # grab content disposition
+ $disposition = 'attachment';
+ if ($opt['content_disposition'])
+ $disposition = $opt['content_disposition'];
+
+ if ($this->output_name)
+ $disposition .= "; filename=\"{$this->output_name}\"";
+
+ $headers = array(
+ 'Content-Type' => $content_type,
+ 'Content-Disposition' => $disposition,
+ 'Pragma' => 'public',
+ 'Cache-Control' => 'public, must-revalidate',
+ 'Content-Transfer-Encoding' => 'binary',
+ );
+
+ foreach ($headers as $key => $val)
+ header("$key: $val");
+ }
+
function send($str) {
if ($this->need_headers)
- $this->send_http_headers($this->output_name);
+ $this->send_http_headers();
$this->need_headers = false;
echo $str;