Kohana_Response
Implements: HTTP_Response | HTTP_Message | Kohana_HTTP_Message | Kohana_HTTP_Response
Response wrapper. Created as the result of any Request execution or utility method (i.e. Redirect). Implements standard HTTP response format.
Constants
- None
Properties
-
public static $messages
-
array(50) ( 100 => string(8) "Continue" 101 => string(19) "Switching Protocols" 102 => string(10) "Processing" 200 => string(2) "OK" 201 => string(7) "Created" 202 => string(8) "Accepted" 203 => string(29) "Non-Authoritative Information" 204 => string(10) "No Content" 205 => string(13) "Reset Content" 206 => string(15) "Partial Content" 207 => string(12) "Multi-Status" 208 => string(16) "Already Reported" 300 => string(16) "Multiple Choices" 301 => string(17) "Moved Permanently" 302 => string(5) "Found" 303 => string(9) "See Other" 304 => string(12) "Not Modified" 305 => string(9) "Use Proxy" 307 => string(18) "Temporary Redirect" 400 => string(11) "Bad Request" 401 => string(12) "Unauthorized" 402 => string(16) "Payment Required" 403 => string(9) "Forbidden" 404 => string(9) "Not Found" 405 => string(18) "Method Not Allowed" 406 => string(14) "Not Acceptable" 407 => string(29) "Proxy Authentication Required" 408 => string(15) "Request Timeout" 409 => string(8) "Conflict" 410 => string(4) "Gone" 411 => string(15) "Length Required" 412 => string(19) "Precondition Failed" 413 => string(24) "Request Entity Too Large" 414 => string(20) "Request-URI Too Long" 415 => string(22) "Unsupported Media Type" 416 => string(31) "Requested Range Not Satisfiable" 417 => string(18) "Expectation Failed" 422 => string(20) "Unprocessable Entity" 423 => string(6) "Locked" 424 => string(17) "Failed Dependency" 429 => string(17) "Too Many Requests" 500 => string(21) "Internal Server Error" 501 => string(15) "Not Implemented" 502 => string(11) "Bad Gateway" 503 => string(19) "Service Unavailable" 504 => string(15) "Gateway Timeout" 505 => string(26) "HTTP Version Not Supported" 507 => string(20) "Insufficient Storage" 508 => string(13) "Loop Detected" 509 => string(24) "Bandwidth Limit Exceeded" )
-
protected string $_body
-
The response body
-
Default value:
string(0) ""
-
protected array $_cookies
-
Cookies to be returned in the response
-
Default value:
array(0)
-
protected HTTP_Header $_header
-
Headers returned in the response
-
Default value:
NULL
-
protected string $_protocol
-
The response protocol
-
Default value:
NULL
-
protected integer $_status
-
The response http status
-
Default value:
integer 200
Methods
public __construct([ array $config = array(0) ] ) (defined in Kohana_Response)
Sets up the response object
Parameters
- array $config = array(0) - Setup the response object
Return Values
- void
Source Code
public function __construct(array $config = [])
{
$this->_header = new HTTP_Header;
foreach ($config as $key => $value)
{
if (property_exists($this, $key))
{
if ($key == '_header')
{
$this->headers($value);
}
else
{
$this->$key = $value;
}
}
}
}
public __toString() (defined in Kohana_Response)
Outputs the body when cast to string
Return Values
- string
Source Code
public function __toString()
{
return $this->_body;
}
public body() (defined in Kohana_Response)
Gets or sets the body of the response
Return Values
- mixed
Source Code
public function body($content = NULL)
{
if ($content === NULL)
return $this->_body;
$this->_body = (string) $content;
return $this;
}
public content_length() (defined in Kohana_Response)
Returns the length of the body for use with content header
Return Values
- integer
Source Code
public function content_length()
{
return strlen($this->body());
}
public cookie([ mixed $key = NULL , string $value = NULL ] ) (defined in Kohana_Response)
Set and get cookies values for this response.
// Get the cookies set to the response
$cookies = $response->cookie();
// Set a cookie to the response
$response->cookie('session', array(
'value' => $value,
'expiration' => 12352234
));
Parameters
- mixed $key = NULL - Cookie name, or array of cookie values
- string $value = NULL - Value to set to cookie
Return Values
- string
- void
- [Response]
Source Code
public function cookie($key = NULL, $value = NULL)
{
// Handle the get cookie calls
if ($key === NULL)
return $this->_cookies;
elseif ( ! is_array($key) AND ! $value)
return Arr::get($this->_cookies, $key);
// Handle the set cookie calls
if (is_array($key))
{
reset($key);
foreach ($key as $_key => $_value)
{
$this->cookie($_key, $_value);
}
}
else
{
if ( ! is_array($value))
{
$value = [
'value' => $value,
'expiration' => Cookie::$expiration
];
}
elseif ( ! isset($value['expiration']))
{
$value['expiration'] = Cookie::$expiration;
}
$this->_cookies[$key] = $value;
}
return $this;
}
public delete_cookie(string $name ) (defined in Kohana_Response)
Deletes a cookie set to the response
Parameters
- string $name required - $name
Return Values
- Response
Source Code
public function delete_cookie($name)
{
unset($this->_cookies[$name]);
return $this;
}
public delete_cookies() (defined in Kohana_Response)
Deletes all cookies from this response
Return Values
- Response
Source Code
public function delete_cookies()
{
$this->_cookies = [];
return $this;
}
public static factory([ array $config = array(0) ] ) (defined in Kohana_Response)
Factory method to create a new Response. Pass properties in using an associative array.
// Create a new response
$response = Response::factory();
// Create a new response with headers
$response = Response::factory(array('status' => 200));
Parameters
- array $config = array(0) - Setup the response object
Return Values
- Response
Source Code
public static function factory(array $config = [])
{
return new Response($config);
}
public generate_etag() (defined in Kohana_Response)
Generate ETag Generates an ETag from the response ready to be returned
Tags
Return Values
- String - Generated ETag
Source Code
public function generate_etag()
{
if ($this->_body === '')
{
throw new Request_Exception('No response yet associated with request - cannot auto generate resource ETag');
}
// Generate a unique hash for the response
return '"'.sha1($this->render()).'"';
}
public headers([ mixed $key = NULL , string $value = NULL ] ) (defined in Kohana_Response)
Gets and sets headers to the Response, allowing chaining of response methods. If chaining isn't required, direct access to the property should be used instead.
// Get a header
$accept = $response->headers('Content-Type');
// Set a header
$response->headers('Content-Type', 'text/html');
// Get all headers
$headers = $response->headers();
// Set multiple headers
$response->headers(array('Content-Type' => 'text/html', 'Cache-Control' => 'no-cache'));
Parameters
- mixed $key = NULL - $key
- string $value = NULL - $value
Return Values
- mixed
Source Code
public function headers($key = NULL, $value = NULL)
{
if ($key === NULL)
{
return $this->_header;
}
elseif (is_array($key))
{
$this->_header->exchangeArray($key);
return $this;
}
elseif ($value === NULL)
{
return Arr::get($this->_header, $key);
}
else
{
$this->_header[$key] = $value;
return $this;
}
}
public protocol([ string $protocol = NULL ] ) (defined in Kohana_Response)
Gets or sets the HTTP protocol. The standard protocol to use
is HTTP/1.1
.
Parameters
- string $protocol = NULL - Protocol to set to the request/response
Return Values
- mixed
Source Code
public function protocol($protocol = NULL)
{
if ($protocol)
{
$this->_protocol = strtoupper($protocol);
return $this;
}
if ($this->_protocol === NULL)
{
$this->_protocol = HTTP::$protocol;
}
return $this->_protocol;
}
public render() (defined in Kohana_Response)
Renders the HTTP_Interaction to a string, producing
- Protocol
- Headers
- Body
Return Values
- string
Source Code
public function render()
{
if ( ! $this->_header->offsetExists('content-type'))
{
// Add the default Content-Type header if required
$this->_header['content-type'] = Kohana::$content_type.'; charset='.Kohana::$charset;
}
// Set the content length
$this->headers('content-length', (string) $this->content_length());
// If Kohana expose, set the user-agent
if (Kohana::$expose)
{
$this->headers('user-agent', Kohana::version());
}
// Prepare cookies
if ($this->_cookies)
{
if (extension_loaded('http'))
{
$cookies = version_compare(phpversion('http'), '2.0.0', '>=') ?
(string) new \http\Cookie($this->_cookies) :
http_build_cookie($this->_cookies);
$this->_header['set-cookie'] = $cookies;
}
else
{
$cookies = [];
// Parse each
foreach ($this->_cookies as $key => $value)
{
$string = $key.'='.$value['value'].'; expires='.date('l, d M Y H:i:s T', $value['expiration']);
$cookies[] = $string;
}
// Create the cookie string
$this->_header['set-cookie'] = $cookies;
}
}
$output = $this->_protocol.' '.$this->_status.' '.Response::$messages[$this->_status]."\r\n";
$output .= (string) $this->_header;
$output .= $this->_body;
return $output;
}
public send_file(string|resource|bool $filename [, string $download = NULL , array $options = NULL ] ) (defined in Kohana_Response)
Send file download as the response. All execution will be halted when this method is called! Use TRUE for the filename to send the current response as the file content. The third parameter allows the following options to be set:
Type | Option | Description | Default Value |
---|---|---|---|
boolean |
inline | Display inline instead of download | FALSE |
string |
mime_type | Manual mime type | Automatic |
boolean |
delete | Delete the file after sending | FALSE |
Download a file that already exists:
$request->send_file('media/packages/kohana.zip');
Download a generated file:
$csv = tmpfile();
fputcsv($csv, ['label1', 'label2']);
$request->send_file($csv, $filename);
Download generated content as a file:
$request->response($content);
$request->send_file(TRUE, $filename);
No further processing can be done after this method is called!
Parameters
- string|resource|bool $filename required - Filename with path, file stream, or TRUE for the current response
- string $download = NULL - Downloaded file name
- array $options = NULL - Additional options
Tags
Return Values
- void
Source Code
public function send_file($filename, $download = NULL, array $options = NULL)
{
if ( ! empty($options['mime_type']))
{
// The mime-type has been manually set
$mime = $options['mime_type'];
}
if ($filename === TRUE)
{
if (empty($download))
{
throw new Kohana_Exception('Download name must be provided for streaming files');
}
// Temporary files will automatically be deleted
$options['delete'] = FALSE;
if ( ! isset($mime))
{
// Guess the mime using the file extension
$mime = File::mime_by_ext(strtolower(pathinfo($download, PATHINFO_EXTENSION)));
}
// Force the data to be rendered if
$file_data = (string) $this->_body;
// Get the content size
$size = strlen($file_data);
// Create a temporary file to hold the current response
$file = tmpfile();
// Write the current response into the file
fwrite($file, $file_data);
// File data is no longer needed
unset($file_data);
}
else if (is_resource($filename) && get_resource_type($filename) === 'stream')
{
if (empty($download))
{
throw new Kohana_Exception('Download name must be provided for streaming files');
}
// Make sure this is a file handle
$file_meta = stream_get_meta_data($filename);
if ($file_meta['seekable'] === FALSE)
{
throw new Kohana_Exception('Resource must be a file handle');
}
// Handle file streams passed in as resources
$file = $filename;
$size = fstat($file)['size'];
}
else
{
// Get the complete file path
$filename = realpath($filename);
if (empty($download))
{
// Use the file name as the download file name
$download = pathinfo($filename, PATHINFO_BASENAME);
}
// Get the file size
$size = filesize($filename);
if ( ! isset($mime))
{
// Get the mime type from the extension of the download file
$mime = File::mime_by_ext(pathinfo($download, PATHINFO_EXTENSION));
}
// Open the file for reading
$file = fopen($filename, 'rb');
}
if ( ! is_resource($file))
{
throw new Kohana_Exception('Could not read file to send: :file', [
':file' => $download,
]);
}
// Inline or download?
$disposition = empty($options['inline']) ? 'attachment' : 'inline';
// Calculate byte range to download.
list($start, $end) = $this->_calculate_byte_range($size);
if ( ! empty($options['resumable']))
{
if ($start > 0 OR $end < ($size - 1))
{
// Partial Content
$this->_status = 206;
}
// Range of bytes being sent
$this->_header['content-range'] = 'bytes '.$start.'-'.$end.'/'.$size;
$this->_header['accept-ranges'] = 'bytes';
}
// Set the headers for a download
$this->_header['content-disposition'] = $disposition.'; filename="'.$download.'"';
$this->_header['content-type'] = $mime;
$this->_header['content-length'] = (string) (($end - $start) + 1);
if (Request::user_agent('browser') === 'Internet Explorer')
{
// Naturally, IE does not act like a real browser...
if (Request::$initial->secure())
{
// http://support.microsoft.com/kb/316431
$this->_header['pragma'] = $this->_header['cache-control'] = 'public';
}
if (version_compare(Request::user_agent('version'), '8.0', '>='))
{
// http://ajaxian.com/archives/ie-8-security
$this->_header['x-content-type-options'] = 'nosniff';
}
}
// Send all headers now
$this->send_headers();
while (ob_get_level())
{
// Flush all output buffers
ob_end_flush();
}
// Manually stop execution
ignore_user_abort(TRUE);
// Send data in 16kb blocks
$block = 1024 * 16;
fseek($file, $start);
while ( ! feof($file) AND ($pos = ftell($file)) <= $end)
{
if (connection_aborted())
break;
if ($pos + $block > $end)
{
// Don't read past the buffer.
$block = $end - $pos + 1;
}
// Output a block of the file
echo fread($file, $block);
// Send the data now
flush();
}
// Close the file
fclose($file);
if ( ! empty($options['delete']))
{
try
{
// Attempt to remove the file
unlink($filename);
}
catch (Exception $e)
{
// Create a text version of the exception
$error = Kohana_Exception::text($e);
if (is_object(Kohana::$log))
{
// Add this exception to the log
Kohana::$log->add(Log::ERROR, $error);
// Make sure the logs are written
Kohana::$log->write();
}
// Do NOT display the exception, it will corrupt the output!
}
}
// Stop execution
exit;
}
public send_headers([ boolean $replace = bool FALSE , callback $callback = NULL ] ) (defined in Kohana_Response)
Sends the response status and all set headers.
Parameters
- boolean $replace = bool FALSE - Replace existing headers
- callback $callback = NULL - Function to handle header output
Return Values
- mixed
Source Code
public function send_headers($replace = FALSE, $callback = NULL)
{
return $this->_header->send_headers($this, $replace, $callback);
}
public status([ integer $status = NULL ] ) (defined in Kohana_Response)
Sets or gets the HTTP status from this response.
// Set the HTTP status to 404 Not Found
$response = Response::factory()
->status(404);
// Get the current status
$status = $response->status();
Parameters
- integer $status = NULL - Status to set to this response
Return Values
- mixed
Source Code
public function status($status = NULL)
{
if ($status === NULL)
{
return $this->_status;
}
elseif (array_key_exists($status, Response::$messages))
{
$this->_status = (int) $status;
return $this;
}
else
{
throw new Kohana_Exception(__METHOD__.' unknown status value : :value', [':value' => $status]);
}
}
protected _calculate_byte_range(integer $size ) (defined in Kohana_Response)
Calculates the byte range to use with send_file. If HTTP_RANGE doesn't exist then the complete byte range is returned
Parameters
- integer $size required - $size
Return Values
- array
Source Code
protected function _calculate_byte_range($size)
{
// Defaults to start with when the HTTP_RANGE header doesn't exist.
$start = 0;
$end = $size - 1;
if ($range = $this->_parse_byte_range())
{
// We have a byte range from HTTP_RANGE
$start = $range[1];
if ($start[0] === '-')
{
// A negative value means we start from the end, so -500 would be the
// last 500 bytes.
$start = $size - abs($start);
}
if (isset($range[2]))
{
// Set the end range
$end = $range[2];
}
}
// Normalize values.
$start = abs(intval($start));
// Keep the the end value in bounds and normalize it.
$end = min(abs(intval($end)), $size - 1);
// Keep the start in bounds.
$start = ($end < $start) ? 0 : max($start, 0);
return [$start, $end];
}
protected _parse_byte_range() (defined in Kohana_Response)
Parse the byte ranges from the HTTP_RANGE header used for resumable downloads.
Tags
Return Values
- array|FALSE
Source Code
protected function _parse_byte_range()
{
if ( ! isset($_SERVER['HTTP_RANGE']))
{
return FALSE;
}
// TODO, speed this up with the use of string functions.
preg_match_all('/(-?[0-9]++(?:-(?![0-9]++))?)(?:-?([0-9]++))?/', $_SERVER['HTTP_RANGE'], $matches, PREG_SET_ORDER);
return $matches[0];
}