This commit is contained in:
AlexBa16
2026-06-08 15:29:52 +02:00
commit 27903eed4a
9931 changed files with 1535659 additions and 0 deletions
@@ -0,0 +1,55 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2012 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Application;
use Joomla\Application\AbstractApplication;
use Joomla\Input\Input;
use Joomla\Registry\Registry;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Joomla Platform Base Application Class
*
* @property-read Input $input The application input object
*
* @since 3.0.0
*
* @deprecated 4.3 will be removed in 6.0
* Application classes should directly be based on \Joomla\Application\AbstractApplication
* don't use this class anymore
*/
abstract class BaseApplication extends AbstractApplication
{
use EventAware;
use IdentityAware;
/**
* Class constructor.
*
* @param ?Input $input An optional argument to provide dependency injection for the application's
* input object. If the argument is a Input object that object will become
* the application's input object, otherwise a default input object is created.
* @param ?Registry $config An optional argument to provide dependency injection for the application's
* config object. If the argument is a Registry object that object will become
* the application's config object, otherwise a default config object is created.
*
* @since 3.0.0
*/
public function __construct(?Input $input = null, ?Registry $config = null)
{
$this->input = $input instanceof Input ? $input : new Input();
$this->config = $config instanceof Registry ? $config : new Registry();
$this->initialise();
}
}
@@ -0,0 +1,38 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Application\CLI;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Class CliInput
*
* @since 4.0.0
*
* @deprecated 4.3 will be removed in 6.0
* Use the `joomla/console` package instead
*/
class CliInput
{
/**
* Get a value from standard input.
*
* @return string The input string from standard input.
*
* @codeCoverageIgnore
* @since 4.0.0
*/
public function in()
{
return rtrim(fread(STDIN, 8192), "\n\r");
}
}
@@ -0,0 +1,93 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2014 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Application\CLI;
use Joomla\CMS\Application\CLI\Output\Processor\ProcessorInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Base class defining a command line output handler
*
* @since 4.0.0
*
* @deprecated 4.3 will be removed in 6.0
* Use the `joomla/console` package instead
*/
abstract class CliOutput
{
/**
* Output processing object
*
* @var ProcessorInterface
* @since 4.0.0
*/
protected $processor;
/**
* Constructor
*
* @param ?ProcessorInterface $processor The output processor.
*
* @since 4.0.0
*/
public function __construct(?ProcessorInterface $processor = null)
{
$this->setProcessor($processor ?: new Output\Processor\ColorProcessor());
}
/**
* Set a processor
*
* @param ProcessorInterface $processor The output processor.
*
* @return $this
*
* @since 4.0.0
*/
public function setProcessor(ProcessorInterface $processor)
{
$this->processor = $processor;
return $this;
}
/**
* Get a processor
*
* @return ProcessorInterface
*
* @since 4.0.0
* @throws \RuntimeException
*/
public function getProcessor()
{
if ($this->processor) {
return $this->processor;
}
throw new \RuntimeException('A ProcessorInterface object has not been set.');
}
/**
* Write a string to an output handler.
*
* @param string $text The text to display.
* @param boolean $nl True (default) to append a new line at the end of the output string.
*
* @return $this
*
* @since 4.0.0
* @codeCoverageIgnore
*/
abstract public function out($text = '', $nl = true);
}
@@ -0,0 +1,263 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2014 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Application\CLI;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Class defining ANSI-color styles for command line output
*
* @since 4.0.0
*
* @deprecated 4.3 will be removed in 6.0
* Use the `joomla/console` package instead
*/
final class ColorStyle
{
/**
* Known colors
*
* @var array
* @since 4.0.0
*/
private static $knownColors = [
'black' => 0,
'red' => 1,
'green' => 2,
'yellow' => 3,
'blue' => 4,
'magenta' => 5,
'cyan' => 6,
'white' => 7,
];
/**
* Known styles
*
* @var array
* @since 4.0.0
*/
private static $knownOptions = [
'bold' => 1,
'underscore' => 4,
'blink' => 5,
'reverse' => 7,
];
/**
* Foreground base value
*
* @var integer
* @since 4.0.0
*/
private static $fgBase = 30;
/**
* Background base value
*
* @var integer
* @since 4.0.0
*/
private static $bgBase = 40;
/**
* Foreground color
*
* @var integer
* @since 4.0.0
*/
private $fgColor = 0;
/**
* Background color
*
* @var integer
* @since 4.0.0
*/
private $bgColor = 0;
/**
* Array of style options
*
* @var array
* @since 4.0.0
*/
private $options = [];
/**
* Constructor
*
* @param string $fg Foreground color.
* @param string $bg Background color.
* @param array $options Style options.
*
* @since 4.0.0
* @throws \InvalidArgumentException
*/
public function __construct(string $fg = '', string $bg = '', array $options = [])
{
if ($fg) {
if (!\array_key_exists($fg, static::$knownColors)) {
throw new \InvalidArgumentException(
\sprintf(
'Invalid foreground color "%1$s" [%2$s]',
$fg,
implode(', ', $this->getKnownColors())
)
);
}
$this->fgColor = static::$fgBase + static::$knownColors[$fg];
}
if ($bg) {
if (!\array_key_exists($bg, static::$knownColors)) {
throw new \InvalidArgumentException(
\sprintf(
'Invalid background color "%1$s" [%2$s]',
$bg,
implode(', ', $this->getKnownColors())
)
);
}
$this->bgColor = static::$bgBase + static::$knownColors[$bg];
}
foreach ($options as $option) {
if (!\array_key_exists($option, static::$knownOptions)) {
throw new \InvalidArgumentException(
\sprintf(
'Invalid option "%1$s" [%2$s]',
$option,
implode(', ', $this->getKnownOptions())
)
);
}
$this->options[] = $option;
}
}
/**
* Convert to a string.
*
* @return string
*
* @since 4.0.0
*/
public function __toString()
{
return $this->getStyle();
}
/**
* Create a color style from a parameter string.
*
* Example: fg=red;bg=blue;options=bold,blink
*
* @param string $string The parameter string.
*
* @return $this
*
* @since 4.0.0
* @throws \RuntimeException
*/
public static function fromString(string $string): self
{
$fg = '';
$bg = '';
$options = [];
$parts = explode(';', $string);
foreach ($parts as $part) {
$subParts = explode('=', $part);
if (\count($subParts) < 2) {
continue;
}
switch ($subParts[0]) {
case 'fg':
$fg = $subParts[1];
break;
case 'bg':
$bg = $subParts[1];
break;
case 'options':
$options = explode(',', $subParts[1]);
break;
default:
throw new \RuntimeException('Invalid option: ' . $subParts[0]);
}
}
return new self($fg, $bg, $options);
}
/**
* Get the translated color code.
*
* @return string
*
* @since 4.0.0
*/
public function getStyle(): string
{
$values = [];
if ($this->fgColor) {
$values[] = $this->fgColor;
}
if ($this->bgColor) {
$values[] = $this->bgColor;
}
foreach ($this->options as $option) {
$values[] = static::$knownOptions[$option];
}
return implode(';', $values);
}
/**
* Get the known colors.
*
* @return string[]
*
* @since 4.0.0
*/
public function getKnownColors(): array
{
return array_keys(static::$knownColors);
}
/**
* Get the known options.
*
* @return string[]
*
* @since 4.0.0
*/
public function getKnownOptions(): array
{
return array_keys(static::$knownOptions);
}
}
@@ -0,0 +1,194 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2014 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Application\CLI\Output\Processor;
use Joomla\CMS\Application\CLI\ColorStyle;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Command line output processor supporting ANSI-colored output
*
* @since 4.0.0
*
* @deprecated 4.3 will be removed in 6.0
* Use the `joomla/console` package instead
*/
class ColorProcessor implements ProcessorInterface
{
/**
* Flag to remove color codes from the output
*
* @var boolean
* @since 4.0.0
*/
public $noColors = false;
/**
* Regex to match tags
*
* @var string
* @since 4.0.0
*/
protected $tagFilter = '/<([a-z=;]+)>(.*?)<\/\\1>/s';
/**
* Regex used for removing color codes
*
* @var string
* @since 4.0.0
*/
protected static $stripFilter = '/<[\/]?[a-z=;]+>/';
/**
* Array of ColorStyle objects
*
* @var ColorStyle[]
* @since 4.0.0
*/
protected $styles = [];
/**
* Class constructor
*
* @param boolean $noColors Defines non-colored mode on construct
*
* @since 4.0.0
*/
public function __construct($noColors = null)
{
if ($noColors === null) {
/*
* By default windows cmd.exe and PowerShell does not support ANSI-colored output
* if the variable is not set explicitly colors should be disabled on Windows
*/
$noColors = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
}
$this->noColors = $noColors;
$this->addPredefinedStyles();
}
/**
* Add a style.
*
* @param string $name The style name.
* @param ColorStyle $style The color style.
*
* @return $this
*
* @since 4.0.0
*/
public function addStyle($name, ColorStyle $style)
{
$this->styles[$name] = $style;
return $this;
}
/**
* Strip color tags from a string.
*
* @param string $string The string.
*
* @return string
*
* @since 4.0.0
*/
public static function stripColors($string)
{
return preg_replace(static::$stripFilter, '', $string);
}
/**
* Process a string.
*
* @param string $string The string to process.
*
* @return string
*
* @since 4.0.0
*/
public function process($string)
{
preg_match_all($this->tagFilter, $string, $matches);
if (!$matches) {
return $string;
}
foreach ($matches[0] as $i => $m) {
if (\array_key_exists($matches[1][$i], $this->styles)) {
$string = $this->replaceColors($string, $matches[1][$i], $matches[2][$i], $this->styles[$matches[1][$i]]);
} elseif (strpos($matches[1][$i], '=')) {
// Custom format
$string = $this->replaceColors($string, $matches[1][$i], $matches[2][$i], ColorStyle::fromString($matches[1][$i]));
}
}
return $string;
}
/**
* Replace color tags in a string.
*
* @param string $text The original text.
* @param string $tag The matched tag.
* @param string $match The match.
* @param ColorStyle $style The color style to apply.
*
* @return mixed
*
* @since 4.0.0
*/
private function replaceColors($text, $tag, $match, ColorStyle $style)
{
$replace = $this->noColors
? $match
: "\033[" . $style . 'm' . $match . "\033[0m";
return str_replace('<' . $tag . '>' . $match . '</' . $tag . '>', $replace, $text);
}
/**
* Adds predefined color styles to the ColorProcessor object
*
* @return $this
*
* @since 4.0.0
*/
private function addPredefinedStyles()
{
$this->addStyle(
'info',
new ColorStyle('green', '', ['bold'])
);
$this->addStyle(
'comment',
new ColorStyle('yellow', '', ['bold'])
);
$this->addStyle(
'question',
new ColorStyle('black', 'cyan')
);
$this->addStyle(
'error',
new ColorStyle('white', 'red')
);
return $this;
}
}
@@ -0,0 +1,36 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2014 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Application\CLI\Output\Processor;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Interface for a command line output processor
*
* @since 4.0.0
*
* @deprecated 4.3 will be removed in 6.0
* Use the `joomla/console` package instead
*/
interface ProcessorInterface
{
/**
* Process the provided output into a string.
*
* @param string $output The string to process.
*
* @return string
*
* @since 4.0.0
*/
public function process($output);
}
@@ -0,0 +1,45 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2014 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Application\CLI\Output;
use Joomla\CMS\Application\CLI\CliOutput;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Output handler for writing command line output to the stdout interface
*
* @since 4.0.0
*
* @deprecated 4.3 will be removed in 6.0
* Use the `joomla/console` package instead
*/
class Stdout extends CliOutput
{
/**
* Write a string to standard output
*
* @param string $text The text to display.
* @param boolean $nl True (default) to append a new line at the end of the output string.
*
* @return $this
*
* @codeCoverageIgnore
* @since 4.0.0
*/
public function out($text = '', $nl = true)
{
fwrite(STDOUT, $this->getProcessor()->process($text) . ($nl ? "\n" : null));
return $this;
}
}
@@ -0,0 +1,46 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2014 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Application\CLI\Output;
use Joomla\CMS\Application\CLI\CliOutput;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Output handler for writing command line output to the stdout interface
*
* @since 4.0.0
*
* @deprecated 4.3 will be removed in 6.0
* Use the `joomla/console` package instead
*/
class Xml extends CliOutput
{
/**
* Write a string to standard output.
*
* @param string $text The text to display.
* @param boolean $nl True (default) to append a new line at the end of the output string.
*
* @return $this
*
* @since 4.0.0
* @throws \RuntimeException
* @codeCoverageIgnore
*/
public function out($text = '', $nl = true)
{
fwrite(STDOUT, $text . ($nl ? "\n" : null));
return $this;
}
}
@@ -0,0 +1,428 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Application;
use Joomla\Application\AbstractApplication;
use Joomla\CMS\Application\CLI\CliInput;
use Joomla\CMS\Application\CLI\CliOutput;
use Joomla\CMS\Application\CLI\Output\Stdout;
use Joomla\CMS\Event\Application\AfterExecuteEvent;
use Joomla\CMS\Event\Application\BeforeExecuteEvent;
use Joomla\CMS\Extension\ExtensionManagerTrait;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Language;
use Joomla\DI\Container;
use Joomla\DI\ContainerAwareTrait;
use Joomla\Event\DispatcherInterface;
use Joomla\Input\Input;
use Joomla\Registry\Registry;
use Joomla\Session\SessionInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Base class for a Joomla! command line application.
*
* @since 2.5.0
*
* @deprecated 4.0 will be removed in 6.0
* Use the ConsoleApplication instead
*/
abstract class CliApplication extends AbstractApplication implements CMSApplicationInterface
{
use EventAware;
use IdentityAware;
use ContainerAwareTrait;
use ExtensionManagerTrait;
use ExtensionNamespaceMapper;
/**
* Output object
*
* @var CliOutput
* @since 4.0.0
*/
protected $output;
/**
* The input.
*
* @var \Joomla\Input\Input
* @since 4.0.0
*/
protected $input = null;
/**
* CLI Input object
*
* @var CliInput
* @since 4.0.0
*/
protected $cliInput;
/**
* The application language object.
*
* @var Language
* @since 4.0.0
*/
protected $language;
/**
* The application message queue.
*
* @var array
* @since 4.0.0
*/
protected $messages = [];
/**
* The application instance.
*
* @var CliApplication
* @since 1.7.0
*/
protected static $instance;
/**
* Class constructor.
*
* @param ?Input $input An optional argument to provide dependency injection for the application's
* input object. If the argument is a JInputCli object that object will become
* the application's input object, otherwise a default input object is created.
* @param ?Registry $config An optional argument to provide dependency injection for the application's
* config object. If the argument is a Registry object that object will become
* the application's config object, otherwise a default config object is created.
* @param ?CliOutput $output The output handler.
* @param ?CliInput $cliInput The CLI input handler.
* @param ?DispatcherInterface $dispatcher An optional argument to provide dependency injection for the application's
* event dispatcher. If the argument is a DispatcherInterface object that object will become
* the application's event dispatcher, if it is null then the default event dispatcher
* will be created based on the application's loadDispatcher() method.
* @param ?Container $container Dependency injection container.
*
* @since 1.7.0
*/
public function __construct(
?Input $input = null,
?Registry $config = null,
?CliOutput $output = null,
?CliInput $cliInput = null,
?DispatcherInterface $dispatcher = null,
?Container $container = null
) {
// Close the application if we are not executed from the command line.
if (!\defined('STDOUT') || !\defined('STDIN') || !isset($_SERVER['argv'])) {
$this->close();
}
$container = $container ?: Factory::getContainer();
$this->setContainer($container);
$this->setDispatcher($dispatcher ?: $container->get(\Joomla\Event\DispatcherInterface::class));
if (!$container->has('session')) {
$container->alias('session', 'session.cli')
->alias('JSession', 'session.cli')
->alias(\Joomla\CMS\Session\Session::class, 'session.cli')
->alias(\Joomla\Session\Session::class, 'session.cli')
->alias(\Joomla\Session\SessionInterface::class, 'session.cli');
}
$this->input = new \Joomla\CMS\Input\Cli();
$this->language = Factory::getLanguage();
$this->output = $output ?: new Stdout();
$this->cliInput = $cliInput ?: new CliInput();
parent::__construct($config);
// Set the current directory.
$this->set('cwd', getcwd());
// Set up the environment
$this->input->set('format', 'cli');
}
/**
* Magic method to access properties of the application.
*
* @param string $name The name of the property.
*
* @return mixed A value if the property name is valid, null otherwise.
*
* @since 4.0.0
*
* @deprecated 4.0 will be removed in 6.0
* This is a B/C proxy for deprecated read accesses
* Example: Factory::getApplication()->getInput();
*/
public function __get($name)
{
switch ($name) {
case 'input':
@trigger_error(
'Accessing the input property of the application is deprecated, use the getInput() method instead.',
E_USER_DEPRECATED
);
return $this->getInput();
default:
$trace = debug_backtrace();
trigger_error(
\sprintf(
'Undefined property via __get(): %1$s in %2$s on line %3$s',
$name,
$trace[0]['file'],
$trace[0]['line']
),
E_USER_NOTICE
);
}
}
/**
* Method to get the application input object.
*
* @return Input
*
* @since 4.0.0
*/
public function getInput(): Input
{
return $this->input;
}
/**
* Method to get the application language object.
*
* @return Language The language object
*
* @since 4.0.0
*/
public function getLanguage()
{
return $this->language;
}
/**
* Returns a reference to the global CliApplication object, only creating it if it doesn't already exist.
*
* This method must be invoked as: $cli = CliApplication::getInstance();
*
* @param string $name The name (optional) of the Application Cli class to instantiate.
*
* @return CliApplication
*
* @since 1.7.0
*
* @deprecated 4.0 will be removed in 6.0
* Load the app through the container or via the Factory
* Example: Factory::getContainer()->get(CliApplication::class)
*
* @throws \RuntimeException
*/
public static function getInstance($name = null)
{
// Only create the object if it doesn't exist.
if (empty(static::$instance)) {
if (!class_exists($name)) {
throw new \RuntimeException(\sprintf('Unable to load application: %s', $name), 500);
}
static::$instance = new $name();
}
return static::$instance;
}
/**
* Execute the application.
*
* @return void
*
* @since 1.7.0
*/
public function execute()
{
$this->createExtensionNamespaceMap();
// Trigger the onBeforeExecute event
$this->dispatchEvent(
'onBeforeExecute',
new BeforeExecuteEvent('onBeforeExecute', ['subject' => $this, 'container' => $this->getContainer()])
);
// Perform application routines.
$this->doExecute();
// Trigger the onAfterExecute event.
$this->dispatchEvent(
'onAfterExecute',
new AfterExecuteEvent('onAfterExecute', ['subject' => $this])
);
}
/**
* Get an output object.
*
* @return CliOutput
*
* @since 4.0.0
*/
public function getOutput()
{
return $this->output;
}
/**
* Get a CLI input object.
*
* @return CliInput
*
* @since 4.0.0
*/
public function getCliInput()
{
return $this->cliInput;
}
/**
* Write a string to standard output.
*
* @param string $text The text to display.
* @param boolean $nl True (default) to append a new line at the end of the output string.
*
* @return $this
*
* @since 4.0.0
*/
public function out($text = '', $nl = true)
{
$this->getOutput()->out($text, $nl);
return $this;
}
/**
* Get a value from standard input.
*
* @return string The input string from standard input.
*
* @codeCoverageIgnore
* @since 4.0.0
*/
public function in()
{
return $this->getCliInput()->in();
}
/**
* Set an output object.
*
* @param CliOutput $output CliOutput object
*
* @return $this
*
* @since 3.3
*/
public function setOutput(CliOutput $output)
{
$this->output = $output;
return $this;
}
/**
* Enqueue a system message.
*
* @param string $msg The message to enqueue.
* @param string $type The message type.
*
* @return void
*
* @since 4.0.0
*/
public function enqueueMessage($msg, $type = self::MSG_INFO)
{
if (!\array_key_exists($type, $this->messages)) {
$this->messages[$type] = [];
}
$this->messages[$type][] = $msg;
}
/**
* Get the system message queue.
*
* @return array The system message queue.
*
* @since 4.0.0
*/
public function getMessageQueue()
{
return $this->messages;
}
/**
* Check the client interface by name.
*
* @param string $identifier String identifier for the application interface
*
* @return boolean True if this application is of the given type client interface.
*
* @since 4.0.0
*/
public function isClient($identifier)
{
return $identifier === 'cli';
}
/**
* Method to get the application session object.
*
* @return SessionInterface The session object
*
* @since 4.0.0
*/
public function getSession()
{
return $this->container->get(SessionInterface::class);
}
/**
* Retrieve the application configuration object.
*
* @return Registry
*
* @since 4.0.0
*/
public function getConfig()
{
return $this->config;
}
/**
* Flag if the application instance is a CLI or web based application.
*
* Helper function, you should use the native PHP functions to detect if it is a CLI application.
*
* @return boolean
*
* @since 4.0.0
* @deprecated 4.0 will be removed in 6.0
* Will be removed without replacements
*/
public function isCli()
{
return true;
}
}
@@ -0,0 +1,624 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Filesystem;
use Joomla\CMS\Client\ClientHelper;
use Joomla\CMS\Client\FtpClient;
use Joomla\CMS\Factory;
use Joomla\CMS\Filter\InputFilter;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Log\Log;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* A File handling class
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\File instead.
*/
class File
{
/**
* @var boolean true if OPCache enabled, and we have permission to invalidate files
* @since 4.0.1
*/
protected static $canFlushFileCache;
/**
* Gets the extension of a file name
*
* @param string $file The file name
*
* @return string The file extension
*
* @since 1.7.0
*/
public static function getExt($file)
{
// String manipulation should be faster than pathinfo() on newer PHP versions.
$dot = strrpos($file, '.');
if ($dot === false) {
return '';
}
$ext = substr($file, $dot + 1);
// Extension cannot contain slashes.
if (str_contains($ext, '/') || (DIRECTORY_SEPARATOR === '\\' && str_contains($ext, '\\'))) {
return '';
}
return $ext;
}
/**
* Strips the last extension off of a file name
*
* @param string $file The file name
*
* @return string The file name without the extension
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\File::stripExt() instead.
*/
public static function stripExt($file)
{
return preg_replace('#\.[^.]*$#', '', $file);
}
/**
* Makes file name safe to use
*
* @param string $file The name of the file [not full path]
*
* @return string The sanitised string
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\File::makeSafe() instead.
*/
public static function makeSafe($file)
{
// Remove any trailing dots, as those aren't ever valid file names.
$file = rtrim($file, '.');
// Try transliterating the file name using the native php function
if (\function_exists('transliterator_transliterate') && \function_exists('iconv')) {
// Using iconv to ignore characters that can't be transliterated
$file = iconv("UTF-8", "ASCII//TRANSLIT//IGNORE", transliterator_transliterate('Any-Latin; Latin-ASCII', $file));
}
$regex = ['#(\.){2,}#', '#[^A-Za-z0-9\.\_\- ]#', '#^\.#'];
return trim(preg_replace($regex, '', $file));
}
/**
* Copies a file
*
* @param string $src The path to the source file
* @param string $dest The path to the destination file
* @param string $path An optional base path to prefix to the file names
* @param boolean $useStreams True to use streams
*
* @return boolean True on success
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\File::copy() instead.
* The framework class throws Exceptions in case of error which you have to catch.
*/
public static function copy($src, $dest, $path = null, $useStreams = false)
{
// Prepend a base path if it exists
if ($path) {
$src = Path::clean($path . '/' . $src);
$dest = Path::clean($path . '/' . $dest);
}
// Check src path
if (!is_readable($src)) {
Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_FILE_FIND_COPY', __METHOD__, $src), Log::WARNING, 'jerror');
return false;
}
if ($useStreams) {
$stream = Factory::getStream();
if (!$stream->copy($src, $dest)) {
Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_FILE_STREAMS', __METHOD__, $src, $dest, $stream->getError()), Log::WARNING, 'jerror');
return false;
}
self::invalidateFileCache($dest);
return true;
}
$FTPOptions = ClientHelper::getCredentials('ftp');
if ($FTPOptions['enabled'] == 1) {
// Connect the FTP client
$ftp = FtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], [], $FTPOptions['user'], $FTPOptions['pass']);
// If the parent folder doesn't exist we must create it
if (!file_exists(\dirname($dest))) {
Folder::create(\dirname($dest));
}
// Translate the destination path for the FTP account
$dest = Path::clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $dest), '/');
if (!$ftp->store($src, $dest)) {
// FTP connector throws an error
return false;
}
} else {
if (!@ copy($src, $dest)) {
Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_COPY_FAILED_ERR01', $src, $dest), Log::WARNING, 'jerror');
return false;
}
}
self::invalidateFileCache($dest);
return true;
}
/**
* Invalidate opcache for a newly written/deleted file immediately, if opcache* functions exist and if this was a PHP file.
*
* @param string $filepath The path to the file just written to, to flush from opcache
* @param boolean $force If set to true, the script will be invalidated regardless of whether invalidation is necessary
*
* @return boolean TRUE if the opcode cache for script was invalidated/nothing to invalidate,
* or FALSE if the opcode cache is disabled or other conditions returning
* FALSE from opcache_invalidate (like file not found).
*
* @since 4.0.1
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\File::invalidateFileCache() instead.
*/
public static function invalidateFileCache($filepath, $force = true)
{
if (self::canFlushFileCache() && '.php' === strtolower(substr($filepath, -4))) {
return opcache_invalidate($filepath, $force);
}
return false;
}
/**
* First we check if opcache is enabled
* Then we check if the opcache_invalidate function is available
* Lastly we check if the host has restricted which scripts can use opcache_invalidate using opcache.restrict_api.
*
* `$_SERVER['SCRIPT_FILENAME']` approximates the origin file's path, but `realpath()`
* is necessary because `SCRIPT_FILENAME` can be a relative path when run from CLI.
* If the host has this set, check whether the path in `opcache.restrict_api` matches
* the beginning of the path of the origin file.
*
* @return boolean TRUE if we can proceed to use opcache_invalidate to flush a file from the OPCache
*
* @since 4.0.1
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\File::invalidateFileCache() instead.
* This method will be removed without replacement.
*/
public static function canFlushFileCache()
{
if (isset(static::$canFlushFileCache)) {
return static::$canFlushFileCache;
}
if (
\ini_get('opcache.enable')
&& \function_exists('opcache_invalidate')
&& (!\ini_get('opcache.restrict_api') || stripos(realpath($_SERVER['SCRIPT_FILENAME']), \ini_get('opcache.restrict_api')) === 0)
) {
static::$canFlushFileCache = true;
} else {
static::$canFlushFileCache = false;
}
return static::$canFlushFileCache;
}
/**
* Delete a file or array of files
*
* @param mixed $file The file name or an array of file names
*
* @return boolean True on success
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\File::delete() instead.
* The framework class throws Exceptions in case of error which you have to catch.
*/
public static function delete($file)
{
$FTPOptions = ClientHelper::getCredentials('ftp');
if (\is_array($file)) {
$files = $file;
} else {
$files[] = $file;
}
// Do NOT use ftp if it is not enabled
if ($FTPOptions['enabled'] == 1) {
// Connect the FTP client
$ftp = FtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], [], $FTPOptions['user'], $FTPOptions['pass']);
}
foreach ($files as $file) {
$file = Path::clean($file);
if (!is_file($file)) {
continue;
}
/**
* Try making the file writable first. If it's read-only, it can't be deleted
* on Windows, even if the parent folder is writable
*/
@chmod($file, 0777);
/**
* Invalidate the OPCache for the file before actually deleting it
* @link https://github.com/joomla/joomla-cms/pull/32915#issuecomment-812865635
* @link https://www.php.net/manual/en/function.opcache-invalidate.php#116372
*/
self::invalidateFileCache($file);
/**
* In case of restricted permissions we delete it one way or the other
* as long as the owner is either the webserver or the ftp
*/
if (@unlink($file)) {
// Do nothing
} elseif ($FTPOptions['enabled'] == 1) {
$file = Path::clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $file), '/');
if (!$ftp->delete($file)) {
// FTP connector throws an error
return false;
}
} else {
$filename = basename($file);
Log::add(Text::sprintf('JLIB_FILESYSTEM_DELETE_FAILED', $filename), Log::WARNING, 'jerror');
return false;
}
}
return true;
}
/**
* Moves a file
*
* @param string $src The path to the source file
* @param string $dest The path to the destination file
* @param string $path An optional base path to prefix to the file names
* @param boolean $useStreams True to use streams
*
* @return boolean True on success
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\File::move() instead.
* The framework class throws Exceptions in case of error which you have to catch.
*/
public static function move($src, $dest, $path = '', $useStreams = false)
{
if ($path) {
$src = Path::clean($path . '/' . $src);
$dest = Path::clean($path . '/' . $dest);
}
// Check src path
if (!is_readable($src)) {
Log::add(Text::_('JLIB_FILESYSTEM_CANNOT_FIND_SOURCE_FILE'), Log::WARNING, 'jerror');
return false;
}
if ($useStreams) {
$stream = Factory::getStream();
if (!$stream->move($src, $dest)) {
Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_GENERIC', __METHOD__, $stream->getError()), Log::WARNING, 'jerror');
return false;
}
self::invalidateFileCache($dest);
return true;
}
$FTPOptions = ClientHelper::getCredentials('ftp');
// Invalidate the compiled OPCache of the old file so it's no longer used.
self::invalidateFileCache($src);
if ($FTPOptions['enabled'] == 1) {
// Connect the FTP client
$ftp = FtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], [], $FTPOptions['user'], $FTPOptions['pass']);
// Translate path for the FTP account
$src = Path::clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $src), '/');
$dest = Path::clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $dest), '/');
// Use FTP rename to simulate move
if (!$ftp->rename($src, $dest)) {
Log::add(Text::_('JLIB_FILESYSTEM_ERROR_RENAME_FILE'), Log::WARNING, 'jerror');
return false;
}
} else {
if (!@ rename($src, $dest)) {
Log::add(Text::_('JLIB_FILESYSTEM_ERROR_RENAME_FILE'), Log::WARNING, 'jerror');
return false;
}
}
self::invalidateFileCache($dest);
return true;
}
/**
* Write contents to a file
*
* @param string $file The full file path
* @param string $buffer The buffer to write
* @param boolean $useStreams Use streams
*
* @return boolean True on success
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\File::write() instead.
*/
public static function write($file, $buffer, $useStreams = false)
{
if (\function_exists('set_time_limit')) {
set_time_limit(\ini_get('max_execution_time'));
}
// If the destination directory doesn't exist we need to create it
if (!file_exists(\dirname($file))) {
if (!Folder::create(\dirname($file))) {
return false;
}
}
if ($useStreams) {
$stream = Factory::getStream();
// Beef up the chunk size to a meg
$stream->set('chunksize', (1024 * 1024));
if (!$stream->writeFile($file, $buffer)) {
Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_WRITE_STREAMS', __METHOD__, $file, $stream->getError()), Log::WARNING, 'jerror');
return false;
}
self::invalidateFileCache($file);
return true;
}
$FTPOptions = ClientHelper::getCredentials('ftp');
if ($FTPOptions['enabled'] == 1) {
// Connect the FTP client
$ftp = FtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], [], $FTPOptions['user'], $FTPOptions['pass']);
// Translate path for the FTP account and use FTP write buffer to file
$file = Path::clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $file), '/');
$ret = $ftp->write($file, $buffer);
} else {
$file = Path::clean($file);
$ret = \is_int(file_put_contents($file, $buffer));
}
self::invalidateFileCache($file);
return $ret;
}
/**
* Append contents to a file
*
* @param string $file The full file path
* @param string $buffer The buffer to write
* @param boolean $useStreams Use streams
*
* @return boolean True on success
*
* @since 3.6.0
*
*/
public static function append($file, $buffer, $useStreams = false)
{
if (\function_exists('set_time_limit')) {
set_time_limit(\ini_get('max_execution_time'));
}
// If the file doesn't exist, just write instead of append
if (!file_exists($file)) {
return self::write($file, $buffer, $useStreams);
}
if ($useStreams) {
$stream = Factory::getStream();
// Beef up the chunk size to a meg
$stream->set('chunksize', (1024 * 1024));
if ($stream->open($file, 'ab') && $stream->write($buffer) && $stream->close()) {
self::invalidateFileCache($file);
return true;
}
Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_WRITE_STREAMS', __METHOD__, $file, $stream->getError()), Log::WARNING, 'jerror');
return false;
}
// Initialise variables.
$FTPOptions = ClientHelper::getCredentials('ftp');
if ($FTPOptions['enabled'] == 1) {
// Connect the FTP client
$ftp = FtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], [], $FTPOptions['user'], $FTPOptions['pass']);
// Translate path for the FTP account and use FTP write buffer to file
$file = Path::clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $file), '/');
$ret = $ftp->append($file, $buffer);
} else {
$file = Path::clean($file);
$ret = \is_int(file_put_contents($file, $buffer, FILE_APPEND));
}
self::invalidateFileCache($file);
return $ret;
}
/**
* Moves an uploaded file to a destination folder
*
* @param string $src The name of the php (temporary) uploaded file
* @param string $dest The path (including filename) to move the uploaded file to
* @param boolean $useStreams True to use streams
* @param boolean $allowUnsafe Allow the upload of unsafe files
* @param array $safeFileOptions Options to InputFilter::isSafeFile
*
* @return boolean True on success
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\File::upload() instead.
* The framework class throws Exceptions in case of error which you have to catch.
*/
public static function upload($src, $dest, $useStreams = false, $allowUnsafe = false, $safeFileOptions = [])
{
if (!$allowUnsafe) {
$descriptor = [
'tmp_name' => $src,
'name' => basename($dest),
'type' => '',
'error' => '',
'size' => '',
];
$isSafe = InputFilter::isSafeFile($descriptor, $safeFileOptions);
if (!$isSafe) {
Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_WARNFS_ERR03', $dest), Log::WARNING, 'jerror');
return false;
}
}
// Ensure that the path is valid and clean
$dest = Path::clean($dest);
// Create the destination directory if it does not exist
$baseDir = \dirname($dest);
if (!file_exists($baseDir)) {
Folder::create($baseDir);
}
if ($useStreams) {
$stream = Factory::getStream();
if (!$stream->upload($src, $dest)) {
Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_GENERIC', __METHOD__, $stream->getError()), Log::WARNING, 'jerror');
return false;
}
return true;
}
$FTPOptions = ClientHelper::getCredentials('ftp');
$ret = false;
if ($FTPOptions['enabled'] == 1) {
// Connect the FTP client
$ftp = FtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], [], $FTPOptions['user'], $FTPOptions['pass']);
// Translate path for the FTP account
$dest = Path::clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $dest), '/');
// Copy the file to the destination directory
if (is_uploaded_file($src) && $ftp->store($src, $dest)) {
self::invalidateFileCache($src);
unlink($src);
$ret = true;
} else {
Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_WARNFS_ERR04', $src, $dest), Log::WARNING, 'jerror');
}
} else {
self::invalidateFileCache($src);
if (is_writable($baseDir) && move_uploaded_file($src, $dest)) {
// Short circuit to prevent file permission errors
if (Path::setPermissions($dest)) {
$ret = true;
} else {
Log::add(Text::_('JLIB_FILESYSTEM_ERROR_WARNFS_ERR01'), Log::WARNING, 'jerror');
}
} else {
Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_WARNFS_ERR04', $src, $dest), Log::WARNING, 'jerror');
}
}
self::invalidateFileCache($dest);
return $ret;
}
/**
* Wrapper for the standard file_exists function
*
* @param string $file File path
*
* @return boolean True if path is a file
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use is_file() instead.
*/
public static function exists($file)
{
return is_file(Path::clean($file));
}
}
@@ -0,0 +1,368 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2008 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Filesystem;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* File system helper
*
* Holds support functions for the filesystem, particularly the stream
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Helper instead.
*/
class FilesystemHelper
{
/**
* Remote file size function for streams that don't support it
*
* @param string $url Link identifier
*
* @return mixed
*
* @link https://www.php.net/manual/en/function.filesize.php
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Helper::remotefsize() instead.
*/
public static function remotefsize($url)
{
$sch = parse_url($url, PHP_URL_SCHEME);
if (($sch !== 'http') && ($sch !== 'https') && ($sch !== 'ftp') && ($sch !== 'ftps')) {
return false;
}
if (($sch === 'http') || ($sch === 'https')) {
$headers = get_headers($url, 1);
if ((!\array_key_exists('Content-Length', $headers))) {
return false;
}
return $headers['Content-Length'];
}
if (($sch === 'ftp') || ($sch === 'ftps')) {
$server = parse_url($url, PHP_URL_HOST);
$port = parse_url($url, PHP_URL_PORT);
$path = parse_url($url, PHP_URL_PATH);
$user = parse_url($url, PHP_URL_USER);
$pass = parse_url($url, PHP_URL_PASS);
if ((!$server) || (!$path)) {
return false;
}
if (!$port) {
$port = 21;
}
if (!$user) {
$user = 'anonymous';
}
if (!$pass) {
$pass = '';
}
switch ($sch) {
case 'ftp':
$ftpid = ftp_connect($server, $port);
break;
case 'ftps':
$ftpid = ftp_ssl_connect($server, $port);
break;
}
if (!$ftpid) {
return false;
}
$login = ftp_login($ftpid, $user, $pass);
if (!$login) {
return false;
}
$ftpsize = ftp_size($ftpid, $path);
ftp_close($ftpid);
if ($ftpsize == -1) {
return false;
}
return $ftpsize;
}
}
/**
* Quick FTP chmod
*
* @param string $url Link identifier
* @param integer $mode The new permissions, given as an octal value.
*
* @return mixed
*
* @link https://www.php.net/manual/en/function.ftp-chmod.php
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Helper::ftpChmod() instead.
*/
public static function ftpChmod($url, $mode)
{
$sch = parse_url($url, PHP_URL_SCHEME);
if (($sch !== 'ftp') && ($sch !== 'ftps')) {
return false;
}
$server = parse_url($url, PHP_URL_HOST);
$port = parse_url($url, PHP_URL_PORT);
$path = parse_url($url, PHP_URL_PATH);
$user = parse_url($url, PHP_URL_USER);
$pass = parse_url($url, PHP_URL_PASS);
if ((!$server) || (!$path)) {
return false;
}
if (!$port) {
$port = 21;
}
if (!$user) {
$user = 'anonymous';
}
if (!$pass) {
$pass = '';
}
switch ($sch) {
case 'ftp':
$ftpid = ftp_connect($server, $port);
break;
case 'ftps':
$ftpid = ftp_ssl_connect($server, $port);
break;
}
if (!$ftpid) {
return false;
}
$login = ftp_login($ftpid, $user, $pass);
if (!$login) {
return false;
}
$res = ftp_chmod($ftpid, $mode, $path);
ftp_close($ftpid);
return $res;
}
/**
* Modes that require a write operation
*
* @return array
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Helper::getWriteModes() instead.
*/
public static function getWriteModes()
{
return ['w', 'w+', 'a', 'a+', 'r+', 'x', 'x+'];
}
/**
* Stream and Filter Support Operations
*
* Returns the supported streams, in addition to direct file access
* Also includes Joomla! streams as well as PHP streams
*
* @return array Streams
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Helper::getSupported() instead.
*/
public static function getSupported()
{
// Really quite cool what php can do with arrays when you let it...
static $streams;
if (!$streams) {
$streams = array_merge(stream_get_wrappers(), self::getJStreams());
}
return $streams;
}
/**
* Returns a list of transports
*
* @return array
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Helper::getTransports() instead.
*/
public static function getTransports()
{
// Is this overkill?
return stream_get_transports();
}
/**
* Returns a list of filters
*
* @return array
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Helper::getFilters() instead.
*/
public static function getFilters()
{
// Note: This will look like the getSupported() function with J! filters.
// @todo: add user space filter loading like user space stream loading
return stream_get_filters();
}
/**
* Returns a list of J! streams
*
* @return array
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Helper::getJStreams() instead.
*/
public static function getJStreams()
{
static $streams = [];
if (!$streams) {
$files = new \DirectoryIterator(__DIR__ . '/Streams');
/** @var $file \DirectoryIterator */
foreach ($files as $file) {
// Only load for php files.
if (!$file->isFile() || $file->getExtension() !== 'php') {
continue;
}
$streams[] = str_replace('stream', '', strtolower($file->getBasename('.php')));
}
}
return $streams;
}
/**
* Determine if a stream is a Joomla stream.
*
* @param string $streamname The name of a stream
*
* @return boolean True for a Joomla Stream
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Helper::isJoomlaStream() instead.
*/
public static function isJoomlaStream($streamname)
{
return \in_array($streamname, self::getJStreams());
}
/**
* Calculates the maximum upload file size and returns string with unit or the size in bytes
*
* Call it with JFilesystemHelper::fileUploadMaxSize();
*
* @param bool $unitOutput This parameter determines whether the return value should be a string with a unit
*
* @return float|string The maximum upload size of files with the appropriate unit or in bytes
*
* @since 3.4
*/
public static function fileUploadMaxSize($unitOutput = true)
{
static $max_size = false;
static $output_type = true;
if ($max_size === false || $output_type != $unitOutput) {
$max_size = self::parseSize(\ini_get('post_max_size'));
$upload_max = self::parseSize(\ini_get('upload_max_filesize'));
if ($upload_max > 0 && ($upload_max < $max_size || $max_size == 0)) {
$max_size = $upload_max;
}
if ($unitOutput) {
$max_size = self::parseSizeUnit($max_size);
}
$output_type = $unitOutput;
}
return $max_size;
}
/**
* Returns the size in bytes without the unit for the comparison
*
* @param string $size The size which is received from the PHP settings
*
* @return float The size in bytes without the unit
*
* @since 3.4
*/
private static function parseSize($size)
{
$unit = preg_replace('/[^bkmgtpezy]/i', '', $size);
$size = preg_replace('/[^0-9\.]/', '', $size);
$return = round($size);
if ($unit) {
$return = round($size * pow(1024, stripos('bkmgtpezy', $unit[0])));
}
return $return;
}
/**
* Creates the rounded size of the size with the appropriate unit
*
* @param float $maxSize The maximum size which is allowed for the uploads
*
* @return string String with the size and the appropriate unit
*
* @since 3.4
*/
private static function parseSizeUnit($maxSize)
{
$base = log($maxSize) / log(1024);
$suffixes = ['', 'k', 'M', 'G', 'T'];
return round(pow(1024, $base - floor($base)), 0) . $suffixes[floor($base)];
}
}
@@ -0,0 +1,685 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Filesystem;
use Joomla\CMS\Client\ClientHelper;
use Joomla\CMS\Client\FtpClient;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Log\Log;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* A Folder handling class
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Folder instead.
*/
abstract class Folder
{
/**
* Copy a folder.
*
* @param string $src The path to the source folder.
* @param string $dest The path to the destination folder.
* @param string $path An optional base path to prefix to the file names.
* @param boolean $force Force copy.
* @param boolean $useStreams Optionally force folder/file overwrites.
*
* @return boolean True on success.
*
* @since 1.7.0
* @throws \RuntimeException
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Folder::copy() instead.
*/
public static function copy($src, $dest, $path = '', $force = false, $useStreams = false)
{
if (\function_exists('set_time_limit')) {
set_time_limit(\ini_get('max_execution_time'));
}
$FTPOptions = ClientHelper::getCredentials('ftp');
if ($path) {
$src = Path::clean($path . '/' . $src);
$dest = Path::clean($path . '/' . $dest);
}
// Eliminate trailing directory separators, if any
$src = rtrim($src, DIRECTORY_SEPARATOR);
$dest = rtrim($dest, DIRECTORY_SEPARATOR);
if (!self::exists($src)) {
throw new \RuntimeException('Source folder not found', -1);
}
if (self::exists($dest) && !$force) {
throw new \RuntimeException('Destination folder already exists', -1);
}
// Make sure the destination exists
if (!self::create($dest)) {
throw new \RuntimeException('Cannot create destination folder', -1);
}
// If we're using ftp and don't have streams enabled
if ($FTPOptions['enabled'] == 1 && !$useStreams) {
// Connect the FTP client
$ftp = FtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], [], $FTPOptions['user'], $FTPOptions['pass']);
if (!($dh = @opendir($src))) {
throw new \RuntimeException('Cannot open source folder', -1);
}
// Walk through the directory copying files and recursing into folders.
while (($file = readdir($dh)) !== false) {
$sfid = $src . '/' . $file;
$dfid = $dest . '/' . $file;
switch (filetype($sfid)) {
case 'dir':
if ($file != '.' && $file != '..') {
$ret = self::copy($sfid, $dfid, null, $force);
if ($ret !== true) {
return $ret;
}
}
break;
case 'file':
// Translate path for the FTP account
$dfid = Path::clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $dfid), '/');
if (!$ftp->store($sfid, $dfid)) {
throw new \RuntimeException('Copy file failed', -1);
}
break;
}
}
} else {
if (!($dh = @opendir($src))) {
throw new \RuntimeException('Cannot open source folder', -1);
}
// Walk through the directory copying files and recursing into folders.
while (($file = readdir($dh)) !== false) {
$sfid = $src . '/' . $file;
$dfid = $dest . '/' . $file;
switch (filetype($sfid)) {
case 'dir':
if ($file != '.' && $file != '..') {
$ret = self::copy($sfid, $dfid, null, $force, $useStreams);
if ($ret !== true) {
return $ret;
}
}
break;
case 'file':
if ($useStreams) {
$stream = Factory::getStream();
if (!$stream->copy($sfid, $dfid)) {
throw new \RuntimeException(
\sprintf(
"Cannot copy file: %s",
Path::removeRoot($stream->getError())
),
-1
);
}
} else {
if (!@copy($sfid, $dfid)) {
throw new \RuntimeException('Copy file failed', -1);
}
}
break;
}
}
}
return true;
}
/**
* Create a folder -- and all necessary parent folders.
*
* @param string $path A path to create from the base path.
* @param integer $mode Directory permissions to set for folders created. 0755 by default.
*
* @return boolean True if successful.
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Folder::create() instead.
* The framework class throws Exceptions in case of error which you have to catch.
*/
public static function create($path = '', $mode = 0755)
{
$FTPOptions = ClientHelper::getCredentials('ftp');
static $nested = 0;
// Check to make sure the path valid and clean
$path = Path::clean($path);
// Check if parent dir exists
$parent = \dirname($path);
if (!self::exists($parent)) {
// Prevent infinite loops!
$nested++;
if (($nested > 20) || ($parent == $path)) {
Log::add(__METHOD__ . ': ' . Text::_('JLIB_FILESYSTEM_ERROR_FOLDER_LOOP'), Log::WARNING, 'jerror');
$nested--;
return false;
}
// Create the parent directory
if (self::create($parent, $mode) !== true) {
// Folder::create throws an error
$nested--;
return false;
}
// OK, parent directory has been created
$nested--;
}
// Check if dir already exists
if (self::exists($path)) {
return true;
}
// Check for safe mode
if ($FTPOptions['enabled'] == 1) {
// Connect the FTP client
$ftp = FtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], [], $FTPOptions['user'], $FTPOptions['pass']);
// Translate path to FTP path
$path = Path::clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $path), '/');
$ret = $ftp->mkdir($path);
$ftp->chmod($path, $mode);
} else {
// We need to get and explode the open_basedir paths
$obd = \ini_get('open_basedir');
// If open_basedir is set we need to get the open_basedir that the path is in
if ($obd != null) {
if (IS_WIN) {
$obdSeparator = ';';
} else {
$obdSeparator = ':';
}
// Create the array of open_basedir paths
$obdArray = explode($obdSeparator, $obd);
$inBaseDir = false;
// Iterate through open_basedir paths looking for a match
foreach ($obdArray as $test) {
$test = Path::clean($test);
if (str_starts_with($path, $test) || str_starts_with($path, realpath($test))) {
$inBaseDir = true;
break;
}
}
if (!$inBaseDir) {
// Return false for JFolder::create because the path to be created is not in open_basedir
Log::add(__METHOD__ . ': ' . Text::_('JLIB_FILESYSTEM_ERROR_FOLDER_PATH'), Log::WARNING, 'jerror');
return false;
}
}
// First set umask
$origmask = @umask(0);
// Create the path
if (!$ret = @mkdir($path, $mode)) {
@umask($origmask);
Log::add(
__METHOD__ . ': ' . Text::_('JLIB_FILESYSTEM_ERROR_COULD_NOT_CREATE_DIRECTORY') . 'Path: ' . $path,
Log::WARNING,
'jerror'
);
return false;
}
// Reset umask
@umask($origmask);
}
return $ret;
}
/**
* Delete a folder.
*
* @param string $path The path to the folder to delete.
*
* @return boolean True on success.
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Folder::delete() instead.
* The framework class throws Exceptions in case of error which you have to catch.
*/
public static function delete($path)
{
if (\function_exists('set_time_limit')) {
set_time_limit(\ini_get('max_execution_time'));
}
// Sanity check
if (!$path) {
// Bad programmer! Bad Bad programmer!
Log::add(__METHOD__ . ': ' . Text::_('JLIB_FILESYSTEM_ERROR_DELETE_BASE_DIRECTORY'), Log::WARNING, 'jerror');
return false;
}
$FTPOptions = ClientHelper::getCredentials('ftp');
// Check to make sure the path valid and clean
$path = Path::clean($path);
// Is this really a folder?
if (!is_dir($path)) {
Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER', __METHOD__, $path), Log::WARNING, 'jerror');
return false;
}
// Remove all the files in folder if they exist; disable all filtering
$files = self::files($path, '.', false, true, [], []);
if (!empty($files)) {
if (File::delete($files) !== true) {
// File::delete throws an error
return false;
}
}
// Remove sub-folders of folder; disable all filtering
$folders = self::folders($path, '.', false, true, [], []);
foreach ($folders as $folder) {
if (is_link($folder)) {
// Don't descend into linked directories, just delete the link.
if (File::delete($folder) !== true) {
// File::delete throws an error
return false;
}
} elseif (self::delete($folder) !== true) {
// Folder::delete throws an error
return false;
}
}
if ($FTPOptions['enabled'] == 1) {
// Connect the FTP client
$ftp = FtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], [], $FTPOptions['user'], $FTPOptions['pass']);
}
// In case of restricted permissions we zap it one way or the other
// as long as the owner is either the webserver or the ftp.
if (@rmdir($path)) {
$ret = true;
} elseif ($FTPOptions['enabled'] == 1) {
// Translate path and delete
$path = Path::clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $path), '/');
// FTP connector throws an error
$ret = $ftp->delete($path);
} else {
Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_FOLDER_DELETE', $path), Log::WARNING, 'jerror');
$ret = false;
}
return $ret;
}
/**
* Moves a folder.
*
* @param string $src The path to the source folder.
* @param string $dest The path to the destination folder.
* @param string $path An optional base path to prefix to the file names.
* @param boolean $useStreams Optionally use streams.
*
* @return mixed Error message on false or boolean true on success.
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Folder::move() instead.
* The framework class throws Exceptions in case of error which you have to catch.
*/
public static function move($src, $dest, $path = '', $useStreams = false)
{
$FTPOptions = ClientHelper::getCredentials('ftp');
if ($path) {
$src = Path::clean($path . '/' . $src);
$dest = Path::clean($path . '/' . $dest);
}
if (!self::exists($src)) {
return Text::_('JLIB_FILESYSTEM_ERROR_FIND_SOURCE_FOLDER');
}
if (self::exists($dest)) {
return Text::_('JLIB_FILESYSTEM_ERROR_FOLDER_EXISTS');
}
if ($useStreams) {
$stream = Factory::getStream();
if (!$stream->move($src, $dest)) {
return Text::sprintf('JLIB_FILESYSTEM_ERROR_FOLDER_RENAME', $stream->getError());
}
$ret = true;
} else {
if ($FTPOptions['enabled'] == 1) {
// Connect the FTP client
$ftp = FtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], [], $FTPOptions['user'], $FTPOptions['pass']);
// Translate path for the FTP account
$src = Path::clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $src), '/');
$dest = Path::clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $dest), '/');
// Use FTP rename to simulate move
if (!$ftp->rename($src, $dest)) {
return Text::_('JLIB_FILESYSTEM_ERROR_RENAME_FILE');
}
$ret = true;
} else {
if (!@rename($src, $dest)) {
return Text::_('JLIB_FILESYSTEM_ERROR_RENAME_FILE');
}
$ret = true;
}
}
return $ret;
}
/**
* Wrapper for the standard file_exists function
*
* @param string $path Folder name relative to installation dir
*
* @return boolean True if path is a folder
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use is_dir() instead.
*/
public static function exists($path)
{
return is_dir(Path::clean($path));
}
/**
* Utility function to read the files in a folder.
*
* @param string $path The path of the folder to read.
* @param string $filter A filter for file names.
* @param mixed $recurse True to recursively search into sub-folders, or an integer to specify the maximum depth.
* @param boolean $full True to return the full path to the file.
* @param array $exclude Array with names of files which should not be shown in the result.
* @param array $excludeFilter Array of filter to exclude
* @param boolean $naturalSort False for asort, true for natsort
*
* @return array|boolean Files in the given folder.
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Folder::files() instead.
* The framework class throws Exceptions in case of error which you have to catch.
*/
public static function files(
$path,
$filter = '.',
$recurse = false,
$full = false,
$exclude = ['.svn', 'CVS', '.DS_Store', '__MACOSX'],
$excludeFilter = ['^\..*', '.*~'],
$naturalSort = false
) {
// Check to make sure the path valid and clean
$path = Path::clean($path);
// Is the path a folder?
if (!is_dir($path)) {
Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER', __METHOD__, $path), Log::WARNING, 'jerror');
return false;
}
// Compute the excludefilter string
if (\count($excludeFilter)) {
$excludeFilterString = '/(' . implode('|', $excludeFilter) . ')/';
} else {
$excludeFilterString = '';
}
// Get the files
$arr = self::_items($path, $filter, $recurse, $full, $exclude, $excludeFilterString, true);
// Sort the files based on either natural or alpha method
if ($naturalSort) {
natsort($arr);
} else {
asort($arr);
}
return array_values($arr);
}
/**
* Utility function to read the folders in a folder.
*
* @param string $path The path of the folder to read.
* @param string $filter A filter for folder names.
* @param mixed $recurse True to recursively search into sub-folders, or an integer to specify the maximum depth.
* @param boolean $full True to return the full path to the folders.
* @param array $exclude Array with names of folders which should not be shown in the result.
* @param array $excludeFilter Array with regular expressions matching folders which should not be shown in the result.
*
* @return array Folders in the given folder.
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Folder::folders() instead.
* The framework class throws Exceptions in case of error which you have to catch.
*/
public static function folders(
$path,
$filter = '.',
$recurse = false,
$full = false,
$exclude = ['.svn', 'CVS', '.DS_Store', '__MACOSX'],
$excludeFilter = ['^\..*']
) {
// Check to make sure the path valid and clean
$path = Path::clean($path);
// Is the path a folder?
if (!is_dir($path)) {
Log::add(Text::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER', __METHOD__, $path), Log::WARNING, 'jerror');
return false;
}
// Compute the excludefilter string
if (\count($excludeFilter)) {
$excludeFilterString = '/(' . implode('|', $excludeFilter) . ')/';
} else {
$excludeFilterString = '';
}
// Get the folders
$arr = self::_items($path, $filter, $recurse, $full, $exclude, $excludeFilterString, false);
// Sort the folders
asort($arr);
return array_values($arr);
}
/**
* Function to read the files/folders in a folder.
*
* @param string $path The path of the folder to read.
* @param string $filter A filter for file names.
* @param mixed $recurse True to recursively search into sub-folders, or an integer to specify the maximum depth.
* @param boolean $full True to return the full path to the file.
* @param array $exclude Array with names of files which should not be shown in the result.
* @param string $excludeFilterString Regexp of files to exclude
* @param boolean $findFiles True to read the files, false to read the folders
*
* @return array Files.
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Folder::_items() instead.
*/
protected static function _items($path, $filter, $recurse, $full, $exclude, $excludeFilterString, $findFiles)
{
if (\function_exists('set_time_limit')) {
set_time_limit(\ini_get('max_execution_time'));
}
$arr = [];
// Read the source directory
if (!($handle = @opendir($path))) {
return $arr;
}
while (($file = readdir($handle)) !== false) {
if (
$file != '.' && $file != '..' && !\in_array($file, $exclude)
&& (empty($excludeFilterString) || !preg_match($excludeFilterString, $file))
) {
// Compute the fullpath
$fullpath = $path . '/' . $file;
// Compute the isDir flag
$isDir = is_dir($fullpath);
if (($isDir xor $findFiles) && preg_match("/$filter/", $file)) {
// (fullpath is dir and folders are searched or fullpath is not dir and files are searched) and file matches the filter
if ($full) {
// Full path is requested
$arr[] = $fullpath;
} else {
// Filename is requested
$arr[] = $file;
}
}
if ($isDir && $recurse) {
// Search recursively
if (\is_int($recurse)) {
// Until depth 0 is reached
$arr = array_merge($arr, self::_items($fullpath, $filter, $recurse - 1, $full, $exclude, $excludeFilterString, $findFiles));
} else {
$arr = array_merge($arr, self::_items($fullpath, $filter, $recurse, $full, $exclude, $excludeFilterString, $findFiles));
}
}
}
}
closedir($handle);
return $arr;
}
/**
* Lists folder in format suitable for tree display.
*
* @param string $path The path of the folder to read.
* @param string $filter A filter for folder names.
* @param integer $maxLevel The maximum number of levels to recursively read, defaults to three.
* @param integer $level The current level, optional.
* @param integer $parent Unique identifier of the parent folder, if any.
*
* @return array Folders in the given folder.
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Folder::listFolderTree() instead.
*/
public static function listFolderTree($path, $filter, $maxLevel = 3, $level = 0, $parent = 0)
{
$dirs = [];
if ($level == 0) {
$GLOBALS['_JFolder_folder_tree_index'] = 0;
}
if ($level < $maxLevel) {
$folders = self::folders($path, $filter);
// First path, index foldernames
foreach ($folders as $name) {
$id = ++$GLOBALS['_JFolder_folder_tree_index'];
$fullName = Path::clean($path . '/' . $name);
$dirs[] = [
'id' => $id,
'parent' => $parent,
'name' => $name,
'fullname' => $fullName,
'relname' => str_replace(JPATH_ROOT, '', $fullName),
];
$dirs2 = self::listFolderTree($fullName, $filter, $maxLevel, $level + 1, $id);
$dirs = array_merge($dirs, $dirs2);
}
}
return $dirs;
}
/**
* Makes path name safe to use.
*
* @param string $path The full path to sanitise.
*
* @return string The sanitised string.
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Folder::makeSafe() instead.
*/
public static function makeSafe($path)
{
$regex = ['#[^A-Za-z0-9_\\\/\(\)\[\]\{\}\#\$\^\+\.\'~`!@&=;,-]#'];
return preg_replace($regex, '', $path);
}
}
@@ -0,0 +1,12 @@
; Joomla! Project
; (C) 2012 Open Source Matters, Inc. <https://www.joomla.org>
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
JLIB_FILESYSTEM_PATCHER_FAILED_VERIFY="Failed source verification of file %s at line %d"
JLIB_FILESYSTEM_PATCHER_INVALID_DIFF="Invalid unified diff block"
JLIB_FILESYSTEM_PATCHER_INVALID_INPUT="Invalid input"
JLIB_FILESYSTEM_PATCHER_UNEXISTING_SOURCE="Unexisting source file"
JLIB_FILESYSTEM_PATCHER_UNEXPECTED_ADD_LINE="Unexpected add line at line %d'"
JLIB_FILESYSTEM_PATCHER_UNEXPECTED_EOF="Unexpected end of file"
JLIB_FILESYSTEM_PATCHER_UNEXPECTED_REMOVE_LINE="Unexpected remove line at line %d"
@@ -0,0 +1,529 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2012 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Filesystem;
use Joomla\CMS\Language\Text;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* A Unified Diff Format Patcher class
*
* @link http://sourceforge.net/projects/phppatcher/ This has been derived from the PhpPatcher version 0.1.1 written by Giuseppe Mazzotta
* @since 3.0.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Patcher instead.
*/
class Patcher
{
/**
* Regular expression for searching source files
*/
public const SRC_FILE = '/^---\\s+(\\S+)\s+\\d{1,4}-\\d{1,2}-\\d{1,2}\\s+\\d{1,2}:\\d{1,2}:\\d{1,2}(\\.\\d+)?\\s+(\+|-)\\d{4}/A';
/**
* Regular expression for searching destination files
*/
public const DST_FILE = '/^\\+\\+\\+\\s+(\\S+)\s+\\d{1,4}-\\d{1,2}-\\d{1,2}\\s+\\d{1,2}:\\d{1,2}:\\d{1,2}(\\.\\d+)?\\s+(\+|-)\\d{4}/A';
/**
* Regular expression for searching hunks of differences
*/
public const HUNK = '/@@ -(\\d+)(,(\\d+))?\\s+\\+(\\d+)(,(\\d+))?\\s+@@($)/A';
/**
* Regular expression for splitting lines
*/
public const SPLIT = '/(\r\n)|(\r)|(\n)/';
/**
* @var array sources files
* @since 3.0.0
*/
protected $sources = [];
/**
* @var array destination files
* @since 3.0.0
*/
protected $destinations = [];
/**
* @var array removal files
* @since 3.0.0
*/
protected $removals = [];
/**
* @var array patches
* @since 3.0.0
*/
protected $patches = [];
/**
* @var array instance of this class
* @since 3.0.0
*/
protected static $instance;
/**
* Constructor
*
* The constructor is protected to force the use of FilesystemPatcher::getInstance()
*
* @since 3.0.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Patcher::__construct() instead.
*/
protected function __construct()
{
}
/**
* Method to get a patcher
*
* @return Patcher an instance of the patcher
*
* @since 3.0.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Patcher::getInstance() instead.
*/
public static function getInstance()
{
if (!isset(static::$instance)) {
static::$instance = new static();
}
return static::$instance;
}
/**
* Reset the patcher
*
* @return Patcher This object for chaining
*
* @since 3.0.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Patcher::reset() instead.
*/
public function reset()
{
$this->sources = [];
$this->destinations = [];
$this->removals = [];
$this->patches = [];
return $this;
}
/**
* Apply the patches
*
* @return integer The number of files patched
*
* @since 3.0.0
* @throws \RuntimeException
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Patcher::apply() instead.
*/
public function apply()
{
foreach ($this->patches as $patch) {
// Separate the input into lines
$lines = self::splitLines($patch['udiff']);
// Loop for each header
while (self::findHeader($lines, $src, $dst)) {
$done = false;
$regex = '#^([^/]*/)*#';
if ($patch['strip'] !== null) {
$regex = '#^([^/]*/){' . (int) $patch['strip'] . '}#';
}
$src = $patch['root'] . preg_replace($regex, '', $src);
$dst = $patch['root'] . preg_replace($regex, '', $dst);
// Loop for each hunk of differences
while (self::findHunk($lines, $src_line, $src_size, $dst_line, $dst_size)) {
$done = true;
// Apply the hunk of differences
$this->applyHunk($lines, $src, $dst, $src_line, $src_size, $dst_line, $dst_size);
}
// If no modifications were found, throw an exception
if (!$done) {
throw new \RuntimeException('Invalid Diff');
}
}
}
// Initialize the counter
$done = 0;
// Patch each destination file
foreach ($this->destinations as $file => $content) {
$buffer = implode("\n", $content);
if (File::write($file, $buffer)) {
if (isset($this->sources[$file])) {
$this->sources[$file] = $content;
}
$done++;
}
}
// Remove each removed file
foreach ($this->removals as $file) {
if (File::delete($file)) {
if (isset($this->sources[$file])) {
unset($this->sources[$file]);
}
$done++;
}
}
// Clear the destinations cache
$this->destinations = [];
// Clear the removals
$this->removals = [];
// Clear the patches
$this->patches = [];
return $done;
}
/**
* Add a unified diff file to the patcher
*
* @param string $filename Path to the unified diff file
* @param string $root The files root path
* @param integer $strip The number of '/' to strip
*
* @return Patcher $this for chaining
*
* @since 3.0.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Patcher::addFile() instead.
*/
public function addFile($filename, $root = JPATH_BASE, $strip = 0)
{
return $this->add(file_get_contents($filename), $root, $strip);
}
/**
* Add a unified diff string to the patcher
*
* @param string $udiff Unified diff input string
* @param string $root The files root path
* @param integer $strip The number of '/' to strip
*
* @return Patcher $this for chaining
*
* @since 3.0.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Patcher::add() instead.
*/
public function add($udiff, $root = JPATH_BASE, $strip = 0)
{
$this->patches[] = [
'udiff' => $udiff,
'root' => isset($root) ? rtrim($root, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : '',
'strip' => $strip,
];
return $this;
}
/**
* Separate CR or CRLF lines
*
* @param string $data Input string
*
* @return array The lines of the inputdestination file
*
* @since 3.0.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Patcher::splitLines() instead.
*/
protected static function splitLines($data)
{
return preg_split(self::SPLIT, $data);
}
/**
* Find the diff header
*
* The internal array pointer of $lines is on the next line after the finding
*
* @param array $lines The udiff array of lines
* @param string $src The source file
* @param string $dst The destination file
*
* @return boolean TRUE in case of success, FALSE in case of failure
*
* @since 3.0.0
* @throws \RuntimeException
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Patcher::findHeader() instead.
*/
protected static function findHeader(&$lines, &$src, &$dst)
{
// Get the current line
$line = current($lines);
// Search for the header
while ($line !== false && !preg_match(self::SRC_FILE, $line, $m)) {
$line = next($lines);
}
if ($line === false) {
// No header found, return false
return false;
}
// Set the source file
$src = $m[1];
// Advance to the next line
$line = next($lines);
if ($line === false) {
throw new \RuntimeException('Unexpected EOF');
}
// Search the destination file
if (!preg_match(self::DST_FILE, $line, $m)) {
throw new \RuntimeException('Invalid Diff file');
}
// Set the destination file
$dst = $m[1];
// Advance to the next line
if (next($lines) === false) {
throw new \RuntimeException('Unexpected EOF');
}
return true;
}
/**
* Find the next hunk of difference
*
* The internal array pointer of $lines is on the next line after the finding
*
* @param array $lines The udiff array of lines
* @param string $srcLine The beginning of the patch for the source file
* @param string $srcSize The size of the patch for the source file
* @param string $dstLine The beginning of the patch for the destination file
* @param string $dstSize The size of the patch for the destination file
*
* @return boolean TRUE in case of success, false in case of failure
*
* @since 3.0.0
* @throws \RuntimeException
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Patcher::findHunk() instead.
*/
protected static function findHunk(&$lines, &$srcLine, &$srcSize, &$dstLine, &$dstSize)
{
$line = current($lines);
if (preg_match(self::HUNK, $line, $m)) {
$srcLine = (int) $m[1];
$srcSize = 1;
if ($m[3] !== '') {
$srcSize = (int) $m[3];
}
$dstLine = (int) $m[4];
$dstSize = 1;
if ($m[6] !== '') {
$dstSize = (int) $m[6];
}
if (next($lines) === false) {
throw new \RuntimeException('Unexpected EOF');
}
return true;
}
return false;
}
/**
* Apply the patch
*
* @param array $lines The udiff array of lines
* @param string $src The source file
* @param string $dst The destination file
* @param string $srcLine The beginning of the patch for the source file
* @param string $srcSize The size of the patch for the source file
* @param string $dstLine The beginning of the patch for the destination file
* @param string $dstSize The size of the patch for the destination file
*
* @return void
*
* @since 3.0.0
* @throws \RuntimeException
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Patcher::applyHunk() instead.
*/
protected function applyHunk(&$lines, $src, $dst, $srcLine, $srcSize, $dstLine, $dstSize)
{
$srcLine--;
$dstLine--;
$line = current($lines);
// Source lines (old file)
$source = [];
// New lines (new file)
$destin = [];
$src_left = $srcSize;
$dst_left = $dstSize;
do {
if (!isset($line[0])) {
$source[] = '';
$destin[] = '';
$src_left--;
$dst_left--;
} elseif ($line[0] == '-') {
if ($src_left == 0) {
throw new \RuntimeException(Text::sprintf('JLIB_FILESYSTEM_PATCHER_UNEXPECTED_REMOVE_LINE', key($lines)));
}
$source[] = substr($line, 1);
$src_left--;
} elseif ($line[0] == '+') {
if ($dst_left == 0) {
throw new \RuntimeException(Text::sprintf('JLIB_FILESYSTEM_PATCHER_UNEXPECTED_ADD_LINE', key($lines)));
}
$destin[] = substr($line, 1);
$dst_left--;
} elseif ($line != '\\ No newline at end of file') {
$line = substr($line, 1);
$source[] = $line;
$destin[] = $line;
$src_left--;
$dst_left--;
}
if ($src_left == 0 && $dst_left == 0) {
// Now apply the patch, finally!
if ($srcSize > 0) {
$src_lines = & $this->getSource($src);
if (!isset($src_lines)) {
throw new \RuntimeException(
Text::sprintf(
'JLIB_FILESYSTEM_PATCHER_UNEXISTING_SOURCE',
Path::removeRoot($src)
)
);
}
}
if ($dstSize > 0) {
if ($srcSize > 0) {
$dst_lines = & $this->getDestination($dst, $src);
$src_bottom = $srcLine + \count($source);
for ($l = $srcLine; $l < $src_bottom; $l++) {
if ($src_lines[$l] != $source[$l - $srcLine]) {
throw new \RuntimeException(
Text::sprintf(
'JLIB_FILESYSTEM_PATCHER_FAILED_VERIFY',
Path::removeRoot($src),
$l
)
);
}
}
array_splice($dst_lines, $dstLine, \count($source), $destin);
} else {
$this->destinations[$dst] = $destin;
}
} else {
$this->removals[] = $src;
}
next($lines);
return;
}
$line = next($lines);
} while ($line !== false);
throw new \RuntimeException('Unexpected EOF');
}
/**
* Get the lines of a source file
*
* @param string $src The path of a file
*
* @return array The lines of the source file
*
* @since 3.0.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Patcher::getSource() instead.
*/
protected function &getSource($src)
{
if (!isset($this->sources[$src])) {
$this->sources[$src] = null;
if (is_readable($src)) {
$this->sources[$src] = self::splitLines(file_get_contents($src));
}
}
return $this->sources[$src];
}
/**
* Get the lines of a destination file
*
* @param string $dst The path of a destination file
* @param string $src The path of a source file
*
* @return array The lines of the destination file
*
* @since 3.0.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Patcher::getDestination() instead.
*/
protected function &getDestination($dst, $src)
{
if (!isset($this->destinations[$dst])) {
$this->destinations[$dst] = $this->getSource($src);
}
return $this->destinations[$dst];
}
}
@@ -0,0 +1,97 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Filesystem;
\defined('_JEXEC') or die;
use Joomla\Filesystem\Path as FilesystemPath;
if (!\defined('JPATH_ROOT')) {
// Define a string constant for the root directory of the file system in native format
\define('JPATH_ROOT', Path::clean(JPATH_SITE));
}
/**
* A Path handling class
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Path instead.
*/
class Path extends FilesystemPath
{
/**
* Checks for snooping outside of the file system root.
*
* @param string $path A file system path to check.
*
* @return string A cleaned version of the path or exit on error.
*
* @throws \Exception
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Path::check() instead.
*/
public static function check($path, $basePath = '')
{
if ($basePath == '') {
$basePath = JPATH_ROOT;
}
return parent::check($path, $basePath);
}
/**
* 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.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Path::isOwner() instead.
*/
public static function isOwner($path)
{
$tmp = md5(random_bytes(16));
$ssp = \ini_get('session.save_path');
$jtp = JPATH_SITE . '/tmp';
// Try to find a writable directory
$dir = false;
foreach ([$jtp, $ssp, '/tmp'] as $currentDir) {
if (is_writable($currentDir)) {
$dir = $currentDir;
break;
}
}
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;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,304 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2008 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Filesystem\Streams;
\defined('_JEXEC') or die;
use Joomla\CMS\Filesystem\Support\StringController;
/**
* String Stream Wrapper
*
* This class allows you to use a PHP string in the same way that
* you would normally use a regular stream wrapper
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Stream\StringWrapper instead.
*/
class StreamString
{
/**
* The current string
*
* @var string
* @since 3.0.0
*/
protected $currentString;
/**
* The path
*
* @var string
* @since 3.0.0
*/
protected $path;
/**
* The mode
*
* @var string
* @since 3.0.0
*/
protected $mode;
/**
* Enter description here ...
*
* @var string
* @since 3.0.0
*/
protected $options;
/**
* Enter description here ...
*
* @var string
* @since 3.0.0
*/
protected $openedPath;
/**
* Current position
*
* @var integer
* @since 3.0.0
*/
protected $pos;
/**
* Length of the string
*
* @var string
* @since 3.0.0
*/
protected $len;
/**
* Statistics for a file
*
* @var array
* @since 3.0.0
*
* @link http://us.php.net/manual/en/function.stat.php
*/
protected $stat;
/**
* Method to open a file or URL.
*
* @param string $path The stream path.
* @param string $mode Not used.
* @param integer $options Not used.
* @param string $openedPath Not used.
*
* @return boolean
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Stream\StringWrapper::stream_open() instead.
*/
public function stream_open($path, $mode, $options, &$openedPath)
{
$this->currentString = &StringController::getRef(str_replace('string://', '', $path));
if ($this->currentString) {
$this->len = \strlen($this->currentString);
$this->pos = 0;
$this->stat = $this->url_stat($path, 0);
return true;
}
return false;
}
/**
* Method to retrieve information from a file resource
*
* @return array
*
* @link https://www.php.net/manual/en/streamwrapper.stream-stat.php
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Stream\StringWrapper::stream_stat instead.
*/
public function stream_stat()
{
return $this->stat;
}
/**
* Method to retrieve information about a file.
*
* @param string $path File path or URL to stat
* @param integer $flags Additional flags set by the streams API
*
* @return array
*
* @link https://www.php.net/manual/en/streamwrapper.url-stat.php
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Stream\StringWrapper::url_stat() instead.
*/
public function url_stat($path, $flags = 0)
{
$now = time();
$string = &StringController::getRef(str_replace('string://', '', $path));
$stat = [
'dev' => 0,
'ino' => 0,
'mode' => 0,
'nlink' => 1,
'uid' => 0,
'gid' => 0,
'rdev' => 0,
'size' => \strlen($string),
'atime' => $now,
'mtime' => $now,
'ctime' => $now,
'blksize' => '512',
'blocks' => ceil(\strlen($string) / 512),
];
return $stat;
}
/**
* Method to read a given number of bytes starting at the current position
* and moving to the end of the string defined by the current position plus the
* given number.
*
* @param integer $count Bytes of data from the current position should be returned.
*
* @return string
*
* @link https://www.php.net/manual/en/streamwrapper.stream-read.php
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Stream\StringWrapper::stream_read() instead.
*/
public function stream_read($count)
{
$result = substr($this->currentString, $this->pos, $count);
$this->pos += $count;
return $result;
}
/**
* Stream write, always returning false.
*
* @param string $data The data to write.
*
* @return boolean
*
* @since 1.7.0
* @note Updating the string is not supported.
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Stream\StringWrapper::stream_write() instead.
*/
public function stream_write($data)
{
// We don't support updating the string.
return false;
}
/**
* Method to get the current position
*
* @return integer The position
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Stream\StringWrapper::stream_tell() instead.
*/
public function stream_tell()
{
return $this->pos;
}
/**
* End of field check
*
* @return boolean True if at end of field.
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Stream\StringWrapper::stream_eof() instead.
*/
public function stream_eof()
{
if ($this->pos > $this->len) {
return true;
}
return false;
}
/**
* Stream offset
*
* @param integer $offset The starting offset.
* @param integer $whence SEEK_SET, SEEK_CUR, SEEK_END
*
* @return boolean True on success.
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Stream\StringWrapper::stream_seek() instead.
*/
public function stream_seek($offset, $whence)
{
// $whence: SEEK_SET, SEEK_CUR, SEEK_END
if ($offset > $this->len) {
// We can't seek beyond our len.
return false;
}
switch ($whence) {
case SEEK_SET:
$this->pos = $offset;
break;
case SEEK_CUR:
if (($this->pos + $offset) < $this->len) {
$this->pos += $offset;
} else {
return false;
}
break;
case SEEK_END:
$this->pos = $this->len - $offset;
break;
}
return true;
}
/**
* Stream flush, always returns true.
*
* @return boolean
*
* @since 1.7.0
* @note Data storage is not supported
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Stream\StringWrapper::stream_flush() instead.
*/
public function stream_flush()
{
// We don't store data.
return true;
}
}
stream_wrapper_register('string', '\\Joomla\\CMS\\Filesystem\\Streams\\StreamString') or die('StreamString Wrapper Registration Failed');
@@ -0,0 +1,76 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2008 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Filesystem\Support;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* String Controller
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Support\StringController instead.
*/
class StringController
{
/**
* Defines a variable as an array
*
* @return array
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Support\StringController::getArray() instead.
*/
public function _getArray()
{
static $strings = [];
return $strings;
}
/**
* Create a reference
*
* @param string $reference The key
* @param string $string The value
*
* @return void
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Support\StringController::createRef() instead.
*/
public function createRef($reference, &$string)
{
$ref =& self::_getArray();
$ref[$reference] =& $string;
}
/**
* Get reference
*
* @param string $reference The key for the reference.
*
* @return mixed False if not set, reference if it exists
*
* @since 1.7.0
* @deprecated 4.4 will be removed in 6.0
* Use Joomla\Filesystem\Support\StringController::getRef() instead.
*/
public function getRef($reference)
{
$ref =& self::_getArray();
return $ref[$reference] ?? false;
}
}
@@ -0,0 +1,159 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Input;
use Joomla\CMS\Filter\InputFilter;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Joomla! Input Cookie Class
*
* @since 1.7.0
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Cookie instead
*/
class Cookie extends Input
{
/**
* Constructor.
*
* @param array $source Ignored.
* @param array $options Array of configuration parameters (Optional)
*
* @since 1.7.0
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Cookie instead
*/
public function __construct(?array $source = null, array $options = [])
{
if (isset($options['filter'])) {
$this->filter = $options['filter'];
} else {
$this->filter = InputFilter::getInstance();
}
// Set the data source.
$this->data = &$_COOKIE;
// Set the options for the class.
$this->options = $options;
}
/**
* Sets a value
*
* @param string $name Name of the value to set.
* @param mixed $value Value to assign to the input.
* @param array $options An associative array which may have any of the keys expires, path, domain,
* secure, httponly and samesite. The values have the same meaning as described
* for the parameters with the same name. The value of the samesite element
* should be either Lax or Strict. If any of the allowed options are not given,
* their default values are the same as the default values of the explicit
* parameters. If the samesite element is omitted, no SameSite cookie attribute
* is set.
*
* @return void
*
* @link http://www.ietf.org/rfc/rfc2109.txt
* @see setcookie()
* @since 1.7.0
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Cookie instead
*/
public function set($name, $value, $options = [])
{
// BC layer to convert old method parameters.
if (\is_array($options) === false) {
trigger_deprecation(
'joomla/input',
'1.4.0',
'The %s($name, $value, $expire, $path, $domain, $secure, $httpOnly) signature is deprecated and'
. ' will not be supported once support'
. ' for PHP 7.2 and earlier is dropped, use the %s($name, $value, $options) signature instead',
__METHOD__,
__METHOD__
);
$argList = \func_get_args();
$options = [
'expires' => $argList[2] ?? 0,
'path' => $argList[3] ?? '',
'domain' => $argList[4] ?? '',
'secure' => $argList[5] ?? false,
'httponly' => $argList[6] ?? false,
];
}
// Set the cookie
if (version_compare(PHP_VERSION, '7.3', '>=')) {
if (\is_array($value)) {
foreach ($value as $key => $val) {
setcookie($name . "[$key]", $val, $options);
}
} else {
setcookie($name, $value, $options);
}
} else {
// Using the setcookie function before php 7.3, make sure we have default values.
if (\array_key_exists('expires', $options) === false) {
$options['expires'] = 0;
}
if (\array_key_exists('path', $options) === false) {
$options['path'] = '';
}
if (\array_key_exists('domain', $options) === false) {
$options['domain'] = '';
}
if (\array_key_exists('secure', $options) === false) {
$options['secure'] = false;
}
if (\array_key_exists('httponly', $options) === false) {
$options['httponly'] = false;
}
if (\is_array($value)) {
foreach ($value as $key => $val) {
setcookie(
$name . "[$key]",
$val,
$options['expires'],
$options['path'],
$options['domain'],
$options['secure'],
$options['httponly']
);
}
} else {
setcookie(
$name,
$value,
$options['expires'],
$options['path'],
$options['domain'],
$options['secure'],
$options['httponly']
);
}
}
$this->data[$name] = $value;
}
}
@@ -0,0 +1,152 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Input;
use Joomla\CMS\Filter\InputFilter;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Joomla! Input Files Class
*
* @since 1.7.0
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Files instead
*/
class Files extends Input
{
/**
* The pivoted data from a $_FILES or compatible array.
*
* @var array
* @since 1.7.0
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Files instead
*/
protected $decodedData = [];
/**
* The class constructor.
*
* @param array $source The source argument is ignored. $_FILES is always used.
* @param array $options An optional array of configuration options:
* filter : a custom InputFilter object.
*
* @since 3.0.0
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Files instead
*/
public function __construct(?array $source = null, array $options = [])
{
if (isset($options['filter'])) {
$this->filter = $options['filter'];
} else {
$this->filter = InputFilter::getInstance();
}
// Set the data source.
$this->data = &$_FILES;
// Set the options for the class.
$this->options = $options;
}
/**
* Gets a value from the input data.
*
* @param string $name The name of the input property (usually the name of the files INPUT tag) to get.
* @param mixed $default The default value to return if the named property does not exist.
* @param string $filter The filter to apply to the value.
*
* @return mixed The filtered input value.
*
* @see InputFilter::clean()
* @since 1.7.0
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Files instead
*/
public function get($name, $default = null, $filter = 'cmd')
{
if (isset($this->data[$name])) {
$results = $this->decodeData(
[
$this->data[$name]['name'],
$this->data[$name]['type'],
$this->data[$name]['tmp_name'],
$this->data[$name]['error'],
$this->data[$name]['size'],
]
);
// Prevent returning an unsafe file unless specifically requested
if (strtoupper($filter) !== 'RAW') {
$isSafe = InputFilter::isSafeFile($results);
if (!$isSafe) {
return $default;
}
}
return $results;
}
return $default;
}
/**
* Method to decode a data array.
*
* @param array $data The data array to decode.
*
* @return array
*
* @since 1.7.0
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Files instead
*/
protected function decodeData(array $data)
{
$result = [];
if (\is_array($data[0])) {
foreach ($data[0] as $k => $v) {
$result[$k] = $this->decodeData([$data[0][$k], $data[1][$k], $data[2][$k], $data[3][$k], $data[4][$k]]);
}
return $result;
}
return ['name' => $data[0], 'type' => $data[1], 'tmp_name' => $data[2], 'error' => $data[3], 'size' => $data[4]];
}
/**
* Sets a value.
*
* @param string $name The name of the input property to set.
* @param mixed $value The value to assign to the input property.
*
* @return void
*
* @since 1.7.0
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Files instead
*/
public function set($name, $value)
{
}
}
@@ -0,0 +1,222 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Input;
use Joomla\CMS\Filter\InputFilter;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Joomla! Input Base Class
*
* This is an abstracted input class used to manage retrieving data from the application environment.
*
* @since 1.7.0
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Input instead
*
* @property-read Input $get
* @property-read Input $post
* @property-read Input $request
* @property-read Input $server
* @property-read Input $env
* @property-read Files $files
* @property-read Cookie $cookie
* @property-read Json $json
*/
class Input extends \Joomla\Input\Input
{
/**
* Container with allowed superglobals
*
* @var array
* @since 3.8.9
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Input instead
*/
private static $allowedGlobals = ['REQUEST', 'GET', 'POST', 'FILES', 'SERVER', 'ENV'];
/**
* Input objects
*
* @var Input[]
* @since 1.7.0
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Input instead
*/
protected $inputs = [];
/**
* Constructor.
*
* @param array $source Source data (Optional, default is $_REQUEST)
* @param array $options Array of configuration parameters (Optional)
*
* @since 1.7.0
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Input instead
*/
public function __construct($source = null, array $options = [])
{
if (!isset($options['filter'])) {
$this->filter = InputFilter::getInstance();
}
parent::__construct($source, $options);
}
/**
* Magic method to get an input object
*
* @param mixed $name Name of the input object to retrieve.
*
* @return \Joomla\Input\Input The request input object
*
* @since 1.7.0
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Input instead
*/
public function __get($name)
{
if (isset($this->inputs[$name])) {
return $this->inputs[$name];
}
$className = '\\Joomla\\CMS\\Input\\' . ucfirst($name);
if (class_exists($className)) {
$this->inputs[$name] = new $className(null, $this->options);
return $this->inputs[$name];
}
$superGlobal = '_' . strtoupper($name);
if (\in_array(strtoupper($name), self::$allowedGlobals, true) && isset($GLOBALS[$superGlobal])) {
$this->inputs[$name] = new Input($GLOBALS[$superGlobal], $this->options);
return $this->inputs[$name];
}
// Try using the parent class
return parent::__get($name);
}
/**
* Gets an array of values from the request.
*
* @param array $vars Associative array of keys and filter types to apply.
* If empty and datasource is null, all the input data will be returned
* but filtered using the filter given by the parameter defaultFilter in
* InputFilter::clean.
* @param mixed $datasource Array to retrieve data from, or null.
* @param string $defaultFilter Default filter used in InputFilter::clean if vars is empty and
* datasource is null. If 'unknown', the default case is used in
* InputFilter::clean.
*
* @return mixed The filtered input data.
*
* @since 1.7.0
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Input instead
*/
public function getArray(array $vars = [], $datasource = null, $defaultFilter = 'unknown')
{
return $this->getArrayRecursive($vars, $datasource, $defaultFilter, false);
}
/**
* Gets an array of values from the request.
*
* @param array $vars Associative array of keys and filter types to apply.
* If empty and datasource is null, all the input data will be returned
* but filtered using the filter given by the parameter defaultFilter in
* InputFilter::clean.
* @param mixed $datasource Array to retrieve data from, or null.
* @param string $defaultFilter Default filter used in InputFilter::clean if vars is empty and
* datasource is null. If 'unknown', the default case is used in
* InputFilter::clean.
* @param bool $recursion Flag to indicate a recursive function call.
*
* @return mixed The filtered input data.
*
* @since 3.4.2
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Input instead
*/
protected function getArrayRecursive(array $vars = [], $datasource = null, $defaultFilter = 'unknown', $recursion = false)
{
if (empty($vars) && \is_null($datasource)) {
$vars = $this->data;
} else {
if (!$recursion) {
$defaultFilter = null;
}
}
$results = [];
foreach ($vars as $k => $v) {
if (\is_array($v)) {
if (\is_null($datasource)) {
$results[$k] = $this->getArrayRecursive($v, $this->get($k, null, 'array'), $defaultFilter, true);
} else {
$results[$k] = $this->getArrayRecursive($v, $datasource[$k], $defaultFilter, true);
}
} else {
$filter = $defaultFilter ?? $v;
if (\is_null($datasource)) {
$results[$k] = $this->get($k, null, $filter);
} elseif (isset($datasource[$k])) {
$results[$k] = $this->filter->clean($datasource[$k], $filter);
} else {
$results[$k] = $this->filter->clean(null, $filter);
}
}
}
return $results;
}
/**
* Method to unserialize the input.
*
* @param string $input The serialized input.
*
* @return void
*
* @since 3.0.0
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Input instead
*/
public function unserialize($input)
{
// Unserialize the options, data, and inputs.
list($this->options, $this->data, $this->inputs) = unserialize($input);
// Load the filter.
if (isset($this->options['filter'])) {
$this->filter = $this->options['filter'];
} else {
$this->filter = InputFilter::getInstance();
}
}
}
@@ -0,0 +1,88 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2012 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Input;
use Joomla\CMS\Filter\InputFilter;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Joomla! Input JSON Class
*
* This class decodes a JSON string from the raw request data and makes it available via
* the standard JInput interface.
*
* @since 3.0.1
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Json instead
*/
class Json extends Input
{
/**
* @var string The raw JSON string from the request.
* @since 3.0.1
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Json instead
*/
// phpcs:ignore
private $_raw;
/**
* Constructor.
*
* @param array $source Source data (Optional, default is the raw HTTP input decoded from JSON)
* @param array $options Array of configuration parameters (Optional)
*
* @since 3.0.1
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Json instead
*/
public function __construct(?array $source = null, array $options = [])
{
if (isset($options['filter'])) {
$this->filter = $options['filter'];
} else {
$this->filter = InputFilter::getInstance();
}
if (\is_null($source)) {
$this->_raw = file_get_contents('php://input');
$this->data = json_decode($this->_raw, true);
if (!\is_array($this->data)) {
$this->data = [];
}
} else {
$this->data = &$source;
}
$this->options = $options;
}
/**
* Gets the raw JSON string from the request.
*
* @return string The raw JSON string from the request.
*
* @since 3.0.1
*
* @deprecated 4.3 will be removed in 6.0.
* Use Joomla\Input\Json instead
*/
public function getRaw()
{
return $this->_raw;
}
}