primo commit
This commit is contained in:
718
libraries/f0f/dispatcher/dispatcher.php
Normal file
718
libraries/f0f/dispatcher/dispatcher.php
Normal file
@ -0,0 +1,718 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FrameworkOnFramework
|
||||
* @subpackage dispatcher
|
||||
* @copyright Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
// Protect from unauthorized access
|
||||
defined('F0F_INCLUDED') or die;
|
||||
|
||||
/**
|
||||
* FrameworkOnFramework dispatcher class
|
||||
*
|
||||
* FrameworkOnFramework is a set of classes which extend Joomla! 1.5 and later's
|
||||
* MVC framework with features making maintaining complex software much easier,
|
||||
* without tedious repetitive copying of the same code over and over again.
|
||||
*
|
||||
* @package FrameworkOnFramework
|
||||
* @since 1.0
|
||||
*/
|
||||
class F0FDispatcher extends F0FUtilsObject
|
||||
{
|
||||
/** @var array Configuration variables */
|
||||
protected $config = array();
|
||||
|
||||
/** @var F0FInput Input variables */
|
||||
protected $input = array();
|
||||
|
||||
/** @var string The name of the default view, in case none is specified */
|
||||
public $defaultView = 'cpanel';
|
||||
|
||||
// Variables for F0F's transparent user authentication. You can override them
|
||||
// in your Dispatcher's __construct() method.
|
||||
|
||||
/** @var int The Time Step for the TOTP used in F0F's transparent user authentication */
|
||||
protected $fofAuth_timeStep = 6;
|
||||
|
||||
/** @var string The key for the TOTP, Base32 encoded (watch out; Base32, NOT Base64!) */
|
||||
protected $fofAuth_Key = null;
|
||||
|
||||
/** @var array Which formats to be handled by transparent authentication */
|
||||
protected $fofAuth_Formats = array('json', 'csv', 'xml', 'raw');
|
||||
|
||||
/**
|
||||
* Should I logout the transparently authenticated user on logout?
|
||||
* Recommended to leave it on in order to avoid crashing the sessions table.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $fofAuth_LogoutOnReturn = true;
|
||||
|
||||
/** @var array Which methods to use to fetch authentication credentials and in which order */
|
||||
protected $fofAuth_AuthMethods = array(
|
||||
/* HTTP Basic Authentication using encrypted information protected
|
||||
* with a TOTP (the username must be "_fof_auth") */
|
||||
'HTTPBasicAuth_TOTP',
|
||||
/* Encrypted information protected with a TOTP passed in the
|
||||
* _fofauthentication query string parameter */
|
||||
'QueryString_TOTP',
|
||||
/* HTTP Basic Authentication using a username and password pair in plain text */
|
||||
'HTTPBasicAuth_Plaintext',
|
||||
/* Plaintext, JSON-encoded username and password pair passed in the
|
||||
* _fofauthentication query string parameter */
|
||||
'QueryString_Plaintext',
|
||||
/* Plaintext username and password in the _fofauthentication_username
|
||||
* and _fofauthentication_username query string parameters */
|
||||
'SplitQueryString_Plaintext',
|
||||
);
|
||||
|
||||
/** @var bool Did we successfully and transparently logged in a user? */
|
||||
private $_fofAuth_isLoggedIn = false;
|
||||
|
||||
/** @var string The calculated encryption key for the _TOTP methods, used if we have to encrypt the reply */
|
||||
private $_fofAuth_CryptoKey = '';
|
||||
|
||||
/**
|
||||
* Get a static (Singleton) instance of a particular Dispatcher
|
||||
*
|
||||
* @param string $option The component name
|
||||
* @param string $view The View name
|
||||
* @param array $config Configuration data
|
||||
*
|
||||
* @staticvar array $instances Holds the array of Dispatchers F0F knows about
|
||||
*
|
||||
* @return F0FDispatcher
|
||||
*/
|
||||
public static function &getAnInstance($option = null, $view = null, $config = array())
|
||||
{
|
||||
static $instances = array();
|
||||
|
||||
$hash = $option . $view;
|
||||
|
||||
if (!array_key_exists($hash, $instances))
|
||||
{
|
||||
$instances[$hash] = self::getTmpInstance($option, $view, $config);
|
||||
}
|
||||
|
||||
return $instances[$hash];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a temporary instance of a Dispatcher
|
||||
*
|
||||
* @param string $option The component name
|
||||
* @param string $view The View name
|
||||
* @param array $config Configuration data
|
||||
*
|
||||
* @return F0FDispatcher
|
||||
*/
|
||||
public static function &getTmpInstance($option = null, $view = null, $config = array())
|
||||
{
|
||||
if (array_key_exists('input', $config))
|
||||
{
|
||||
if ($config['input'] instanceof F0FInput)
|
||||
{
|
||||
$input = $config['input'];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!is_array($config['input']))
|
||||
{
|
||||
$config['input'] = (array) $config['input'];
|
||||
}
|
||||
|
||||
$config['input'] = array_merge($_REQUEST, $config['input']);
|
||||
$input = new F0FInput($config['input']);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$input = new F0FInput;
|
||||
}
|
||||
|
||||
$config['option'] = !is_null($option) ? $option : $input->getCmd('option', 'com_foobar');
|
||||
$config['view'] = !is_null($view) ? $view : $input->getCmd('view', '');
|
||||
|
||||
$input->set('option', $config['option']);
|
||||
$input->set('view', $config['view']);
|
||||
|
||||
$config['input'] = $input;
|
||||
|
||||
$className = ucfirst(str_replace('com_', '', $config['option'])) . 'Dispatcher';
|
||||
|
||||
if (!class_exists($className))
|
||||
{
|
||||
$componentPaths = F0FPlatform::getInstance()->getComponentBaseDirs($config['option']);
|
||||
|
||||
$searchPaths = array(
|
||||
$componentPaths['main'],
|
||||
$componentPaths['main'] . '/dispatchers',
|
||||
$componentPaths['admin'],
|
||||
$componentPaths['admin'] . '/dispatchers'
|
||||
);
|
||||
|
||||
if (array_key_exists('searchpath', $config))
|
||||
{
|
||||
array_unshift($searchPaths, $config['searchpath']);
|
||||
}
|
||||
|
||||
$filesystem = F0FPlatform::getInstance()->getIntegrationObject('filesystem');
|
||||
|
||||
$path = $filesystem->pathFind(
|
||||
$searchPaths, 'dispatcher.php'
|
||||
);
|
||||
|
||||
if ($path)
|
||||
{
|
||||
require_once $path;
|
||||
}
|
||||
}
|
||||
|
||||
if (!class_exists($className))
|
||||
{
|
||||
$className = 'F0FDispatcher';
|
||||
}
|
||||
|
||||
$instance = new $className($config);
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public constructor
|
||||
*
|
||||
* @param array $config The configuration variables
|
||||
*/
|
||||
public function __construct($config = array())
|
||||
{
|
||||
// Cache the config
|
||||
$this->config = $config;
|
||||
|
||||
// Get the input for this MVC triad
|
||||
if (array_key_exists('input', $config))
|
||||
{
|
||||
$this->input = $config['input'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->input = new F0FInput;
|
||||
}
|
||||
|
||||
// Get the default values for the component name
|
||||
$this->component = $this->input->getCmd('option', 'com_foobar');
|
||||
|
||||
// Load the component's fof.xml configuration file
|
||||
$configProvider = new F0FConfigProvider;
|
||||
$this->defaultView = $configProvider->get($this->component . '.dispatcher.default_view', $this->defaultView);
|
||||
|
||||
// Get the default values for the view name
|
||||
$this->view = $this->input->getCmd('view', null);
|
||||
|
||||
if (empty($this->view))
|
||||
{
|
||||
// Do we have a task formatted as controller.task?
|
||||
$task = $this->input->getCmd('task', '');
|
||||
|
||||
if (!empty($task) && (strstr($task, '.') !== false))
|
||||
{
|
||||
list($this->view, $task) = explode('.', $task, 2);
|
||||
$this->input->set('task', $task);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->view))
|
||||
{
|
||||
$this->view = $this->defaultView;
|
||||
}
|
||||
|
||||
$this->layout = $this->input->getCmd('layout', null);
|
||||
|
||||
// Overrides from the config
|
||||
if (array_key_exists('option', $config))
|
||||
{
|
||||
$this->component = $config['option'];
|
||||
}
|
||||
|
||||
if (array_key_exists('view', $config))
|
||||
{
|
||||
$this->view = empty($config['view']) ? $this->view : $config['view'];
|
||||
}
|
||||
|
||||
if (array_key_exists('layout', $config))
|
||||
{
|
||||
$this->layout = $config['layout'];
|
||||
}
|
||||
|
||||
$this->input->set('option', $this->component);
|
||||
$this->input->set('view', $this->view);
|
||||
$this->input->set('layout', $this->layout);
|
||||
|
||||
if (array_key_exists('authTimeStep', $config))
|
||||
{
|
||||
$this->fofAuth_timeStep = empty($config['authTimeStep']) ? 6 : $config['authTimeStep'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main code of the Dispatcher. It spawns the necessary controller and
|
||||
* runs it.
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return void|Exception
|
||||
*/
|
||||
public function dispatch()
|
||||
{
|
||||
$platform = F0FPlatform::getInstance();
|
||||
|
||||
if (!$platform->authorizeAdmin($this->input->getCmd('option', 'com_foobar')))
|
||||
{
|
||||
return $platform->raiseError(403, JText::_('JLIB_APPLICATION_ERROR_ACCESS_FORBIDDEN'));
|
||||
}
|
||||
|
||||
$this->transparentAuthentication();
|
||||
|
||||
// Merge English and local translations
|
||||
$platform->loadTranslations($this->component);
|
||||
|
||||
$canDispatch = true;
|
||||
|
||||
if ($platform->isCli())
|
||||
{
|
||||
$canDispatch = $canDispatch && $this->onBeforeDispatchCLI();
|
||||
}
|
||||
|
||||
$canDispatch = $canDispatch && $this->onBeforeDispatch();
|
||||
|
||||
if (!$canDispatch)
|
||||
{
|
||||
// We can set header only if we're not in CLI
|
||||
if(!$platform->isCli())
|
||||
{
|
||||
$platform->setHeader('Status', '403 Forbidden', true);
|
||||
}
|
||||
|
||||
return $platform->raiseError(403, JText::_('JLIB_APPLICATION_ERROR_ACCESS_FORBIDDEN'));
|
||||
}
|
||||
|
||||
// Get and execute the controller
|
||||
$option = $this->input->getCmd('option', 'com_foobar');
|
||||
$view = $this->input->getCmd('view', $this->defaultView);
|
||||
$task = $this->input->getCmd('task', null);
|
||||
|
||||
if (empty($task))
|
||||
{
|
||||
$task = $this->getTask($view);
|
||||
}
|
||||
|
||||
// Pluralise/sungularise the view name for typical tasks
|
||||
if (in_array($task, array('edit', 'add', 'read')))
|
||||
{
|
||||
$view = F0FInflector::singularize($view);
|
||||
}
|
||||
elseif (in_array($task, array('browse')))
|
||||
{
|
||||
$view = F0FInflector::pluralize($view);
|
||||
}
|
||||
|
||||
$this->input->set('view', $view);
|
||||
$this->input->set('task', $task);
|
||||
|
||||
$config = $this->config;
|
||||
$config['input'] = $this->input;
|
||||
|
||||
$controller = F0FController::getTmpInstance($option, $view, $config);
|
||||
$status = $controller->execute($task);
|
||||
|
||||
if (!$this->onAfterDispatch())
|
||||
{
|
||||
// We can set header only if we're not in CLI
|
||||
if(!$platform->isCli())
|
||||
{
|
||||
$platform->setHeader('Status', '403 Forbidden', true);
|
||||
}
|
||||
|
||||
return $platform->raiseError(403, JText::_('JLIB_APPLICATION_ERROR_ACCESS_FORBIDDEN'));
|
||||
}
|
||||
|
||||
$format = $this->input->get('format', 'html', 'cmd');
|
||||
$format = empty($format) ? 'html' : $format;
|
||||
|
||||
if ($controller->hasRedirect())
|
||||
{
|
||||
$controller->redirect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to guess the controller task to execute based on the view name and
|
||||
* the HTTP request method.
|
||||
*
|
||||
* @param string $view The name of the view
|
||||
*
|
||||
* @return string The best guess of the task to execute
|
||||
*/
|
||||
protected function getTask($view)
|
||||
{
|
||||
// Get a default task based on plural/singular view
|
||||
$request_task = $this->input->getCmd('task', null);
|
||||
$task = F0FInflector::isPlural($view) ? 'browse' : 'edit';
|
||||
|
||||
// Get a potential ID, we might need it later
|
||||
$id = $this->input->get('id', null, 'int');
|
||||
|
||||
if ($id == 0)
|
||||
{
|
||||
$ids = $this->input->get('ids', array(), 'array');
|
||||
|
||||
if (!empty($ids))
|
||||
{
|
||||
$id = array_shift($ids);
|
||||
}
|
||||
}
|
||||
|
||||
// Check the request method
|
||||
|
||||
if (!isset($_SERVER['REQUEST_METHOD']))
|
||||
{
|
||||
$_SERVER['REQUEST_METHOD'] = 'GET';
|
||||
}
|
||||
|
||||
$requestMethod = strtoupper($_SERVER['REQUEST_METHOD']);
|
||||
|
||||
switch ($requestMethod)
|
||||
{
|
||||
case 'POST':
|
||||
case 'PUT':
|
||||
if (!is_null($id))
|
||||
{
|
||||
$task = 'save';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'DELETE':
|
||||
if ($id != 0)
|
||||
{
|
||||
$task = 'delete';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'GET':
|
||||
default:
|
||||
// If it's an edit without an ID or ID=0, it's really an add
|
||||
if (($task == 'edit') && ($id == 0))
|
||||
{
|
||||
$task = 'add';
|
||||
}
|
||||
|
||||
// If it's an edit in the frontend, it's really a read
|
||||
elseif (($task == 'edit') && F0FPlatform::getInstance()->isFrontend())
|
||||
{
|
||||
$task = 'read';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes right before the dispatcher tries to instantiate and run the
|
||||
* controller.
|
||||
*
|
||||
* @return boolean Return false to abort
|
||||
*/
|
||||
public function onBeforeDispatch()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up some environment variables, so we can work as usually on CLI, too.
|
||||
*
|
||||
* @return boolean Return false to abort
|
||||
*/
|
||||
public function onBeforeDispatchCLI()
|
||||
{
|
||||
JLoader::import('joomla.environment.uri');
|
||||
JLoader::import('joomla.application.component.helper');
|
||||
|
||||
// Trick to create a valid url used by JURI
|
||||
$this->_originalPhpScript = '';
|
||||
|
||||
// We have no Application Helper (there is no Application!), so I have to define these constants manually
|
||||
$option = $this->input->get('option', '', 'cmd');
|
||||
|
||||
if ($option)
|
||||
{
|
||||
$componentPaths = F0FPlatform::getInstance()->getComponentBaseDirs($option);
|
||||
|
||||
if (!defined('JPATH_COMPONENT'))
|
||||
{
|
||||
define('JPATH_COMPONENT', $componentPaths['main']);
|
||||
}
|
||||
|
||||
if (!defined('JPATH_COMPONENT_SITE'))
|
||||
{
|
||||
define('JPATH_COMPONENT_SITE', $componentPaths['site']);
|
||||
}
|
||||
|
||||
if (!defined('JPATH_COMPONENT_ADMINISTRATOR'))
|
||||
{
|
||||
define('JPATH_COMPONENT_ADMINISTRATOR', $componentPaths['admin']);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes right after the dispatcher runs the controller.
|
||||
*
|
||||
* @return boolean Return false to abort
|
||||
*/
|
||||
public function onAfterDispatch()
|
||||
{
|
||||
// If we have to log out the user, please do so now
|
||||
if ($this->fofAuth_LogoutOnReturn && $this->_fofAuth_isLoggedIn)
|
||||
{
|
||||
F0FPlatform::getInstance()->logoutUser();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transparently authenticates a user
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function transparentAuthentication()
|
||||
{
|
||||
// Only run when there is no logged in user
|
||||
if (!F0FPlatform::getInstance()->getUser()->guest)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// @todo Check the format
|
||||
$format = $this->input->getCmd('format', 'html');
|
||||
|
||||
if (!in_array($format, $this->fofAuth_Formats))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->fofAuth_AuthMethods as $method)
|
||||
{
|
||||
// If we're already logged in, don't bother
|
||||
if ($this->_fofAuth_isLoggedIn)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// This will hold our authentication data array (username, password)
|
||||
$authInfo = null;
|
||||
|
||||
switch ($method)
|
||||
{
|
||||
case 'HTTPBasicAuth_TOTP':
|
||||
|
||||
if (empty($this->fofAuth_Key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($_SERVER['PHP_AUTH_USER']))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($_SERVER['PHP_AUTH_PW']))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($_SERVER['PHP_AUTH_USER'] != '_fof_auth')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$encryptedData = $_SERVER['PHP_AUTH_PW'];
|
||||
|
||||
$authInfo = $this->_decryptWithTOTP($encryptedData);
|
||||
break;
|
||||
|
||||
case 'QueryString_TOTP':
|
||||
$encryptedData = $this->input->get('_fofauthentication', '', 'raw');
|
||||
|
||||
if (empty($encryptedData))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$authInfo = $this->_decryptWithTOTP($encryptedData);
|
||||
break;
|
||||
|
||||
case 'HTTPBasicAuth_Plaintext':
|
||||
if (!isset($_SERVER['PHP_AUTH_USER']))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($_SERVER['PHP_AUTH_PW']))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$authInfo = array(
|
||||
'username' => $_SERVER['PHP_AUTH_USER'],
|
||||
'password' => $_SERVER['PHP_AUTH_PW']
|
||||
);
|
||||
break;
|
||||
|
||||
case 'QueryString_Plaintext':
|
||||
$jsonencoded = $this->input->get('_fofauthentication', '', 'raw');
|
||||
|
||||
if (empty($jsonencoded))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$authInfo = json_decode($jsonencoded, true);
|
||||
|
||||
if (!is_array($authInfo))
|
||||
{
|
||||
$authInfo = null;
|
||||
}
|
||||
elseif (!array_key_exists('username', $authInfo) || !array_key_exists('password', $authInfo))
|
||||
{
|
||||
$authInfo = null;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'SplitQueryString_Plaintext':
|
||||
$authInfo = array(
|
||||
'username' => $this->input->get('_fofauthentication_username', '', 'raw'),
|
||||
'password' => $this->input->get('_fofauthentication_password', '', 'raw'),
|
||||
);
|
||||
|
||||
if (empty($authInfo['username']))
|
||||
{
|
||||
$authInfo = null;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// No point trying unless we have a username and password
|
||||
if (!is_array($authInfo))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->_fofAuth_isLoggedIn = F0FPlatform::getInstance()->loginUser($authInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a transparent authentication message using a TOTP
|
||||
*
|
||||
* @param string $encryptedData The encrypted data
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @return array The decrypted data
|
||||
*/
|
||||
private function _decryptWithTOTP($encryptedData)
|
||||
{
|
||||
if (empty($this->fofAuth_Key))
|
||||
{
|
||||
$this->_fofAuth_CryptoKey = null;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$totp = new F0FEncryptTotp($this->fofAuth_timeStep);
|
||||
$period = $totp->getPeriod();
|
||||
$period--;
|
||||
|
||||
for ($i = 0; $i <= 2; $i++)
|
||||
{
|
||||
$time = ($period + $i) * $this->fofAuth_timeStep;
|
||||
$otp = $totp->getCode($this->fofAuth_Key, $time);
|
||||
$this->_fofAuth_CryptoKey = hash('sha256', $this->fofAuth_Key . $otp);
|
||||
|
||||
$aes = new F0FEncryptAes($this->_fofAuth_CryptoKey);
|
||||
$ret = $aes->decryptString($encryptedData);
|
||||
$ret = rtrim($ret, "\000");
|
||||
|
||||
$ret = json_decode($ret, true);
|
||||
|
||||
if (!is_array($ret))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!array_key_exists('username', $ret))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!array_key_exists('password', $ret))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Successful decryption!
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// Obviously if we're here we could not decrypt anything. Bail out.
|
||||
$this->_fofAuth_CryptoKey = null;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a decryption key for use with the TOTP decryption method
|
||||
*
|
||||
* @param integer $time The timestamp used for TOTP calculation, leave empty to use current timestamp
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @return string THe encryption key
|
||||
*/
|
||||
private function _createDecryptionKey($time = null)
|
||||
{
|
||||
$totp = new F0FEncryptTotp($this->fofAuth_timeStep);
|
||||
$otp = $totp->getCode($this->fofAuth_Key, $time);
|
||||
|
||||
$key = hash('sha256', $this->fofAuth_Key . $otp);
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function to detect if we're running in a CLI environment and we're admin
|
||||
*
|
||||
* @return array isCLI and isAdmin. It's not an associtive array, so we can use list.
|
||||
*/
|
||||
public static function isCliAdmin()
|
||||
{
|
||||
static $isCLI = null;
|
||||
static $isAdmin = null;
|
||||
|
||||
if (is_null($isCLI) && is_null($isAdmin))
|
||||
{
|
||||
$isCLI = F0FPlatform::getInstance()->isCli();
|
||||
$isAdmin = F0FPlatform::getInstance()->isBackend();
|
||||
}
|
||||
|
||||
return array($isCLI, $isAdmin);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user