commit vendor
This commit is contained in:
21
vendor/wapmorgan/unified-archive/LICENSE
vendored
Normal file
21
vendor/wapmorgan/unified-archive/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Sergey S. V.
|
||||
|
||||
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.
|
||||
1
vendor/wapmorgan/unified-archive/_config.yml
vendored
Normal file
1
vendor/wapmorgan/unified-archive/_config.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
theme: jekyll-theme-slate
|
||||
97
vendor/wapmorgan/unified-archive/bin/cam
vendored
Normal file
97
vendor/wapmorgan/unified-archive/bin/cam
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
use wapmorgan\UnifiedArchive\CamApplication;
|
||||
use wapmorgan\UnifiedArchive\UnifiedArchive;
|
||||
|
||||
$paths = [
|
||||
// as a root package or phar
|
||||
__DIR__.'/../vendor/autoload.php',
|
||||
// as a dependency from bin
|
||||
__DIR__.'/../autoload.php',
|
||||
// as a dependency from package folder
|
||||
__DIR__.'/../../../autoload.php',
|
||||
];
|
||||
function init_composer(array $paths) {
|
||||
foreach ($paths as $path) {
|
||||
if (file_exists($path)) {
|
||||
require_once $path;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!init_composer($paths)) die('Run `composer install` firstly.'.PHP_EOL);
|
||||
if (!class_exists('\Docopt')) die('Install docopt firsly. Run `composer require docopt/docopt ~1.0`.'.PHP_EOL);
|
||||
|
||||
$version = UnifiedArchive::VERSION;
|
||||
$doc = <<<DOC
|
||||
Universal console archive manager for Windows/Linux (part of UnifiedArchive $version).
|
||||
|
||||
USAGE: cam (-l|--list) ARCHIVE
|
||||
cam (-t|--table) ARCHIVE
|
||||
cam (-i|--info) ARCHIVE
|
||||
cam (-e|--extract) [--output=DIR] [--replace=(all|ask|none|time|size)] [--flat=(file|path)] [--exclude=PATTERN] ARCHIVE [FILES_IN_ARCHIVE...]
|
||||
cam (-p|--print) ARCHIVE FILES_IN_ARCHIVE...
|
||||
cam (-d|--details) ARCHIVE FILES_IN_ARCHIVE...
|
||||
cam (-x|--delete) ARCHIVE FILES_IN_ARCHIVE...
|
||||
cam (-a|--add) ARCHIVE FILES_ON_DISK...
|
||||
cam (-c|--create) ARCHIVE FILES_ON_DISK...
|
||||
cam (-f|--formats)
|
||||
|
||||
ACTIONS:
|
||||
-l(--list) List files in archive
|
||||
-t(--table) List files as table in archive
|
||||
-i(--info) Summary about archive
|
||||
|
||||
-e(--extract) Extract from archive
|
||||
|
||||
-p(--print) Extract archive file content on terminal
|
||||
-d(--details) Details about file in archive
|
||||
-x(--delete) Delete files from archive
|
||||
|
||||
-a(--add) Pack files to archive
|
||||
-c(--create) Create new archive
|
||||
|
||||
OPTIONS:
|
||||
for --extract (-e):
|
||||
--replace=all|ask|none|time|size
|
||||
Set how should be resolved cases in that extracting files already exist.
|
||||
all - replaces all files
|
||||
ask - ask for manual resolution on every case
|
||||
none - preserve all existing on disk files
|
||||
time - selects file with later timestamp
|
||||
size - selects file with bigger size
|
||||
|
||||
--flat=[file,path]
|
||||
Removes all hierarchy and stores all files in one directory. With path option file name will be prepended with in-archive path (all "/" replaced by "-").
|
||||
|
||||
--exclude FILES... or
|
||||
--exclude /PATTERN/
|
||||
Excludes one or few files, directories by exact in-archive path or by regular expression pattern.
|
||||
|
||||
--output=DIRECTORY
|
||||
Set output directory in that all files will be extracted.
|
||||
DOC;
|
||||
|
||||
$args = Docopt::handle($doc, ['version' => UnifiedArchive::VERSION]);
|
||||
|
||||
$actions = array(
|
||||
'l:list' => 'listArray',
|
||||
't:table' => 'table',
|
||||
'i:info' => 'info',
|
||||
'e:extract' => 'extract',
|
||||
'p:print' => 'printFile',
|
||||
'd:details' => 'details',
|
||||
'x:delete' => 'delete',
|
||||
'a:add' => 'add',
|
||||
'c:create' => 'create',
|
||||
'f:formats' => 'checkFormats',
|
||||
);
|
||||
|
||||
foreach ($actions as $arg => $v) {
|
||||
$arg = explode(':', $arg);
|
||||
if ($args['-'.$arg[0]] === true || $args['--'.$arg[1]] === true) {
|
||||
$application = new CamApplication();
|
||||
call_user_func(array($application, $v), $args);
|
||||
}
|
||||
}
|
||||
47
vendor/wapmorgan/unified-archive/src/ArchiveEntry.php
vendored
Normal file
47
vendor/wapmorgan/unified-archive/src/ArchiveEntry.php
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive;
|
||||
|
||||
/**
|
||||
* Information class. Represent information about concrete file in archive.
|
||||
*
|
||||
* @package wapmorgan\UnifiedArchive
|
||||
*/
|
||||
class ArchiveEntry
|
||||
{
|
||||
/** @var string Path of archive entry */
|
||||
public $path;
|
||||
/** @var int Size of packed entry in bytes */
|
||||
public $compressedSize;
|
||||
/** @var int Size of unpacked entry in bytes */
|
||||
public $uncompressedSize;
|
||||
/** @var int Time of entry modification in unix timestamp format. */
|
||||
public $modificationTime;
|
||||
/** @var bool */
|
||||
public $isCompressed;
|
||||
|
||||
/**
|
||||
* @var string Path of archive entry
|
||||
* @deprecated 0.1.0
|
||||
* @see $path property
|
||||
*/
|
||||
public $filename;
|
||||
|
||||
/**
|
||||
* ArchiveEntry constructor.
|
||||
* @param $path
|
||||
* @param $compressedSize
|
||||
* @param $uncompressedSize
|
||||
* @param $modificationTime
|
||||
* @param $isCompressed
|
||||
*/
|
||||
public function __construct($path, $compressedSize, $uncompressedSize, $modificationTime, $isCompressed = null)
|
||||
{
|
||||
$this->path = $path;
|
||||
$this->compressedSize = $compressedSize;
|
||||
$this->uncompressedSize = $uncompressedSize;
|
||||
$this->modificationTime = $modificationTime;
|
||||
if ($isCompressed === null)
|
||||
$isCompressed = $uncompressedSize !== $compressedSize;
|
||||
$this->isCompressed = $isCompressed;
|
||||
}
|
||||
}
|
||||
19
vendor/wapmorgan/unified-archive/src/ArchiveInformation.php
vendored
Normal file
19
vendor/wapmorgan/unified-archive/src/ArchiveInformation.php
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive;
|
||||
|
||||
/**
|
||||
* Information class. Represent information about the whole archive.
|
||||
*
|
||||
* @package wapmorgan\UnifiedArchive
|
||||
*/
|
||||
class ArchiveInformation
|
||||
{
|
||||
/** @var array List of files inside archive */
|
||||
public $files = [];
|
||||
|
||||
/** @var int Size of files inside archive in bytes */
|
||||
public $compressedFilesSize = 0;
|
||||
|
||||
/** @var int Original size of files inside archive in bytes */
|
||||
public $uncompressedFilesSize = 0;
|
||||
}
|
||||
299
vendor/wapmorgan/unified-archive/src/CamApplication.php
vendored
Normal file
299
vendor/wapmorgan/unified-archive/src/CamApplication.php
vendored
Normal file
@ -0,0 +1,299 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive;
|
||||
|
||||
use Exception;
|
||||
use wapmorgan\UnifiedArchive\UnifiedArchive;
|
||||
|
||||
class CamApplication {
|
||||
/**
|
||||
* @param $file
|
||||
* @return UnifiedArchive
|
||||
* @throws Exception
|
||||
* @throws \Archive7z\Exception
|
||||
*/
|
||||
protected function open($file)
|
||||
{
|
||||
if (!UnifiedArchive::canOpenArchive($file))
|
||||
throw new Exception('Could not open archive '.$file.'. Try installing suggested packages or run `cam -f` to see formats support.');
|
||||
|
||||
$archive = UnifiedArchive::open($file);
|
||||
if ($archive === null)
|
||||
throw new Exception('Could not open archive '.$file);
|
||||
|
||||
return $archive;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function checkFormats()
|
||||
{
|
||||
$types = [
|
||||
'.zip' => [UnifiedArchive::canOpenType(UnifiedArchive::ZIP), 'install "zip" extension'],
|
||||
'.rar' => [UnifiedArchive::canOpenType(UnifiedArchive::RAR), 'install "rar" extension'],
|
||||
'.gz' => [UnifiedArchive::canOpenType(UnifiedArchive::GZIP), 'install "zlib" extension'],
|
||||
'.bz2' => [UnifiedArchive::canOpenType(UnifiedArchive::BZIP), 'install "bz2" extension'],
|
||||
'.xz' => [UnifiedArchive::canOpenType(UnifiedArchive::LZMA), 'install "xz" extension'],
|
||||
'.7z' => [UnifiedArchive::canOpenType(UnifiedArchive::SEVEN_ZIP), 'install "gemorroj/archive7z" package'],
|
||||
'.iso' => [UnifiedArchive::canOpenType(UnifiedArchive::ISO), 'install "phpclasses/php-iso-file" package'],
|
||||
'.cab' => [UnifiedArchive::canOpenType(UnifiedArchive::CAB), 'install "wapmorgan/cab-archive" package'],
|
||||
|
||||
'.tar' => [UnifiedArchive::canOpenType(UnifiedArchive::TAR), 'install "phar" extension or "pear/archive_tar" package'],
|
||||
'.tar.gz' => [UnifiedArchive::canOpenType(UnifiedArchive::TAR_GZIP), 'install "phar" extension or "pear/archive_tar" package and "zlib" extension'],
|
||||
'.tar.bz2' => [UnifiedArchive::canOpenType(UnifiedArchive::TAR_BZIP), 'install "phar" extension or "pear/archive_tar" package and "bz2" extension'],
|
||||
'.tar.xz' => [UnifiedArchive::canOpenType(UnifiedArchive::TAR_LZMA), 'install "pear/archive_tar" package and "xz" extension'],
|
||||
'.tar.Z' => [UnifiedArchive::canOpenType(UnifiedArchive::TAR_LZW), 'install "pear/archive_tar" package and "compress" system utility'],
|
||||
];
|
||||
|
||||
$installed = $not_installed = [];
|
||||
|
||||
foreach ($types as $extension => $configuration) {
|
||||
if ($configuration[0]) {
|
||||
$installed[] = $extension;
|
||||
} else {
|
||||
$not_installed[$extension] = $configuration[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($installed)) {
|
||||
echo 'Supported archive types: '.implode(', ', $installed).PHP_EOL;
|
||||
}
|
||||
|
||||
if (!empty($not_installed)) {
|
||||
echo 'Not supported archive types:'.PHP_EOL;
|
||||
array_walk($not_installed, function ($instruction, $extension) {
|
||||
echo '- '.$extension.': '.$instruction.PHP_EOL;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $args
|
||||
* @throws Exception
|
||||
* @throws \Archive7z\Exception
|
||||
*/
|
||||
public function listArray($args)
|
||||
{
|
||||
$archive = $this->open($args['ARCHIVE']);
|
||||
foreach ($archive->getFileNames() as $file) {
|
||||
echo $file.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $args
|
||||
* @throws Exception
|
||||
* @throws \Archive7z\Exception
|
||||
*/
|
||||
public function table($args)
|
||||
{
|
||||
$archive = $this->open($args['ARCHIVE']);
|
||||
|
||||
echo sprintf('%51s | %4s | %-18s'.PHP_EOL, 'File name', 'Size', 'Date');
|
||||
echo str_repeat('-', 80).PHP_EOL;
|
||||
foreach ($archive->getFileNames() as $file) {
|
||||
$info = $archive->getFileData($file);
|
||||
$size = $this->formatSize($info->uncompressedSize);
|
||||
$file_name = strlen($file) > 51 ? substr($file, 0, 49).'..' : $file;
|
||||
echo sprintf('%-51s | %1.1f%s | %18s'.PHP_EOL,
|
||||
$file_name,
|
||||
$size[0],
|
||||
$size[1],
|
||||
$this->formatDate($info->modificationTime)
|
||||
);
|
||||
}
|
||||
$size = $this->formatSize($archive->countUncompressedFilesSize());
|
||||
$packed_size = $this->formatSize($archive->countCompressedFilesSize());
|
||||
echo str_repeat('-', 80).PHP_EOL;
|
||||
echo sprintf('%51s | %1.1f%s | %1.1f%s'.PHP_EOL, 'Total '.$archive->countFiles().' file(s)', $size[0], $size[1], $packed_size[0], $packed_size[1]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $bytes
|
||||
* @param int $precision
|
||||
* @return array
|
||||
*/
|
||||
public function formatSize($bytes, $precision = 1)
|
||||
{
|
||||
$units = array('b', 'k', 'm', 'g', 't');
|
||||
|
||||
$bytes = max($bytes, 0);
|
||||
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
||||
$pow = min($pow, count($units) - 1);
|
||||
$bytes /= pow(1024, $pow);
|
||||
$i = round($bytes, $precision);
|
||||
if ($precision == 1 && $i >= 10) {
|
||||
$i = round($i / 1024, 1);
|
||||
$pow++;
|
||||
}
|
||||
|
||||
return array($i, $units[$pow]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $unixtime
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function formatDate($unixtime)
|
||||
{
|
||||
if (strtotime('today') < $unixtime)
|
||||
return 'Today, '.date('G:m', $unixtime);
|
||||
else if (strtotime('yesterday') < $unixtime)
|
||||
return 'Yesterday, '.date('G:m', $unixtime);
|
||||
else {
|
||||
$datetime = new \DateTime();
|
||||
$datetime->setTimestamp($unixtime);
|
||||
if ($datetime->format('Y') == date('Y'))
|
||||
return $datetime->format('d M, G:m');
|
||||
else
|
||||
return $datetime->format('d M Y, G:m');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $args
|
||||
* @throws Exception
|
||||
* @throws \Archive7z\Exception
|
||||
*/
|
||||
public function info($args)
|
||||
{
|
||||
$archive = $this->open($args['ARCHIVE']);
|
||||
echo 'Archive type: '.$archive->getArchiveType().PHP_EOL;
|
||||
echo 'Archive changed: '.$this->formatDate(filemtime($args['ARCHIVE'])).PHP_EOL;
|
||||
echo 'Archive contains: '.$archive->countFiles().' file'.($archive->countFiles() > 1 ? 's' : null).PHP_EOL;
|
||||
echo 'Archive compressed size: '.implode(' ', $this->formatSize($archive->countCompressedFilesSize(), 2)).PHP_EOL;
|
||||
echo 'Archive uncompressed size: '.implode(' ', $this->formatSize($archive->countUncompressedFilesSize(), 2)).PHP_EOL;
|
||||
echo 'Archive compression ratio: '.round($archive->countUncompressedFilesSize() / $archive->countCompressedFilesSize(), 6).'/1 ('.floor($archive->countCompressedFilesSize() / $archive->countUncompressedFilesSize() * 100).'%)'.PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $args
|
||||
* @throws Exception
|
||||
* @throws \Archive7z\Exception
|
||||
*/
|
||||
public function extract($args)
|
||||
{
|
||||
$archive = $this->open($args['ARCHIVE']);
|
||||
$output = getcwd();
|
||||
if (isset($args['--output'])) {
|
||||
if (!is_dir($args['--output']))
|
||||
mkdir($args['--output']);
|
||||
$output = realpath($args['--output']);
|
||||
}
|
||||
|
||||
if (empty($args['FILES_IN_ARCHIVE']) || $args['FILES_IN_ARCHIVE'] == array('/') || $args['FILES_IN_ARCHIVE'] == array('*')) {
|
||||
$result = $archive->extractFiles($output);
|
||||
if ($result === false) echo 'Error occured'.PHP_EOL;
|
||||
else echo 'Extracted '.$result.' file(s) to '.$output.PHP_EOL;
|
||||
} else {
|
||||
$extracted = 0;
|
||||
$errored = [];
|
||||
foreach ($args['FILES_IN_ARCHIVE'] as $file) {
|
||||
$result = $archive->extractFiles($output, $file);
|
||||
if ($result === false) $errored[] = $file;
|
||||
else $extracted += $result;
|
||||
}
|
||||
if (!empty($errored)) echo 'Errored: '.implode(', ', $errored).PHP_EOL;
|
||||
if ($extracted > 0) echo 'Exctracted '.$extracted.' file(s) to '.$output.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $args
|
||||
* @throws Exception
|
||||
* @throws \Archive7z\Exception
|
||||
*/
|
||||
public function printFile($args)
|
||||
{
|
||||
$archive = $this->open($args['ARCHIVE']);
|
||||
foreach ($args['FILES_IN_ARCHIVE'] as $file) {
|
||||
$info = $archive->getFileData($file);
|
||||
if ($info === false) {
|
||||
echo 'File '.$file.' IS NOT PRESENT'.PHP_EOL;
|
||||
continue;
|
||||
}
|
||||
echo 'File content: '.$file.' (size is '.implode('', $this->formatSize($info->uncompressedSize, 1)).')'.PHP_EOL;
|
||||
echo $archive->getFileContent($file).PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $args
|
||||
* @throws Exception
|
||||
* @throws \Archive7z\Exception
|
||||
*/
|
||||
public function details($args)
|
||||
{
|
||||
$archive = $this->open($args['ARCHIVE']);
|
||||
foreach ($args['FILES_IN_ARCHIVE'] as $file) {
|
||||
$info = $archive->getFileData($file);
|
||||
if ($info === false) {
|
||||
echo 'File '.$file.' IS NOT PRESENT'.PHP_EOL;
|
||||
continue;
|
||||
}
|
||||
echo 'File name : '.$file.PHP_EOL;
|
||||
echo 'Compressed size : '.implode('', $this->formatSize($info->compressedSize, 2)).PHP_EOL;
|
||||
echo 'Uncompressed size: '.implode('', $this->formatSize($info->uncompressedSize, 2)).PHP_EOL;
|
||||
echo 'Is compressed : '.($info->isCompressed ? 'yes' : 'no').PHP_EOL;
|
||||
echo 'Date modification: '.$this->formatDate($info->modificationTime).PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $args
|
||||
* @throws Exception
|
||||
* @throws \Archive7z\Exception
|
||||
*/
|
||||
public function delete($args)
|
||||
{
|
||||
$archive = $this->open($args['ARCHIVE']);
|
||||
$files = $archive->getFileNames();
|
||||
foreach ($args['FILES_IN_ARCHIVE'] as $file) {
|
||||
if (!in_array($file, $files)) {
|
||||
echo 'File '.$file.' is NOT in archive'.PHP_EOL;
|
||||
continue;
|
||||
}
|
||||
if ($archive->deleteFiles($file) === false)
|
||||
echo 'Error file '.$file.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $args
|
||||
* @throws Exception
|
||||
* @throws \Archive7z\Exception
|
||||
*/
|
||||
public function add($args)
|
||||
{
|
||||
$archive = $this->open($args['ARCHIVE']);
|
||||
$added_files = $archive->addFiles($args['FILES_ON_DISK']);
|
||||
if ($added_files === false)
|
||||
echo 'Error'.PHP_EOL;
|
||||
else
|
||||
echo 'Added '.$added_files.' file(s)'.PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $args
|
||||
* @throws Exception
|
||||
*/
|
||||
public function create($args)
|
||||
{
|
||||
if (file_exists($args['ARCHIVE'])) {
|
||||
if (is_dir($args['ARCHIVE']))
|
||||
echo $args['ARCHIVE'].' is a directory!'.PHP_EOL;
|
||||
else {
|
||||
echo 'File '.$args['ARCHIVE'].' already exists!'.PHP_EOL;
|
||||
}
|
||||
} else {
|
||||
$archived_files = UnifiedArchive::archiveFiles($args['FILES_ON_DISK'], $args['ARCHIVE']);
|
||||
if ($archived_files === false)
|
||||
echo 'Error'.PHP_EOL;
|
||||
else
|
||||
echo 'Created archive ' . $args['ARCHIVE'] . ' with ' . $archived_files . ' file(s) of total size ' . implode('', $this->formatSize(filesize($args['ARCHIVE']))) . PHP_EOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
6
vendor/wapmorgan/unified-archive/src/Exceptions/ArchiveCreationException.php
vendored
Normal file
6
vendor/wapmorgan/unified-archive/src/Exceptions/ArchiveCreationException.php
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Exceptions;
|
||||
|
||||
class ArchiveCreationException extends \Exception
|
||||
{
|
||||
}
|
||||
6
vendor/wapmorgan/unified-archive/src/Exceptions/ArchiveExtractionException.php
vendored
Normal file
6
vendor/wapmorgan/unified-archive/src/Exceptions/ArchiveExtractionException.php
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Exceptions;
|
||||
|
||||
class ArchiveExtractionException extends \Exception
|
||||
{
|
||||
}
|
||||
6
vendor/wapmorgan/unified-archive/src/Exceptions/ArchiveModificationException.php
vendored
Normal file
6
vendor/wapmorgan/unified-archive/src/Exceptions/ArchiveModificationException.php
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Exceptions;
|
||||
|
||||
class ArchiveModificationException extends \Exception
|
||||
{
|
||||
}
|
||||
6
vendor/wapmorgan/unified-archive/src/Exceptions/EmptyFileListException.php
vendored
Normal file
6
vendor/wapmorgan/unified-archive/src/Exceptions/EmptyFileListException.php
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Exceptions;
|
||||
|
||||
class EmptyFileListException extends \InvalidArgumentException
|
||||
{
|
||||
}
|
||||
6
vendor/wapmorgan/unified-archive/src/Exceptions/FileAlreadyExistsException.php
vendored
Normal file
6
vendor/wapmorgan/unified-archive/src/Exceptions/FileAlreadyExistsException.php
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Exceptions;
|
||||
|
||||
class FileAlreadyExistsException extends \Exception
|
||||
{
|
||||
}
|
||||
6
vendor/wapmorgan/unified-archive/src/Exceptions/NonExistentArchiveFileException.php
vendored
Normal file
6
vendor/wapmorgan/unified-archive/src/Exceptions/NonExistentArchiveFileException.php
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Exceptions;
|
||||
|
||||
class NonExistentArchiveFileException extends \Exception
|
||||
{
|
||||
}
|
||||
6
vendor/wapmorgan/unified-archive/src/Exceptions/UnsupportedArchiveException.php
vendored
Normal file
6
vendor/wapmorgan/unified-archive/src/Exceptions/UnsupportedArchiveException.php
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Exceptions;
|
||||
|
||||
class UnsupportedArchiveException extends \InvalidArgumentException
|
||||
{
|
||||
}
|
||||
6
vendor/wapmorgan/unified-archive/src/Exceptions/UnsupportedOperationException.php
vendored
Normal file
6
vendor/wapmorgan/unified-archive/src/Exceptions/UnsupportedOperationException.php
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Exceptions;
|
||||
|
||||
class UnsupportedOperationException extends \Exception
|
||||
{
|
||||
}
|
||||
29
vendor/wapmorgan/unified-archive/src/Formats/Archive7z.php
vendored
Normal file
29
vendor/wapmorgan/unified-archive/src/Formats/Archive7z.php
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Formats;
|
||||
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class Archive7z extends \Archive7z\Archive7z
|
||||
{
|
||||
/**
|
||||
* @throws \Archive7z\Exception
|
||||
*/
|
||||
public static function getBinaryVersion()
|
||||
{
|
||||
if (method_exists(__CLASS__, 'makeBinary7z'))
|
||||
$binary = static::makeBinary7z();
|
||||
else {
|
||||
// some hack for gemorroj/archive7z 4.x version
|
||||
$seven_zip = new self(null);
|
||||
$binary = $seven_zip->getAutoCli();
|
||||
unset($seven_zip);
|
||||
}
|
||||
|
||||
$process = new Process([str_replace('\\', '/', $binary)]);
|
||||
$result = $process->mustRun()->getOutput();
|
||||
if (!preg_match('~7-Zip (\[[\d]+\] )?(?<version>\d+\.\d+)~i', $result, $version))
|
||||
return false;
|
||||
|
||||
return $version['version'];
|
||||
}
|
||||
}
|
||||
134
vendor/wapmorgan/unified-archive/src/Formats/BasicFormat.php
vendored
Normal file
134
vendor/wapmorgan/unified-archive/src/Formats/BasicFormat.php
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Formats;
|
||||
|
||||
use wapmorgan\UnifiedArchive\ArchiveEntry;
|
||||
use wapmorgan\UnifiedArchive\ArchiveInformation;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveCreationException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveExtractionException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveModificationException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedArchiveException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedOperationException;
|
||||
use wapmorgan\UnifiedArchive\PclzipZipInterface;
|
||||
|
||||
abstract class BasicFormat
|
||||
{
|
||||
/**
|
||||
* BasicFormat constructor.
|
||||
* @param string $archiveFileName
|
||||
*/
|
||||
abstract public function __construct($archiveFileName);
|
||||
|
||||
/**
|
||||
* Returns summary about an archive.
|
||||
* Called after
|
||||
* - constructing
|
||||
* - addFiles()
|
||||
* - deleteFiles()
|
||||
* @return ArchiveInformation
|
||||
*/
|
||||
abstract public function getArchiveInformation();
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
abstract public function getFileNames();
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function isFileExists($fileName);
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
* @return ArchiveEntry|false
|
||||
*/
|
||||
abstract public function getFileData($fileName);
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
* @return string|false
|
||||
*/
|
||||
abstract public function getFileContent($fileName);
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
* @return bool|resource|string
|
||||
*/
|
||||
abstract public function getFileResource($fileName);
|
||||
|
||||
/**
|
||||
* @param string $outputFolder
|
||||
* @param array $files
|
||||
* @return int Number of extracted files
|
||||
* @throws ArchiveExtractionException
|
||||
*/
|
||||
abstract public function extractFiles($outputFolder, array $files);
|
||||
|
||||
/**
|
||||
* @param string $outputFolder
|
||||
* @return int Number of extracted files
|
||||
* @throws ArchiveExtractionException
|
||||
*/
|
||||
abstract public function extractArchive($outputFolder);
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @return false|int Number of deleted files
|
||||
* @throws UnsupportedOperationException
|
||||
* @throws ArchiveModificationException
|
||||
*/
|
||||
abstract public function deleteFiles(array $files);
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @return int Number of added files
|
||||
* @throws UnsupportedOperationException
|
||||
* @throws ArchiveModificationException
|
||||
*/
|
||||
abstract public function addFiles(array $files);
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @param string $archiveFileName
|
||||
* @return int Number of archived files
|
||||
* @throws UnsupportedOperationException
|
||||
* @throws ArchiveCreationException
|
||||
*/
|
||||
public static function createArchive(array $files, $archiveFileName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function canCreateArchive()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function canAddFiles()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function canDeleteFiles()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException
|
||||
* @return PclzipZipInterface
|
||||
*/
|
||||
public function getPclZip()
|
||||
{
|
||||
throw new UnsupportedOperationException('Format '.get_class($this).' does not support PclZip-interface');
|
||||
}
|
||||
}
|
||||
50
vendor/wapmorgan/unified-archive/src/Formats/Bzip.php
vendored
Normal file
50
vendor/wapmorgan/unified-archive/src/Formats/Bzip.php
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Formats;
|
||||
|
||||
class Bzip extends OneFileFormat
|
||||
{
|
||||
const FORMAT_SUFFIX = 'bz2';
|
||||
|
||||
/**
|
||||
* Bzip constructor.
|
||||
*
|
||||
* @param $archiveFileName
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($archiveFileName)
|
||||
{
|
||||
parent::__construct($archiveFileName);
|
||||
$this->modificationTime = filemtime($this->fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public function getFileContent($fileName = null)
|
||||
{
|
||||
return bzdecompress(file_get_contents($this->fileName));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return bool|resource|string
|
||||
*/
|
||||
public function getFileResource($fileName = null)
|
||||
{
|
||||
return bzopen($this->fileName, 'r');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
protected static function compressData($data)
|
||||
{
|
||||
return bzcompress($data);
|
||||
}
|
||||
}
|
||||
182
vendor/wapmorgan/unified-archive/src/Formats/Cab.php
vendored
Normal file
182
vendor/wapmorgan/unified-archive/src/Formats/Cab.php
vendored
Normal file
@ -0,0 +1,182 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Formats;
|
||||
|
||||
use CabArchive;
|
||||
use Exception;
|
||||
use wapmorgan\UnifiedArchive\ArchiveEntry;
|
||||
use wapmorgan\UnifiedArchive\ArchiveInformation;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveExtractionException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedOperationException;
|
||||
|
||||
class Cab extends BasicFormat
|
||||
{
|
||||
/** @var CabArchive */
|
||||
protected $cab;
|
||||
|
||||
/**
|
||||
* BasicFormat constructor.
|
||||
*
|
||||
* @param string $archiveFileName
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct($archiveFileName)
|
||||
{
|
||||
$this->open($archiveFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iso format destructor
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->cab = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $archiveFileName
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function open($archiveFileName)
|
||||
{
|
||||
try {
|
||||
$this->cab = new CabArchive($archiveFileName);
|
||||
} catch (Exception $e) {
|
||||
throw new Exception('Could not open Cab archive: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArchiveInformation
|
||||
*/
|
||||
public function getArchiveInformation()
|
||||
{
|
||||
$information = new ArchiveInformation();
|
||||
foreach ($this->cab->getFileNames() as $file) {
|
||||
$information->files[] = $file;
|
||||
$file_info = $this->cab->getFileData($file);
|
||||
$information->uncompressedFilesSize += $file_info->size;
|
||||
$information->compressedFilesSize += $file_info->packedSize;
|
||||
}
|
||||
return $information;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFileNames()
|
||||
{
|
||||
return $this->cab->getFileNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isFileExists($fileName)
|
||||
{
|
||||
return in_array($fileName, $this->cab->getFileNames(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return ArchiveEntry|false
|
||||
*/
|
||||
public function getFileData($fileName)
|
||||
{
|
||||
$data = $this->cab->getFileData($fileName);
|
||||
|
||||
return new ArchiveEntry($fileName, $data->packedSize, $data->size, $data->unixtime, $data->is_compressed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return string|false
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getFileContent($fileName)
|
||||
{
|
||||
return $this->cab->getFileContent($fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return bool|resource|string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getFileResource($fileName)
|
||||
{
|
||||
$resource = fopen('php://temp', 'r+');
|
||||
fwrite($resource, $this->cab->getFileContent($fileName));
|
||||
rewind($resource);
|
||||
return $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $outputFolder
|
||||
* @param array $files
|
||||
* @return int Number of extracted files
|
||||
* @throws ArchiveExtractionException
|
||||
*/
|
||||
public function extractFiles($outputFolder, array $files)
|
||||
{
|
||||
try {
|
||||
return $this->cab->extract($outputFolder, $files);
|
||||
} catch (Exception $e) {
|
||||
throw new ArchiveExtractionException($e->getMessage(),
|
||||
$e->getCode(),
|
||||
$e->getPrevious()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $outputFolder
|
||||
* @return int
|
||||
* @throws ArchiveExtractionException
|
||||
*/
|
||||
public function extractArchive($outputFolder)
|
||||
{
|
||||
try {
|
||||
return $this->cab->extract($outputFolder);
|
||||
} catch (Exception $e) {
|
||||
throw new ArchiveExtractionException($e->getMessage(),
|
||||
$e->getCode(),
|
||||
$e->getPrevious()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @return void
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public function deleteFiles(array $files)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @return void
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public function addFiles(array $files)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @param string $archiveFileName
|
||||
* @return void
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public static function createArchive(array $files, $archiveFileName){
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
77
vendor/wapmorgan/unified-archive/src/Formats/Gzip.php
vendored
Normal file
77
vendor/wapmorgan/unified-archive/src/Formats/Gzip.php
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Formats;
|
||||
|
||||
use Exception;
|
||||
|
||||
class Gzip extends OneFileFormat
|
||||
{
|
||||
const FORMAT_SUFFIX = 'gz';
|
||||
|
||||
/**
|
||||
* @param string $file GZipped file
|
||||
* @return array|false Array with 'mtime' and 'size' items
|
||||
*/
|
||||
public static function gzipStat($file)
|
||||
{
|
||||
$fp = fopen($file, 'rb');
|
||||
if (filesize($file) < 18 || strcmp(fread($fp, 2), "\x1f\x8b")) {
|
||||
return false; // Not GZIP format (See RFC 1952)
|
||||
}
|
||||
$method = fread($fp, 1);
|
||||
$flags = fread($fp, 1);
|
||||
$stat = unpack('Vmtime', fread($fp, 4));
|
||||
fseek($fp, -4, SEEK_END);
|
||||
$stat += unpack('Vsize', fread($fp, 4));
|
||||
fclose($fp);
|
||||
|
||||
return $stat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gzip constructor.
|
||||
*
|
||||
* @param $archiveFileName
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($archiveFileName)
|
||||
{
|
||||
parent::__construct($archiveFileName);
|
||||
$stat = static::gzipStat($archiveFileName);
|
||||
if ($stat === false) {
|
||||
throw new Exception('Could not open Gzip file');
|
||||
}
|
||||
$this->uncompressedSize = $stat['size'];
|
||||
$this->modificationTime = $stat['mtime'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public function getFileContent($fileName = null)
|
||||
{
|
||||
return gzdecode(file_get_contents($this->fileName));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return bool|resource|string
|
||||
*/
|
||||
public function getFileResource($fileName = null)
|
||||
{
|
||||
return gzopen($this->fileName, 'rb');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
protected static function compressData($data)
|
||||
{
|
||||
return gzencode($data);
|
||||
}
|
||||
}
|
||||
229
vendor/wapmorgan/unified-archive/src/Formats/Iso.php
vendored
Normal file
229
vendor/wapmorgan/unified-archive/src/Formats/Iso.php
vendored
Normal file
@ -0,0 +1,229 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Formats;
|
||||
|
||||
use wapmorgan\UnifiedArchive\ArchiveEntry;
|
||||
use wapmorgan\UnifiedArchive\ArchiveInformation;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedOperationException;
|
||||
|
||||
class Iso extends BasicFormat
|
||||
{
|
||||
/** @var \CISOFile */
|
||||
protected $iso;
|
||||
|
||||
/** @var array List of files */
|
||||
protected $files = [];
|
||||
|
||||
/** @var array */
|
||||
protected $filesData = [];
|
||||
|
||||
/** @var int */
|
||||
protected $filesSize = 0;
|
||||
|
||||
/** @var null|int Size of block in ISO. Used to find real position of file in ISO */
|
||||
protected $blockSize;
|
||||
|
||||
/**
|
||||
* BasicFormat constructor.
|
||||
*
|
||||
* @param string $archiveFileName
|
||||
*/
|
||||
public function __construct($archiveFileName)
|
||||
{
|
||||
$this->open($archiveFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iso format destructor
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->iso->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $archiveFileName
|
||||
*/
|
||||
protected function open($archiveFileName)
|
||||
{
|
||||
// load php-iso-files
|
||||
$this->iso = new \CISOFile;
|
||||
$this->iso->open($archiveFileName);
|
||||
$this->iso->ISOInit();
|
||||
|
||||
/** @var \CVolumeDescriptor $usedDesc */
|
||||
$usedDesc = $this->iso->GetDescriptor(SUPPLEMENTARY_VOLUME_DESC);
|
||||
if (!$usedDesc)
|
||||
$usedDesc = $this->iso->GetDescriptor(PRIMARY_VOLUME_DESC);
|
||||
$this->blockSize = $usedDesc->iBlockSize;
|
||||
$directories = $usedDesc->LoadMPathTable($this->iso);
|
||||
// iterate over all directories
|
||||
/** @var \CPathTableRecord $Directory */
|
||||
foreach ($directories as $Directory) {
|
||||
$directory = $Directory->GetFullPath($directories);
|
||||
$directory = trim($directory, '/');
|
||||
if ($directory != '') {
|
||||
$directory .= '/';
|
||||
// $this->files[$Directory->Location] = $directory;
|
||||
}
|
||||
// $this->isoCatalogsStructure[$Directory->Location]
|
||||
// = $directory;
|
||||
|
||||
/** @var \CFileDirDescriptors[] $files */
|
||||
$files = $Directory->LoadExtents($this->iso,
|
||||
$usedDesc->iBlockSize, true);
|
||||
if ($files) {
|
||||
/** @var \CFileDirDescriptors $file */
|
||||
foreach ($files as $file) {
|
||||
if (in_array($file->strd_FileId, ['.', '..']) || $file->IsDirectory())
|
||||
continue;
|
||||
$this->files[$file->Location] = $directory.$file->strd_FileId;
|
||||
$this->filesSize += $file->DataLen;
|
||||
|
||||
$this->filesData[$directory . $file->strd_FileId] =
|
||||
[
|
||||
'size' => $file->DataLen,
|
||||
'mtime' =>
|
||||
strtotime((string)$file->isoRecDate),
|
||||
];
|
||||
}
|
||||
}
|
||||
// break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArchiveInformation
|
||||
*/
|
||||
public function getArchiveInformation()
|
||||
{
|
||||
$information = new ArchiveInformation();
|
||||
$information->files = array_values($this->files);
|
||||
$information->compressedFilesSize = $information->uncompressedFilesSize = $this->filesSize;
|
||||
return $information;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFileNames()
|
||||
{
|
||||
return array_values($this->files);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isFileExists($fileName)
|
||||
{
|
||||
return array_key_exists($fileName, $this->filesData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return ArchiveEntry|false
|
||||
*/
|
||||
public function getFileData($fileName)
|
||||
{
|
||||
if (!isset($this->filesData[$fileName]))
|
||||
return false;
|
||||
|
||||
return new ArchiveEntry($fileName, $this->filesData[$fileName]['size'],
|
||||
$this->filesData[$fileName]['size'], $this->filesData[$fileName]['mtime'],false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public function getFileContent($fileName)
|
||||
{
|
||||
$data = $this->prepareForFileExtracting($fileName);
|
||||
return $this->iso->Read($data['size']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return bool|resource|string
|
||||
*/
|
||||
public function getFileResource($fileName)
|
||||
{
|
||||
$data = $this->prepareForFileExtracting($fileName);
|
||||
$resource = fopen('php://temp', 'r+');
|
||||
fwrite($resource, $this->iso->Read($data['size']));
|
||||
rewind($resource);
|
||||
return $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareForFileExtracting($fileName)
|
||||
{
|
||||
$Location = array_search($fileName, $this->files, true);
|
||||
if (!isset($this->filesData[$fileName])) return false;
|
||||
$data = $this->filesData[$fileName];
|
||||
$Location_Real = $Location * $this->blockSize;
|
||||
if ($this->iso->Seek($Location_Real, SEEK_SET) === false)
|
||||
return false;
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $outputFolder
|
||||
* @param array $files
|
||||
* @return void
|
||||
* @throws UnsupportedOperationException
|
||||
* @todo Implement extracting with reading & writing to FS
|
||||
*/
|
||||
public function extractFiles($outputFolder, array $files)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $outputFolder
|
||||
* @return void
|
||||
* @throws UnsupportedOperationException
|
||||
* @todo Implement extracting with reading & writing to FS
|
||||
*/
|
||||
public function extractArchive($outputFolder)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @return void
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public function deleteFiles(array $files)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @return void
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public function addFiles(array $files)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @param string $archiveFileName
|
||||
* @return void
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public static function createArchive(array $files, $archiveFileName){
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
60
vendor/wapmorgan/unified-archive/src/Formats/Lzma.php
vendored
Normal file
60
vendor/wapmorgan/unified-archive/src/Formats/Lzma.php
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Formats;
|
||||
|
||||
/**
|
||||
* Class Lzma
|
||||
*
|
||||
* @package wapmorgan\UnifiedArchive\Formats
|
||||
* @requires ext-lzma2
|
||||
*/
|
||||
class Lzma extends OneFileFormat
|
||||
{
|
||||
const FORMAT_SUFFIX = 'xz';
|
||||
|
||||
/**
|
||||
* Lzma constructor.
|
||||
*
|
||||
* @param $archiveFileName
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($archiveFileName)
|
||||
{
|
||||
parent::__construct($archiveFileName);
|
||||
$this->modificationTime = filemtime($this->fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public function getFileContent($fileName = null)
|
||||
{
|
||||
return stream_get_contents(xzopen($this->fileName, 'r'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return bool|resource|string
|
||||
*/
|
||||
public function getFileResource($fileName = null)
|
||||
{
|
||||
return xzopen($this->fileName, 'r');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
protected static function compressData($data)
|
||||
{
|
||||
$fp = xzopen('php://temp', 'w');
|
||||
xzwrite($fp, $data);
|
||||
$data = stream_get_contents($fp);
|
||||
xzclose($fp);
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
174
vendor/wapmorgan/unified-archive/src/Formats/OneFileFormat.php
vendored
Normal file
174
vendor/wapmorgan/unified-archive/src/Formats/OneFileFormat.php
vendored
Normal file
@ -0,0 +1,174 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Formats;
|
||||
|
||||
use Exception;
|
||||
use wapmorgan\UnifiedArchive\ArchiveEntry;
|
||||
use wapmorgan\UnifiedArchive\ArchiveInformation;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveCreationException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveExtractionException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveModificationException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\EmptyFileListException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedOperationException;
|
||||
|
||||
abstract class OneFileFormat extends BasicFormat
|
||||
{
|
||||
/** @var null|string Should be filled for real format like 'gz' or other */
|
||||
const FORMAT_SUFFIX = null;
|
||||
|
||||
protected $fileName;
|
||||
protected $inArchiveFileName;
|
||||
protected $uncompressedSize;
|
||||
protected $modificationTime;
|
||||
|
||||
/**
|
||||
* BasicFormat constructor.
|
||||
*
|
||||
* @param string $archiveFileName
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($archiveFileName)
|
||||
{
|
||||
if (static::FORMAT_SUFFIX === null)
|
||||
throw new \Exception('Format should be initialized');
|
||||
$this->fileName = $archiveFileName;
|
||||
$this->inArchiveFileName = basename($archiveFileName, '.'.self::FORMAT_SUFFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArchiveInformation
|
||||
*/
|
||||
public function getArchiveInformation()
|
||||
{
|
||||
$information = new ArchiveInformation();
|
||||
$information->compressedFilesSize = filesize($this->fileName);
|
||||
$information->uncompressedFilesSize = $this->uncompressedSize;
|
||||
$information->files[] = $this->inArchiveFileName;
|
||||
return $information;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFileNames()
|
||||
{
|
||||
return [$this->inArchiveFileName];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isFileExists($fileName)
|
||||
{
|
||||
return $fileName === $this->inArchiveFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
* @return ArchiveEntry|false
|
||||
*/
|
||||
public function getFileData($fileName)
|
||||
{
|
||||
return new ArchiveEntry(
|
||||
$this->inArchiveFileName,
|
||||
filesize($this->fileName),
|
||||
$this->uncompressedSize,
|
||||
$this->modificationTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $outputFolder
|
||||
* @param array $files
|
||||
* @return int
|
||||
* @throws ArchiveExtractionException
|
||||
*/
|
||||
public function extractFiles($outputFolder, array $files = null)
|
||||
{
|
||||
return $this->extractArchive($outputFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $outputFolder
|
||||
* @return int
|
||||
* @throws ArchiveExtractionException
|
||||
*/
|
||||
public function extractArchive($outputFolder)
|
||||
{
|
||||
$data = $this->getFileContent($this->inArchiveFileName);
|
||||
if ($data === false)
|
||||
throw new ArchiveExtractionException('Could not extract archive');
|
||||
|
||||
$size = strlen($data);
|
||||
$written = file_put_contents($outputFolder.$this->inArchiveFileName, $data);
|
||||
|
||||
if ($written === true) {
|
||||
throw new ArchiveExtractionException('Could not extract file "'.$this->inArchiveFileName.'": could not write data');
|
||||
} else if ($written < $size) {
|
||||
throw new ArchiveExtractionException('Could not archive file "'.$this->inArchiveFileName.'": written '.$written.' of '.$size);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @return void
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public function deleteFiles(array $files)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @return void
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public function addFiles(array $files)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @param string $archiveFileName
|
||||
* @return int
|
||||
* @throws UnsupportedOperationException
|
||||
* @throws EmptyFileListException
|
||||
* @throws ArchiveCreationException
|
||||
*/
|
||||
public static function createArchive(array $files, $archiveFileName){
|
||||
if (count($files) > 1) {
|
||||
throw new UnsupportedOperationException('One-file format ('.__CLASS__.') could not archive few files');
|
||||
}
|
||||
if (empty($files)) {
|
||||
throw new EmptyFileListException();
|
||||
}
|
||||
|
||||
$filename = array_shift($files);
|
||||
|
||||
$compressed_content = static::compressData(file_get_contents($filename));
|
||||
$size = strlen($compressed_content);
|
||||
$written = file_put_contents($archiveFileName, $compressed_content);
|
||||
|
||||
if ($written === true) {
|
||||
throw new ArchiveCreationException('Could not archive file: could not write data');
|
||||
} else if ($written < $size) {
|
||||
throw new ArchiveCreationException('Could not archive file: written '.$written.' of '.$size);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
*
|
||||
* @return mixed
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
protected static function compressData($data)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
175
vendor/wapmorgan/unified-archive/src/Formats/Rar.php
vendored
Normal file
175
vendor/wapmorgan/unified-archive/src/Formats/Rar.php
vendored
Normal file
@ -0,0 +1,175 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Formats;
|
||||
|
||||
use Exception;
|
||||
use wapmorgan\UnifiedArchive\ArchiveEntry;
|
||||
use wapmorgan\UnifiedArchive\ArchiveInformation;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedOperationException;
|
||||
|
||||
class Rar extends BasicFormat
|
||||
{
|
||||
/** @var \RarArchive */
|
||||
protected $rar;
|
||||
|
||||
/**
|
||||
* BasicFormat constructor.
|
||||
*
|
||||
* @param string $archiveFileName
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($archiveFileName)
|
||||
{
|
||||
\RarException::setUsingExceptions(true);
|
||||
$this->open($archiveFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $archiveFileName
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function open($archiveFileName)
|
||||
{
|
||||
$this->rar = \RarArchive::open($archiveFileName);
|
||||
if ($this->rar === false) {
|
||||
throw new Exception('Could not open Rar archive');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rar format destructor
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->rar->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArchiveInformation
|
||||
*/
|
||||
public function getArchiveInformation()
|
||||
{
|
||||
$information = new ArchiveInformation();
|
||||
foreach ($this->rar->getEntries() as $i => $entry) {
|
||||
if ($entry->isDirectory()) continue;
|
||||
$information->files[] = $entry->getName();
|
||||
$information->compressedFilesSize += $entry->getPackedSize();
|
||||
$information->uncompressedFilesSize += $entry->getUnpackedSize();
|
||||
}
|
||||
return $information;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFileNames()
|
||||
{
|
||||
$files = [];
|
||||
foreach ($this->rar->getEntries() as $i => $entry) {
|
||||
if ($entry->isDirectory()) continue;
|
||||
$files[] = $entry->getName();
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isFileExists($fileName)
|
||||
{
|
||||
return $this->rar->getEntry($fileName) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return ArchiveEntry|false
|
||||
*/
|
||||
public function getFileData($fileName)
|
||||
{
|
||||
$entry = $this->rar->getEntry($fileName);
|
||||
return new ArchiveEntry($fileName, $entry->getPackedSize(), $entry->getUnpackedSize(),
|
||||
strtotime($entry->getFileTime()), $entry->getMethod() != 48);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public function getFileContent($fileName)
|
||||
{
|
||||
$entry = $this->rar->getEntry($fileName);
|
||||
if ($entry->isDirectory()) return false;
|
||||
return stream_get_contents($entry->getStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return bool|resource|string
|
||||
*/
|
||||
public function getFileResource($fileName)
|
||||
{
|
||||
$entry = $this->rar->getEntry($fileName);
|
||||
if ($entry->isDirectory()) return false;
|
||||
return $entry->getStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $outputFolder
|
||||
* @param array $files
|
||||
*
|
||||
* @return false|int
|
||||
*/
|
||||
public function extractFiles($outputFolder, array $files)
|
||||
{
|
||||
$count = 0;
|
||||
foreach ($files as $file) {
|
||||
if ($this->rar->getEntry($file)->extract($outputFolder)) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $outputFolder
|
||||
*
|
||||
* @return false|resource
|
||||
*/
|
||||
public function extractArchive($outputFolder)
|
||||
{
|
||||
return $this->extractFiles($outputFolder, $this->getFileNames());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public function deleteFiles(array $files)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public function addFiles(array $files)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @param string $archiveFileName
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public static function createArchive(array $files, $archiveFileName){
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
236
vendor/wapmorgan/unified-archive/src/Formats/SevenZip.php
vendored
Normal file
236
vendor/wapmorgan/unified-archive/src/Formats/SevenZip.php
vendored
Normal file
@ -0,0 +1,236 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Formats;
|
||||
|
||||
use Exception;
|
||||
use wapmorgan\UnifiedArchive\ArchiveEntry;
|
||||
use wapmorgan\UnifiedArchive\ArchiveInformation;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveCreationException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveExtractionException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveModificationException;
|
||||
|
||||
class SevenZip extends BasicFormat
|
||||
{
|
||||
/** @var Archive7z */
|
||||
protected $sevenZip;
|
||||
|
||||
/**
|
||||
* BasicFormat constructor.
|
||||
*
|
||||
* @param string $archiveFileName
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($archiveFileName)
|
||||
{
|
||||
try {
|
||||
$this->sevenZip = new Archive7z($archiveFileName, null, null);
|
||||
} catch (\Archive7z\Exception $e) {
|
||||
throw new Exception('Could not open 7Zip archive: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArchiveInformation
|
||||
*/
|
||||
public function getArchiveInformation()
|
||||
{
|
||||
$information = new ArchiveInformation();
|
||||
foreach ($this->sevenZip->getEntries() as $entry) {
|
||||
$information->files[] = method_exists($entry, 'getUnixPath')
|
||||
? $entry->getUnixPath()
|
||||
: str_replace('\\', '/', $entry->getPath());
|
||||
$information->compressedFilesSize += (int)$entry->getPackedSize();
|
||||
$information->uncompressedFilesSize += (int)$entry->getSize();
|
||||
}
|
||||
return $information;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFileNames()
|
||||
{
|
||||
$files = [];
|
||||
foreach ($this->sevenZip->getEntries() as $entry)
|
||||
$files[] = $entry->getPath();
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isFileExists($fileName)
|
||||
{
|
||||
return $this->sevenZip->getEntry($fileName) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return ArchiveEntry|false
|
||||
*/
|
||||
public function getFileData($fileName)
|
||||
{
|
||||
$entry = $this->sevenZip->getEntry($fileName);
|
||||
return new ArchiveEntry($fileName, $entry->getPackedSize(), $entry->getSize(),
|
||||
strtotime($entry->getModified()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public function getFileContent($fileName)
|
||||
{
|
||||
$entry = $this->sevenZip->getEntry($fileName);
|
||||
return $entry->getContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return bool|resource|string
|
||||
*/
|
||||
public function getFileResource($fileName)
|
||||
{
|
||||
$resource = fopen('php://temp', 'r+');
|
||||
$entry = $this->sevenZip->getEntry($fileName);
|
||||
|
||||
fwrite($resource, $entry->getContent());
|
||||
rewind($resource);
|
||||
return $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $outputFolder
|
||||
* @param array $files
|
||||
* @return int
|
||||
* @throws ArchiveExtractionException
|
||||
*/
|
||||
public function extractFiles($outputFolder, array $files)
|
||||
{
|
||||
$count = 0;
|
||||
try {
|
||||
$this->sevenZip->setOutputDirectory($outputFolder);
|
||||
|
||||
foreach ($files as $file) {
|
||||
$this->sevenZip->extractEntry($file);
|
||||
$count++;
|
||||
}
|
||||
return $count;
|
||||
} catch (Exception $e) {
|
||||
throw new ArchiveExtractionException('Could not extract archive: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $outputFolder
|
||||
*
|
||||
* @return bool
|
||||
* @throws ArchiveExtractionException
|
||||
*/
|
||||
public function extractArchive($outputFolder)
|
||||
{
|
||||
try {
|
||||
$this->sevenZip->setOutputDirectory($outputFolder);
|
||||
$this->sevenZip->extract();
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
throw new ArchiveExtractionException('Could not extract archive: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @return int Number of deleted files
|
||||
* @throws ArchiveModificationException
|
||||
*/
|
||||
public function deleteFiles(array $files)
|
||||
{
|
||||
$count = 0;
|
||||
try {
|
||||
foreach ($files as $file) {
|
||||
$this->sevenZip->delEntry($file);
|
||||
$count++;
|
||||
}
|
||||
return $count;
|
||||
} catch (Exception $e) {
|
||||
throw new ArchiveModificationException('Could not modify archive: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
*
|
||||
* @return int
|
||||
* @throws ArchiveModificationException
|
||||
*/
|
||||
public function addFiles(array $files)
|
||||
{
|
||||
$added_files = 0;
|
||||
try {
|
||||
foreach ($files as $localName => $filename) {
|
||||
if (!is_null($filename)) {
|
||||
$this->sevenZip->addEntry($filename);
|
||||
$this->sevenZip->renameEntry($filename, $localName);
|
||||
$added_files++;
|
||||
}
|
||||
}
|
||||
return $added_files;
|
||||
} catch (Exception $e) {
|
||||
throw new ArchiveModificationException('Could not modify archive: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @param string $archiveFileName
|
||||
* @return int
|
||||
* @throws ArchiveCreationException
|
||||
*/
|
||||
public static function createArchive(array $files, $archiveFileName) {
|
||||
try {
|
||||
$seven_zip = new Archive7z($archiveFileName);
|
||||
foreach ($files as $localName => $filename) {
|
||||
if ($filename !== null) {
|
||||
$seven_zip->addEntry($filename, true);
|
||||
$seven_zip->renameEntry($filename, $localName);
|
||||
}
|
||||
}
|
||||
unset($seven_zip);
|
||||
} catch (Exception $e) {
|
||||
throw new ArchiveCreationException('Could not create archive: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
return count($files);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws \Archive7z\Exception
|
||||
*/
|
||||
public static function canCreateArchive()
|
||||
{
|
||||
return static::canAddFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws \Archive7z\Exception
|
||||
*/
|
||||
public static function canAddFiles()
|
||||
{
|
||||
$version = Archive7z::getBinaryVersion();
|
||||
return $version !== false && version_compare('9.30', $version, '<=');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function canDeleteFiles()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
649
vendor/wapmorgan/unified-archive/src/Formats/Tar.php
vendored
Normal file
649
vendor/wapmorgan/unified-archive/src/Formats/Tar.php
vendored
Normal file
@ -0,0 +1,649 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Formats;
|
||||
|
||||
use Archive_Tar;
|
||||
use Exception;
|
||||
use FilesystemIterator;
|
||||
use Phar;
|
||||
use PharData;
|
||||
use RecursiveIteratorIterator;
|
||||
use wapmorgan\UnifiedArchive\ArchiveEntry;
|
||||
use wapmorgan\UnifiedArchive\ArchiveInformation;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveCreationException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveExtractionException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveModificationException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\NonExistentArchiveFileException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedArchiveException;
|
||||
use wapmorgan\UnifiedArchive\LzwStreamWrapper;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedOperationException;
|
||||
|
||||
/**
|
||||
* Tar format handler
|
||||
* @package wapmorgan\UnifiedArchive\Formats
|
||||
*/
|
||||
class Tar extends BasicFormat
|
||||
{
|
||||
const TAR = 'tar';
|
||||
const TAR_GZIP = 'tgz';
|
||||
const TAR_BZIP = 'tbz2';
|
||||
const TAR_LZMA = 'txz';
|
||||
const TAR_LZW = 'tar.z';
|
||||
|
||||
/** @var bool */
|
||||
static protected $enabledPearTar;
|
||||
|
||||
/** @var bool */
|
||||
static protected $enabledPharData;
|
||||
/**
|
||||
* Checks system configuration for available Tar-manipulation libraries
|
||||
*/
|
||||
protected static function checkRequirements()
|
||||
{
|
||||
if (self::$enabledPharData === null || self::$enabledPearTar === null) {
|
||||
self::$enabledPearTar = class_exists('\Archive_Tar');
|
||||
self::$enabledPharData = class_exists('\PharData');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether archive can be opened with current system configuration
|
||||
* @param $archiveFileName
|
||||
* @return boolean
|
||||
*/
|
||||
// public static function canOpenArchive($archiveFileName)
|
||||
// {
|
||||
// self::checkRequirements();
|
||||
//
|
||||
// $type = self::detectArchiveType($archiveFileName);
|
||||
// if ($type !== false) {
|
||||
// return self::canOpenType($type);
|
||||
// }
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Detect archive type by its filename or content.
|
||||
* @param $archiveFileName
|
||||
* @param bool $contentCheck
|
||||
* @return string|boolean One of TarArchive type constants OR false if type is not detected
|
||||
*/
|
||||
public static function detectArchiveType($archiveFileName, $contentCheck = true)
|
||||
{
|
||||
// by file name
|
||||
if (preg_match('~\.(?<ext>tar|tgz|tbz2|txz|tar\.(gz|bz2|xz|z))$~', strtolower($archiveFileName), $match)) {
|
||||
switch ($match['ext']) {
|
||||
case 'tar':
|
||||
return self::TAR;
|
||||
|
||||
case 'tgz':
|
||||
case 'tar.gz':
|
||||
return self::TAR_GZIP;
|
||||
|
||||
case 'tbz2':
|
||||
case 'tar.bz2':
|
||||
return self::TAR_BZIP;
|
||||
|
||||
case 'txz':
|
||||
case 'tar.xz':
|
||||
return self::TAR_LZMA;
|
||||
|
||||
case 'tar.z':
|
||||
return self::TAR_LZW;
|
||||
}
|
||||
}
|
||||
|
||||
// by content
|
||||
if ($contentCheck) {
|
||||
$mime_type = mime_content_type($archiveFileName);
|
||||
switch ($mime_type) {
|
||||
case 'application/x-tar':
|
||||
return self::TAR;
|
||||
case 'application/x-gtar':
|
||||
return self::TAR_GZIP;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether specific archive type can be opened with current system configuration
|
||||
* @param $type
|
||||
* @return boolean
|
||||
*/
|
||||
// public static function canOpenType($type)
|
||||
// {
|
||||
// self::checkRequirements();
|
||||
// switch ($type) {
|
||||
// case self::TAR:
|
||||
// return self::$enabledPearTar || self::$enabledPharData;
|
||||
//
|
||||
// case self::TAR_GZIP:
|
||||
// return (self::$enabledPearTar || self::$enabledPharData) && extension_loaded('zlib');
|
||||
//
|
||||
// case self::TAR_BZIP:
|
||||
// return (self::$enabledPearTar || self::$enabledPharData) && extension_loaded('bz2');
|
||||
//
|
||||
//
|
||||
// case self::TAR_LZMA:
|
||||
// return self::$enabledPearTar && extension_loaded('lzma2');
|
||||
//
|
||||
// case self::TAR_LZW:
|
||||
// return self::$enabledPearTar && LzwStreamWrapper::isBinaryAvailable();
|
||||
// }
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @param string $archiveFileName
|
||||
* @return false|int
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function createArchive(array $files, $archiveFileName)
|
||||
{
|
||||
static::checkRequirements();
|
||||
|
||||
if (static::$enabledPharData)
|
||||
return static::createArchiveForPhar($files, $archiveFileName);
|
||||
|
||||
if (static::$enabledPearTar)
|
||||
return static::createArchiveForPear($files, $archiveFileName);
|
||||
|
||||
throw new UnsupportedOperationException('Archive_Tar nor PharData not available');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an archive via Pear library
|
||||
* @param array $files
|
||||
* @param $archiveFileName
|
||||
* @return int
|
||||
* @throws ArchiveCreationException
|
||||
*/
|
||||
protected static function createArchiveForPear(array $files, $archiveFileName)
|
||||
{
|
||||
$compression = null;
|
||||
switch (strtolower(pathinfo($archiveFileName, PATHINFO_EXTENSION))) {
|
||||
case 'gz':
|
||||
case 'tgz':
|
||||
$compression = 'gz';
|
||||
break;
|
||||
case 'bz2':
|
||||
case 'tbz2':
|
||||
$compression = 'bz2';
|
||||
break;
|
||||
case 'xz':
|
||||
$compression = 'lzma2';
|
||||
break;
|
||||
case 'z':
|
||||
$tar_aname = 'compress.lzw://' . $archiveFileName;
|
||||
break;
|
||||
}
|
||||
|
||||
if (isset($tar_aname))
|
||||
$tar = new Archive_Tar($tar_aname, $compression);
|
||||
else
|
||||
$tar = new Archive_Tar($archiveFileName, $compression);
|
||||
|
||||
foreach ($files as $localName => $filename) {
|
||||
$remove_dir = dirname($filename);
|
||||
$add_dir = dirname($localName);
|
||||
|
||||
if (is_null($filename)) {
|
||||
if ($tar->addString($localName, '') === false)
|
||||
throw new ArchiveCreationException('Error when adding directory '.$localName.' to archive');
|
||||
} else {
|
||||
if ($tar->addModify($filename, $add_dir, $remove_dir) === false)
|
||||
throw new ArchiveCreationException('Error when adding file '.$filename.' to archive');
|
||||
}
|
||||
}
|
||||
$tar = null;
|
||||
|
||||
return count($files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an archive via Phar library
|
||||
* @param array $files
|
||||
* @param $archiveFileName
|
||||
* @return bool
|
||||
* @throws ArchiveCreationException
|
||||
*/
|
||||
protected static function createArchiveForPhar(array $files, $archiveFileName)
|
||||
{
|
||||
if (preg_match('~^(.+)\.(tar\.(gz|bz2))$~i', $archiveFileName, $match)) {
|
||||
$ext = $match[2];
|
||||
$basename = $match[1];
|
||||
} else {
|
||||
$ext = pathinfo($archiveFileName, PATHINFO_EXTENSION);
|
||||
$basename = dirname($archiveFileName).'/'.basename($archiveFileName, '.'.$ext);
|
||||
}
|
||||
$tar = new PharData($basename.'.tar', 0, null, Phar::TAR);
|
||||
|
||||
try {
|
||||
foreach ($files as $localName => $filename) {
|
||||
if (is_null($filename)) {
|
||||
if (!in_array($localName, ['/', ''], true)) {
|
||||
if ($tar->addEmptyDir($localName) === false) {
|
||||
throw new ArchiveCreationException('Error when adding directory '.$localName.' to archive');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($tar->addFile($filename, $localName) === false) {
|
||||
throw new ArchiveCreationException('Error when adding file '.$localName.' to archive');
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
throw new ArchiveCreationException('Error when creating archive: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
switch (strtolower(pathinfo($archiveFileName, PATHINFO_EXTENSION))) {
|
||||
case 'gz':
|
||||
case 'tgz':
|
||||
$tar->compress(Phar::GZ, $ext);
|
||||
break;
|
||||
case 'bz2':
|
||||
case 'tbz2':
|
||||
$tar->compress(Phar::BZ2, $ext);
|
||||
break;
|
||||
}
|
||||
$tar = null;
|
||||
|
||||
return count($files);
|
||||
}
|
||||
|
||||
/** @var string Full path to archive */
|
||||
protected $archiveFileName;
|
||||
|
||||
/** @var string Full path to archive */
|
||||
protected $archiveType;
|
||||
|
||||
/** @var Archive_Tar|PharData */
|
||||
protected $tar;
|
||||
|
||||
/** @var float Overall compression ratio of Tar archive when Archive_Tar is used */
|
||||
protected $pearCompressionRatio;
|
||||
|
||||
/** @var array<string, integer> List of files and their index in listContent() result */
|
||||
protected $pearFilesIndex;
|
||||
|
||||
/** @var int Flags for iterator */
|
||||
const PHAR_FLAGS = FilesystemIterator::UNIX_PATHS;
|
||||
|
||||
/**
|
||||
* Tar format constructor.
|
||||
*
|
||||
* @param string $archiveFileName
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct($archiveFileName)
|
||||
{
|
||||
static::checkRequirements();
|
||||
|
||||
$this->archiveFileName = realpath($archiveFileName);
|
||||
$this->archiveType = static::detectArchiveType($this->archiveFileName);
|
||||
|
||||
if ($this->archiveType === false)
|
||||
throw new UnsupportedArchiveException('Could not detect type for archive '.$this->archiveFileName);
|
||||
|
||||
$this->open($this->archiveType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tar destructor
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->tar = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $archiveType
|
||||
* @throws UnsupportedArchiveException
|
||||
*/
|
||||
protected function open($archiveType)
|
||||
{
|
||||
switch ($archiveType) {
|
||||
case self::TAR_GZIP:
|
||||
if (self::$enabledPharData) {
|
||||
$this->tar = new PharData($this->archiveFileName, self::PHAR_FLAGS);
|
||||
} else {
|
||||
$this->tar = new Archive_Tar($this->archiveFileName, 'gz');
|
||||
}
|
||||
break;
|
||||
|
||||
case self::TAR_BZIP:
|
||||
if (self::$enabledPharData) {
|
||||
$this->tar = new PharData($this->archiveFileName, self::PHAR_FLAGS);
|
||||
} else {
|
||||
$this->tar = new Archive_Tar($this->archiveFileName, 'bz2');
|
||||
}
|
||||
break;
|
||||
|
||||
case self::TAR_LZMA:
|
||||
if (!self::$enabledPearTar) {
|
||||
throw new UnsupportedArchiveException('Archive_Tar not available');
|
||||
}
|
||||
$this->tar = new Archive_Tar($this->archiveFileName, 'lzma2');
|
||||
break;
|
||||
|
||||
case self::TAR_LZW:
|
||||
if (!self::$enabledPearTar) {
|
||||
throw new UnsupportedArchiveException('Archive_Tar not available');
|
||||
}
|
||||
|
||||
LzwStreamWrapper::registerWrapper();
|
||||
$this->tar = new Archive_Tar('compress.lzw://' . $this->archiveFileName);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (self::$enabledPharData) {
|
||||
$this->tar = new PharData($this->archiveFileName, self::PHAR_FLAGS);
|
||||
} else {
|
||||
$this->tar = new Archive_Tar($this->archiveFileName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArchiveInformation
|
||||
*/
|
||||
public function getArchiveInformation()
|
||||
{
|
||||
$information = new ArchiveInformation();
|
||||
if ($this->tar instanceof Archive_Tar) {
|
||||
$this->pearFilesIndex = [];
|
||||
|
||||
foreach ($this->tar->listContent() as $i => $file) {
|
||||
// BUG workaround: http://pear.php.net/bugs/bug.php?id=20275
|
||||
if ($file['filename'] === 'pax_global_header') {
|
||||
continue;
|
||||
}
|
||||
$information->files[] = $file['filename'];
|
||||
$information->uncompressedFilesSize += $file['size'];
|
||||
$this->pearFilesIndex[$file['filename']] = $i;
|
||||
}
|
||||
|
||||
$information->uncompressedFilesSize = filesize($this->archiveFileName);
|
||||
$this->pearCompressionRatio = $information->uncompressedFilesSize != 0
|
||||
? ceil($information->compressedFilesSize / $information->uncompressedFilesSize)
|
||||
: 1;
|
||||
} else {
|
||||
$stream_path_length = strlen('phar://'.$this->archiveFileName.'/');
|
||||
foreach (new RecursiveIteratorIterator($this->tar) as $i => $file) {
|
||||
$information->files[] = substr($file->getPathname(), $stream_path_length);
|
||||
$information->compressedFilesSize += $file->getCompressedSize();
|
||||
$information->uncompressedFilesSize += filesize($file->getPathname());
|
||||
}
|
||||
}
|
||||
|
||||
return $information;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFileNames()
|
||||
{
|
||||
return $this->tar instanceof Archive_Tar
|
||||
? $this->getFileNamesForPear()
|
||||
: $this->getFileNamesForPhar();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
* @return bool
|
||||
*/
|
||||
public function isFileExists($fileName)
|
||||
{
|
||||
if ($this->tar instanceof Archive_Tar)
|
||||
return isset($this->pearFilesIndex[$fileName]);
|
||||
|
||||
try {
|
||||
$this->tar->offsetGet($fileName);
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
* @return ArchiveEntry
|
||||
* @throws NonExistentArchiveFileException
|
||||
*/
|
||||
public function getFileData($fileName)
|
||||
{
|
||||
if ($this->tar instanceof Archive_Tar) {
|
||||
if (!isset($this->pearFilesIndex[$fileName]))
|
||||
throw new NonExistentArchiveFileException('File '.$fileName.' is not found in archive files list');
|
||||
|
||||
$index = $this->pearFilesIndex[$fileName];
|
||||
|
||||
$files_list = $this->tar->listContent();
|
||||
if (!isset($files_list[$index]))
|
||||
throw new NonExistentArchiveFileException('File '.$fileName.' is not found in Tar archive');
|
||||
|
||||
$data = $files_list[$index];
|
||||
unset($files_list);
|
||||
|
||||
return new ArchiveEntry($fileName, $data['size'] / $this->pearCompressionRatio,
|
||||
$data['size'], $data['mtime'], in_array(strtolower(pathinfo($this->archiveFileName,
|
||||
PATHINFO_EXTENSION)), array('gz', 'bz2', 'xz', 'Z')));
|
||||
}
|
||||
|
||||
/** @var \PharFileInfo $entry_info */
|
||||
$entry_info = $this->tar->offsetGet($fileName);
|
||||
return new ArchiveEntry($fileName, $entry_info->getSize(), filesize($entry_info->getPathname()),
|
||||
0, $entry_info->isCompressed());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
* @return string
|
||||
* @throws NonExistentArchiveFileException
|
||||
*/
|
||||
public function getFileContent($fileName)
|
||||
{
|
||||
if ($this->tar instanceof Archive_Tar) {
|
||||
if (!isset($this->pearFilesIndex[$fileName]))
|
||||
throw new NonExistentArchiveFileException('File '.$fileName.' is not found in archive files list');
|
||||
|
||||
return $this->tar->extractInString($fileName);
|
||||
}
|
||||
|
||||
return $this->tar->offsetGet($fileName)->getContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
* @return resource
|
||||
* @throws NonExistentArchiveFileException
|
||||
*/
|
||||
public function getFileResource($fileName)
|
||||
{
|
||||
$resource = fopen('php://temp', 'r+');
|
||||
if ($this->tar instanceof Archive_Tar) {
|
||||
if (!isset($this->pearFilesIndex[$fileName]))
|
||||
throw new NonExistentArchiveFileException('File '.$fileName.' is not found in archive files list');
|
||||
|
||||
fwrite($resource, $this->tar->extractInString($fileName));
|
||||
} else
|
||||
fwrite($resource, $this->tar->offsetGet($fileName)->getContent());
|
||||
|
||||
rewind($resource);
|
||||
return $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $outputFolder
|
||||
* @param array $files
|
||||
* @return int
|
||||
* @throws ArchiveExtractionException
|
||||
*/
|
||||
public function extractFiles($outputFolder, array $files)
|
||||
{
|
||||
if ($this->tar instanceof Archive_Tar) {
|
||||
$result = $this->tar->extractList($files, $outputFolder);
|
||||
} else {
|
||||
$result = $this->tar->extractTo($outputFolder, $files, true);
|
||||
}
|
||||
|
||||
if ($result === false) {
|
||||
throw new ArchiveExtractionException('Error when extracting from '.$this->archiveFileName);
|
||||
}
|
||||
|
||||
return count($files);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $outputFolder
|
||||
* @return false|int
|
||||
* @throws ArchiveExtractionException
|
||||
*/
|
||||
public function extractArchive($outputFolder)
|
||||
{
|
||||
if ($this->tar instanceof Archive_Tar) {
|
||||
$result = $this->tar->extract($outputFolder);
|
||||
} else {
|
||||
$result = $this->tar->extractTo($outputFolder, null, true);
|
||||
}
|
||||
|
||||
if ($result === false) {
|
||||
throw new ArchiveExtractionException('Error when extracting from '.$this->archiveFileName);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @return int
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public function deleteFiles(array $files)
|
||||
{
|
||||
if ($this->tar instanceof Archive_Tar)
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
$deleted = 0;
|
||||
|
||||
foreach ($files as $i => $file) {
|
||||
if ($this->tar->delete($file))
|
||||
$deleted++;
|
||||
}
|
||||
|
||||
$this->tar = null;
|
||||
$this->open($this->archiveType);
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @return false|int
|
||||
* @throws ArchiveModificationException
|
||||
*/
|
||||
public function addFiles(array $files)
|
||||
{
|
||||
$added = 0;
|
||||
|
||||
if ($this->tar instanceof Archive_Tar) {
|
||||
foreach ($files as $localName => $filename) {
|
||||
$remove_dir = dirname($filename);
|
||||
$add_dir = dirname($localName);
|
||||
if (is_null($filename)) {
|
||||
if ($this->tar->addString($localName, "") === false) {
|
||||
throw new ArchiveModificationException('Could not add directory "'.$filename.'": '.$this->tar->error_object->message, $this->tar->error_object->code);
|
||||
}
|
||||
} else {
|
||||
if ($this->tar->addModify($filename, $add_dir, $remove_dir) === false) {
|
||||
throw new ArchiveModificationException('Could not add file "'.$filename.'": '.$this->tar->error_object->message, $this->tar->error_object->code);
|
||||
}
|
||||
$added++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
foreach ($files as $localName => $filename) {
|
||||
if (is_null($filename)) {
|
||||
$this->tar->addEmptyDir($localName);
|
||||
} else {
|
||||
$this->tar->addFile($filename, $localName);
|
||||
$added++;
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
throw new ArchiveModificationException('Could not add file "'.$filename.'": '.$e->getMessage(), $e->getCode());
|
||||
}
|
||||
$this->tar = null;
|
||||
// reopen to refresh files list properly
|
||||
$this->open($this->archiveType);
|
||||
}
|
||||
|
||||
return $added;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getFileNamesForPear()
|
||||
{
|
||||
$files = [];
|
||||
|
||||
$Content = $this->tar->listContent();
|
||||
foreach ($Content as $i => $file) {
|
||||
// BUG workaround: http://pear.php.net/bugs/bug.php?id=20275
|
||||
if ($file['filename'] === 'pax_global_header') {
|
||||
continue;
|
||||
}
|
||||
$files[] = $file['filename'];
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getFileNamesForPhar()
|
||||
{
|
||||
$files = [];
|
||||
|
||||
$stream_path_length = strlen('phar://'.$this->archiveFileName.'/');
|
||||
foreach (new RecursiveIteratorIterator($this->tar) as $i => $file) {
|
||||
$files[] = substr($file->getPathname(), $stream_path_length);
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function canCreateArchive()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function canAddFiles()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function canDeleteFiles()
|
||||
{
|
||||
static::checkRequirements();
|
||||
return self::$enabledPharData;
|
||||
}
|
||||
}
|
||||
273
vendor/wapmorgan/unified-archive/src/Formats/Zip.php
vendored
Normal file
273
vendor/wapmorgan/unified-archive/src/Formats/Zip.php
vendored
Normal file
@ -0,0 +1,273 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive\Formats;
|
||||
|
||||
use Exception;
|
||||
use wapmorgan\UnifiedArchive\ArchiveEntry;
|
||||
use wapmorgan\UnifiedArchive\ArchiveInformation;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveCreationException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveExtractionException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveModificationException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedOperationException;
|
||||
use wapmorgan\UnifiedArchive\PclzipZipInterface;
|
||||
use ZipArchive;
|
||||
|
||||
/**
|
||||
* Class Zip
|
||||
*
|
||||
* @package wapmorgan\UnifiedArchive\Formats
|
||||
* @requires ext-zip
|
||||
*/
|
||||
class Zip extends BasicFormat
|
||||
{
|
||||
/** @var ZipArchive */
|
||||
protected $zip;
|
||||
|
||||
/**
|
||||
* BasicFormat constructor.
|
||||
*
|
||||
* @param string $archiveFileName
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($archiveFileName)
|
||||
{
|
||||
$this->open($archiveFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $archiveFileName
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
protected function open($archiveFileName)
|
||||
{
|
||||
$this->zip = new ZipArchive();
|
||||
$open_result = $this->zip->open($archiveFileName);
|
||||
if ($open_result !== true) {
|
||||
throw new UnsupportedOperationException('Could not open Zip archive: '.$open_result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Zip format destructor
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
unset($this->zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArchiveInformation
|
||||
*/
|
||||
public function getArchiveInformation()
|
||||
{
|
||||
$information = new ArchiveInformation();
|
||||
for ($i = 0; $i < $this->zip->numFiles; $i++) {
|
||||
$file = $this->zip->statIndex($i);
|
||||
// skip directories
|
||||
if (in_array(substr($file['name'], -1), ['/', '\\'], true))
|
||||
continue;
|
||||
$information->files[$i] = $file['name'];
|
||||
$information->compressedFilesSize += $file['comp_size'];
|
||||
$information->uncompressedFilesSize += $file['size'];
|
||||
}
|
||||
return $information;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFileNames()
|
||||
{
|
||||
$files = [];
|
||||
for ($i = 0; $i < $this->zip->numFiles; $i++) {
|
||||
$file_name = $this->zip->getNameIndex($i);
|
||||
// skip directories
|
||||
if (in_array(substr($file_name, -1), ['/', '\\'], true))
|
||||
continue;
|
||||
$files[] = $file_name;
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isFileExists($fileName)
|
||||
{
|
||||
return $this->zip->statName($fileName) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return ArchiveEntry
|
||||
*/
|
||||
public function getFileData($fileName)
|
||||
{
|
||||
$stat = $this->zip->statName($fileName);
|
||||
return new ArchiveEntry($fileName, $stat['comp_size'], $stat['size'], $stat['mtime'],
|
||||
$stat['comp_method'] != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return string|false
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getFileContent($fileName)
|
||||
{
|
||||
$result = $this->zip->getFromName($fileName);
|
||||
if ($result === false)
|
||||
throw new Exception('Could not get file information: '.$result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return bool|resource|string
|
||||
*/
|
||||
public function getFileResource($fileName)
|
||||
{
|
||||
return $this->zip->getStream($fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $outputFolder
|
||||
* @param array $files
|
||||
* @return int Number of extracted files
|
||||
* @throws ArchiveExtractionException
|
||||
*/
|
||||
public function extractFiles($outputFolder, array $files)
|
||||
{
|
||||
if ($this->zip->extractTo($outputFolder, $files) === false)
|
||||
throw new ArchiveExtractionException($this->zip->getStatusString(), $this->zip->status);
|
||||
|
||||
return count($files);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $outputFolder
|
||||
* @return int Number of extracted files
|
||||
*@throws ArchiveExtractionException
|
||||
*/
|
||||
public function extractArchive($outputFolder)
|
||||
{
|
||||
if ($this->zip->extractTo($outputFolder) === false)
|
||||
throw new ArchiveExtractionException($this->zip->getStatusString(), $this->zip->status);
|
||||
|
||||
return $this->zip->numFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @return int
|
||||
* @throws ArchiveModificationException
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public function deleteFiles(array $files)
|
||||
{
|
||||
$count = 0;
|
||||
foreach ($files as $file) {
|
||||
if ($this->zip->deleteName($file) === false)
|
||||
throw new ArchiveModificationException($this->zip->getStatusString(), $this->zip->status);
|
||||
$count++;
|
||||
}
|
||||
|
||||
// reopen archive to save changes
|
||||
$archive_filename = $this->zip->filename;
|
||||
$this->zip->close();
|
||||
$this->open($archive_filename);
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @return int
|
||||
* @throws ArchiveModificationException
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public function addFiles(array $files)
|
||||
{
|
||||
$added_files = 0;
|
||||
foreach ($files as $localName => $fileName) {
|
||||
if (is_null($fileName)) {
|
||||
if ($this->zip->addEmptyDir($localName) === false)
|
||||
throw new ArchiveModificationException($this->zip->getStatusString(), $this->zip->status);
|
||||
} else {
|
||||
if ($this->zip->addFile($fileName, $localName) === false)
|
||||
throw new ArchiveModificationException($this->zip->getStatusString(), $this->zip->status);
|
||||
$added_files++;
|
||||
}
|
||||
}
|
||||
|
||||
// reopen archive to save changes
|
||||
$archive_filename = $this->zip->filename;
|
||||
$this->zip->close();
|
||||
$this->open($archive_filename);
|
||||
|
||||
return $added_files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @param string $archiveFileName
|
||||
* @return int
|
||||
* @throws ArchiveCreationException
|
||||
*/
|
||||
public static function createArchive(array $files, $archiveFileName){
|
||||
$zip = new ZipArchive();
|
||||
$result = $zip->open($archiveFileName, ZipArchive::CREATE);
|
||||
|
||||
if ($result !== true)
|
||||
throw new ArchiveCreationException('ZipArchive error: '.$result);
|
||||
|
||||
foreach ($files as $localName => $fileName) {
|
||||
if ($fileName === null) {
|
||||
if ($zip->addEmptyDir($localName) === false)
|
||||
throw new ArchiveCreationException('Could not archive directory "'.$localName.'": '.$zip->getStatusString(), $zip->status);
|
||||
} else {
|
||||
if ($zip->addFile($fileName, $localName) === false)
|
||||
throw new ArchiveCreationException('Could not archive file "'.$fileName.'": '.$zip->getStatusString(), $zip->status);
|
||||
}
|
||||
}
|
||||
$zip->close();
|
||||
|
||||
return count($files);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PclzipZipInterface
|
||||
*/
|
||||
public function getPclZip()
|
||||
{
|
||||
return new PclzipZipInterface($this->zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function canCreateArchive()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function canAddFiles()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function canDeleteFiles()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
440
vendor/wapmorgan/unified-archive/src/LzwStreamWrapper.php
vendored
Normal file
440
vendor/wapmorgan/unified-archive/src/LzwStreamWrapper.php
vendored
Normal file
@ -0,0 +1,440 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive;
|
||||
|
||||
/**
|
||||
* Stream-wrapper and handler for lzw-compressed data.
|
||||
* @requires "compress" system command (linux-only)
|
||||
*
|
||||
* @package wapmorgan\UnifiedArchive
|
||||
*/
|
||||
class LzwStreamWrapper
|
||||
{
|
||||
private static $registered = false;
|
||||
private static $installed;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static function registerWrapper()
|
||||
{
|
||||
if (!self::$registered)
|
||||
stream_wrapper_register('compress.lzw', __CLASS__);
|
||||
self::$registered = true;
|
||||
}
|
||||
|
||||
public static $TMP_FILE_THRESHOLD = 0.5;
|
||||
private static $AVERAGE_COMPRESSION_RATIO = 2;
|
||||
public static $forceTmpFile = false;
|
||||
/** High limit. unit: MBytes.
|
||||
*/
|
||||
public static $highLimit = 512;
|
||||
|
||||
private $mode;
|
||||
private $path;
|
||||
private $tmp;
|
||||
private $tmp2;
|
||||
private $data;
|
||||
private $dataSize;
|
||||
private $pointer;
|
||||
private $writtenBytes = 0;
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @param $mode
|
||||
* @param $options
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function stream_open($path, $mode, $options)
|
||||
{
|
||||
// check for compress & uncompress utility
|
||||
$this->checkBinary();
|
||||
if (self::$installed === false)
|
||||
throw new \Exception('compress and uncompress commands are required');
|
||||
|
||||
$schema = 'compress.lzw://';
|
||||
if (strncasecmp($schema, $path, strlen($schema)) == 0)
|
||||
$path = substr($path, strlen($schema));
|
||||
|
||||
if (file_exists($path)) {
|
||||
$this->path = realpath($path);
|
||||
$expected_data_size = filesize($path)
|
||||
* self::$AVERAGE_COMPRESSION_RATIO;
|
||||
$available_memory = $this->getAvailableMemory();
|
||||
if ($expected_data_size <=
|
||||
(self::$TMP_FILE_THRESHOLD * $available_memory)
|
||||
&& !self::$forceTmpFile
|
||||
&& $expected_data_size < (self::$highLimit * 1024 * 1024)) {
|
||||
$this->read();
|
||||
} else {
|
||||
$prefix = basename(__FILE__, '.php');
|
||||
if (($tmp = tempnam(sys_get_temp_dir(), $prefix)) === false)
|
||||
throw new \Exception(__CLASS__.', line '.__LINE__.
|
||||
': Could not create temporary file in '.
|
||||
sys_get_temp_dir());
|
||||
if (($tmp2 = tempnam(sys_get_temp_dir(), $prefix)) === false)
|
||||
throw new \Exception(__CLASS__.', line '.__LINE__.
|
||||
': Could not create temporary file in '.
|
||||
sys_get_temp_dir());
|
||||
$this->tmp = $tmp;
|
||||
$this->tmp2 = $tmp2;
|
||||
$this->read();
|
||||
}
|
||||
} else {
|
||||
$this->path = $path;
|
||||
if (self::$forceTmpFile) {
|
||||
$prefix = basename(__FILE__, '.php');
|
||||
if (($tmp = tempnam(sys_get_temp_dir(), $prefix)) === false)
|
||||
throw new \Exception(__CLASS__.', line '.__LINE__.
|
||||
': Could not create temporary file in '.
|
||||
sys_get_temp_dir());
|
||||
if (($tmp2 = tempnam(sys_get_temp_dir(), $prefix)) === false)
|
||||
throw new \Exception(__CLASS__.', line '.__LINE__.
|
||||
': Could not create temporary file in '.
|
||||
sys_get_temp_dir());
|
||||
$this->tmp = $tmp;
|
||||
$this->tmp2 = $tmp2;
|
||||
$this->pointer = 0;
|
||||
} else {
|
||||
$this->pointer = 0;
|
||||
}
|
||||
}
|
||||
$this->mode = $mode;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float|int|string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getAvailableMemory()
|
||||
{
|
||||
$limit = strtoupper(ini_get('memory_limit'));
|
||||
$s = array('K', 'M', 'G');
|
||||
if (($multipleer = array_search(substr($limit, -1), $s)) !== false) {
|
||||
$limit = substr($limit, 0, -1) * pow(1024, $multipleer + 1);
|
||||
$limit -= memory_get_usage();
|
||||
} elseif ($limit == -1) {
|
||||
$limit = $this->getSystemMemory();
|
||||
}
|
||||
// var_dump(['multipleer' => $multipleer]);
|
||||
// var_dump(['memory_limit' => $memory_limit]);
|
||||
return $limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getSystemMemory()
|
||||
{
|
||||
self::exec('free --bytes | head -n3 | tail -n1 | awk \'{print $4}\'',
|
||||
$output, $resultCode);
|
||||
|
||||
return trim($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $command
|
||||
* @param $output
|
||||
* @param null $resultCode
|
||||
* @throws \Exception
|
||||
*/
|
||||
private static function exec($command, &$output, &$resultCode = null)
|
||||
{
|
||||
if (function_exists('system')) {
|
||||
ob_start();
|
||||
system($command, $resultCode);
|
||||
$output = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
return;
|
||||
} elseif (function_exists('exec')) {
|
||||
$execOutput = array();
|
||||
exec($command, $execOutput, $resultCode);
|
||||
$output = implode(PHP_EOL, $execOutput);
|
||||
|
||||
return;
|
||||
} elseif (function_exists('proc_open')) {
|
||||
$process = proc_open($command, array(1 =>
|
||||
fopen('php://memory', 'w')), $pipes);
|
||||
$output = stream_get_contents($pipes[1]);
|
||||
fclose($pipes[1]);
|
||||
$resultCode = proc_close($process);
|
||||
|
||||
return;
|
||||
} elseif (function_exists('shell_exec')) {
|
||||
$output = shell_exec($command);
|
||||
|
||||
return;
|
||||
} else {
|
||||
throw new \Exception(__FILE__.', line '.__LINE__
|
||||
.': Execution functions is required! Make sure one of exec'.
|
||||
' function is allowed (system, exec, proc_open, shell_exec)');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function read()
|
||||
{
|
||||
if ($this->tmp !== null) {
|
||||
self::exec('uncompress --stdout '.escapeshellarg($this->path).
|
||||
' > '.$this->tmp, $output, $resultCode);
|
||||
// var_dump(['command' => 'uncompress --stdout '.
|
||||
// escapeshellarg($this->path).' > '.$this->tmp, 'output' =>
|
||||
// $output, 'resultCode' => $resultCode]);
|
||||
if ($resultCode == 0 || $resultCode == 2 || is_null($resultCode)) {
|
||||
$this->dataSize = filesize($this->tmp);
|
||||
// rewind pointer
|
||||
$this->pointer = 0;
|
||||
} else {
|
||||
throw new \Exception(__FILE__.', line '.__LINE__.
|
||||
': Could not read file '.$this->path);
|
||||
}
|
||||
} else {
|
||||
self::exec('uncompress --stdout '.escapeshellarg($this->path),
|
||||
$output, $resultCode);
|
||||
$this->data = &$output;
|
||||
if ($resultCode == 0 || $resultCode == 2 || is_null($resultCode)) {
|
||||
$this->dataSize = strlen($this->data);
|
||||
// rewind pointer
|
||||
$this->pointer = 0;
|
||||
} else {
|
||||
throw new \Exception(__FILE__.', line '.__LINE__.
|
||||
': Could not read file '.$this->path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function stream_stat()
|
||||
{
|
||||
return array(
|
||||
'size' => $this->dataSize,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function stream_close()
|
||||
{
|
||||
// rewrite file
|
||||
if ($this->writtenBytes > 0) {
|
||||
// stored in temp file
|
||||
if ($this->tmp !== null) {
|
||||
// compress in tmp2
|
||||
self::exec('compress -c '.escapeshellarg($this->tmp).' > '.
|
||||
escapeshellarg($this->tmp2), $output, $code);
|
||||
|
||||
// escapeshellarg($this->tmp).' > '.escapeshellarg($this->tmp2),
|
||||
// 'output' => $output, 'code' => $code]);
|
||||
if ($code == 0 || $code == 2 || is_null($code)) {
|
||||
// rewrite original file
|
||||
if (rename($this->tmp2, $this->path) !== true) {
|
||||
throw new \RuntimeException(__FILE__ . ', line ' . __LINE__ .
|
||||
': Could not replace original file ' . $this->path);
|
||||
}
|
||||
} else {
|
||||
throw new \RuntimeException(__FILE__.', line '.__LINE__.
|
||||
': Could not compress changed data in '.$this->tmp2);
|
||||
}
|
||||
} else { // stored in local var
|
||||
// compress in original path
|
||||
// $this->exec('compress '.escapeshellarg($this->tmp).' > '.
|
||||
// escapeshellarg($this->tmp2), $output, $resultCode);
|
||||
if (!function_exists('proc_open')) {
|
||||
throw new \Exception('proc_open is necessary for writing '.
|
||||
'changed data in the file');
|
||||
}
|
||||
//var_dump(['command' => 'compress > '.
|
||||
// escapeshellarg($this->path), 'path' => $this->path]);
|
||||
$process = proc_open('compress > '.escapeshellarg($this->path),
|
||||
array(0 => array('pipe', 'r')), $pipes);
|
||||
// write data to process' input
|
||||
fwrite($pipes[0], $this->data);
|
||||
fclose($pipes[0]);
|
||||
$resultCode = proc_close($process);
|
||||
if ($resultCode == 0 || $resultCode == 2) {
|
||||
// ok
|
||||
} else {
|
||||
throw new \RuntimeException(__FILE__.', line '.__LINE__.
|
||||
': Could not compress changed data in '.$this->path);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->tmp !== null) {
|
||||
unlink($this->tmp);
|
||||
if (file_exists($this->tmp2)) unlink($this->tmp2);
|
||||
} else {
|
||||
$this->data = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $count
|
||||
* @return bool|string
|
||||
*/
|
||||
public function stream_read($count)
|
||||
{
|
||||
if ($this->tmp !== null) {
|
||||
$fp = fopen($this->tmp, 'r'.(strpos($this->mode, 'b') !== 0 ? 'b'
|
||||
: null));
|
||||
fseek($fp, $this->pointer);
|
||||
$data = fread($fp, $count);
|
||||
$this->pointer = ftell($fp);
|
||||
fclose($fp);
|
||||
|
||||
return $data;
|
||||
} else {
|
||||
$data = substr($this->data, $this->pointer,
|
||||
($this->pointer + $count));
|
||||
$this->pointer = $this->pointer + $count;
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function stream_eof()
|
||||
{
|
||||
return $this->pointer >= $this->dataSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function stream_tell()
|
||||
{
|
||||
return $this->pointer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return bool|int
|
||||
*/
|
||||
public function stream_write($data)
|
||||
{
|
||||
$this->writtenBytes += strlen($data);
|
||||
if ($this->tmp !== null) {
|
||||
$fp = fopen($this->tmp, 'w'.(strpos($this->mode, 'b') !== 0 ? 'b'
|
||||
: null));
|
||||
fseek($fp, $this->pointer);
|
||||
$count = fwrite($fp, $data);
|
||||
$this->pointer += $count;
|
||||
fclose($fp);
|
||||
|
||||
return $count;
|
||||
} else {
|
||||
$count = strlen($data);
|
||||
$prefix = substr($this->data, 0, $this->pointer);
|
||||
$postfix = substr($this->data, ($this->pointer + $count));
|
||||
$this->data = $prefix.$data.$postfix;
|
||||
$this->pointer += $count;
|
||||
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $offset
|
||||
* @param int $whence
|
||||
* @return bool
|
||||
*/
|
||||
public function stream_seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
switch ($whence) {
|
||||
case SEEK_SET:
|
||||
$this->pointer = $offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
$this->pointer += $offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
$actual_data_size = (is_null($this->tmp)) ? strlen($this->data)
|
||||
: filesize($this->tmp);
|
||||
$this->pointer = $actual_data_size - $offset;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $operation
|
||||
* @return bool
|
||||
*/
|
||||
public function stream_lock($operation)
|
||||
{
|
||||
if ($this->tmp !== null) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $new_size
|
||||
*/
|
||||
public function stream_truncate($new_size)
|
||||
{
|
||||
$actual_data_size = (is_null($this->tmp)) ? strlen($this->data)
|
||||
: filesize($this->tmp);
|
||||
if ($new_size > $actual_data_size) {
|
||||
$this->stream_write(str_repeat("\00", $new_size
|
||||
- $actual_data_size));
|
||||
} elseif ($new_size < $actual_data_size) {
|
||||
if ($this->tmp === null) {
|
||||
$this->data = substr($this->data, 0, $new_size);
|
||||
} else {
|
||||
$fp = fopen($this->tmp, 'w'.(strpos($this->mode, 'b') !== 0
|
||||
? 'b' : null));
|
||||
ftruncate($fp, $new_size);
|
||||
fclose($fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected static function checkBinary()
|
||||
{
|
||||
if (self::$installed === null) {
|
||||
if (strncasecmp(PHP_OS, 'win', 3) === 0) {
|
||||
self::$installed = false;
|
||||
} else {
|
||||
self::exec('command -v compress', $output);
|
||||
if (empty($output)) {
|
||||
self::$installed = false;
|
||||
} else {
|
||||
self::exec('command -v uncompress', $output);
|
||||
if (empty($output)) {
|
||||
self::$installed = false;
|
||||
} else {
|
||||
self::$installed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function isBinaryAvailable()
|
||||
{
|
||||
self::checkBinary();
|
||||
return self::$installed;
|
||||
}
|
||||
}
|
||||
800
vendor/wapmorgan/unified-archive/src/PclzipZipInterface.php
vendored
Normal file
800
vendor/wapmorgan/unified-archive/src/PclzipZipInterface.php
vendored
Normal file
@ -0,0 +1,800 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive;
|
||||
|
||||
if (!defined('PCLZIP_ERR_NO_ERROR')) {
|
||||
// ----- Constants
|
||||
if (!defined('PCLZIP_READ_BLOCK_SIZE')) {
|
||||
define('PCLZIP_READ_BLOCK_SIZE', 2048);
|
||||
}
|
||||
if (!defined('PCLZIP_SEPARATOR')) {
|
||||
define('PCLZIP_SEPARATOR', ',');
|
||||
}
|
||||
if (!defined('PCLZIP_ERROR_EXTERNAL')) {
|
||||
define('PCLZIP_ERROR_EXTERNAL', 0);
|
||||
}
|
||||
if (!defined('PCLZIP_TEMPORARY_DIR')) {
|
||||
define('PCLZIP_TEMPORARY_DIR', sys_get_temp_dir());
|
||||
}
|
||||
|
||||
define('PCLZIP_ERR_USER_ABORTED', 2);
|
||||
define('PCLZIP_ERR_NO_ERROR', 0);
|
||||
define('PCLZIP_ERR_WRITE_OPEN_FAIL', -1);
|
||||
define('PCLZIP_ERR_READ_OPEN_FAIL', -2);
|
||||
define('PCLZIP_ERR_INVALID_PARAMETER', -3);
|
||||
define('PCLZIP_ERR_MISSING_FILE', -4);
|
||||
define('PCLZIP_ERR_FILENAME_TOO_LONG', -5);
|
||||
define('PCLZIP_ERR_INVALID_ZIP', -6);
|
||||
define('PCLZIP_ERR_BAD_EXTRACTED_FILE', -7);
|
||||
define('PCLZIP_ERR_DIR_CREATE_FAIL', -8);
|
||||
define('PCLZIP_ERR_BAD_EXTENSION', -9);
|
||||
define('PCLZIP_ERR_BAD_FORMAT', -10);
|
||||
define('PCLZIP_ERR_DELETE_FILE_FAIL', -11);
|
||||
define('PCLZIP_ERR_RENAME_FILE_FAIL', -12);
|
||||
define('PCLZIP_ERR_BAD_CHECKSUM', -13);
|
||||
define('PCLZIP_ERR_INVALID_ARCHIVE_ZIP', -14);
|
||||
define('PCLZIP_ERR_MISSING_OPTION_VALUE', -15);
|
||||
define('PCLZIP_ERR_INVALID_OPTION_VALUE', -16);
|
||||
define('PCLZIP_ERR_ALREADY_A_DIRECTORY', -17);
|
||||
define('PCLZIP_ERR_UNSUPPORTED_COMPRESSION', -18);
|
||||
define('PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', -19);
|
||||
define('PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', -20);
|
||||
define('PCLZIP_ERR_DIRECTORY_RESTRICTION', -21);
|
||||
|
||||
// ----- Options values
|
||||
define('PCLZIP_OPT_PATH', 77001);
|
||||
define('PCLZIP_OPT_ADD_PATH', 77002);
|
||||
define('PCLZIP_OPT_REMOVE_PATH', 77003);
|
||||
define('PCLZIP_OPT_REMOVE_ALL_PATH', 77004);
|
||||
define('PCLZIP_OPT_SET_CHMOD', 77005);
|
||||
define('PCLZIP_OPT_EXTRACT_AS_STRING', 77006);
|
||||
define('PCLZIP_OPT_NO_COMPRESSION', 77007);
|
||||
define('PCLZIP_OPT_BY_NAME', 77008);
|
||||
define('PCLZIP_OPT_BY_INDEX', 77009);
|
||||
define('PCLZIP_OPT_BY_EREG', 77010);
|
||||
define('PCLZIP_OPT_BY_PREG', 77011);
|
||||
define('PCLZIP_OPT_COMMENT', 77012);
|
||||
define('PCLZIP_OPT_ADD_COMMENT', 77013);
|
||||
define('PCLZIP_OPT_PREPEND_COMMENT', 77014);
|
||||
define('PCLZIP_OPT_EXTRACT_IN_OUTPUT', 77015);
|
||||
define('PCLZIP_OPT_REPLACE_NEWER', 77016);
|
||||
define('PCLZIP_OPT_STOP_ON_ERROR', 77017);
|
||||
// Having big trouble with crypt. Need to multiply 2 long int
|
||||
// which is not correctly supported by PHP ...
|
||||
//define( 'PCLZIP_OPT_CRYPT', 77018 );
|
||||
define('PCLZIP_OPT_EXTRACT_DIR_RESTRICTION', 77019);
|
||||
define('PCLZIP_OPT_TEMP_FILE_THRESHOLD', 77020);
|
||||
define('PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD', 77020); // alias
|
||||
define('PCLZIP_OPT_TEMP_FILE_ON', 77021);
|
||||
define('PCLZIP_OPT_ADD_TEMP_FILE_ON', 77021); // alias
|
||||
define('PCLZIP_OPT_TEMP_FILE_OFF', 77022);
|
||||
define('PCLZIP_OPT_ADD_TEMP_FILE_OFF', 77022); // alias
|
||||
|
||||
// ----- File description attributes
|
||||
define('PCLZIP_ATT_FILE_NAME', 79001);
|
||||
define('PCLZIP_ATT_FILE_NEW_SHORT_NAME', 79002);
|
||||
define('PCLZIP_ATT_FILE_NEW_FULL_NAME', 79003);
|
||||
define('PCLZIP_ATT_FILE_MTIME', 79004);
|
||||
define('PCLZIP_ATT_FILE_CONTENT', 79005);
|
||||
define('PCLZIP_ATT_FILE_COMMENT', 79006);
|
||||
|
||||
// ----- Call backs values
|
||||
define('PCLZIP_CB_PRE_EXTRACT', 78001);
|
||||
define('PCLZIP_CB_POST_EXTRACT', 78002);
|
||||
define('PCLZIP_CB_PRE_ADD', 78003);
|
||||
define('PCLZIP_CB_POST_ADD', 78004);
|
||||
}
|
||||
|
||||
class PclzipZipInterface
|
||||
{
|
||||
const SELECT_FILTER_PASS = 1;
|
||||
const SELECT_FILTER_REFUSE = 0;
|
||||
|
||||
const AVERAGE_ZIP_COMPRESSION_RATIO = 2;
|
||||
|
||||
private $archive;
|
||||
|
||||
/**
|
||||
* PclzipZipInterface constructor.
|
||||
*
|
||||
* @param \ZipArchive $archive
|
||||
*/
|
||||
public function __construct(\ZipArchive $archive)
|
||||
{
|
||||
$this->archive = $archive;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $localname
|
||||
* @param $filename
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function createFileHeader($localname, $filename)
|
||||
{
|
||||
return (object) array(
|
||||
'filename' => $filename,
|
||||
'stored_filename' => $localname,
|
||||
'size' => filesize($filename),
|
||||
'compressed_size' => ceil(filesize($filename)
|
||||
/ self::AVERAGE_ZIP_COMPRESSION_RATIO),
|
||||
'mtime' => filemtime($filename),
|
||||
'comment' => null,
|
||||
'folder' => is_dir($filename),
|
||||
'status' => 'ok',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new archive
|
||||
* Two ways of usage:
|
||||
* <code>create($content, [$addDir, [$removeDir]])</code>
|
||||
* <code>create($content, [... options ...]])</code>
|
||||
*/
|
||||
public function create($content)
|
||||
{
|
||||
if (is_array($content)) $paths_list = $content;
|
||||
else $paths_list = explode(',', $content);
|
||||
$report = array();
|
||||
|
||||
$options = func_get_args();
|
||||
array_shift($options);
|
||||
|
||||
// parse options
|
||||
if (isset($options[0]) && is_string($options[0])) {
|
||||
$options[PCLZIP_OPT_ADD_PATH] = $options[0];
|
||||
if (isset($options[1]) && is_string($options[1])) {
|
||||
$options[PCLZIP_OPT_REMOVE_PATH] = $options[1];
|
||||
}
|
||||
} else {
|
||||
$options = array_combine(
|
||||
array_filter($options, function ($v) {return (bool) $v&2;}),
|
||||
array_filter($options, function ($v) {return (bool) ($v-1)&2;})
|
||||
);
|
||||
}
|
||||
|
||||
// filters initiation
|
||||
$filters = array();
|
||||
if (isset($options[PCLZIP_OPT_REMOVE_PATH])
|
||||
&& !isset($options[PCLZIP_OPT_REMOVE_ALL_PATH]))
|
||||
$filters[] = function (&$key, &$value) use ($options) {
|
||||
$key = str_replace($key, null, $key); };
|
||||
if (isset($options[PCLZIP_OPT_REMOVE_ALL_PATH]))
|
||||
$filters[] = function (&$key, &$value) { $key = basename($key); };
|
||||
if (isset($options[PCLZIP_OPT_ADD_PATH]))
|
||||
$filters[] = function (&$key, &$value) use ($options) {
|
||||
$key = rtrim($options[PCLZIP_OPT_ADD_PATH], '/').'/'.
|
||||
ltrim($key, '/');
|
||||
};
|
||||
|
||||
if (isset($options[PCLZIP_CB_PRE_ADD])
|
||||
&& is_callable($options[PCLZIP_CB_PRE_ADD]))
|
||||
$preAddCallback = $options[PCLZIP_CB_PRE_ADD];
|
||||
else $preAddCallback = function () { return 1; };
|
||||
|
||||
if (isset($options[PCLZIP_CB_POST_ADD])
|
||||
&& is_callable($options[PCLZIP_CB_POST_ADD]))
|
||||
$postAddCallback = $options[PCLZIP_CB_POST_ADD];
|
||||
else $postAddCallback = function () { return 1; };
|
||||
|
||||
if (isset($options[PCLZIP_OPT_COMMENT]))
|
||||
$this->archive->setArchiveComment($options[PCLZIP_OPT_COMMENT]);
|
||||
|
||||
// scan filesystem for files list
|
||||
$files_list = array();
|
||||
foreach ($content as $file_to_add) {
|
||||
$report[] = $this->addSnippet($file_to_add, $filters,
|
||||
$preAddCallback, $postAddCallback);
|
||||
|
||||
// additional dir contents
|
||||
if (is_dir($file_to_add)) {
|
||||
$directory_contents = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator(
|
||||
$file_to_add, \RecursiveDirectoryIterator::SKIP_DOTS),
|
||||
RecursiveIteratorIterator::SELF_FIRST);
|
||||
foreach ($directory_contents as $file_to_add) {
|
||||
$report[] = $this->addSnippet($file_to_add, $filters,
|
||||
$preAddCallback, $postAddCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
// ...
|
||||
return $report;
|
||||
}
|
||||
|
||||
private function addSnippet($file_to_add, array $filters, $preAddCallback,
|
||||
$postAddCallback)
|
||||
{
|
||||
if (is_file($file_to_add) || is_dir($file_to_add)) {
|
||||
// apply filters to a file
|
||||
$localname = $file_to_add;
|
||||
$filename = $file_to_add;
|
||||
foreach ($filters as $filter)
|
||||
call_user_func($filter, $localname, $filename);
|
||||
$file_header = $this->createFileHeader($localname, $filename);
|
||||
if (call_user_func($preAddCallback, $file_header) == 1) {
|
||||
//
|
||||
// Check for max length > 255
|
||||
//
|
||||
if (strlen(basename($file_header->stored_filename)) > 255)
|
||||
$file_header->status = 'filename_too_long';
|
||||
if (is_file($filename))
|
||||
$this->archive->addFile($file_header->filename,
|
||||
$file_header->stored_filename);
|
||||
else if (is_dir($filename))
|
||||
$this->archive->addEmptyDir($file_header->stored_filename);
|
||||
} else {
|
||||
//
|
||||
// File was skipped
|
||||
//
|
||||
$file_header->status = 'skipped';
|
||||
}
|
||||
|
||||
return $file_header;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists archive content
|
||||
*/
|
||||
public function listContent()
|
||||
{
|
||||
$filesList = array();
|
||||
$numFiles = $this->archive->numFiles;
|
||||
for ($i = 0; $i < $numFiles; $i++) {
|
||||
$statIndex = $this->archive->statIndex($i);
|
||||
$filesList[] = (object) array(
|
||||
'filename' => $statIndex['name'],
|
||||
'stored_filename' => $statIndex['name'],
|
||||
'size' => $statIndex['size'],
|
||||
'compressed_size' => $statIndex['comp_size'],
|
||||
'mtime' => $statIndex,
|
||||
'comment' => ($comment = $this->archive->getCommentIndex
|
||||
($statIndex['index']) !== false) ? $comment : null,
|
||||
'folder' => in_array(substr($statIndex['name'], -1),
|
||||
array('/', '\\')),
|
||||
'index' => $statIndex['index'],
|
||||
'status' => 'ok',
|
||||
);
|
||||
}
|
||||
|
||||
return $filesList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts files
|
||||
* Two ways of usage:
|
||||
* <code>extract([$extractPath, [$removePath]])</code>
|
||||
* <code>extract([... options ...]])</code>
|
||||
*/
|
||||
public function extract()
|
||||
{
|
||||
$options = func_get_args();
|
||||
array_shift($options);
|
||||
|
||||
// parse options
|
||||
if (isset($options[0]) && is_string($options[0])) {
|
||||
$options[PCLZIP_OPT_PATH] = $options[0];
|
||||
if (isset($options[1]) && is_string($options[1])) {
|
||||
$options[PCLZIP_OPT_REMOVE_PATH] = $options[1];
|
||||
}
|
||||
} else {
|
||||
$options = array_combine(
|
||||
array_filter($options, function ($v) {return (bool) $v&2;}),
|
||||
array_filter($options, function ($v) {return (bool) ($v-1)&2;})
|
||||
);
|
||||
}
|
||||
|
||||
// filters initiation
|
||||
if (isset($options[PCLZIP_OPT_PATH]))
|
||||
$extractPath = rtrim($options[PCLZIP_OPT_PATH], '/');
|
||||
else $extractPath = rtrim(getcwd(), '/');
|
||||
|
||||
$filters = array();
|
||||
if (isset($options[PCLZIP_OPT_REMOVE_PATH])
|
||||
&& !isset($options[PCLZIP_OPT_REMOVE_ALL_PATH]))
|
||||
$filters[] = function (&$key, &$value) use ($options) {
|
||||
$key = str_replace($key, null, $key);
|
||||
};
|
||||
if (isset($options[PCLZIP_OPT_REMOVE_ALL_PATH]))
|
||||
$filters[] = function (&$key, &$value) { $key = basename($key); };
|
||||
if (isset($options[PCLZIP_OPT_ADD_PATH]))
|
||||
$filters[] = function (&$key, &$value) use ($options) {
|
||||
$key = rtrim($options[PCLZIP_OPT_ADD_PATH], '/').'/'.
|
||||
ltrim($key, '/');
|
||||
};
|
||||
|
||||
if (isset($options[PCLZIP_CB_PRE_EXTRACT])
|
||||
&& is_callable($options[PCLZIP_CB_PRE_EXTRACT]))
|
||||
$preExtractCallback = $options[PCLZIP_CB_PRE_EXTRACT];
|
||||
else $preExtractCallback = function () { return 1; };
|
||||
|
||||
if (isset($options[PCLZIP_CB_POST_EXTRACT])
|
||||
&& is_callable($options[PCLZIP_CB_POST_EXTRACT]))
|
||||
$postExtractCallback = $options[PCLZIP_CB_POST_EXTRACT];
|
||||
else $postExtractCallback = function () { return 1; };
|
||||
|
||||
// exact matching
|
||||
if (isset($options[PCLZIP_OPT_BY_NAME]))
|
||||
$selectFilter = function ($key, $value) use ($options) {
|
||||
$allowedNames = is_array($options[PCLZIP_OPT_BY_NAME])
|
||||
? $options[PCLZIP_OPT_BY_NAME]
|
||||
: explode(',', $options[PCLZIP_OPT_BY_NAME]);
|
||||
foreach ($allowedNames as $name) {
|
||||
// select directory with nested files
|
||||
if (in_array(substr($name, -1), array('/', '\\'))) {
|
||||
if (strncasecmp($name, $key, strlen($name)) === 0) {
|
||||
// that's a file inside a dir or that dir
|
||||
return self::SELECT_FILTER_PASS;
|
||||
}
|
||||
} else {
|
||||
// select exact name only
|
||||
if (strcasecmp($name, $key) === 0) {
|
||||
// that's a file with this name
|
||||
return self::SELECT_FILTER_PASS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// that file is not in allowed list
|
||||
return self::SELECT_FILTER_REFUSE;
|
||||
};
|
||||
// <ereg> rule
|
||||
else if (isset($options[PCLZIP_OPT_BY_EREG]) && function_exists('ereg'))
|
||||
$selectFilter = function ($key, $value) use ($options) {
|
||||
return (ereg($options[PCLZIP_OPT_BY_EREG], $key) !== false)
|
||||
? self::SELECT_FILTER_PASS
|
||||
: self::SELECT_FILTER_REFUSE;
|
||||
};
|
||||
// <preg_match> rule
|
||||
else if (isset($options[PCLZIP_OPT_BY_PREG]))
|
||||
$selectFilter = function ($key, $value) use ($options) {
|
||||
return preg_match($options[PCLZIP_OPT_BY_PREG], $key)
|
||||
? self::SELECT_FILTER_PASS
|
||||
: self::SELECT_FILTER_REFUSE;
|
||||
};
|
||||
// index rule
|
||||
else if (isset($options[PCLZIP_OPT_BY_INDEX]))
|
||||
$selectFilter = function ($key, $value, $index) use ($options) {
|
||||
$allowedIndexes = array();
|
||||
foreach ($options[PCLZIP_OPT_BY_INDEX] as $rule) {
|
||||
$parts = explode('-', $rule);
|
||||
if (count($parts) == 1) $allowedIndexes[] = $rule;
|
||||
else $allowedIndexes = array_merge(
|
||||
range($parts[0], $parts[1]), $allowedIndexes);
|
||||
}
|
||||
|
||||
return in_array($index, $allowedIndexes) ? self::SELECT_FILTER_PASS
|
||||
: self::SELECT_FILTER_REFUSE;
|
||||
};
|
||||
// no rule
|
||||
else
|
||||
$selectFilter = function () { return self::SELECT_FILTER_PASS; };
|
||||
|
||||
if (isset($options[PCLZIP_OPT_EXTRACT_AS_STRING]))
|
||||
$anotherOutputFormat = PCLZIP_OPT_EXTRACT_AS_STRING;
|
||||
else if (isset($options[PCLZIP_OPT_EXTRACT_IN_OUTPUT]))
|
||||
$anotherOutputFormat = PCLZIP_OPT_EXTRACT_IN_OUTPUT;
|
||||
else $anotherOutputFormat = false;
|
||||
|
||||
if (isset($options[PCLZIP_OPT_REPLACE_NEWER]))
|
||||
$doNotReplaceNewer = false;
|
||||
else $doNotReplaceNewer = true;
|
||||
|
||||
if (isset($options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION]))
|
||||
$restrictExtractDir = $options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION];
|
||||
else $restrictExtractDir = false;
|
||||
|
||||
$report = array();
|
||||
foreach ($this->listContent() as $file_header) {
|
||||
// add file information to report
|
||||
$report[] = $file_header;
|
||||
// refuse by select rule
|
||||
if (call_user_func($selectFilter, $file_header->stored_filename,
|
||||
$file_header->filename, $file_header->index)
|
||||
=== self::SELECT_FILTER_REFUSE) {
|
||||
//
|
||||
// I don't know need to remain this file in report or not,
|
||||
// but for now I remove
|
||||
array_pop($report);
|
||||
// $file_header->status = 'filtered';
|
||||
//
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// add extract path in case of extraction
|
||||
// for some reason need to do it before call pre extract callback
|
||||
// (pclzip.lib.php v2.8.2, line 3670)
|
||||
// so I decided to do it here too
|
||||
//
|
||||
if ($anotherOutputFormat === false) {
|
||||
$file_header->filename = realpath($extractPath.'/'.
|
||||
$file_header->filename);
|
||||
//
|
||||
// check for path correlation with restricted path
|
||||
//
|
||||
if ($restrictExtractDir !== false) {
|
||||
$filename = $file_header->filename;
|
||||
$restrictedDir = realpath($restrictExtractDir);
|
||||
if (strncasecmp($restrictedDir, $filename,
|
||||
strlen($restrictedDir)) !== 0) {
|
||||
// refuse file extraction
|
||||
$file_header->status = 'filtered';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// apply pre extract callback
|
||||
$callback_result = call_user_func($preExtractCallback,
|
||||
$file_header);
|
||||
if ($callback_result == 1) {
|
||||
// go on ...
|
||||
} elseif ($callback_result == 0) {
|
||||
// skip current file
|
||||
$file_header->status = 'skipped';
|
||||
continue;
|
||||
} elseif ($callback_result == 2) {
|
||||
// skip & stop extraction
|
||||
$file_header->status = 'aborted';
|
||||
break;
|
||||
}
|
||||
|
||||
// return content
|
||||
if ($anotherOutputFormat == PCLZIP_OPT_EXTRACT_AS_STRING) {
|
||||
$file_header->content
|
||||
= $this->archive->getFromName($file_header->stored_filename);
|
||||
}
|
||||
// echo content
|
||||
else if ($anotherOutputFormat == PCLZIP_OPT_EXTRACT_IN_OUTPUT) {
|
||||
echo $this->archive->getFromName($file_header->stored_filename);
|
||||
}
|
||||
// extract content
|
||||
else if ($anotherOutputFormat === false) {
|
||||
// apply path filters
|
||||
foreach ($filters as $filter) call_user_func($filter,
|
||||
$file_header->stored_filename, $file_header->filename);
|
||||
// dir extraction process
|
||||
if ($file_header->folder) {
|
||||
// if dir doesn't exist
|
||||
if (!is_dir($file_header->filename)) {
|
||||
// try to create folder
|
||||
if (!mkdir($file_header)) {
|
||||
$file_header->status = 'path_creation_fail';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// file extraction process
|
||||
else {
|
||||
// check if path is already taken by a folder
|
||||
if (is_dir($file_header->filename)) {
|
||||
$file_header->status = 'already_a_directory';
|
||||
continue;
|
||||
}
|
||||
// check if file path is not writable
|
||||
if (!is_writable($file_header->filename)) {
|
||||
$file_header->status = 'write_protected';
|
||||
continue;
|
||||
}
|
||||
// check if file exists and it's newer
|
||||
if (is_file($file_header->filename)) {
|
||||
if (filemtime($file_header->filename)
|
||||
> $file_header->mtime) {
|
||||
// skip extraction if option EXTRACT_NEWER isn't set
|
||||
if ($doNotReplaceNewer) {
|
||||
$file_header->status = 'newer_exist';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
$directory = dirname($file_header->filename);
|
||||
// check if running process can not create extraction folder
|
||||
if (!is_dir($directory)) {
|
||||
if (!mkdir($directory)) {
|
||||
$file_header->status = 'path_creation_fail';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// extraction
|
||||
if (copy("zip://".$this->archive->filename."#"
|
||||
.$file_header->stored_filename
|
||||
, $file_header->filename)) {
|
||||
// ok
|
||||
}
|
||||
// extraction fails
|
||||
else {
|
||||
$file_header->status = 'write_error';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// apply post extract callback
|
||||
$callback_result = call_user_func($postExtractCallback,
|
||||
$file_header);
|
||||
if ($callback_result == 1) {
|
||||
// go on
|
||||
} elseif ($callback_result == 2) {
|
||||
// skip & stop extraction
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $report;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads properties of archive
|
||||
*/
|
||||
public function properties()
|
||||
{
|
||||
return array(
|
||||
'nb' => $this->archive->numFiles,
|
||||
'comment' =>
|
||||
(($comment = $this->archive->getArchiveComment() !== false)
|
||||
? $comment : null),
|
||||
'status' => 'OK',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds files in archive
|
||||
* <code>add($content, [$addDir, [$removeDir]])</code>
|
||||
* <code>add($content, [ ... options ... ])</code>
|
||||
*/
|
||||
public function add($content)
|
||||
{
|
||||
if (is_array($content)) $paths_list = $content;
|
||||
else $paths_list = array_map(explode(',', $content));
|
||||
$report = array();
|
||||
|
||||
$options = func_get_args();
|
||||
array_shift($options);
|
||||
|
||||
// parse options
|
||||
if (isset($options[0]) && is_string($options[0])) {
|
||||
$options[PCLZIP_OPT_ADD_PATH] = $options[0];
|
||||
if (isset($options[1]) && is_string($options[1])) {
|
||||
$options[PCLZIP_OPT_REMOVE_PATH] = $options[1];
|
||||
}
|
||||
} else {
|
||||
$options = array_combine(
|
||||
array_filter($options, function ($v) {return (bool) $v&2;}),
|
||||
array_filter($options, function ($v) {return (bool) ($v-1)&2;})
|
||||
);
|
||||
}
|
||||
|
||||
// filters initiation
|
||||
$filters = array();
|
||||
if (isset($options[PCLZIP_OPT_REMOVE_PATH])
|
||||
&& !isset($options[PCLZIP_OPT_REMOVE_ALL_PATH]))
|
||||
$filters[] = function (&$key, &$value) use ($options) {
|
||||
$key = str_replace($key, null, $key);
|
||||
};
|
||||
if (isset($options[PCLZIP_OPT_REMOVE_ALL_PATH]))
|
||||
$filters[] = function (&$key, &$value) { $key = basename($key); };
|
||||
if (isset($options[PCLZIP_OPT_ADD_PATH]))
|
||||
$filters[] = function (&$key, &$value) use ($options) {
|
||||
$key = rtrim($options[PCLZIP_OPT_ADD_PATH], '/').'/'.
|
||||
ltrim($key, '/');
|
||||
};
|
||||
|
||||
if (isset($options[PCLZIP_CB_PRE_ADD])
|
||||
&& is_callable($options[PCLZIP_CB_PRE_ADD]))
|
||||
$preAddCallback = $options[PCLZIP_CB_PRE_ADD];
|
||||
else $preAddCallback = function () { return 1; };
|
||||
|
||||
if (isset($options[PCLZIP_CB_POST_ADD])
|
||||
&& is_callable($options[PCLZIP_CB_POST_ADD]))
|
||||
$postAddCallback = $options[PCLZIP_CB_POST_ADD];
|
||||
else $postAddCallback = function () { return 1; };
|
||||
|
||||
if (isset($options[PCLZIP_OPT_COMMENT]))
|
||||
$this->archive->setArchiveComment($options[PCLZIP_OPT_COMMENT]);
|
||||
if (isset($options[PCLZIP_OPT_ADD_COMMENT])) {
|
||||
$comment =
|
||||
($comment = $this->archive->getArchiveComment() !== false)
|
||||
? $comment : null;
|
||||
$this->archive->setArchiveComment(
|
||||
$comment . $options[PCLZIP_OPT_ADD_COMMENT]);
|
||||
}
|
||||
if (isset($options[PCLZIP_OPT_PREPEND_COMMENT])) {
|
||||
$comment =
|
||||
($comment = $this->archive->getArchiveComment() !== false)
|
||||
? $comment : null;
|
||||
$this->archive->setArchiveComment(
|
||||
$options[PCLZIP_OPT_PREPEND_COMMENT] . $comment);
|
||||
}
|
||||
|
||||
|
||||
// scan filesystem for files list
|
||||
$files_list = array();
|
||||
foreach ($content as $file_to_add) {
|
||||
$report[] = $this->addSnippet($file_to_add, $filters,
|
||||
$preAddCallback, $postAddCallback);
|
||||
|
||||
// additional dir contents
|
||||
if (is_dir($file_to_add)) {
|
||||
$directory_contents = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator(
|
||||
$file_to_add, \RecursiveDirectoryIterator::SKIP_DOTS),
|
||||
RecursiveIteratorIterator::SELF_FIRST);
|
||||
foreach ($directory_contents as $file_to_add) {
|
||||
$report[] = $this->addSnippet($file_to_add, $filters,
|
||||
$preAddCallback, $postAddCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
// ...
|
||||
return $report;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes files from archive
|
||||
* Usage:
|
||||
* <code>delete([... options ...])</code>
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
$report = array();
|
||||
$options = func_get_args();
|
||||
$options = array_combine(
|
||||
array_filter($options, function ($v) {return (bool) $v&2;}),
|
||||
array_filter($options, function ($v) {return (bool) ($v-1)&2;})
|
||||
);
|
||||
|
||||
// exact matching
|
||||
if (isset($options[PCLZIP_OPT_BY_NAME]))
|
||||
$selectFilter = function ($key, $value) use ($options) {
|
||||
$allowedNames = is_array($options[PCLZIP_OPT_BY_NAME])
|
||||
? $options[PCLZIP_OPT_BY_NAME]
|
||||
: explode(',', $options[PCLZIP_OPT_BY_NAME]);
|
||||
foreach ($allowedNames as $name) {
|
||||
// select directory with nested files
|
||||
if (in_array(substr($name, -1), array('/', '\\'))) {
|
||||
if (strncasecmp($name, $key, strlen($name)) === 0) {
|
||||
// that's a file inside a dir or that dir
|
||||
return self::SELECT_FILTER_PASS;
|
||||
}
|
||||
} else {
|
||||
// select exact name only
|
||||
if (strcasecmp($name, $key) === 0) {
|
||||
// that's a file with this name
|
||||
return self::SELECT_FILTER_PASS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// that file is not in allowed list
|
||||
return self::SELECT_FILTER_REFUSE;
|
||||
};
|
||||
// <ereg> rule
|
||||
else if (isset($options[PCLZIP_OPT_BY_EREG]) && function_exists('ereg'))
|
||||
$selectFilter = function ($key, $value) use ($options) {
|
||||
return (ereg($options[PCLZIP_OPT_BY_EREG], $key) !== false)
|
||||
? self::SELECT_FILTER_PASS
|
||||
: self::SELECT_FILTER_REFUSE;
|
||||
};
|
||||
// <preg_match> rule
|
||||
else if (isset($options[PCLZIP_OPT_BY_PREG]))
|
||||
$selectFilter = function ($key, $value) use ($options) {
|
||||
return preg_match($options[PCLZIP_OPT_BY_PREG], $key)
|
||||
? self::SELECT_FILTER_PASS
|
||||
: self::SELECT_FILTER_REFUSE;
|
||||
};
|
||||
// index rule
|
||||
else if (isset($options[PCLZIP_OPT_BY_INDEX]))
|
||||
$selectFilter = function ($key, $value, $index) use ($options) {
|
||||
$allowedIndexes = array();
|
||||
foreach ($options[PCLZIP_OPT_BY_INDEX] as $rule) {
|
||||
$parts = explode('-', $rule);
|
||||
if (count($parts) == 1) $allowedIndexes[] = $rule;
|
||||
else $allowedIndexes = array_merge(
|
||||
range($parts[0], $parts[1]), $allowedIndexes);
|
||||
}
|
||||
|
||||
return in_array($index, $allowedIndexes)
|
||||
? self::SELECT_FILTER_PASS
|
||||
: self::SELECT_FILTER_REFUSE;
|
||||
};
|
||||
// no rule
|
||||
else
|
||||
$selectFilter = function () { return self::SELECT_FILTER_PASS; };
|
||||
|
||||
foreach ($this->listContent() as $file_header) {
|
||||
// select by select rule
|
||||
if (call_user_func($selectFilter, $file_header->stored_filename,
|
||||
$file_header->filename, $file_header->index)
|
||||
=== self::SELECT_FILTER_REFUSE) {
|
||||
// delete file from archive
|
||||
if ($this->archive->deleteName($file_header->stored_filename)) {
|
||||
// ok
|
||||
continue;
|
||||
}
|
||||
// deletion fails
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// unselected file add in report
|
||||
$report[] = $file_header;
|
||||
}
|
||||
|
||||
return $report;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges given archive into current archive
|
||||
* Two ways of usage:
|
||||
* <code>merge($filename)</code>
|
||||
* <code>merge(UnifiedArchive $unifiedArchiveInstance)</code>
|
||||
* This implementation is more intelligent than original' one.
|
||||
*/
|
||||
public function merge($a)
|
||||
{
|
||||
// filename
|
||||
if (is_string($a)) {
|
||||
if ($a = UnifiedArchive::open($a) !== null) {
|
||||
// ok
|
||||
} else {
|
||||
// // unsupported type of archive
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// UnifiedArchive instance
|
||||
else if ($a instanceof UnifiedArchive) {
|
||||
// go on
|
||||
}
|
||||
// invalid argument
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$tempDir = tempnam(PCLZIP_TEMPORARY_DIR, 'merging');
|
||||
if (file_exists($tempDir)) unlink($tempDir);
|
||||
if (!mkdir($tempDir)) return 0;
|
||||
|
||||
// go through archive content list and copy all files
|
||||
foreach ($a->getFileNames() as $filename) {
|
||||
// dir merging process
|
||||
if (in_array(substr($filename, -1), array('/', '\\'))) {
|
||||
$this->archive->addEmptyDir(rtrim($filename, '/\\'));
|
||||
}
|
||||
// file merging process
|
||||
else {
|
||||
// extract file in temporary dir
|
||||
if ($a->extractNode($tempDir, '/'.$filename)) {
|
||||
// go on
|
||||
} else {
|
||||
// extraction fails
|
||||
return 0;
|
||||
}
|
||||
// add file in archive
|
||||
if ($this->archive->addFile($tempDir.'/'.$filename,
|
||||
$filename)) {
|
||||
// ok
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
call_user_func(function ($directory) {
|
||||
foreach (glob($directory.'/*') as $f) {
|
||||
if (is_dir($f)) call_user_func(__FUNCTION__, $f);
|
||||
else unlink($f);
|
||||
}
|
||||
}, $tempDir);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates archive
|
||||
*/
|
||||
public function duplicate($clone_filename)
|
||||
{
|
||||
return copy($this->archive->filename, $clone_filename) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
762
vendor/wapmorgan/unified-archive/src/UnifiedArchive.php
vendored
Normal file
762
vendor/wapmorgan/unified-archive/src/UnifiedArchive.php
vendored
Normal file
@ -0,0 +1,762 @@
|
||||
<?php
|
||||
namespace wapmorgan\UnifiedArchive;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveCreationException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveExtractionException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\ArchiveModificationException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\EmptyFileListException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\FileAlreadyExistsException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\NonExistentArchiveFileException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedArchiveException;
|
||||
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedOperationException;
|
||||
use wapmorgan\UnifiedArchive\Formats\BasicFormat;
|
||||
use wapmorgan\UnifiedArchive\Formats\Bzip;
|
||||
use wapmorgan\UnifiedArchive\Formats\Cab;
|
||||
use wapmorgan\UnifiedArchive\Formats\Gzip;
|
||||
use wapmorgan\UnifiedArchive\Formats\Iso;
|
||||
use wapmorgan\UnifiedArchive\Formats\Lzma;
|
||||
use wapmorgan\UnifiedArchive\Formats\Rar;
|
||||
use wapmorgan\UnifiedArchive\Formats\SevenZip;
|
||||
use wapmorgan\UnifiedArchive\Formats\Tar;
|
||||
use wapmorgan\UnifiedArchive\Formats\Zip;
|
||||
|
||||
/**
|
||||
* Class which represents archive in one of supported formats.
|
||||
*/
|
||||
class UnifiedArchive
|
||||
{
|
||||
const VERSION = '1.0.0';
|
||||
|
||||
const ZIP = 'zip';
|
||||
const SEVEN_ZIP = '7zip';
|
||||
const RAR = 'rar';
|
||||
const GZIP = 'gzip';
|
||||
const BZIP = 'bzip2';
|
||||
const LZMA = 'lzma2';
|
||||
const ISO = 'iso';
|
||||
const CAB = 'cab';
|
||||
const TAR = 'tar';
|
||||
const TAR_GZIP = 'tgz';
|
||||
const TAR_BZIP = 'tbz2';
|
||||
const TAR_LZMA = 'txz';
|
||||
const TAR_LZW = 'tar.z';
|
||||
|
||||
/** @var array List of archive format handlers */
|
||||
protected static $formatHandlers = [
|
||||
self::ZIP => Zip::class,
|
||||
self::SEVEN_ZIP => SevenZip::class,
|
||||
self::RAR => Rar::class,
|
||||
self::GZIP => Gzip::class,
|
||||
self::BZIP => Bzip::class,
|
||||
self::LZMA => Lzma::class,
|
||||
self::ISO => Iso::class,
|
||||
self::CAB => Cab::class,
|
||||
self::TAR => Tar::class,
|
||||
self::TAR_GZIP => Tar::class,
|
||||
self::TAR_BZIP => Tar::class,
|
||||
self::TAR_LZMA => Tar::class,
|
||||
self::TAR_LZW => Tar::class,
|
||||
];
|
||||
|
||||
/** @var array List of archive types with support-state */
|
||||
static protected $enabledTypes = [];
|
||||
|
||||
/** @var string Type of current archive */
|
||||
protected $type;
|
||||
|
||||
/** @var BasicFormat Adapter for current archive */
|
||||
protected $archive;
|
||||
|
||||
/** @var array List of files in current archive */
|
||||
protected $files;
|
||||
|
||||
/** @var int Number of files in archive */
|
||||
protected $filesQuantity;
|
||||
|
||||
/** @var int Cumulative size of uncompressed files */
|
||||
protected $uncompressedFilesSize;
|
||||
|
||||
/** @var int Cumulative size of compressed files */
|
||||
protected $compressedFilesSize;
|
||||
|
||||
/** @var int Total size of archive file */
|
||||
protected $archiveSize;
|
||||
|
||||
/**
|
||||
* Creates a UnifiedArchive instance for passed archive
|
||||
*
|
||||
* @param string $fileName Archive filename
|
||||
* @return UnifiedArchive|null Returns UnifiedArchive in case of successful reading of the file
|
||||
* @throws InvalidArgumentException If archive file is not readable
|
||||
*/
|
||||
public static function open($fileName)
|
||||
{
|
||||
self::checkRequirements();
|
||||
|
||||
if (!file_exists($fileName) || !is_readable($fileName))
|
||||
throw new InvalidArgumentException('Could not open file: '.$fileName);
|
||||
|
||||
$type = self::detectArchiveType($fileName);
|
||||
if (!self::canOpenType($type)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new self($fileName, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether archive can be opened with current system configuration
|
||||
*
|
||||
* @param string $fileName Archive filename
|
||||
* @return bool
|
||||
*/
|
||||
public static function canOpenArchive($fileName)
|
||||
{
|
||||
self::checkRequirements();
|
||||
|
||||
$type = self::detectArchiveType($fileName);
|
||||
|
||||
return $type !== false && self::canOpenType($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether specific archive type can be opened with current system configuration
|
||||
*
|
||||
* @param string $type One of predefined archive types (class constants)
|
||||
* @return bool
|
||||
*/
|
||||
public static function canOpenType($type)
|
||||
{
|
||||
self::checkRequirements();
|
||||
|
||||
return isset(self::$enabledTypes[$type])
|
||||
? self::$enabledTypes[$type]
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether specified archive can be created
|
||||
*
|
||||
* @param string $type One of predefined archive types (class constants)
|
||||
* @return bool
|
||||
*/
|
||||
public static function canCreateType($type)
|
||||
{
|
||||
self::checkRequirements();
|
||||
|
||||
return isset(self::$enabledTypes[$type])
|
||||
? call_user_func([static::$formatHandlers[$type], 'canCreateArchive'])
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect archive type by its filename or content
|
||||
*
|
||||
* @param string $fileName Archive filename
|
||||
* @param bool $contentCheck Whether archive type can be detected by content
|
||||
* @return string|bool One of UnifiedArchive type constants OR false if type is not detected
|
||||
*/
|
||||
public static function detectArchiveType($fileName, $contentCheck = true)
|
||||
{
|
||||
// by file name
|
||||
$ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
|
||||
if (stripos($fileName, '.tar.') !== false && preg_match('~\.(?<ext>tar\.(gz|bz2|xz|z))$~', strtolower($fileName), $match)) {
|
||||
switch ($match['ext']) {
|
||||
case 'tar.gz':
|
||||
return self::TAR_GZIP;
|
||||
case 'tar.bz2':
|
||||
return self::TAR_BZIP;
|
||||
case 'tar.xz':
|
||||
return self::TAR_LZMA;
|
||||
case 'tar.z':
|
||||
return self::TAR_LZW;
|
||||
}
|
||||
}
|
||||
|
||||
switch ($ext) {
|
||||
case 'zip':
|
||||
return self::ZIP;
|
||||
case '7z':
|
||||
return self::SEVEN_ZIP;
|
||||
case 'rar':
|
||||
return self::RAR;
|
||||
case 'gz':
|
||||
return self::GZIP;
|
||||
case 'bz2':
|
||||
return self::BZIP;
|
||||
case 'xz':
|
||||
return self::LZMA;
|
||||
case 'iso':
|
||||
return self::ISO;
|
||||
case 'cab':
|
||||
return self::CAB;
|
||||
case 'tar':
|
||||
return self::TAR;
|
||||
case 'tgz':
|
||||
return self::TAR_GZIP;
|
||||
case 'tbz2':
|
||||
return self::TAR_BZIP;
|
||||
case 'txz':
|
||||
return self::TAR_LZMA;
|
||||
}
|
||||
|
||||
// by file content
|
||||
if ($contentCheck) {
|
||||
$mime_type = mime_content_type($fileName);
|
||||
switch ($mime_type) {
|
||||
case 'application/zip':
|
||||
return self::ZIP;
|
||||
case 'application/x-7z-compressed':
|
||||
return self::SEVEN_ZIP;
|
||||
case 'application/x-rar':
|
||||
return self::RAR;
|
||||
case 'application/zlib':
|
||||
return self::GZIP;
|
||||
case 'application/x-bzip2':
|
||||
return self::BZIP;
|
||||
case 'application/x-lzma':
|
||||
return self::LZMA;
|
||||
case 'application/x-iso9660-image':
|
||||
return self::ISO;
|
||||
case 'application/vnd.ms-cab-compressed':
|
||||
return self::CAB;
|
||||
case 'application/x-tar':
|
||||
return self::TAR;
|
||||
case 'application/x-gtar':
|
||||
return self::TAR_GZIP;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the file as one of supported formats
|
||||
*
|
||||
* @param string $fileName Archive filename
|
||||
* @param string $type Archive type
|
||||
* @throws UnsupportedArchiveException If archive can not be opened
|
||||
*/
|
||||
public function __construct($fileName, $type)
|
||||
{
|
||||
self::checkRequirements();
|
||||
|
||||
$this->type = $type;
|
||||
$this->archiveSize = filesize($fileName);
|
||||
|
||||
if (!isset(static::$formatHandlers[$type]))
|
||||
throw new UnsupportedArchiveException('Unsupported archive type: '.$type.' of archive '.$fileName);
|
||||
|
||||
$handler_class = static::$formatHandlers[$type];
|
||||
|
||||
$this->archive = new $handler_class($fileName);
|
||||
$this->scanArchive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rescans array after modification
|
||||
*/
|
||||
protected function scanArchive()
|
||||
{
|
||||
$information = $this->archive->getArchiveInformation();
|
||||
$this->files = $information->files;
|
||||
$this->compressedFilesSize = $information->compressedFilesSize;
|
||||
$this->uncompressedFilesSize = $information->uncompressedFilesSize;
|
||||
$this->filesQuantity = count($information->files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes archive
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
unset($this->archive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of class implementing PclZipOriginalInterface
|
||||
* interface.
|
||||
*
|
||||
* @return PclzipZipInterface Returns an instance of a class implementing PclZipOriginalInterface
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public function getPclZipInterface()
|
||||
{
|
||||
return $this->archive->getPclZip();
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts number of files
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countFiles()
|
||||
{
|
||||
return $this->filesQuantity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts cumulative size of all uncompressed data (bytes)
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countUncompressedFilesSize()
|
||||
{
|
||||
return $this->uncompressedFilesSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns size of archive file in bytes
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getArchiveSize()
|
||||
{
|
||||
return $this->archiveSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns type of archive
|
||||
*
|
||||
* @return string One of class constants
|
||||
*/
|
||||
public function getArchiveType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts cumulative size of all compressed data (in bytes)
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countCompressedFilesSize()
|
||||
{
|
||||
return $this->compressedFilesSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of files, excluding folders.
|
||||
*
|
||||
* Paths is present in unix-style (with forward slash - /).
|
||||
*
|
||||
* @return array List of files
|
||||
*/
|
||||
public function getFileNames()
|
||||
{
|
||||
return array_values($this->files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that file exists in archive
|
||||
*
|
||||
* @param string $fileName File name in archive
|
||||
* @return bool
|
||||
*/
|
||||
public function isFileExists($fileName)
|
||||
{
|
||||
return in_array($fileName, $this->files, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns file metadata of file in archive
|
||||
*
|
||||
* @param string $fileName File name in archive
|
||||
* @return ArchiveEntry
|
||||
* @throws NonExistentArchiveFileException
|
||||
*/
|
||||
public function getFileData($fileName)
|
||||
{
|
||||
if (!in_array($fileName, $this->files, true))
|
||||
throw new NonExistentArchiveFileException('File '.$fileName.' does not exist in archive');
|
||||
|
||||
return $this->archive->getFileData($fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns full file content as string
|
||||
*
|
||||
* @param string $fileName File name in archive
|
||||
* @return string
|
||||
* @throws NonExistentArchiveFileException
|
||||
*/
|
||||
public function getFileContent($fileName)
|
||||
{
|
||||
if (!in_array($fileName, $this->files, true))
|
||||
throw new NonExistentArchiveFileException('File '.$fileName.' does not exist in archive');
|
||||
|
||||
return $this->archive->getFileContent($fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a resource for reading file from archive
|
||||
*
|
||||
* @param string $fileName File name in archive
|
||||
* @return resource
|
||||
* @throws NonExistentArchiveFileException
|
||||
*/
|
||||
public function getFileResource($fileName)
|
||||
{
|
||||
if (!in_array($fileName, $this->files, true))
|
||||
throw new NonExistentArchiveFileException('File '.$fileName.' does not exist in archive');
|
||||
|
||||
return $this->archive->getFileResource($fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpacks files to disk
|
||||
*
|
||||
* @param string $outputFolder Extraction output dir
|
||||
* @param string|array|null $files One file or files list or null to extract all content.
|
||||
* @param bool $expandFilesList Whether paths like 'src/' should be expanded to all files inside 'src/' dir or not.
|
||||
* @return int Number of extracted files
|
||||
* @throws EmptyFileListException
|
||||
* @throws ArchiveExtractionException
|
||||
*/
|
||||
public function extractFiles($outputFolder, $files = null, $expandFilesList = false)
|
||||
{
|
||||
if ($files !== null) {
|
||||
if (is_string($files)) $files = [$files];
|
||||
|
||||
if ($expandFilesList)
|
||||
$files = self::expandFileList($this->files, $files);
|
||||
|
||||
if (empty($files))
|
||||
throw new EmptyFileListException('Files list is empty!');
|
||||
|
||||
return $this->archive->extractFiles($outputFolder, $files);
|
||||
} else {
|
||||
return $this->archive->extractArchive($outputFolder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates existing archive by removing files from it
|
||||
*
|
||||
* Only 7zip and zip types support deletion.
|
||||
* @param string|string[] $fileOrFiles
|
||||
* @param bool $expandFilesList
|
||||
*
|
||||
* @return bool|int
|
||||
* @throws EmptyFileListException
|
||||
* @throws UnsupportedOperationException
|
||||
* @throws ArchiveModificationException
|
||||
*/
|
||||
public function deleteFiles($fileOrFiles, $expandFilesList = false)
|
||||
{
|
||||
$fileOrFiles = is_string($fileOrFiles) ? [$fileOrFiles] : $fileOrFiles;
|
||||
|
||||
if ($expandFilesList && $fileOrFiles !== null)
|
||||
$fileOrFiles = self::expandFileList($this->files, $fileOrFiles);
|
||||
|
||||
if (empty($fileOrFiles))
|
||||
throw new EmptyFileListException('Files list is empty!');
|
||||
|
||||
$result = $this->archive->deleteFiles($fileOrFiles);
|
||||
$this->scanArchive();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates existing archive by adding new files
|
||||
*
|
||||
* @param string[] $fileOrFiles See [[archiveFiles]] method for file list format.
|
||||
* @return int|bool Number of added files
|
||||
* @throws ArchiveModificationException
|
||||
* @throws EmptyFileListException
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public function addFiles($fileOrFiles)
|
||||
{
|
||||
$files_list = self::createFilesList($fileOrFiles);
|
||||
|
||||
if (empty($files_list))
|
||||
throw new EmptyFileListException('Files list is empty!');
|
||||
|
||||
$result = $this->archive->addFiles($files_list);
|
||||
$this->scanArchive();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds file into archive
|
||||
*
|
||||
* @param string $file File name to be added
|
||||
* @param string|null $inArchiveName If not passed, full path will be preserved.
|
||||
* @return bool
|
||||
* @throws ArchiveModificationException
|
||||
* @throws EmptyFileListException
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public function addFile($file, $inArchiveName = null)
|
||||
{
|
||||
if (!is_file($file))
|
||||
throw new InvalidArgumentException($file.' is not a valid file to add in archive');
|
||||
|
||||
return ($inArchiveName !== null
|
||||
? $this->addFiles([$file => $inArchiveName])
|
||||
: $this->addFiles([$file])) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds directory contents to archive
|
||||
*
|
||||
* @param string $directory
|
||||
* @param string|null $inArchivePath If not passed, full paths will be preserved.
|
||||
* @return bool
|
||||
* @throws ArchiveModificationException
|
||||
* @throws EmptyFileListException
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public function addDirectory($directory, $inArchivePath = null)
|
||||
{
|
||||
if (!is_dir($directory) || !is_readable($directory))
|
||||
throw new InvalidArgumentException($directory.' is not a valid directory to add in archive');
|
||||
|
||||
return ($inArchivePath !== null
|
||||
? $this->addFiles([$directory => $inArchivePath])
|
||||
: $this->addFiles([$inArchivePath])) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare files list for archiving
|
||||
*
|
||||
* @param string $fileOrFiles File of list of files. See [[archiveFiles]] for details.
|
||||
* @param string $archiveName File name of archive. See [[archiveFiles]] for details.
|
||||
* @return array An array containing entries:
|
||||
* - totalSize (int) - size in bytes for all files
|
||||
* - numberOfFiles (int) - quantity of files
|
||||
* - files (array) - list of files prepared for archiving
|
||||
* - type (string) - prepared format for archive. One of class constants
|
||||
* @throws EmptyFileListException
|
||||
* @throws UnsupportedArchiveException
|
||||
*/
|
||||
public static function prepareForArchiving($fileOrFiles, $archiveName)
|
||||
{
|
||||
$archiveType = self::detectArchiveType($archiveName, false);
|
||||
|
||||
if ($archiveType === false)
|
||||
throw new UnsupportedArchiveException('Could not detect archive type for name "'.$archiveName.'"');
|
||||
|
||||
$files_list = self::createFilesList($fileOrFiles);
|
||||
|
||||
if (empty($files_list))
|
||||
throw new EmptyFileListException('Files list is empty!');
|
||||
|
||||
$totalSize = 0;
|
||||
foreach ($files_list as $fn) {
|
||||
$totalSize += filesize($fn);
|
||||
}
|
||||
|
||||
return [
|
||||
'totalSize' => $totalSize,
|
||||
'numberOfFiles' => count($files_list),
|
||||
'files' => $files_list,
|
||||
'type' => $archiveType,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an archive with passed files list
|
||||
*
|
||||
* @param string|string[]|array<string,string> $fileOrFiles List of files. Can be one of three formats:
|
||||
* 1. A string containing path to file or directory.
|
||||
* File will have it's basename.
|
||||
* `UnifiedArchive::archiveFiles('/etc/php.ini', 'archive.zip)` will store
|
||||
* file with 'php.ini' name.
|
||||
* Directory contents will be stored in archive root.
|
||||
* `UnifiedArchive::archiveFiles('/var/log/', 'archive.zip')` will store all
|
||||
* directory contents in archive root.
|
||||
* 2. An array with strings containing pats to files or directories.
|
||||
* Files and directories will be stored with full paths.
|
||||
* `UnifiedArchive::archiveFiles(['/etc/php.ini', '/var/log/'], 'archive.zip)`
|
||||
* will preserve full paths.
|
||||
* 3. An array with strings where keys are strings.
|
||||
* Files will have name from key.
|
||||
* Directories contents will have prefix from key.
|
||||
* `UnifiedArchive::archiveFiles(['doc.txt' => 'very_long_name_of_document.txt',
|
||||
* 'static' => '/var/www/html/static/'], 'archive.zip')`
|
||||
*
|
||||
* @param string $archiveName File name of archive. Type of archive will be determined by it's name.
|
||||
* @return int Count of stored files is returned.
|
||||
* @throws EmptyFileListException
|
||||
* @throws FileAlreadyExistsException
|
||||
* @throws UnsupportedOperationException
|
||||
* @throws ArchiveCreationException
|
||||
*/
|
||||
public static function archiveFiles($fileOrFiles, $archiveName)
|
||||
{
|
||||
if (file_exists($archiveName))
|
||||
throw new FileAlreadyExistsException('Archive '.$archiveName.' already exists!');
|
||||
|
||||
self::checkRequirements();
|
||||
|
||||
$info = static::prepareForArchiving($fileOrFiles, $archiveName);
|
||||
|
||||
if (!isset(static::$formatHandlers[$info['type']]))
|
||||
throw new UnsupportedArchiveException('Unsupported archive type: '.$info['type'].' of archive '.$archiveName);
|
||||
|
||||
/** @var BasicFormat $handler_class */
|
||||
$handler_class = static::$formatHandlers[$info['type']];
|
||||
|
||||
return $handler_class::createArchive($info['files'], $archiveName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an archive with one file
|
||||
*
|
||||
* @param string $file
|
||||
* @param string $archiveName
|
||||
* @return bool
|
||||
* @throws EmptyFileListException
|
||||
* @throws FileAlreadyExistsException
|
||||
* @throws UnsupportedOperationException
|
||||
* @throws ArchiveCreationException
|
||||
*/
|
||||
public static function archiveFile($file, $archiveName)
|
||||
{
|
||||
if (!is_file($file)) {
|
||||
throw new InvalidArgumentException($file . ' is not a valid file to archive');
|
||||
}
|
||||
|
||||
return static::archiveFiles($file, $archiveName) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an archive with full directory contents
|
||||
*
|
||||
* @param string $directory
|
||||
* @param string $archiveName
|
||||
* @return bool
|
||||
* @throws ArchiveCreationException
|
||||
* @throws EmptyFileListException
|
||||
* @throws FileAlreadyExistsException
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public static function archiveDirectory($directory, $archiveName)
|
||||
{
|
||||
if (!is_dir($directory) || !is_readable($directory))
|
||||
throw new InvalidArgumentException($directory.' is not a valid directory to archive');
|
||||
|
||||
return static::archiveFiles($directory, $archiveName) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests system configuration
|
||||
*/
|
||||
protected static function checkRequirements()
|
||||
{
|
||||
if (empty(self::$enabledTypes)) {
|
||||
self::$enabledTypes[self::ZIP] = extension_loaded('zip');
|
||||
self::$enabledTypes[self::SEVEN_ZIP] = class_exists('\Archive7z\Archive7z');
|
||||
self::$enabledTypes[self::RAR] = extension_loaded('rar');
|
||||
self::$enabledTypes[self::GZIP] = extension_loaded('zlib');
|
||||
self::$enabledTypes[self::BZIP] = extension_loaded('bz2');
|
||||
self::$enabledTypes[self::LZMA] = extension_loaded('xz');
|
||||
self::$enabledTypes[self::ISO] = class_exists('\CISOFile');
|
||||
self::$enabledTypes[self::CAB] = class_exists('\CabArchive');
|
||||
self::$enabledTypes[self::TAR] = class_exists('\Archive_Tar') || class_exists('\PharData');
|
||||
self::$enabledTypes[self::TAR_GZIP] = (class_exists('\Archive_Tar') || class_exists('\PharData')) && extension_loaded('zlib');
|
||||
self::$enabledTypes[self::TAR_BZIP] = (class_exists('\Archive_Tar') || class_exists('\PharData')) && extension_loaded('bz2');
|
||||
self::$enabledTypes[self::TAR_LZMA] = class_exists('\Archive_Tar') && extension_loaded('lzma2');
|
||||
self::$enabledTypes[self::TAR_LZW] = class_exists('\Archive_Tar') && LzwStreamWrapper::isBinaryAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands files list
|
||||
* @param $archiveFiles
|
||||
* @param $files
|
||||
* @return array
|
||||
*/
|
||||
protected static function expandFileList($archiveFiles, $files)
|
||||
{
|
||||
$newFiles = [];
|
||||
foreach ($files as $file) {
|
||||
foreach ($archiveFiles as $archiveFile) {
|
||||
if (fnmatch($file.'*', $archiveFile))
|
||||
$newFiles[] = $archiveFile;
|
||||
}
|
||||
}
|
||||
return $newFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|array $nodes
|
||||
* @return array|bool
|
||||
*/
|
||||
protected static function createFilesList($nodes)
|
||||
{
|
||||
$files = [];
|
||||
|
||||
// passed an extended list
|
||||
if (is_array($nodes)) {
|
||||
foreach ($nodes as $source => $destination) {
|
||||
if (is_numeric($source))
|
||||
$source = $destination;
|
||||
|
||||
$destination = rtrim($destination, '/\\*');
|
||||
|
||||
// if is directory
|
||||
if (is_dir($source))
|
||||
self::importFilesFromDir(rtrim($source, '/\\*').'/*',
|
||||
!empty($destination) ? $destination.'/' : null, true, $files);
|
||||
else if (is_file($source))
|
||||
$files[$destination] = $source;
|
||||
}
|
||||
|
||||
} else if (is_string($nodes)) { // passed one file or directory
|
||||
// if is directory
|
||||
if (is_dir($nodes))
|
||||
self::importFilesFromDir(rtrim($nodes, '/\\*').'/*', null, true,
|
||||
$files);
|
||||
else if (is_file($nodes))
|
||||
$files[basename($nodes)] = $nodes;
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $source
|
||||
* @param string|null $destination
|
||||
* @param bool $recursive
|
||||
* @param array $map
|
||||
*/
|
||||
protected static function importFilesFromDir($source, $destination, $recursive, &$map)
|
||||
{
|
||||
// $map[$destination] = rtrim($source, '/*');
|
||||
// do not map root archive folder
|
||||
|
||||
if ($destination !== null)
|
||||
$map[$destination] = null;
|
||||
|
||||
foreach (glob($source, GLOB_MARK) as $node) {
|
||||
if (in_array(substr($node, -1), ['/', '\\'], true) && $recursive) {
|
||||
self::importFilesFromDir(str_replace('\\', '/', $node).'*',
|
||||
$destination.basename($node).'/', $recursive, $map);
|
||||
} elseif (is_file($node) && is_readable($node)) {
|
||||
$map[$destination.basename($node)] = $node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function canAddFiles()
|
||||
{
|
||||
return call_user_func([static::$formatHandlers[$this->type], 'canAddFiles']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function canDeleteFiles()
|
||||
{
|
||||
return call_user_func([static::$formatHandlers[$this->type], 'canDeleteFiles']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user