PageRenderTime 52ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/core/model/modx/modresponse.class.php

https://github.com/gbds/revolution
PHP | 260 lines | 177 code | 16 blank | 67 comment | 52 complexity | e11ab6aa9754d43de6b45fb7c8be6702 MD5 | raw file
  1. <?php
  2. /*
  3. * MODX Revolution
  4. *
  5. * Copyright 2006-2011 by MODX, LLC.
  6. * All rights reserved.
  7. *
  8. * This program is free software; you can redistribute it and/or modify it under
  9. * the terms of the GNU General Public License as published by the Free Software
  10. * Foundation; either version 2 of the License, or (at your option) any later
  11. * version.
  12. *
  13. * This program is distributed in the hope that it will be useful, but WITHOUT
  14. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  15. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU General Public License along with
  19. * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  20. * Place, Suite 330, Boston, MA 02111-1307 USA
  21. */
  22. /**
  23. * Encapsulates a MODX response to a web request.
  24. *
  25. * Includes functions to manipluate header data, such as status codes, as well
  26. * as manipulating the response body.
  27. *
  28. * @package modx
  29. */
  30. class modResponse {
  31. public $modx= null;
  32. public $header= null;
  33. public $body= null;
  34. function __construct(modX &$modx) {
  35. $this->modx= & $modx;
  36. }
  37. /**
  38. * Prepare the final response after the resource has been processed.
  39. *
  40. * @param array $options Various options that can be set.
  41. */
  42. public function outputContent(array $options = array()) {
  43. if (!($contentType = $this->modx->resource->getOne('ContentType'))) {
  44. if ($this->modx->getDebug() === true) {
  45. $this->modx->log(modX::LOG_LEVEL_DEBUG, "No valid content type for RESOURCE: " . print_r($this->modx->resource->toArray(), true));
  46. }
  47. $this->modx->log(modX::LOG_LEVEL_FATAL, "The requested resource has no valid content type specified.");
  48. }
  49. if (!$contentType->get('binary')) {
  50. $this->modx->resource->process();
  51. $this->modx->resource->_output= $this->modx->resource->_content;
  52. $this->modx->resource->_jscripts= $this->modx->jscripts;
  53. $this->modx->resource->_sjscripts= $this->modx->sjscripts;
  54. $this->modx->resource->_loadedjscripts= $this->modx->loadedjscripts;
  55. /* collect any uncached element tags in the content and process them */
  56. $this->modx->getParser();
  57. $maxIterations= intval($this->modx->getOption('parser_max_iterations', $options, 10));
  58. $this->modx->parser->processElementTags('', $this->modx->resource->_output, true, false, '[[', ']]', array(), $maxIterations);
  59. $this->modx->parser->processElementTags('', $this->modx->resource->_output, true, true, '[[', ']]', array(), $maxIterations);
  60. /*FIXME: only do this for HTML content ?*/
  61. if (strpos($contentType->get('mime_type'), 'text/html') !== false) {
  62. /* Insert Startup jscripts & CSS scripts into template - template must have a </head> tag */
  63. if (($js= $this->modx->getRegisteredClientStartupScripts()) && (strpos($this->modx->resource->_output, '</head>') !== false)) {
  64. /* change to just before closing </head> */
  65. $this->modx->resource->_output= preg_replace("/(<\/head>)/i", $js . "\n\\1", $this->modx->resource->_output);
  66. }
  67. /* Insert jscripts & html block into template - template must have a </body> tag */
  68. if ((strpos($this->modx->resource->_output, '</body>') !== false) && ($js= $this->modx->getRegisteredClientScripts())) {
  69. $this->modx->resource->_output= preg_replace("/(<\/body>)/i", $js . "\n\\1", $this->modx->resource->_output);
  70. }
  71. }
  72. $this->modx->beforeRender();
  73. /* invoke OnWebPagePrerender event */
  74. if (!isset($options['noEvent']) || empty($options['noEvent'])) {
  75. $this->modx->invokeEvent('OnWebPagePrerender');
  76. }
  77. $totalTime= ($this->modx->getMicroTime() - $this->modx->startTime);
  78. $queryTime= $this->modx->queryTime;
  79. $queryTime= sprintf("%2.4f s", $queryTime);
  80. $queries= isset ($this->modx->executedQueries) ? $this->modx->executedQueries : 0;
  81. $totalTime= sprintf("%2.4f s", $totalTime);
  82. $phpTime= $totalTime - $queryTime;
  83. $phpTime= sprintf("%2.4f s", $phpTime);
  84. $source= $this->modx->resourceGenerated ? "database" : "cache";
  85. $this->modx->resource->_output= str_replace("[^q^]", $queries, $this->modx->resource->_output);
  86. $this->modx->resource->_output= str_replace("[^qt^]", $queryTime, $this->modx->resource->_output);
  87. $this->modx->resource->_output= str_replace("[^p^]", $phpTime, $this->modx->resource->_output);
  88. $this->modx->resource->_output= str_replace("[^t^]", $totalTime, $this->modx->resource->_output);
  89. $this->modx->resource->_output= str_replace("[^s^]", $source, $this->modx->resource->_output);
  90. } else {
  91. $this->modx->beforeRender();
  92. /* invoke OnWebPagePrerender event */
  93. if (!isset($options['noEvent']) || empty($options['noEvent'])) {
  94. $this->modx->invokeEvent("OnWebPagePrerender");
  95. }
  96. }
  97. /* send out content-type, content-disposition, and custom headers from the content type */
  98. if ($this->modx->getOption('set_header')) {
  99. $type= $contentType->get('mime_type') ? $contentType->get('mime_type') : 'text/html';
  100. $header= 'Content-Type: ' . $type;
  101. if (!$contentType->get('binary')) {
  102. $charset= $this->modx->getOption('modx_charset',null,'UTF-8');
  103. $header .= '; charset=' . $charset;
  104. }
  105. header($header);
  106. if (!$this->checkPreview()) {
  107. $dispositionSet= false;
  108. if ($customHeaders= $contentType->get('headers')) {
  109. foreach ($customHeaders as $headerKey => $headerString) {
  110. header($headerString);
  111. if (strpos($headerString, 'Content-Disposition:') !== false) $dispositionSet= true;
  112. }
  113. }
  114. if (!$dispositionSet && $this->modx->resource->get('content_dispo')) {
  115. if ($alias= array_search($this->modx->resourceIdentifier, $this->modx->aliasMap)) {
  116. $name= basename($alias);
  117. } elseif ($this->modx->resource->get('alias')) {
  118. $name= $this->modx->resource->get('alias');
  119. if ($ext= $contentType->getExtension()) {
  120. $name .= ".{$ext}";
  121. }
  122. } elseif ($name= $this->modx->resource->get('pagetitle')) {
  123. $name= $this->modx->resource->cleanAlias($name);
  124. if ($ext= $contentType->getExtension()) {
  125. $name .= ".{$ext}";
  126. }
  127. } else {
  128. $name= 'download';
  129. if ($ext= $contentType->getExtension()) {
  130. $name .= ".{$ext}";
  131. }
  132. }
  133. $header= 'Cache-Control: public';
  134. header($header);
  135. $header= 'Content-Disposition: attachment; filename=' . $name;
  136. header($header);
  137. $header= 'Vary: User-Agent';
  138. header($header);
  139. }
  140. }
  141. }
  142. /* tell PHP to call _postProcess after returning the response (for caching) */
  143. register_shutdown_function(array (
  144. & $this->modx,
  145. "_postProcess"
  146. ));
  147. if ($this->modx->resource instanceof modStaticResource && $contentType->get('binary')) {
  148. $this->modx->resource->process();
  149. } else {
  150. if ($contentType->get('binary')) {
  151. $this->modx->resource->_output = $this->modx->resource->process();
  152. }
  153. @session_write_close();
  154. echo $this->modx->resource->_output;
  155. while (@ ob_end_flush()) {}
  156. exit();
  157. }
  158. }
  159. /**
  160. * Sends a redirect to the specified URL using the specified method.
  161. *
  162. * Valid $type values include:
  163. * REDIRECT_REFRESH Uses the header refresh method
  164. * REDIRECT_META Sends a a META HTTP-EQUIV="Refresh" tag to the output
  165. * REDIRECT_HEADER Uses the header location method
  166. *
  167. * REDIRECT_HEADER is the default.
  168. *
  169. * @param string $url The URL to redirect the client browser to.
  170. * @param array|boolean $options An array of options for the redirect OR
  171. * indicates if redirect attempts should be counted and limited to 3 (latter is deprecated
  172. * usage; use count_attempts in options array).
  173. * @param string $type The type of redirection to attempt (deprecated, use type in
  174. * options array).
  175. * @param string $responseCode The type of HTTP response code HEADER to send for the
  176. * redirect (deprecated, use responseCode in options array)
  177. */
  178. public function sendRedirect($url, $options= false, $type= '', $responseCode= '') {
  179. if (!is_array($options)) {
  180. $options = array('count_attempts' => (boolean) $options);
  181. }
  182. $options = array_merge(array('count_attempts' => false, 'type' => $type, 'responseCode' => $responseCode), $options);
  183. $url= str_replace('&amp;','&',$url);
  184. if (empty ($url)) {
  185. $this->modx->log(modX::LOG_LEVEL_ERROR, "Attempted to redirect to an empty URL.");
  186. return false;
  187. }
  188. if (!$this->modx->getRequest()) {
  189. $this->modx->log(modX::LOG_LEVEL_FATAL, "Could not load request class.");
  190. }
  191. if (isset($options['preserve_request']) && !empty($options['preserve_request'])) {
  192. $this->modx->request->preserveRequest('referrer.redirected');
  193. }
  194. if ($options['count_attempts']) {
  195. /* append the redirect count string to the url */
  196. $currentNumberOfRedirects= isset ($_REQUEST['err']) ? $_REQUEST['err'] : 0;
  197. if ($currentNumberOfRedirects > 3) {
  198. $this->modx->log(modX::LOG_LEVEL_FATAL, 'Redirection attempt failed - please ensure the resource you\'re trying to redirect to exists. <p>Redirection URL: <i>' . $url . '</i></p>');
  199. } else {
  200. $currentNumberOfRedirects += 1;
  201. if (strpos($url, "?") > 0) {
  202. $url .= "&err=$currentNumberOfRedirects";
  203. } else {
  204. $url .= "?err=$currentNumberOfRedirects";
  205. }
  206. }
  207. }
  208. switch ($options['type']) {
  209. case 'REDIRECT_REFRESH':
  210. $header= 'Refresh: 0;URL=' . $url;
  211. break;
  212. case 'REDIRECT_META':
  213. $header= '<META HTTP-EQUIV="Refresh" CONTENT="0; URL=' . $url . '" />';
  214. echo $header;
  215. exit();
  216. default:
  217. if (strpos($url, '://') === false && !(substr($url, 0, 1) === '/' || substr($url, 0, 2) === './' || substr($url, 0, 3) === '../')) {
  218. $url= $this->modx->getOption('site_url',null,'/') . $url;
  219. }
  220. $header= 'Location: ' . $url;
  221. break;
  222. }
  223. @session_write_close();
  224. if (!empty($options['responseCode']) && (strpos($options['responseCode'], '30') !== false)) {
  225. header($options['responseCode']);
  226. }
  227. header($header);
  228. exit();
  229. }
  230. /**
  231. * Checks to see if the preview parameter is set.
  232. *
  233. * @return boolean
  234. */
  235. public function checkPreview() {
  236. $preview= false;
  237. if ($this->modx->checkSession('mgr') === true) {
  238. if (isset ($_REQUEST['z']) && $_REQUEST['z'] == 'manprev') {
  239. $preview= true;
  240. }
  241. }
  242. return $preview;
  243. }
  244. }