| 1 | <?php |
|---|
| 2 | /* |
|---|
| 3 | Zip file creation class |
|---|
| 4 | makes zip files on the fly... |
|---|
| 5 | |
|---|
| 6 | use the functions add_dir() and add_file() to build the zip file; |
|---|
| 7 | see example code below |
|---|
| 8 | |
|---|
| 9 | by Eric Mueller |
|---|
| 10 | http://www.themepark.com |
|---|
| 11 | |
|---|
| 12 | v1.1 9-20-01 |
|---|
| 13 | - added comments to example |
|---|
| 14 | |
|---|
| 15 | v1.0 2-5-01 |
|---|
| 16 | |
|---|
| 17 | initial version with: |
|---|
| 18 | - class appearance |
|---|
| 19 | - add_file() and file() methods |
|---|
| 20 | - gzcompress() output hacking |
|---|
| 21 | by 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 | |
|---|
| 27 | class 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 | ?> |
|---|