updated php-archive library

This commit is contained in:
Andreas Gohr 2017-03-31 09:41:47 +02:00
parent e0dd796db5
commit 361134418d
6 changed files with 213 additions and 64 deletions

14
composer.lock generated
View File

@ -254,16 +254,16 @@
},
{
"name": "splitbrain/php-archive",
"version": "1.0.7",
"version": "1.0.8",
"source": {
"type": "git",
"url": "https://github.com/splitbrain/php-archive.git",
"reference": "c075304b44c4aadff0718af445e86bf730f331ff"
"reference": "6b1c1746fa0a6f9f68f0bc832892ddeda8db905c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/splitbrain/php-archive/zipball/c075304b44c4aadff0718af445e86bf730f331ff",
"reference": "c075304b44c4aadff0718af445e86bf730f331ff",
"url": "https://api.github.com/repos/splitbrain/php-archive/zipball/6b1c1746fa0a6f9f68f0bc832892ddeda8db905c",
"reference": "6b1c1746fa0a6f9f68f0bc832892ddeda8db905c",
"shasum": ""
},
"require": {
@ -272,6 +272,10 @@
"require-dev": {
"phpunit/phpunit": "4.5.*"
},
"suggest": {
"ext-iconv": "Used for proper filename encode handling",
"ext-mbstring": "Can be used alternatively for handling filename encoding"
},
"type": "library",
"autoload": {
"psr-4": {
@ -297,7 +301,7 @@
"unzip",
"zip"
],
"time": "2015-08-12T13:24:34+00:00"
"time": "2017-03-19T09:10:53+00:00"
}
],
"packages-dev": [],

View File

@ -1,53 +1,4 @@
[
{
"name": "splitbrain/php-archive",
"version": "1.0.7",
"version_normalized": "1.0.7.0",
"source": {
"type": "git",
"url": "https://github.com/splitbrain/php-archive.git",
"reference": "c075304b44c4aadff0718af445e86bf730f331ff"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/splitbrain/php-archive/zipball/c075304b44c4aadff0718af445e86bf730f331ff",
"reference": "c075304b44c4aadff0718af445e86bf730f331ff",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "4.5.*"
},
"time": "2015-08-12T13:24:34+00:00",
"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.18",
@ -301,5 +252,58 @@
"pseudorandom",
"random"
]
},
{
"name": "splitbrain/php-archive",
"version": "1.0.8",
"version_normalized": "1.0.8.0",
"source": {
"type": "git",
"url": "https://github.com/splitbrain/php-archive.git",
"reference": "6b1c1746fa0a6f9f68f0bc832892ddeda8db905c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/splitbrain/php-archive/zipball/6b1c1746fa0a6f9f68f0bc832892ddeda8db905c",
"reference": "6b1c1746fa0a6f9f68f0bc832892ddeda8db905c",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "4.5.*"
},
"suggest": {
"ext-iconv": "Used for proper filename encode handling",
"ext-mbstring": "Can be used alternatively for handling filename encoding"
},
"time": "2017-03-19T09:10:53+00:00",
"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

@ -14,6 +14,11 @@
"php": ">=5.3.0"
},
"suggest": {
"ext-iconv": "Used for proper filename encode handling",
"ext-mbstring": "Can be used alternatively for handling filename encoding"
},
"require-dev": {
"phpunit/phpunit": "4.5.*"
},

View File

@ -74,10 +74,11 @@ class FileInfo
}
/**
* @return int
* @return int the filesize. always 0 for directories
*/
public function getSize()
{
if($this->isdir) return 0;
return $this->size;
}

View File

@ -230,9 +230,10 @@ class Tar extends Archive
/**
* Add a file to the current TAR archive using an existing file in the filesystem
*
* @param string $file path to the original file
* @param string $file path to the original file
* @param string|FileInfo $fileinfo either the name to us in archive (string) or a FileInfo oject with all meta data, empty to take from original
* @throws ArchiveIOException
* @throws ArchiveCorruptedException when the file changes while reading it, the archive will be corrupt and should be deleted
* @throws ArchiveIOException there was trouble reading the given file, it was not added
*/
public function addFile($file, $fileinfo = '')
{
@ -253,8 +254,10 @@ class Tar extends Archive
$this->writeFileHeader($fileinfo);
// write data
$read = 0;
while (!feof($fp)) {
$data = fread($fp, 512);
$read += strlen($data);
if ($data === false) {
break;
}
@ -265,6 +268,11 @@ class Tar extends Archive
$this->writebytes($packed);
}
fclose($fp);
if($read != $fileinfo->getSize()) {
$this->close();
throw new ArchiveCorruptedException("The size of $file changed while reading, archive corrupted. read $read expected ".$fileinfo->getSize());
}
}
/**
@ -573,7 +581,7 @@ class Tar extends Archive
// Handle Long-Link entries from GNU Tar
if ($return['typeflag'] == 'L') {
// following data block(s) is the filename
$filename = trim($this->readbytes(ceil($header['size'] / 512) * 512));
$filename = trim($this->readbytes(ceil($return['size'] / 512) * 512));
// next block is the real header
$block = $this->readbytes(512);
$return = $this->parseHeader($block);

View File

@ -272,7 +272,7 @@ class Zip extends Archive
* Add a file to the current archive using an existing file in the filesystem
*
* @param string $file path to the original file
* @param string|FileInfo $fileinfo either the name to us in archive (string) or a FileInfo oject with all meta data, empty to take from original
* @param string|FileInfo $fileinfo either the name to use in archive (string) or a FileInfo oject with all meta data, empty to take from original
* @throws ArchiveIOException
*/
public function addFile($file, $fileinfo = '')
@ -295,7 +295,7 @@ class Zip extends Archive
}
/**
* Add a file to the current TAR archive using the given $data as content
* Add a file to the current Zip archive using the given $data as content
*
* @param string|FileInfo $fileinfo either the name to us in archive (string) or a FileInfo oject with all meta data
* @param string $data binary content of the file to add
@ -495,8 +495,10 @@ class Zip extends Archive
if ($header['extra_len'] != 0) {
$header['extra'] = fread($this->fh, $header['extra_len']);
$header['extradata'] = $this->parseExtra($header['extra']);
} else {
$header['extra'] = '';
$header['extradata'] = array();
}
if ($header['comment_len'] != 0) {
@ -536,8 +538,10 @@ class Zip extends Archive
$header['filename'] = fread($this->fh, $data['filename_len']);
if ($data['extra_len'] != 0) {
$header['extra'] = fread($this->fh, $data['extra_len']);
$header['extradata'] = array_merge($header['extradata'], $this->parseExtra($header['extra']));
} else {
$header['extra'] = '';
$header['extradata'] = array();
}
$header['compression'] = $data['compression'];
@ -559,6 +563,35 @@ class Zip extends Archive
return $header;
}
/**
* Parse the extra headers into fields
*
* @param string $header
* @return array
*/
protected function parseExtra($header)
{
$extra = array();
// parse all extra fields as raw values
while (strlen($header) !== 0) {
$set = unpack('vid/vlen', $header);
$header = substr($header, 4);
$value = substr($header, 0, $set['len']);
$header = substr($header, $set['len']);
$extra[$set['id']] = $value;
}
// handle known ones
if(isset($extra[0x6375])) {
$extra['utf8comment'] = substr($extra[0x7075], 5); // strip version and crc
}
if(isset($extra[0x7075])) {
$extra['utf8path'] = substr($extra[0x7075], 5); // strip version and crc
}
return $extra;
}
/**
* Create fileinfo object from header data
*
@ -568,15 +601,75 @@ class Zip extends Archive
protected function header2fileinfo($header)
{
$fileinfo = new FileInfo();
$fileinfo->setPath($header['filename']);
$fileinfo->setSize($header['size']);
$fileinfo->setCompressedSize($header['compressed_size']);
$fileinfo->setMtime($header['mtime']);
$fileinfo->setComment($header['comment']);
$fileinfo->setIsdir($header['external'] == 0x41FF0010 || $header['external'] == 16);
if(isset($header['extradata']['utf8path'])) {
$fileinfo->setPath($header['extradata']['utf8path']);
} else {
$fileinfo->setPath($this->cpToUtf8($header['filename']));
}
if(isset($header['extradata']['utf8comment'])) {
$fileinfo->setComment($header['extradata']['utf8comment']);
} else {
$fileinfo->setComment($this->cpToUtf8($header['comment']));
}
return $fileinfo;
}
/**
* Convert the given CP437 encoded string to UTF-8
*
* Tries iconv with the correct encoding first, falls back to mbstring with CP850 which is
* similar enough. CP437 seems not to be available in mbstring. Lastly falls back to keeping the
* string as is, which is still better than nothing.
*
* @param $string
* @return string
*/
protected function cpToUtf8($string)
{
if (function_exists('iconv')) {
return iconv('CP437', 'UTF-8', $string);
} elseif (function_exists('mb_convert_encoding')) {
return mb_convert_encoding($string, 'UTF-8', 'CP850');
} else {
return $string;
}
}
/**
* Convert the given UTF-8 encoded string to CP437
*
* Same caveats as for cpToUtf8() apply
*
* @param $string
* @return string
*/
protected function utf8ToCp($string)
{
// try iconv first
if (function_exists('iconv')) {
$conv = @iconv('UTF-8', 'CP437//IGNORE', $string);
if($conv) return $conv; // it worked
}
// still here? iconv failed to convert the string. Try another method
// see http://php.net/manual/en/function.iconv.php#108643
if (function_exists('mb_convert_encoding')) {
return mb_convert_encoding($string, 'CP850', 'UTF-8');
} else {
return $string;
}
}
/**
* Write to the open filepointer or memory
*
@ -684,6 +777,8 @@ class Zip extends Archive
$comp = $comp ? 8 : 0;
$dtime = dechex($this->makeDosTime($ts));
list($name, $extra) = $this->encodeFilename($name);
$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
@ -700,13 +795,14 @@ class Zip extends Archive
$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', strlen($extra)); // 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
$header .= $extra; // extra (utf-8 filename)
return $header;
}
@ -728,6 +824,8 @@ class Zip extends Archive
$comp = $comp ? 8 : 0;
$dtime = dechex($this->makeDosTime($ts));
list($name, $extra) = $this->encodeFilename($name);
$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
@ -743,8 +841,37 @@ class Zip extends Archive
$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;
$header .= pack('v', strlen($extra)); // extra field length
$header .= $name; // file name
$header .= $extra; // extra (utf-8 filename)
return $header;
}
/**
* Returns an allowed filename and an extra field header
*
* When encoding stuff outside the 7bit ASCII range it needs to be placed in a separate
* extra field
*
* @param $original
* @return array($filename, $extra)
*/
protected function encodeFilename($original)
{
$cp437 = $this->utf8ToCp($original);
if ($cp437 === $original) {
return array($original, '');
}
$extra = pack(
'vvCV',
0x7075, // tag
strlen($original) + 5, // length of file + version + crc
1, // version
crc32($original) // crc
);
$extra .= $original;
return array($cp437, $extra);
}
}