/core/model/modx/modresponse.class.php
PHP | 282 lines | 178 code | 15 blank | 89 comment | 53 complexity | 77b69df89301e70204bb4c465742b882 MD5 | raw file
- <?php
- /**
- * MODX Revolution
- *
- * Copyright 2006-2014 by MODX, LLC.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * @package modx
- */
- /**
- * Encapsulates a MODX response to a web request.
- *
- * Includes functions to manipluate header data, such as status codes, as well
- * as manipulating the response body.
- *
- * @package modx
- */
- class modResponse {
- /**
- * A reference to the modX instance
- * @var modX $modx
- */
- public $modx= null;
- /**
- * The HTTP header for this Response
- * @var string $header
- */
- public $header= null;
- /**
- * The body of this response
- * @var string $body
- */
- public $body= null;
- /**
- * The current content type on the resource
- * @var modContentType $contentType
- */
- public $contentType = null;
- /**
- * @param modX $modx A reference to the modX instance
- */
- function __construct(modX &$modx) {
- $this->modx= & $modx;
- }
- /**
- * Prepare the final response after the resource has been processed.
- *
- * @param array $options Various options that can be set.
- */
- public function outputContent(array $options = array()) {
- if (!($this->contentType = $this->modx->resource->getOne('ContentType'))) {
- if ($this->modx->getDebug() === true) {
- $this->modx->log(modX::LOG_LEVEL_DEBUG, "No valid content type for RESOURCE: " . print_r($this->modx->resource->toArray(), true));
- }
- $this->modx->log(modX::LOG_LEVEL_FATAL, "The requested resource has no valid content type specified.");
- }
- if (!$this->contentType->get('binary')) {
- $this->modx->resource->_output= $this->modx->resource->process();
- $this->modx->resource->_jscripts= $this->modx->jscripts;
- $this->modx->resource->_sjscripts= $this->modx->sjscripts;
- $this->modx->resource->_loadedjscripts= $this->modx->loadedjscripts;
- /* collect any uncached element tags in the content and process them */
- $this->modx->getParser();
- $maxIterations= intval($this->modx->getOption('parser_max_iterations', $options, 10));
- $this->modx->parser->processElementTags('', $this->modx->resource->_output, true, false, '[[', ']]', array(), $maxIterations);
- $this->modx->parser->processElementTags('', $this->modx->resource->_output, true, true, '[[', ']]', array(), $maxIterations);
- /*FIXME: only do this for HTML content ?*/
- if (strpos($this->contentType->get('mime_type'), 'text/html') !== false) {
- /* Insert Startup jscripts & CSS scripts into template - template must have a </head> tag */
- if (($js= $this->modx->getRegisteredClientStartupScripts()) && (strpos($this->modx->resource->_output, '</head>') !== false)) {
- /* change to just before closing </head> */
- $this->modx->resource->_output= preg_replace("/(<\/head>)/i", $js . "\n\\1", $this->modx->resource->_output,1);
- }
- /* Insert jscripts & html block into template - template must have a </body> tag */
- if ((strpos($this->modx->resource->_output, '</body>') !== false) && ($js= $this->modx->getRegisteredClientScripts())) {
- $this->modx->resource->_output= preg_replace("/(<\/body>)/i", $js . "\n\\1", $this->modx->resource->_output,1);
- }
- }
- $this->modx->beforeRender();
- /* invoke OnWebPagePrerender event */
- if (!isset($options['noEvent']) || empty($options['noEvent'])) {
- $this->modx->invokeEvent('OnWebPagePrerender');
- }
- $totalTime= (microtime(true) - $this->modx->startTime);
- $queryTime= $this->modx->queryTime;
- $queryTime= sprintf("%2.4f s", $queryTime);
- $queries= isset ($this->modx->executedQueries) ? $this->modx->executedQueries : 0;
- $totalTime= sprintf("%2.4f s", $totalTime);
- $phpTime= $totalTime - $queryTime;
- $phpTime= sprintf("%2.4f s", $phpTime);
- $source= $this->modx->resourceGenerated ? "database" : "cache";
- $this->modx->resource->_output= str_replace("[^q^]", $queries, $this->modx->resource->_output);
- $this->modx->resource->_output= str_replace("[^qt^]", $queryTime, $this->modx->resource->_output);
- $this->modx->resource->_output= str_replace("[^p^]", $phpTime, $this->modx->resource->_output);
- $this->modx->resource->_output= str_replace("[^t^]", $totalTime, $this->modx->resource->_output);
- $this->modx->resource->_output= str_replace("[^s^]", $source, $this->modx->resource->_output);
- } else {
- $this->modx->beforeRender();
- /* invoke OnWebPagePrerender event */
- if (!isset($options['noEvent']) || empty($options['noEvent'])) {
- $this->modx->invokeEvent("OnWebPagePrerender");
- }
- }
- /* send out content-type, content-disposition, and custom headers from the content type */
- if ($this->modx->getOption('set_header')) {
- $type= $this->contentType->get('mime_type') ? $this->contentType->get('mime_type') : 'text/html';
- $header= 'Content-Type: ' . $type;
- if (!$this->contentType->get('binary')) {
- $charset= $this->modx->getOption('modx_charset',null,'UTF-8');
- $header .= '; charset=' . $charset;
- }
- header($header);
- if (!$this->checkPreview()) {
- $dispositionSet= false;
- if ($customHeaders= $this->contentType->get('headers')) {
- foreach ($customHeaders as $headerKey => $headerString) {
- header($headerString);
- if (strpos($headerString, 'Content-Disposition:') !== false) $dispositionSet= true;
- }
- }
- if (!$dispositionSet && $this->modx->resource->get('content_dispo')) {
- if ($alias= $this->modx->resource->get('uri')) {
- $name= basename($alias);
- } elseif ($this->modx->resource->get('alias')) {
- $name= $this->modx->resource->get('alias');
- if ($ext= $this->contentType->getExtension()) {
- $name .= "{$ext}";
- }
- } elseif ($name= $this->modx->resource->get('pagetitle')) {
- $name= $this->modx->resource->cleanAlias($name);
- if ($ext= $this->contentType->getExtension()) {
- $name .= "{$ext}";
- }
- } else {
- $name= 'download';
- if ($ext= $this->contentType->getExtension()) {
- $name .= "{$ext}";
- }
- }
- $header= 'Cache-Control: public';
- header($header);
- $header= 'Content-Disposition: attachment; filename=' . $name;
- header($header);
- $header= 'Vary: User-Agent';
- header($header);
- }
- }
- }
- /* tell PHP to call _postProcess after returning the response (for caching) */
- register_shutdown_function(array (
- & $this->modx,
- "_postProcess"
- ));
- if ($this->modx->resource instanceof modStaticResource && $this->contentType->get('binary')) {
- $this->modx->resource->process();
- } else {
- if ($this->contentType->get('binary')) {
- $this->modx->resource->_output = $this->modx->resource->process();
- }
- @session_write_close();
- echo $this->modx->resource->_output;
- while (ob_get_level() && @ob_end_flush()) {}
- flush();
- exit();
- }
- }
- /**
- * Sends a redirect to the specified URL using the specified method.
- *
- * Valid $type values include:
- * REDIRECT_REFRESH Uses the header refresh method
- * REDIRECT_META Sends a a META HTTP-EQUIV="Refresh" tag to the output
- * REDIRECT_HEADER Uses the header location method
- *
- * REDIRECT_HEADER is the default.
- *
- * @param string $url The URL to redirect the client browser to.
- * @param array|boolean $options An array of options for the redirect OR
- * indicates if redirect attempts should be counted and limited to 3 (latter is deprecated
- * usage; use count_attempts in options array).
- * @param string $type The type of redirection to attempt (deprecated, use type in
- * options array).
- * @param string $responseCode The type of HTTP response code HEADER to send for the
- * redirect (deprecated, use responseCode in options array)
- * @return void|boolean
- */
- public function sendRedirect($url, $options= false, $type= '', $responseCode= '') {
- if (!is_array($options)) {
- $options = array('count_attempts' => (boolean) $options);
- }
- $options = array_merge(array('count_attempts' => false, 'type' => $type, 'responseCode' => $responseCode), $options);
- $url= str_replace('&','&',$url);
- if (empty ($url)) {
- $this->modx->log(modX::LOG_LEVEL_ERROR, "Attempted to redirect to an empty URL.");
- return false;
- }
- if (!$this->modx->getRequest()) {
- $this->modx->log(modX::LOG_LEVEL_FATAL, "Could not load request class.");
- }
- if (isset($options['preserve_request']) && !empty($options['preserve_request'])) {
- $this->modx->request->preserveRequest('referrer.redirected');
- }
- if ($options['count_attempts']) {
- /* append the redirect count string to the url */
- $currentNumberOfRedirects= isset ($_REQUEST['err']) ? $_REQUEST['err'] : 0;
- if ($currentNumberOfRedirects > 3) {
- $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>');
- } else {
- $currentNumberOfRedirects += 1;
- if (strpos($url, "?") > 0) {
- $url .= "&err=$currentNumberOfRedirects";
- } else {
- $url .= "?err=$currentNumberOfRedirects";
- }
- }
- }
- switch ($options['type']) {
- case 'REDIRECT_REFRESH':
- $header= 'Refresh: 0;URL=' . $url;
- break;
- case 'REDIRECT_META':
- $header= '<META HTTP-EQUIV="Refresh" CONTENT="0; URL=' . $url . '" />';
- echo $header;
- exit();
- default:
- if (strpos($url, '://') === false && !(substr($url, 0, 1) === '/' || substr($url, 0, 2) === './' || substr($url, 0, 3) === '../')) {
- $url= $this->modx->getOption('site_url',null,'/') . $url;
- }
- $header= 'Location: ' . $url;
- break;
- }
- @session_write_close();
- if (!empty($options['responseCode']) && (strpos($options['responseCode'], '30') !== false)) {
- header($options['responseCode']);
- }
- header($header);
- exit();
- }
- /**
- * Checks to see if the preview parameter is set.
- *
- * @return boolean
- */
- public function checkPreview() {
- $preview= false;
- if ($this->modx->checkSession('mgr') === true) {
- if (isset ($_REQUEST['z']) && $_REQUEST['z'] == 'manprev') {
- $preview= true;
- }
- }
- return $preview;
- }
- }