Blame | Letzte Änderung | Log anzeigen | RSS feed
<?php/*** THttpResponse class** @author Qiang Xue <qiang.xue@gmail.com>* @link http://www.pradosoft.com/* @copyright Copyright © 2005-2008 PradoSoft* @license http://www.pradosoft.com/license/* @version $Id: THttpResponse.php 2541 2008-10-21 15:05:13Z qiang.xue $* @package System.Web*//*** Includes the THttpResponse adapter.*/Prado::using('System.Web.THttpResponseAdapter');/*** THttpResponse class** THttpResponse implements the mechanism for sending output to client users.** To output a string to client, use {@link write()}. By default, the output is* buffered until {@link flush()} is called or the application ends. The output in* the buffer can also be cleaned by {@link clear()}. To disable output buffering,* set BufferOutput property to false.** To send cookies to client, use {@link getCookies()}.* To redirect client browser to a new URL, use {@link redirect()}.* To send a file to client, use {@link writeFile()}.** By default, THttpResponse is registered with {@link TApplication} as the* response module. It can be accessed via {@link TApplication::getResponse()}.** THttpResponse may be configured in application configuration file as follows** <module id="response" class="System.Web.THttpResponse" CacheExpire="20" CacheControl="nocache" BufferOutput="true" />** where {@link getCacheExpire CacheExpire}, {@link getCacheControl CacheControl}* and {@link getBufferOutput BufferOutput} are optional properties of THttpResponse.** THttpResponse sends charset header if either {@link setCharset() Charset}* or {@link TGlobalization::setCharset() TGlobalization.Charset} is set.** Since 3.1.2, HTTP status code can be set with the {@link setStatusCode StatusCode} property.** Note: Some HTTP Status codes can require additional header or body information. So, if you use {@link setStatusCode StatusCode}* in your application, be sure to add theses informations.* E.g : to make an http authentication :* <code>* public function clickAuth ($sender, $param)* {* $response=$this->getResponse();* $response->setStatusCode(401);* $response->appendHeader('WWW-Authenticate: Basic realm="Test"');* }* </code>** This event handler will sent the 401 status code (Unauthorized) to the browser, with the WWW-Authenticate header field. This* will force the browser to ask for a username and a password.** @author Qiang Xue <qiang.xue@gmail.com>* @version $Id: THttpResponse.php 2541 2008-10-21 15:05:13Z qiang.xue $* @package System.Web* @since 3.0*/class THttpResponse extends TModule implements ITextWriter{/*** @var The differents defined status code by RFC 2616 {@link http://www.faqs.org/rfcs/rfc2616}*/private static $HTTP_STATUS_CODES = array(100 => 'Continue', 101 => 'Switching Protocols',200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content',300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect',400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed',500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported');/*** @var boolean whether to buffer output*/private $_bufferOutput=true;/*** @var boolean if the application is initialized*/private $_initialized=false;/*** @var THttpCookieCollection list of cookies to return*/private $_cookies=null;/*** @var integer response status code*/private $_status=200;/*** @var string reason correspond to status code*/private $_reason='OK';/*** @var string HTML writer type*/private $_htmlWriterType='System.Web.UI.THtmlWriter';/*** @var string content type*/private $_contentType=null;/*** @var string character set, e.g. UTF-8*/private $_charset='';/*** @var THttpResponseAdapter adapter.*/private $_adapter;/*** Destructor.* Flushes any existing content in buffer.*/public function __destruct(){//if($this->_bufferOutput)// @ob_end_flush();}/*** @param THttpResponseAdapter response adapter*/public function setAdapter(THttpResponseAdapter $adapter){$this->_adapter=$adapter;}/*** @return THttpResponseAdapter response adapter, null if not exist.*/public function getAdapter(){return $this->_adapter;}/*** @return boolean true if adapter exists, false otherwise.*/public function getHasAdapter(){return !is_null($this->_adapter);}/*** Initializes the module.* This method is required by IModule and is invoked by application.* It starts output buffer if it is enabled.* @param TXmlElement module configuration*/public function init($config){if($this->_bufferOutput)ob_start();$this->_initialized=true;$this->getApplication()->setResponse($this);}/*** @return integer time-to-live for cached session pages in minutes, this has no effect for nocache limiter. Defaults to 180.*/public function getCacheExpire(){return session_cache_expire();}/*** @param integer time-to-live for cached session pages in minutes, this has no effect for nocache limiter.*/public function setCacheExpire($value){session_cache_expire(TPropertyValue::ensureInteger($value));}/*** @return string cache control method to use for session pages*/public function getCacheControl(){return session_cache_limiter();}/*** @param string cache control method to use for session pages. Valid values* include none/nocache/private/private_no_expire/public*/public function setCacheControl($value){session_cache_limiter(TPropertyValue::ensureEnum($value,array('none','nocache','private','private_no_expire','public')));}/*** @return string content type, default is text/html*/public function setContentType($type){$this->_contentType = $type;}/*** @return string current content type*/public function getContentType(){return $this->_contentType;}/*** @return string output charset.*/public function getCharset(){return $this->_charset;}/*** @param string output charset.*/public function setCharset($charset){$this->_charset = $charset;}/*** @return boolean whether to enable output buffer*/public function getBufferOutput(){return $this->_bufferOutput;}/*** @param boolean whether to enable output buffer* @throws TInvalidOperationException if session is started already*/public function setBufferOutput($value){if($this->_initialized)throw new TInvalidOperationException('httpresponse_bufferoutput_unchangeable');else$this->_bufferOutput=TPropertyValue::ensureBoolean($value);}/*** @return integer HTTP status code, defaults to 200*/public function getStatusCode(){return $this->_status;}/*** Set the HTTP status code for the response.* The code and its reason will be sent to client using the currently requested http protocol version (see {@link THttpRequest::getHttpProtocolVersion})* Keep in mind that HTTP/1.0 clients might not understand all status codes from HTTP/1.1** @param integer HTTP status code* @param string HTTP status reason, defaults to standard HTTP reasons*/public function setStatusCode($status, $reason=null){$status=TPropertyValue::ensureInteger($status);if(isset(self::$HTTP_STATUS_CODES[$status])) {$this->_reason=self::$HTTP_STATUS_CODES[$status];}else{if($reason===null || $reason==='') {throw new TInvalidDataValueException("response_status_reason_missing");}$reason=TPropertyValue::ensureString($reason);if(strpos($reason, "\r")!=false || strpos($reason, "\n")!=false) {throw new TInvalidDataValueException("response_status_reason_barchars");}$this->_reason=$reason;}$this->_status=$status;}/*** @param string HTTP status reason*/public function getStatusReason() {return $this->_reason;}/*** @return THttpCookieCollection list of output cookies*/public function getCookies(){if($this->_cookies===null)$this->_cookies=new THttpCookieCollection($this);return $this->_cookies;}/*** Outputs a string.* It may not be sent back to user immediately if output buffer is enabled.* @param string string to be output*/public function write($str){echo $str;}/*** Sends a file back to user.* Make sure not to output anything else after calling this method.* @param string file name* @param string content to be set. If null, the content will be read from the server file pointed to by $fileName.* @param string mime type of the content.* @param array list of headers to be sent. Each array element represents a header string (e.g. 'Content-Type: text/plain').* @throws TInvalidDataValueException if the file cannot be found*/public function writeFile($fileName,$content=null,$mimeType=null,$headers=null){static $defaultMimeTypes=array('css'=>'text/css','gif'=>'image/gif','jpg'=>'image/jpeg','jpeg'=>'image/jpeg','htm'=>'text/html','html'=>'text/html','js'=>'javascript/js','pdf'=>'application/pdf','xls'=>'application/vnd.ms-excel',);if($mimeType===null){$mimeType='text/plain';if(function_exists('mime_content_type'))$mimeType=mime_content_type($fileName);else if(($ext=strrchr($fileName,'.'))!==false){$ext=substr($ext,1);if(isset($defaultMimeTypes[$ext]))$mimeType=$defaultMimeTypes[$ext];}}$fn=basename($fileName);$this->sendHttpHeader();if(is_array($headers)){foreach($headers as $h)header($h);}else{header('Pragma: public');header('Expires: 0');header('Cache-Control: must-revalidate, post-check=0, pre-check=0');}header("Content-type: $mimeType");header('Content-Length: '.($content===null?filesize($fileName):strlen($content)));header("Content-Disposition: attachment; filename=\"$fn\"");header('Content-Transfer-Encoding: binary');if($content===null)readfile($fileName);elseecho $content;}/*** Redirects the browser to the specified URL.* The current application will be terminated after this method is invoked.* @param string URL to be redirected to. If the URL is a relative one, the base URL of* the current request will be inserted at the beginning.*/public function redirect($url){if($this->getHasAdapter())$this->_adapter->httpRedirect($url);else$this->httpRedirect($url);}/*** Redirect the browser to another URL and exists the current application.* This method is used internally. Please use {@link redirect} instead.* @param string URL to be redirected to. If the URL is a relative one, the base URL of* the current request will be inserted at the beginning.*/public function httpRedirect($url){if(!$this->getApplication()->getRequestCompleted())$this->getApplication()->onEndRequest();if($url[0]==='/')$url=$this->getRequest()->getBaseUrl().$url;header('Location: '.str_replace('&','&',$url));exit();}/*** Reloads the current page.* The effect of this method call is the same as user pressing the* refresh button on his browser (without post data).**/public function reload(){$this->redirect($this->getRequest()->getRequestUri());}/*** Flush the response contents and headers.*/public function flush(){if($this->getHasAdapter())$this->_adapter->flushContent();else$this->flushContent();}/*** Outputs the buffered content, sends content-type and charset header.* This method is used internally. Please use {@link flush} instead.*/public function flushContent(){Prado::trace("Flushing output",'System.Web.THttpResponse');$this->sendHttpHeader();$this->sendContentTypeHeader();if($this->_bufferOutput)ob_flush();}/*** Send the HTTP header with the status code (defaults to 200) and status reason (defaults to OK)*/protected function sendHttpHeader (){if (($version=$this->getRequest()->getHttpProtocolVersion())==='')header (' ', true, $this->_status);elseheader($version.' '.$this->_status.' '.$this->_reason, true, $this->_status);}/*** Sends content type header if charset is not empty.*/protected function sendContentTypeHeader(){$charset=$this->getCharset();if($charset==='' && ($globalization=$this->getApplication()->getGlobalization(false))!==null)$charset=$globalization->getCharset();if($charset!==''){$contentType=$this->_contentType===null?'text/html':$this->_contentType;$this->appendHeader('Content-Type: '.$contentType.';charset='.$charset);}else if($this->_contentType!==null)$this->appendHeader('Content-Type: '.$this->_contentType.';charset=UTF-8');}/*** Returns the content in the output buffer.* The buffer will NOT be cleared after calling this method.* Use {@link clear()} is you want to clear the buffer.* @return string output that is in the buffer.*/public function getContents(){Prado::trace("Retrieving output",'System.Web.THttpResponse');return $this->_bufferOutput?ob_get_contents():'';}/*** Clears any existing buffered content.*/public function clear(){if($this->_bufferOutput)ob_clean();Prado::trace("Clearing output",'System.Web.THttpResponse');}/*** Sends a header.* @param string header*/public function appendHeader($value){Prado::trace("Sending header '$value'",'System.Web.THttpResponse');header($value);}/*** Writes a log message into error log.* This method is simple wrapper of PHP function error_log.* @param string The error message that should be logged* @param integer where the error should go* @param string The destination. Its meaning depends on the message parameter as described above* @param string The extra headers. It's used when the message parameter is set to 1. This message type uses the same internal function as mail() does.* @see http://us2.php.net/manual/en/function.error-log.php*/public function appendLog($message,$messageType=0,$destination='',$extraHeaders=''){error_log($message,$messageType,$destination,$extraHeaders);}/*** Sends a cookie.* Do not call this method directly. Operate with the result of {@link getCookies} instead.* @param THttpCookie cook to be sent*/public function addCookie($cookie){$request=$this->getRequest();if($request->getEnableCookieValidation()){$value=$this->getApplication()->getSecurityManager()->hashData($cookie->getValue());setcookie($cookie->getName(),$value,$cookie->getExpire(),$cookie->getPath(),$cookie->getDomain(),$cookie->getSecure());}elsesetcookie($cookie->getName(),$cookie->getValue(),$cookie->getExpire(),$cookie->getPath(),$cookie->getDomain(),$cookie->getSecure());}/*** Deletes a cookie.* Do not call this method directly. Operate with the result of {@link getCookies} instead.* @param THttpCookie cook to be deleted*/public function removeCookie($cookie){setcookie($cookie->getName(),null,0,$cookie->getPath(),$cookie->getDomain(),$cookie->getSecure());}/*** @return string the type of HTML writer to be used, defaults to THtmlWriter*/public function getHtmlWriterType(){return $this->_htmlWriterType;}/*** @param string the type of HTML writer to be used, may be the class name or the namespace*/public function setHtmlWriterType($value){$this->_htmlWriterType=$value;}/*** Creates a new instance of HTML writer.* If the type of the HTML writer is not supplied, {@link getHtmlWriterType HtmlWriterType} will be assumed.* @param string type of the HTML writer to be created. If null, {@link getHtmlWriterType HtmlWriterType} will be assumed.*/public function createHtmlWriter($type=null){if($type===null)$type=$this->getHtmlWriterType();if($this->getHasAdapter())return $this->_adapter->createNewHtmlWriter($type, $this);elsereturn $this->createNewHtmlWriter($type, $this);}/*** Create a new html writer instance.* This method is used internally. Please use {@link createHtmlWriter} instead.* @param string type of HTML writer to be created.* @param ITextWriter text writer holding the contents.*/public function createNewHtmlWriter($type, $writer){return Prado::createComponent($type, $writer);}}