模块

Response

Response wrapper. Created as the result of any Request execution or utility method (i.e. Redirect). Implements standard HTTP response format.

package
BootPHP
category
Base
author
Tinsh
copyright
© 2005-2016 Kilofox Studio

该类在 SYSPATH/classes/response.php 第 13 行声明。

属性

public static $messages

array(41) (
	100 => string(8) "Continue"
	101 => string(19) "Switching Protocols"
	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"
	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"
	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"
	509 => string(24) "Bandwidth Limit Exceeded"
)

protected string $_body

The response body

protected array $_cookies

Cookies to be returned in the response

protected HTTP_Header $_header

Headers returned in the response

protected string $_protocol

The response protocol

protected integer $_status

The response http status

方法

public __construct( [ array $config = array(0) ] ) (在 Response 中定义)

Sets up the response object

参数

  • array $config = array(0) - Setup the response object

返回值

  • void

源代码

public function __construct(array $config = array())
{
	$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( ) (在 Response 中定义)

Outputs the body when cast to string

返回值

  • string

源代码

public function __toString()
{
	return $this->_body;
}

public body( ) (在 Response 中定义)

Gets || sets the body of the response

返回值

  • mixed

源代码

public function body($content = NULL)
{
	if ($content === NULL)
		return $this->_body;
	$this->_body = (string) $content;
	return $this;
}

public check_cache( [ string $etag = NULL , Request $request = NULL ] ) (在 Response 中定义)

Check Cache Checks the browser cache to see the response needs to be returned

参数

  • string $etag = NULL - Resource ETag
  • Request $request = NULL - The request to test against

Tags

返回值

  • Response

源代码

public function check_cache($etag = NULL, Request $request = NULL)
{
	if (!$etag)
	{
		$etag = $this->generate_etag();
	}
	if (!$request)
		throw new Request_Exception('A Request object must be supplied with an etag for evaluation');
	// Set the ETag header
	$this->_header['etag'] = $etag;
	// Add the Cache-Control header if it is not already set
	// This allows etags to be used with max-age, etc
	if ($this->_header->offsetExists('cache-control'))
	{
		if (is_array($this->_header['cache-control']))
		{
			$this->_header['cache-control'][] = new HTTP_Header_Value('must-revalidate');
		}
		else
		{
			$this->_header['cache-control'] = $this->_header['cache-control'] . ', must-revalidate';
		}
	}
	else
	{
		$this->_header['cache-control'] = 'must-revalidate';
	}
	if ($request->headers('if-none-match') && (string) $request->headers('if-none-match') === $etag)
	{
		// No need to send data again
		$this->_status = 304;
		$this->send_headers();
		// Stop execution
		exit;
	}
	return $this;
}

public content_length( ) (在 Response 中定义)

Returns the length of the body for use with content header

返回值

  • integer

源代码

public function content_length()
{
	return strlen($this->body());
}

Set && 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
));

参数

  • mixed $key = NULL - Cookie name, || array of cookie values
  • string $value = NULL - Value to set to cookie

返回值

  • string
  • void
  • [Response]

源代码

public function cookie($key = NULL, $value = NULL)
{
	// Handle the get cookie calls
	if ($key === NULL)
		return $this->_cookies;
	elseif (!is_array($key) && !$value)
		return Arr::get($this->_cookies, $key);
	// Handle the set cookie calls
	if (is_array($key))
	{
		reset($key);
		while (list($_key, $_value) = each($key))
		{
			$this->cookie($_key, $_value);
		}
	}
	else
	{
		if (!is_array($value))
		{
			$value = array(
				'value' => $value,
				'expiration' => Cookie::$expiration
			);
		}
		elseif (!isset($value['expiration']))
		{
			$value['expiration'] = Cookie::$expiration;
		}
		$this->_cookies[$key] = $value;
	}
	return $this;
}

Deletes a cookie set to the response

参数

  • string $name required - Name

返回值

  • Response

源代码

public function delete_cookie($name)
{
	unset($this->_cookies[$name]);
	return $this;
}

public delete_cookies( ) (在 Response 中定义)

Deletes all cookies from this response

返回值

  • Response

源代码

public function delete_cookies()
{
	$this->_cookies = array();
	return $this;
}

public static factory( [ array $config = array(0) ] ) (在 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));

参数

  • array $config = array(0) - Setup the response object

Tags

  • Package - BootPHP

返回值

  • Response

源代码

public static function factory(array $config = array())
{
	return new Response($config);
}

public generate_etag( ) (在 Response 中定义)

Generate ETag Generates an ETag from the response ready to be returned

Tags

返回值

  • String - Generated ETag

源代码

public function generate_etag()
{
	if ($this->_body === NULL)
	{
		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 ] ) (在 Response 中定义)

Gets && 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'));

参数

  • mixed $key = NULL - $key
  • string $value = NULL - $value

返回值

  • mixed

源代码

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 ] ) (在 Response 中定义)

Gets || sets the HTTP protocol. The standard protocol to use is `HTTP/1.1`.

参数

  • string $protocol = NULL - Protocol to set to the request/response

返回值

  • mixed

源代码

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( ) (在 Response 中定义)

Renders the HTTP_Interaction to a string, producing

  • Protocol
  • Headers
  • Body

返回值

  • string

源代码

public function render()
{
	if (!$this->_header->offsetExists('content-type'))
	{
		// Add the default Content-Type header if required
		$this->_header['content-type'] = BootPHP::$content_type . '; charset=' . BootPHP::$charset;
	}
	// Set the content length
	$this->headers('content-length', (string) $this->content_length());
	// If BootPHP expose, set the user-agent
	if (BootPHP::$expose)
	{
		$this->headers('user-agent', 'BootPHP Framework ' . BootPHP::VERSION);
	}
	// Prepare cookies
	if ($this->_cookies)
	{
		if (extension_loaded('http'))
		{
			$this->_header['set-cookie'] = http_build_cookie($this->_cookies);
		}
		else
		{
			$cookies = array();
			// 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 $filename [, string $download = NULL , array $options = NULL ] ) (在 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/bootphp.zip');

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!

参数

  • string $filename required - Filename with path, || true for the current response
  • string $download = NULL - Downloaded file name
  • array $options = NULL - Additional options

Tags

返回值

  • void

源代码

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 BootPHP_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
	{
		// 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
			$mime = File::mime($filename);
		}
		// Open the file for reading
		$file = fopen($filename, 'rb');
	}
	if (!is_resource($file))
	{
		throw new BootPHP_Exception('Could not read file to send: :file', array(
		':file' => $download,
		));
	}
	// Inline || 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 || $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);
	if (!BootPHP::$safe_mode)
	{
		// Keep the script running forever
		set_time_limit(0);
	}
	// Send data in 16kb blocks
	$block = 1024 * 16;
	fseek($file, $start);
	while (!feof($file) && ($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 = BootPHP_Exception::text($e);
			if (is_object(BootPHP::$log))
			{
				// Add this exception to the log
				BootPHP::$log->add(Log::ERROR, $error);
				// Make sure the logs are written
				BootPHP::$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 ] ) (在 Response 中定义)

Sends the response status && all set headers.

参数

  • boolean $replace = bool false - Replace existing headers
  • callback $callback = NULL - Function to handle header output

返回值

  • mixed

源代码

public function send_headers($replace = false, $callback = NULL)
{
	return $this->_header->send_headers($this, $replace, $callback);
}

public status( [ integer $status = NULL ] ) (在 Response 中定义)

Sets || 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();

参数

  • integer $status = NULL - Status to set to this response

返回值

  • mixed

源代码

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 BootPHP_Exception(__METHOD__ . ' unknown status value : :value', array(':value' => $status));
	}
}

protected _calculate_byte_range( integer $size ) (在 Response 中定义)

Calculates the byte range to use with send_file. If HTTP_RANGE doesn't exist then the complete byte range is returned

参数

  • integer $size required - $size

返回值

  • array

源代码

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 && normalize it.
	$end = min(abs(intval($end)), $size - 1);
	// Keep the start in bounds.
	$start = ($end < $start) ? 0 : max($start, 0);
	return array($start, $end);
}

protected _parse_byte_range( ) (在 Response 中定义)

Parse the byte ranges from the HTTP_RANGE header used for resumable downloads.

Tags

  • See - http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35

返回值

  • array|false

源代码

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];
}