updated archive library via composer

This commit is contained in:
Andreas Gohr 2015-06-30 21:17:23 +02:00
parent 0f7eafd90c
commit 2b6c681901
4 changed files with 224 additions and 124 deletions

10
composer.lock generated
View File

@ -54,16 +54,16 @@
},
{
"name": "splitbrain/php-archive",
"version": "1.0.0",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/splitbrain/php-archive.git",
"reference": "a0fbfc2f85ed491f3d2af42cff48a9cb783a8549"
"reference": "89b4cba038e8cf01af3a8180572f19b8e4afaa31"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/splitbrain/php-archive/zipball/a0fbfc2f85ed491f3d2af42cff48a9cb783a8549",
"reference": "a0fbfc2f85ed491f3d2af42cff48a9cb783a8549",
"url": "https://api.github.com/repos/splitbrain/php-archive/zipball/89b4cba038e8cf01af3a8180572f19b8e4afaa31",
"reference": "89b4cba038e8cf01af3a8180572f19b8e4afaa31",
"shasum": ""
},
"require": {
@ -97,7 +97,7 @@
"unzip",
"zip"
],
"time": "2015-02-25 20:15:02"
"time": "2015-06-30 19:12:21"
}
],
"packages-dev": [],

View File

@ -1,53 +1,4 @@
[
{
"name": "splitbrain/php-archive",
"version": "1.0.0",
"version_normalized": "1.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/splitbrain/php-archive.git",
"reference": "a0fbfc2f85ed491f3d2af42cff48a9cb783a8549"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/splitbrain/php-archive/zipball/a0fbfc2f85ed491f3d2af42cff48a9cb783a8549",
"reference": "a0fbfc2f85ed491f3d2af42cff48a9cb783a8549",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "4.5.*"
},
"time": "2015-02-25 20:15:02",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"splitbrain\\PHPArchive\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Andreas Gohr",
"email": "andi@splitbrain.org"
}
],
"description": "Pure-PHP implementation to read and write TAR and ZIP archives",
"keywords": [
"archive",
"extract",
"tar",
"unpack",
"unzip",
"zip"
]
},
{
"name": "easybook/geshi",
"version": "v1.0.8.15",
@ -95,5 +46,54 @@
"highlighter",
"syntax"
]
},
{
"name": "splitbrain/php-archive",
"version": "1.0.2",
"version_normalized": "1.0.2.0",
"source": {
"type": "git",
"url": "https://github.com/splitbrain/php-archive.git",
"reference": "89b4cba038e8cf01af3a8180572f19b8e4afaa31"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/splitbrain/php-archive/zipball/89b4cba038e8cf01af3a8180572f19b8e4afaa31",
"reference": "89b4cba038e8cf01af3a8180572f19b8e4afaa31",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "4.5.*"
},
"time": "2015-06-30 19:12:21",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"splitbrain\\PHPArchive\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Andreas Gohr",
"email": "andi@splitbrain.org"
}
],
"description": "Pure-PHP implementation to read and write TAR and ZIP archives",
"keywords": [
"archive",
"extract",
"tar",
"unpack",
"unzip",
"zip"
]
}
]

View File

@ -18,24 +18,29 @@ Use composer:
Usage
-----
The usage for the Zip and Tar classes are basically the same. Here are some examples for working with TARs to get
you started. Check the source code comments for more info
The usage for the Zip and Tar classes are basically the same. Here are some
examples for working with TARs to get you started. Check the source code
comments for more info
```php
require_once 'vendor/autoload.php';
use splitbrain\PHPArchive\Tar;
// To list the contents of an existing TAR archive, open() it and use contents() on it:
// To list the contents of an existing TAR archive, open() it and use
// contents() on it:
$tar = new Tar();
$tar->open('myfile.tgz');
$toc = $tar->contents();
print_r($toc); // array of FileInfo objects
// To extract the contents of an existing TAR archive, open() it and use extract() on it:
// To extract the contents of an existing TAR archive, open() it and use
// extract() on it:
$tar = new Tar();
$tar->open('myfile.tgz');
$tar->extract('/tmp');
// To create a new TAR archive directly on the filesystem (low memory requirements), create() it,
// To create a new TAR archive directly on the filesystem (low memory
// requirements), create() it:
$tar = new Tar();
$tar->create('myfile.tgz');
$tar->addFile(...);
@ -43,8 +48,8 @@ $tar->addData(...);
...
$tar->close();
// To create a TAR archive directly in memory, create() it, add*() files and then either save()
// or getData() it:
// To create a TAR archive directly in memory, create() it, add*()
// files and then either save() or getArchive() it:
$tar = new Tar();
$tar->create();
$tar->addFile(...);
@ -54,8 +59,8 @@ $tar->save('myfile.tgz'); // compresses and saves it
echo $tar->getArchive(Archive::COMPRESS_GZIP); // compresses and returns it
```
Differences between Tar and Zip: Tars are compressed as a whole while Zips compress each file individually. Therefore
you can call ```setCompression``` before each ```addFile()``` and ```addData()``` functions.
Differences between Tar and Zip: Tars are compressed as a whole, while Zips compress each file individually. Therefore
you can call ```setCompression``` before each ```addFile()``` and ```addData()``` function call.
The FileInfo class can be used to specify additional info like ownership or permissions when adding a file to
an archive.

View File

@ -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
@ -308,45 +310,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 +363,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 +504,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 +519,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 +550,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 +639,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;
}
}