This commit is contained in:
2019-09-27 00:29:18 +02:00
parent 40af43681e
commit b857814072
470 changed files with 37562 additions and 10060 deletions
@@ -0,0 +1,66 @@
<?php
/**
* @package Grav\Common\Filesystem
*
* @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Common\Filesystem;
use Grav\Common\Utils;
abstract class Archiver
{
protected $options = [
'exclude_files' => ['.DS_Store'],
'exclude_paths' => []
];
protected $archive_file;
public static function create($compression)
{
if ($compression === 'zip') {
return new ZipArchiver();
}
return new ZipArchiver();
}
public function setArchive($archive_file)
{
$this->archive_file = $archive_file;
return $this;
}
public function setOptions($options)
{
// Set infinite PHP execution time if possible.
if (function_exists('set_time_limit') && !Utils::isFunctionDisabled('set_time_limit')) {
set_time_limit(0);
}
$this->options = $options + $this->options;
return $this;
}
public abstract function compress($folder, callable $status = null);
public abstract function extract($destination, callable $status = null);
public abstract function addEmptyFolders($folders, callable $status = null);
protected function getArchiveFiles($rootPath)
{
$exclude_paths = $this->options['exclude_paths'];
$exclude_files = $this->options['exclude_files'];
$dirItr = new \RecursiveDirectoryIterator($rootPath, \RecursiveDirectoryIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS | \FilesystemIterator::UNIX_PATHS);
$filterItr = new RecursiveDirectoryFilterIterator($dirItr, $rootPath, $exclude_paths, $exclude_files);
$files = new \RecursiveIteratorIterator($filterItr, \RecursiveIteratorIterator::SELF_FIRST);
return $files;
}
}
+30 -24
View File
@@ -1,8 +1,9 @@
<?php
/**
* @package Grav.Common.FileSystem
* @package Grav\Common\Filesystem
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -48,7 +49,7 @@ abstract class Folder
/**
* Recursively find the last modified time under given path by file.
*
* @param string $path
* @param string $path
* @param string $extensions which files to search for specifically
*
* @return int
@@ -86,7 +87,7 @@ abstract class Folder
/**
* Recursively md5 hash all files in a path
*
* @param $path
* @param string $path
* @return string
*/
public static function hashAllFiles($path)
@@ -141,6 +142,7 @@ abstract class Folder
*/
public static function getRelativePathDotDot($path, $base)
{
// Normalize paths.
$base = preg_replace('![\\\/]+!', '/', $base);
$path = preg_replace('![\\\/]+!', '/', $path);
@@ -148,8 +150,8 @@ abstract class Folder
return '';
}
$baseParts = explode('/', isset($base[0]) && '/' === $base[0] ? substr($base, 1) : $base);
$pathParts = explode('/', isset($path[0]) && '/' === $path[0] ? substr($path, 1) : $path);
$baseParts = explode('/', ltrim($base, '/'));
$pathParts = explode('/', ltrim($path, '/'));
array_pop($baseParts);
$lastPart = array_pop($pathParts);
@@ -164,7 +166,7 @@ abstract class Folder
$path = str_repeat('../', count($baseParts)) . implode('/', $pathParts);
return '' === $path
|| '/' === $path[0]
|| strpos($path, '/') === 0
|| false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos)
? "./$path" : $path;
}
@@ -199,14 +201,14 @@ abstract class Folder
}
$compare = isset($params['compare']) ? 'get' . $params['compare'] : null;
$pattern = isset($params['pattern']) ? $params['pattern'] : null;
$filters = isset($params['filters']) ? $params['filters'] : null;
$recursive = isset($params['recursive']) ? $params['recursive'] : true;
$levels = isset($params['levels']) ? $params['levels'] : -1;
$pattern = $params['pattern'] ?? null;
$filters = $params['filters'] ?? null;
$recursive = $params['recursive'] ?? true;
$levels = $params['levels'] ?? -1;
$key = isset($params['key']) ? 'get' . $params['key'] : null;
$value = isset($params['value']) ? 'get' . $params['value'] : ($recursive ? 'getSubPathname' : 'getFilename');
$folders = isset($params['folders']) ? $params['folders'] : true;
$files = isset($params['files']) ? $params['files'] : true;
$value = 'get' . ($params['value'] ?? ($recursive ? 'SubPathname' : 'Filename'));
$folders = $params['folders'] ?? true;
$files = $params['files'] ?? true;
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
@@ -233,7 +235,7 @@ abstract class Folder
/** @var \RecursiveDirectoryIterator $file */
foreach ($iterator as $file) {
// Ignore hidden files.
if ($file->getFilename()[0] === '.') {
if (strpos($file->getFilename(), '.') === 0) {
continue;
}
if (!$folders && $file->isDir()) {
@@ -255,7 +257,7 @@ abstract class Folder
if (isset($filters['value'])) {
$filter = $filters['value'];
if (is_callable($filter)) {
$filePath = call_user_func($filter, $file);
$filePath = $filter($file);
} else {
$filePath = preg_replace($filter, '', $filePath);
}
@@ -316,7 +318,7 @@ abstract class Folder
if (!$success) {
$error = error_get_last();
throw new \RuntimeException($error['message']);
throw new \RuntimeException($error['message'] ?? 'Unknown error');
}
// Make sure that the change will be detected when caching.
@@ -416,23 +418,27 @@ abstract class Folder
*/
public static function create($folder)
{
if (is_dir($folder)) {
// Silence error for open_basedir; should fail in mkdir instead.
if (@is_dir($folder)) {
return;
}
$success = @mkdir($folder, 0777, true);
if (!$success) {
$error = error_get_last();
throw new \RuntimeException($error['message']);
// Take yet another look, make sure that the folder doesn't exist.
clearstatcache(true, $folder);
if (!@is_dir($folder)) {
throw new \RuntimeException(sprintf('Unable to create directory: %s', $folder));
}
}
}
/**
* Recursive copy of one directory to another
*
* @param $src
* @param $dest
* @param string $src
* @param string $dest
*
* @return bool
* @throws \RuntimeException
@@ -448,7 +454,7 @@ abstract class Folder
// If the destination directory does not exist create it
if (!is_dir($dest)) {
static::mkdir($dest);
static::create($dest);
}
// Open the source directory to read in files
@@ -475,7 +481,7 @@ abstract class Folder
protected static function doDelete($folder, $include_target = true)
{
// Special case for symbolic links.
if (is_link($folder)) {
if ($include_target && is_link($folder)) {
return @unlink($folder);
}
@@ -0,0 +1,67 @@
<?php
/**
* @package Grav\Common\Filesystem
*
* @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Common\Filesystem;
class RecursiveDirectoryFilterIterator extends \RecursiveFilterIterator
{
protected static $root;
protected static $ignore_folders;
protected static $ignore_files;
/**
* Create a RecursiveFilterIterator from a RecursiveIterator
*
* @param \RecursiveIterator $iterator
* @param string $root
* @param array $ignore_folders
* @param array $ignore_files
*/
public function __construct(\RecursiveIterator $iterator, $root, $ignore_folders, $ignore_files)
{
parent::__construct($iterator);
$this::$root = $root;
$this::$ignore_folders = $ignore_folders;
$this::$ignore_files = $ignore_files;
}
/**
* Check whether the current element of the iterator is acceptable
*
* @return bool true if the current element is acceptable, otherwise false.
*/
public function accept()
{
/** @var \SplFileInfo $file */
$file = $this->current();
$filename = $file->getFilename();
$relative_filename = str_replace($this::$root . '/', '', $file->getPathname());
if ($file->isDir()) {
if (in_array($relative_filename, $this::$ignore_folders, true)) {
return false;
}
if (!in_array($filename, $this::$ignore_files, true)) {
return true;
}
} elseif ($file->isFile() && !in_array($filename, $this::$ignore_files, true)) {
return true;
}
return false;
}
public function getChildren()
{
/** @var RecursiveDirectoryFilterIterator $iterator */
$iterator = $this->getInnerIterator();
return new self($iterator->getChildren(), $this::$root, $this::$ignore_folders, $this::$ignore_files);
}
}
@@ -1,8 +1,9 @@
<?php
/**
* @package Grav.Common.FileSystem
* @package Grav\Common\Filesystem
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -12,19 +13,23 @@ use Grav\Common\Grav;
class RecursiveFolderFilterIterator extends \RecursiveFilterIterator
{
protected static $folder_ignores;
protected static $ignore_folders;
/**
* Create a RecursiveFilterIterator from a RecursiveIterator
*
* @param \RecursiveIterator $iterator
* @param array $ignore_folders
*/
public function __construct(\RecursiveIterator $iterator)
public function __construct(\RecursiveIterator $iterator, $ignore_folders = [])
{
parent::__construct($iterator);
if (empty($this::$folder_ignores)) {
$this::$folder_ignores = Grav::instance()['config']->get('system.pages.ignore_folders');
if (empty($ignore_folders)) {
$ignore_folders = Grav::instance()['config']->get('system.pages.ignore_folders');
}
$this::$ignore_folders = $ignore_folders;
}
/**
@@ -34,12 +39,9 @@ class RecursiveFolderFilterIterator extends \RecursiveFilterIterator
*/
public function accept()
{
/** @var $current \SplFileInfo */
/** @var \SplFileInfo $current */
$current = $this->current();
if ($current->isDir() && !in_array($current->getFilename(), $this::$folder_ignores, true)) {
return true;
}
return false;
return $current->isDir() && !in_array($current->getFilename(), $this::$ignore_folders, true);
}
}
@@ -0,0 +1,111 @@
<?php
/**
* @package Grav\Common\Filesystem
*
* @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Common\Filesystem;
class ZipArchiver extends Archiver
{
public function extract($destination, callable $status = null)
{
$zip = new \ZipArchive();
$archive = $zip->open($this->archive_file);
if ($archive === true) {
Folder::create($destination);
if (!$zip->extractTo($destination)) {
throw new \RuntimeException('ZipArchiver: ZIP failed to extract ' . $this->archive_file . ' to ' . $destination);
}
$zip->close();
return $this;
}
throw new \RuntimeException('ZipArchiver: Failed to open ' . $this->archive_file);
}
public function compress($source, callable $status = null)
{
if (!extension_loaded('zip')) {
throw new \InvalidArgumentException('ZipArchiver: Zip PHP module not installed...');
}
if (!file_exists($source)) {
throw new \InvalidArgumentException('ZipArchiver: ' . $source . ' cannot be found...');
}
$zip = new \ZipArchive();
if (!$zip->open($this->archive_file, \ZipArchive::CREATE)) {
throw new \InvalidArgumentException('ZipArchiver:' . $this->archive_file . ' cannot be created...');
}
// Get real path for our folder
$rootPath = realpath($source);
$files = $this->getArchiveFiles($rootPath);
$status && $status([
'type' => 'count',
'steps' => iterator_count($files),
]);
foreach ($files as $file) {
$filePath = $file->getPathname();
$relativePath = ltrim(substr($filePath, strlen($rootPath)), '/');
if ($file->isDir()) {
$zip->addEmptyDir($relativePath);
} else {
$zip->addFile($filePath, $relativePath);
}
$status && $status([
'type' => 'progress',
]);
}
$status && $status([
'type' => 'message',
'message' => 'Compressing...'
]);
$zip->close();
return $this;
}
public function addEmptyFolders($folders, callable $status = null)
{
if (!extension_loaded('zip')) {
throw new \InvalidArgumentException('ZipArchiver: Zip PHP module not installed...');
}
$zip = new \ZipArchive();
if (!$zip->open($this->archive_file)) {
throw new \InvalidArgumentException('ZipArchiver: ' . $this->archive_file . ' cannot be opened...');
}
$status && $status([
'type' => 'message',
'message' => 'Adding empty folders...'
]);
foreach($folders as $folder) {
$zip->addEmptyDir($folder);
$status && $status([
'type' => 'progress',
]);
}
$zip->close();
return $this;
}
}