diff options
Diffstat (limited to 'wiki/vendor/splitbrain/php-archive')
-rw-r--r-- | wiki/vendor/splitbrain/php-archive/LICENSE | 19 | ||||
-rw-r--r-- | wiki/vendor/splitbrain/php-archive/README.md | 70 | ||||
-rw-r--r-- | wiki/vendor/splitbrain/php-archive/phpunit.xml | 22 | ||||
-rw-r--r-- | wiki/vendor/splitbrain/php-archive/src/Archive.php | 132 | ||||
-rw-r--r-- | wiki/vendor/splitbrain/php-archive/src/FileInfo.php | 344 | ||||
-rw-r--r-- | wiki/vendor/splitbrain/php-archive/src/Tar.php | 667 | ||||
-rw-r--r-- | wiki/vendor/splitbrain/php-archive/src/Zip.php | 879 |
7 files changed, 0 insertions, 2133 deletions
diff --git a/wiki/vendor/splitbrain/php-archive/LICENSE b/wiki/vendor/splitbrain/php-archive/LICENSE deleted file mode 100644 index 66d08e4..0000000 --- a/wiki/vendor/splitbrain/php-archive/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2015 Andreas Gohr <gohr@cosmocode.de> - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/wiki/vendor/splitbrain/php-archive/README.md b/wiki/vendor/splitbrain/php-archive/README.md deleted file mode 100644 index f18764b..0000000 --- a/wiki/vendor/splitbrain/php-archive/README.md +++ /dev/null @@ -1,70 +0,0 @@ -PHPArchive - Pure PHP ZIP and TAR handling -========================================== - -This library allows to handle new ZIP and TAR archives without the need for any special PHP extensions (gz and bzip are -needed for compression). It can create new files or extract existing ones. - -To keep things simple, the modification (adding or removing files) of existing archives is not supported. - -[](https://travis-ci.org/splitbrain/php-archive) - -Install -------- - -Use composer: - -```php composer.phar require splitbrain/php-archive``` - -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 [API docs](https://splitbrain.github.io/php-archive/) 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: -$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: -$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: -$tar = new Tar(); -$tar->create('myfile.tgz'); -$tar->addFile(...); -$tar->addData(...); -... -$tar->close(); - -// To create a TAR archive directly in memory, create() it, add*() -// files and then either save() or getArchive() it: -$tar = new Tar(); -$tar->setCompression(9, Archive::COMPRESS_BZIP); -$tar->create(); -$tar->addFile(...); -$tar->addData(...); -... -$tar->save('myfile.tbz'); // compresses and saves it -echo $tar->getArchive(); // 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()``` function call. - -The FileInfo class can be used to specify additional info like ownership or permissions when adding a file to -an archive. diff --git a/wiki/vendor/splitbrain/php-archive/phpunit.xml b/wiki/vendor/splitbrain/php-archive/phpunit.xml deleted file mode 100644 index c5e1ad3..0000000 --- a/wiki/vendor/splitbrain/php-archive/phpunit.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<phpunit backupGlobals="false" - backupStaticAttributes="false" - bootstrap="vendor/autoload.php" - colors="true" - convertErrorsToExceptions="true" - convertNoticesToExceptions="true" - convertWarningsToExceptions="true" - processIsolation="false" - stopOnFailure="false" - syntaxCheck="false"> - <testsuites> - <testsuite name="Test Suite"> - <directory suffix=".php">./tests/</directory> - </testsuite> - </testsuites> - <filter> - <whitelist processUncoveredFilesFromWhitelist="false"> - <directory suffix=".php">src</directory> - </whitelist> - </filter> -</phpunit> diff --git a/wiki/vendor/splitbrain/php-archive/src/Archive.php b/wiki/vendor/splitbrain/php-archive/src/Archive.php deleted file mode 100644 index d672cc6..0000000 --- a/wiki/vendor/splitbrain/php-archive/src/Archive.php +++ /dev/null @@ -1,132 +0,0 @@ -<?php - -namespace splitbrain\PHPArchive; - -abstract class Archive -{ - - const COMPRESS_AUTO = -1; - const COMPRESS_NONE = 0; - const COMPRESS_GZIP = 1; - const COMPRESS_BZIP = 2; - - /** - * Set the compression level and type - * - * @param int $level Compression level (0 to 9) - * @param int $type Type of compression to use (use COMPRESS_* constants) - * @return mixed - */ - abstract public function setCompression($level = 9, $type = Archive::COMPRESS_AUTO); - - /** - * Open an existing archive file for reading - * - * @param string $file - * @throws ArchiveIOException - */ - abstract public function open($file); - - /** - * Read the contents of an archive - * - * This function lists the files stored in the archive, and returns an indexed array of FileInfo objects - * - * The archive is closed afer reading the contents, because rewinding is not possible in bzip2 streams. - * Reopen the file with open() again if you want to do additional operations - * - * @return FileInfo[] - */ - abstract public function contents(); - - /** - * Extract an existing archive - * - * The $strip parameter allows you to strip a certain number of path components from the filenames - * found in the archive file, similar to the --strip-components feature of GNU tar. This is triggered when - * an integer is passed as $strip. - * Alternatively a fixed string prefix may be passed in $strip. If the filename matches this prefix, - * the prefix will be stripped. It is recommended to give prefixes with a trailing slash. - * - * By default this will extract all files found in the archive. You can restrict the output using the $include - * and $exclude parameter. Both expect a full regular expression (including delimiters and modifiers). If - * $include is set, only files that match this expression will be extracted. Files that match the $exclude - * expression will never be extracted. Both parameters can be used in combination. Expressions are matched against - * stripped filenames as described above. - * - * The archive is closed afterwards. Reopen the file with open() again if you want to do additional operations - * - * @param string $outdir the target directory for extracting - * @param int|string $strip either the number of path components or a fixed prefix to strip - * @param string $exclude a regular expression of files to exclude - * @param string $include a regular expression of files to include - * @throws ArchiveIOException - * @return array - */ - abstract public function extract($outdir, $strip = '', $exclude = '', $include = ''); - - /** - * Create a new archive file - * - * If $file is empty, the archive file will be created in memory - * - * @param string $file - */ - abstract public function create($file = ''); - - /** - * 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 - * @throws ArchiveIOException - */ - abstract public function addFile($file, $fileinfo = ''); - - /** - * Add a file to the current 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 - * @throws ArchiveIOException - */ - abstract public function addData($fileinfo, $data); - - /** - * Close the archive, close all file handles - * - * After a call to this function no more data can be added to the archive, for - * read access no reading is allowed anymore - */ - abstract public function close(); - - /** - * Returns the created in-memory archive data - * - * This implicitly calls close() on the Archive - */ - abstract public function getArchive(); - - /** - * Save the created in-memory archive data - * - * Note: It is more memory effective to specify the filename in the create() function and - * let the library work on the new file directly. - * - * @param string $file - */ - abstract public function save($file); - -} - -class ArchiveIOException extends \Exception -{ -} - -class ArchiveIllegalCompressionException extends \Exception -{ -} - -class ArchiveCorruptedException extends \Exception -{ -} diff --git a/wiki/vendor/splitbrain/php-archive/src/FileInfo.php b/wiki/vendor/splitbrain/php-archive/src/FileInfo.php deleted file mode 100644 index 99f60c0..0000000 --- a/wiki/vendor/splitbrain/php-archive/src/FileInfo.php +++ /dev/null @@ -1,344 +0,0 @@ -<?php - -namespace splitbrain\PHPArchive; - -/** - * Class FileInfo - * - * stores meta data about a file in an Archive - * - * @author Andreas Gohr <andi@splitbrain.org> - * @package splitbrain\PHPArchive - * @license MIT - */ -class FileInfo -{ - - protected $isdir = false; - protected $path = ''; - protected $size = 0; - protected $csize = 0; - protected $mtime = 0; - protected $mode = 0664; - protected $owner = ''; - protected $group = ''; - protected $uid = 0; - protected $gid = 0; - protected $comment = ''; - - /** - * initialize dynamic defaults - * - * @param string $path The path of the file, can also be set later through setPath() - */ - public function __construct($path = '') - { - $this->mtime = time(); - $this->setPath($path); - } - - /** - * Factory to build FileInfo from existing file or directory - * - * @param string $path path to a file on the local file system - * @param string $as optional path to use inside the archive - * @throws FileInfoException - * @return FileInfo - */ - public static function fromPath($path, $as = '') - { - clearstatcache(false, $path); - - if (!file_exists($path)) { - throw new FileInfoException("$path does not exist"); - } - - $stat = stat($path); - $file = new FileInfo(); - - $file->setPath($path); - $file->setIsdir(is_dir($path)); - $file->setMode(fileperms($path)); - $file->setOwner(fileowner($path)); - $file->setGroup(filegroup($path)); - $file->setSize(filesize($path)); - $file->setUid($stat['uid']); - $file->setGid($stat['gid']); - $file->setMtime($stat['mtime']); - - if ($as) { - $file->setPath($as); - } - - return $file; - } - - /** - * @return int the filesize. always 0 for directories - */ - public function getSize() - { - if($this->isdir) return 0; - return $this->size; - } - - /** - * @param int $size - */ - public function setSize($size) - { - $this->size = $size; - } - - /** - * @return int - */ - public function getCompressedSize() - { - return $this->csize; - } - - /** - * @param int $csize - */ - public function setCompressedSize($csize) - { - $this->csize = $csize; - } - - /** - * @return int - */ - public function getMtime() - { - return $this->mtime; - } - - /** - * @param int $mtime - */ - public function setMtime($mtime) - { - $this->mtime = $mtime; - } - - /** - * @return int - */ - public function getGid() - { - return $this->gid; - } - - /** - * @param int $gid - */ - public function setGid($gid) - { - $this->gid = $gid; - } - - /** - * @return int - */ - public function getUid() - { - return $this->uid; - } - - /** - * @param int $uid - */ - public function setUid($uid) - { - $this->uid = $uid; - } - - /** - * @return string - */ - public function getComment() - { - return $this->comment; - } - - /** - * @param string $comment - */ - public function setComment($comment) - { - $this->comment = $comment; - } - - /** - * @return string - */ - public function getGroup() - { - return $this->group; - } - - /** - * @param string $group - */ - public function setGroup($group) - { - $this->group = $group; - } - - /** - * @return boolean - */ - public function getIsdir() - { - return $this->isdir; - } - - /** - * @param boolean $isdir - */ - public function setIsdir($isdir) - { - // default mode for directories - if ($isdir && $this->mode === 0664) { - $this->mode = 0775; - } - $this->isdir = $isdir; - } - - /** - * @return int - */ - public function getMode() - { - return $this->mode; - } - - /** - * @param int $mode - */ - public function setMode($mode) - { - $this->mode = $mode; - } - - /** - * @return string - */ - public function getOwner() - { - return $this->owner; - } - - /** - * @param string $owner - */ - public function setOwner($owner) - { - $this->owner = $owner; - } - - /** - * @return string - */ - public function getPath() - { - return $this->path; - } - - /** - * @param string $path - */ - public function setPath($path) - { - $this->path = $this->cleanPath($path); - } - - /** - * Cleans up a path and removes relative parts, also strips leading slashes - * - * @param string $path - * @return string - */ - protected function cleanPath($path) - { - $path = str_replace('\\', '/', $path); - $path = explode('/', $path); - $newpath = array(); - foreach ($path as $p) { - if ($p === '' || $p === '.') { - continue; - } - if ($p === '..') { - array_pop($newpath); - continue; - } - array_push($newpath, $p); - } - return trim(implode('/', $newpath), '/'); - } - - /** - * Strip given prefix or number of path segments from the filename - * - * The $strip parameter allows you to strip a certain number of path components from the filenames - * found in the tar file, similar to the --strip-components feature of GNU tar. This is triggered when - * an integer is passed as $strip. - * Alternatively a fixed string prefix may be passed in $strip. If the filename matches this prefix, - * the prefix will be stripped. It is recommended to give prefixes with a trailing slash. - * - * @param int|string $strip - * @return FileInfo - */ - public function strip($strip) - { - $filename = $this->getPath(); - $striplen = strlen($strip); - if (is_int($strip)) { - // if $strip is an integer we strip this many path components - $parts = explode('/', $filename); - if (!$this->getIsdir()) { - $base = array_pop($parts); // keep filename itself - } else { - $base = ''; - } - $filename = join('/', array_slice($parts, $strip)); - if ($base) { - $filename .= "/$base"; - } - } else { - // if strip is a string, we strip a prefix here - if (substr($filename, 0, $striplen) == $strip) { - $filename = substr($filename, $striplen); - } - } - - $this->setPath($filename); - } - - /** - * Does the file match the given include and exclude expressions? - * - * Exclude rules take precedence over include rules - * - * @param string $include Regular expression of files to include - * @param string $exclude Regular expression of files to exclude - * @return bool - */ - public function match($include = '', $exclude = '') - { - $extract = true; - if ($include && !preg_match($include, $this->getPath())) { - $extract = false; - } - if ($exclude && preg_match($exclude, $this->getPath())) { - $extract = false; - } - - return $extract; - } -} - -class FileInfoException extends \Exception -{ -} \ No newline at end of file diff --git a/wiki/vendor/splitbrain/php-archive/src/Tar.php b/wiki/vendor/splitbrain/php-archive/src/Tar.php deleted file mode 100644 index 5f01f39..0000000 --- a/wiki/vendor/splitbrain/php-archive/src/Tar.php +++ /dev/null @@ -1,667 +0,0 @@ -<?php - -namespace splitbrain\PHPArchive; - -/** - * Class Tar - * - * Creates or extracts Tar archives. Supports gz and bzip compression - * - * Long pathnames (>100 chars) are supported in POSIX ustar and GNU longlink formats. - * - * @author Andreas Gohr <andi@splitbrain.org> - * @package splitbrain\PHPArchive - * @license MIT - */ -class Tar extends Archive -{ - - protected $file = ''; - protected $comptype = Archive::COMPRESS_AUTO; - protected $complevel = 9; - protected $fh; - protected $memory = ''; - protected $closed = true; - protected $writeaccess = false; - - /** - * Sets the compression to use - * - * @param int $level Compression level (0 to 9) - * @param int $type Type of compression to use (use COMPRESS_* constants) - * @return mixed - */ - public function setCompression($level = 9, $type = Archive::COMPRESS_AUTO) - { - $this->compressioncheck($type); - $this->comptype = $type; - $this->complevel = $level; - if($level == 0) $this->comptype = Archive::COMPRESS_NONE; - if($type == Archive::COMPRESS_NONE) $this->complevel = 0; - } - - /** - * Open an existing TAR file for reading - * - * @param string $file - * @throws ArchiveIOException - */ - public function open($file) - { - $this->file = $file; - - // update compression to mach file - if ($this->comptype == Tar::COMPRESS_AUTO) { - $this->setCompression($this->complevel, $this->filetype($file)); - } - - // open file handles - if ($this->comptype === Archive::COMPRESS_GZIP) { - $this->fh = @gzopen($this->file, 'rb'); - } elseif ($this->comptype === Archive::COMPRESS_BZIP) { - $this->fh = @bzopen($this->file, 'r'); - } else { - $this->fh = @fopen($this->file, 'rb'); - } - - if (!$this->fh) { - throw new ArchiveIOException('Could not open file for reading: '.$this->file); - } - $this->closed = false; - } - - /** - * Read the contents of a TAR archive - * - * This function lists the files stored in the archive - * - * The archive is closed afer reading the contents, because rewinding is not possible in bzip2 streams. - * Reopen the file with open() again if you want to do additional operations - * - * @throws ArchiveIOException - * @returns FileInfo[] - */ - public function contents() - { - if ($this->closed || !$this->file) { - throw new ArchiveIOException('Can not read from a closed archive'); - } - - $result = array(); - while ($read = $this->readbytes(512)) { - $header = $this->parseHeader($read); - if (!is_array($header)) { - continue; - } - - $this->skipbytes(ceil($header['size'] / 512) * 512); - $result[] = $this->header2fileinfo($header); - } - - $this->close(); - return $result; - } - - /** - * Extract an existing TAR archive - * - * The $strip parameter allows you to strip a certain number of path components from the filenames - * found in the tar file, similar to the --strip-components feature of GNU tar. This is triggered when - * an integer is passed as $strip. - * Alternatively a fixed string prefix may be passed in $strip. If the filename matches this prefix, - * the prefix will be stripped. It is recommended to give prefixes with a trailing slash. - * - * By default this will extract all files found in the archive. You can restrict the output using the $include - * and $exclude parameter. Both expect a full regular expression (including delimiters and modifiers). If - * $include is set only files that match this expression will be extracted. Files that match the $exclude - * expression will never be extracted. Both parameters can be used in combination. Expressions are matched against - * stripped filenames as described above. - * - * The archive is closed afer reading the contents, because rewinding is not possible in bzip2 streams. - * Reopen the file with open() again if you want to do additional operations - * - * @param string $outdir the target directory for extracting - * @param int|string $strip either the number of path components or a fixed prefix to strip - * @param string $exclude a regular expression of files to exclude - * @param string $include a regular expression of files to include - * @throws ArchiveIOException - * @return FileInfo[] - */ - public function extract($outdir, $strip = '', $exclude = '', $include = '') - { - if ($this->closed || !$this->file) { - throw new ArchiveIOException('Can not read from a closed archive'); - } - - $outdir = rtrim($outdir, '/'); - @mkdir($outdir, 0777, true); - if (!is_dir($outdir)) { - throw new ArchiveIOException("Could not create directory '$outdir'"); - } - - $extracted = array(); - while ($dat = $this->readbytes(512)) { - // read the file header - $header = $this->parseHeader($dat); - if (!is_array($header)) { - continue; - } - $fileinfo = $this->header2fileinfo($header); - - // apply strip rules - $fileinfo->strip($strip); - - // skip unwanted files - if (!strlen($fileinfo->getPath()) || !$fileinfo->match($include, $exclude)) { - $this->skipbytes(ceil($header['size'] / 512) * 512); - continue; - } - - // create output directory - $output = $outdir.'/'.$fileinfo->getPath(); - $directory = ($fileinfo->getIsdir()) ? $output : dirname($output); - @mkdir($directory, 0777, true); - - // extract data - if (!$fileinfo->getIsdir()) { - $fp = @fopen($output, "wb"); - if (!$fp) { - throw new ArchiveIOException('Could not open file for writing: '.$output); - } - - $size = floor($header['size'] / 512); - for ($i = 0; $i < $size; $i++) { - fwrite($fp, $this->readbytes(512), 512); - } - if (($header['size'] % 512) != 0) { - fwrite($fp, $this->readbytes(512), $header['size'] % 512); - } - - fclose($fp); - touch($output, $fileinfo->getMtime()); - chmod($output, $fileinfo->getMode()); - } else { - $this->skipbytes(ceil($header['size'] / 512) * 512); // the size is usually 0 for directories - } - - $extracted[] = $fileinfo; - } - - $this->close(); - return $extracted; - } - - /** - * Create a new TAR file - * - * If $file is empty, the tar file will be created in memory - * - * @param string $file - * @throws ArchiveIOException - */ - public function create($file = '') - { - $this->file = $file; - $this->memory = ''; - $this->fh = 0; - - if ($this->file) { - // determine compression - if ($this->comptype == Archive::COMPRESS_AUTO) { - $this->setCompression($this->complevel, $this->filetype($file)); - } - - if ($this->comptype === Archive::COMPRESS_GZIP) { - $this->fh = @gzopen($this->file, 'wb'.$this->complevel); - } elseif ($this->comptype === Archive::COMPRESS_BZIP) { - $this->fh = @bzopen($this->file, 'w'); - } else { - $this->fh = @fopen($this->file, 'wb'); - } - - if (!$this->fh) { - throw new ArchiveIOException('Could not open file for writing: '.$this->file); - } - } - $this->writeaccess = true; - $this->closed = false; - } - - /** - * 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|FileInfo $fileinfo either the name to us in archive (string) or a FileInfo oject with all meta data, empty to take from original - * @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 = '') - { - if (is_string($fileinfo)) { - $fileinfo = FileInfo::fromPath($file, $fileinfo); - } - - if ($this->closed) { - throw new ArchiveIOException('Archive has been closed, files can no longer be added'); - } - - $fp = @fopen($file, 'rb'); - if (!$fp) { - throw new ArchiveIOException('Could not open file for reading: '.$file); - } - - // create file header - $this->writeFileHeader($fileinfo); - - // write data - $read = 0; - while (!feof($fp)) { - $data = fread($fp, 512); - $read += strlen($data); - if ($data === false) { - break; - } - if ($data === '') { - break; - } - $packed = pack("a512", $data); - $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()); - } - } - - /** - * Add a file to the current TAR 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 - * @throws ArchiveIOException - */ - public function addData($fileinfo, $data) - { - if (is_string($fileinfo)) { - $fileinfo = new FileInfo($fileinfo); - } - - if ($this->closed) { - throw new ArchiveIOException('Archive has been closed, files can no longer be added'); - } - - $len = strlen($data); - $fileinfo->setSize($len); - $this->writeFileHeader($fileinfo); - - for ($s = 0; $s < $len; $s += 512) { - $this->writebytes(pack("a512", substr($data, $s, 512))); - } - } - - /** - * Add the closing footer to the archive if in write mode, close all file handles - * - * After a call to this function no more data can be added to the archive, for - * read access no reading is allowed anymore - * - * "Physically, an archive consists of a series of file entries terminated by an end-of-archive entry, which - * consists of two 512 blocks of zero bytes" - * - * @link http://www.gnu.org/software/tar/manual/html_chapter/tar_8.html#SEC134 - */ - public function close() - { - if ($this->closed) { - return; - } // we did this already - - // write footer - if ($this->writeaccess) { - $this->writebytes(pack("a512", "")); - $this->writebytes(pack("a512", "")); - } - - // close file handles - if ($this->file) { - if ($this->comptype === Archive::COMPRESS_GZIP) { - gzclose($this->fh); - } elseif ($this->comptype === Archive::COMPRESS_BZIP) { - bzclose($this->fh); - } else { - fclose($this->fh); - } - - $this->file = ''; - $this->fh = 0; - } - - $this->writeaccess = false; - $this->closed = true; - } - - /** - * Returns the created in-memory archive data - * - * This implicitly calls close() on the Archive - */ - public function getArchive() - { - $this->close(); - - if ($this->comptype === Archive::COMPRESS_AUTO) { - $this->comptype = Archive::COMPRESS_NONE; - } - - if ($this->comptype === Archive::COMPRESS_GZIP) { - return gzencode($this->memory, $this->complevel); - } - if ($this->comptype === Archive::COMPRESS_BZIP) { - return bzcompress($this->memory); - } - return $this->memory; - } - - /** - * Save the created in-memory archive data - * - * Note: It more memory effective to specify the filename in the create() function and - * let the library work on the new file directly. - * - * @param string $file - * @throws ArchiveIOException - */ - public function save($file) - { - if ($this->comptype === Archive::COMPRESS_AUTO) { - $this->setCompression($this->complevel, $this->filetype($file)); - } - - if (!@file_put_contents($file, $this->getArchive())) { - throw new ArchiveIOException('Could not write to file: '.$file); - } - } - - /** - * Read from the open file pointer - * - * @param int $length bytes to read - * @return string - */ - protected function readbytes($length) - { - if ($this->comptype === Archive::COMPRESS_GZIP) { - return @gzread($this->fh, $length); - } elseif ($this->comptype === Archive::COMPRESS_BZIP) { - return @bzread($this->fh, $length); - } else { - return @fread($this->fh, $length); - } - } - - /** - * Write to the open filepointer or memory - * - * @param string $data - * @throws ArchiveIOException - * @return int number of bytes written - */ - protected function writebytes($data) - { - if (!$this->file) { - $this->memory .= $data; - $written = strlen($data); - } elseif ($this->comptype === Archive::COMPRESS_GZIP) { - $written = @gzwrite($this->fh, $data); - } elseif ($this->comptype === Archive::COMPRESS_BZIP) { - $written = @bzwrite($this->fh, $data); - } else { - $written = @fwrite($this->fh, $data); - } - if ($written === false) { - throw new ArchiveIOException('Failed to write to archive stream'); - } - return $written; - } - - /** - * Skip forward in the open file pointer - * - * This is basically a wrapper around seek() (and a workaround for bzip2) - * - * @param int $bytes seek to this position - */ - protected function skipbytes($bytes) - { - if ($this->comptype === Archive::COMPRESS_GZIP) { - @gzseek($this->fh, $bytes, SEEK_CUR); - } elseif ($this->comptype === Archive::COMPRESS_BZIP) { - // there is no seek in bzip2, we simply read on - // bzread allows to read a max of 8kb at once - while($bytes) { - $toread = min(8192, $bytes); - @bzread($this->fh, $toread); - $bytes -= $toread; - } - } else { - @fseek($this->fh, $bytes, SEEK_CUR); - } - } - - /** - * Write the given file metat data as header - * - * @param FileInfo $fileinfo - */ - protected function writeFileHeader(FileInfo $fileinfo) - { - $this->writeRawFileHeader( - $fileinfo->getPath(), - $fileinfo->getUid(), - $fileinfo->getGid(), - $fileinfo->getMode(), - $fileinfo->getSize(), - $fileinfo->getMtime(), - $fileinfo->getIsdir() ? '5' : '0' - ); - } - - /** - * Write a file header to the stream - * - * @param string $name - * @param int $uid - * @param int $gid - * @param int $perm - * @param int $size - * @param int $mtime - * @param string $typeflag Set to '5' for directories - */ - protected function writeRawFileHeader($name, $uid, $gid, $perm, $size, $mtime, $typeflag = '') - { - // handle filename length restrictions - $prefix = ''; - $namelen = strlen($name); - if ($namelen > 100) { - $file = basename($name); - $dir = dirname($name); - if (strlen($file) > 100 || strlen($dir) > 155) { - // we're still too large, let's use GNU longlink - $this->writeRawFileHeader('././@LongLink', 0, 0, 0, $namelen, 0, 'L'); - for ($s = 0; $s < $namelen; $s += 512) { - $this->writebytes(pack("a512", substr($name, $s, 512))); - } - $name = substr($name, 0, 100); // cut off name - } else { - // we're fine when splitting, use POSIX ustar - $prefix = $dir; - $name = $file; - } - } - - // values are needed in octal - $uid = sprintf("%6s ", decoct($uid)); - $gid = sprintf("%6s ", decoct($gid)); - $perm = sprintf("%6s ", decoct($perm)); - $size = sprintf("%11s ", decoct($size)); - $mtime = sprintf("%11s", decoct($mtime)); - - $data_first = pack("a100a8a8a8a12A12", $name, $perm, $uid, $gid, $size, $mtime); - $data_last = pack("a1a100a6a2a32a32a8a8a155a12", $typeflag, '', 'ustar', '', '', '', '', '', $prefix, ""); - - for ($i = 0, $chks = 0; $i < 148; $i++) { - $chks += ord($data_first[$i]); - } - - for ($i = 156, $chks += 256, $j = 0; $i < 512; $i++, $j++) { - $chks += ord($data_last[$j]); - } - - $this->writebytes($data_first); - - $chks = pack("a8", sprintf("%6s ", decoct($chks))); - $this->writebytes($chks.$data_last); - } - - /** - * Decode the given tar file header - * - * @param string $block a 512 byte block containing the header data - * @return array|false returns false when this was a null block - * @throws ArchiveCorruptedException - */ - protected function parseHeader($block) - { - if (!$block || strlen($block) != 512) { - throw new ArchiveCorruptedException('Unexpected length of header'); - } - - // null byte blocks are ignored - if(trim($block) === '') return false; - - for ($i = 0, $chks = 0; $i < 148; $i++) { - $chks += ord($block[$i]); - } - - for ($i = 156, $chks += 256; $i < 512; $i++) { - $chks += ord($block[$i]); - } - - $header = @unpack( - "a100filename/a8perm/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155prefix", - $block - ); - if (!$header) { - throw new ArchiveCorruptedException('Failed to parse header'); - } - - $return['checksum'] = OctDec(trim($header['checksum'])); - if ($return['checksum'] != $chks) { - throw new ArchiveCorruptedException('Header does not match it\'s checksum'); - } - - $return['filename'] = trim($header['filename']); - $return['perm'] = OctDec(trim($header['perm'])); - $return['uid'] = OctDec(trim($header['uid'])); - $return['gid'] = OctDec(trim($header['gid'])); - $return['size'] = OctDec(trim($header['size'])); - $return['mtime'] = OctDec(trim($header['mtime'])); - $return['typeflag'] = $header['typeflag']; - $return['link'] = trim($header['link']); - $return['uname'] = trim($header['uname']); - $return['gname'] = trim($header['gname']); - - // Handle ustar Posix compliant path prefixes - if (trim($header['prefix'])) { - $return['filename'] = trim($header['prefix']).'/'.$return['filename']; - } - - // Handle Long-Link entries from GNU Tar - if ($return['typeflag'] == 'L') { - // following data block(s) is the filename - $filename = trim($this->readbytes(ceil($return['size'] / 512) * 512)); - // next block is the real header - $block = $this->readbytes(512); - $return = $this->parseHeader($block); - // overwrite the filename - $return['filename'] = $filename; - } - - return $return; - } - - /** - * Creates a FileInfo object from the given parsed header - * - * @param $header - * @return FileInfo - */ - protected function header2fileinfo($header) - { - $fileinfo = new FileInfo(); - $fileinfo->setPath($header['filename']); - $fileinfo->setMode($header['perm']); - $fileinfo->setUid($header['uid']); - $fileinfo->setGid($header['gid']); - $fileinfo->setSize($header['size']); - $fileinfo->setMtime($header['mtime']); - $fileinfo->setOwner($header['uname']); - $fileinfo->setGroup($header['gname']); - $fileinfo->setIsdir((bool) $header['typeflag']); - - return $fileinfo; - } - - /** - * Checks if the given compression type is available and throws an exception if not - * - * @param $comptype - * @throws ArchiveIllegalCompressionException - */ - protected function compressioncheck($comptype) - { - if ($comptype === Archive::COMPRESS_GZIP && !function_exists('gzopen')) { - throw new ArchiveIllegalCompressionException('No gzip support available'); - } - - if ($comptype === Archive::COMPRESS_BZIP && !function_exists('bzopen')) { - throw new ArchiveIllegalCompressionException('No bzip2 support available'); - } - } - - /** - * Guesses the wanted compression from the given file - * - * Uses magic bytes for existing files, the file extension otherwise - * - * You don't need to call this yourself. It's used when you pass Archive::COMPRESS_AUTO somewhere - * - * @param string $file - * @return int - */ - public function filetype($file) - { - // for existing files, try to read the magic bytes - if(file_exists($file) && is_readable($file) && filesize($file) > 5) { - $fh = @fopen($file, 'rb'); - if(!$fh) return false; - $magic = fread($fh, 5); - fclose($fh); - - if(strpos($magic, "\x42\x5a") === 0) return Archive::COMPRESS_BZIP; - if(strpos($magic, "\x1f\x8b") === 0) return Archive::COMPRESS_GZIP; - } - - // otherwise rely on file name - $file = strtolower($file); - if (substr($file, -3) == '.gz' || substr($file, -4) == '.tgz') { - return Archive::COMPRESS_GZIP; - } elseif (substr($file, -4) == '.bz2' || substr($file, -4) == '.tbz') { - return Archive::COMPRESS_BZIP; - } - - return Archive::COMPRESS_NONE; - } -} diff --git a/wiki/vendor/splitbrain/php-archive/src/Zip.php b/wiki/vendor/splitbrain/php-archive/src/Zip.php deleted file mode 100644 index e84516b..0000000 --- a/wiki/vendor/splitbrain/php-archive/src/Zip.php +++ /dev/null @@ -1,879 +0,0 @@ -<?php - -namespace splitbrain\PHPArchive; - -/** - * Class Zip - * - * Creates or extracts Zip archives - * - * for specs see http://www.pkware.com/appnote - * - * @author Andreas Gohr <andi@splitbrain.org> - * @package splitbrain\PHPArchive - * @license MIT - */ -class Zip extends Archive -{ - - protected $file = ''; - protected $fh; - protected $memory = ''; - protected $closed = true; - protected $writeaccess = false; - protected $ctrl_dir; - protected $complevel = 9; - - /** - * Set the compression level. - * - * Compression Type is ignored for ZIP - * - * You can call this function before adding each file to set differen compression levels - * for each file. - * - * @param int $level Compression level (0 to 9) - * @param int $type Type of compression to use ignored for ZIP - * @return mixed - */ - public function setCompression($level = 9, $type = Archive::COMPRESS_AUTO) - { - $this->complevel = $level; - } - - /** - * Open an existing ZIP file for reading - * - * @param string $file - * @throws ArchiveIOException - */ - public function open($file) - { - $this->file = $file; - $this->fh = @fopen($this->file, 'rb'); - if (!$this->fh) { - throw new ArchiveIOException('Could not open file for reading: '.$this->file); - } - $this->closed = false; - } - - /** - * Read the contents of a ZIP archive - * - * This function lists the files stored in the archive, and returns an indexed array of FileInfo objects - * - * The archive is closed afer reading the contents, for API compatibility with TAR files - * Reopen the file with open() again if you want to do additional operations - * - * @throws ArchiveIOException - * @return FileInfo[] - */ - public function contents() - { - if ($this->closed || !$this->file) { - throw new ArchiveIOException('Can not read from a closed archive'); - } - - $result = array(); - - $centd = $this->readCentralDir(); - - @rewind($this->fh); - @fseek($this->fh, $centd['offset']); - - for ($i = 0; $i < $centd['entries']; $i++) { - $result[] = $this->header2fileinfo($this->readCentralFileHeader()); - } - - $this->close(); - return $result; - } - - /** - * Extract an existing ZIP archive - * - * The $strip parameter allows you to strip a certain number of path components from the filenames - * found in the tar file, similar to the --strip-components feature of GNU tar. This is triggered when - * an integer is passed as $strip. - * Alternatively a fixed string prefix may be passed in $strip. If the filename matches this prefix, - * the prefix will be stripped. It is recommended to give prefixes with a trailing slash. - * - * By default this will extract all files found in the archive. You can restrict the output using the $include - * and $exclude parameter. Both expect a full regular expression (including delimiters and modifiers). If - * $include is set only files that match this expression will be extracted. Files that match the $exclude - * expression will never be extracted. Both parameters can be used in combination. Expressions are matched against - * stripped filenames as described above. - * - * @param string $outdir the target directory for extracting - * @param int|string $strip either the number of path components or a fixed prefix to strip - * @param string $exclude a regular expression of files to exclude - * @param string $include a regular expression of files to include - * @throws ArchiveIOException - * @return FileInfo[] - */ - public function extract($outdir, $strip = '', $exclude = '', $include = '') - { - if ($this->closed || !$this->file) { - throw new ArchiveIOException('Can not read from a closed archive'); - } - - $outdir = rtrim($outdir, '/'); - @mkdir($outdir, 0777, true); - - $extracted = array(); - - $cdir = $this->readCentralDir(); - $pos_entry = $cdir['offset']; // begin of the central file directory - - for ($i = 0; $i < $cdir['entries']; $i++) { - // read file header - @fseek($this->fh, $pos_entry); - $header = $this->readCentralFileHeader(); - $header['index'] = $i; - $pos_entry = ftell($this->fh); // position of the next file in central file directory - fseek($this->fh, $header['offset']); // seek to beginning of file header - $header = $this->readFileHeader($header); - $fileinfo = $this->header2fileinfo($header); - - // apply strip rules - $fileinfo->strip($strip); - - // skip unwanted files - if (!strlen($fileinfo->getPath()) || !$fileinfo->match($include, $exclude)) { - continue; - } - - $extracted[] = $fileinfo; - - // create output directory - $output = $outdir.'/'.$fileinfo->getPath(); - $directory = ($header['folder']) ? $output : dirname($output); - @mkdir($directory, 0777, true); - - // nothing more to do for directories - if ($fileinfo->getIsdir()) { - continue; - } - - // compressed files are written to temporary .gz file first - if ($header['compression'] == 0) { - $extractto = $output; - } else { - $extractto = $output.'.gz'; - } - - // open file for writing - $fp = @fopen($extractto, "wb"); - if (!$fp) { - throw new ArchiveIOException('Could not open file for writing: '.$extractto); - } - - // prepend compression header - if ($header['compression'] != 0) { - $binary_data = pack( - 'va1a1Va1a1', - 0x8b1f, - chr($header['compression']), - chr(0x00), - time(), - chr(0x00), - chr(3) - ); - fwrite($fp, $binary_data, 10); - } - - // read the file and store it on disk - $size = $header['compressed_size']; - while ($size != 0) { - $read_size = ($size < 2048 ? $size : 2048); - $buffer = fread($this->fh, $read_size); - $binary_data = pack('a'.$read_size, $buffer); - fwrite($fp, $binary_data, $read_size); - $size -= $read_size; - } - - // finalize compressed file - if ($header['compression'] != 0) { - $binary_data = pack('VV', $header['crc'], $header['size']); - fwrite($fp, $binary_data, 8); - } - - // close file - fclose($fp); - - // unpack compressed file - if ($header['compression'] != 0) { - $gzp = @gzopen($extractto, 'rb'); - if (!$gzp) { - @unlink($extractto); - throw new ArchiveIOException('Failed file extracting. gzip support missing?'); - } - $fp = @fopen($output, 'wb'); - if (!$fp) { - throw new ArchiveIOException('Could not open file for writing: '.$extractto); - } - - $size = $header['size']; - while ($size != 0) { - $read_size = ($size < 2048 ? $size : 2048); - $buffer = gzread($gzp, $read_size); - $binary_data = pack('a'.$read_size, $buffer); - @fwrite($fp, $binary_data, $read_size); - $size -= $read_size; - } - fclose($fp); - gzclose($gzp); - unlink($extractto); // remove temporary gz file - } - - touch($output, $fileinfo->getMtime()); - //FIXME what about permissions? - } - - $this->close(); - return $extracted; - } - - /** - * Create a new ZIP file - * - * If $file is empty, the zip file will be created in memory - * - * @param string $file - * @throws ArchiveIOException - */ - public function create($file = '') - { - $this->file = $file; - $this->memory = ''; - $this->fh = 0; - - if ($this->file) { - $this->fh = @fopen($this->file, 'wb'); - - if (!$this->fh) { - throw new ArchiveIOException('Could not open file for writing: '.$this->file); - } - } - $this->writeaccess = true; - $this->closed = false; - $this->ctrl_dir = array(); - } - - /** - * Add a file to the current ZIP 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 - * @throws ArchiveIOException - */ - - /** - * 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 use in archive (string) or a FileInfo oject with all meta data, empty to take from original - * @throws ArchiveIOException - */ - public function addFile($file, $fileinfo = '') - { - if (is_string($fileinfo)) { - $fileinfo = FileInfo::fromPath($file, $fileinfo); - } - - if ($this->closed) { - throw new ArchiveIOException('Archive has been closed, files can no longer be added'); - } - - $data = @file_get_contents($file); - if ($data === false) { - throw new ArchiveIOException('Could not open file for reading: '.$file); - } - - // FIXME could we stream writing compressed data? gzwrite on a fopen handle? - $this->addData($fileinfo, $data); - } - - /** - * 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 - * @throws ArchiveIOException - */ - public function addData($fileinfo, $data) - { - if (is_string($fileinfo)) { - $fileinfo = new FileInfo($fileinfo); - } - - if ($this->closed) { - throw new ArchiveIOException('Archive has been closed, files can no longer be added'); - } - - // prepare info and compress data - $size = strlen($data); - $crc = crc32($data); - if ($this->complevel) { - $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($data); - - // we store no data descriptor - - // add info to central file directory - $this->ctrl_dir[] = $this->makeCentralFileRecord( - $offset, - $time, - $crc, - $size, - $csize, - $name, - (bool) $this->complevel - ); - } - - /** - * Add the closing footer to the archive if in write mode, close all file handles - * - * After a call to this function no more data can be added to the archive, for - * read access no reading is allowed anymore - */ - public function close() - { - if ($this->closed) { - return; - } // we did this already - - if ($this->writeaccess) { - // write central directory - $offset = $this->dataOffset(); - $ctrldir = join('', $this->ctrl_dir); - $this->writebytes($ctrldir); - - // 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(); - } - - // close file handles - if ($this->file) { - fclose($this->fh); - $this->file = ''; - $this->fh = 0; - } - - $this->writeaccess = false; - $this->closed = true; - } - - /** - * Returns the created in-memory archive data - * - * This implicitly calls close() on the Archive - */ - public function getArchive() - { - $this->close(); - - return $this->memory; - } - - /** - * Save the created in-memory archive data - * - * Note: It's more memory effective to specify the filename in the create() function and - * let the library work on the new file directly. - * - * @param $file - * @throws ArchiveIOException - */ - public function save($file) - { - if (!@file_put_contents($file, $this->getArchive())) { - throw new ArchiveIOException('Could not write to file: '.$file); - } - } - - /** - * Read the central directory - * - * This key-value list contains general information about the ZIP file - * - * @return array - */ - protected function readCentralDir() - { - $size = filesize($this->file); - if ($size < 277) { - $maximum_size = $size; - } else { - $maximum_size = 277; - } - - @fseek($this->fh, $size - $maximum_size); - $pos = ftell($this->fh); - $bytes = 0x00000000; - - while ($pos < $size) { - $byte = @fread($this->fh, 1); - $bytes = (($bytes << 8) & 0xFFFFFFFF) | ord($byte); - if ($bytes == 0x504b0506) { - break; - } - $pos++; - } - - $data = unpack( - 'vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', - fread($this->fh, 18) - ); - - if ($data['comment_size'] != 0) { - $centd['comment'] = fread($this->fh, $data['comment_size']); - } else { - $centd['comment'] = ''; - } - $centd['entries'] = $data['entries']; - $centd['disk_entries'] = $data['disk_entries']; - $centd['offset'] = $data['offset']; - $centd['disk_start'] = $data['disk_start']; - $centd['size'] = $data['size']; - $centd['disk'] = $data['disk']; - return $centd; - } - - /** - * Read the next central file header - * - * Assumes the current file pointer is pointing at the right position - * - * @return array - */ - protected function readCentralFileHeader() - { - $binary_data = fread($this->fh, 46); - $header = unpack( - 'vchkid/vid/vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', - $binary_data - ); - - if ($header['filename_len'] != 0) { - $header['filename'] = fread($this->fh, $header['filename_len']); - } else { - $header['filename'] = ''; - } - - 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) { - $header['comment'] = fread($this->fh, $header['comment_len']); - } else { - $header['comment'] = ''; - } - - $header['mtime'] = $this->makeUnixTime($header['mdate'], $header['mtime']); - $header['stored_filename'] = $header['filename']; - $header['status'] = 'ok'; - if (substr($header['filename'], -1) == '/') { - $header['external'] = 0x41FF0010; - } - $header['folder'] = ($header['external'] == 0x41FF0010 || $header['external'] == 16) ? 1 : 0; - - return $header; - } - - /** - * 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 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 - */ - protected function readFileHeader($header) - { - $binary_data = fread($this->fh, 30); - $data = unpack( - 'vchk/vid/vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', - $binary_data - ); - - $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']; - foreach (array( - 'size', - 'compressed_size', - 'crc' - ) as $hd) { // On ODT files, these headers are 0. Keep the previous value. - if ($data[$hd] != 0) { - $header[$hd] = $data[$hd]; - } - } - $header['flag'] = $data['flag']; - $header['mtime'] = $this->makeUnixTime($data['mdate'], $data['mtime']); - - $header['stored_filename'] = $header['filename']; - $header['status'] = "ok"; - $header['folder'] = ($header['external'] == 0x41FF0010 || $header['external'] == 16) ? 1 : 0; - 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 - * - * @param $header - * @return FileInfo - */ - protected function header2fileinfo($header) - { - $fileinfo = new FileInfo(); - $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. - * - * On some systems iconv is available, but the codepage is not. We also check for that. - * - * @param $string - * @return string - */ - protected function cpToUtf8($string) - { - if (function_exists('iconv') && @iconv_strlen('', 'CP437') !== false) { - 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 - * - * @param string $data - * @throws ArchiveIOException - * @return int number of bytes written - */ - protected function writebytes($data) - { - if (!$this->file) { - $this->memory .= $data; - $written = strlen($data); - } else { - $written = @fwrite($this->fh, $data); - } - if ($written === false) { - throw new ArchiveIOException('Failed to write to archive stream'); - } - return $written; - } - - /** - * Current data pointer position - * - * @fixme might need a -1 - * @return int - */ - protected function dataOffset() - { - if ($this->file) { - return ftell($this->fh); - } else { - return strlen($this->memory); - } - } - - /** - * Create a DOS timestamp from a UNIX timestamp - * - * DOS timestamps start at 1980-01-01, earlier UNIX stamps will be set to this date - * - * @param $time - * @return int - */ - protected function makeDosTime($time) - { - $timearray = getdate($time); - if ($timearray['year'] < 1980) { - $timearray['year'] = 1980; - $timearray['mon'] = 1; - $timearray['mday'] = 1; - $timearray['hours'] = 0; - $timearray['minutes'] = 0; - $timearray['seconds'] = 0; - } - return (($timearray['year'] - 1980) << 25) | - ($timearray['mon'] << 21) | - ($timearray['mday'] << 16) | - ($timearray['hours'] << 11) | - ($timearray['minutes'] << 5) | - ($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)); - - 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 - $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', 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; - } - - /** - * 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)); - - 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 - $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', 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); - } -} |