source: trunk/common/external_libs/zipfile.php @ 1184

Revision 1014, 7.0 KB checked in by alexthero, 3 years ago (diff)

Attachments of a page can now be downloaded as a ZIP file

Line 
1<?php 
2/*
3Zip file creation class
4makes zip files on the fly...
5
6use the functions add_dir() and add_file() to build the zip file;
7see example code below
8
9by Eric Mueller
10http://www.themepark.com
11
12v1.1 9-20-01
13  - added comments to example
14
15v1.0 2-5-01
16
17initial version with:
18  - class appearance
19  - add_file() and file() methods
20  - gzcompress() output hacking
21by Denis O.Philippov, webmaster@atlant.ru, http://www.atlant.ru
22
23*/ 
24
25// official ZIP file format: http://www.pkware.com/appnote.txt
26
27class zipfile   
28{   
29
30    var $datasec = array(); // array to store compressed data
31    var $ctrl_dir = array(); // central directory   
32    var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00"; //end of Central directory record
33    var $old_offset = 0; 
34
35    function add_dir($name)   
36
37    // adds "directory" to archive - do this before putting any files in directory!
38    // $name - name of directory... like this: "path/"
39    // ...then you can add files using add_file with names like "path/file.txt"
40    {   
41        $name = str_replace("\\", "/", $name);   
42
43        $fr = "\x50\x4b\x03\x04"; 
44        $fr .= "\x0a\x00";    // ver needed to extract
45        $fr .= "\x00\x00";    // gen purpose bit flag
46        $fr .= "\x00\x00";    // compression method
47        $fr .= "\x00\x00\x00\x00"; // last mod time and date
48
49        $fr .= pack("V",0); // crc32
50        $fr .= pack("V",0); //compressed filesize
51        $fr .= pack("V",0); //uncompressed filesize
52        $fr .= pack("v", strlen($name) ); //length of pathname
53        $fr .= pack("v", 0 ); //extra field length
54        $fr .= $name;   
55        // end of "local file header" segment
56
57        // no "file data" segment for path
58
59        // "data descriptor" segment (optional but necessary if archive is not served as file)
60        $fr .= pack("V",$crc); //crc32
61        $fr .= pack("V",$c_len); //compressed filesize
62        $fr .= pack("V",$unc_len); //uncompressed filesize
63
64        // add this entry to array
65        $this -> datasec[] = $fr; 
66
67        $new_offset = strlen(implode("", $this->datasec)); 
68
69        // ext. file attributes mirrors MS-DOS directory attr byte, detailed
70        // at http://support.microsoft.com/support/kb/articles/Q125/0/19.asp
71
72        // now add to central record
73        $cdrec = "\x50\x4b\x01\x02"; 
74        $cdrec .="\x00\x00";    // version made by
75        $cdrec .="\x0a\x00";    // version needed to extract
76        $cdrec .="\x00\x00";    // gen purpose bit flag
77        $cdrec .="\x00\x00";    // compression method
78        $cdrec .="\x00\x00\x00\x00"; // last mod time & date
79        $cdrec .= pack("V",0); // crc32
80        $cdrec .= pack("V",0); //compressed filesize
81        $cdrec .= pack("V",0); //uncompressed filesize
82        $cdrec .= pack("v", strlen($name) ); //length of filename
83        $cdrec .= pack("v", 0 ); //extra field length   
84        $cdrec .= pack("v", 0 ); //file comment length
85        $cdrec .= pack("v", 0 ); //disk number start
86        $cdrec .= pack("v", 0 ); //internal file attributes
87        $ext = "\x00\x00\x10\x00"; 
88        $ext = "\xff\xff\xff\xff";   
89        $cdrec .= pack("V", 16 ); //external file attributes  - 'directory' bit set
90
91        $cdrec .= pack("V", $this -> old_offset ); //relative offset of local header
92        $this -> old_offset = $new_offset; 
93
94        $cdrec .= $name;   
95        // optional extra field, file comment goes here
96        // save to array
97        $this -> ctrl_dir[] = $cdrec;   
98
99         
100    } 
101
102
103    function add_file($data, $name)   
104
105    // adds "file" to archive   
106    // $data - file contents
107    // $name - name of file in archive. Add path if your want
108
109    {   
110        $name = str_replace("\\", "/", $name);   
111        //$name = str_replace("\\", "\\\\", $name);
112
113        $fr = "\x50\x4b\x03\x04"; 
114        $fr .= "\x14\x00";    // ver needed to extract
115        $fr .= "\x00\x00";    // gen purpose bit flag
116        $fr .= "\x08\x00";    // compression method
117        $fr .= "\x00\x00\x00\x00"; // last mod time and date
118
119        $unc_len = strlen($data);   
120        $crc = crc32($data);   
121        $zdata = gzcompress($data);   
122        $zdata = substr( substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug
123        $c_len = strlen($zdata);   
124        $fr .= pack("V",$crc); // crc32
125        $fr .= pack("V",$c_len); //compressed filesize
126        $fr .= pack("V",$unc_len); //uncompressed filesize
127        $fr .= pack("v", strlen($name) ); //length of filename
128        $fr .= pack("v", 0 ); //extra field length
129        $fr .= $name;   
130        // end of "local file header" segment
131         
132        // "file data" segment
133        $fr .= $zdata;   
134
135        // "data descriptor" segment (optional but necessary if archive is not served as file)
136        $fr .= pack("V",$crc); //crc32
137        $fr .= pack("V",$c_len); //compressed filesize
138        $fr .= pack("V",$unc_len); //uncompressed filesize
139
140        // add this entry to array
141        $this -> datasec[] = $fr; 
142
143        $new_offset = strlen(implode("", $this->datasec)); 
144
145        // now add to central directory record
146        $cdrec = "\x50\x4b\x01\x02"; 
147        $cdrec .="\x00\x00";    // version made by
148        $cdrec .="\x14\x00";    // version needed to extract
149        $cdrec .="\x00\x00";    // gen purpose bit flag
150        $cdrec .="\x08\x00";    // compression method
151        $cdrec .="\x00\x00\x00\x00"; // last mod time & date
152        $cdrec .= pack("V",$crc); // crc32
153        $cdrec .= pack("V",$c_len); //compressed filesize
154        $cdrec .= pack("V",$unc_len); //uncompressed filesize
155        $cdrec .= pack("v", strlen($name) ); //length of filename
156        $cdrec .= pack("v", 0 ); //extra field length   
157        $cdrec .= pack("v", 0 ); //file comment length
158        $cdrec .= pack("v", 0 ); //disk number start
159        $cdrec .= pack("v", 0 ); //internal file attributes
160        $cdrec .= pack("V", 32 ); //external file attributes - 'archive' bit set
161
162        $cdrec .= pack("V", $this -> old_offset ); //relative offset of local header
163//        echo "old offset is ".$this->old_offset.", new offset is $new_offset<br>";
164        $this -> old_offset = $new_offset; 
165
166        $cdrec .= $name;   
167        // optional extra field, file comment goes here
168        // save to central directory
169        $this -> ctrl_dir[] = $cdrec;   
170    } 
171
172    function file() { // dump out file   
173        $data = implode("", $this -> datasec);   
174        $ctrldir = implode("", $this -> ctrl_dir);   
175
176        return   
177            $data.   
178            $ctrldir.   
179            $this -> eof_ctrl_dir.   
180            pack("v", sizeof($this -> ctrl_dir)).     // total # of entries "on this disk"
181            pack("v", sizeof($this -> ctrl_dir)).     // total # of entries overall
182            pack("V", strlen($ctrldir)).             // size of central dir
183            pack("V", strlen($data)).                 // offset to start of central dir
184            "\x00\x00";                             // .zip file comment length
185    } 
186}   
187
188?>
Note: See TracBrowser for help on using the repository browser.