zip.lib.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. *
  5. * @package PhpMyAdmin
  6. */
  7. /**
  8. * Zip file creation class.
  9. * Makes zip files.
  10. *
  11. * @see Official ZIP file format: http://www.pkware.com/support/zip-app-note
  12. *
  13. * @access public
  14. * @package PhpMyAdmin
  15. */
  16. class zipfile
  17. {
  18. /**
  19. * Whether to echo zip as it's built or return as string from -> file
  20. *
  21. * @var boolean $doWrite
  22. */
  23. var $doWrite = false;
  24. /**
  25. * Array to store compressed data
  26. *
  27. * @var array $datasec
  28. */
  29. var $datasec = array();
  30. /**
  31. * Central directory
  32. *
  33. * @var array $ctrl_dir
  34. */
  35. var $ctrl_dir = array();
  36. /**
  37. * End of central directory record
  38. *
  39. * @var string $eof_ctrl_dir
  40. */
  41. var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";
  42. /**
  43. * Last offset position
  44. *
  45. * @var integer $old_offset
  46. */
  47. var $old_offset = 0;
  48. /**
  49. * Sets member variable this -> doWrite to true
  50. * - Should be called immediately after class instantiantion
  51. * - If set to true, then ZIP archive are echo'ed to STDOUT as each
  52. * file is added via this -> addfile(), and central directories are
  53. * echoed to STDOUT on final call to this -> file(). Also,
  54. * this -> file() returns an empty string so it is safe to issue a
  55. * "echo $zipfile;" command
  56. *
  57. * @access public
  58. *
  59. * @return nothing
  60. */
  61. function setDoWrite()
  62. {
  63. $this -> doWrite = true;
  64. } // end of the 'setDoWrite()' method
  65. /**
  66. * Converts an Unix timestamp to a four byte DOS date and time format (date
  67. * in high two bytes, time in low two bytes allowing magnitude comparison).
  68. *
  69. * @param integer $unixtime the current Unix timestamp
  70. *
  71. * @return integer the current date in a four byte DOS format
  72. *
  73. * @access private
  74. */
  75. function unix2DosTime($unixtime = 0)
  76. {
  77. $timearray = ($unixtime == 0) ? getdate() : getdate($unixtime);
  78. if ($timearray['year'] < 1980) {
  79. $timearray['year'] = 1980;
  80. $timearray['mon'] = 1;
  81. $timearray['mday'] = 1;
  82. $timearray['hours'] = 0;
  83. $timearray['minutes'] = 0;
  84. $timearray['seconds'] = 0;
  85. } // end if
  86. return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) |
  87. ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1);
  88. } // end of the 'unix2DosTime()' method
  89. /**
  90. * Adds "file" to archive
  91. *
  92. * @param string $data file contents
  93. * @param string $name name of the file in the archive (may contains the path)
  94. * @param integer $time the current timestamp
  95. *
  96. * @access public
  97. *
  98. * @return nothing
  99. */
  100. function addFile($data, $name, $time = 0)
  101. {
  102. $name = str_replace('\\', '/', $name);
  103. $dtime = substr("00000000" . dechex($this->unix2DosTime($time)), -8);
  104. $hexdtime = '\x' . $dtime[6] . $dtime[7]
  105. . '\x' . $dtime[4] . $dtime[5]
  106. . '\x' . $dtime[2] . $dtime[3]
  107. . '\x' . $dtime[0] . $dtime[1];
  108. eval('$hexdtime = "' . $hexdtime . '";');
  109. $fr = "\x50\x4b\x03\x04";
  110. $fr .= "\x14\x00"; // ver needed to extract
  111. $fr .= "\x00\x00"; // gen purpose bit flag
  112. $fr .= "\x08\x00"; // compression method
  113. $fr .= $hexdtime; // last mod time and date
  114. // "local file header" segment
  115. $unc_len = strlen($data);
  116. $crc = crc32($data);
  117. $zdata = gzcompress($data);
  118. $zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug
  119. $c_len = strlen($zdata);
  120. $fr .= pack('V', $crc); // crc32
  121. $fr .= pack('V', $c_len); // compressed filesize
  122. $fr .= pack('V', $unc_len); // uncompressed filesize
  123. $fr .= pack('v', strlen($name)); // length of filename
  124. $fr .= pack('v', 0); // extra field length
  125. $fr .= $name;
  126. // "file data" segment
  127. $fr .= $zdata;
  128. // echo this entry on the fly, ...
  129. if ( $this -> doWrite) {
  130. echo $fr;
  131. } else { // ... OR add this entry to array
  132. $this -> datasec[] = $fr;
  133. }
  134. // now add to central directory record
  135. $cdrec = "\x50\x4b\x01\x02";
  136. $cdrec .= "\x00\x00"; // version made by
  137. $cdrec .= "\x14\x00"; // version needed to extract
  138. $cdrec .= "\x00\x00"; // gen purpose bit flag
  139. $cdrec .= "\x08\x00"; // compression method
  140. $cdrec .= $hexdtime; // last mod time & date
  141. $cdrec .= pack('V', $crc); // crc32
  142. $cdrec .= pack('V', $c_len); // compressed filesize
  143. $cdrec .= pack('V', $unc_len); // uncompressed filesize
  144. $cdrec .= pack('v', strlen($name)); // length of filename
  145. $cdrec .= pack('v', 0); // extra field length
  146. $cdrec .= pack('v', 0); // file comment length
  147. $cdrec .= pack('v', 0); // disk number start
  148. $cdrec .= pack('v', 0); // internal file attributes
  149. $cdrec .= pack('V', 32); // external file attributes - 'archive' bit set
  150. $cdrec .= pack('V', $this -> old_offset); // relative offset of local header
  151. $this -> old_offset += strlen($fr);
  152. $cdrec .= $name;
  153. // optional extra field, file comment goes here
  154. // save to central directory
  155. $this -> ctrl_dir[] = $cdrec;
  156. } // end of the 'addFile()' method
  157. /**
  158. * Echo central dir if ->doWrite==true, else build string to return
  159. *
  160. * @return string if ->doWrite {empty string} else the ZIP file contents
  161. *
  162. * @access public
  163. */
  164. function file()
  165. {
  166. $ctrldir = implode('', $this -> ctrl_dir);
  167. $header = $ctrldir .
  168. $this -> eof_ctrl_dir .
  169. pack('v', sizeof($this -> ctrl_dir)) . // total # of entries "on this disk"
  170. pack('v', sizeof($this -> ctrl_dir)) . // total # of entries overall
  171. pack('V', strlen($ctrldir)) . // size of central dir
  172. pack('V', $this -> old_offset) . // offset to start of central dir
  173. "\x00\x00"; // .zip file comment length
  174. if ( $this -> doWrite ) { // Send central directory & end ctrl dir to STDOUT
  175. echo $header;
  176. return ""; // Return empty string
  177. } else { // Return entire ZIP archive as string
  178. $data = implode('', $this -> datasec);
  179. return $data . $header;
  180. }
  181. } // end of the 'file()' method
  182. } // end of the 'zipfile' class
  183. ?>