2007-08-17 05:32:14 +02:00
< ? php
/**
* Represenets an HTTPResponse returned by a controller .
2008-02-25 03:10:37 +01:00
*
* @ package sapphire
* @ subpackage control
2007-08-17 05:32:14 +02:00
*/
class HTTPResponse extends Object {
protected static $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' ,
301 => 'Moved Permanently' ,
302 => 'Found' ,
303 => 'See Other' ,
304 => 'Not Modified' ,
305 => 'Use Proxy' ,
307 => 'Temporary Redirect' ,
400 => 'Bad Request' ,
401 => 'Unauthorized' ,
403 => 'Forbidden' ,
404 => 'Not Found' ,
405 => 'Method Not Allowed' ,
406 => 'Not Acceptable' ,
407 => 'Proxy Authentication Required' ,
408 => 'Request Timeout' ,
409 => 'Conflict' ,
410 => 'Gone' ,
411 => 'Length Required' ,
412 => 'Precondition Failed' ,
413 => 'Request Entity Too Large' ,
414 => 'Request-URI Too Long' ,
415 => 'Unsupported Media Type' ,
416 => 'Request Range Not Satisfiable' ,
417 => 'Expectation Failed' ,
500 => 'Internal Server Error' ,
501 => 'Not Implemented' ,
502 => 'Bad Gateway' ,
503 => 'Service Unavailable' ,
504 => 'Gateway Timeout' ,
505 => 'HTTP Version Not Supported' ,
);
2008-04-22 03:45:55 +02:00
protected static $redirect_codes = array (
301 ,
302 ,
303 ,
304 ,
305 ,
307
);
2007-08-17 05:32:14 +02:00
protected $statusCode = 200 ;
2008-09-12 03:47:39 +02:00
protected $statusDescription = " OK " ;
2008-08-09 09:03:24 +02:00
/**
* HTTP Headers like " Content-Type: text/xml "
*
* @ see http :// en . wikipedia . org / wiki / List_of_HTTP_headers
* @ var array
*/
2007-08-17 05:32:14 +02:00
protected $headers = array ();
2008-08-09 09:03:24 +02:00
/**
* @ var string
*/
2007-08-17 05:32:14 +02:00
protected $body = null ;
2008-09-12 03:47:39 +02:00
/**
* Create a new HTTP response
* @ param $body The body of the response
* @ param $statusCode The numeric status code - 200 , 404 , etc
* @ param $statusDescription The text to be given alongside the status code . This can be accessed by javascript
*/
function __construct ( $body = null , $statusCode = null , $statusDescription = null ) {
parent :: __construct ();
$this -> body = $body ;
if ( $statusCode ) $this -> setStatusCode ( $statusCode , $statusDescription );
}
function setStatusCode ( $code , $description = null ) {
2007-08-17 05:32:14 +02:00
if ( isset ( self :: $status_codes [ $code ])) $this -> statusCode = $code ;
else user_error ( " Unrecognised HTTP status code ' $code ' " , E_USER_WARNING );
2008-09-12 03:47:39 +02:00
if ( $description ) $this -> statusDescription = $description ;
else $this -> statusDescription = self :: $status_codes [ $code ];
2007-08-17 05:32:14 +02:00
}
2008-08-09 09:03:24 +02:00
2007-12-02 22:29:31 +01:00
function getStatusCode () {
return $this -> statusCode ;
}
2008-08-11 05:03:52 +02:00
/**
* @ return string Description for a HTTP status code
*/
function getStatusDescription () {
2008-09-12 03:47:39 +02:00
return $this -> statusDescription ;
2008-08-11 05:03:52 +02:00
}
2007-08-17 05:32:14 +02:00
2008-08-11 02:03:57 +02:00
/**
* Returns true if this HTTP response is in error
*/
function isError () {
return $this -> statusCode && ( $this -> statusCode < 200 || $this -> statusCode > 399 );
}
2007-08-17 05:32:14 +02:00
function setBody ( $body ) {
$this -> body = $body ;
}
2008-08-09 09:03:24 +02:00
2007-08-17 05:32:14 +02:00
function getBody () {
return $this -> body ;
}
2007-08-27 07:09:54 +02:00
/**
2008-08-09 09:03:24 +02:00
* Add a HTTP header to the response , replacing any header of the same name .
*
* @ param string $header Example : " Content-Type "
* @ param string $value Example : " text/xml "
2007-08-27 07:09:54 +02:00
*/
2007-08-17 05:32:14 +02:00
function addHeader ( $header , $value ) {
$this -> headers [ $header ] = $value ;
}
2007-08-27 07:09:54 +02:00
/**
2008-08-09 09:03:24 +02:00
* Return the HTTP header of the given name .
*
* @ param string $header
2007-08-27 07:09:54 +02:00
* @ returns string
*/
function getHeader ( $header ) {
2007-08-31 02:26:41 +02:00
if ( isset ( $this -> headers [ $header ])) {
return $this -> headers [ $header ];
} else {
return null ;
}
2007-08-27 07:09:54 +02:00
}
2008-08-09 09:03:24 +02:00
/**
* @ return array
*/
function getHeaders () {
return $this -> headers ;
}
/**
* Remove an existing HTTP header by its name ,
* e . g . " Content-Type " .
*
* @ param unknown_type $header
*/
function removeHeader ( $header ) {
if ( isset ( $this -> headers [ $header ])) unset ( $this -> headers [ $header ]);
}
2008-04-22 03:45:55 +02:00
function redirect ( $dest , $code = 302 ) {
if ( ! in_array ( $code , self :: $redirect_codes )) $code = 302 ;
$this -> statusCode = $code ;
2007-08-17 05:32:14 +02:00
$this -> headers [ 'Location' ] = $dest ;
}
/**
* Send this HTTPReponse to the browser
*/
function output () {
2008-11-12 05:31:33 +01:00
// Attach appropriate X-Include-JavaScript and X-Include-CSS headers
if ( Director :: is_ajax ()) {
Requirements :: include_in_response ( $this );
}
2008-04-22 03:45:55 +02:00
if ( in_array ( $this -> statusCode , self :: $redirect_codes ) && headers_sent ( $file , $line )) {
2007-08-17 05:32:14 +02:00
$url = $this -> headers [ 'Location' ];
2008-08-11 05:03:52 +02:00
echo
2007-08-17 05:32:14 +02:00
" <p>Redirecting to <a href= \" $url\ " title = \ " Please click this link if your browser does not redirect you \" > $url ... (output started on $file , line $line )</a></p>
< meta http - equiv = \ " refresh \" content= \" 1; url= $url\ " />
< script type = \ " text/javascript \" >setTimeout('window.location.href = \" $url\ " ' , 50 ); </ script > " ;
} else {
if ( ! headers_sent ()) {
2008-09-29 22:23:47 +02:00
header ( $_SERVER [ 'SERVER_PROTOCOL' ] . " $this->statusCode " . $this -> getStatusDescription ());
2007-08-17 05:32:14 +02:00
foreach ( $this -> headers as $header => $value ) {
header ( " $header : $value " );
}
}
2008-10-01 16:43:43 +02:00
if ( Director :: isLive () && $this -> isError ()) {
Debug :: friendlyError ( $this -> statusCode , $this -> getStatusDescription ());
} else {
echo $this -> body ;
}
2007-08-17 05:32:14 +02:00
}
}
/**
* Returns true if this response is " finished " , that is , no more script execution should be done .
* Specifically , returns true if a redirect has already been requested
*/
function isFinished () {
return $this -> statusCode == 302 || $this -> statusCode == 301 ;
}
2007-08-21 00:38:37 +02:00
/**
* Return all the links in the body as an array .
* @ returns An array of maps . Each map will contain 'id' , 'class' , and 'href' , representing the HTML attributes of the link .
*/
function getLinks () {
$attributes = array ( 'id' , 'href' , 'class' );
$links = array ();
$results = array ();
preg_match_all ( '/<a[^>]+>/i' , $this -> body , $links );
// $links[0] contains the actual matches
foreach ( $links [ 0 ] as $link ) {
$processedLink = array ();
foreach ( $attributes as $attribute ) {
$matches = array ();
if ( preg_match ( '/' . $attribute . '\s*=\s*"([^"]+)"/i' , $link , $matches )) {
$processedLink [ $attribute ] = $matches [ 1 ];
}
}
$results [] = $processedLink ;
}
return $results ;
}
2007-08-17 05:32:14 +02:00
}