00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 ##############################################################
00016 # Class dUnzip2 v2.4
00017 #
00018 # Author: Alexandre Tedeschi (d)
00019 # E-Mail: alexandrebr at gmail dot com
00020 # Londrina - PR / Brazil
00021 #
00022 # Objective:
00023 # This class allows programmer to easily unzip files on the fly.
00024 #
00025 # Requirements:
00026 # This class requires extension ZLib Enabled. It is default
00027 # for most site hosts around the world, and for the PHP Win32 dist.
00028 #
00029 # To do:
00030 # * Error handling
00031 # * Write a PHP-Side gzinflate, to completely avoid any external extensions
00032 # * Write other decompress algorithms
00033 #
00034 # If you modify this class, or have any ideas to improve it, please contact me!
00035 # You are allowed to redistribute this class, if you keep my name and contact e-mail on it.
00036 ##############################################################
00037
00038 class ArchiveUnzip{
00039
00040
00041 var $files = array();
00042 var $value = '';
00043 var $fileName;
00044 var $compressedList;
00045 var $centralDirList;
00046 var $endOfCentral;
00047 var $debug;
00048
00049
00050 var $fh;
00051 var $zipSignature = "\x50\x4b\x03\x04";
00052 var $dirSignature = "\x50\x4b\x01\x02";
00053 var $dirSignatureE= "\x50\x4b\x05\x06";
00054
00055
00056 Function ArchiveUnzip()
00057 {
00058 $this->compressedList =
00059 $this->centralDirList =
00060 $this->endOfCentral = Array();
00061 }
00062
00063 function open( $value )
00064 {
00065 $this->fileName = tempnam('/tmp','unzip');
00066
00067 $fo = fopen( $this->fileName,'w');
00068 fwrite($fo,$value);
00069 $this->unzipAll();
00070 }
00071
00072
00073 Function getList($stopOnFile=false){
00074 if(sizeof($this->compressedList)){
00075 $this->debugMsg(1, "Returning already loaded file list.");
00076 return $this->compressedList;
00077 }
00078
00079
00080 $fh = fopen($this->fileName, "r");
00081 $this->fh = &$fh;
00082 if(!$fh){
00083 $this->debugMsg(2, "Failed to load file.");
00084 return false;
00085 }
00086
00087
00088 $ddTry = false;
00089 fseek($fh, 0);
00090 for(;;){
00091
00092 $signature = fread($fh, 4);
00093 if(feof($fh)){
00094 # $this->debugMsg(1, "Reached end of file");
00095 break;
00096 }
00097
00098
00099 if($signature == 'PK00'){
00100 $this->debugMsg(1, "Found PK00: Packed to Removable Disk");
00101 continue;
00102 }
00103
00104
00105 if($signature == $this->zipSignature){
00106 # $this->debugMsg(1, "Zip Signature!");
00107
00108
00109 $file['version_needed'] = unpack("v", fread($fh, 2));
00110 $file['general_bit_flag'] = unpack("v", fread($fh, 2));
00111 $file['compression_method'] = unpack("v", fread($fh, 2));
00112 $file['lastmod_time'] = unpack("v", fread($fh, 2));
00113 $file['lastmod_date'] = unpack("v", fread($fh, 2));
00114 $file['crc-32'] = fread($fh, 4);
00115 $file['compressed_size'] = unpack("V", fread($fh, 4));
00116 $file['uncompressed_size'] = unpack("V", fread($fh, 4));
00117 $fileNameLength = unpack("v", fread($fh, 2));
00118 $extraFieldLength = unpack("v", fread($fh, 2));
00119 $file['file_name'] = fread($fh, $fileNameLength[1]);
00120 $file['extra_field'] = $extraFieldLength[1]?fread($fh, $extraFieldLength[1]):'';
00121 $file['contents-startOffset']= ftell($fh);
00122
00123
00124 fseek($fh, $file['compressed_size'][1], SEEK_CUR);
00125
00126
00127 $BINlastmod_date = str_pad(decbin($file['lastmod_date'][1]), 16, '0', STR_PAD_LEFT);
00128 $BINlastmod_time = str_pad(decbin($file['lastmod_time'][1]), 16, '0', STR_PAD_LEFT);
00129 $lastmod_dateY = bindec(substr($BINlastmod_date, 0, 7))+1980;
00130 $lastmod_dateM = bindec(substr($BINlastmod_date, 7, 4));
00131 $lastmod_dateD = bindec(substr($BINlastmod_date, 11, 5));
00132 $lastmod_timeH = bindec(substr($BINlastmod_time, 0, 5));
00133 $lastmod_timeM = bindec(substr($BINlastmod_time, 5, 6));
00134 $lastmod_timeS = bindec(substr($BINlastmod_time, 11, 5));
00135
00136
00137 $this->compressedList[$file['file_name']] = Array(
00138 'file_name' =>$file['file_name'],
00139 'compression_method'=>$file['compression_method'][1],
00140 'version_needed' =>$file['version_needed'][1],
00141 'lastmod_datetime' =>mktime($lastmod_timeH, $lastmod_timeM, $lastmod_timeS, $lastmod_dateM, $lastmod_dateD, $lastmod_dateY),
00142 'crc-32' =>str_pad(dechex(ord($file['crc-32'][3])), 2, '0', STR_PAD_LEFT).
00143 str_pad(dechex(ord($file['crc-32'][2])), 2, '0', STR_PAD_LEFT).
00144 str_pad(dechex(ord($file['crc-32'][1])), 2, '0', STR_PAD_LEFT).
00145 str_pad(dechex(ord($file['crc-32'][0])), 2, '0', STR_PAD_LEFT),
00146 'compressed_size' =>$file['compressed_size'][1],
00147 'uncompressed_size' =>$file['uncompressed_size'][1],
00148 'extra_field' =>$file['extra_field'],
00149 'general_bit_flag' =>str_pad(decbin($file['general_bit_flag'][1]), 8, '0', STR_PAD_LEFT),
00150 'contents-startOffset'=>$file['contents-startOffset']
00151 );
00152
00153 if($stopOnFile) if($file['file_name'] == $stopOnFile){
00154 $this->debugMsg(1, "Stopping on file...");
00155 break;
00156 }
00157 }
00158
00159
00160 elseif($signature == $this->dirSignature){
00161 # $this->debugMsg(1, "Dir Signature!");
00162
00163 $dir['version_madeby'] = unpack("v", fread($fh, 2));
00164 $dir['version_needed'] = unpack("v", fread($fh, 2));
00165 $dir['general_bit_flag'] = unpack("v", fread($fh, 2));
00166 $dir['compression_method'] = unpack("v", fread($fh, 2));
00167 $dir['lastmod_time'] = unpack("v", fread($fh, 2));
00168 $dir['lastmod_date'] = unpack("v", fread($fh, 2));
00169 $dir['crc-32'] = fread($fh, 4);
00170 $dir['compressed_size'] = unpack("V", fread($fh, 4));
00171 $dir['uncompressed_size'] = unpack("V", fread($fh, 4));
00172 $fileNameLength = unpack("v", fread($fh, 2));
00173 $extraFieldLength = unpack("v", fread($fh, 2));
00174 $fileCommentLength = unpack("v", fread($fh, 2));
00175 $dir['disk_number_start'] = unpack("v", fread($fh, 2));
00176 $dir['internal_attributes'] = unpack("v", fread($fh, 2));
00177 $dir['external_attributes1']= unpack("v", fread($fh, 2));
00178 $dir['external_attributes2']= unpack("v", fread($fh, 2));
00179 $dir['relative_offset'] = unpack("V", fread($fh, 4));
00180 $dir['file_name'] = fread($fh, $fileNameLength[1]);
00181 $dir['extra_field'] = $extraFieldLength[1] ?fread($fh, $extraFieldLength[1]) :'';
00182 $dir['file_comment'] = $fileCommentLength[1]?fread($fh, $fileCommentLength[1]):'';
00183
00184
00185 $BINlastmod_date = str_pad(decbin($file['lastmod_date'][1]), 16, '0', STR_PAD_LEFT);
00186 $BINlastmod_time = str_pad(decbin($file['lastmod_time'][1]), 16, '0', STR_PAD_LEFT);
00187 $lastmod_dateY = bindec(substr($BINlastmod_date, 0, 7))+1980;
00188 $lastmod_dateM = bindec(substr($BINlastmod_date, 7, 4));
00189 $lastmod_dateD = bindec(substr($BINlastmod_date, 11, 5));
00190 $lastmod_timeH = bindec(substr($BINlastmod_time, 0, 5));
00191 $lastmod_timeM = bindec(substr($BINlastmod_time, 5, 6));
00192 $lastmod_timeS = bindec(substr($BINlastmod_time, 11, 5));
00193
00194 $this->centralDirList[$dir['file_name']] = Array(
00195 'version_madeby'=>$dir['version_madeby'][1],
00196 'version_needed'=>$dir['version_needed'][1],
00197 'general_bit_flag'=>str_pad(decbin($file['general_bit_flag'][1]), 8, '0', STR_PAD_LEFT),
00198 'compression_method'=>$dir['compression_method'][1],
00199 'lastmod_datetime' =>mktime($lastmod_timeH, $lastmod_timeM, $lastmod_timeS, $lastmod_dateM, $lastmod_dateD, $lastmod_dateY),
00200 'crc-32' =>str_pad(dechex(ord($file['crc-32'][3])), 2, '0', STR_PAD_LEFT).
00201 str_pad(dechex(ord($file['crc-32'][2])), 2, '0', STR_PAD_LEFT).
00202 str_pad(dechex(ord($file['crc-32'][1])), 2, '0', STR_PAD_LEFT).
00203 str_pad(dechex(ord($file['crc-32'][0])), 2, '0', STR_PAD_LEFT),
00204 'compressed_size'=>$dir['compressed_size'][1],
00205 'uncompressed_size'=>$dir['uncompressed_size'][1],
00206 'disk_number_start'=>$dir['disk_number_start'][1],
00207 'internal_attributes'=>$dir['internal_attributes'][1],
00208 'external_attributes1'=>$dir['external_attributes1'][1],
00209 'external_attributes2'=>$dir['external_attributes2'][1],
00210 'relative_offset'=>$dir['relative_offset'][1],
00211 'file_name'=>$dir['file_name'],
00212 'extra_field'=>$dir['extra_field'],
00213 'file_comment'=>$dir['file_comment'],
00214 );
00215 }
00216
00217 elseif($signature == $this->dirSignatureE){
00218 # $this->debugMsg(1, "EOF Dir Signature!");
00219
00220 $eodir['disk_number_this'] = unpack("v", fread($fh, 2));
00221 $eodir['disk_number'] = unpack("v", fread($fh, 2));
00222 $eodir['total_entries_this'] = unpack("v", fread($fh, 2));
00223 $eodir['total_entries'] = unpack("v", fread($fh, 2));
00224 $eodir['size_of_cd'] = unpack("V", fread($fh, 4));
00225 $eodir['offset_start_cd'] = unpack("V", fread($fh, 4));
00226 $zipFileCommentLenght = unpack("v", fread($fh, 2));
00227 $eodir['zipfile_comment'] = $zipFileCommentLenght[1]?fread($fh, $zipFileCommentLenght[1]):'';
00228 $this->endOfCentral = Array(
00229 'disk_number_this'=>$eodir['disk_number_this'][1],
00230 'disk_number'=>$eodir['disk_number'][1],
00231 'total_entries_this'=>$eodir['total_entries_this'][1],
00232 'total_entries'=>$eodir['total_entries'][1],
00233 'size_of_cd'=>$eodir['size_of_cd'][1],
00234 'offset_start_cd'=>$eodir['offset_start_cd'][1],
00235 'zipfile_comment'=>$eodir['zipfile_comment'],
00236 );
00237 }
00238 else{
00239 if(!$ddTry){
00240 $this->debugMsg(1, "Unexpected header. Trying to detect wrong placed 'Data Descriptor'...\n");
00241 $ddTry = true;
00242 fseek($fh, 12-4, SEEK_CUR);
00243 continue;
00244 }
00245 $this->debugMsg(1, "Unexpected header, ending loop at offset ".ftell($fh));
00246 break;
00247 }
00248 $ddTry = false;
00249 }
00250
00251 if($this->debug){
00252 #------- Debug compressedList
00253 $kkk = 0;
00254 echo "<table border='0' style='font: 11px Verdana; border: 1px solid #000'>";
00255 foreach($this->compressedList as $fileName=>$item){
00256 if(!$kkk && $kkk=1){
00257 echo "<tr style='background: #ADA'>";
00258 foreach($item as $fieldName=>$value)
00259 echo "<td>$fieldName</td>";
00260 echo '</tr>';
00261 }
00262 echo "<tr style='background: #CFC'>";
00263 foreach($item as $fieldName=>$value){
00264 if($fieldName == 'lastmod_datetime')
00265 echo "<td title='$fieldName' nowrap='nowrap'>".date("d/m/Y H:i:s", $value)."</td>";
00266 else
00267 echo "<td title='$fieldName' nowrap='nowrap'>$value</td>";
00268 }
00269 echo "</tr>";
00270 }
00271 echo "</table>";
00272
00273 #------- Debug centralDirList
00274 $kkk = 0;
00275 if(sizeof($this->centralDirList)){
00276 echo "<table border='0' style='font: 11px Verdana; border: 1px solid #000'>";
00277 foreach($this->centralDirList as $fileName=>$item){
00278 if(!$kkk && $kkk=1){
00279 echo "<tr style='background: #AAD'>";
00280 foreach($item as $fieldName=>$value)
00281 echo "<td>$fieldName</td>";
00282 echo '</tr>';
00283 }
00284 echo "<tr style='background: #CCF'>";
00285 foreach($item as $fieldName=>$value){
00286 if($fieldName == 'lastmod_datetime')
00287 echo "<td title='$fieldName' nowrap='nowrap'>".date("d/m/Y H:i:s", $value)."</td>";
00288 else
00289 echo "<td title='$fieldName' nowrap='nowrap'>$value</td>";
00290 }
00291 echo "</tr>";
00292 }
00293 echo "</table>";
00294 }
00295
00296 #------- Debug endOfCentral
00297 $kkk = 0;
00298 if(sizeof($this->endOfCentral)){
00299 echo "<table border='0' style='font: 11px Verdana' style='border: 1px solid #000'>";
00300 echo "<tr style='background: #DAA'><td colspan='2'>dUnzip - End of file</td></tr>";
00301 foreach($this->endOfCentral as $field=>$value){
00302 echo "<tr>";
00303 echo "<td style='background: #FCC'>$field</td>";
00304 echo "<td style='background: #FDD'>$value</td>";
00305 echo "</tr>";
00306 }
00307 echo "</table>";
00308 }
00309 }
00310
00311 return $this->compressedList;
00312 }
00313
00314
00315 Function getExtraInfo($compressedFileName)
00316 {
00317 return
00318 isset($this->centralDirList[$compressedFileName])?
00319 $this->centralDirList[$compressedFileName]:
00320 false;
00321 }
00322
00323
00324 Function getZipInfo($detail=false)
00325 {
00326 return $detail?
00327 $this->endOfCentral[$detail]:
00328 $this->endOfCentral;
00329 }
00330
00331
00332 Function unzip($compressedFileName, $targetFileName=false){
00333 $fdetails = &$this->compressedList[$compressedFileName];
00334
00335 if(!sizeof($this->compressedList)){
00336 $this->debugMsg(1, "Trying to unzip before loading file list... Loading it!");
00337 $this->getList(false, $compressedFileName);
00338 }
00339 if(!isset($this->compressedList[$compressedFileName])){
00340 $this->debugMsg(2, "File '<b>$compressedFileName</b>' is not compressed in the zip.");
00341 return false;
00342 }
00343 if(substr($compressedFileName, -1) == "/"){
00344 $this->debugMsg(2, "Trying to unzip a folder name '<b>$compressedFileName</b>'.");
00345 return false;
00346 }
00347 if(!$fdetails['uncompressed_size']){
00348 $this->debugMsg(1, "File '<b>$compressedFileName</b>' is empty.");
00349 return "";
00350 }
00351
00352 fseek($this->fh, $fdetails['contents-startOffset']);
00353 return $this->uncompress(
00354 fread($this->fh, $fdetails['compressed_size']),
00355 $fdetails['compression_method'],
00356 $fdetails['uncompressed_size'] );
00357 }
00358
00359
00360 Function unzipAll($targetDir=false, $baseDir="", $maintainStructure=true, $chmod=false){
00361 if($targetDir === false)
00362 $targetDir = dirname(__FILE__)."/";
00363
00364 $lista = $this->getList();
00365 if(sizeof($lista)) foreach($lista as $fileName=>$trash){
00366 $dirname = dirname($fileName);
00367 $outDN = "$targetDir/$dirname";
00368
00369 if(substr($dirname, 0, strlen($baseDir)) != $baseDir)
00370 continue;
00371
00372 if(!is_dir($outDN) && $maintainStructure){
00373 $str = "";
00374 $folders = explode("/", $dirname);
00375 foreach($folders as $folder){
00376 $str = $str?"$str/$folder":$folder;
00377 if(!is_dir("$targetDir/$str")){
00378 $this->debugMsg(1, "Creating folder: $targetDir/$str");
00379 mkdir("$targetDir/$str");
00380 if($chmod)
00381 chmod("$targetDir/$str", $chmod);
00382 }
00383 }
00384 }
00385 if(substr($fileName, -1, 1) == "/")
00386 continue;
00387
00388 $maintainStructure?
00389 $this->unzip($fileName, "$targetDir/$fileName"):
00390 $this->unzip($fileName, "$targetDir/".basename($fileName));
00391
00392 if($chmod)
00393 chmod($maintainStructure?"$targetDir/$fileName":"$targetDir/".basename($fileName), $chmod);
00394 }
00395 }
00396
00397 Function close(){
00398 if($this->fh)
00399 fclose($this->fh);
00400 }
00401
00402
00403 Function uncompress($content, $mode, $uncompressedSize, $targetFileName=false){
00404 switch($mode){
00405 case 0:
00406
00407 return $content;
00408 case 1:
00409 $this->debugMsg(2, "Shrunk mode is not supported... yet?");
00410 return false;
00411 case 2:
00412 case 3:
00413 case 4:
00414 case 5:
00415 $this->debugMsg(2, "Compression factor ".($mode-1)." is not supported... yet?");
00416 return false;
00417 case 6:
00418 $this->debugMsg(2, "Implode is not supported... yet?");
00419 return false;
00420 case 7:
00421 $this->debugMsg(2, "Tokenizing compression algorithm is not supported... yet?");
00422 return false;
00423 case 8:
00424
00425 return gzinflate($content, $uncompressedSize);
00426 case 9:
00427 $this->debugMsg(2, "Enhanced Deflating is not supported... yet?");
00428 return false;
00429 case 10:
00430 $this->debugMsg(2, "PKWARE Date Compression Library Impoloding is not supported... yet?");
00431 return false;
00432 default:
00433 $this->debugMsg(2, "Unknown uncompress method: $mode");
00434 return false;
00435 }
00436 }
00437
00438
00439 Function debugMsg($level, $string){
00440 if($this->debug)
00441 if($level == 1)
00442 echo "<b style='color: #777'>dUnzip2:</b> $string<br>";
00443 if($level == 2)
00444 echo "<b style='color: #F00'>dUnzip2:</b> $string<br>";
00445 }
00446 }
00447 ?>