primo commit

This commit is contained in:
2024-12-17 17:34:10 +01:00
commit e650f8df99
16435 changed files with 2451012 additions and 0 deletions

View File

@ -0,0 +1,69 @@
<?php
/**
* @package FOF
* @copyright Copyright (c)2010-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
namespace FOF40\Cli\Traits;
defined('_JEXEC') || die;
/**
* CGI Mode detection and workaround
*
* Some hosts only give access to the PHP CGI binary, even for running CLI scripts. While problematic, it mostly works.
* This trait detects PHP-CGI and manipulates $_GET in such a way that we populate the $argv and $argc global variables
* in the same way that PHP-CLI would set them. This allows the CLI input object to work. Moreover, we unset the PHP
* execution time limit, if possible, to prevent accidental timeouts.
*
* @package FOF40\Cli\Traits
*/
trait CGIModeAware
{
/**
* Detect if we are running under CGI mode. In this case it populates the global $argv and $argc parameters off the
* CGI input ($_GET superglobal).
*/
private function detectAndWorkAroundCGIMode()
{
// This code only executes when running under CGI. So let's detect it first.
$cgiMode = (!defined('STDOUT') || !defined('STDIN') || !isset($_SERVER['argv']));
if (!$cgiMode)
{
return;
}
// CGI mode has a time limit. Unset it to prevent timeouts.
if (function_exists('set_time_limit'))
{
set_time_limit(0);
}
// Convert $_GET into the appropriate $argv representation. This allows Input\Cli to work under PHP-CGI.
$query = "";
if (!empty($_GET))
{
foreach ($_GET as $k => $v)
{
$query .= " $k";
if ($v != "")
{
$query .= "=$v";
}
}
}
$query = ltrim($query);
global $argv, $argc;
$argv = explode(' ', $query);
$argc = count($argv);
$_SERVER['argv'] = $argv;
}
}

View File

@ -0,0 +1,204 @@
<?php
/**
* @package FOF
* @copyright Copyright (c)2010-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
namespace FOF40\Cli\Traits;
defined('_JEXEC') || die;
use JFilterInput;
use Joomla\CMS\Filter\InputFilter;
/**
* Implements a simpler, more straightforward options parser than the Joomla CLI input object. It supports short options
* when the Joomla CLI input object doesn't. Eventually this will go away and we can use something like Symfony Console
* instead.
*
* @package FOF40\Cli\Traits
*/
trait CustomOptionsAware
{
/**
* POSIX-style CLI options. Access them with through the getOption method.
*
* @var array
*/
protected static $cliOptions = [];
/**
* Filter object to use for custom options parsing.
*
* @var JFilterInput|InputFilter
*/
protected $filter = null;
/**
* Initializes the custom CLI options parsing
*
* @return void
*/
protected function initialiseCustomOptions()
{
// Create a new JFilterInput
if (class_exists('JFilterInput'))
{
$this->filter = JFilterInput::getInstance();
}
else
{
$this->filter = InputFilter::getInstance();
}
// Parse the POSIX options
$this->parseOptions();
}
/**
* Parses POSIX command line options and sets the self::$cliOptions associative array. Each array item contains
* a single dimensional array of values. Arguments without a dash are silently ignored.
*
* This works much better than JInputCli since it allows you to use all valid POSIX ways of defining CLI parameters.
*
* @return void
*/
protected function parseOptions()
{
global $argc, $argv;
// Workaround for PHP-CGI
if (!isset($argc) && !isset($argv))
{
$query = "";
if (!empty($_GET))
{
foreach ($_GET as $k => $v)
{
$query .= " $k";
if ($v != "")
{
$query .= "=$v";
}
}
}
$query = ltrim($query);
$argv = explode(' ', $query);
$argc = count($argv);
}
$currentName = "";
$options = [];
for ($i = 1; $i < $argc; $i++)
{
$argument = $argv[$i];
$value = $argument;
if (strpos($argument, "-") === 0)
{
$argument = ltrim($argument, '-');
$name = $argument;
$value = null;
if (strstr($argument, '='))
{
list($name, $value) = explode('=', $argument, 2);
}
$currentName = $name;
if (!isset($options[$currentName]) || ($options[$currentName] == null))
{
$options[$currentName] = [];
}
}
if ((!is_null($value)) && (!is_null($currentName)))
{
$key = null;
if (strstr($value, '='))
{
$parts = explode('=', $value, 2);
$key = $parts[0];
$value = $parts[1];
}
$values = $options[$currentName];
if (is_null($values))
{
$values = [];
}
if (is_null($key))
{
array_push($values, $value);
}
else
{
$values[$key] = $value;
}
$options[$currentName] = $values;
}
}
self::$cliOptions = $options;
}
/**
* Returns the value of a command line option. This does NOT use JInputCLI. You MUST run parseOptions before.
*
* @param string $key The full name of the option, e.g. "foobar"
* @param mixed $default The default value to return
* @param string $type Joomla! filter type, e.g. cmd, int, bool and so on.
*
* @return mixed The value of the option
*/
protected function getOption($key, $default = null, $type = 'raw')
{
// If the key doesn't exist set it to the default value
if (!array_key_exists($key, self::$cliOptions))
{
self::$cliOptions[$key] = is_array($default) ? $default : [$default];
}
$type = strtolower($type);
if ($type == 'array')
{
return self::$cliOptions[$key];
}
$value = null;
if (!empty(self::$cliOptions[$key]))
{
$value = self::$cliOptions[$key][0];
}
return $this->filterVariable($value, $type);
}
/**
* Filter a variable using JInputFilter
*
* @param mixed $var The variable to filter
* @param string $type The filter type, default 'cmd'
*
* @return mixed The filtered value
*/
protected function filterVariable($var, $type = 'cmd')
{
return $this->filter->clean($var, $type);
}
}

View File

@ -0,0 +1,55 @@
<?php
/**
* @package FOF
* @copyright Copyright (c)2010-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
namespace FOF40\Cli\Traits;
defined('_JEXEC') || die;
/**
* Allows the CLI application to use the Joomla Global Configuration parameters as its own configuration.
*
* @package FOF40\Cli\Traits
*/
trait JoomlaConfigAware
{
/**
* Method to load the application configuration, returning it as an object or array
*
* This can be overridden in subclasses if you don't want to fetch config from a PHP class file.
*
* @param string|null $file The filepath to the file containing the configuration class. Default: Joomla's
* configuration.php
* @param string $className The name of the PHP class holding the configuration. Default: JConfig
*
* @return mixed Either an array or object to be loaded into the configuration object.
*/
protected function fetchConfigurationData($file = null, $className = 'JConfig')
{
// Set the configuration file name.
if (empty($file))
{
$file = JPATH_BASE . '/configuration.php';
}
// Import the configuration file.
if (!is_file($file))
{
return [];
}
include_once $file;
// Instantiate the configuration object.
if (!class_exists('JConfig'))
{
return [];
}
return new $className();
}
}

View File

@ -0,0 +1,73 @@
<?php
/**
* @package FOF
* @copyright Copyright (c)2010-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
namespace FOF40\Cli\Traits;
defined('_JEXEC') || die;
/**
* Memory statistics
*
* This is an optional trait which allows the developer to print memory usage statistics and format byte sizes into
* human-readable strings.
*
* @package FOF40\Cli\Traits
*/
trait MemStatsAware
{
/**
* Formats a number of bytes in human readable format
*
* @param int $size The size in bytes to format, e.g. 8254862
*
* @return string The human-readable representation of the byte size, e.g. "7.87 Mb"
*/
protected function formatByteSize($size)
{
$unit = ['b', 'KB', 'MB', 'GB', 'TB', 'PB'];
return @round($size / pow(1024, ($i = floor(log($size, 1024)))), 2) . ' ' . $unit[$i];
}
/**
* Returns the current memory usage, formatted
*
* @return string
*/
protected function memUsage()
{
if (function_exists('memory_get_usage'))
{
$size = memory_get_usage();
return $this->formatByteSize($size);
}
else
{
return "(unknown)";
}
}
/**
* Returns the peak memory usage, formatted
*
* @return string
*/
protected function peakMemUsage()
{
if (function_exists('memory_get_peak_usage'))
{
$size = memory_get_peak_usage();
return $this->formatByteSize($size);
}
else
{
return "(unknown)";
}
}
}

View File

@ -0,0 +1,64 @@
<?php
/**
* @package FOF
* @copyright Copyright (c)2010-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
namespace FOF40\Cli\Traits;
defined('_JEXEC') || die;
/**
* Sometimes other extensions will try to enqueue messages to the application. Methods for those tasks only exists in
* web applications, so we have to replicate their behavior in CLI environment or fatal errors will occur
*
* @package FOF40\Cli\Traits
*/
trait MessageAware
{
/** @var array Queue holding all messages */
protected $messageQueue = [];
/**
* @param $msg
* @param $type
*
* @return void
*/
public function enqueueMessage($msg, $type)
{
// Don't add empty messages.
if (trim($msg) === '')
{
return;
}
$message = ['message' => $msg, 'type' => strtolower($type)];
if (!in_array($message, $this->messageQueue))
{
// Enqueue the message.
$this->messageQueue[] = $message;
}
}
/**
* Loosely based on Joomla getMessageQueue
*
* @param bool $clear
*
* @return array
*/
public function getMessageQueue($clear = false)
{
$messageQueue = $this->messageQueue;
if ($clear)
{
$this->messageQueue = [];
}
return $messageQueue;
}
}

View File

@ -0,0 +1,100 @@
<?php
/**
* @package FOF
* @copyright Copyright (c)2010-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
namespace FOF40\Cli\Traits;
defined('_JEXEC') || die;
/**
* Allows the developer to show the relative time difference between two timestamps.
*
* @package FOF40\Cli\Traits
*/
trait TimeAgoAware
{
/**
* Returns the relative time difference between two timestamps in a human readable format
*
* @param int $referenceTimestamp Timestamp of the reference date/time
* @param int|null $currentTimestamp Timestamp of the current date/time. Null for time().
* @param string $timeUnit Time unit. One of s, m, h, d, or y.
* @param bool $autoSuffix Add "ago" / "from now" suffix?
*
* @return string For example, "10 seconds ago"
*/
protected function timeAgo($referenceTimestamp = 0, $currentTimestamp = null, $timeUnit = '', $autoSuffix = true)
{
if (is_null($currentTimestamp))
{
$currentTimestamp = time();
}
// Raw time difference
$raw = $currentTimestamp - $referenceTimestamp;
$clean = abs($raw);
$calcNum = [
['s', 60],
['m', 60 * 60],
['h', 60 * 60 * 60],
['d', 60 * 60 * 60 * 24],
['y', 60 * 60 * 60 * 24 * 365],
];
$calc = [
's' => [1, 'second'],
'm' => [60, 'minute'],
'h' => [60 * 60, 'hour'],
'd' => [60 * 60 * 24, 'day'],
'y' => [60 * 60 * 24 * 365, 'year'],
];
$effectiveTimeUnit = $timeUnit;
if ($timeUnit == '')
{
$effectiveTimeUnit = 's';
for ($i = 0; $i < count($calcNum); $i++)
{
if ($clean <= $calcNum[$i][1])
{
$effectiveTimeUnit = $calcNum[$i][0];
$i = count($calcNum);
}
}
}
$timeDifference = floor($clean / $calc[$effectiveTimeUnit][0]);
$textSuffix = '';
if ($autoSuffix == true && ($currentTimestamp == time()))
{
if ($raw < 0)
{
$textSuffix = ' from now';
}
else
{
$textSuffix = ' ago';
}
}
if ($referenceTimestamp != 0)
{
if ($timeDifference == 1)
{
return $timeDifference . ' ' . $calc[$effectiveTimeUnit][1] . ' ' . $textSuffix;
}
return $timeDifference . ' ' . $calc[$effectiveTimeUnit][1] . 's ' . $textSuffix;
}
return '(no reference timestamp was provided).';
}
}