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,338 @@
<?php
/**
* @package FOF
* @copyright Copyright (c)2010-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
// Do not put the JEXEC or die check on this file
/**
* FOF-powered Joomla! CLI application implementation.
*
* Get all the power of Joomla in CLI without all the awkward decisions which make CLI scripts fail on many common,
* commercial hosting environments. We've been doing that in our software before Joomla got CLI support. We know of all
* the pitfalls and this little gem here will work around most of them (or at least fail gracefully).
*
* Your CLI script must begin with the following boilerplate code:
*
* // Boilerplate -- START
* define('_JEXEC', 1);
*
* foreach ([__DIR__, getcwd()] as $curdir)
* {
* if (file_exists($curdir . '/defines.php'))
* {
* define('JPATH_BASE', realpath($curdir . '/..'));
* require_once $curdir . '/defines.php';
*
* break;
* }
*
* if (file_exists($curdir . '/../includes/defines.php'))
* {
* define('JPATH_BASE', realpath($curdir . '/..'));
* require_once $curdir . '/../includes/defines.php';
*
* break;
* }
* }
*
* defined('JPATH_LIBRARIES') || die ('This script must be placed in or run from the cli folder of your site.');
*
* require_once JPATH_LIBRARIES . '/fof40/Cli/Application.php';
* // Boilerplate -- END
*
* Create a class which extends FOFCliApplication and implements doExecute, e.g.
*
* // Class definition -- START
* class YourClassName extends FOFCliApplication
* {
* protected function doExecute()
* {
* // Do something useful
* }
* }
* // Class definition -- END
*
* Finally, execute your script with:
*
* // Execute script -- START
* FOFCliApplication::getInstance('YourClassName')->execute();
* // Execute script -- END
*
* You can optionally define $minphp before the boilerplate code to enforce a different minimum PHP version.
*/
// Abort immediately when this file is executed from a web SAPI
if (array_key_exists('REQUEST_METHOD', $_SERVER))
{
die('This is a command line script. You are not allowed to access it over the web.');
}
// Work around some badly configured servers which print out notices
if (function_exists('error_reporting'))
{
$oldLevel = error_reporting(E_ERROR | E_NOTICE | E_DEPRECATED);
}
// Minimum PHP version check
if (!isset($minphp))
{
$minphp = '5.6.0';
}
if (version_compare(PHP_VERSION, $minphp, 'lt'))
{
require_once __DIR__ . '/wrong_php.php';
die;
}
// Required by scripts written for old Joomla! versions.
define('DS', DIRECTORY_SEPARATOR);
/**
* Timezone fix
*
* This piece of code was originally put here because some PHP 5.3 servers forgot to declare a default timezone.
* Unfortunately it's still required because some hosts STILL forget to provide a timezone in their php.ini files or,
* worse, use invalid timezone names.
*/
if (function_exists('date_default_timezone_get') && function_exists('date_default_timezone_set'))
{
$serverTimezone = @date_default_timezone_get();
// Do I have no timezone set?
if (empty($serverTimezone) || !is_string($serverTimezone))
{
$serverTimezone = 'UTC';
}
// Do I have an invalid timezone?
try
{
$testTimeZone = new DateTimeZone($serverTimezone);
}
catch (\Exception $e)
{
$serverTimezone = 'UTC';
}
// Set the default timezone to a correct thing
@date_default_timezone_set($serverTimezone);
}
// This is not necessary if you have used the boilerplate code.
if (!isset($curdir) && !defined('JPATH_ROOT'))
{
foreach ([__DIR__ . '/../../../cli', getcwd()] as $curdir)
{
if (file_exists($curdir . '/defines.php'))
{
define('JPATH_BASE', realpath($curdir . '/..'));
require_once $curdir . '/defines.php';
break;
}
if (file_exists($curdir . '/../includes/defines.php'))
{
define('JPATH_BASE', realpath($curdir . '/..'));
require_once $curdir . '/../includes/defines.php';
break;
}
}
defined('JPATH_LIBRARIES') || die ('This script must be placed in or run from the cli folder of your site.');
}
// Restore the error reporting before importing Joomla core code
if (function_exists('error_reporting'))
{
error_reporting($oldLevel);
}
// Awkward Joomla version detection before we can actually load Joomla! itself
$joomlaMajorVersion = 3;
$joomlaMinorVersion = 0;
$jVersionFile = JPATH_LIBRARIES . '/src/Version.php';
if ($versionFileContents = @file_get_contents($jVersionFile))
{
preg_match("/MAJOR_VERSION\s*=\s*(\d*)\s*;/", $versionFileContents, $versionMatches);
$joomlaMajorVersion = (int) $versionMatches[1];
preg_match("/MINOR_VERSION\s*=\s*(\d*)\s*;/", $versionFileContents, $versionMatches);
$joomlaMinorVersion = (int) $versionMatches[1];
}
// Load the Trait files
include_once __DIR__ . '/Traits/CGIModeAware.php';
include_once __DIR__ . '/Traits/CustomOptionsAware.php';
include_once __DIR__ . '/Traits/JoomlaConfigAware.php';
include_once __DIR__ . '/Traits/MemStatsAware.php';
include_once __DIR__ . '/Traits/MessageAware.php';
include_once __DIR__ . '/Traits/TimeAgoAware.php';
// The actual implementation of the CliApplication depends on the Joomla version we're running under
switch ($joomlaMajorVersion)
{
case 3:
default:
require_once __DIR__ . '/Joomla3.php';
abstract class FOFApplicationCLI extends FOFCliApplicationJoomla3
{
}
;
break;
case 4:
require_once __DIR__ . '/Joomla4.php';
abstract class FOFApplicationCLI extends FOFCliApplicationJoomla4
{
}
;
break;
}
/**
* A default exception handler. Catches all unhandled exceptions, displays debug information about them and sets the
* error level to 254.
*
* @param Throwable $ex The Exception / Error being handled
*/
function FOFCliExceptionHandler($ex)
{
echo "\n\n";
echo "********** ERROR! **********\n\n";
echo $ex->getMessage();
echo "\n\nTechnical information:\n\n";
echo "Code: " . $ex->getCode() . "\n";
echo "File: " . $ex->getFile() . "\n";
echo "Line: " . $ex->getLine() . "\n";
echo "\nStack Trace:\n\n" . $ex->getTraceAsString();
echo "\n\n";
exit(254);
}
/**
* Timeout handler
*
* This function is registered as a shutdown script. If a catchable timeout occurs it will detect it and print a helpful
* error message instead of just dying cold. The error level is set to 253 in this case.
*
* @return void
*/
function FOFCliTimeoutHandler()
{
$connection_status = connection_status();
if ($connection_status == 0)
{
// Normal script termination, do not report an error.
return;
}
echo "\n\n";
echo "********** ERROR! **********\n\n";
if ($connection_status == 1)
{
echo <<< END
The process was aborted on user's request.
This usually means that you pressed CTRL-C to terminate the script (if you're
running it from a terminal / SSH session), or that your host's CRON daemon
aborted the execution of this script.
If you are running this script through a CRON job and saw this message, please
contact your host and request an increase in the timeout limit for CRON jobs.
Moreover you need to ask them to increase the max_execution_time in the
php.ini file or, even better, set it to 0.
END;
}
else
{
echo <<< END
This script has timed out. As a result, the process has FAILED to complete.
Your host applies a maximum execution time for CRON jobs which is too low for
this script to work properly. Please contact your host and request an increase
in the timeout limit for CRON jobs. Moreover you need to ask them to increase
the max_execution_time in the php.ini file or, even better, set it to 0.
END;
if (!function_exists('php_ini_loaded_file'))
{
echo "\n\n";
return;
}
$ini_location = php_ini_loaded_file();
echo <<<END
The php.ini file your host will need to modify is located at:
$ini_location
Info for the host: the location above is reported by PHP's php_ini_loaded_file() method.
END;
echo "\n\n";
exit(253);
}
}
/**
* Error handler. It tries to catch fatal errors and report them in a meaningful way. Obviously it only works for
* catchable fatal errors. It sets the error level to 252.
*
* IMPORTANT! Under PHP 7 the default exception handler will be called instead, including when there is a non-catchable
* fatal error.
*
* @param int $errno Error number
* @param string $errstr Error string, tells us what went wrong
* @param string $errfile Full path to file where the error occurred
* @param int $errline Line number where the error occurred
*
* @return void
*/
function FOFCliErrorHandler($errno, $errstr, $errfile, $errline)
{
switch ($errno)
{
case E_ERROR:
case E_USER_ERROR:
echo "\n\n";
echo "********** ERROR! **********\n\n";
echo "PHP Fatal Error: $errstr";
echo "\n\nTechnical information:\n\n";
echo "File: " . $errfile . "\n";
echo "Line: " . $errline . "\n";
echo "\nStack Trace:\n\n" . debug_backtrace();
echo "\n\n";
exit(252);
break;
default:
break;
}
}
/**
* Custom default handlers for otherwise unhandled exceptions and PHP catchable errors.
*
* Moreover, we register a shutdown function to catch timeouts and SIGTERM signals, because some hosts *are* monsters.
*/
set_exception_handler('FOFCliExceptionHandler');
set_error_handler('FOFCliErrorHandler', E_ERROR | E_USER_ERROR);
register_shutdown_function('FOFCliTimeoutHandler');

View File

@ -0,0 +1,134 @@
<?php
/**
* @package FOF
* @copyright Copyright (c)2010-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
// Do not put the JEXEC or die check on this file
use FOF40\Cli\Traits\CGIModeAware;
use FOF40\Cli\Traits\CustomOptionsAware;
use FOF40\Cli\Traits\JoomlaConfigAware;
use FOF40\Cli\Traits\MemStatsAware;
use FOF40\Cli\Traits\MessageAware;
use FOF40\Cli\Traits\TimeAgoAware;
use FOF40\Utils\CliSessionHandler;
use Joomla\CMS\Application\CliApplication;
use Joomla\CMS\Input\Cli;
// Load the legacy Joomla! include files (Joomla! 3 only)
include_once JPATH_LIBRARIES . '/import.legacy.php';
// Load the CMS import file if it exists (newer Joomla! 3 versions and Joomla! 4)
$cmsImportFilePath = JPATH_LIBRARIES . '/cms.php';
if (@file_exists($cmsImportFilePath))
{
@include_once $cmsImportFilePath;
}
/**
* Base class for a Joomla! command line application. Adapted from JCli / JApplicationCli
*/
abstract class FOFCliApplicationJoomla3 extends CliApplication
{
use CGIModeAware, CustomOptionsAware, JoomlaConfigAware, MemStatsAware, MessageAware, TimeAgoAware;
private $allowedToClose = false;
public static function getInstance($name = null)
{
// Load the Joomla global configuration in JFactory. This must happen BEFORE loading FOF.
JFactory::getConfig(JPATH_CONFIGURATION . '/configuration.php');
// Load FOF
if (!defined('FOF40_INCLUDED') && !@include_once(JPATH_LIBRARIES . '/fof40/include.php'))
{
throw new RuntimeException('Cannot load FOF', 500);
}
// Create a CLI-specific session
JFactory::$session = JSession::getInstance('none', [
'expire' => 84400,
], new CliSessionHandler());
$instance = parent::getInstance($name);
JFactory::$application = $instance;
return $instance;
}
public function __construct(Cli $input = null, \Joomla\Registry\Registry $config = null, \JEventDispatcher $dispatcher = null)
{
// Some servers only provide a CGI executable. While not ideal for running CLI applications we can make do.
$this->detectAndWorkAroundCGIMode();
// Initialize custom options handling which is a bit more straightforward than Input\Cli.
$this->initialiseCustomOptions();
parent::__construct($input, $config, $dispatcher);
/**
* Allow the application to close.
*
* This is required to allow CliApplication to execute under CGI mode. The checks performed in the parent
* constructor will call close() if the application does not run pure CLI mode. However, some hosts only provide
* the PHP CGI binary for executing CLI scripts. While wrong it will work in most cases. By default close() will
* do nothing, thereby allowing the parent constructor to call it without a problem. Finally, we set this flag
* to true to allow doExecute() to call close() and actually close the application properly. Yeehaw!
*/
$this->allowedToClose = true;
}
/**
* Method to close the application.
*
* See the constructor for details on why it works the way it works.
*
* @param integer $code The exit code (optional; default is 0).
*
* @return void
*
* @codeCoverageIgnore
* @since 1.0
*/
public function close($code = 0)
{
// See the constructor for details
if (!$this->allowedToClose)
{
return;
}
exit($code);
}
/**
* Gets the name of the current running application.
*
* @return string The name of the application.
*
* @since 4.0.0
*/
public function getName()
{
return get_class($this);
}
/**
* Get the menu object.
*
* @param string $name The application name for the menu
* @param array $options An array of options to initialise the menu with
*
* @return \Joomla\CMS\Menu\AbstractMenu|null A AbstractMenu object or null if not set.
*
* @since 4.0.0
*/
public function getMenu($name = null, $options = [])
{
return null;
}
}

View File

@ -0,0 +1,196 @@
<?php
/**
* @package FOF
* @copyright Copyright (c)2010-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
// Do not put the JEXEC or die check on this file
use FOF40\Cli\Traits\CGIModeAware;
use FOF40\Cli\Traits\CustomOptionsAware;
use FOF40\Cli\Traits\JoomlaConfigAware;
use FOF40\Cli\Traits\MemStatsAware;
use FOF40\Cli\Traits\TimeAgoAware;
use Joomla\CMS\Application\CliApplication;
use Joomla\CMS\Application\ExtensionNamespaceMapper;
use Joomla\CMS\Factory;
use Joomla\Event\Dispatcher;
use Joomla\Registry\Registry;
use Joomla\Session\SessionInterface;
/**
* Load the legacy Joomla! include files
*
* Despite Joomla complaining about it with an E_DEPRECATED notice, if you use bootstrap.php instead of
* import.legacy.php you get an HTML error page (yes, under CLI!) which is kinda daft.
*/
if (function_exists('error_reporting'))
{
$oldErrorReporting = @error_reporting(E_ERROR | E_NOTICE | E_DEPRECATED);
}
include_once JPATH_LIBRARIES . '/import.legacy.php';
if (function_exists('error_reporting'))
{
@error_reporting($oldErrorReporting);
}
// Load the Framework (J4 beta 1 and later) or CMS import file (J4 a12 and lower)
$cmsImportFilePath = JPATH_BASE . '/includes/framework.php';
$cmsImportFilePathOld = JPATH_LIBRARIES . '/cms.php';
if (@file_exists($cmsImportFilePath))
{
@include_once $cmsImportFilePath;
// Boot the DI container
$container = \Joomla\CMS\Factory::getContainer();
/*
* Alias the session service keys to the CLI session service as that is the primary session backend for this application
*
* In addition to aliasing "common" service keys, we also create aliases for the PHP classes to ensure autowiring objects
* is supported. This includes aliases for aliased class names, and the keys for aliased class names should be considered
* deprecated to be removed when the class name alias is removed as well.
*/
$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');
}
elseif (@file_exists($cmsImportFilePathOld))
{
@include_once $cmsImportFilePathOld;
}
/**
* Base class for a Joomla! command line application. Adapted from JCli / JApplicationCli
*/
abstract class FOFCliApplicationJoomla4 extends CliApplication
{
use CGIModeAware, CustomOptionsAware, JoomlaConfigAware, MemStatsAware, TimeAgoAware, ExtensionNamespaceMapper;
private $allowedToClose = false;
public static function getInstance($name = null)
{
$instance = parent::getInstance($name);
Factory::$application = $instance;
/**
* Load FOF.
*
* In Joomla 4 this must happen after we have set up the application in the factory because Factory::getLanguage
* goes through the application object to retrieve the configuration.
*/
if (!defined('FOF40_INCLUDED') && !@include_once(JPATH_LIBRARIES . '/fof40/include.php'))
{
throw new RuntimeException('Cannot load FOF', 500);
}
return $instance;
}
public function __construct(\Joomla\Input\Input $input = null, Registry $config = null, \Joomla\CMS\Application\CLI\CliOutput $output = null, \Joomla\CMS\Application\CLI\CliInput $cliInput = null, \Joomla\Event\DispatcherInterface $dispatcher = null, \Joomla\DI\Container $container = null)
{
// Some servers only provide a CGI executable. While not ideal for running CLI applications we can make do.
$this->detectAndWorkAroundCGIMode();
// We need to tell Joomla to register its default namespace conventions
$this->createExtensionNamespaceMap();
// Initialize custom options handling which is a bit more straightforward than Input\Cli.
$this->initialiseCustomOptions();
// Default configuration: Joomla Global Configuration
if (empty($config))
{
$config = new Registry($this->fetchConfigurationData());
}
if (empty($dispatcher))
{
$dispatcher = new Dispatcher();
}
parent::__construct($input, $config, $output, $cliInput, $dispatcher, $container);
/**
* Allow the application to close.
*
* This is required to allow CliApplication to execute under CGI mode. The checks performed in the parent
* constructor will call close() if the application does not run pure CLI mode. However, some hosts only provide
* the PHP CGI binary for executing CLI scripts. While wrong it will work in most cases. By default close() will
* do nothing, thereby allowing the parent constructor to call it without a problem. Finally, we set this flag
* to true to allow doExecute() to call close() and actually close the application properly. Yeehaw!
*/
$this->allowedToClose = true;
}
/**
* Method to close the application.
*
* See the constructor for details on why it works the way it works.
*
* @param integer $code The exit code (optional; default is 0).
*
* @return void
*
* @codeCoverageIgnore
* @since 1.0
*/
public function close($code = 0)
{
// See the constructor for details
if (!$this->allowedToClose)
{
return;
}
exit($code);
}
/**
* Gets the name of the current running application.
*
* @return string The name of the application.
*
* @since 4.0.0
*/
public function getName()
{
return get_class($this);
}
/**
* Get the menu object.
*
* @param string $name The application name for the menu
* @param array $options An array of options to initialise the menu with
*
* @return \Joomla\CMS\Menu\AbstractMenu|null A AbstractMenu object or null if not set.
*
* @since 4.0.0
*/
public function getMenu($name = null, $options = [])
{
return null;
}
/**
* Method to get the application session object.
*
* @return SessionInterface The session object
*
* @since 4.0.0
*/
public function getSession()
{
return $this->getContainer()->get('session.cli');
}
}

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).';
}
}

View File

@ -0,0 +1,67 @@
<?php
/**
* @package FOF
* @copyright Copyright (c)2010-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
/** @var string $minphp */
if (!isset($minphp))
{
die;
}
?>
================================================================================
WARNING! Incompatible PHP version <?php echo PHP_VERSION ?> (required: <?php echo $minphp ?> or later)
================================================================================
This script must be run using PHP version <?php echo $minphp ?> or later. Your server is
currently using a much older version which would cause this script to crash. As
a result we have aborted execution of the script. Please contact your host and
ask them for the correct path to the PHP CLI binary for PHP <?php echo $minphp ?> or later, then
edit your CRON job and replace your current path to PHP with the one your host
gave you.
For your information, the current PHP version information is as follows.
PATH: <?php echo PHP_BINDIR ?>
VERSION: <?php echo PHP_VERSION ?>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
IMPORTANT!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PHP version numbers are NOT decimals! Trailing zeros do matter. For example,
PHP 5.3.28 is twenty four versions newer (greater than) than PHP 5.3.4.
Please consult https://www.akeeba.com/how-do-version-numbers-work.html
Further clarifications:
1. There is no possible way that you are receiving this message in error. We
are using the PHP_VERSION constant to detect the PHP version you are
currently using. This is what PHP itself reports as its own version. It
simply cannot lie.
2. Even though your *site* may be running in a higher PHP version that the one
reported above, your CRON scripts will most likely not be running under it.
This has to do with the fact that your site DOES NOT run under the command
line and there are different executable files (binaries) for the web and
command line versions of PHP.
3. Please note that we cannot provide support about this error as the solution
depends only on your server setup. The only people who know how your server
is set up are your host's technicians. Therefore we can only advise you to
contact your host and request them the correct path to the PHP CLI binary.
Let us stress out that only your host knows and can give this information
to you.
4. The latest published versions of PHP can be found at http://www.php.net/
Any older version is considered insecure and must not be used on a
production site. If your server uses a much older version of PHP than those
published in the URL above please notify your host that their servers are
insecure and in need of an update.
This script will now terminate. Goodbye.