PageRenderTime 44ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/libraries/joomla/application/web.php

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