PageRenderTime 130ms CodeModel.GetById 60ms app.highlight 29ms RepoModel.GetById 32ms app.codeStats 0ms

/libraries/joomla/application/web.php

https://bitbucket.org/izubizarreta/https-bitbucket.org-bityvip
PHP | 1239 lines | 544 code | 129 blank | 566 comment | 67 complexity | 467e3e414c8f37a1b2e477b1aa9778c5 MD5 | raw file
   1<?php
   2/**
   3 * @package     Joomla.Platform
   4 * @subpackage  Application
   5 *
   6 * @copyright   Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
   7 * @license     GNU General Public License version 2 or later; see LICENSE
   8 */
   9
  10defined('JPATH_PLATFORM') or die;
  11
  12jimport('joomla.application.input');
  13jimport('joomla.application.web.webclient');
  14jimport('joomla.environment.uri');
  15jimport('joomla.event.dispatcher');
  16
  17/**
  18 * Base class for a Joomla! Web application.
  19 *
  20 * @package     Joomla.Platform
  21 * @subpackage  Application
  22 * @since       11.4
  23 */
  24class JApplicationWeb
  25{
  26	/**
  27	 * @var    JInput  The application input object.
  28	 * @since  11.3
  29	 */
  30	public $input;
  31
  32	/**
  33	 * @var    string  Character encoding string.
  34	 * @since  11.3
  35	 */
  36	public $charSet = 'utf-8';
  37
  38	/**
  39	 * @var    string  Response mime type.
  40	 * @since  11.3
  41	 */
  42	public $mimeType = 'text/html';
  43
  44	/**
  45	 * @var    JDate  The body modified date for response headers.
  46	 * @since  11.3
  47	 */
  48	public $modifiedDate;
  49
  50	/**
  51	 * @var    JWebClient  The application client object.
  52	 * @since  11.3
  53	 */
  54	public $client;
  55
  56	/**
  57	 * @var    JRegistry  The application configuration object.
  58	 * @since  11.3
  59	 */
  60	protected $config;
  61
  62	/**
  63	 * @var    JDispatcher  The application dispatcher object.
  64	 * @since  11.3
  65	 */
  66	protected $dispatcher;
  67
  68	/**
  69	 * @var    JDocument  The application document object.
  70	 * @since  11.3
  71	 */
  72	protected $document;
  73
  74	/**
  75	 * @var    JLanguage  The application language object.
  76	 * @since  11.3
  77	 */
  78	protected $language;
  79
  80	/**
  81	 * @var    JSession  The application session object.
  82	 * @since  11.3
  83	 */
  84	protected $session;
  85
  86	/**
  87	 * @var    object  The application response object.
  88	 * @since  11.3
  89	 */
  90	protected $response;
  91
  92	/**
  93	 * @var    JApplicationWeb  The application instance.
  94	 * @since  11.3
  95	 */
  96	protected static $instance;
  97
  98	/**
  99	 * Class constructor.
 100	 *
 101	 * @param   mixed  $input   An optional argument to provide dependency injection for the application's
 102	 *                          input object.  If the argument is a JInput object that object will become
 103	 *                          the application's input object, otherwise a default input object is created.
 104	 * @param   mixed  $config  An optional argument to provide dependency injection for the application's
 105	 *                          config object.  If the argument is a JRegistry object that object will become
 106	 *                          the application's config object, otherwise a default config object is created.
 107	 * @param   mixed  $client  An optional argument to provide dependency injection for the application's
 108	 *                          client object.  If the argument is a JWebClient object that object will become
 109	 *                          the application's client object, otherwise a default client object is created.
 110	 *
 111	 * @since   11.3
 112	 */
 113	public function __construct(JInput $input = null, JRegistry $config = null, JWebClient $client = null)
 114	{
 115		// If a input object is given use it.
 116		if ($input instanceof JInput)
 117		{
 118			$this->input = $input;
 119		}
 120		// Create the input based on the application logic.
 121		else
 122		{
 123			$this->input = new JInput;
 124		}
 125
 126		// If a config object is given use it.
 127		if ($config instanceof JRegistry)
 128		{
 129			$this->config = $config;
 130		}
 131		// Instantiate a new configuration object.
 132		else
 133		{
 134			$this->config = new JRegistry;
 135		}
 136
 137		// If a client object is given use it.
 138		if ($client instanceof JWebClient)
 139		{
 140			$this->client = $client;
 141		}
 142		// Instantiate a new web client object.
 143		else
 144		{
 145			$this->client = new JWebClient;
 146		}
 147
 148		// Load the configuration object.
 149		$this->loadConfiguration($this->fetchConfigurationData());
 150
 151		// Set the execution datetime and timestamp;
 152		$this->set('execution.datetime', gmdate('Y-m-d H:i:s'));
 153		$this->set('execution.timestamp', time());
 154
 155		// Setup the response object.
 156		$this->response = new stdClass;
 157		$this->response->cachable = false;
 158		$this->response->headers = array();
 159		$this->response->body = array();
 160
 161		// Set the system URIs.
 162		$this->loadSystemUris();
 163	}
 164
 165	/**
 166	 * Returns a reference to the global JApplicationWeb object, only creating it if it doesn't already exist.
 167	 *
 168	 * This method must be invoked as: $web = JApplicationWeb::getInstance();
 169	 *
 170	 * @param   string  $name  The name (optional) of the JApplicationWeb class to instantiate.
 171	 *
 172	 * @return  JApplicationWeb
 173	 *
 174	 * @since   11.3
 175	 */
 176	public static function getInstance($name = null)
 177	{
 178		// Only create the object if it doesn't exist.
 179		if (empty(self::$instance))
 180		{
 181			if (class_exists($name) && (is_subclass_of($name, 'JApplicationWeb')))
 182			{
 183				self::$instance = new $name;
 184			}
 185			else
 186			{
 187				self::$instance = new JApplicationWeb;
 188			}
 189		}
 190
 191		return self::$instance;
 192	}
 193
 194	/**
 195	 * Initialise the application.
 196	 *
 197	 * @param   mixed  $session     An optional argument to provide dependency injection for the application's
 198	 *                              session object.  If the argument is a JSession object that object will become
 199	 *                              the application's session object, if it is false then there will be no session
 200	 *                              object, and if it is null then the default session object will be created based
 201	 *                              on the application's loadSession() method.
 202	 * @param   mixed  $document    An optional argument to provide dependency injection for the application's
 203	 *                              document object.  If the argument is a JDocument object that object will become
 204	 *                              the application's document object, if it is false then there will be no document
 205	 *                              object, and if it is null then the default document object will be created based
 206	 *                              on the application's loadDocument() method.
 207	 * @param   mixed  $language    An optional argument to provide dependency injection for the application's
 208	 *                              language object.  If the argument is a JLanguage object that object will become
 209	 *                              the application's language object, if it is false then there will be no language
 210	 *                              object, and if it is null then the default language object will be created based
 211	 *                              on the application's loadLanguage() method.
 212	 * @param   mixed  $dispatcher  An optional argument to provide dependency injection for the application's
 213	 *                              event dispatcher.  If the argument is a JDispatcher object that object will become
 214	 *                              the application's event dispatcher, if it is null then the default event dispatcher
 215	 *                              will be created based on the application's loadDispatcher() method.
 216	 *
 217	 * @return  JApplicationWeb  Instance of $this to allow chaining.
 218	 *
 219	 * @see     loadSession()
 220	 * @see     loadDocument()
 221	 * @see     loadLanguage()
 222	 * @see     loadDispatcher()
 223	 * @since   11.3
 224	 */
 225	public function initialise($session = null, $document = null, $language = null, $dispatcher = null)
 226	{
 227		// If a session object is given use it.
 228		if ($session instanceof JSession)
 229		{
 230			$this->session = $session;
 231		}
 232		// We don't have a session, nor do we want one.
 233		elseif ($session === false)
 234		{
 235			// Do nothing.
 236		}
 237		// Create the session based on the application logic.
 238		else
 239		{
 240			$this->loadSession();
 241		}
 242
 243		// If a document object is given use it.
 244		if ($document instanceof JDocument)
 245		{
 246			$this->document = $document;
 247		}
 248		// We don't have a document, nor do we want one.
 249		elseif ($document === false)
 250		{
 251			// Do nothing.
 252		}
 253		// Create the document based on the application logic.
 254		else
 255		{
 256			$this->loadDocument();
 257		}
 258
 259		// If a language object is given use it.
 260		if ($language instanceof JLanguage)
 261		{
 262			$this->language = $language;
 263		}
 264		// We don't have a language, nor do we want one.
 265		elseif ($language === false)
 266		{
 267			// Do nothing.
 268		}
 269		// Create the language based on the application logic.
 270		else
 271		{
 272			$this->loadLanguage();
 273		}
 274
 275		// Reverted back for CMS version 2.5.6
 276		// If a dispatcher object is given use it.
 277		if ($dispatcher instanceof JDispatcher)
 278		{
 279			$this->dispatcher = $dispatcher;
 280		}
 281		// Create the dispatcher based on the application logic.
 282		else
 283		{
 284			$this->loadDispatcher();
 285		}
 286
 287		return $this;
 288	}
 289
 290	/**
 291	 * Execute the application.
 292	 *
 293	 * @return  void
 294	 *
 295	 * @since   11.3
 296	 */
 297	public function execute()
 298	{
 299		// Trigger the onBeforeExecute event.
 300		$this->triggerEvent('onBeforeExecute');
 301
 302		// Perform application routines.
 303		$this->doExecute();
 304
 305		// Trigger the onAfterExecute event.
 306		$this->triggerEvent('onAfterExecute');
 307
 308		// If we have an application document object, render it.
 309		if ($this->document instanceof JDocument)
 310		{
 311			// Trigger the onBeforeRender event.
 312			$this->triggerEvent('onBeforeRender');
 313
 314			// Render the application output.
 315			$this->render();
 316
 317			// Trigger the onAfterRender event.
 318			$this->triggerEvent('onAfterRender');
 319		}
 320
 321		// If gzip compression is enabled in configuration and the server is compliant, compress the output.
 322		if ($this->get('gzip') && !ini_get('zlib.output_compression') && (ini_get('output_handler') != 'ob_gzhandler'))
 323		{
 324			$this->compress();
 325		}
 326
 327		// Trigger the onBeforeRespond event.
 328		$this->triggerEvent('onBeforeRespond');
 329
 330		// Send the application response.
 331		$this->respond();
 332
 333		// Trigger the onAfterRespond event.
 334		$this->triggerEvent('onAfterRespond');
 335	}
 336
 337	/**
 338	 * Method to run the Web application routines.  Most likely you will want to instantiate a controller
 339	 * and execute it, or perform some sort of action that populates a JDocument object so that output
 340	 * can be rendered to the client.
 341	 *
 342	 * @return  void
 343	 *
 344	 * @codeCoverageIgnore
 345	 * @since   11.3
 346	 */
 347	protected function doExecute()
 348	{
 349		// Your application routines go here.
 350	}
 351
 352	/**
 353	 * Rendering is the process of pushing the document buffers into the template
 354	 * placeholders, retrieving data from the document and pushing it into
 355	 * the application response buffer.
 356	 *
 357	 * @return  void
 358	 *
 359	 * @since   11.3
 360	 */
 361	protected function render()
 362	{
 363		// Setup the document options.
 364		$options = array(
 365			'template' => $this->get('theme'),
 366			'file' => 'index.php',
 367			'params' => ''
 368		);
 369
 370		if ($this->get('themes.base'))
 371		{
 372			$options['directory'] = $this->get('themes.base');
 373		}
 374		// Fall back to constants.
 375		else
 376		{
 377			$options['directory'] = (defined('JPATH_BASE') ? JPATH_BASE : dirname(__FILE__)) . '/themes';
 378		}
 379
 380		// Parse the document.
 381		$this->document->parse($options);
 382
 383		// Render the document.
 384		$data = $this->document->render($this->get('cache_enabled'), $options);
 385
 386		// Set the application output data.
 387		$this->setBody($data);
 388	}
 389
 390	/**
 391	 * Checks the accept encoding of the browser and compresses the data before
 392	 * sending it to the client if possible.
 393	 *
 394	 * @return  void
 395	 *
 396	 * @since   11.3
 397	 */
 398	protected function compress()
 399	{
 400		// Supported compression encodings.
 401		$supported = array(
 402			'x-gzip' => 'gz',
 403			'gzip' => 'gz',
 404			'deflate' => 'deflate'
 405		);
 406
 407		// Get the supported encoding.
 408		$encodings = array_intersect($this->client->encodings, array_keys($supported));
 409
 410		// If no supported encoding is detected do nothing and return.
 411		if (empty($encodings))
 412		{
 413			return;
 414		}
 415
 416		// Verify that headers have not yet been sent, and that our connection is still alive.
 417		if ($this->checkHeadersSent() || !$this->checkConnectionAlive())
 418		{
 419			return;
 420		}
 421
 422		// Iterate through the encodings and attempt to compress the data using any found supported encodings.
 423		foreach ($encodings as $encoding)
 424		{
 425			if (($supported[$encoding] == 'gz') || ($supported[$encoding] == 'deflate'))
 426			{
 427				// Verify that the server supports gzip compression before we attempt to gzip encode the data.
 428				// @codeCoverageIgnoreStart
 429				if (!extension_loaded('zlib') || ini_get('zlib.output_compression'))
 430				{
 431					continue;
 432				}
 433				// @codeCoverageIgnoreEnd
 434
 435				// Attempt to gzip encode the data with an optimal level 4.
 436				$data = $this->getBody();
 437				$gzdata = gzencode($data, 4, ($supported[$encoding] == 'gz') ? FORCE_GZIP : FORCE_DEFLATE);
 438
 439				// If there was a problem encoding the data just try the next encoding scheme.
 440				// @codeCoverageIgnoreStart
 441				if ($gzdata === false)
 442				{
 443					continue;
 444				}
 445				// @codeCoverageIgnoreEnd
 446
 447				// Set the encoding headers.
 448				$this->setHeader('Content-Encoding', $encoding);
 449				$this->setHeader('X-Content-Encoded-By', 'Joomla');
 450
 451				// Replace the output with the encoded data.
 452				$this->setBody($gzdata);
 453
 454				// Compression complete, let's break out of the loop.
 455				break;
 456			}
 457		}
 458	}
 459
 460	/**
 461	 * Method to send the application response to the client.  All headers will be sent prior to the main
 462	 * application output data.
 463	 *
 464	 * @return  void
 465	 *
 466	 * @since   11.3
 467	 */
 468	protected function respond()
 469	{
 470		// Send the content-type header.
 471		$this->setHeader('Content-Type', $this->mimeType . '; charset=' . $this->charSet);
 472
 473		// If the response is set to uncachable, we need to set some appropriate headers so browsers don't cache the response.
 474		if (!$this->response->cachable)
 475		{
 476			// Expires in the past.
 477			$this->setHeader('Expires', 'Mon, 1 Jan 2001 00:00:00 GMT', true);
 478			// Always modified.
 479			$this->setHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT', true);
 480			$this->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0', false);
 481			// HTTP 1.0
 482			$this->setHeader('Pragma', 'no-cache');
 483		}
 484		else
 485		{
 486			// Expires.
 487			$this->setHeader('Expires', gmdate('D, d M Y H:i:s', time() + 900) . ' GMT');
 488			// Last modified.
 489			if ($this->modifiedDate instanceof JDate)
 490			{
 491				$this->setHeader('Last-Modified', $this->modifiedDate->format('D, d M Y H:i:s'));
 492			}
 493		}
 494
 495		$this->sendHeaders();
 496
 497		echo $this->getBody();
 498	}
 499
 500	/**
 501	 * Redirect to another URL.
 502	 *
 503	 * If the headers have not been sent the redirect will be accomplished using a "301 Moved Permanently"
 504	 * or "303 See Other" code in the header pointing to the new location. If the headers have already been
 505	 * sent this will be accomplished using a JavaScript statement.
 506	 *
 507	 * @param   string   $url    The URL to redirect to. Can only be http/https URL
 508	 * @param   boolean  $moved  True if the page is 301 Permanently Moved, otherwise 303 See Other is assumed.
 509	 *
 510	 * @return  void
 511	 *
 512	 * @since   11.3
 513	 */
 514	public function redirect($url, $moved = false)
 515	{
 516		// Import library dependencies.
 517		jimport('phputf8.utils.ascii');
 518
 519		// Check for relative internal links.
 520		if (preg_match('#^index\.php#', $url))
 521		{
 522			$url = $this->get('uri.base.full') . $url;
 523		}
 524
 525		// Perform a basic sanity check to make sure we don't have any CRLF garbage.
 526		$url = preg_split("/[\r\n]/", $url);
 527		$url = $url[0];
 528
 529		/*
 530		 * Here we need to check and see if the URL is relative or absolute.  Essentially, do we need to
 531		 * prepend the URL with our base URL for a proper redirect.  The rudimentary way we are looking
 532		 * at this is to simply check whether or not the URL string has a valid scheme or not.
 533		 */
 534		if (!preg_match('#^[a-z]+\://#i', $url))
 535		{
 536			// Get a JURI instance for the requested URI.
 537			$uri = JURI::getInstance($this->get('uri.request'));
 538
 539			// Get a base URL to prepend from the requested URI.
 540			$prefix = $uri->toString(array('scheme', 'user', 'pass', 'host', 'port'));
 541
 542			// We just need the prefix since we have a path relative to the root.
 543			if ($url[0] == '/')
 544			{
 545				$url = $prefix . $url;
 546			}
 547			// It's relative to where we are now, so lets add that.
 548			else
 549			{
 550				$parts = explode('/', $uri->toString(array('path')));
 551				array_pop($parts);
 552				$path = implode('/', $parts) . '/';
 553				$url = $prefix . $path . $url;
 554			}
 555		}
 556
 557		// If the headers have already been sent we need to send the redirect statement via JavaScript.
 558		if ($this->checkHeadersSent())
 559		{
 560			echo "<script>document.location.href='$url';</script>\n";
 561		}
 562		else
 563		{
 564			// We have to use a JavaScript redirect here because MSIE doesn't play nice with utf-8 URLs.
 565			if (($this->client->engine == JWebClient::TRIDENT) && !utf8_is_ascii($url))
 566			{
 567				$html = '<html><head>';
 568				$html .= '<meta http-equiv="content-type" content="text/html; charset=' . $this->charSet . '" />';
 569				$html .= '<script>document.location.href=\'' . $url . '\';</script>';
 570				$html .= '</head><body></body></html>';
 571
 572				echo $html;
 573			}
 574			/*
 575			 * For WebKit based browsers do not send a 303, as it causes subresource reloading.  You can view the
 576			 * bug report at: https://bugs.webkit.org/show_bug.cgi?id=38690
 577			 */
 578			elseif (!$moved and ($this->client->engine == JWebClient::WEBKIT))
 579			{
 580				$html = '<html><head>';
 581				$html .= '<meta http-equiv="refresh" content="0; url=' . $url . '" />';
 582				$html .= '<meta http-equiv="content-type" content="text/html; charset=' . $this->charSet . '" />';
 583				$html .= '</head><body></body></html>';
 584
 585				echo $html;
 586			}
 587			else
 588			{
 589				// All other cases use the more efficient HTTP header for redirection.
 590				$this->header($moved ? 'HTTP/1.1 301 Moved Permanently' : 'HTTP/1.1 303 See other');
 591				$this->header('Location: ' . $url);
 592				$this->header('Content-Type: text/html; charset=' . $this->charSet);
 593			}
 594		}
 595
 596		// Close the application after the redirect.
 597		$this->close();
 598	}
 599
 600	/**
 601	 * Exit the application.
 602	 *
 603	 * @param   integer  $code  The exit code (optional; default is 0).
 604	 *
 605	 * @return  void
 606	 *
 607	 * @codeCoverageIgnore
 608	 * @since   11.3
 609	 */
 610	public function close($code = 0)
 611	{
 612		exit($code);
 613	}
 614
 615	/**
 616	 * Load an object or array into the application configuration object.
 617	 *
 618	 * @param   mixed  $data  Either an array or object to be loaded into the configuration object.
 619	 *
 620	 * @return  JApplicationWeb  Instance of $this to allow chaining.
 621	 *
 622	 * @since   11.3
 623	 */
 624	public function loadConfiguration($data)
 625	{
 626		// Load the data into the configuration object.
 627		if (is_array($data))
 628		{
 629			$this->config->loadArray($data);
 630		}
 631		elseif (is_object($data))
 632		{
 633			$this->config->loadObject($data);
 634		}
 635
 636		return $this;
 637	}
 638
 639	/**
 640	 * Registers a handler to a particular event group.
 641	 *
 642	 * @param   string    $event    The event name.
 643	 * @param   callback  $handler  The handler, a function or an instance of a event object.
 644	 *
 645	 * @return  JApplicationWeb  Instance of $this to allow chaining.
 646	 *
 647	 * @since   11.3
 648	 */
 649	public function registerEvent($event, $handler)
 650	{
 651		if ($this->dispatcher instanceof JDispatcher)
 652		{
 653			$this->dispatcher->register($event, $handler);
 654		}
 655
 656		return $this;
 657	}
 658
 659	/**
 660	 * Calls all handlers associated with an event group.
 661	 *
 662	 * @param   string  $event  The event name.
 663	 * @param   array   $args   An array of arguments (optional).
 664	 *
 665	 * @return  array   An array of results from each function call, or null if no dispatcher is defined.
 666	 *
 667	 * @since   11.3
 668	 */
 669	public function triggerEvent($event, array $args = null)
 670	{
 671		if ($this->dispatcher instanceof JDispatcher)
 672		{
 673			return $this->dispatcher->trigger($event, $args);
 674		}
 675
 676		return null;
 677	}
 678
 679	/**
 680	 * Returns a property of the object or the default value if the property is not set.
 681	 *
 682	 * @param   string  $key      The name of the property.
 683	 * @param   mixed   $default  The default value (optional) if none is set.
 684	 *
 685	 * @return  mixed   The value of the configuration.
 686	 *
 687	 * @since   11.3
 688	 */
 689	public function get($key, $default = null)
 690	{
 691		return $this->config->get($key, $default);
 692	}
 693
 694	/**
 695	 * Modifies a property of the object, creating it if it does not already exist.
 696	 *
 697	 * @param   string  $key    The name of the property.
 698	 * @param   mixed   $value  The value of the property to set (optional).
 699	 *
 700	 * @return  mixed   Previous value of the property
 701	 *
 702	 * @since   11.3
 703	 */
 704	public function set($key, $value = null)
 705	{
 706		$previous = $this->config->get($key);
 707		$this->config->set($key, $value);
 708
 709		return $previous;
 710	}
 711
 712	/**
 713	 * Set/get cachable state for the response.  If $allow is set, sets the cachable state of the
 714	 * response.  Always returns the current state.
 715	 *
 716	 * @param   boolean  $allow  True to allow browser caching.
 717	 *
 718	 * @return  boolean
 719	 *
 720	 * @since   11.3
 721	 */
 722	public function allowCache($allow = null)
 723	{
 724		if ($allow !== null)
 725		{
 726			$this->response->cachable = (bool) $allow;
 727		}
 728
 729		return $this->response->cachable;
 730	}
 731
 732	/**
 733	 * Method to set a response header.  If the replace flag is set then all headers
 734	 * with the given name will be replaced by the new one.  The headers are stored
 735	 * in an internal array to be sent when the site is sent to the browser.
 736	 *
 737	 * @param   string   $name     The name of the header to set.
 738	 * @param   string   $value    The value of the header to set.
 739	 * @param   boolean  $replace  True to replace any headers with the same name.
 740	 *
 741	 * @return  JApplicationWeb  Instance of $this to allow chaining.
 742	 *
 743	 * @since   11.3
 744	 */
 745	public function setHeader($name, $value, $replace = false)
 746	{
 747		// Sanitize the input values.
 748		$name = (string) $name;
 749		$value = (string) $value;
 750
 751		// If the replace flag is set, unset all known headers with the given name.
 752		if ($replace)
 753		{
 754			foreach ($this->response->headers as $key => $header)
 755			{
 756				if ($name == $header['name'])
 757				{
 758					unset($this->response->headers[$key]);
 759				}
 760			}
 761
 762			// Clean up the array as unsetting nested arrays leaves some junk.
 763			$this->response->headers = array_values($this->response->headers);
 764		}
 765
 766		// Add the header to the internal array.
 767		$this->response->headers[] = array('name' => $name, 'value' => $value);
 768
 769		return $this;
 770	}
 771
 772	/**
 773	 * Method to get the array of response headers to be sent when the response is sent
 774	 * to the client.
 775	 *
 776	 * @return  array
 777	 *
 778	 * @since   11.3
 779	 */
 780	public function getHeaders()
 781	{
 782		return $this->response->headers;
 783	}
 784
 785	/**
 786	 * Method to clear any set response headers.
 787	 *
 788	 * @return  JApplicationWeb  Instance of $this to allow chaining.
 789	 *
 790	 * @since   11.3
 791	 */
 792	public function clearHeaders()
 793	{
 794		$this->response->headers = array();
 795
 796		return $this;
 797	}
 798
 799	/**
 800	 * Send the response headers.
 801	 *
 802	 * @return  JApplicationWeb  Instance of $this to allow chaining.
 803	 *
 804	 * @since   11.3
 805	 */
 806	public function sendHeaders()
 807	{
 808		if (!$this->checkHeadersSent())
 809		{
 810			foreach ($this->response->headers as $header)
 811			{
 812				if ('status' == strtolower($header['name']))
 813				{
 814					// 'status' headers indicate an HTTP status, and need to be handled slightly differently
 815					$this->header(ucfirst(strtolower($header['name'])) . ': ' . $header['value'], null, (int) $header['value']);
 816				}
 817				else
 818				{
 819					$this->header($header['name'] . ': ' . $header['value']);
 820				}
 821			}
 822		}
 823
 824		return $this;
 825	}
 826
 827	/**
 828	 * Set body content.  If body content already defined, this will replace it.
 829	 *
 830	 * @param   string  $content  The content to set as the response body.
 831	 *
 832	 * @return  JApplicationWeb  Instance of $this to allow chaining.
 833	 *
 834	 * @since   11.3
 835	 */
 836	public function setBody($content)
 837	{
 838		$this->response->body = array((string) $content);
 839
 840		return $this;
 841	}
 842
 843	/**
 844	 * Prepend content to the body content
 845	 *
 846	 * @param   string  $content  The content to prepend to the response body.
 847	 *
 848	 * @return  JApplicationWeb  Instance of $this to allow chaining.
 849	 *
 850	 * @since   11.3
 851	 */
 852	public function prependBody($content)
 853	{
 854		array_unshift($this->response->body, (string) $content);
 855
 856		return $this;
 857	}
 858
 859	/**
 860	 * Append content to the body content
 861	 *
 862	 * @param   string  $content  The content to append to the response body.
 863	 *
 864	 * @return  JApplicationWeb  Instance of $this to allow chaining.
 865	 *
 866	 * @since   11.3
 867	 */
 868	public function appendBody($content)
 869	{
 870		array_push($this->response->body, (string) $content);
 871
 872		return $this;
 873	}
 874
 875	/**
 876	 * Return the body content
 877	 *
 878	 * @param   boolean  $asArray  True to return the body as an array of strings.
 879	 *
 880	 * @return  mixed  The response body either as an array or concatenated string.
 881	 *
 882	 * @since   11.3
 883	 */
 884	public function getBody($asArray = false)
 885	{
 886		return $asArray ? $this->response->body : implode((array) $this->response->body);
 887	}
 888
 889	/**
 890	 * Method to get the application document object.
 891	 *
 892	 * @return  JDocument  The document object
 893	 *
 894	 * @since   11.3
 895	 */
 896	public function getDocument()
 897	{
 898		return $this->document;
 899	}
 900
 901	/**
 902	 * Method to get the application language object.
 903	 *
 904	 * @return  JLanguage  The language object
 905	 *
 906	 * @since   11.3
 907	 */
 908	public function getLanguage()
 909	{
 910		return $this->language;
 911	}
 912
 913	/**
 914	 * Method to get the application session object.
 915	 *
 916	 * @return  JSession  The session object
 917	 *
 918	 * @since   11.3
 919	 */
 920	public function getSession()
 921	{
 922		return $this->session;
 923	}
 924
 925	/**
 926	 * Method to check the current client connnection status to ensure that it is alive.  We are
 927	 * wrapping this to isolate the connection_status() function from our code base for testing reasons.
 928	 *
 929	 * @return  boolean  True if the connection is valid and normal.
 930	 *
 931	 * @codeCoverageIgnore
 932	 * @see     connection_status()
 933	 * @since   11.3
 934	 */
 935	protected function checkConnectionAlive()
 936	{
 937		return (connection_status() === CONNECTION_NORMAL);
 938	}
 939
 940	/**
 941	 * Method to check to see if headers have already been sent.  We are wrapping this to isolate the
 942	 * headers_sent() function from our code base for testing reasons.
 943	 *
 944	 * @return  boolean  True if the headers have already been sent.
 945	 *
 946	 * @codeCoverageIgnore
 947	 * @see     headers_sent()
 948	 * @since   11.3
 949	 */
 950	protected function checkHeadersSent()
 951	{
 952		return headers_sent();
 953	}
 954
 955	/**
 956	 * Method to detect the requested URI from server environment variables.
 957	 *
 958	 * @return  string  The requested URI
 959	 *
 960	 * @since   11.3
 961	 */
 962	protected function detectRequestUri()
 963	{
 964		// Initialise variables.
 965		$uri = '';
 966
 967		// First we need to detect the URI scheme.
 968		if (isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS']) != 'off'))
 969		{
 970			$scheme = 'https://';
 971		}
 972		else
 973		{
 974			$scheme = 'http://';
 975		}
 976
 977		/*
 978		 * There are some differences in the way that Apache and IIS populate server environment variables.  To
 979		 * properly detect the requested URI we need to adjust our algorithm based on whether or not we are getting
 980		 * information from Apache or IIS.
 981		 */
 982
 983		// If PHP_SELF and REQUEST_URI are both populated then we will assume "Apache Mode".
 984		if (!empty($_SERVER['PHP_SELF']) && !empty($_SERVER['REQUEST_URI']))
 985		{
 986			// The URI is built from the HTTP_HOST and REQUEST_URI environment variables in an Apache environment.
 987			$uri = $scheme . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
 988		}
 989		// If not in "Apache Mode" we will assume that we are in an IIS environment and proceed.
 990		else
 991		{
 992			// IIS uses the SCRIPT_NAME variable instead of a REQUEST_URI variable... thanks, MS
 993			$uri = $scheme . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'];
 994
 995			// If the QUERY_STRING variable exists append it to the URI string.
 996			if (isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING']))
 997			{
 998				$uri .= '?' . $_SERVER['QUERY_STRING'];
 999			}
1000		}
1001
1002		return trim($uri);
1003	}
1004
1005	/**
1006	 * Method to load a PHP configuration class file based on convention and return the instantiated data object.  You
1007	 * will extend this method in child classes to provide configuration data from whatever data source is relevant
1008	 * for your specific application.
1009	 *
1010	 * @param   string  $file   The path and filename of the configuration file. If not provided, configuration.php
1011	 *                          in JPATH_BASE will be used.
1012	 * @param   string  $class  The class name to instantiate.
1013	 *
1014	 * @return  mixed   Either an array or object to be loaded into the configuration object.
1015	 *
1016	 * @since   11.3
1017	 */
1018	protected function fetchConfigurationData($file = '', $class = 'JConfig')
1019	{
1020		// Instantiate variables.
1021		$config = array();
1022
1023		if (empty($file) && defined('JPATH_BASE'))
1024		{
1025			$file = JPATH_BASE . '/configuration.php';
1026
1027			// Applications can choose not to have any configuration data
1028			// by not implementing this method and not having a config file.
1029			if (!file_exists($file))
1030			{
1031				$file = '';
1032			}
1033		}
1034
1035		if (!empty($file))
1036		{
1037			JLoader::register($class, $file);
1038
1039			if (class_exists($class))
1040			{
1041				$config = new $class;
1042			}
1043			else
1044			{
1045				throw new RuntimeException('Configuration class does not exist.');
1046			}
1047		}
1048
1049		return $config;
1050	}
1051
1052	/**
1053	 * Method to send a header to the client.  We are wrapping this to isolate the header() function
1054	 * from our code base for testing reasons.
1055	 *
1056	 * @param   string   $string   The header string.
1057	 * @param   boolean  $replace  The optional replace parameter indicates whether the header should
1058	 *                             replace a previous similar header, or add a second header of the same type.
1059	 * @param   integer  $code     Forces the HTTP response code to the specified value. Note that
1060	 *                             this parameter only has an effect if the string is not empty.
1061	 *
1062	 * @return  void
1063	 *
1064	 * @codeCoverageIgnore
1065	 * @see     header()
1066	 * @since   11.3
1067	 */
1068	protected function header($string, $replace = true, $code = null)
1069	{
1070		header($string, $replace, $code);
1071	}
1072
1073	/**
1074	 * Method to create an event dispatcher for the Web application.  The logic and options for creating
1075	 * this object are adequately generic for default cases but for many applications it will make sense
1076	 * to override this method and create event dispatchers based on more specific needs.
1077	 *
1078	 * @return  void
1079	 *
1080	 * @since   11.3
1081	 */
1082	protected function loadDispatcher()
1083	{
1084		$this->dispatcher = JDispatcher::getInstance();
1085	}
1086
1087	/**
1088	 * Method to create a document for the Web application.  The logic and options for creating this
1089	 * object are adequately generic for default cases but for many applications it will make sense
1090	 * to override this method and create document objects based on more specific needs.
1091	 *
1092	 * @return  void
1093	 *
1094	 * @since   11.3
1095	 */
1096	protected function loadDocument()
1097	{
1098		$this->document = JFactory::getDocument();
1099	}
1100
1101	/**
1102	 * Method to create a language for the Web application.  The logic and options for creating this
1103	 * object are adequately generic for default cases but for many applications it will make sense
1104	 * to override this method and create language objects based on more specific needs.
1105	 *
1106	 * @return  void
1107	 *
1108	 * @since   11.3
1109	 */
1110	protected function loadLanguage()
1111	{
1112		$this->language = JFactory::getLanguage();
1113	}
1114
1115	/**
1116	 * Method to create a session for the Web application.  The logic and options for creating this
1117	 * object are adequately generic for default cases but for many applications it will make sense
1118	 * to override this method and create session objects based on more specific needs.
1119	 *
1120	 * @return  void
1121	 *
1122	 * @since   11.3
1123	 */
1124	protected function loadSession()
1125	{
1126		// Generate a session name.
1127		$name = md5($this->get('secret') . $this->get('session_name', get_class($this)));
1128
1129		// Calculate the session lifetime.
1130		$lifetime = (($this->get('sess_lifetime')) ? $this->get('sess_lifetime') * 60 : 900);
1131
1132		// Get the session handler from the configuration.
1133		$handler = $this->get('sess_handler', 'none');
1134
1135		// Initialize the options for JSession.
1136		$options = array(
1137			'name' => $name,
1138			'expire' => $lifetime,
1139			'force_ssl' => $this->get('force_ssl')
1140		);
1141
1142		// Instantiate the session object.
1143		$session = JSession::getInstance($handler, $options);
1144		if ($session->getState() == 'expired')
1145		{
1146			$session->restart();
1147		}
1148
1149		// If the session is new, load the user and registry objects.
1150		if ($session->isNew())
1151		{
1152			$session->set('registry', new JRegistry);
1153			$session->set('user', new JUser);
1154		}
1155
1156		// Set the session object.
1157		$this->session = $session;
1158	}
1159
1160	/**
1161	 * Method to load the system URI strings for the application.
1162	 *
1163	 * @param   string  $requestUri  An optional request URI to use instead of detecting one from the
1164	 *                               server environment variables.
1165	 *
1166	 * @return  void
1167	 *
1168	 * @since   11.3
1169	 */
1170	protected function loadSystemUris($requestUri = null)
1171	{
1172		// Set the request URI.
1173		// @codeCoverageIgnoreStart
1174		if (!empty($requestUri))
1175		{
1176			$this->set('uri.request', $requestUri);
1177		}
1178		else
1179		{
1180			$this->set('uri.request', $this->detectRequestUri());
1181		}
1182		// @codeCoverageIgnoreEnd
1183
1184		// Check to see if an explicit site URI has been set.
1185		$siteUri = trim($this->get('site_uri'));
1186		if ($siteUri != '')
1187		{
1188			$uri = JUri::getInstance($siteUri);
1189		}
1190		// No explicit site URI was set so use the system one.
1191		else
1192		{
1193			$uri = JUri::getInstance($this->get('uri.request'));
1194		}
1195
1196		// Get the host and path from the URI.
1197		$host = $uri->toString(array('scheme', 'user', 'pass', 'host', 'port'));
1198		$path = rtrim($uri->toString(array('path')), '/\\');
1199
1200		// Set the base URI both as just a path and as the full URI.
1201		$this->set('uri.base.full', $host . $path . '/');
1202		$this->set('uri.base.host', $host);
1203		$this->set('uri.base.path', $path . '/');
1204
1205		// Get an explicitly set media URI is present.
1206		$mediaURI = trim($this->get('media_uri'));
1207		if ($mediaURI)
1208		{
1209			if (strpos($mediaURI, '://') !== false)
1210			{
1211				$this->set('uri.media.full', $mediaURI);
1212				$this->set('uri.media.path', $mediaURI);
1213			}
1214			else
1215			{
1216				$this->set('uri.media.full', $this->get('uri.base.host') . $mediaURI);
1217				$this->set('uri.media.path', $mediaURI);
1218			}
1219		}
1220		// No explicit media URI was set, build it dynamically from the base uri.
1221		else
1222		{
1223			$this->set('uri.media.full', $this->get('uri.base.full') . 'media/');
1224			$this->set('uri.media.path', $this->get('uri.base.path') . 'media/');
1225		}
1226	}
1227}
1228
1229/**
1230 * Deprecated class placeholder.  You should use JApplicationWeb instead.
1231 *
1232 * @package     Joomla.Platform
1233 * @subpackage  Application
1234 * @since       11.3
1235 * @deprecated  12.3
1236 */
1237class JWeb extends JApplicationWeb
1238{
1239}