summaryrefslogtreecommitdiff
path: root/vendor/splitbrain/php-archive/src/Zip.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/splitbrain/php-archive/src/Zip.php')
-rw-r--r--vendor/splitbrain/php-archive/src/Zip.php218
1 files changed, 157 insertions, 61 deletions
diff --git a/vendor/splitbrain/php-archive/src/Zip.php b/vendor/splitbrain/php-archive/src/Zip.php
index c2ff36575..1bc1ac1b7 100644
--- a/vendor/splitbrain/php-archive/src/Zip.php
+++ b/vendor/splitbrain/php-archive/src/Zip.php
@@ -7,6 +7,8 @@ namespace splitbrain\PHPArchive;
*
* Creates or extracts Zip archives
*
+ * for specs see http://www.pkware.com/appnote
+ *
* @author Andreas Gohr <andi@splitbrain.org>
* @package splitbrain\PHPArchive
* @license MIT
@@ -221,6 +223,7 @@ class Zip extends Archive
}
fclose($fp);
gzclose($gzp);
+ unlink($extractto); // remove temporary gz file
}
touch($output, $fileinfo->getMtime());
@@ -308,45 +311,45 @@ class Zip extends Archive
throw new ArchiveIOException('Archive has been closed, files can no longer be added');
}
- // prepare the various header infos
- $dtime = dechex($this->makeDosTime($fileinfo->getMtime()));
- $hexdtime = pack(
- 'H*',
- $dtime[6].$dtime[7].
- $dtime[4].$dtime[5].
- $dtime[2].$dtime[3].
- $dtime[0].$dtime[1]
- );
+ // prepare info and compress data
$size = strlen($data);
$crc = crc32($data);
if ($this->complevel) {
- $fmagic = "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00";
- $cmagic = "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00";
- $data = gzcompress($data, $this->complevel);
- $data = substr($data, 2, -4); // strip compression headers
- } else {
- $fmagic = "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00";
- $cmagic = "\x50\x4b\x01\x02\x14\x00\x0a\x00\x00\x00\x00\x00";
+ $data = gzcompress($data, $this->complevel);
+ $data = substr($data, 2, -4); // strip compression headers
}
$csize = strlen($data);
$offset = $this->dataOffset();
$name = $fileinfo->getPath();
+ $time = $fileinfo->getMtime();
+
+ // write local file header
+ $this->writebytes($this->makeLocalFileHeader(
+ $time,
+ $crc,
+ $size,
+ $csize,
+ $name,
+ (bool) $this->complevel
+ ));
+
+ // we store no encryption header
// write data
- $this->writebytes($fmagic);
- $this->writebytes($hexdtime);
- $this->writebytes(pack('V', $crc).pack('V', $csize).pack('V', $size)); //pre header
- $this->writebytes(pack('v', strlen($name)).pack('v', 0).$name.$data); //file data
- $this->writebytes(pack('V', $crc).pack('V', $csize).pack('V', $size)); //post header
+ $this->writebytes($data);
+
+ // we store no data descriptor
// add info to central file directory
- $cdrec = $cmagic;
- $cdrec .= $hexdtime.pack('V', $crc).pack('V', $csize).pack('V', $size);
- $cdrec .= pack('v', strlen($name)).pack('v', 0).pack('v', 0);
- $cdrec .= pack('v', 0).pack('v', 0).pack('V', 32);
- $cdrec .= pack('V', $offset);
- $cdrec .= $name;
- $this->ctrl_dir[] = $cdrec;
+ $this->ctrl_dir[] = $this->makeCentralFileRecord(
+ $offset,
+ $time,
+ $crc,
+ $size,
+ $csize,
+ $name,
+ (bool) $this->complevel
+ );
}
/**
@@ -361,14 +364,24 @@ class Zip extends Archive
return;
} // we did this already
- // write footer
if ($this->writeaccess) {
- $offset = $this->dataOffset();
+ // write central directory
+ $offset = $this->dataOffset();
$ctrldir = join('', $this->ctrl_dir);
$this->writebytes($ctrldir);
- $this->writebytes("\x50\x4b\x05\x06\x00\x00\x00\x00"); // EOF CTRL DIR
- $this->writebytes(pack('v', count($this->ctrl_dir)).pack('v', count($this->ctrl_dir)));
- $this->writebytes(pack('V', strlen($ctrldir)).pack('V', strlen($offset))."\x00\x00");
+
+ // write end of central directory record
+ $this->writebytes("\x50\x4b\x05\x06"); // end of central dir signature
+ $this->writebytes(pack('v', 0)); // number of this disk
+ $this->writebytes(pack('v', 0)); // number of the disk with the start of the central directory
+ $this->writebytes(pack('v',
+ count($this->ctrl_dir))); // total number of entries in the central directory on this disk
+ $this->writebytes(pack('v', count($this->ctrl_dir))); // total number of entries in the central directory
+ $this->writebytes(pack('V', strlen($ctrldir))); // size of the central directory
+ $this->writebytes(pack('V',
+ $offset)); // offset of start of central directory with respect to the starting disk number
+ $this->writebytes(pack('v', 0)); // .ZIP file comment length
+
$this->ctrl_dir = array();
}
@@ -492,18 +505,7 @@ class Zip extends Archive
$header['comment'] = '';
}
- if ($header['mdate'] && $header['mtime']) {
- $hour = ($header['mtime'] & 0xF800) >> 11;
- $minute = ($header['mtime'] & 0x07E0) >> 5;
- $seconde = ($header['mtime'] & 0x001F) * 2;
- $year = (($header['mdate'] & 0xFE00) >> 9) + 1980;
- $month = ($header['mdate'] & 0x01E0) >> 5;
- $day = $header['mdate'] & 0x001F;
- $header['mtime'] = mktime($hour, $minute, $seconde, $month, $day, $year);
- } else {
- $header['mtime'] = time();
- }
-
+ $header['mtime'] = $this->makeUnixTime($header['mdate'], $header['mtime']);
$header['stored_filename'] = $header['filename'];
$header['status'] = 'ok';
if (substr($header['filename'], -1) == '/') {
@@ -518,12 +520,12 @@ class Zip extends Archive
* Reads the local file header
*
* This header precedes each individual file inside the zip file. Assumes the current file pointer is pointing at
- * the right position already. Enhances this given central header with the data found at the local header.
+ * the right position already. Enhances the given central header with the data found at the local header.
*
* @param array $header the central file header read previously (see above)
* @return array
*/
- function readFileHeader($header)
+ protected function readFileHeader($header)
{
$binary_data = fread($this->fh, 30);
$data = unpack(
@@ -549,20 +551,7 @@ class Zip extends Archive
}
}
$header['flag'] = $data['flag'];
- $header['mdate'] = $data['mdate'];
- $header['mtime'] = $data['mtime'];
-
- if ($header['mdate'] && $header['mtime']) {
- $hour = ($header['mtime'] & 0xF800) >> 11;
- $minute = ($header['mtime'] & 0x07E0) >> 5;
- $seconde = ($header['mtime'] & 0x001F) * 2;
- $year = (($header['mdate'] & 0xFE00) >> 9) + 1980;
- $month = ($header['mdate'] & 0x01E0) >> 5;
- $day = $header['mdate'] & 0x001F;
- $header['mtime'] = mktime($hour, $minute, $seconde, $month, $day, $year);
- } else {
- $header['mtime'] = time();
- }
+ $header['mtime'] = $this->makeUnixTime($data['mdate'], $data['mtime']);
$header['stored_filename'] = $header['filename'];
$header['status'] = "ok";
@@ -651,4 +640,111 @@ class Zip extends Archive
($timearray['seconds'] >> 1);
}
+ /**
+ * Create a UNIX timestamp from a DOS timestamp
+ *
+ * @param $mdate
+ * @param $mtime
+ * @return int
+ */
+ protected function makeUnixTime($mdate = null, $mtime = null)
+ {
+ if ($mdate && $mtime) {
+ $year = (($mdate & 0xFE00) >> 9) + 1980;
+ $month = ($mdate & 0x01E0) >> 5;
+ $day = $mdate & 0x001F;
+
+ $hour = ($mtime & 0xF800) >> 11;
+ $minute = ($mtime & 0x07E0) >> 5;
+ $seconde = ($mtime & 0x001F) << 1;
+
+ $mtime = mktime($hour, $minute, $seconde, $month, $day, $year);
+ } else {
+ $mtime = time();
+ }
+
+ return $mtime;
+ }
+
+ /**
+ * Returns a local file header for the given data
+ *
+ * @param int $offset location of the local header
+ * @param int $ts unix timestamp
+ * @param int $crc CRC32 checksum of the uncompressed data
+ * @param int $len length of the uncompressed data
+ * @param int $clen length of the compressed data
+ * @param string $name file name
+ * @param boolean|null $comp if compression is used, if null it's determined from $len != $clen
+ * @return string
+ */
+ protected function makeCentralFileRecord($offset, $ts, $crc, $len, $clen, $name, $comp = null)
+ {
+ if(is_null($comp)) $comp = $len != $clen;
+ $comp = $comp ? 8 : 0;
+ $dtime = dechex($this->makeDosTime($ts));
+
+ $header = "\x50\x4b\x01\x02"; // central file header signature
+ $header .= pack('v', 14); // version made by - VFAT
+ $header .= pack('v', 20); // version needed to extract - 2.0
+ $header .= pack('v', 0); // general purpose flag - no flags set
+ $header .= pack('v', $comp); // compression method - deflate|none
+ $header .= pack(
+ 'H*',
+ $dtime[6] . $dtime[7] .
+ $dtime[4] . $dtime[5] .
+ $dtime[2] . $dtime[3] .
+ $dtime[0] . $dtime[1]
+ ); // last mod file time and date
+ $header .= pack('V', $crc); // crc-32
+ $header .= pack('V', $clen); // compressed size
+ $header .= pack('V', $len); // uncompressed size
+ $header .= pack('v', strlen($name)); // file name length
+ $header .= pack('v', 0); // extra field length
+ $header .= pack('v', 0); // file comment length
+ $header .= pack('v', 0); // disk number start
+ $header .= pack('v', 0); // internal file attributes
+ $header .= pack('V', 0); // external file attributes @todo was 0x32!?
+ $header .= pack('V', $offset); // relative offset of local header
+ $header .= $name; // file name
+
+ return $header;
+ }
+
+ /**
+ * Returns a local file header for the given data
+ *
+ * @param int $ts unix timestamp
+ * @param int $crc CRC32 checksum of the uncompressed data
+ * @param int $len length of the uncompressed data
+ * @param int $clen length of the compressed data
+ * @param string $name file name
+ * @param boolean|null $comp if compression is used, if null it's determined from $len != $clen
+ * @return string
+ */
+ protected function makeLocalFileHeader($ts, $crc, $len, $clen, $name, $comp = null)
+ {
+ if(is_null($comp)) $comp = $len != $clen;
+ $comp = $comp ? 8 : 0;
+ $dtime = dechex($this->makeDosTime($ts));
+
+ $header = "\x50\x4b\x03\x04"; // local file header signature
+ $header .= pack('v', 20); // version needed to extract - 2.0
+ $header .= pack('v', 0); // general purpose flag - no flags set
+ $header .= pack('v', $comp); // compression method - deflate|none
+ $header .= pack(
+ 'H*',
+ $dtime[6] . $dtime[7] .
+ $dtime[4] . $dtime[5] .
+ $dtime[2] . $dtime[3] .
+ $dtime[0] . $dtime[1]
+ ); // last mod file time and date
+ $header .= pack('V', $crc); // crc-32
+ $header .= pack('V', $clen); // compressed size
+ $header .= pack('V', $len); // uncompressed size
+ $header .= pack('v', strlen($name)); // file name length
+ $header .= pack('v', 0); // extra field length
+ $header .= $name;
+ return $header;
+ }
}