[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * Joomla! Content Management System 5 * 6 * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> 7 * @license GNU General Public License version 2 or later; see LICENSE.txt 8 */ 9 10 namespace Joomla\CMS\Application; 11 12 use Joomla\Application\SessionAwareWebApplicationTrait; 13 use Joomla\Application\Web\WebClient; 14 use Joomla\CMS\Authentication\Authentication; 15 use Joomla\CMS\Component\ComponentHelper; 16 use Joomla\CMS\Event\AbstractEvent; 17 use Joomla\CMS\Event\ErrorEvent; 18 use Joomla\CMS\Exception\ExceptionHandler; 19 use Joomla\CMS\Extension\ExtensionManagerTrait; 20 use Joomla\CMS\Factory; 21 use Joomla\CMS\Filter\InputFilter; 22 use Joomla\CMS\Input\Input; 23 use Joomla\CMS\Language\Language; 24 use Joomla\CMS\Language\Text; 25 use Joomla\CMS\Log\Log; 26 use Joomla\CMS\Menu\AbstractMenu; 27 use Joomla\CMS\Menu\MenuFactoryInterface; 28 use Joomla\CMS\Pathway\Pathway; 29 use Joomla\CMS\Plugin\PluginHelper; 30 use Joomla\CMS\Profiler\Profiler; 31 use Joomla\CMS\Router\Route; 32 use Joomla\CMS\Router\Router; 33 use Joomla\CMS\Session\MetadataManager; 34 use Joomla\CMS\Session\Session; 35 use Joomla\CMS\Uri\Uri; 36 use Joomla\DI\Container; 37 use Joomla\DI\ContainerAwareInterface; 38 use Joomla\DI\ContainerAwareTrait; 39 use Joomla\Registry\Registry; 40 use Joomla\String\StringHelper; 41 42 // phpcs:disable PSR1.Files.SideEffects 43 \defined('JPATH_PLATFORM') or die; 44 // phpcs:enable PSR1.Files.SideEffects 45 46 /** 47 * Joomla! CMS Application class 48 * 49 * @since 3.2 50 */ 51 abstract class CMSApplication extends WebApplication implements ContainerAwareInterface, CMSWebApplicationInterface 52 { 53 use ContainerAwareTrait; 54 use ExtensionManagerTrait; 55 use ExtensionNamespaceMapper; 56 use SessionAwareWebApplicationTrait; 57 58 /** 59 * Array of options for the \JDocument object 60 * 61 * @var array 62 * @since 3.2 63 */ 64 protected $docOptions = array(); 65 66 /** 67 * Application instances container. 68 * 69 * @var CmsApplication[] 70 * @since 3.2 71 */ 72 protected static $instances = array(); 73 74 /** 75 * The scope of the application. 76 * 77 * @var string 78 * @since 3.2 79 */ 80 public $scope = null; 81 82 /** 83 * The client identifier. 84 * 85 * @var integer 86 * @since 4.0.0 87 */ 88 protected $clientId = null; 89 90 /** 91 * The application message queue. 92 * 93 * @var array 94 * @since 4.0.0 95 */ 96 protected $messageQueue = array(); 97 98 /** 99 * The name of the application. 100 * 101 * @var string 102 * @since 4.0.0 103 */ 104 protected $name = null; 105 106 /** 107 * The profiler instance 108 * 109 * @var Profiler 110 * @since 3.2 111 */ 112 protected $profiler = null; 113 114 /** 115 * Currently active template 116 * 117 * @var object 118 * @since 3.2 119 */ 120 protected $template = null; 121 122 /** 123 * The pathway object 124 * 125 * @var Pathway 126 * @since 4.0.0 127 */ 128 protected $pathway = null; 129 130 /** 131 * The authentication plugin type 132 * 133 * @var string 134 * @since 4.0.0 135 */ 136 protected $authenticationPluginType = 'authentication'; 137 138 /** 139 * Menu instances container. 140 * 141 * @var AbstractMenu[] 142 * @since 4.2.0 143 */ 144 protected $menus = []; 145 146 /** 147 * The menu factory 148 * 149 * @var MenuFactoryInterface 150 * 151 * @since 4.2.0 152 */ 153 private $menuFactory; 154 155 /** 156 * Class constructor. 157 * 158 * @param Input $input An optional argument to provide dependency injection for the application's input 159 * object. If the argument is a JInput object that object will become the 160 * application's input object, otherwise a default input object is created. 161 * @param Registry $config An optional argument to provide dependency injection for the application's config 162 * object. If the argument is a Registry object that object will become the 163 * application's config object, otherwise a default config object is created. 164 * @param WebClient $client An optional argument to provide dependency injection for the application's client 165 * object. If the argument is a WebClient object that object will become the 166 * application's client object, otherwise a default client object is created. 167 * @param Container $container Dependency injection container. 168 * 169 * @since 3.2 170 */ 171 public function __construct(Input $input = null, Registry $config = null, WebClient $client = null, Container $container = null) 172 { 173 $container = $container ?: new Container(); 174 $this->setContainer($container); 175 176 parent::__construct($input, $config, $client); 177 178 // If JDEBUG is defined, load the profiler instance 179 if (\defined('JDEBUG') && JDEBUG) { 180 $this->profiler = Profiler::getInstance('Application'); 181 } 182 183 // Enable sessions by default. 184 if ($this->config->get('session') === null) { 185 $this->config->set('session', true); 186 } 187 188 // Set the session default name. 189 if ($this->config->get('session_name') === null) { 190 $this->config->set('session_name', $this->getName()); 191 } 192 } 193 194 /** 195 * Checks the user session. 196 * 197 * If the session record doesn't exist, initialise it. 198 * If session is new, create session variables 199 * 200 * @return void 201 * 202 * @since 3.2 203 * @throws \RuntimeException 204 */ 205 public function checkSession() 206 { 207 $this->getContainer()->get(MetadataManager::class)->createOrUpdateRecord($this->getSession(), $this->getIdentity()); 208 } 209 210 /** 211 * Enqueue a system message. 212 * 213 * @param string $msg The message to enqueue. 214 * @param string $type The message type. Default is message. 215 * 216 * @return void 217 * 218 * @since 3.2 219 */ 220 public function enqueueMessage($msg, $type = self::MSG_INFO) 221 { 222 // Don't add empty messages. 223 if ($msg === null || trim($msg) === '') { 224 return; 225 } 226 227 $inputFilter = InputFilter::getInstance( 228 [], 229 [], 230 InputFilter::ONLY_BLOCK_DEFINED_TAGS, 231 InputFilter::ONLY_BLOCK_DEFINED_ATTRIBUTES 232 ); 233 234 // Build the message array and apply the HTML InputFilter with the default blacklist to the message 235 $message = array( 236 'message' => $inputFilter->clean($msg, 'html'), 237 'type' => $inputFilter->clean(strtolower($type), 'cmd'), 238 ); 239 240 // For empty queue, if messages exists in the session, enqueue them first. 241 $messages = $this->getMessageQueue(); 242 243 if (!\in_array($message, $this->messageQueue)) { 244 // Enqueue the message. 245 $this->messageQueue[] = $message; 246 } 247 } 248 249 /** 250 * Ensure several core system input variables are not arrays. 251 * 252 * @return void 253 * 254 * @since 3.9 255 */ 256 private function sanityCheckSystemVariables() 257 { 258 $input = $this->input; 259 260 // Get invalid input variables 261 $invalidInputVariables = array_filter( 262 array('option', 'view', 'format', 'lang', 'Itemid', 'template', 'templateStyle', 'task'), 263 function ($systemVariable) use ($input) { 264 return $input->exists($systemVariable) && is_array($input->getRaw($systemVariable)); 265 } 266 ); 267 268 // Unset invalid system variables 269 foreach ($invalidInputVariables as $systemVariable) { 270 $input->set($systemVariable, null); 271 } 272 273 // Abort when there are invalid variables 274 if ($invalidInputVariables) { 275 throw new \RuntimeException('Invalid input, aborting application.'); 276 } 277 } 278 279 /** 280 * Execute the application. 281 * 282 * @return void 283 * 284 * @since 3.2 285 */ 286 public function execute() 287 { 288 try { 289 $this->sanityCheckSystemVariables(); 290 $this->setupLogging(); 291 $this->createExtensionNamespaceMap(); 292 293 // Perform application routines. 294 $this->doExecute(); 295 296 // If we have an application document object, render it. 297 if ($this->document instanceof \Joomla\CMS\Document\Document) { 298 // Render the application output. 299 $this->render(); 300 } 301 302 // If gzip compression is enabled in configuration and the server is compliant, compress the output. 303 if ($this->get('gzip') && !ini_get('zlib.output_compression') && ini_get('output_handler') !== 'ob_gzhandler') { 304 $this->compress(); 305 306 // Trigger the onAfterCompress event. 307 $this->triggerEvent('onAfterCompress'); 308 } 309 } catch (\Throwable $throwable) { 310 /** @var ErrorEvent $event */ 311 $event = AbstractEvent::create( 312 'onError', 313 [ 314 'subject' => $throwable, 315 'eventClass' => ErrorEvent::class, 316 'application' => $this, 317 ] 318 ); 319 320 // Trigger the onError event. 321 $this->triggerEvent('onError', $event); 322 323 ExceptionHandler::handleException($event->getError()); 324 } 325 326 // Trigger the onBeforeRespond event. 327 $this->getDispatcher()->dispatch('onBeforeRespond'); 328 329 // Send the application response. 330 $this->respond(); 331 332 // Trigger the onAfterRespond event. 333 $this->getDispatcher()->dispatch('onAfterRespond'); 334 } 335 336 /** 337 * Check if the user is required to reset their password. 338 * 339 * If the user is required to reset their password will be redirected to the page that manage the password reset. 340 * 341 * @param string $option The option that manage the password reset 342 * @param string $view The view that manage the password reset 343 * @param string $layout The layout of the view that manage the password reset 344 * @param string $tasks Permitted tasks 345 * 346 * @return void 347 * 348 * @throws \Exception 349 */ 350 protected function checkUserRequireReset($option, $view, $layout, $tasks) 351 { 352 if (Factory::getUser()->get('requireReset', 0)) { 353 $redirect = false; 354 355 /* 356 * By default user profile edit page is used. 357 * That page allows you to change more than just the password and might not be the desired behavior. 358 * This allows a developer to override the page that manage the password reset. 359 * (can be configured using the file: configuration.php, or if extended, through the global configuration form) 360 */ 361 $name = $this->getName(); 362 363 if ($this->get($name . '_reset_password_override', 0)) { 364 $option = $this->get($name . '_reset_password_option', ''); 365 $view = $this->get($name . '_reset_password_view', ''); 366 $layout = $this->get($name . '_reset_password_layout', ''); 367 $tasks = $this->get($name . '_reset_password_tasks', ''); 368 } 369 370 $task = $this->input->getCmd('task', ''); 371 372 // Check task or option/view/layout 373 if (!empty($task)) { 374 $tasks = explode(',', $tasks); 375 376 // Check full task version "option/task" 377 if (array_search($this->input->getCmd('option', '') . '/' . $task, $tasks) === false) { 378 // Check short task version, must be on the same option of the view 379 if ($this->input->getCmd('option', '') !== $option || array_search($task, $tasks) === false) { 380 // Not permitted task 381 $redirect = true; 382 } 383 } 384 } else { 385 if ( 386 $this->input->getCmd('option', '') !== $option || $this->input->getCmd('view', '') !== $view 387 || $this->input->getCmd('layout', '') !== $layout 388 ) { 389 // Requested a different option/view/layout 390 $redirect = true; 391 } 392 } 393 394 if ($redirect) { 395 // Redirect to the profile edit page 396 $this->enqueueMessage(Text::_('JGLOBAL_PASSWORD_RESET_REQUIRED'), 'notice'); 397 398 $url = Route::_('index.php?option=' . $option . '&view=' . $view . '&layout=' . $layout, false); 399 400 // In the administrator we need a different URL 401 if (strtolower($name) === 'administrator') { 402 $user = Factory::getApplication()->getIdentity(); 403 $url = Route::_('index.php?option=' . $option . '&task=' . $view . '.' . $layout . '&id=' . $user->id, false); 404 } 405 406 $this->redirect($url); 407 } 408 } 409 } 410 411 /** 412 * Gets a configuration value. 413 * 414 * @param string $varname The name of the value to get. 415 * @param string $default Default value to return 416 * 417 * @return mixed The user state. 418 * 419 * @since 3.2 420 * @deprecated 5.0 Use get() instead 421 */ 422 public function getCfg($varname, $default = null) 423 { 424 try { 425 Log::add( 426 sprintf('%s() is deprecated and will be removed in 5.0. Use JFactory->getApplication()->get() instead.', __METHOD__), 427 Log::WARNING, 428 'deprecated' 429 ); 430 } catch (\RuntimeException $exception) { 431 // Informational log only 432 } 433 434 return $this->get($varname, $default); 435 } 436 437 /** 438 * Gets the client id of the current running application. 439 * 440 * @return integer A client identifier. 441 * 442 * @since 3.2 443 */ 444 public function getClientId() 445 { 446 return $this->clientId; 447 } 448 449 /** 450 * Returns a reference to the global CmsApplication object, only creating it if it doesn't already exist. 451 * 452 * This method must be invoked as: $web = CmsApplication::getInstance(); 453 * 454 * @param string $name The name (optional) of the CmsApplication class to instantiate. 455 * @param string $prefix The class name prefix of the object. 456 * @param Container $container An optional dependency injection container to inject into the application. 457 * 458 * @return CmsApplication 459 * 460 * @since 3.2 461 * @throws \RuntimeException 462 * @deprecated 5.0 Use \Joomla\CMS\Factory::getContainer()->get($name) instead 463 */ 464 public static function getInstance($name = null, $prefix = '\JApplication', Container $container = null) 465 { 466 if (empty(static::$instances[$name])) { 467 // Create a CmsApplication object. 468 $classname = $prefix . ucfirst($name); 469 470 if (!$container) { 471 $container = Factory::getContainer(); 472 } 473 474 if ($container->has($classname)) { 475 static::$instances[$name] = $container->get($classname); 476 } elseif (class_exists($classname)) { 477 // @todo This creates an implicit hard requirement on the ApplicationCms constructor 478 static::$instances[$name] = new $classname(null, null, null, $container); 479 } else { 480 throw new \RuntimeException(Text::sprintf('JLIB_APPLICATION_ERROR_APPLICATION_LOAD', $name), 500); 481 } 482 483 static::$instances[$name]->loadIdentity(Factory::getUser()); 484 } 485 486 return static::$instances[$name]; 487 } 488 489 /** 490 * Returns the application \JMenu object. 491 * 492 * @param string $name The name of the application/client. 493 * @param array $options An optional associative array of configuration settings. 494 * 495 * @return AbstractMenu 496 * 497 * @since 3.2 498 */ 499 public function getMenu($name = null, $options = array()) 500 { 501 if (!isset($name)) { 502 $name = $this->getName(); 503 } 504 505 // Inject this application object into the \JMenu tree if one isn't already specified 506 if (!isset($options['app'])) { 507 $options['app'] = $this; 508 } 509 510 if (array_key_exists($name, $this->menus)) { 511 return $this->menus[$name]; 512 } 513 514 if ($this->menuFactory === null) { 515 @trigger_error('Menu factory must be set in 5.0', E_USER_DEPRECATED); 516 $this->menuFactory = $this->getContainer()->get(MenuFactoryInterface::class); 517 } 518 519 $this->menus[$name] = $this->menuFactory->createMenu($name, $options); 520 521 // Make sure the abstract menu has the instance too, is needed for BC and will be removed with version 5 522 AbstractMenu::$instances[$name] = $this->menus[$name]; 523 524 return $this->menus[$name]; 525 } 526 527 /** 528 * Get the system message queue. 529 * 530 * @param boolean $clear Clear the messages currently attached to the application object 531 * 532 * @return array The system message queue. 533 * 534 * @since 3.2 535 */ 536 public function getMessageQueue($clear = false) 537 { 538 // For empty queue, if messages exists in the session, enqueue them. 539 if (!\count($this->messageQueue)) { 540 $sessionQueue = $this->getSession()->get('application.queue', []); 541 542 if ($sessionQueue) { 543 $this->messageQueue = $sessionQueue; 544 $this->getSession()->set('application.queue', []); 545 } 546 } 547 548 $messageQueue = $this->messageQueue; 549 550 if ($clear) { 551 $this->messageQueue = array(); 552 } 553 554 return $messageQueue; 555 } 556 557 /** 558 * Gets the name of the current running application. 559 * 560 * @return string The name of the application. 561 * 562 * @since 3.2 563 */ 564 public function getName() 565 { 566 return $this->name; 567 } 568 569 /** 570 * Returns the application Pathway object. 571 * 572 * @return Pathway 573 * 574 * @since 3.2 575 */ 576 public function getPathway() 577 { 578 if (!$this->pathway) { 579 $resourceName = ucfirst($this->getName()) . 'Pathway'; 580 581 if (!$this->getContainer()->has($resourceName)) { 582 throw new \RuntimeException( 583 Text::sprintf('JLIB_APPLICATION_ERROR_PATHWAY_LOAD', $this->getName()), 584 500 585 ); 586 } 587 588 $this->pathway = $this->getContainer()->get($resourceName); 589 } 590 591 return $this->pathway; 592 } 593 594 /** 595 * Returns the application Router object. 596 * 597 * @param string $name The name of the application. 598 * @param array $options An optional associative array of configuration settings. 599 * 600 * @return Router 601 * 602 * @since 3.2 603 * 604 * @deprecated 5.0 Inject the router or load it from the dependency injection container 605 */ 606 public static function getRouter($name = null, array $options = array()) 607 { 608 $app = Factory::getApplication(); 609 610 if (!isset($name)) { 611 $name = $app->getName(); 612 } 613 614 $options['mode'] = $app->get('sef'); 615 616 return Router::getInstance($name, $options); 617 } 618 619 /** 620 * Gets the name of the current template. 621 * 622 * @param boolean $params An optional associative array of configuration settings 623 * 624 * @return mixed System is the fallback. 625 * 626 * @since 3.2 627 */ 628 public function getTemplate($params = false) 629 { 630 if ($params) { 631 $template = new \stdClass(); 632 633 $template->template = 'system'; 634 $template->params = new Registry(); 635 $template->inheritable = 0; 636 $template->parent = ''; 637 638 return $template; 639 } 640 641 return 'system'; 642 } 643 644 /** 645 * Gets a user state. 646 * 647 * @param string $key The path of the state. 648 * @param mixed $default Optional default value, returned if the internal value is null. 649 * 650 * @return mixed The user state or null. 651 * 652 * @since 3.2 653 */ 654 public function getUserState($key, $default = null) 655 { 656 $registry = $this->getSession()->get('registry'); 657 658 if ($registry !== null) { 659 return $registry->get($key, $default); 660 } 661 662 return $default; 663 } 664 665 /** 666 * Gets the value of a user state variable. 667 * 668 * @param string $key The key of the user state variable. 669 * @param string $request The name of the variable passed in a request. 670 * @param string $default The default value for the variable if not found. Optional. 671 * @param string $type Filter for the variable, for valid values see {@link InputFilter::clean()}. Optional. 672 * 673 * @return mixed The request user state. 674 * 675 * @since 3.2 676 */ 677 public function getUserStateFromRequest($key, $request, $default = null, $type = 'none') 678 { 679 $cur_state = $this->getUserState($key, $default); 680 $new_state = $this->input->get($request, null, $type); 681 682 if ($new_state === null) { 683 return $cur_state; 684 } 685 686 // Save the new value only if it was set in this request. 687 $this->setUserState($key, $new_state); 688 689 return $new_state; 690 } 691 692 /** 693 * Initialise the application. 694 * 695 * @param array $options An optional associative array of configuration settings. 696 * 697 * @return void 698 * 699 * @since 3.2 700 */ 701 protected function initialiseApp($options = array()) 702 { 703 // Check that we were given a language in the array (since by default may be blank). 704 if (isset($options['language'])) { 705 $this->set('language', $options['language']); 706 } 707 708 // Build our language object 709 $lang = Language::getInstance($this->get('language'), $this->get('debug_lang')); 710 711 // Load the language to the API 712 $this->loadLanguage($lang); 713 714 // Register the language object with Factory 715 Factory::$language = $this->getLanguage(); 716 717 // Load the library language files 718 $this->loadLibraryLanguage(); 719 720 // Set user specific editor. 721 $user = Factory::getUser(); 722 $editor = $user->getParam('editor', $this->get('editor')); 723 724 if (!PluginHelper::isEnabled('editors', $editor)) { 725 $editor = $this->get('editor'); 726 727 if (!PluginHelper::isEnabled('editors', $editor)) { 728 $editor = 'none'; 729 } 730 } 731 732 $this->set('editor', $editor); 733 734 // Load the behaviour plugins 735 PluginHelper::importPlugin('behaviour'); 736 737 // Trigger the onAfterInitialise event. 738 PluginHelper::importPlugin('system'); 739 $this->triggerEvent('onAfterInitialise'); 740 } 741 742 /** 743 * Checks if HTTPS is forced in the client configuration. 744 * 745 * @param integer $clientId An optional client id (defaults to current application client). 746 * 747 * @return boolean True if is forced for the client, false otherwise. 748 * 749 * @since 3.7.3 750 */ 751 public function isHttpsForced($clientId = null) 752 { 753 $clientId = (int) ($clientId !== null ? $clientId : $this->getClientId()); 754 $forceSsl = (int) $this->get('force_ssl'); 755 756 if ($clientId === 0 && $forceSsl === 2) { 757 return true; 758 } 759 760 if ($clientId === 1 && $forceSsl >= 1) { 761 return true; 762 } 763 764 return false; 765 } 766 767 /** 768 * Check the client interface by name. 769 * 770 * @param string $identifier String identifier for the application interface 771 * 772 * @return boolean True if this application is of the given type client interface. 773 * 774 * @since 3.7.0 775 */ 776 public function isClient($identifier) 777 { 778 return $this->getName() === $identifier; 779 } 780 781 /** 782 * Load the library language files for the application 783 * 784 * @return void 785 * 786 * @since 3.6.3 787 */ 788 protected function loadLibraryLanguage() 789 { 790 $this->getLanguage()->load('lib_joomla', JPATH_ADMINISTRATOR); 791 } 792 793 /** 794 * Login authentication function. 795 * 796 * Username and encoded password are passed the onUserLogin event which 797 * is responsible for the user validation. A successful validation updates 798 * the current session record with the user's details. 799 * 800 * Username and encoded password are sent as credentials (along with other 801 * possibilities) to each observer (authentication plugin) for user 802 * validation. Successful validation will update the current session with 803 * the user details. 804 * 805 * @param array $credentials Array('username' => string, 'password' => string) 806 * @param array $options Array('remember' => boolean) 807 * 808 * @return boolean|\Exception True on success, false if failed or silent handling is configured, or a \Exception object on authentication error. 809 * 810 * @since 3.2 811 */ 812 public function login($credentials, $options = array()) 813 { 814 // Get the global Authentication object. 815 $authenticate = Authentication::getInstance($this->authenticationPluginType); 816 $response = $authenticate->authenticate($credentials, $options); 817 818 // Import the user plugin group. 819 PluginHelper::importPlugin('user'); 820 821 if ($response->status === Authentication::STATUS_SUCCESS) { 822 /* 823 * Validate that the user should be able to login (different to being authenticated). 824 * This permits authentication plugins blocking the user. 825 */ 826 $authorisations = $authenticate->authorise($response, $options); 827 $denied_states = Authentication::STATUS_EXPIRED | Authentication::STATUS_DENIED; 828 829 foreach ($authorisations as $authorisation) { 830 if ((int) $authorisation->status & $denied_states) { 831 // Trigger onUserAuthorisationFailure Event. 832 $this->triggerEvent('onUserAuthorisationFailure', array((array) $authorisation)); 833 834 // If silent is set, just return false. 835 if (isset($options['silent']) && $options['silent']) { 836 return false; 837 } 838 839 // Return the error. 840 switch ($authorisation->status) { 841 case Authentication::STATUS_EXPIRED: 842 Factory::getApplication()->enqueueMessage(Text::_('JLIB_LOGIN_EXPIRED'), 'error'); 843 844 return false; 845 846 case Authentication::STATUS_DENIED: 847 Factory::getApplication()->enqueueMessage(Text::_('JLIB_LOGIN_DENIED'), 'error'); 848 849 return false; 850 851 default: 852 Factory::getApplication()->enqueueMessage(Text::_('JLIB_LOGIN_AUTHORISATION'), 'error'); 853 854 return false; 855 } 856 } 857 } 858 859 // OK, the credentials are authenticated and user is authorised. Let's fire the onLogin event. 860 $results = $this->triggerEvent('onUserLogin', array((array) $response, $options)); 861 862 /* 863 * If any of the user plugins did not successfully complete the login routine 864 * then the whole method fails. 865 * 866 * Any errors raised should be done in the plugin as this provides the ability 867 * to provide much more information about why the routine may have failed. 868 */ 869 $user = Factory::getUser(); 870 871 if ($response->type === 'Cookie') { 872 $user->set('cookieLogin', true); 873 } 874 875 if (\in_array(false, $results, true) == false) { 876 $options['user'] = $user; 877 $options['responseType'] = $response->type; 878 879 // The user is successfully logged in. Run the after login events 880 $this->triggerEvent('onUserAfterLogin', array($options)); 881 882 return true; 883 } 884 } 885 886 // Trigger onUserLoginFailure Event. 887 $this->triggerEvent('onUserLoginFailure', array((array) $response)); 888 889 // If silent is set, just return false. 890 if (isset($options['silent']) && $options['silent']) { 891 return false; 892 } 893 894 // If status is success, any error will have been raised by the user plugin 895 if ($response->status !== Authentication::STATUS_SUCCESS) { 896 $this->getLogger()->warning($response->error_message, array('category' => 'jerror')); 897 } 898 899 return false; 900 } 901 902 /** 903 * Logout authentication function. 904 * 905 * Passed the current user information to the onUserLogout event and reverts the current 906 * session record back to 'anonymous' parameters. 907 * If any of the authentication plugins did not successfully complete 908 * the logout routine then the whole method fails. Any errors raised 909 * should be done in the plugin as this provides the ability to give 910 * much more information about why the routine may have failed. 911 * 912 * @param integer $userid The user to load - Can be an integer or string - If string, it is converted to ID automatically 913 * @param array $options Array('clientid' => array of client id's) 914 * 915 * @return boolean True on success 916 * 917 * @since 3.2 918 */ 919 public function logout($userid = null, $options = array()) 920 { 921 // Get a user object from the Application. 922 $user = Factory::getUser($userid); 923 924 // Build the credentials array. 925 $parameters['username'] = $user->get('username'); 926 $parameters['id'] = $user->get('id'); 927 928 // Set clientid in the options array if it hasn't been set already and shared sessions are not enabled. 929 if (!$this->get('shared_session', '0') && !isset($options['clientid'])) { 930 $options['clientid'] = $this->getClientId(); 931 } 932 933 // Import the user plugin group. 934 PluginHelper::importPlugin('user'); 935 936 // OK, the credentials are built. Lets fire the onLogout event. 937 $results = $this->triggerEvent('onUserLogout', array($parameters, $options)); 938 939 // Check if any of the plugins failed. If none did, success. 940 if (!\in_array(false, $results, true)) { 941 $options['username'] = $user->get('username'); 942 $this->triggerEvent('onUserAfterLogout', array($options)); 943 944 return true; 945 } 946 947 // Trigger onUserLogoutFailure Event. 948 $this->triggerEvent('onUserLogoutFailure', array($parameters)); 949 950 return false; 951 } 952 953 /** 954 * Redirect to another URL. 955 * 956 * If the headers have not been sent the redirect will be accomplished using a "301 Moved Permanently" 957 * or "303 See Other" code in the header pointing to the new location. If the headers have already been 958 * sent this will be accomplished using a JavaScript statement. 959 * 960 * @param string $url The URL to redirect to. Can only be http/https URL 961 * @param integer $status The HTTP 1.1 status code to be provided. 303 is assumed by default. 962 * 963 * @return void 964 * 965 * @since 3.2 966 */ 967 public function redirect($url, $status = 303) 968 { 969 // Persist messages if they exist. 970 if (\count($this->messageQueue)) { 971 $this->getSession()->set('application.queue', $this->messageQueue); 972 } 973 974 // Hand over processing to the parent now 975 parent::redirect($url, $status); 976 } 977 978 /** 979 * Rendering is the process of pushing the document buffers into the template 980 * placeholders, retrieving data from the document and pushing it into 981 * the application response buffer. 982 * 983 * @return void 984 * 985 * @since 3.2 986 */ 987 protected function render() 988 { 989 // Setup the document options. 990 $this->docOptions['template'] = $this->get('theme'); 991 $this->docOptions['file'] = $this->get('themeFile', 'index.php'); 992 $this->docOptions['params'] = $this->get('themeParams'); 993 $this->docOptions['csp_nonce'] = $this->get('csp_nonce'); 994 $this->docOptions['templateInherits'] = $this->get('themeInherits'); 995 996 if ($this->get('themes.base')) { 997 $this->docOptions['directory'] = $this->get('themes.base'); 998 } else { 999 // Fall back to constants. 1000 $this->docOptions['directory'] = \defined('JPATH_THEMES') ? JPATH_THEMES : (\defined('JPATH_BASE') ? JPATH_BASE : __DIR__) . '/themes'; 1001 } 1002 1003 // Parse the document. 1004 $this->document->parse($this->docOptions); 1005 1006 // Trigger the onBeforeRender event. 1007 PluginHelper::importPlugin('system'); 1008 $this->triggerEvent('onBeforeRender'); 1009 1010 $caching = false; 1011 1012 if ($this->isClient('site') && $this->get('caching') && $this->get('caching', 2) == 2 && !Factory::getUser()->get('id')) { 1013 $caching = true; 1014 } 1015 1016 // Render the document. 1017 $data = $this->document->render($caching, $this->docOptions); 1018 1019 // Set the application output data. 1020 $this->setBody($data); 1021 1022 // Trigger the onAfterRender event. 1023 $this->triggerEvent('onAfterRender'); 1024 1025 // Mark afterRender in the profiler. 1026 JDEBUG ? $this->profiler->mark('afterRender') : null; 1027 } 1028 1029 /** 1030 * Route the application. 1031 * 1032 * Routing is the process of examining the request environment to determine which 1033 * component should receive the request. The component optional parameters 1034 * are then set in the request object to be processed when the application is being 1035 * dispatched. 1036 * 1037 * @return void 1038 * 1039 * @since 3.2 1040 * 1041 * @deprecated 5.0 Implement the route functionality in the extending class, this here will be removed without replacement 1042 */ 1043 protected function route() 1044 { 1045 // Get the full request URI. 1046 $uri = clone Uri::getInstance(); 1047 1048 $router = static::getRouter(); 1049 $result = $router->parse($uri, true); 1050 1051 $active = $this->getMenu()->getActive(); 1052 1053 if ( 1054 $active !== null 1055 && $active->type === 'alias' 1056 && $active->getParams()->get('alias_redirect') 1057 && \in_array($this->input->getMethod(), array('GET', 'HEAD'), true) 1058 ) { 1059 $item = $this->getMenu()->getItem($active->getParams()->get('aliasoptions')); 1060 1061 if ($item !== null) { 1062 $oldUri = clone Uri::getInstance(); 1063 1064 if ($oldUri->getVar('Itemid') == $active->id) { 1065 $oldUri->setVar('Itemid', $item->id); 1066 } 1067 1068 $base = Uri::base(true); 1069 $oldPath = StringHelper::strtolower(substr($oldUri->getPath(), \strlen($base) + 1)); 1070 $activePathPrefix = StringHelper::strtolower($active->route); 1071 1072 $position = strpos($oldPath, $activePathPrefix); 1073 1074 if ($position !== false) { 1075 $oldUri->setPath($base . '/' . substr_replace($oldPath, $item->route, $position, \strlen($activePathPrefix))); 1076 1077 $this->setHeader('Expires', 'Wed, 17 Aug 2005 00:00:00 GMT', true); 1078 $this->setHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT', true); 1079 $this->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate', false); 1080 $this->sendHeaders(); 1081 1082 $this->redirect((string) $oldUri, 301); 1083 } 1084 } 1085 } 1086 1087 foreach ($result as $key => $value) { 1088 $this->input->def($key, $value); 1089 } 1090 1091 // Trigger the onAfterRoute event. 1092 PluginHelper::importPlugin('system'); 1093 $this->triggerEvent('onAfterRoute'); 1094 } 1095 1096 /** 1097 * Sets the value of a user state variable. 1098 * 1099 * @param string $key The path of the state. 1100 * @param mixed $value The value of the variable. 1101 * 1102 * @return mixed|void The previous state, if one existed. 1103 * 1104 * @since 3.2 1105 */ 1106 public function setUserState($key, $value) 1107 { 1108 $session = $this->getSession(); 1109 $registry = $session->get('registry'); 1110 1111 if ($registry !== null) { 1112 return $registry->set($key, $value); 1113 } 1114 } 1115 1116 /** 1117 * Sends all headers prior to returning the string 1118 * 1119 * @param boolean $compress If true, compress the data 1120 * 1121 * @return string 1122 * 1123 * @since 3.2 1124 */ 1125 public function toString($compress = false) 1126 { 1127 // Don't compress something if the server is going to do it anyway. Waste of time. 1128 if ($compress && !ini_get('zlib.output_compression') && ini_get('output_handler') !== 'ob_gzhandler') { 1129 $this->compress(); 1130 } 1131 1132 if ($this->allowCache() === false) { 1133 $this->setHeader('Cache-Control', 'no-cache', false); 1134 } 1135 1136 $this->sendHeaders(); 1137 1138 return $this->getBody(); 1139 } 1140 1141 /** 1142 * Method to determine a hash for anti-spoofing variable names 1143 * 1144 * @param boolean $forceNew If true, force a new token to be created 1145 * 1146 * @return string Hashed var name 1147 * 1148 * @since 4.0.0 1149 */ 1150 public function getFormToken($forceNew = false) 1151 { 1152 /** @var Session $session */ 1153 $session = $this->getSession(); 1154 1155 return $session->getFormToken($forceNew); 1156 } 1157 1158 /** 1159 * Checks for a form token in the request. 1160 * 1161 * Use in conjunction with getFormToken. 1162 * 1163 * @param string $method The request method in which to look for the token key. 1164 * 1165 * @return boolean True if found and valid, false otherwise. 1166 * 1167 * @since 4.0.0 1168 */ 1169 public function checkToken($method = 'post') 1170 { 1171 /** @var Session $session */ 1172 $session = $this->getSession(); 1173 1174 return $session->checkToken($method); 1175 } 1176 1177 /** 1178 * Flag if the application instance is a CLI or web based application. 1179 * 1180 * Helper function, you should use the native PHP functions to detect if it is a CLI application. 1181 * 1182 * @return boolean 1183 * 1184 * @since 4.0.0 1185 * @deprecated 5.0 Will be removed without replacements 1186 */ 1187 public function isCli() 1188 { 1189 return false; 1190 } 1191 1192 /** 1193 * No longer used 1194 * 1195 * @return boolean 1196 * 1197 * @since 4.0.0 1198 * 1199 * @throws \Exception 1200 * @deprecated 4.2.0 Will be removed in 5.0 without replacement. 1201 */ 1202 protected function isTwoFactorAuthenticationRequired(): bool 1203 { 1204 return false; 1205 } 1206 1207 /** 1208 * No longer used 1209 * 1210 * @return boolean 1211 * 1212 * @since 4.0.0 1213 * 1214 * @throws \Exception 1215 * @deprecated 4.2.0 Will be removed in 5.0 without replacement. 1216 */ 1217 private function hasUserConfiguredTwoFactorAuthentication(): bool 1218 { 1219 return false; 1220 } 1221 1222 /** 1223 * Setup logging functionality. 1224 * 1225 * @return void 1226 * 1227 * @since 4.0.0 1228 */ 1229 private function setupLogging(): void 1230 { 1231 // Add InMemory logger that will collect all log entries to allow to display them later by extensions 1232 if ($this->get('debug')) { 1233 Log::addLogger(['logger' => 'inmemory']); 1234 } 1235 1236 // Log the deprecated API. 1237 if ($this->get('log_deprecated')) { 1238 Log::addLogger(['text_file' => 'deprecated.php'], Log::ALL, ['deprecated']); 1239 } 1240 1241 // We only log errors unless Site Debug is enabled 1242 $logLevels = Log::ERROR | Log::CRITICAL | Log::ALERT | Log::EMERGENCY; 1243 1244 if ($this->get('debug')) { 1245 $logLevels = Log::ALL; 1246 } 1247 1248 Log::addLogger(['text_file' => 'joomla_core_errors.php'], $logLevels, ['system']); 1249 1250 // Log everything (except deprecated APIs, these are logged separately with the option above). 1251 if ($this->get('log_everything')) { 1252 Log::addLogger(['text_file' => 'everything.php'], Log::ALL, ['deprecated', 'deprecation-notes', 'databasequery'], true); 1253 } 1254 1255 if ($this->get('log_categories')) { 1256 $priority = 0; 1257 1258 foreach ($this->get('log_priorities', ['all']) as $p) { 1259 $const = '\\Joomla\\CMS\\Log\\Log::' . strtoupper($p); 1260 1261 if (defined($const)) { 1262 $priority |= constant($const); 1263 } 1264 } 1265 1266 // Split into an array at any character other than alphabet, numbers, _, ., or - 1267 $categories = preg_split('/[^\w.-]+/', $this->get('log_categories', ''), -1, PREG_SPLIT_NO_EMPTY); 1268 $mode = (bool) $this->get('log_category_mode', false); 1269 1270 if (!$categories) { 1271 return; 1272 } 1273 1274 Log::addLogger(['text_file' => 'custom-logging.php'], $priority, $categories, $mode); 1275 } 1276 } 1277 1278 /** 1279 * Sets the internal menu factory. 1280 * 1281 * @param MenuFactoryInterface $menuFactory The menu factory 1282 * 1283 * @return void 1284 * 1285 * @since 4.2.0 1286 */ 1287 public function setMenuFactory(MenuFactoryInterface $menuFactory): void 1288 { 1289 $this->menuFactory = $menuFactory; 1290 } 1291 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |