Файловый менеджер - Редактировать - /home/wuectly/www/03cbe/application.tar
Назад
web/router/base.php 0000604 00000011052 15245571671 0010274 0 ustar 00 <?php /** * @package Joomla.Platform * @subpackage Application * * @copyright (C) 2012 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * Basic Web application router class for the Joomla Platform. * * @since 3.0 * @deprecated 4.0 Use the `joomla/router` package via Composer instead */ class JApplicationWebRouterBase extends JApplicationWebRouter { /** * @var array An array of rules, each rule being an associative array('regex'=> $regex, 'vars' => $vars, 'controller' => $controller) * for routing the request. * @since 3.0 */ protected $maps = array(); /** * Add a route map to the router. If the pattern already exists it will be overwritten. * * @param string $pattern The route pattern to use for matching. * @param string $controller The controller name to map to the given pattern. * * @return JApplicationWebRouter This object for method chaining. * * @since 3.0 */ public function addMap($pattern, $controller) { // Sanitize and explode the pattern. $pattern = explode('/', trim(parse_url((string) $pattern, PHP_URL_PATH), ' /')); // Prepare the route variables $vars = array(); // Initialize regular expression $regex = array(); // Loop on each segment foreach ($pattern as $segment) { // Match a splat with no variable. if ($segment == '*') { $regex[] = '.*'; } // Match a splat and capture the data to a named variable. elseif ($segment[0] == '*') { $vars[] = substr($segment, 1); $regex[] = '(.*)'; } // Match an escaped splat segment. elseif ($segment[0] == '\\' && $segment[1] == '*') { $regex[] = '\*' . preg_quote(substr($segment, 2)); } // Match an unnamed variable without capture. elseif ($segment == ':') { $regex[] = '[^/]*'; } // Match a named variable and capture the data. elseif ($segment[0] == ':') { $vars[] = substr($segment, 1); $regex[] = '([^/]*)'; } // Match a segment with an escaped variable character prefix. elseif ($segment[0] == '\\' && $segment[1] == ':') { $regex[] = preg_quote(substr($segment, 1)); } // Match the standard segment. else { $regex[] = preg_quote($segment); } } $this->maps[] = array( 'regex' => chr(1) . '^' . implode('/', $regex) . '$' . chr(1), 'vars' => $vars, 'controller' => (string) $controller, ); return $this; } /** * Add a route map to the router. If the pattern already exists it will be overwritten. * * @param array $maps A list of route maps to add to the router as $pattern => $controller. * * @return JApplicationWebRouter This object for method chaining. * * @since 3.0 */ public function addMaps($maps) { foreach ($maps as $pattern => $controller) { $this->addMap($pattern, $controller); } return $this; } /** * Parse the given route and return the name of a controller mapped to the given route. * * @param string $route The route string for which to find and execute a controller. * * @return string The controller name for the given route excluding prefix. * * @since 3.0 * @throws InvalidArgumentException */ protected function parseRoute($route) { $controller = false; // Trim the query string off. $route = preg_replace('/([^?]*).*/u', '\1', $route); // Sanitize and explode the route. $route = trim(parse_url($route, PHP_URL_PATH), ' /'); // If the route is empty then simply return the default route. No parsing necessary. if ($route == '') { return $this->default; } // Iterate through all of the known route maps looking for a match. foreach ($this->maps as $rule) { if (preg_match($rule['regex'], $route, $matches)) { // If we have gotten this far then we have a positive match. $controller = $rule['controller']; // Time to set the input variables. // We are only going to set them if they don't already exist to avoid overwriting things. foreach ($rule['vars'] as $i => $var) { $this->input->def($var, $matches[$i + 1]); // Don't forget to do an explicit set on the GET superglobal. $this->input->get->def($var, $matches[$i + 1]); } $this->input->def('_rawRoute', $route); break; } } // We were unable to find a route match for the request. Panic. if (!$controller) { throw new InvalidArgumentException(sprintf('Unable to handle request for route `%s`.', $route), 404); } return $controller; } } web/router/rest.php 0000604 00000007001 15245571671 0010336 0 ustar 00 <?php /** * @package Joomla.Platform * @subpackage Application * * @copyright (C) 2012 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * RESTful Web application router class for the Joomla Platform. * * @since 3.0 * @deprecated 4.0 Use the `joomla/router` package via Composer instead */ class JApplicationWebRouterRest extends JApplicationWebRouterBase { /** * @var boolean A boolean allowing to pass _method as parameter in POST requests * @since 3.0 */ protected $methodInPostRequest = false; /** * @var array An array of HTTP Method => controller suffix pairs for routing the request. * @since 3.0 */ protected $suffixMap = array( 'GET' => 'Get', 'POST' => 'Create', 'PUT' => 'Update', 'PATCH' => 'Update', 'DELETE' => 'Delete', 'HEAD' => 'Head', 'OPTIONS' => 'Options', ); /** * Find and execute the appropriate controller based on a given route. * * @param string $route The route string for which to find and execute a controller. * * @return void * * @since 3.0 * @throws InvalidArgumentException * @throws RuntimeException */ public function execute($route) { // Get the controller name based on the route patterns and requested route. $name = $this->parseRoute($route); // Append the HTTP method based suffix. $name .= $this->fetchControllerSuffix(); // Get the controller object by name. $controller = $this->fetchController($name); // Execute the controller. $controller->execute(); } /** * Set a controller class suffix for a given HTTP method. * * @param string $method The HTTP method for which to set the class suffix. * @param string $suffix The class suffix to use when fetching the controller name for a given request. * * @return JApplicationWebRouter This object for method chaining. * * @since 3.0 */ public function setHttpMethodSuffix($method, $suffix) { $this->suffixMap[strtoupper((string) $method)] = (string) $suffix; return $this; } /** * Set to allow or not method in POST request * * @param boolean $value A boolean to allow or not method in POST request * * @return void * * @since 3.0 */ public function setMethodInPostRequest($value) { $this->methodInPostRequest = $value; } /** * Get the property to allow or not method in POST request * * @return boolean * * @since 3.0 */ public function isMethodInPostRequest() { return $this->methodInPostRequest; } /** * Get the controller class suffix string. * * @return string * * @since 3.0 * @throws RuntimeException */ protected function fetchControllerSuffix() { // Validate that we have a map to handle the given HTTP method. if (!isset($this->suffixMap[$this->input->getMethod()])) { throw new RuntimeException(sprintf('Unable to support the HTTP method `%s`.', $this->input->getMethod()), 404); } // Check if request method is POST if ($this->methodInPostRequest == true && strcmp(strtoupper($this->input->server->getMethod()), 'POST') === 0) { // Get the method from input $postMethod = $this->input->get->getWord('_method'); // Validate that we have a map to handle the given HTTP method from input if ($postMethod && isset($this->suffixMap[strtoupper($postMethod)])) { return ucfirst($this->suffixMap[strtoupper($postMethod)]); } } return ucfirst($this->suffixMap[$this->input->getMethod()]); } } web/router.php 0000604 00000007547 15245571671 0007400 0 ustar 00 <?php /** * @package Joomla.Platform * @subpackage Application * * @copyright (C) 2012 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * Class to define an abstract Web application router. * * @since 3.0 * @deprecated 4.0 Use the `joomla/router` package via Composer instead */ abstract class JApplicationWebRouter { /** * @var JApplicationWeb The web application on whose behalf we are routing the request. * @since 3.0 */ protected $app; /** * @var string The default page controller name for an empty route. * @since 3.0 */ protected $default; /** * @var string Controller class name prefix for creating controller objects by name. * @since 3.0 */ protected $controllerPrefix; /** * @var JInput An input object from which to derive the route. * @since 3.0 */ protected $input; /** * Constructor. * * @param JApplicationWeb $app The web application on whose behalf we are routing the request. * @param JInput $input An optional input object from which to derive the route. If none * is given than the input from the application object will be used. * * @since 3.0 */ public function __construct(JApplicationWeb $app, JInput $input = null) { $this->app = $app; $this->input = ($input === null) ? $this->app->input : $input; } /** * Find and execute the appropriate controller based on a given route. * * @param string $route The route string for which to find and execute a controller. * * @return mixed The return value of the controller executed * * @since 3.0 * @throws InvalidArgumentException * @throws RuntimeException */ public function execute($route) { // Get the controller name based on the route patterns and requested route. $name = $this->parseRoute($route); // Get the controller object by name. $controller = $this->fetchController($name); // Execute the controller. return $controller->execute(); } /** * Set the controller name prefix. * * @param string $prefix Controller class name prefix for creating controller objects by name. * * @return JApplicationWebRouter This object for method chaining. * * @since 3.0 */ public function setControllerPrefix($prefix) { $this->controllerPrefix = (string) $prefix; return $this; } /** * Set the default controller name. * * @param string $name The default page controller name for an empty route. * * @return JApplicationWebRouter This object for method chaining. * * @since 3.0 */ public function setDefaultController($name) { $this->default = (string) $name; return $this; } /** * Parse the given route and return the name of a controller mapped to the given route. * * @param string $route The route string for which to find and execute a controller. * * @return string The controller name for the given route excluding prefix. * * @since 3.0 * @throws InvalidArgumentException */ abstract protected function parseRoute($route); /** * Get a JController object for a given name. * * @param string $name The controller name (excluding prefix) for which to fetch and instance. * * @return JController * * @since 3.0 * @throws RuntimeException */ protected function fetchController($name) { // Derive the controller class name. $class = $this->controllerPrefix . ucfirst($name); // If the controller class does not exist panic. if (!class_exists($class) || !is_subclass_of($class, 'JController')) { throw new RuntimeException(sprintf('Unable to locate controller `%s`.', $class), 404); } // Instantiate the controller. $controller = new $class($this->input, $this->app); return $controller; } } application.php 0000604 00000072565 15245616714 0007606 0 ustar 00 <?php /** * @package Joomla.Legacy * @subpackage Application * * @copyright (C) 2005 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ defined('JPATH_PLATFORM') or die; use Joomla\CMS\Application\BaseApplication; use Joomla\Registry\Registry; JLog::add('JApplication is deprecated.', JLog::WARNING, 'deprecated'); /** * Base class for a Joomla! application. * * Acts as a Factory class for application specific objects and provides many * supporting API functions. Derived clases should supply the route(), dispatch() * and render() functions. * * @since 1.5 * @deprecated 3.2 Use CMSApplication instead unless specified otherwise */ class JApplication extends BaseApplication { /** * The client identifier. * * @var integer * @since 1.5 * @deprecated 3.2 */ protected $_clientId = null; /** * The application message queue. * * @var array * @since 1.5 * @deprecated 3.2 */ protected $_messageQueue = array(); /** * The name of the application. * * @var array * @since 1.5 * @deprecated 3.2 */ protected $_name = null; /** * The scope of the application. * * @var string * @since 1.5 * @deprecated 3.2 */ public $scope = null; /** * The time the request was made. * * @var string * @since 1.5 * @deprecated 3.2 */ public $requestTime = null; /** * The time the request was made as Unix timestamp. * * @var integer * @since 1.6 * @deprecated 3.2 */ public $startTime = null; /** * The application client object. * * @var JApplicationWebClient * @since 3.0 * @deprecated 3.2 */ public $client; /** * JApplication instances container. * * @var JApplication[] * @since 2.5 * @deprecated 3.2 */ protected static $instances = array(); /** * Class constructor. * * @param array $config A configuration array including optional elements such as session * session_name, clientId and others. This is not exhaustive. * * @since 1.5 * @deprecated 3.2 */ public function __construct($config = array()) { // Set the view name. $this->_name = $this->getName(); // Only set the clientId if available. if (isset($config['clientId'])) { $this->_clientId = $config['clientId']; } // Enable sessions by default. if (!isset($config['session'])) { $config['session'] = true; } // Create the input object $this->input = new JInput; $this->client = new JApplicationWebClient; $this->loadDispatcher(); // Set the session default name. if (!isset($config['session_name'])) { $config['session_name'] = $this->_name; } // Set the default configuration file. if (!isset($config['config_file'])) { $config['config_file'] = 'configuration.php'; } // Create the configuration object. if (file_exists(JPATH_CONFIGURATION . '/' . $config['config_file'])) { $this->_createConfiguration(JPATH_CONFIGURATION . '/' . $config['config_file']); } // Create the session if a session name is passed. if ($config['session'] !== false) { $this->_createSession(JApplicationHelper::getHash($config['session_name'])); } $this->requestTime = gmdate('Y-m-d H:i'); // Used by task system to ensure that the system doesn't go over time. $this->startTime = JProfiler::getmicrotime(); } /** * Returns the global JApplicationCms object, only creating it if it * doesn't already exist. * * @param mixed $client A client identifier or name. * @param array $config An optional associative array of configuration settings. * @param string $prefix A prefix for class names * * @return JApplicationCms A JApplicationCms object. * * @since 1.5 * @deprecated 3.2 Use JApplicationCms::getInstance() instead * @note As of 3.2, this proxies to JApplicationCms::getInstance() */ public static function getInstance($client, $config = array(), $prefix = 'J') { return JApplicationCms::getInstance($client); } /** * Initialise the application. * * @param array $options An optional associative array of configuration settings. * * @return void * * @since 1.5 * @deprecated 3.2 */ public function initialise($options = array()) { // Set the language in the class. $config = JFactory::getConfig(); // Check that we were given a language in the array (since by default may be blank). if (isset($options['language'])) { $config->set('language', $options['language']); } // Set user specific editor. $user = JFactory::getUser(); $editor = $user->getParam('editor', $this->get('editor')); if (!JPluginHelper::isEnabled('editors', $editor)) { $editor = $this->get('editor'); if (!JPluginHelper::isEnabled('editors', $editor)) { $editor = 'none'; } } $config->set('editor', $editor); // Trigger the onAfterInitialise event. JPluginHelper::importPlugin('system'); $this->triggerEvent('onAfterInitialise'); } /** * Route the application. * * Routing is the process of examining the request environment to determine which * component should receive the request. The component optional parameters * are then set in the request object to be processed when the application is being * dispatched. * * @return void * * @since 1.5 * @deprecated 3.2 */ public function route() { // Get the full request URI. $uri = clone JUri::getInstance(); $router = $this->getRouter(); $result = $router->parse($uri); foreach ($result as $key => $value) { $this->input->def($key, $value); } // Trigger the onAfterRoute event. JPluginHelper::importPlugin('system'); $this->triggerEvent('onAfterRoute'); } /** * Dispatch the application. * * Dispatching is the process of pulling the option from the request object and * mapping them to a component. If the component does not exist, it handles * determining a default component to dispatch. * * @param string $component The component to dispatch. * * @return void * * @since 1.5 * @deprecated 3.2 */ public function dispatch($component = null) { $document = JFactory::getDocument(); $contents = JComponentHelper::renderComponent($component); $document->setBuffer($contents, 'component'); // Trigger the onAfterDispatch event. JPluginHelper::importPlugin('system'); $this->triggerEvent('onAfterDispatch'); } /** * Render the application. * * Rendering is the process of pushing the document buffers into the template * placeholders, retrieving data from the document and pushing it into * the JResponse buffer. * * @return void * * @since 1.5 * @deprecated 3.2 */ public function render() { $template = $this->getTemplate(true); $params = array('template' => $template->template, 'file' => 'index.php', 'directory' => JPATH_THEMES, 'params' => $template->params); // Parse the document. $document = JFactory::getDocument(); $document->parse($params); // Trigger the onBeforeRender event. JPluginHelper::importPlugin('system'); $this->triggerEvent('onBeforeRender'); // Render the document. $caching = ($this->get('caching') >= 2); JResponse::setBody($document->render($caching, $params)); // Trigger the onAfterRender event. $this->triggerEvent('onAfterRender'); } /** * Redirect to another URL. * * Optionally enqueues a message in the system message queue (which will be displayed * the next time a page is loaded) using the enqueueMessage method. If the headers have * not been sent the redirect will be accomplished using a "301 Moved Permanently" * code in the header pointing to the new location. If the headers have already been * sent this will be accomplished using a JavaScript statement. * * @param string $url The URL to redirect to. Can only be http/https URL * @param string $msg An optional message to display on redirect. * @param string $msgType An optional message type. Defaults to message. * @param boolean $moved True if the page is 301 Permanently Moved, otherwise 303 See Other is assumed. * * @return void Calls exit(). * * @since 1.5 * @deprecated 3.2 * * @see JApplication::enqueueMessage() */ public function redirect($url, $msg = '', $msgType = 'message', $moved = false) { // Check for relative internal links. if (preg_match('#^index2?\.php#', $url)) { $url = JUri::base() . $url; } // Strip out any line breaks. $url = preg_split("/[\r\n]/", $url); $url = $url[0]; /* * If we don't start with a http we need to fix this before we proceed. * We could validly start with something else (e.g. ftp), though this would * be unlikely and isn't supported by this API. */ if (stripos($url, 'http') !== 0) { $uri = JUri::getInstance(); $prefix = $uri->toString(array('scheme', 'user', 'pass', 'host', 'port')); if ($url[0] === '/') { // We just need the prefix since we have a path relative to the root. $url = $prefix . $url; } else { // It's relative to where we are now, so lets add that. $parts = explode('/', $uri->toString(array('path'))); array_pop($parts); $path = implode('/', $parts) . '/'; $url = $prefix . $path . $url; } } // If the message exists, enqueue it. if (trim($msg)) { $this->enqueueMessage($msg, $msgType); } // Persist messages if they exist. if (count($this->_messageQueue)) { $session = JFactory::getSession(); $session->set('application.queue', $this->_messageQueue); } // If the headers have been sent, then we cannot send an additional location header // so we will output a javascript redirect statement. if (headers_sent()) { echo "<script>document.location.href=" . json_encode(str_replace("'", ''', $url)) . ";</script>\n"; } else { $document = JFactory::getDocument(); jimport('phputf8.utils.ascii'); if (($this->client->engine == JApplicationWebClient::TRIDENT) && !utf8_is_ascii($url)) { // MSIE type browser and/or server cause issues when URL contains utf8 character,so use a javascript redirect method echo '<html><head><meta http-equiv="content-type" content="text/html; charset=' . $document->getCharset() . '" />' . '<script>document.location.href=' . json_encode(str_replace("'", ''', $url)) . ';</script></head></html>'; } else { // All other browsers, use the more efficient HTTP header method header($moved ? 'HTTP/1.1 301 Moved Permanently' : 'HTTP/1.1 303 See other'); header('Location: ' . $url); header('Content-Type: text/html; charset=' . $document->getCharset()); } } $this->close(); } /** * Enqueue a system message. * * @param string $msg The message to enqueue. * @param string $type The message type. Default is message. * * @return void * * @since 1.5 * @deprecated 3.2 */ public function enqueueMessage($msg, $type = 'message') { // For empty queue, if messages exists in the session, enqueue them first. if (!count($this->_messageQueue)) { $session = JFactory::getSession(); $sessionQueue = $session->get('application.queue'); if (count($sessionQueue)) { $this->_messageQueue = $sessionQueue; $session->set('application.queue', null); } } // Enqueue the message. $this->_messageQueue[] = array('message' => $msg, 'type' => strtolower($type)); } /** * Get the system message queue. * * @return array The system message queue. * * @since 1.5 * @deprecated 3.2 */ public function getMessageQueue() { // For empty queue, if messages exists in the session, enqueue them. if (!count($this->_messageQueue)) { $session = JFactory::getSession(); $sessionQueue = $session->get('application.queue'); if (count($sessionQueue)) { $this->_messageQueue = $sessionQueue; $session->set('application.queue', null); } } return $this->_messageQueue; } /** * Gets a configuration value. * * @param string $varname The name of the value to get. * @param string $default Default value to return * * @return mixed The user state. * * @since 1.5 * @deprecated 3.2 */ public function getCfg($varname, $default = null) { $config = JFactory::getConfig(); return $config->get('' . $varname, $default); } /** * Method to get the application name. * * The dispatcher name is by default parsed using the classname, or it can be set * by passing a $config['name'] in the class constructor. * * @return string The name of the dispatcher. * * @since 1.5 * @deprecated 3.2 */ public function getName() { $name = $this->_name; if (empty($name)) { $r = null; if (!preg_match('/J(.*)/i', get_class($this), $r)) { JLog::add(JText::_('JLIB_APPLICATION_ERROR_APPLICATION_GET_NAME'), JLog::WARNING, 'jerror'); } $name = strtolower($r[1]); } return $name; } /** * Gets a user state. * * @param string $key The path of the state. * @param mixed $default Optional default value, returned if the internal value is null. * * @return mixed The user state or null. * * @since 1.5 * @deprecated 3.2 */ public function getUserState($key, $default = null) { $session = JFactory::getSession(); $registry = $session->get('registry'); if ($registry !== null) { return $registry->get($key, $default); } return $default; } /** * Sets the value of a user state variable. * * @param string $key The path of the state. * @param string $value The value of the variable. * * @return mixed The previous state, if one existed. * * @since 1.5 * @deprecated 3.2 */ public function setUserState($key, $value) { $session = JFactory::getSession(); $registry = $session->get('registry'); if ($registry !== null) { return $registry->set($key, $value); } } /** * Gets the value of a user state variable. * * @param string $key The key of the user state variable. * @param string $request The name of the variable passed in a request. * @param string $default The default value for the variable if not found. Optional. * @param string $type Filter for the variable, for valid values see {@link JFilterInput::clean()}. Optional. * * @return mixed The request user state. * * @since 1.5 * @deprecated 3.2 */ public function getUserStateFromRequest($key, $request, $default = null, $type = 'none') { $cur_state = $this->getUserState($key, $default); $new_state = $this->input->get($request, null, $type); // Save the new value only if it was set in this request. if ($new_state !== null) { $this->setUserState($key, $new_state); } else { $new_state = $cur_state; } return $new_state; } /** * Login authentication function. * * Username and encoded password are passed the onUserLogin event which * is responsible for the user validation. A successful validation updates * the current session record with the user's details. * * Username and encoded password are sent as credentials (along with other * possibilities) to each observer (authentication plugin) for user * validation. Successful validation will update the current session with * the user details. * * @param array $credentials Array('username' => string, 'password' => string) * @param array $options Array('remember' => boolean) * * @return boolean|JException True on success, false if failed or silent handling is configured, or a JException object on authentication error. * * @since 1.5 * @deprecated 3.2 */ public function login($credentials, $options = array()) { JPluginHelper::importPlugin('user'); // Get the global JAuthentication object. $authenticate = JAuthentication::getInstance(); $response = $authenticate->authenticate($credentials, $options); if ($response->status === JAuthentication::STATUS_SUCCESS) { // Validate that the user should be able to login (different to being authenticated). // This permits authentication plugins blocking the user $authorisations = $authenticate->authorise($response, $options); foreach ($authorisations as $authorisation) { $denied_states = array(JAuthentication::STATUS_EXPIRED, JAuthentication::STATUS_DENIED); if (in_array($authorisation->status, $denied_states)) { // Trigger onUserAuthorisationFailure Event. $this->triggerEvent('onUserAuthorisationFailure', array((array) $authorisation)); // If silent is set, just return false. if (isset($options['silent']) && $options['silent']) { return false; } // Return the error. switch ($authorisation->status) { case JAuthentication::STATUS_EXPIRED: return JError::raiseWarning('102002', JText::_('JLIB_LOGIN_EXPIRED')); break; case JAuthentication::STATUS_DENIED: return JError::raiseWarning('102003', JText::_('JLIB_LOGIN_DENIED')); break; default: return JError::raiseWarning('102004', JText::_('JLIB_LOGIN_AUTHORISATION')); break; } } } // Import the user plugin group. JPluginHelper::importPlugin('user'); // OK, the credentials are authenticated and user is authorised. Let's fire the onLogin event. $results = $this->triggerEvent('onUserLogin', array((array) $response, $options)); /* * If any of the user plugins did not successfully complete the login routine * then the whole method fails. * * Any errors raised should be done in the plugin as this provides the ability * to provide much more information about why the routine may have failed. */ $user = JFactory::getUser(); if ($response->type === 'Cookie') { $user->set('cookieLogin', true); } if (in_array(false, $results, true) == false) { $options['user'] = $user; $options['responseType'] = $response->type; if (isset($response->length, $response->secure, $response->lifetime)) { $options['length'] = $response->length; $options['secure'] = $response->secure; $options['lifetime'] = $response->lifetime; } // The user is successfully logged in. Run the after login events $this->triggerEvent('onUserAfterLogin', array($options)); } return true; } // Trigger onUserLoginFailure Event. $this->triggerEvent('onUserLoginFailure', array((array) $response)); // If silent is set, just return false. if (isset($options['silent']) && $options['silent']) { return false; } // If status is success, any error will have been raised by the user plugin if ($response->status !== JAuthentication::STATUS_SUCCESS) { JLog::add($response->error_message, JLog::WARNING, 'jerror'); } return false; } /** * Logout authentication function. * * Passed the current user information to the onUserLogout event and reverts the current * session record back to 'anonymous' parameters. * If any of the authentication plugins did not successfully complete * the logout routine then the whole method fails. Any errors raised * should be done in the plugin as this provides the ability to give * much more information about why the routine may have failed. * * @param integer $userid The user to load - Can be an integer or string - If string, it is converted to ID automatically * @param array $options Array('clientid' => array of client id's) * * @return boolean True on success * * @since 1.5 * @deprecated 3.2 */ public function logout($userid = null, $options = array()) { // Get a user object from the JApplication. $user = JFactory::getUser($userid); // Build the credentials array. $parameters['username'] = $user->get('username'); $parameters['id'] = $user->get('id'); // Set clientid in the options array if it hasn't been set already. if (!isset($options['clientid'])) { $options['clientid'] = $this->getClientId(); } // Import the user plugin group. JPluginHelper::importPlugin('user'); // OK, the credentials are built. Lets fire the onLogout event. $results = $this->triggerEvent('onUserLogout', array($parameters, $options)); if (!in_array(false, $results, true)) { $options['username'] = $user->get('username'); $this->triggerEvent('onUserAfterLogout', array($options)); return true; } // Trigger onUserLoginFailure Event. $this->triggerEvent('onUserLogoutFailure', array($parameters)); return false; } /** * Gets the name of the current template. * * @param boolean $params An optional associative array of configuration settings * * @return mixed System is the fallback. * * @since 1.5 * @deprecated 3.2 */ public function getTemplate($params = false) { $template = new stdClass; $template->template = 'system'; $template->params = new Registry; if ($params) { return $template; } return $template->template; } /** * Returns the application JRouter object. * * @param string $name The name of the application. * @param array $options An optional associative array of configuration settings. * * @return JRouter|null A JRouter object * * @since 1.5 * @deprecated 3.2 */ public static function getRouter($name = null, array $options = array()) { if (!isset($name)) { $app = JFactory::getApplication(); $name = $app->getName(); } try { $router = JRouter::getInstance($name, $options); } catch (Exception $e) { return; } return $router; } /** * This method transliterates a string into a URL * safe string or returns a URL safe UTF-8 string * based on the global configuration * * @param string $string String to process * * @return string Processed string * * @since 1.6 * @deprecated 3.2 Use JApplicationHelper::stringURLSafe instead */ public static function stringURLSafe($string) { return JApplicationHelper::stringURLSafe($string); } /** * Returns the application JPathway object. * * @param string $name The name of the application. * @param array $options An optional associative array of configuration settings. * * @return JPathway|null A JPathway object * * @since 1.5 * @deprecated 3.2 */ public function getPathway($name = null, $options = array()) { if (!isset($name)) { $name = $this->_name; } try { $pathway = JPathway::getInstance($name, $options); } catch (Exception $e) { return; } return $pathway; } /** * Returns the application JPathway object. * * @param string $name The name of the application/client. * @param array $options An optional associative array of configuration settings. * * @return JMenu|null JMenu object. * * @since 1.5 * @deprecated 3.2 */ public function getMenu($name = null, $options = array()) { if (!isset($name)) { $name = $this->_name; } try { $menu = JMenu::getInstance($name, $options); } catch (Exception $e) { return; } return $menu; } /** * Provides a secure hash based on a seed * * @param string $seed Seed string. * * @return string A secure hash * * @since 1.6 * @deprecated 3.2 Use JApplicationHelper::getHash instead */ public static function getHash($seed) { return JApplicationHelper::getHash($seed); } /** * Create the configuration registry. * * @param string $file The path to the configuration file * * @return JConfig A JConfig object * * @since 1.5 * @deprecated 3.2 */ protected function _createConfiguration($file) { JLoader::register('JConfig', $file); // Create the JConfig object. $config = new JConfig; // Get the global configuration object. $registry = JFactory::getConfig(); // Load the configuration values into the registry. $registry->loadObject($config); return $config; } /** * Create the user session. * * Old sessions are flushed based on the configuration value for the cookie * lifetime. If an existing session, then the last access time is updated. * If a new session, a session id is generated and a record is created in * the #__sessions table. * * @param string $name The sessions name. * * @return JSession JSession on success. May call exit() on database error. * * @since 1.5 * @deprecated 3.2 */ protected function _createSession($name) { $options = array(); $options['name'] = $name; switch ($this->_clientId) { case 0: if ($this->get('force_ssl') == 2) { $options['force_ssl'] = true; } break; case 1: if ($this->get('force_ssl') >= 1) { $options['force_ssl'] = true; } break; } $this->registerEvent('onAfterSessionStart', array($this, 'afterSessionStart')); $session = JFactory::getSession($options); $session->initialise($this->input, $this->dispatcher); $session->start(); // TODO: At some point we need to get away from having session data always in the db. $db = JFactory::getDbo(); // Remove expired sessions from the database. $time = time(); if ($time % 2) { // The modulus introduces a little entropy, making the flushing less accurate // but fires the query less than half the time. $query = $db->getQuery(true) ->delete($db->quoteName('#__session')) ->where($db->quoteName('time') . ' < ' . (int) ($time - $session->getExpire())); $db->setQuery($query); $db->execute(); } // Check to see the the session already exists. $handler = $this->get('session_handler'); if (($handler !== 'database' && ($time % 2 || $session->isNew())) || ($handler === 'database' && $session->isNew())) { $this->checkSession(); } return $session; } /** * Checks the user session. * * If the session record doesn't exist, initialise it. * If session is new, create session variables * * @return void * * @since 1.6 * @deprecated 3.2 */ public function checkSession() { $db = JFactory::getDbo(); $session = JFactory::getSession(); $user = JFactory::getUser(); $query = $db->getQuery(true) ->select($db->quoteName('session_id')) ->from($db->quoteName('#__session')) ->where($db->quoteName('session_id') . ' = ' . $db->quoteBinary($session->getId())); $db->setQuery($query, 0, 1); $exists = $db->loadResult(); // If the session record doesn't exist initialise it. if (!$exists) { $query->clear(); if ($session->isNew()) { $query->insert($db->quoteName('#__session')) ->columns($db->quoteName('session_id') . ', ' . $db->quoteName('client_id') . ', ' . $db->quoteName('time')) ->values($db->quote($session->getId()) . ', ' . (int) $this->getClientId() . ', ' . time()); $db->setQuery($query); } else { $query->insert($db->quoteName('#__session')) ->columns( $db->quoteName('session_id') . ', ' . $db->quoteName('client_id') . ', ' . $db->quoteName('guest') . ', ' . $db->quoteName('time') . ', ' . $db->quoteName('userid') . ', ' . $db->quoteName('username') ) ->values( $db->quote($session->getId()) . ', ' . (int) $this->getClientId() . ', ' . (int) $user->get('guest') . ', ' . (int) $session->get('session.timer.start') . ', ' . (int) $user->get('id') . ', ' . $db->quote($user->get('username')) ); $db->setQuery($query); } // If the insert failed, exit the application. try { $db->execute(); } catch (RuntimeException $e) { jexit($e->getMessage()); } } } /** * After the session has been started we need to populate it with some default values. * * @return void * * @since 3.0 * @deprecated 3.2 */ public function afterSessionStart() { $session = JFactory::getSession(); if ($session->isNew()) { $session->set('registry', new Registry); $session->set('user', new JUser); } } /** * Gets the client id of the current running application. * * @return integer A client identifier. * * @since 1.5 * @deprecated 3.2 */ public function getClientId() { return $this->_clientId; } /** * Is admin interface? * * @return boolean True if this application is administrator. * * @since 1.0.2 * @deprecated 3.2 */ public function isAdmin() { return $this->isClient('administrator'); } /** * Is site interface? * * @return boolean True if this application is site. * * @since 1.5 * @deprecated 3.2 */ public function isSite() { return $this->isClient('site'); } /** * 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 3.7.0 */ public function isClient($identifier) { return $this->getName() == $identifier; } /** * Method to determine if the host OS is Windows * * @return boolean True if Windows OS * * @since 1.6 * @deprecated 4.0 Use the IS_WIN constant instead. */ public static function isWinOs() { JLog::add('JApplication::isWinOS() is deprecated. Use the IS_WIN constant instead.', JLog::WARNING, 'deprecated'); return IS_WIN; } /** * Determine if we are using a secure (SSL) connection. * * @return boolean True if using SSL, false if not. * * @since 3.0 * @deprecated 3.2 */ public function isSSLConnection() { return (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') || getenv('SSL_PROTOCOL_VERSION'); } /** * Returns the response as a string. * * @return string The response * * @since 1.6 * @deprecated 3.2 */ public function __toString() { $compress = $this->get('gzip', false); return JResponse::toString($compress); } } LICENSE 0000604 00000042630 15245622151 0005555 0 ustar 00 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. src/Cli/Output/Xml.php 0000604 00000001521 15245622151 0010611 0 ustar 00 <?php /** * Part of the Joomla Framework Application Package * * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Application\Cli\Output; use Joomla\Application\Cli\CliOutput; /** * Class Xml. * * @since 1.0 * @deprecated 2.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 void * * @since 1.0 * @throws \RuntimeException * @codeCoverageIgnore */ public function out($text = '', $nl = true) { fwrite(STDOUT, $text . ($nl ? "\n" : null)); } } src/Cli/Output/Processor/ProcessorInterface.php 0000604 00000001175 15245622151 0015635 0 ustar 00 <?php /** * Part of the Joomla Framework Application Package * * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Application\Cli\Output\Processor; /** * Class ProcessorInterface. * * @since 1.1.0 * @deprecated 2.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 1.1.0 */ public function process($output); } src/Cli/Output/Processor/ColorProcessor.php 0000604 00000007547 15245622151 0015024 0 ustar 00 <?php /** * Part of the Joomla Framework Application Package * * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Application\Cli\Output\Processor; use Joomla\Application\Cli\ColorStyle; use Joomla\Application\Cli\Output\Stdout; /** * Class ColorProcessor. * * @since 1.0 * @deprecated 2.0 Use the `joomla/console` package instead */ class ColorProcessor implements ProcessorInterface { /** * Flag to remove color codes from the output * * @var boolean * @since 1.0 */ public $noColors = false; /** * Regex to match tags * * @var string * @since 1.0 */ protected $tagFilter = '/<([a-z=;]+)>(.*?)<\/\\1>/s'; /** * Regex used for removing color codes * * @var string * @since 1.0 */ protected static $stripFilter = '/<[\/]?[a-z=;]+>/'; /** * Array of ColorStyle objects * * @var array * @since 1.0 */ protected $styles = array(); /** * Class constructor * * @param boolean $noColors Defines non-colored mode on construct * * @since 1.1.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 ColorProcessor Instance of $this to allow chaining. * * @since 1.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 1.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 1.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]]); } // Custom format elseif (strpos($matches[1][$i], '=')) { $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 string * * @since 1.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 Stdout Instance of $this to allow chaining. * * @since 1.0 */ private function addPredefinedStyles() { $this->addStyle( 'info', new ColorStyle('green', '', array('bold')) ); $this->addStyle( 'comment', new ColorStyle('yellow', '', array('bold')) ); $this->addStyle( 'question', new ColorStyle('black', 'cyan') ); $this->addStyle( 'error', new ColorStyle('white', 'red') ); return $this; } } src/Cli/Output/Stdout.php 0000604 00000001620 15245622151 0011333 0 ustar 00 <?php /** * Part of the Joomla Framework Application Package * * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Application\Cli\Output; use Joomla\Application\Cli\CliOutput; /** * Class Stdout. * * @since 1.0 * @deprecated 2.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 Stdout Instance of $this to allow chaining. * * @codeCoverageIgnore * @since 1.0 */ public function out($text = '', $nl = true) { fwrite(STDOUT, $this->getProcessor()->process($text) . ($nl ? "\n" : null)); return $this; } } src/Cli/CliOutput.php 0000604 00000003216 15245622151 0010504 0 ustar 00 <?php /** * Part of the Joomla Framework Application Package * * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Application\Cli; use Joomla\Application\Cli\Output\Processor\ProcessorInterface; /** * Class CliOutput * * @since 1.0 * @deprecated 2.0 Use the `joomla/console` package instead */ abstract class CliOutput { /** * Color processing object * * @var ProcessorInterface * @since 1.0 */ protected $processor; /** * Constructor * * @param ProcessorInterface $processor The output processor. * * @since 1.1.2 */ public function __construct(ProcessorInterface $processor = null) { $this->setProcessor(($processor instanceof ProcessorInterface) ? $processor : new Output\Processor\ColorProcessor); } /** * Set a processor * * @param ProcessorInterface $processor The output processor. * * @return Stdout Instance of $this to allow chaining. * * @since 1.0 */ public function setProcessor(ProcessorInterface $processor) { $this->processor = $processor; return $this; } /** * Get a processor * * @return ProcessorInterface * * @since 1.0 */ public function getProcessor() { return $this->processor; } /** * 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 void * * @since 1.0 * @codeCoverageIgnore */ abstract public function out($text = '', $nl = true); } src/Cli/CliInput.php 0000604 00000001164 15245622151 0010303 0 ustar 00 <?php /** * Part of the Joomla Framework Application Package * * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Application\Cli; /** * Class CliInput * * @since 1.6.0 * @deprecated 2.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 1.6.0 */ public function in() { return rtrim(fread(STDIN, 8192), "\n\r"); } } src/Cli/ColorStyle.php 0000604 00000010452 15245622151 0010653 0 ustar 00 <?php /** * Part of the Joomla Framework Application Package * * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Application\Cli; /** * Class ColorStyle * * @since 1.0 * @deprecated 2.0 Use the `joomla/console` package instead */ final class ColorStyle { /** * Known colors * * @var array * @since 1.0 */ private static $knownColors = array( 'black' => 0, 'red' => 1, 'green' => 2, 'yellow' => 3, 'blue' => 4, 'magenta' => 5, 'cyan' => 6, 'white' => 7, ); /** * Known styles * * @var array * @since 1.0 */ private static $knownOptions = array( 'bold' => 1, 'underscore' => 4, 'blink' => 5, 'reverse' => 7, ); /** * Foreground base value * * @var integer * @since 1.0 */ private static $fgBase = 30; /** * Background base value * * @var integer * @since 1.0 */ private static $bgBase = 40; /** * Foreground color * * @var integer * @since 1.0 */ private $fgColor = 0; /** * Background color * * @var integer * @since 1.0 */ private $bgColor = 0; /** * Array of style options * * @var array * @since 1.0 */ private $options = array(); /** * Constructor * * @param string $fg Foreground color. * @param string $bg Background color. * @param array $options Style options. * * @since 1.0 * @throws \InvalidArgumentException */ public function __construct($fg = '', $bg = '', $options = array()) { if ($fg) { if (array_key_exists($fg, static::$knownColors) == false) { 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) == false) { 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) == false) { throw new \InvalidArgumentException( sprintf('Invalid option "%1$s" [%2$s]', $option, implode(', ', $this->getKnownOptions()) ) ); } $this->options[] = $option; } } /** * Convert to a string. * * @return string * * @since 1.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 ColorStyle Instance of $this to allow chaining. * * @since 1.0 * @throws \RuntimeException */ public static function fromString($string) { $fg = ''; $bg = ''; $options = array(); $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'); break; } } return new self($fg, $bg, $options); } /** * Get the translated color code. * * @return string * * @since 1.0 */ public function getStyle() { $values = array(); 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 1.0 */ public function getKnownColors() { return array_keys(static::$knownColors); } /** * Get the known options. * * @return array * * @since 1.0 */ public function getKnownOptions() { return array_keys(static::$knownOptions); } } src/Cli/ColorProcessor.php 0000604 00000001011 15245622151 0011521 0 ustar 00 <?php /** * Part of the Joomla Framework Application Package * * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Application\Cli; use \Joomla\Application\Cli\Output\Processor\ColorProcessor as RealColorProcessor; /** * Class ColorProcessor. * * @since 1.0 * @deprecated 2.0 Use the `joomla/console` package instead */ class ColorProcessor extends RealColorProcessor { } src/AbstractWebApplication.php 0000604 00000066035 15245622151 0012442 0 ustar 00 <?php /** * Part of the Joomla Framework Application Package * * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Application; use Joomla\Input\Input; use Joomla\Registry\Registry; use Joomla\Session\Session; use Joomla\Uri\Uri; /** * Base class for a Joomla! Web application. * * @since 1.0 */ abstract class AbstractWebApplication extends AbstractApplication { /** * Character encoding string. * * @var string * @since 1.0 */ public $charSet = 'utf-8'; /** * Response mime type. * * @var string * @since 1.0 */ public $mimeType = 'text/html'; /** * HTTP protocol version. * * @var string * @since 1.9.0 */ public $httpVersion = '1.1'; /** * The body modified date for response headers. * * @var \DateTime * @since 1.0 */ public $modifiedDate; /** * The application client object. * * @var Web\WebClient * @since 1.0 */ public $client; /** * The application response object. * * @var object * @since 1.0 */ protected $response; /** * The application session object. * * @var Session * @since 1.0 */ private $session; /** * A map of integer HTTP response codes to the full HTTP Status for the headers. * * @var array * @since 1.6.0 * @link https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml */ private $responseMap = array( 100 => 'HTTP/{version} 100 Continue', 101 => 'HTTP/{version} 101 Switching Protocols', 102 => 'HTTP/{version} 102 Processing', 200 => 'HTTP/{version} 200 OK', 201 => 'HTTP/{version} 201 Created', 202 => 'HTTP/{version} 202 Accepted', 203 => 'HTTP/{version} 203 Non-Authoritative Information', 204 => 'HTTP/{version} 204 No Content', 205 => 'HTTP/{version} 205 Reset Content', 206 => 'HTTP/{version} 206 Partial Content', 207 => 'HTTP/{version} 207 Multi-Status', 208 => 'HTTP/{version} 208 Already Reported', 226 => 'HTTP/{version} 226 IM Used', 300 => 'HTTP/{version} 300 Multiple Choices', 301 => 'HTTP/{version} 301 Moved Permanently', 302 => 'HTTP/{version} 302 Found', 303 => 'HTTP/{version} 303 See other', 304 => 'HTTP/{version} 304 Not Modified', 305 => 'HTTP/{version} 305 Use Proxy', 306 => 'HTTP/{version} 306 (Unused)', 307 => 'HTTP/{version} 307 Temporary Redirect', 308 => 'HTTP/{version} 308 Permanent Redirect', 400 => 'HTTP/{version} 400 Bad Request', 401 => 'HTTP/{version} 401 Unauthorized', 402 => 'HTTP/{version} 402 Payment Required', 403 => 'HTTP/{version} 403 Forbidden', 404 => 'HTTP/{version} 404 Not Found', 405 => 'HTTP/{version} 405 Method Not Allowed', 406 => 'HTTP/{version} 406 Not Acceptable', 407 => 'HTTP/{version} 407 Proxy Authentication Required', 408 => 'HTTP/{version} 408 Request Timeout', 409 => 'HTTP/{version} 409 Conflict', 410 => 'HTTP/{version} 410 Gone', 411 => 'HTTP/{version} 411 Length Required', 412 => 'HTTP/{version} 412 Precondition Failed', 413 => 'HTTP/{version} 413 Payload Too Large', 414 => 'HTTP/{version} 414 URI Too Long', 415 => 'HTTP/{version} 415 Unsupported Media Type', 416 => 'HTTP/{version} 416 Range Not Satisfiable', 417 => 'HTTP/{version} 417 Expectation Failed', 418 => 'HTTP/{version} 418 I\'m a teapot', 421 => 'HTTP/{version} 421 Misdirected Request', 422 => 'HTTP/{version} 422 Unprocessable Entity', 423 => 'HTTP/{version} 423 Locked', 424 => 'HTTP/{version} 424 Failed Dependency', 426 => 'HTTP/{version} 426 Upgrade Required', 428 => 'HTTP/{version} 428 Precondition Required', 429 => 'HTTP/{version} 429 Too Many Requests', 431 => 'HTTP/{version} 431 Request Header Fields Too Large', 451 => 'HTTP/{version} 451 Unavailable For Legal Reasons', 500 => 'HTTP/{version} 500 Internal Server Error', 501 => 'HTTP/{version} 501 Not Implemented', 502 => 'HTTP/{version} 502 Bad Gateway', 503 => 'HTTP/{version} 503 Service Unavailable', 504 => 'HTTP/{version} 504 Gateway Timeout', 505 => 'HTTP/{version} 505 HTTP Version Not Supported', 506 => 'HTTP/{version} 506 Variant Also Negotiates', 507 => 'HTTP/{version} 507 Insufficient Storage', 508 => 'HTTP/{version} 508 Loop Detected', 510 => 'HTTP/{version} 510 Not Extended', 511 => 'HTTP/{version} 511 Network Authentication Required', ); /** * Class constructor. * * @param Input $input An optional argument to provide dependency injection for the application's input object. If the argument * is an 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. * @param Web\WebClient $client An optional argument to provide dependency injection for the application's client object. If the argument * is a Web\WebClient object that object will become the application's client object, otherwise a default client * object is created. * * @since 1.0 */ public function __construct(Input $input = null, Registry $config = null, Web\WebClient $client = null) { $this->client = $client instanceof Web\WebClient ? $client : new Web\WebClient; // Setup the response object. $this->response = new \stdClass; $this->response->cachable = false; $this->response->headers = array(); $this->response->body = array(); // Call the constructor as late as possible (it runs `initialise`). parent::__construct($input, $config); // Set the system URIs. $this->loadSystemUris(); } /** * Execute the application. * * @return void * * @since 1.0 */ public function execute() { // @event onBeforeExecute // Perform application routines. $this->doExecute(); // @event onAfterExecute // If gzip compression is enabled in configuration and the server is compliant, compress the output. if ($this->get('gzip') && !ini_get('zlib.output_compression') && (ini_get('output_handler') != 'ob_gzhandler')) { $this->compress(); } // @event onBeforeRespond // Send the application response. $this->respond(); // @event onAfterRespond } /** * Checks the accept encoding of the browser and compresses the data before * sending it to the client if possible. * * @return void * * @since 1.0 */ protected function compress() { // Supported compression encodings. $supported = array( 'x-gzip' => 'gz', 'gzip' => 'gz', 'deflate' => 'deflate', ); // Get the supported encoding. $encodings = array_intersect($this->client->encodings, array_keys($supported)); // If no supported encoding is detected do nothing and return. if (empty($encodings)) { return; } // Verify that headers have not yet been sent, and that our connection is still alive. if ($this->checkHeadersSent() || !$this->checkConnectionAlive()) { return; } // Iterate through the encodings and attempt to compress the data using any found supported encodings. foreach ($encodings as $encoding) { if (($supported[$encoding] == 'gz') || ($supported[$encoding] == 'deflate')) { // Verify that the server supports gzip compression before we attempt to gzip encode the data. // @codeCoverageIgnoreStart if (!\extension_loaded('zlib') || ini_get('zlib.output_compression')) { continue; } // @codeCoverageIgnoreEnd // Attempt to gzip encode the data with an optimal level 4. $data = $this->getBody(); $gzdata = gzencode($data, 4, ($supported[$encoding] == 'gz') ? FORCE_GZIP : FORCE_DEFLATE); // If there was a problem encoding the data just try the next encoding scheme. // @codeCoverageIgnoreStart if ($gzdata === false) { continue; } // @codeCoverageIgnoreEnd // Set the encoding headers. $this->setHeader('Content-Encoding', $encoding); $this->setHeader('Vary', 'Accept-Encoding'); $this->setHeader('X-Content-Encoded-By', 'Joomla'); // Replace the output with the encoded data. $this->setBody($gzdata); // Compression complete, let's break out of the loop. break; } } } /** * Method to send the application response to the client. All headers will be sent prior to the main * application output data. * * @return void * * @since 1.0 */ protected function respond() { // Send the content-type header. $this->setHeader('Content-Type', $this->mimeType . '; charset=' . $this->charSet); // If the response is set to uncachable, we need to set some appropriate headers so browsers don't cache the response. if (!$this->allowCache()) { // Expires in the past. $this->setHeader('Expires', 'Wed, 17 Aug 2005 00:00:00 GMT', true); // Always modified. $this->setHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT', true); $this->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0', false); // HTTP 1.0 $this->setHeader('Pragma', 'no-cache'); } else { // Expires. $this->setHeader('Expires', gmdate('D, d M Y H:i:s', time() + 900) . ' GMT'); // Last modified. if ($this->modifiedDate instanceof \DateTime) { $this->modifiedDate->setTimezone(new \DateTimeZone('UTC')); $this->setHeader('Last-Modified', $this->modifiedDate->format('D, d M Y H:i:s') . ' GMT'); } } $this->sendHeaders(); echo $this->getBody(); } /** * Redirect to another URL. * * If the headers have not been sent the redirect will be accomplished using a "301 Moved Permanently" * or "303 See Other" code in the header pointing to the new location. If the headers have already been * sent this will be accomplished using a JavaScript statement. * * @param string $url The URL to redirect to. Can only be http/https URL * @param integer $status The HTTP status code to be provided. 303 is assumed by default. * * @return void * * @since 1.0 * @throws \InvalidArgumentException */ public function redirect($url, $status = 303) { // Check for relative internal links. if (preg_match('#^index\.php#', $url)) { $url = $this->get('uri.base.full') . $url; } // Perform a basic sanity check to make sure we don't have any CRLF garbage. $url = preg_split("/[\r\n]/", $url); $url = $url[0]; /* * Here we need to check and see if the URL is relative or absolute. Essentially, do we need to * prepend the URL with our base URL for a proper redirect. The rudimentary way we are looking * at this is to simply check whether or not the URL string has a valid scheme or not. */ if (!preg_match('#^[a-z]+\://#i', $url)) { // Get a Uri instance for the requested URI. $uri = new Uri($this->get('uri.request')); // Get a base URL to prepend from the requested URI. $prefix = $uri->toString(array('scheme', 'user', 'pass', 'host', 'port')); // We just need the prefix since we have a path relative to the root. if ($url[0] == '/') { $url = $prefix . $url; } else { // It's relative to where we are now, so lets add that. $parts = explode('/', $uri->toString(array('path'))); array_pop($parts); $path = implode('/', $parts) . '/'; $url = $prefix . $path . $url; } } // If the headers have already been sent we need to send the redirect statement via JavaScript. if ($this->checkHeadersSent()) { echo '<script>document.location.href=' . json_encode($url) . ";</script>\n"; } else { // We have to use a JavaScript redirect here because MSIE doesn't play nice with utf-8 URLs. if (($this->client->engine == Web\WebClient::TRIDENT) && !static::isAscii($url)) { $html = '<html><head>'; $html .= '<meta http-equiv="content-type" content="text/html; charset=' . $this->charSet . '" />'; $html .= '<script>document.location.href=' . json_encode($url) . ';</script>'; $html .= '</head><body></body></html>'; echo $html; } else { // Check if we have a boolean for the status variable for compatibility with v1 of the framework // @deprecated 3.0 if (\is_bool($status)) { $status = $status ? 301 : 303; } if (!\is_int($status) && !$this->isRedirectState($status)) { throw new \InvalidArgumentException('You have not supplied a valid HTTP status code'); } // All other cases use the more efficient HTTP header for redirection. $this->setHeader('Status', $status, true); $this->setHeader('Location', $url, true); } } // Set appropriate headers $this->respond(); // Close the application after the redirect. $this->close(); } /** * Set/get cachable state for the response. If $allow is set, sets the cachable state of the * response. Always returns the current state. * * @param boolean $allow True to allow browser caching. * * @return boolean * * @since 1.0 */ public function allowCache($allow = null) { if ($allow !== null) { $this->response->cachable = (bool) $allow; } return $this->response->cachable; } /** * Method to set a response header. If the replace flag is set then all headers * with the given name will be replaced by the new one. The headers are stored * in an internal array to be sent when the site is sent to the browser. * * @param string $name The name of the header to set. * @param string $value The value of the header to set. * @param boolean $replace True to replace any headers with the same name. * * @return AbstractWebApplication Instance of $this to allow chaining. * * @since 1.0 */ public function setHeader($name, $value, $replace = false) { // Sanitize the input values. $name = (string) $name; $value = (string) $value; // If the replace flag is set, unset all known headers with the given name. if ($replace) { foreach ($this->response->headers as $key => $header) { if ($name == $header['name']) { unset($this->response->headers[$key]); } } // Clean up the array as unsetting nested arrays leaves some junk. $this->response->headers = array_values($this->response->headers); } // Add the header to the internal array. $this->response->headers[] = array('name' => $name, 'value' => $value); return $this; } /** * Method to get the array of response headers to be sent when the response is sent * to the client. * * @return array * * @since 1.0 */ public function getHeaders() { return $this->response->headers; } /** * Method to clear any set response headers. * * @return AbstractWebApplication Instance of $this to allow chaining. * * @since 1.0 */ public function clearHeaders() { $this->response->headers = array(); return $this; } /** * Send the response headers. * * @return AbstractWebApplication Instance of $this to allow chaining. * * @since 1.0 */ public function sendHeaders() { if (!$this->checkHeadersSent()) { foreach ($this->response->headers as $header) { if (strtolower($header['name']) == 'status') { // 'status' headers indicate an HTTP status, and need to be handled slightly differently $status = $this->getHttpStatusValue($header['value']); $this->header($status, true, (int) $header['value']); } else { $this->header($header['name'] . ': ' . $header['value']); } } } return $this; } /** * Set body content. If body content already defined, this will replace it. * * @param string $content The content to set as the response body. * * @return AbstractWebApplication Instance of $this to allow chaining. * * @since 1.0 */ public function setBody($content) { $this->response->body = array((string) $content); return $this; } /** * Prepend content to the body content * * @param string $content The content to prepend to the response body. * * @return AbstractWebApplication Instance of $this to allow chaining. * * @since 1.0 */ public function prependBody($content) { array_unshift($this->response->body, (string) $content); return $this; } /** * Append content to the body content * * @param string $content The content to append to the response body. * * @return AbstractWebApplication Instance of $this to allow chaining. * * @since 1.0 */ public function appendBody($content) { $this->response->body[] = (string) $content; return $this; } /** * Return the body content * * @param boolean $asArray True to return the body as an array of strings. * * @return string|string[] The response body either as an array or concatenated string. * * @since 1.0 */ public function getBody($asArray = false) { return $asArray ? $this->response->body : implode((array) $this->response->body); } /** * Method to get the application session object. * * @return Session The session object * * @since 1.0 */ public function getSession() { if ($this->session === null) { throw new \RuntimeException('A \Joomla\Session\Session object has not been set.'); } return $this->session; } /** * Check if a given value can be successfully mapped to a valid http status value * * @param string|int $value The given status as int or string * * @return string * * @since 1.8.0 */ protected function getHttpStatusValue($value) { $code = (int) $value; if (array_key_exists($code, $this->responseMap)) { $value = $this->responseMap[$code]; } else { $value = 'HTTP/{version} ' . $code; } return str_replace('{version}', $this->httpVersion, $value); } /** * Check if the value is a valid HTTP status code * * @param integer $code The potential status code * * @return boolean * * @since 1.8.1 */ public function isValidHttpStatus($code) { return array_key_exists($code, $this->responseMap); } /** * Method to check the current client connection status to ensure that it is alive. We are * wrapping this to isolate the connection_status() function from our code base for testing reasons. * * @return boolean True if the connection is valid and normal. * * @codeCoverageIgnore * @see connection_status() * @since 1.0 */ protected function checkConnectionAlive() { return connection_status() === CONNECTION_NORMAL; } /** * Method to check to see if headers have already been sent. We are wrapping this to isolate the * headers_sent() function from our code base for testing reasons. * * @return boolean True if the headers have already been sent. * * @codeCoverageIgnore * @see headers_sent() * @since 1.0 */ protected function checkHeadersSent() { return headers_sent(); } /** * Method to detect the requested URI from server environment variables. * * @return string The requested URI * * @since 1.0 */ protected function detectRequestUri() { // First we need to detect the URI scheme. if ($this->isSslConnection()) { $scheme = 'https://'; } else { $scheme = 'http://'; } /* * There are some differences in the way that Apache and IIS populate server environment variables. To * properly detect the requested URI we need to adjust our algorithm based on whether or not we are getting * information from Apache or IIS. */ $phpSelf = $this->input->server->getString('PHP_SELF', ''); $requestUri = $this->input->server->getString('REQUEST_URI', ''); // If PHP_SELF and REQUEST_URI are both populated then we will assume "Apache Mode". if (!empty($phpSelf) && !empty($requestUri)) { // The URI is built from the HTTP_HOST and REQUEST_URI environment variables in an Apache environment. $uri = $scheme . $this->input->server->getString('HTTP_HOST') . $requestUri; } else { // If not in "Apache Mode" we will assume that we are in an IIS environment and proceed. // IIS uses the SCRIPT_NAME variable instead of a REQUEST_URI variable... thanks, MS $uri = $scheme . $this->input->server->getString('HTTP_HOST') . $this->input->server->getString('SCRIPT_NAME'); $queryHost = $this->input->server->getString('QUERY_STRING', ''); // If the QUERY_STRING variable exists append it to the URI string. if (!empty($queryHost)) { $uri .= '?' . $queryHost; } } return trim($uri); } /** * Method to send a header to the client. We are wrapping this to isolate the header() function * from our code base for testing reasons. * * @param string $string The header string. * @param boolean $replace The optional replace parameter indicates whether the header should * replace a previous similar header, or add a second header of the same type. * @param integer $code Forces the HTTP response code to the specified value. Note that * this parameter only has an effect if the string is not empty. * * @return void * * @codeCoverageIgnore * @see header() * @since 1.0 */ protected function header($string, $replace = true, $code = null) { header(str_replace(\chr(0), '', $string), $replace, $code); } /** * Checks if a state is a redirect state * * @param integer $state The HTTP status code. * * @return boolean * * @since 1.8.0 */ protected function isRedirectState($state) { $state = (int) $state; return $state > 299 && $state < 400 && array_key_exists($state, $this->responseMap); } /** * Determine if we are using a secure (SSL) connection. * * @return boolean True if using SSL, false if not. * * @since 1.0 */ public function isSslConnection() { $serverSSLVar = $this->input->server->getString('HTTPS', ''); if (!empty($serverSSLVar) && strtolower($serverSSLVar) !== 'off') { return true; } $serverForwarderProtoVar = $this->input->server->getString('HTTP_X_FORWARDED_PROTO', ''); return !empty($serverForwarderProtoVar) && strtolower($serverForwarderProtoVar) === 'https'; } /** * Sets the session for the application to use, if required. * * @param Session $session A session object. * * @return AbstractWebApplication Returns itself to support chaining. * * @since 1.0 */ public function setSession(Session $session) { $this->session = $session; return $this; } /** * Method to load the system URI strings for the application. * * @param string $requestUri An optional request URI to use instead of detecting one from the * server environment variables. * * @return void * * @since 1.0 */ protected function loadSystemUris($requestUri = null) { // Set the request URI. // @codeCoverageIgnoreStart if (!empty($requestUri)) { $this->set('uri.request', $requestUri); } else { $this->set('uri.request', $this->detectRequestUri()); } // @codeCoverageIgnoreEnd // Check to see if an explicit base URI has been set. $siteUri = trim($this->get('site_uri')); if ($siteUri != '') { $uri = new Uri($siteUri); $path = $uri->toString(array('path')); } else { // No explicit base URI was set so we need to detect it. Start with the requested URI. $uri = new Uri($this->get('uri.request')); $requestUri = $this->input->server->getString('REQUEST_URI', ''); // If we are working from a CGI SAPI with the 'cgi.fix_pathinfo' directive disabled we use PHP_SELF. if (strpos(PHP_SAPI, 'cgi') !== false && !ini_get('cgi.fix_pathinfo') && !empty($requestUri)) { // We aren't expecting PATH_INFO within PHP_SELF so this should work. $path = \dirname($this->input->server->getString('PHP_SELF', '')); } else { // Pretty much everything else should be handled with SCRIPT_NAME. $path = \dirname($this->input->server->getString('SCRIPT_NAME', '')); } } // Get the host from the URI. $host = $uri->toString(array('scheme', 'user', 'pass', 'host', 'port')); // Check if the path includes "index.php". if (strpos($path, 'index.php') !== false) { // Remove the index.php portion of the path. $path = substr_replace($path, '', strpos($path, 'index.php'), 9); } $path = rtrim($path, '/\\'); // Set the base URI both as just a path and as the full URI. $this->set('uri.base.full', $host . $path . '/'); $this->set('uri.base.host', $host); $this->set('uri.base.path', $path . '/'); // Set the extended (non-base) part of the request URI as the route. if (stripos($this->get('uri.request'), $this->get('uri.base.full')) === 0) { $this->set('uri.route', substr_replace($this->get('uri.request'), '', 0, \strlen($this->get('uri.base.full')))); } // Get an explicitly set media URI is present. $mediaURI = trim($this->get('media_uri')); if ($mediaURI) { if (strpos($mediaURI, '://') !== false) { $this->set('uri.media.full', $mediaURI); $this->set('uri.media.path', $mediaURI); } else { // Normalise slashes. $mediaURI = trim($mediaURI, '/\\'); $mediaURI = !empty($mediaURI) ? '/' . $mediaURI . '/' : '/'; $this->set('uri.media.full', $this->get('uri.base.host') . $mediaURI); $this->set('uri.media.path', $mediaURI); } } else { // No explicit media URI was set, build it dynamically from the base uri. $this->set('uri.media.full', $this->get('uri.base.full') . 'media/'); $this->set('uri.media.path', $this->get('uri.base.path') . 'media/'); } } /** * Checks for a form token in the request. * * Use in conjunction with getFormToken. * * @param string $method The request method in which to look for the token key. * * @return boolean True if found and valid, false otherwise. * * @since 1.0 */ public function checkToken($method = 'post') { $token = $this->getFormToken(); if (!$this->input->$method->get($token, '', 'alnum')) { if ($this->getSession()->isNew()) { // Redirect to login screen. $this->redirect('index.php'); $this->close(); } else { return false; } } else { return true; } } /** * Method to determine a hash for anti-spoofing variable names * * @param boolean $forceNew If true, force a new token to be created * * @return string Hashed var name * * @since 1.0 */ public function getFormToken($forceNew = false) { // @todo we need the user id somehow here $userId = 0; return md5($this->get('secret') . $userId . $this->getSession()->getToken($forceNew)); } /** * Tests whether a string contains only 7bit ASCII bytes. * * You might use this to conditionally check whether a string * needs handling as UTF-8 or not, potentially offering performance * benefits by using the native PHP equivalent if it's just ASCII e.g.; * * @param string $str The string to test. * * @return boolean True if the string is all ASCII * * @since 1.4.0 */ public static function isAscii($str) { // Search for any bytes which are outside the ASCII range... return preg_match('/(?:[^\x00-\x7F])/', $str) !== 1; } } src/AbstractDaemonApplication.php 0000604 00000060450 15245622151 0013123 0 ustar 00 <?php /** * Part of the Joomla Framework Application Package * * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Application; use Joomla\Input; use Joomla\Registry\Registry; use Psr\Log\LoggerAwareInterface; /** * Class to turn Cli applications into daemons. It requires CLI and PCNTL support built into PHP. * * @link https://www.php.net/manual/en/book.pcntl.php * @link https://www.php.net/manual/en/features.commandline.php * @since 1.0 * @deprecated 2.0 Deprecated without replacement */ abstract class AbstractDaemonApplication extends AbstractCliApplication implements LoggerAwareInterface { /** * @var array The available POSIX signals to be caught by default. * @link https://www.php.net/manual/pcntl.constants.php * @since 1.0 */ protected static $signals = array( 'SIGHUP', 'SIGINT', 'SIGQUIT', 'SIGILL', 'SIGTRAP', 'SIGABRT', 'SIGIOT', 'SIGBUS', 'SIGFPE', 'SIGUSR1', 'SIGSEGV', 'SIGUSR2', 'SIGPIPE', 'SIGALRM', 'SIGTERM', 'SIGSTKFLT', 'SIGCLD', 'SIGCHLD', 'SIGCONT', 'SIGTSTP', 'SIGTTIN', 'SIGTTOU', 'SIGURG', 'SIGXCPU', 'SIGXFSZ', 'SIGVTALRM', 'SIGPROF', 'SIGWINCH', 'SIGPOLL', 'SIGIO', 'SIGPWR', 'SIGSYS', 'SIGBABY', 'SIG_BLOCK', 'SIG_UNBLOCK', 'SIG_SETMASK', ); /** * @var boolean True if the daemon is in the process of exiting. * @since 1.0 */ protected $exiting = false; /** * @var integer The parent process id. * @since 1.0 */ protected $parentId = 0; /** * @var integer The process id of the daemon. * @since 1.0 */ protected $processId = 0; /** * @var boolean True if the daemon is currently running. * @since 1.0 */ protected $running = false; /** * Class constructor. * * @param Input\Cli $input An optional argument to provide dependency injection for the application's input object. If the * argument is an Input\Cli 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 Cli\CliOutput $output An optional argument to provide dependency injection for the application's output object. If the * argument is a Cli\CliOutput object that object will become the application's input object, otherwise * a default output object is created. * @param Cli\CliInput $cliInput An optional argument to provide dependency injection for the application's CLI input object. If the * argument is a Cli\CliInput object that object will become the application's input object, otherwise * a default input object is created. * * @since 1.0 */ public function __construct(Cli $input = null, Registry $config = null, Cli\CliOutput $output = null, Cli\CliInput $cliInput = null) { // Verify that the process control extension for PHP is available. // @codeCoverageIgnoreStart if (!\defined('SIGHUP')) { $this->getLogger()->error('The PCNTL extension for PHP is not available.'); throw new \RuntimeException('The PCNTL extension for PHP is not available.'); } // Verify that POSIX support for PHP is available. if (!\function_exists('posix_getpid')) { $this->getLogger()->error('The POSIX extension for PHP is not available.'); throw new \RuntimeException('The POSIX extension for PHP is not available.'); } // @codeCoverageIgnoreEnd // Call the parent constructor. parent::__construct($input, $config, $output, $cliInput); // Set some system limits. @set_time_limit($this->get('max_execution_time', 0)); if ($this->get('max_memory_limit') !== null) { ini_set('memory_limit', $this->get('max_memory_limit', '256M')); } // Flush content immediately. ob_implicit_flush(); } /** * Method to handle POSIX signals. * * @param integer $signal The received POSIX signal. * * @return void * * @since 1.0 * @see pcntl_signal() * @throws \RuntimeException */ public function signal($signal) { // Log all signals sent to the daemon. $this->getLogger()->debug('Received signal: ' . $signal); // Let's make sure we have an application instance. if (!is_subclass_of($this, __CLASS__)) { $this->getLogger()->emergency('Cannot find the application instance.'); throw new \RuntimeException('Cannot find the application instance.'); } // @event onReceiveSignal switch ($signal) { case SIGINT: case SIGTERM: // Handle shutdown tasks if ($this->running && $this->isActive()) { $this->shutdown(); } else { $this->close(); } break; case SIGHUP: // Handle restart tasks if ($this->running && $this->isActive()) { $this->shutdown(true); } else { $this->close(); } break; case SIGCHLD: // A child process has died while ($this->pcntlWait($signal, WNOHANG || WUNTRACED) > 0) { usleep(1000); } break; case SIGCLD: while ($this->pcntlWait($signal, WNOHANG) > 0) { $signal = $this->pcntlChildExitStatus($signal); } break; default: break; } } /** * Check to see if the daemon is active. This does not assume that $this daemon is active, but * only if an instance of the application is active as a daemon. * * @return boolean True if daemon is active. * * @since 1.0 */ public function isActive() { // Get the process id file location for the application. $pidFile = $this->get('application_pid_file'); // If the process id file doesn't exist then the daemon is obviously not running. if (!is_file($pidFile)) { return false; } // Read the contents of the process id file as an integer. $fp = fopen($pidFile, 'r'); $pid = fread($fp, filesize($pidFile)); $pid = (int) $pid; fclose($fp); // Check to make sure that the process id exists as a positive integer. if (!$pid) { return false; } // Check to make sure the process is active by pinging it and ensure it responds. if (!posix_kill($pid, 0)) { // No response so remove the process id file and log the situation. @ unlink($pidFile); $this->getLogger()->warning('The process found based on PID file was unresponsive.'); return false; } return true; } /** * Load an object or array into the application configuration object. * * @param mixed $data Either an array or object to be loaded into the configuration object. * * @return AbstractDaemonApplication Instance of $this to allow chaining. * * @since 1.0 */ public function loadConfiguration($data) { /* * Setup some application metadata options. This is useful if we ever want to write out startup scripts * or just have some sort of information available to share about things. */ // The application author name. This string is used in generating startup scripts and has // a maximum of 50 characters. $tmp = (string) $this->get('author_name', 'Joomla Framework'); $this->set('author_name', (\strlen($tmp) > 50) ? substr($tmp, 0, 50) : $tmp); // The application author email. This string is used in generating startup scripts. $tmp = (string) $this->get('author_email', 'admin@joomla.org'); $this->set('author_email', filter_var($tmp, FILTER_VALIDATE_EMAIL)); // The application name. This string is used in generating startup scripts. $tmp = (string) $this->get('application_name', 'JApplicationDaemon'); $this->set('application_name', (string) preg_replace('/[^A-Z0-9_-]/i', '', $tmp)); // The application description. This string is used in generating startup scripts. $tmp = (string) $this->get('application_description', 'A generic Joomla Framework application.'); $this->set('application_description', filter_var($tmp, FILTER_SANITIZE_STRING)); /* * Setup the application path options. This defines the default executable name, executable directory, * and also the path to the daemon process id file. */ // The application executable daemon. This string is used in generating startup scripts. $tmp = (string) $this->get('application_executable', basename($this->input->executable)); $this->set('application_executable', $tmp); // The home directory of the daemon. $tmp = (string) $this->get('application_directory', \dirname($this->input->executable)); $this->set('application_directory', $tmp); // The pid file location. This defaults to a path inside the /tmp directory. $name = $this->get('application_name'); $tmp = (string) $this->get('application_pid_file', strtolower('/tmp/' . $name . '/' . $name . '.pid')); $this->set('application_pid_file', $tmp); /* * Setup the application identity options. It is important to remember if the default of 0 is set for * either UID or GID then changing that setting will not be attempted as there is no real way to "change" * the identity of a process from some user to root. */ // The user id under which to run the daemon. $tmp = (int) $this->get('application_uid', 0); $options = array('options' => array('min_range' => 0, 'max_range' => 65000)); $this->set('application_uid', filter_var($tmp, FILTER_VALIDATE_INT, $options)); // The group id under which to run the daemon. $tmp = (int) $this->get('application_gid', 0); $options = array('options' => array('min_range' => 0, 'max_range' => 65000)); $this->set('application_gid', filter_var($tmp, FILTER_VALIDATE_INT, $options)); // Option to kill the daemon if it cannot switch to the chosen identity. $tmp = (bool) $this->get('application_require_identity', 1); $this->set('application_require_identity', $tmp); /* * Setup the application runtime options. By default our execution time limit is infinite obviously * because a daemon should be constantly running unless told otherwise. The default limit for memory * usage is 128M, which admittedly is a little high, but remember it is a "limit" and PHP's memory * management leaves a bit to be desired :-) */ // The maximum execution time of the application in seconds. Zero is infinite. $tmp = $this->get('max_execution_time'); if ($tmp !== null) { $this->set('max_execution_time', (int) $tmp); } // The maximum amount of memory the application can use. $tmp = $this->get('max_memory_limit', '256M'); if ($tmp !== null) { $this->set('max_memory_limit', (string) $tmp); } return $this; } /** * Execute the daemon. * * @return void * * @since 1.0 */ public function execute() { // @event onBeforeExecute // Enable basic garbage collection. gc_enable(); $this->getLogger()->info('Starting ' . $this->name); // Set off the process for becoming a daemon. if ($this->daemonize()) { // Declare ticks to start signal monitoring. When you declare ticks, PCNTL will monitor // incoming signals after each tick and call the relevant signal handler automatically. declare(ticks = 1); // Start the main execution loop. while (true) { // Perform basic garbage collection. $this->gc(); // Don't completely overload the CPU. usleep(1000); // Execute the main application logic. $this->doExecute(); } } else { // We were not able to daemonize the application so log the failure and die gracefully. $this->getLogger()->info('Starting ' . $this->name . ' failed'); } // @event onAfterExecute } /** * Restart daemon process. * * @return void * * @codeCoverageIgnore * @since 1.0 */ public function restart() { $this->getLogger()->info('Stopping ' . $this->name); $this->shutdown(true); } /** * Stop daemon process. * * @return void * * @codeCoverageIgnore * @since 1.0 */ public function stop() { $this->getLogger()->info('Stopping ' . $this->name); $this->shutdown(); } /** * Method to change the identity of the daemon process and resources. * * @return boolean True if identity successfully changed * * @since 1.0 * @see posix_setuid() */ protected function changeIdentity() { // Get the group and user ids to set for the daemon. $uid = (int) $this->get('application_uid', 0); $gid = (int) $this->get('application_gid', 0); // Get the application process id file path. $file = $this->get('application_pid_file'); // Change the user id for the process id file if necessary. if ($uid && (fileowner($file) != $uid) && (!@ chown($file, $uid))) { $this->getLogger()->error('Unable to change user ownership of the process id file.'); return false; } // Change the group id for the process id file if necessary. if ($gid && (filegroup($file) != $gid) && (!@ chgrp($file, $gid))) { $this->getLogger()->error('Unable to change group ownership of the process id file.'); return false; } // Set the correct home directory for the process. if ($uid && ($info = posix_getpwuid($uid)) && is_dir($info['dir'])) { system('export HOME="' . $info['dir'] . '"'); } // Change the user id for the process necessary. if ($uid && (posix_getuid($file) != $uid) && (!@ posix_setuid($uid))) { $this->getLogger()->error('Unable to change user ownership of the proccess.'); return false; } // Change the group id for the process necessary. if ($gid && (posix_getgid($file) != $gid) && (!@ posix_setgid($gid))) { $this->getLogger()->error('Unable to change group ownership of the proccess.'); return false; } // Get the user and group information based on uid and gid. $user = posix_getpwuid($uid); $group = posix_getgrgid($gid); $this->getLogger()->info('Changed daemon identity to ' . $user['name'] . ':' . $group['name']); return true; } /** * Method to put the application into the background. * * @return boolean * * @since 1.0 * @throws \RuntimeException */ protected function daemonize() { // Is there already an active daemon running? if ($this->isActive()) { $this->getLogger()->emergency($this->name . ' daemon is still running. Exiting the application.'); return false; } // Reset Process Information $this->safeMode = !!@ ini_get('safe_mode'); $this->processId = 0; $this->running = false; // Detach process! try { // Check if we should run in the foreground. if (!$this->input->get('f')) { // Detach from the terminal. $this->detach(); } else { // Setup running values. $this->exiting = false; $this->running = true; // Set the process id. $this->processId = (int) posix_getpid(); $this->parentId = $this->processId; } } catch (\RuntimeException $e) { $this->getLogger()->emergency('Unable to fork.'); return false; } // Verify the process id is valid. if ($this->processId < 1) { $this->getLogger()->emergency('The process id is invalid; the fork failed.'); return false; } // Clear the umask. @ umask(0); // Write out the process id file for concurrency management. if (!$this->writeProcessIdFile()) { $this->getLogger()->emergency('Unable to write the pid file at: ' . $this->get('application_pid_file')); return false; } // Attempt to change the identity of user running the process. if (!$this->changeIdentity()) { // If the identity change was required then we need to return false. if ($this->get('application_require_identity')) { $this->getLogger()->critical('Unable to change process owner.'); return false; } $this->getLogger()->warning('Unable to change process owner.'); } // Setup the signal handlers for the daemon. if (!$this->setupSignalHandlers()) { return false; } // Change the current working directory to the application working directory. @ chdir($this->get('application_directory')); return true; } /** * This is truly where the magic happens. This is where we fork the process and kill the parent * process, which is essentially what turns the application into a daemon. * * @return void * * @since 1.0 * @throws \RuntimeException */ protected function detach() { $this->getLogger()->debug('Detaching the ' . $this->name . ' daemon.'); // Attempt to fork the process. $pid = $this->fork(); // If the pid is positive then we successfully forked, and can close this application. if ($pid) { // Add the log entry for debugging purposes and exit gracefully. $this->getLogger()->debug('Ending ' . $this->name . ' parent process'); $this->close(); } else { // We are in the forked child process. // Setup some protected values. $this->exiting = false; $this->running = true; // Set the parent to self. $this->parentId = $this->processId; } } /** * Method to fork the process. * * @return integer The child process id to the parent process, zero to the child process. * * @since 1.0 * @throws \RuntimeException */ protected function fork() { // Attempt to fork the process. $pid = $this->pcntlFork(); // If the fork failed, throw an exception. if ($pid === -1) { throw new \RuntimeException('The process could not be forked.'); } if ($pid === 0) { // Update the process id for the child. $this->processId = (int) posix_getpid(); } else { // Log the fork in the parent. $this->getLogger()->debug('Process forked ' . $pid); } // Trigger the onFork event. $this->postFork(); return $pid; } /** * Method to perform basic garbage collection and memory management in the sense of clearing the * stat cache. We will probably call this method pretty regularly in our main loop. * * @return void * * @codeCoverageIgnore * @since 1.0 */ protected function gc() { // Perform generic garbage collection. gc_collect_cycles(); // Clear the stat cache so it doesn't blow up memory. clearstatcache(); } /** * Method to attach the AbstractDaemonApplication signal handler to the known signals. Applications * can override these handlers by using the pcntl_signal() function and attaching a different * callback method. * * @return boolean * * @since 1.0 * @see pcntl_signal() */ protected function setupSignalHandlers() { // We add the error suppression for the loop because on some platforms some constants are not defined. foreach (self::$signals as $signal) { // Ignore signals that are not defined. if (!\defined($signal) || !\is_int(\constant($signal)) || (\constant($signal) === 0)) { // Define the signal to avoid notices. $this->getLogger()->debug('Signal "' . $signal . '" not defined. Defining it as null.'); \define($signal, null); // Don't listen for signal. continue; } // Attach the signal handler for the signal. if (!$this->pcntlSignal(\constant($signal), array($this, 'signal'))) { $this->getLogger()->emergency(sprintf('Unable to reroute signal handler: %s', $signal)); return false; } } return true; } /** * Method to shut down the daemon and optionally restart it. * * @param boolean $restart True to restart the daemon on exit. * * @return void * * @since 1.0 */ protected function shutdown($restart = false) { // If we are already exiting, chill. if ($this->exiting) { return; } // If not, now we are. $this->exiting = true; // If we aren't already daemonized then just kill the application. if (!$this->running && !$this->isActive()) { $this->getLogger()->info('Process was not daemonized yet, just halting current process'); $this->close(); } // Only read the pid for the parent file. if ($this->parentId == $this->processId) { // Read the contents of the process id file as an integer. $fp = fopen($this->get('application_pid_file'), 'r'); $pid = fread($fp, filesize($this->get('application_pid_file'))); $pid = (int) $pid; fclose($fp); // Remove the process id file. @ unlink($this->get('application_pid_file')); // If we are supposed to restart the daemon we need to execute the same command. if ($restart) { $this->close(exec(implode(' ', $GLOBALS['argv']) . ' > /dev/null &')); } else { // If we are not supposed to restart the daemon let's just kill -9. passthru('kill -9 ' . $pid); $this->close(); } } } /** * Method to write the process id file out to disk. * * @return boolean * * @since 1.0 */ protected function writeProcessIdFile() { // Verify the process id is valid. if ($this->processId < 1) { $this->getLogger()->emergency('The process id is invalid.'); return false; } // Get the application process id file path. $file = $this->get('application_pid_file'); if (empty($file)) { $this->getLogger()->error('The process id file path is empty.'); return false; } // Make sure that the folder where we are writing the process id file exists. $folder = \dirname($file); if (!is_dir($folder) && !@ mkdir($folder, $this->get('folder_permission', 0755))) { $this->getLogger()->error('Unable to create directory: ' . $folder); return false; } // Write the process id file out to disk. if (!file_put_contents($file, $this->processId)) { $this->getLogger()->error('Unable to write proccess id file: ' . $file); return false; } // Make sure the permissions for the proccess id file are accurate. if (!chmod($file, $this->get('file_permission', 0644))) { $this->getLogger()->error('Unable to adjust permissions for the proccess id file: ' . $file); return false; } return true; } /** * Method to handle post-fork triggering of the onFork event. * * @return void * * @since 1.0 */ protected function postFork() { // @event onFork } /** * Method to return the exit code of a terminated child process. * * @param integer $status The status parameter is the status parameter supplied to a successful call to pcntl_waitpid(). * * @return integer The child process exit code. * * @codeCoverageIgnore * @see pcntl_wexitstatus() * @since 1.0 */ protected function pcntlChildExitStatus($status) { return pcntl_wexitstatus($status); } /** * Method to return the exit code of a terminated child process. * * @return integer On success, the PID of the child process is returned in the parent's thread * of execution, and a 0 is returned in the child's thread of execution. On * failure, a -1 will be returned in the parent's context, no child process * will be created, and a PHP error is raised. * * @codeCoverageIgnore * @see pcntl_fork() * @since 1.0 */ protected function pcntlFork() { return pcntl_fork(); } /** * Method to install a signal handler. * * @param integer $signal The signal number. * @param callable $handler The signal handler which may be the name of a user created function, * or method, or either of the two global constants SIG_IGN or SIG_DFL. * @param boolean $restart Specifies whether system call restarting should be used when this * signal arrives. * * @return boolean True on success. * * @codeCoverageIgnore * @see pcntl_signal() * @since 1.0 */ protected function pcntlSignal($signal, $handler, $restart = true) { return pcntl_signal($signal, $handler, $restart); } /** * Method to wait on or return the status of a forked child. * * @param integer $status Status information. * @param integer $options If wait3 is available on your system (mostly BSD-style systems), * you can provide the optional options parameter. * * @return integer The process ID of the child which exited, -1 on error or zero if WNOHANG * was provided as an option (on wait3-available systems) and no child was available. * * @codeCoverageIgnore * @see pcntl_wait() * @since 1.0 */ protected function pcntlWait(&$status, $options = 0) { return pcntl_wait($status, $options); } } src/AbstractCliApplication.php 0000604 00000007531 15245622151 0012430 0 ustar 00 <?php /** * Part of the Joomla Framework Application Package * * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Application; use Joomla\Input; use Joomla\Registry\Registry; /** * Base class for a Joomla! command line application. * * @since 1.0 * @deprecated 2.0 Use the `joomla/console` package instead */ abstract class AbstractCliApplication extends AbstractApplication { /** * Output object * * @var Cli\CliOutput * @since 1.0 */ protected $output; /** * CLI Input object * * @var Cli\CliInput * @since 1.6.0 */ protected $cliInput; /** * Class constructor. * * @param Input\Cli $input An optional argument to provide dependency injection for the application's input object. If the * argument is an Input\Cli 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 Cli\CliOutput $output An optional argument to provide dependency injection for the application's output object. If the * argument is a Cli\CliOutput object that object will become the application's input object, otherwise * a default output object is created. * @param Cli\CliInput $cliInput An optional argument to provide dependency injection for the application's CLI input object. If the * argument is a Cli\CliInput object that object will become the application's input object, otherwise * a default input object is created. * * @since 1.0 */ public function __construct(Input\Cli $input = null, Registry $config = null, Cli\CliOutput $output = null, Cli\CliInput $cliInput = null) { // Close the application if we are not executed from the command line. // @codeCoverageIgnoreStart if (!\defined('STDOUT') || !\defined('STDIN') || !isset($_SERVER['argv'])) { $this->close(); } // @codeCoverageIgnoreEnd $this->output = ($output instanceof Cli\CliOutput) ? $output : new Cli\Output\Stdout; // Set the CLI input object. $this->cliInput = ($cliInput instanceof Cli\CliInput) ? $cliInput : new Cli\CliInput; // Call the constructor as late as possible (it runs `initialise`). parent::__construct($input instanceof Input\Input ? $input : new Input\Cli, $config); // Set the current directory. $this->set('cwd', getcwd()); } /** * Get an output object. * * @return Cli\CliOutput * * @since 1.0 */ public function getOutput() { return $this->output; } /** * Get a CLI input object. * * @return Cli\CliInput * * @since 1.6.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 AbstractCliApplication Instance of $this to allow chaining. * * @since 1.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 1.0 */ public function in() { return $this->getCliInput()->in(); } } src/AbstractApplication.php 0000604 00000011254 15245622151 0011775 0 ustar 00 <?php /** * Part of the Joomla Framework Application Package * * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Application; use Joomla\Input\Input; use Joomla\Registry\Registry; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; /** * Joomla Framework Base Application Class * * @since 1.0 */ abstract class AbstractApplication implements LoggerAwareInterface { /** * The application configuration object. * * @var Registry * @since 1.0 */ protected $config; /** * The application input object. * * @var Input * @since 1.0 */ public $input; /** * A logger. * * @var LoggerInterface * @since 1.0 */ private $logger; /** * Class constructor. * * @param Input $input An optional argument to provide dependency injection for the application's input object. If the argument is an * 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 1.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; // Set the execution datetime and timestamp; $this->set('execution.datetime', gmdate('Y-m-d H:i:s')); $this->set('execution.timestamp', time()); $this->set('execution.microtimestamp', microtime(true)); $this->initialise(); } /** * Method to close the application. * * @param integer $code The exit code (optional; default is 0). * * @return void * * @codeCoverageIgnore * @since 1.0 */ public function close($code = 0) { exit($code); } /** * Method to run the application routines. Most likely you will want to instantiate a controller * and execute it, or perform some sort of task directly. * * @return mixed * * @since 1.0 */ abstract protected function doExecute(); /** * Execute the application. * * @return void * * @since 1.0 */ public function execute() { // @event onBeforeExecute // Perform application routines. $this->doExecute(); // @event onAfterExecute } /** * Returns a property of the object or the default value if the property is not set. * * @param string $key The name of the property. * @param mixed $default The default value (optional) if none is set. * * @return mixed The value of the configuration. * * @since 1.0 */ public function get($key, $default = null) { return $this->config->get($key, $default); } /** * Get the logger. * * @return LoggerInterface * * @since 1.0 */ public function getLogger() { // If a logger hasn't been set, use NullLogger if (! ($this->logger instanceof LoggerInterface)) { $this->logger = new NullLogger; } return $this->logger; } /** * Custom initialisation method. * * Called at the end of the AbstractApplication::__construct method. * This is for developers to inject initialisation code for their application classes. * * @return void * * @codeCoverageIgnore * @since 1.0 */ protected function initialise() { } /** * Modifies a property of the object, creating it if it does not already exist. * * @param string $key The name of the property. * @param mixed $value The value of the property to set (optional). * * @return mixed Previous value of the property * * @since 1.0 */ public function set($key, $value = null) { $previous = $this->config->get($key); $this->config->set($key, $value); return $previous; } /** * Sets the configuration for the application. * * @param Registry $config A registry object holding the configuration. * * @return AbstractApplication Returns itself to support chaining. * * @since 1.0 */ public function setConfiguration(Registry $config) { $this->config = $config; return $this; } /** * Set the logger. * * @param LoggerInterface $logger The logger. * * @return AbstractApplication Returns itself to support chaining. * * @since 1.0 */ public function setLogger(LoggerInterface $logger) { $this->logger = $logger; return $this; } } src/Web/WebClient.php 0000604 00000041074 15245622151 0010442 0 ustar 00 <?php /** * Part of the Joomla Framework Application Package * * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Application\Web; /** * Class to model a Web Client. * * @property-read integer $platform The detected platform on which the web client runs. * @property-read boolean $mobile True if the web client is a mobile device. * @property-read integer $engine The detected rendering engine used by the web client. * @property-read integer $browser The detected browser used by the web client. * @property-read string $browserVersion The detected browser version used by the web client. * @property-read array $languages The priority order detected accepted languages for the client. * @property-read array $encodings The priority order detected accepted encodings for the client. * @property-read string $userAgent The web client's user agent string. * @property-read string $acceptEncoding The web client's accepted encoding string. * @property-read string $acceptLanguage The web client's accepted languages string. * @property-read array $detection An array of flags determining whether or not a detection routine has been run. * @property-read boolean $robot True if the web client is a robot * @property-read array $headers An array of all headers sent by client * * @since 1.0 */ class WebClient { const WINDOWS = 1; const WINDOWS_PHONE = 2; const WINDOWS_CE = 3; const IPHONE = 4; const IPAD = 5; const IPOD = 6; const MAC = 7; const BLACKBERRY = 8; const ANDROID = 9; const LINUX = 10; const TRIDENT = 11; const WEBKIT = 12; const GECKO = 13; const PRESTO = 14; const KHTML = 15; const AMAYA = 16; const IE = 17; const FIREFOX = 18; const CHROME = 19; const SAFARI = 20; const OPERA = 21; const ANDROIDTABLET = 22; const EDGE = 23; const BLINK = 24; const EDG = 25; /** * @var integer The detected platform on which the web client runs. * @since 1.0 */ protected $platform; /** * @var boolean True if the web client is a mobile device. * @since 1.0 */ protected $mobile = false; /** * @var integer The detected rendering engine used by the web client. * @since 1.0 */ protected $engine; /** * @var integer The detected browser used by the web client. * @since 1.0 */ protected $browser; /** * @var string The detected browser version used by the web client. * @since 1.0 */ protected $browserVersion; /** * @var array The priority order detected accepted languages for the client. * @since 1.0 */ protected $languages = array(); /** * @var array The priority order detected accepted encodings for the client. * @since 1.0 */ protected $encodings = array(); /** * @var string The web client's user agent string. * @since 1.0 */ protected $userAgent; /** * @var string The web client's accepted encoding string. * @since 1.0 */ protected $acceptEncoding; /** * @var string The web client's accepted languages string. * @since 1.0 */ protected $acceptLanguage; /** * @var boolean True if the web client is a robot. * @since 1.0 */ protected $robot = false; /** * @var array An array of flags determining whether or not a detection routine has been run. * @since 1.0 */ protected $detection = array(); /** * @var array An array of headers sent by client * @since 1.3.0 */ protected $headers; /** * Class constructor. * * @param string $userAgent The optional user-agent string to parse. * @param string $acceptEncoding The optional client accept encoding string to parse. * @param string $acceptLanguage The optional client accept language string to parse. * * @since 1.0 */ public function __construct($userAgent = null, $acceptEncoding = null, $acceptLanguage = null) { // If no explicit user agent string was given attempt to use the implicit one from server environment. if (empty($userAgent) && isset($_SERVER['HTTP_USER_AGENT'])) { $this->userAgent = $_SERVER['HTTP_USER_AGENT']; } else { $this->userAgent = $userAgent; } // If no explicit acceptable encoding string was given attempt to use the implicit one from server environment. if (empty($acceptEncoding) && isset($_SERVER['HTTP_ACCEPT_ENCODING'])) { $this->acceptEncoding = $_SERVER['HTTP_ACCEPT_ENCODING']; } else { $this->acceptEncoding = $acceptEncoding; } // If no explicit acceptable languages string was given attempt to use the implicit one from server environment. if (empty($acceptLanguage) && isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { $this->acceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE']; } else { $this->acceptLanguage = $acceptLanguage; } } /** * Magic method to get an object property's value by name. * * @param string $name Name of the property for which to return a value. * * @return mixed The requested value if it exists. * * @since 1.0 */ public function __get($name) { switch ($name) { case 'mobile': case 'platform': if (empty($this->detection['platform'])) { $this->detectPlatform($this->userAgent); } break; case 'engine': if (empty($this->detection['engine'])) { $this->detectEngine($this->userAgent); } break; case 'browser': case 'browserVersion': if (empty($this->detection['browser'])) { $this->detectBrowser($this->userAgent); } break; case 'languages': if (empty($this->detection['acceptLanguage'])) { $this->detectLanguage($this->acceptLanguage); } break; case 'encodings': if (empty($this->detection['acceptEncoding'])) { $this->detectEncoding($this->acceptEncoding); } break; case 'robot': if (empty($this->detection['robot'])) { $this->detectRobot($this->userAgent); } break; case 'headers': if (empty($this->detection['headers'])) { $this->detectHeaders(); } break; } // Return the property if it exists. if (isset($this->$name)) { return $this->$name; } } /** * Detects the client browser and version in a user agent string. * * @param string $userAgent The user-agent string to parse. * * @return void * * @since 1.0 */ protected function detectBrowser($userAgent) { // Attempt to detect the browser type. Obviously we are only worried about major browsers. if ((stripos($userAgent, 'MSIE') !== false) && (stripos($userAgent, 'Opera') === false)) { $this->browser = self::IE; $patternBrowser = 'MSIE'; } elseif (stripos($userAgent, 'Trident') !== false) { $this->browser = self::IE; $patternBrowser = ' rv'; } elseif (stripos($userAgent, 'Edge') !== false) { $this->browser = self::EDGE; $patternBrowser = 'Edge'; } elseif (stripos($userAgent, 'Edg') !== false) { $this->browser = self::EDG; $patternBrowser = 'Edg'; } elseif ((stripos($userAgent, 'Firefox') !== false) && (stripos($userAgent, 'like Firefox') === false)) { $this->browser = self::FIREFOX; $patternBrowser = 'Firefox'; } elseif (stripos($userAgent, 'OPR') !== false) { $this->browser = self::OPERA; $patternBrowser = 'OPR'; } elseif (stripos($userAgent, 'Chrome') !== false) { $this->browser = self::CHROME; $patternBrowser = 'Chrome'; } elseif (stripos($userAgent, 'Safari') !== false) { $this->browser = self::SAFARI; $patternBrowser = 'Safari'; } elseif (stripos($userAgent, 'Opera') !== false) { $this->browser = self::OPERA; $patternBrowser = 'Opera'; } // If we detected a known browser let's attempt to determine the version. if ($this->browser) { // Build the REGEX pattern to match the browser version string within the user agent string. $pattern = '#(?<browser>Version|' . $patternBrowser . ')[/ :]+(?<version>[0-9.|a-zA-Z.]*)#'; // Attempt to find version strings in the user agent string. $matches = array(); if (preg_match_all($pattern, $userAgent, $matches)) { // Do we have both a Version and browser match? if (\count($matches['browser']) == 2) { // See whether Version or browser came first, and use the number accordingly. if (strripos($userAgent, 'Version') < strripos($userAgent, $patternBrowser)) { $this->browserVersion = $matches['version'][0]; } else { $this->browserVersion = $matches['version'][1]; } } elseif (\count($matches['browser']) > 2) { $key = array_search('Version', $matches['browser']); if ($key) { $this->browserVersion = $matches['version'][$key]; } } else { // We only have a Version or a browser so use what we have. $this->browserVersion = $matches['version'][0]; } } } // Mark this detection routine as run. $this->detection['browser'] = true; } /** * Method to detect the accepted response encoding by the client. * * @param string $acceptEncoding The client accept encoding string to parse. * * @return void * * @since 1.0 */ protected function detectEncoding($acceptEncoding) { // Parse the accepted encodings. $this->encodings = array_map('trim', (array) explode(',', $acceptEncoding)); // Mark this detection routine as run. $this->detection['acceptEncoding'] = true; } /** * Detects the client rendering engine in a user agent string. * * @param string $userAgent The user-agent string to parse. * * @return void * * @since 1.0 */ protected function detectEngine($userAgent) { if (stripos($userAgent, 'MSIE') !== false || stripos($userAgent, 'Trident') !== false) { // Attempt to detect the client engine -- starting with the most popular ... for now. $this->engine = self::TRIDENT; } elseif (stripos($userAgent, 'Edge') !== false || stripos($userAgent, 'EdgeHTML') !== false) { $this->engine = self::EDGE; } elseif (stripos($userAgent, 'Edg') !== false) { $this->engine = self::BLINK; } elseif (stripos($userAgent, 'Chrome') !== false) { $result = explode('/', stristr($userAgent, 'Chrome')); $version = explode(' ', $result[1]); if ($version[0] >= 28) { $this->engine = self::BLINK; } else { $this->engine = self::WEBKIT; } } elseif (stripos($userAgent, 'AppleWebKit') !== false || stripos($userAgent, 'blackberry') !== false) { if (stripos($userAgent, 'AppleWebKit') !== false) { $result = explode('/', stristr($userAgent, 'AppleWebKit')); $version = explode(' ', $result[1]); if ($version[0] === 537.36) { // AppleWebKit/537.36 is Blink engine specific, exception is Blink emulated IEMobile, Trident or Edge $this->engine = self::BLINK; } } // Evidently blackberry uses WebKit and doesn't necessarily report it. Bad RIM. $this->engine = self::WEBKIT; } elseif (stripos($userAgent, 'Gecko') !== false && stripos($userAgent, 'like Gecko') === false) { // We have to check for like Gecko because some other browsers spoof Gecko. $this->engine = self::GECKO; } elseif (stripos($userAgent, 'Opera') !== false || stripos($userAgent, 'Presto') !== false) { $version = false; if (preg_match('/Opera[\/| ]?([0-9.]+)/u', $userAgent, $match)) { $version = \floatval($match[1]); } if (preg_match('/Version\/([0-9.]+)/u', $userAgent, $match)) { if (\floatval($match[1]) >= 10) { $version = \floatval($match[1]); } } if ($version !== false && $version >= 15) { $this->engine = self::BLINK; } else { $this->engine = self::PRESTO; } } elseif (stripos($userAgent, 'KHTML') !== false) { // *sigh* $this->engine = self::KHTML; } elseif (stripos($userAgent, 'Amaya') !== false) { // Lesser known engine but it finishes off the major list from Wikipedia :-) $this->engine = self::AMAYA; } // Mark this detection routine as run. $this->detection['engine'] = true; } /** * Method to detect the accepted languages by the client. * * @param mixed $acceptLanguage The client accept language string to parse. * * @return void * * @since 1.0 */ protected function detectLanguage($acceptLanguage) { // Parse the accepted encodings. $this->languages = array_map('trim', (array) explode(',', $acceptLanguage)); // Mark this detection routine as run. $this->detection['acceptLanguage'] = true; } /** * Detects the client platform in a user agent string. * * @param string $userAgent The user-agent string to parse. * * @return void * * @since 1.0 */ protected function detectPlatform($userAgent) { // Attempt to detect the client platform. if (stripos($userAgent, 'Windows') !== false) { $this->platform = self::WINDOWS; // Let's look at the specific mobile options in the Windows space. if (stripos($userAgent, 'Windows Phone') !== false) { $this->mobile = true; $this->platform = self::WINDOWS_PHONE; } elseif (stripos($userAgent, 'Windows CE') !== false) { $this->mobile = true; $this->platform = self::WINDOWS_CE; } } elseif (stripos($userAgent, 'iPhone') !== false) { // Interestingly 'iPhone' is present in all iOS devices so far including iPad and iPods. $this->mobile = true; $this->platform = self::IPHONE; // Let's look at the specific mobile options in the iOS space. if (stripos($userAgent, 'iPad') !== false) { $this->platform = self::IPAD; } elseif (stripos($userAgent, 'iPod') !== false) { $this->platform = self::IPOD; } } elseif (stripos($userAgent, 'iPad') !== false) { // In case where iPhone is not mentioned in iPad user agent string $this->mobile = true; $this->platform = self::IPAD; } elseif (stripos($userAgent, 'iPod') !== false) { // In case where iPhone is not mentioned in iPod user agent string $this->mobile = true; $this->platform = self::IPOD; } elseif (preg_match('/macintosh|mac os x/i', $userAgent)) { // This has to come after the iPhone check because mac strings are also present in iOS devices. $this->platform = self::MAC; } elseif (stripos($userAgent, 'Blackberry') !== false) { $this->mobile = true; $this->platform = self::BLACKBERRY; } elseif (stripos($userAgent, 'Android') !== false) { $this->mobile = true; $this->platform = self::ANDROID; /** * Attempt to distinguish between Android phones and tablets * There is no totally foolproof method but certain rules almost always hold * Android 3.x is only used for tablets * Some devices and browsers encourage users to change their UA string to include Tablet. * Google encourages manufacturers to exclude the string Mobile from tablet device UA strings. * In some modes Kindle Android devices include the string Mobile but they include the string Silk. */ if (stripos($userAgent, 'Android 3') !== false || stripos($userAgent, 'Tablet') !== false || stripos($userAgent, 'Mobile') === false || stripos($userAgent, 'Silk') !== false) { $this->platform = self::ANDROIDTABLET; } } elseif (stripos($userAgent, 'Linux') !== false) { $this->platform = self::LINUX; } // Mark this detection routine as run. $this->detection['platform'] = true; } /** * Determines if the browser is a robot or not. * * @param string $userAgent The user-agent string to parse. * * @return void * * @since 1.0 */ protected function detectRobot($userAgent) { if (preg_match('/http|bot|bingbot|googlebot|robot|spider|slurp|crawler|curl|^$/i', $userAgent)) { $this->robot = true; } else { $this->robot = false; } $this->detection['robot'] = true; } /** * Fills internal array of headers * * @return void * * @since 1.3.0 */ protected function detectHeaders() { if (\function_exists('getallheaders')) { // If php is working under Apache, there is a special function $this->headers = getallheaders(); } else { // Else we fill headers from $_SERVER variable $this->headers = array(); foreach ($_SERVER as $name => $value) { if (substr($name, 0, 5) == 'HTTP_') { $this->headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value; } } } // Mark this detection routine as run. $this->detection['headers'] = true; } }
| ver. 1.4 |
Github
|
.
| PHP 8.1.34 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка