first commit
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* Akeeba Engine
|
||||
*
|
||||
* @package akeebaengine
|
||||
* @copyright Copyright (c)2006-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
namespace Akeeba\Engine\Scan;
|
||||
|
||||
defined('AKEEBAENGINE') || die();
|
||||
|
||||
abstract class Base
|
||||
{
|
||||
/**
|
||||
* Gets all the files of a given folder
|
||||
*
|
||||
* @param string $folder The absolute path to the folder to scan for files
|
||||
* @param integer $position The position in the file list to seek to. Use null for the start of list.
|
||||
*
|
||||
* @return array A simple array of files
|
||||
*/
|
||||
abstract public function getFiles($folder, &$position);
|
||||
|
||||
/**
|
||||
* Gets all the folders (subdirectories) of a given folder
|
||||
*
|
||||
* @param string $folder The absolute path to the folder to scan for files
|
||||
* @param integer $position The position in the file list to seek to. Use null for the start of list.
|
||||
*
|
||||
* @return array A simple array of folders
|
||||
*/
|
||||
abstract public function getFolders($folder, &$position);
|
||||
}
|
||||
266
administrator/components/com_akeebabackup/engine/Scan/Smart.php
Normal file
266
administrator/components/com_akeebabackup/engine/Scan/Smart.php
Normal file
@@ -0,0 +1,266 @@
|
||||
<?php
|
||||
/**
|
||||
* Akeeba Engine
|
||||
*
|
||||
* @package akeebaengine
|
||||
* @copyright Copyright (c)2006-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
namespace Akeeba\Engine\Scan;
|
||||
|
||||
defined('AKEEBAENGINE') || die();
|
||||
|
||||
use Akeeba\Engine\Base\Exceptions\WarningException;
|
||||
use Akeeba\Engine\Factory;
|
||||
use DirectoryIterator;
|
||||
use Exception;
|
||||
use RuntimeException;
|
||||
|
||||
/* Windows system detection */
|
||||
if (!defined('_AKEEBA_IS_WINDOWS'))
|
||||
{
|
||||
$isWindows = DIRECTORY_SEPARATOR == '\\';
|
||||
|
||||
if (function_exists('php_uname'))
|
||||
{
|
||||
$isWindows = stristr(php_uname(), 'windows');
|
||||
}
|
||||
|
||||
define('_AKEEBA_IS_WINDOWS', $isWindows);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filesystem scanner which uses opendir() and is smart enough to make large directories
|
||||
* be scanned inside a step of their own.
|
||||
*
|
||||
* The idea is that if it's not the first operation of this step and the number of contained
|
||||
* directories AND files is more than double the number of allowed files per fragment, we should
|
||||
* break the step immediately.
|
||||
*
|
||||
*/
|
||||
class Smart extends Base
|
||||
{
|
||||
public function getFiles($folder, &$position)
|
||||
{
|
||||
$registry = Factory::getConfiguration();
|
||||
// Was the breakflag set BEFORE starting? -- This workaround is required due to PHP5 defaulting to assigning variables by reference
|
||||
$breakflag_before_process = $registry->get('volatile.breakflag', false);
|
||||
|
||||
// Reset break flag before continuing
|
||||
$breakflag = false;
|
||||
|
||||
// Initialize variables
|
||||
$arr = [];
|
||||
$false = false;
|
||||
|
||||
if (!@is_dir($folder) && !@is_dir($folder . '/'))
|
||||
{
|
||||
return $false;
|
||||
}
|
||||
|
||||
$counter = 0;
|
||||
$registry = Factory::getConfiguration();
|
||||
$maxCounter = $registry->get('engine.scan.smart.large_dir_threshold', 100);
|
||||
|
||||
$allowBreakflag = ($registry->get('volatile.operation_counter', 0) != 0) && !$breakflag_before_process;
|
||||
|
||||
if (!@is_dir($folder))
|
||||
{
|
||||
throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP reports it as not a folder.');
|
||||
}
|
||||
|
||||
if (!@is_readable($folder))
|
||||
{
|
||||
throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP reports it as not readable.');
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$di = new DirectoryIterator($folder);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP\'s DirectoryIterator reports the path cannot be opened.', 0, $e);
|
||||
}
|
||||
|
||||
if (!$di->valid())
|
||||
{
|
||||
throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP\'s DirectoryIterator could open the folder but immediately reports itself as not valid. If this happens your server is about to die.');
|
||||
}
|
||||
|
||||
$ds = ($folder == '') || ($folder == '/') || (@substr($folder, -1) == '/') || (@substr($folder, -1) == DIRECTORY_SEPARATOR) ? '' : DIRECTORY_SEPARATOR;
|
||||
|
||||
/** @var DirectoryIterator $file */
|
||||
foreach ($di as $file)
|
||||
{
|
||||
if ($breakflag)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the directory entry is a link pointing somewhere outside the allowed directories per open_basedir we
|
||||
* will get a RuntimeException (tested on PHP 5.3 onwards). Catching it lets us report the link as
|
||||
* unreadable without suffering a PHP Fatal Error.
|
||||
*/
|
||||
try
|
||||
{
|
||||
$file->isLink();
|
||||
}
|
||||
catch (RuntimeException $e)
|
||||
{
|
||||
if (!in_array($di->getFilename(), ['.', '..']))
|
||||
{
|
||||
Factory::getLog()->warning(sprintf("Link %s is inaccessible. Check the open_basedir restrictions in your server's PHP configuration", $file->getPathname()));
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($file->isDot())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($file->isDir())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$dir = $folder . $ds . $file->getFilename();
|
||||
$data = $dir;
|
||||
|
||||
if (_AKEEBA_IS_WINDOWS)
|
||||
{
|
||||
$data = Factory::getFilesystemTools()->TranslateWinPath($dir);
|
||||
}
|
||||
|
||||
if ($data)
|
||||
{
|
||||
$arr[] = $data;
|
||||
}
|
||||
|
||||
$counter++;
|
||||
|
||||
if ($counter >= $maxCounter)
|
||||
{
|
||||
$breakflag = $allowBreakflag;
|
||||
}
|
||||
}
|
||||
|
||||
// Save break flag status
|
||||
$registry->set('volatile.breakflag', $breakflag);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
public function getFolders($folder, &$position)
|
||||
{
|
||||
// Was the breakflag set BEFORE starting? -- This workaround is required due to PHP5 defaulting to assigning variables by reference
|
||||
$registry = Factory::getConfiguration();
|
||||
$breakflag_before_process = $registry->get('volatile.breakflag', false);
|
||||
|
||||
// Reset break flag before continuing
|
||||
$breakflag = false;
|
||||
|
||||
// Initialize variables
|
||||
$arr = [];
|
||||
$false = false;
|
||||
|
||||
if (!is_dir($folder) && !is_dir($folder . '/'))
|
||||
{
|
||||
throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP reports it as not a folder.');
|
||||
}
|
||||
|
||||
if (!@is_readable($folder))
|
||||
{
|
||||
throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP reports it as not readable.');
|
||||
}
|
||||
|
||||
$counter = 0;
|
||||
$registry = Factory::getConfiguration();
|
||||
$maxCounter = $registry->get('engine.scan.smart.large_dir_threshold', 100);
|
||||
|
||||
$allowBreakflag = ($registry->get('volatile.operation_counter', 0) != 0) && !$breakflag_before_process;
|
||||
|
||||
try
|
||||
{
|
||||
$di = new DirectoryIterator($folder);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP\'s DirectoryIterator reports the path cannot be opened.', 0, $e);
|
||||
}
|
||||
|
||||
if (!$di->valid())
|
||||
{
|
||||
throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP\'s DirectoryIterator could open the folder but immediately reports itself as not valid. If this happens your server is about to die.');
|
||||
}
|
||||
|
||||
$ds = ($folder == '') || ($folder == '/') || (@substr($folder, -1) == '/') || (@substr($folder, -1) == DIRECTORY_SEPARATOR) ? '' : DIRECTORY_SEPARATOR;
|
||||
|
||||
/** @var DirectoryIterator $file */
|
||||
foreach ($di as $file)
|
||||
{
|
||||
if ($breakflag)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the directory entry is a link pointing somewhere outside the allowed directories per open_basedir we
|
||||
* will get a RuntimeException (tested on PHP 5.3 onwards). Catching it lets us report the link as
|
||||
* unreadable without suffering a PHP Fatal Error.
|
||||
*/
|
||||
try
|
||||
{
|
||||
$file->isLink();
|
||||
}
|
||||
catch (RuntimeException $e)
|
||||
{
|
||||
if (!in_array($di->getFilename(), ['.', '..']))
|
||||
{
|
||||
Factory::getLog()->warning(sprintf("Link %s is inaccessible. Check the open_basedir restrictions in your server's PHP configuration", $file->getPathname()));
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($file->isDot())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$file->isDir())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$dir = $folder . $ds . $file->getFilename();
|
||||
$data = $dir;
|
||||
|
||||
if (_AKEEBA_IS_WINDOWS)
|
||||
{
|
||||
$data = Factory::getFilesystemTools()->TranslateWinPath($dir);
|
||||
}
|
||||
|
||||
if ($data)
|
||||
{
|
||||
$arr[] = $data;
|
||||
}
|
||||
|
||||
$counter++;
|
||||
|
||||
if ($counter >= $maxCounter)
|
||||
{
|
||||
$breakflag = $allowBreakflag;
|
||||
}
|
||||
}
|
||||
|
||||
// Save break flag status
|
||||
$registry->set('volatile.breakflag', $breakflag);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"_information": {
|
||||
"title": "COM_AKEEBA_CONFIG_ENGINE_SCAN_SMART_TITLE",
|
||||
"description": "COM_AKEEBA_CONFIG_ENGINE_SCAN_SMART_DESCRIPTION"
|
||||
},
|
||||
"engine.scan.smart.large_dir_threshold": {
|
||||
"default": "100",
|
||||
"type": "integer",
|
||||
"min": "0",
|
||||
"max": "500",
|
||||
"shortcuts": "20|50|100|200|300|400|500",
|
||||
"scale": "1",
|
||||
"uom": "",
|
||||
"title": "COM_AKEEBA_CONFIG_LARGEDIRTHRESHOLD_TITLE",
|
||||
"description": "COM_AKEEBA_CONFIG_LARGEDIRTHRESHOLD_DESCRIPTION"
|
||||
},
|
||||
"engine.scan.common.largefile": {
|
||||
"default": "10485760",
|
||||
"type": "integer",
|
||||
"min": "1048576",
|
||||
"max": "1048576000",
|
||||
"shortcuts": "1048576|2097152|5242880|10485760|15728640|20971520|26214400|31457280|41943040|52428800|78643200|104857600",
|
||||
"scale": "1048576",
|
||||
"uom": "MB",
|
||||
"title": "COM_AKEEBA_CONFIG_LARGEFILE_TITLE",
|
||||
"description": "COM_AKEEBA_CONFIG_LARGEFILE_DESCRIPTION"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user