primo commit
This commit is contained in:
376
libraries/vendor/joomla/filesystem/src/Path.php
vendored
Normal file
376
libraries/vendor/joomla/filesystem/src/Path.php
vendored
Normal file
@ -0,0 +1,376 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Part of the Joomla Framework Filesystem Package
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2021 Open Source Matters, Inc. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE
|
||||
*/
|
||||
|
||||
namespace Joomla\Filesystem;
|
||||
|
||||
use Joomla\Filesystem\Exception\FilesystemException;
|
||||
|
||||
/**
|
||||
* A Path handling class
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
class Path
|
||||
{
|
||||
/**
|
||||
* Checks if a path's permissions can be changed.
|
||||
*
|
||||
* @param string $path Path to check.
|
||||
*
|
||||
* @return boolean True if path can have mode changed.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public static function canChmod($path)
|
||||
{
|
||||
if (!file_exists($path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$perms = @fileperms($path);
|
||||
|
||||
if ($perms !== false) {
|
||||
if (@chmod($path, $perms ^ 0001)) {
|
||||
@chmod($path, $perms);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chmods files and directories recursively to given permissions.
|
||||
*
|
||||
* @param string $path Root path to begin changing mode [without trailing slash].
|
||||
* @param string $filemode Octal representation of the value to change file mode to [null = no change].
|
||||
* @param string $foldermode Octal representation of the value to change folder mode to [null = no change].
|
||||
*
|
||||
* @return boolean True if successful [one fail means the whole operation failed].
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public static function setPermissions($path, $filemode = '0644', $foldermode = '0755')
|
||||
{
|
||||
// Initialise return value
|
||||
$ret = true;
|
||||
|
||||
if (is_dir($path)) {
|
||||
$dh = @opendir($path);
|
||||
|
||||
if ($dh) {
|
||||
while ($file = readdir($dh)) {
|
||||
if ($file != '.' && $file != '..') {
|
||||
$fullpath = $path . '/' . $file;
|
||||
|
||||
if (is_dir($fullpath)) {
|
||||
if (!static::setPermissions($fullpath, $filemode, $foldermode)) {
|
||||
$ret = false;
|
||||
}
|
||||
} else {
|
||||
if (isset($filemode)) {
|
||||
if (!static::canChmod($fullpath) || !@ chmod($fullpath, octdec($filemode))) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir($dh);
|
||||
}
|
||||
|
||||
if (isset($foldermode)) {
|
||||
if (!static::canChmod($path) || !@ chmod($path, octdec($foldermode))) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isset($filemode)) {
|
||||
if (!static::canChmod($path) || !@ chmod($path, octdec($filemode))) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the permissions of the file/folder at a give path.
|
||||
*
|
||||
* @param string $path The path of a file/folder.
|
||||
*
|
||||
* @return string Filesystem permissions.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public static function getPermissions($path)
|
||||
{
|
||||
$path = self::clean($path);
|
||||
$mode = @ decoct(@ fileperms($path) & 0777);
|
||||
|
||||
if (\strlen($mode) < 3) {
|
||||
return '---------';
|
||||
}
|
||||
|
||||
$parsedMode = '';
|
||||
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
// Read
|
||||
$parsedMode .= ($mode[$i] & 04) ? 'r' : '-';
|
||||
|
||||
// Write
|
||||
$parsedMode .= ($mode[$i] & 02) ? 'w' : '-';
|
||||
|
||||
// Execute
|
||||
$parsedMode .= ($mode[$i] & 01) ? 'x' : '-';
|
||||
}
|
||||
|
||||
return $parsedMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for snooping outside of the file system root.
|
||||
*
|
||||
* @param string $path A file system path to check.
|
||||
* @param string $basePath The base path of the system
|
||||
*
|
||||
* @return string A cleaned version of the path or exit on error.
|
||||
*
|
||||
* @since 1.0
|
||||
* @throws FilesystemException
|
||||
*/
|
||||
public static function check($path, $basePath = '')
|
||||
{
|
||||
if (strpos($path, '..') !== false) {
|
||||
throw new FilesystemException(
|
||||
sprintf(
|
||||
'%s() - Use of relative paths not permitted',
|
||||
__METHOD__
|
||||
),
|
||||
20
|
||||
);
|
||||
}
|
||||
|
||||
$path = static::clean($path);
|
||||
|
||||
// If a base path is defined then check the cleaned path is not outside of root
|
||||
if (($basePath != '') && strpos($path, static::clean($basePath)) !== 0) {
|
||||
throw new FilesystemException(
|
||||
sprintf(
|
||||
'%1$s() - Snooping out of bounds @ %2$s',
|
||||
__METHOD__,
|
||||
$path
|
||||
),
|
||||
20
|
||||
);
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to strip additional / or \ in a path name.
|
||||
*
|
||||
* @param string $path The path to clean.
|
||||
* @param string $ds Directory separator (optional).
|
||||
*
|
||||
* @return string The cleaned path.
|
||||
*
|
||||
* @since 1.0
|
||||
* @throws \UnexpectedValueException If $path is not a string.
|
||||
*/
|
||||
public static function clean($path, $ds = \DIRECTORY_SEPARATOR)
|
||||
{
|
||||
if ($path === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (!\is_string($path)) {
|
||||
throw new \InvalidArgumentException('You must specify a non-empty path to clean');
|
||||
}
|
||||
|
||||
$stream = explode('://', $path, 2);
|
||||
$scheme = '';
|
||||
$path = $stream[0];
|
||||
|
||||
if (\count($stream) >= 2) {
|
||||
$scheme = $stream[0] . '://';
|
||||
$path = $stream[1];
|
||||
}
|
||||
|
||||
$path = trim($path);
|
||||
|
||||
// Remove double slashes and backslashes and convert all slashes and backslashes to DIRECTORY_SEPARATOR
|
||||
// If dealing with a UNC path don't forget to prepend the path with a backslash.
|
||||
if (($ds == '\\') && ($path[0] == '\\') && ($path[1] == '\\')) {
|
||||
$path = '\\' . preg_replace('#[/\\\\]+#', $ds, $path);
|
||||
} else {
|
||||
$path = preg_replace('#[/\\\\]+#', $ds, $path);
|
||||
}
|
||||
|
||||
return $scheme . $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to determine if script owns the path.
|
||||
*
|
||||
* @param string $path Path to check ownership.
|
||||
*
|
||||
* @return boolean True if the php script owns the path passed.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public static function isOwner($path)
|
||||
{
|
||||
$tmp = md5(random_bytes(16));
|
||||
$ssp = ini_get('session.save_path');
|
||||
|
||||
// Try to find a writable directory
|
||||
$dir = is_writable('/tmp') ? '/tmp' : false;
|
||||
$dir = !$dir && is_writable('.') ? '.' : $dir;
|
||||
$dir = !$dir && is_writable($ssp) ? $ssp : $dir;
|
||||
|
||||
if ($dir) {
|
||||
$test = $dir . '/' . $tmp;
|
||||
|
||||
// Create the test file
|
||||
$blank = '';
|
||||
File::write($test, $blank, false);
|
||||
|
||||
// Test ownership
|
||||
$return = fileowner($test) === fileowner($path);
|
||||
|
||||
// Delete the test file
|
||||
File::delete($test);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the directory paths for a given file.
|
||||
*
|
||||
* @param mixed $paths A path string or array of path strings to search in
|
||||
* @param string $file The file name to look for.
|
||||
*
|
||||
* @return string|boolean The full path and file name for the target file, or boolean false if the file is not found in any of the paths.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public static function find($paths, $file)
|
||||
{
|
||||
// Force to array
|
||||
if (!\is_array($paths) && !($paths instanceof \Iterator)) {
|
||||
settype($paths, 'array');
|
||||
}
|
||||
|
||||
// Start looping through the path set
|
||||
foreach ($paths as $path) {
|
||||
// Get the path to the file
|
||||
$fullname = $path . '/' . $file;
|
||||
|
||||
// Is the path based on a stream?
|
||||
if (strpos($path, '://') === false) {
|
||||
// Not a stream, so do a realpath() to avoid directory
|
||||
// traversal attempts on the local file system.
|
||||
|
||||
// Needed for substr() later
|
||||
$path = realpath($path);
|
||||
$fullname = realpath($fullname);
|
||||
}
|
||||
|
||||
/*
|
||||
* The substr() check added to make sure that the realpath()
|
||||
* results in a directory registered so that
|
||||
* non-registered directories are not accessible via directory
|
||||
* traversal attempts.
|
||||
*/
|
||||
if (file_exists($fullname) && substr($fullname, 0, \strlen($path)) == $path) {
|
||||
return $fullname;
|
||||
}
|
||||
}
|
||||
|
||||
// Could not find the file in the set of paths
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves /./, /../ and multiple / in a string and returns the resulting absolute path, inspired by Flysystem
|
||||
* Removes trailing slashes
|
||||
*
|
||||
* @param string $path A path to resolve
|
||||
*
|
||||
* @return string The resolved path
|
||||
*
|
||||
* @since 1.6.0
|
||||
*/
|
||||
public static function resolve($path)
|
||||
{
|
||||
$path = static::clean($path);
|
||||
|
||||
// Save start character for absolute path
|
||||
$startCharacter = ($path[0] === DIRECTORY_SEPARATOR) ? DIRECTORY_SEPARATOR : '';
|
||||
|
||||
$parts = [];
|
||||
|
||||
foreach (explode(DIRECTORY_SEPARATOR, $path) as $part) {
|
||||
switch ($part) {
|
||||
case '':
|
||||
case '.':
|
||||
break;
|
||||
|
||||
case '..':
|
||||
if (empty($parts)) {
|
||||
throw new FilesystemException('Path is outside of the defined root');
|
||||
}
|
||||
|
||||
array_pop($parts);
|
||||
break;
|
||||
|
||||
default:
|
||||
$parts[] = $part;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $startCharacter . implode(DIRECTORY_SEPARATOR, $parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all references to root directory path and the system tmp path from a message
|
||||
*
|
||||
* @param string $message The message to be cleaned
|
||||
* @param string $rootDirectory Optional root directory, defaults to JPATH_ROOT
|
||||
*
|
||||
* @return string
|
||||
* @since 2.0.1
|
||||
*/
|
||||
public static function removeRoot($message, $rootDirectory = null)
|
||||
{
|
||||
if (empty($rootDirectory)) {
|
||||
$rootDirectory = JPATH_ROOT;
|
||||
}
|
||||
|
||||
$makePattern = static function ($dir) {
|
||||
return '~' . str_replace('~', '\\~', preg_replace('~[/\\\\]+~', '.', $dir)) . '~';
|
||||
};
|
||||
|
||||
$replacements = [
|
||||
$makePattern(static::clean($rootDirectory)) => '[ROOT]',
|
||||
$makePattern(sys_get_temp_dir()) => '[TMP]',
|
||||
];
|
||||
|
||||
return preg_replace(array_keys($replacements), array_values($replacements), $message);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user