zip.lib.php 6.8 KB

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