Always parse query string, on the main request or on sub-requests
[kohana-core.git] / classes / Kohana / Request.php
blob6cd8cc59fa5906295c276fc7bd939f4d1e0d2cc1
1 <?php defined('SYSPATH') OR die('No direct script access.');
2 /**
3 * Request. Uses the [Route] class to determine what
4 * [Controller] to send the request to.
6 * @package Kohana
7 * @category Base
8 * @author Kohana Team
9 * @copyright (c) 2008-2012 Kohana Team
10 * @license http://kohanaframework.org/license
12 class Kohana_Request implements HTTP_Request {
14 /**
15 * @var string client user agent
17 public static $user_agent = '';
19 /**
20 * @var string client IP address
22 public static $client_ip = '0.0.0.0';
24 /**
25 * @var string trusted proxy server IPs
27 public static $trusted_proxies = array('127.0.0.1', 'localhost', 'localhost.localdomain');
29 /**
30 * @var Request main request instance
32 public static $initial;
34 /**
35 * @var Request currently executing request instance
37 public static $current;
39 /**
40 * Creates a new request object for the given URI. New requests should be
41 * Created using the [Request::factory] method.
43 * $request = Request::factory($uri);
45 * If $cache parameter is set, the response for the request will attempt to
46 * be retrieved from the cache.
48 * @param string $uri URI of the request
49 * @param array $client_params An array of params to pass to the request client
50 * @param bool $allow_external Allow external requests? (deprecated in 3.3)
51 * @param array $injected_routes An array of routes to use, for testing
52 * @return void|Request
53 * @throws Request_Exception
54 * @uses Route::all
55 * @uses Route::matches
57 public static function factory($uri = TRUE, $client_params = array(), $allow_external = TRUE, $injected_routes = array())
59 // If this is the initial request
60 if ( ! Request::$initial)
62 $protocol = HTTP::$protocol;
64 if (isset($_SERVER['REQUEST_METHOD']))
66 // Use the server request method
67 $method = $_SERVER['REQUEST_METHOD'];
69 else
71 // Default to GET requests
72 $method = HTTP_Request::GET;
75 if (( ! empty($_SERVER['HTTPS']) AND filter_var($_SERVER['HTTPS'], FILTER_VALIDATE_BOOLEAN))
76 OR (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
77 AND $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
78 AND in_array($_SERVER['REMOTE_ADDR'], Request::$trusted_proxies))
80 // This request is secure
81 $secure = TRUE;
84 if (isset($_SERVER['HTTP_REFERER']))
86 // There is a referrer for this request
87 $referrer = $_SERVER['HTTP_REFERER'];
90 if (isset($_SERVER['HTTP_USER_AGENT']))
92 // Browser type
93 Request::$user_agent = $_SERVER['HTTP_USER_AGENT'];
96 if (isset($_SERVER['HTTP_X_REQUESTED_WITH']))
98 // Typically used to denote AJAX requests
99 $requested_with = $_SERVER['HTTP_X_REQUESTED_WITH'];
102 if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])
103 AND isset($_SERVER['REMOTE_ADDR'])
104 AND in_array($_SERVER['REMOTE_ADDR'], Request::$trusted_proxies))
106 // Use the forwarded IP address, typically set when the
107 // client is using a proxy server.
108 // Format: "X-Forwarded-For: client1, proxy1, proxy2"
109 $client_ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
111 Request::$client_ip = array_shift($client_ips);
113 unset($client_ips);
115 elseif (isset($_SERVER['HTTP_CLIENT_IP'])
116 AND isset($_SERVER['REMOTE_ADDR'])
117 AND in_array($_SERVER['REMOTE_ADDR'], Request::$trusted_proxies))
119 // Use the forwarded IP address, typically set when the
120 // client is using a proxy server.
121 $client_ips = explode(',', $_SERVER['HTTP_CLIENT_IP']);
123 Request::$client_ip = array_shift($client_ips);
125 unset($client_ips);
127 elseif (isset($_SERVER['REMOTE_ADDR']))
129 // The remote IP address
130 Request::$client_ip = $_SERVER['REMOTE_ADDR'];
133 if ($method !== HTTP_Request::GET)
135 // Ensure the raw body is saved for future use
136 $body = file_get_contents('php://input');
139 if ($uri === TRUE)
141 // Attempt to guess the proper URI
142 $uri = Request::detect_uri();
145 $cookies = array();
147 if (($cookie_keys = array_keys($_COOKIE)))
149 foreach ($cookie_keys as $key)
151 $cookies[$key] = Cookie::get($key);
155 // Create the instance singleton
156 Request::$initial = $request = new Request($uri, $client_params, $allow_external, $injected_routes);
158 // Store global GET and POST data in the initial request only
159 $request->protocol($protocol)
160 ->query($_GET)
161 ->post($_POST);
163 if (isset($secure))
165 // Set the request security
166 $request->secure($secure);
169 if (isset($method))
171 // Set the request method
172 $request->method($method);
175 if (isset($referrer))
177 // Set the referrer
178 $request->referrer($referrer);
181 if (isset($requested_with))
183 // Apply the requested with variable
184 $request->requested_with($requested_with);
187 if (isset($body))
189 // Set the request body (probably a PUT type)
190 $request->body($body);
193 if (isset($cookies))
195 $request->cookie($cookies);
198 else
200 $request = new Request($uri, $client_params, $allow_external, $injected_routes);
203 return $request;
207 * Automatically detects the URI of the main request using PATH_INFO,
208 * REQUEST_URI, PHP_SELF or REDIRECT_URL.
210 * $uri = Request::detect_uri();
212 * @return string URI of the main request
213 * @throws Kohana_Exception
214 * @since 3.0.8
216 public static function detect_uri()
218 if ( ! empty($_SERVER['PATH_INFO']))
220 // PATH_INFO does not contain the docroot or index
221 $uri = $_SERVER['PATH_INFO'];
223 else
225 // REQUEST_URI and PHP_SELF include the docroot and index
227 if (isset($_SERVER['REQUEST_URI']))
230 * We use REQUEST_URI as the fallback value. The reason
231 * for this is we might have a malformed URL such as:
233 * http://localhost/http://example.com/judge.php
235 * which parse_url can't handle. So rather than leave empty
236 * handed, we'll use this.
238 $uri = $_SERVER['REQUEST_URI'];
240 if ($request_uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH))
242 // Valid URL path found, set it.
243 $uri = $request_uri;
246 // Decode the request URI
247 $uri = rawurldecode($uri);
249 elseif (isset($_SERVER['PHP_SELF']))
251 $uri = $_SERVER['PHP_SELF'];
253 elseif (isset($_SERVER['REDIRECT_URL']))
255 $uri = $_SERVER['REDIRECT_URL'];
257 else
259 // If you ever see this error, please report an issue at http://dev.kohanaphp.com/projects/kohana3/issues
260 // along with any relevant information about your web server setup. Thanks!
261 throw new Kohana_Exception('Unable to detect the URI using PATH_INFO, REQUEST_URI, PHP_SELF or REDIRECT_URL');
264 // Get the path from the base URL, including the index file
265 $base_url = parse_url(Kohana::$base_url, PHP_URL_PATH);
267 if (strpos($uri, $base_url) === 0)
269 // Remove the base URL from the URI
270 $uri = (string) substr($uri, strlen($base_url));
273 if (Kohana::$index_file AND strpos($uri, Kohana::$index_file) === 0)
275 // Remove the index file from the URI
276 $uri = (string) substr($uri, strlen(Kohana::$index_file));
280 return $uri;
284 * Return the currently executing request. This is changed to the current
285 * request when [Request::execute] is called and restored when the request
286 * is completed.
288 * $request = Request::current();
290 * @return Request
291 * @since 3.0.5
293 public static function current()
295 return Request::$current;
299 * Returns the first request encountered by this framework. This will should
300 * only be set once during the first [Request::factory] invocation.
302 * // Get the first request
303 * $request = Request::initial();
305 * // Test whether the current request is the first request
306 * if (Request::initial() === Request::current())
307 * // Do something useful
309 * @return Request
310 * @since 3.1.0
312 public static function initial()
314 return Request::$initial;
318 * Returns information about the initial user agent.
320 * @param mixed $value array or string to return: browser, version, robot, mobile, platform
321 * @return mixed requested information, FALSE if nothing is found
322 * @uses Request::$user_agent
323 * @uses Text::user_agent
325 public static function user_agent($value)
327 return Text::user_agent(Request::$user_agent, $value);
331 * Returns the accepted content types. If a specific type is defined,
332 * the quality of that type will be returned.
334 * $types = Request::accept_type();
336 * [!!] Deprecated in favor of using [HTTP_Header::accepts_at_quality].
338 * @deprecated since version 3.3.0
339 * @param string $type Content MIME type
340 * @return mixed An array of all types or a specific type as a string
341 * @uses Request::_parse_accept
343 public static function accept_type($type = NULL)
345 static $accepts;
347 if ($accepts === NULL)
349 // Parse the HTTP_ACCEPT header
350 $accepts = Request::_parse_accept($_SERVER['HTTP_ACCEPT'], array('*/*' => 1.0));
353 if (isset($type))
355 // Return the quality setting for this type
356 return isset($accepts[$type]) ? $accepts[$type] : $accepts['*/*'];
359 return $accepts;
363 * Returns the accepted languages. If a specific language is defined,
364 * the quality of that language will be returned. If the language is not
365 * accepted, FALSE will be returned.
367 * $langs = Request::accept_lang();
369 * [!!] Deprecated in favor of using [HTTP_Header::accepts_language_at_quality].
371 * @deprecated since version 3.3.0
372 * @param string $lang Language code
373 * @return mixed An array of all types or a specific type as a string
374 * @uses Request::_parse_accept
376 public static function accept_lang($lang = NULL)
378 static $accepts;
380 if ($accepts === NULL)
382 // Parse the HTTP_ACCEPT_LANGUAGE header
383 $accepts = Request::_parse_accept($_SERVER['HTTP_ACCEPT_LANGUAGE']);
386 if (isset($lang))
388 // Return the quality setting for this lang
389 return isset($accepts[$lang]) ? $accepts[$lang] : FALSE;
392 return $accepts;
396 * Returns the accepted encodings. If a specific encoding is defined,
397 * the quality of that encoding will be returned. If the encoding is not
398 * accepted, FALSE will be returned.
400 * $encodings = Request::accept_encoding();
402 * [!!] Deprecated in favor of using [HTTP_Header::accepts_encoding_at_quality].
404 * @deprecated since version 3.3.0
405 * @param string $type Encoding type
406 * @return mixed An array of all types or a specific type as a string
407 * @uses Request::_parse_accept
409 public static function accept_encoding($type = NULL)
411 static $accepts;
413 if ($accepts === NULL)
415 // Parse the HTTP_ACCEPT_LANGUAGE header
416 $accepts = Request::_parse_accept($_SERVER['HTTP_ACCEPT_ENCODING']);
419 if (isset($type))
421 // Return the quality setting for this type
422 return isset($accepts[$type]) ? $accepts[$type] : FALSE;
425 return $accepts;
429 * Determines if a file larger than the post_max_size has been uploaded. PHP
430 * does not handle this situation gracefully on its own, so this method
431 * helps to solve that problem.
433 * @return boolean
434 * @uses Num::bytes
435 * @uses Arr::get
437 public static function post_max_size_exceeded()
439 // Make sure the request method is POST
440 if (Request::$initial->method() !== HTTP_Request::POST)
441 return FALSE;
443 // Get the post_max_size in bytes
444 $max_bytes = Num::bytes(ini_get('post_max_size'));
446 // Error occurred if method is POST, and content length is too long
447 return (Arr::get($_SERVER, 'CONTENT_LENGTH') > $max_bytes);
451 * Process a request to find a matching route
453 * @param object $request Request
454 * @param array $routes Route
455 * @return array
457 public static function process(Request $request, $routes = NULL)
459 // Load routes
460 $routes = (empty($routes)) ? Route::all() : $routes;
461 $params = NULL;
463 foreach ($routes as $name => $route)
465 // Use external routes for reverse routing only
466 if ($route->is_external())
468 continue;
471 // We found something suitable
472 if ($params = $route->matches($request))
474 return array(
475 'params' => $params,
476 'route' => $route,
481 return NULL;
485 * Parses an accept header and returns an array (type => quality) of the
486 * accepted types, ordered by quality.
488 * $accept = Request::_parse_accept($header, $defaults);
490 * @param string $header Header to parse
491 * @param array $accepts Default values
492 * @return array
494 protected static function _parse_accept( & $header, array $accepts = NULL)
496 if ( ! empty($header))
498 // Get all of the types
499 $types = explode(',', $header);
501 foreach ($types as $type)
503 // Split the type into parts
504 $parts = explode(';', $type);
506 // Make the type only the MIME
507 $type = trim(array_shift($parts));
509 // Default quality is 1.0
510 $quality = 1.0;
512 foreach ($parts as $part)
514 // Prevent undefined $value notice below
515 if (strpos($part, '=') === FALSE)
516 continue;
518 // Separate the key and value
519 list ($key, $value) = explode('=', trim($part));
521 if ($key === 'q')
523 // There is a quality for this type
524 $quality = (float) trim($value);
528 // Add the accept type and quality
529 $accepts[$type] = $quality;
533 // Make sure that accepts is an array
534 $accepts = (array) $accepts;
536 // Order by quality
537 arsort($accepts);
539 return $accepts;
543 * @var string the x-requested-with header which most likely
544 * will be xmlhttprequest
546 protected $_requested_with;
549 * @var string method: GET, POST, PUT, DELETE, HEAD, etc
551 protected $_method = 'GET';
554 * @var string protocol: HTTP/1.1, FTP, CLI, etc
556 protected $_protocol;
559 * @var boolean
561 protected $_secure = FALSE;
564 * @var string referring URL
566 protected $_referrer;
569 * @var Route route matched for this request
571 protected $_route;
574 * @var Route array of routes to manually look at instead of the global namespace
576 protected $_routes;
579 * @var Kohana_HTTP_Header headers to sent as part of the request
581 protected $_header;
584 * @var string the body
586 protected $_body;
589 * @var string controller directory
591 protected $_directory = '';
594 * @var string controller to be executed
596 protected $_controller;
599 * @var string action to be executed in the controller
601 protected $_action;
604 * @var string the URI of the request
606 protected $_uri;
609 * @var boolean external request
611 protected $_external = FALSE;
614 * @var array parameters from the route
616 protected $_params = array();
619 * @var array query parameters
621 protected $_get = array();
624 * @var array post parameters
626 protected $_post = array();
629 * @var array cookies to send with the request
631 protected $_cookies = array();
634 * @var Kohana_Request_Client
636 protected $_client;
639 * Creates a new request object for the given URI. New requests should be
640 * Created using the [Request::factory] method.
642 * $request = new Request($uri);
644 * If $cache parameter is set, the response for the request will attempt to
645 * be retrieved from the cache.
647 * @param string $uri URI of the request
648 * @param array $client_params Array of params to pass to the request client
649 * @param bool $allow_external Allow external requests? (deprecated in 3.3)
650 * @param array $injected_routes An array of routes to use, for testing
651 * @return void
652 * @throws Request_Exception
653 * @uses Route::all
654 * @uses Route::matches
656 public function __construct($uri, $client_params = array(), $allow_external = TRUE, $injected_routes = array())
658 $client_params = is_array($client_params) ? $client_params : array();
660 // Initialise the header
661 $this->_header = new HTTP_Header(array());
663 // Assign injected routes
664 $this->_routes = $injected_routes;
666 // Cleanse query parameters from URI (faster that parse_url())
667 $split_uri = explode('?', $uri);
668 $uri = array_shift($split_uri);
670 if ($split_uri)
672 parse_str($split_uri[0], $this->_get);
675 // Detect protocol (if present)
676 // $allow_external = FALSE prevents the default index.php from
677 // being able to proxy external pages.
678 if ( ! $allow_external OR strpos($uri, '://') === FALSE)
680 // Remove leading and trailing slashes from the URI
681 $this->_uri = trim($uri, '/');
683 // Apply the client
684 $this->_client = new Request_Client_Internal($client_params);
686 else
688 // Create a route
689 $this->_route = new Route($uri);
691 // Store the URI
692 $this->_uri = $uri;
694 // Set the security setting if required
695 if (strpos($uri, 'https://') === 0)
697 $this->secure(TRUE);
700 // Set external state
701 $this->_external = TRUE;
703 // Setup the client
704 $this->_client = Request_Client_External::factory($client_params);
709 * Returns the response as the string representation of a request.
711 * echo $request;
713 * @return string
715 public function __toString()
717 return $this->render();
721 * Sets and gets the uri from the request.
723 * @param string $uri
724 * @return mixed
726 public function uri($uri = NULL)
728 if ($uri === NULL)
730 // Act as a getter
731 return ($this->_uri === '') ? '/' : $this->_uri;
734 // Act as a setter
735 $this->_uri = $uri;
737 return $this;
741 * Create a URL string from the current request. This is a shortcut for:
743 * echo URL::site($this->request->uri(), $protocol);
745 * @param mixed $protocol protocol string or Request object
746 * @return string
747 * @since 3.0.7
748 * @uses URL::site
750 public function url($protocol = NULL)
752 if ($this->is_external())
754 // If it's an external request return the URI
755 return $this->uri();
758 // Create a URI with the current route, convert to a URL and returns
759 return URL::site($this->uri(), $protocol);
763 * Retrieves a value from the route parameters.
765 * $id = $request->param('id');
767 * @param string $key Key of the value
768 * @param mixed $default Default value if the key is not set
769 * @return mixed
771 public function param($key = NULL, $default = NULL)
773 if ($key === NULL)
775 // Return the full array
776 return $this->_params;
779 return isset($this->_params[$key]) ? $this->_params[$key] : $default;
783 * Sets and gets the referrer from the request.
785 * @param string $referrer
786 * @return mixed
788 public function referrer($referrer = NULL)
790 if ($referrer === NULL)
792 // Act as a getter
793 return $this->_referrer;
796 // Act as a setter
797 $this->_referrer = (string) $referrer;
799 return $this;
803 * Sets and gets the route from the request.
805 * @param string $route
806 * @return mixed
808 public function route(Route $route = NULL)
810 if ($route === NULL)
812 // Act as a getter
813 return $this->_route;
816 // Act as a setter
817 $this->_route = $route;
819 return $this;
823 * Sets and gets the directory for the controller.
825 * @param string $directory Directory to execute the controller from
826 * @return mixed
828 public function directory($directory = NULL)
830 if ($directory === NULL)
832 // Act as a getter
833 return $this->_directory;
836 // Act as a setter
837 $this->_directory = (string) $directory;
839 return $this;
843 * Sets and gets the controller for the matched route.
845 * @param string $controller Controller to execute the action
846 * @return mixed
848 public function controller($controller = NULL)
850 if ($controller === NULL)
852 // Act as a getter
853 return $this->_controller;
856 // Act as a setter
857 $this->_controller = (string) $controller;
859 return $this;
863 * Sets and gets the action for the controller.
865 * @param string $action Action to execute the controller from
866 * @return mixed
868 public function action($action = NULL)
870 if ($action === NULL)
872 // Act as a getter
873 return $this->_action;
876 // Act as a setter
877 $this->_action = (string) $action;
879 return $this;
883 * Provides access to the [Request_Client].
885 * @return Request_Client
886 * @return self
888 public function client(Request_Client $client = NULL)
890 if ($client === NULL)
891 return $this->_client;
892 else
894 $this->_client = $client;
895 return $this;
900 * Gets and sets the requested with property, which should
901 * be relative to the x-requested-with pseudo header.
903 * @param string $requested_with Requested with value
904 * @return mixed
906 public function requested_with($requested_with = NULL)
908 if ($requested_with === NULL)
910 // Act as a getter
911 return $this->_requested_with;
914 // Act as a setter
915 $this->_requested_with = strtolower($requested_with);
917 return $this;
921 * Processes the request, executing the controller action that handles this
922 * request, determined by the [Route].
924 * 1. Before the controller action is called, the [Controller::before] method
925 * will be called.
926 * 2. Next the controller action will be called.
927 * 3. After the controller action is called, the [Controller::after] method
928 * will be called.
930 * By default, the output from the controller is captured and returned, and
931 * no headers are sent.
933 * $request->execute();
935 * @return Response
936 * @throws Request_Exception
937 * @throws HTTP_Exception_404
938 * @uses [Kohana::$profiling]
939 * @uses [Profiler]
941 public function execute()
943 if ( ! $this->_external)
945 $processed = Request::process($this, $this->_routes);
947 if ($processed)
949 // Store the matching route
950 $this->_route = $processed['route'];
951 $params = $processed['params'];
953 // Is this route external?
954 $this->_external = $this->_route->is_external();
956 if (isset($params['directory']))
958 // Controllers are in a sub-directory
959 $this->_directory = $params['directory'];
962 // Store the controller
963 $this->_controller = $params['controller'];
965 // Store the action
966 $this->_action = (isset($params['action']))
967 ? $params['action']
968 : Route::$default_action;
970 // These are accessible as public vars and can be overloaded
971 unset($params['controller'], $params['action'], $params['directory']);
973 // Params cannot be changed once matched
974 $this->_params = $params;
978 if ( ! $this->_route instanceof Route)
980 return HTTP_Exception::factory(404, 'Unable to find a route to match the URI: :uri', array(
981 ':uri' => $this->_uri,
982 ))->request($this)
983 ->get_response();
986 if ( ! $this->_client instanceof Request_Client)
988 throw new Request_Exception('Unable to execute :uri without a Kohana_Request_Client', array(
989 ':uri' => $this->_uri,
993 return $this->_client->execute($this);
997 * Returns whether this request is the initial request Kohana received.
998 * Can be used to test for sub requests.
1000 * if ( ! $request->is_initial())
1001 * // This is a sub request
1003 * @return boolean
1005 public function is_initial()
1007 return ($this === Request::$initial);
1011 * Readonly access to the [Request::$_external] property.
1013 * if ( ! $request->is_external())
1014 * // This is an internal request
1016 * @return boolean
1018 public function is_external()
1020 return $this->_external;
1024 * Returns whether this is an ajax request (as used by JS frameworks)
1026 * @return boolean
1028 public function is_ajax()
1030 return ($this->requested_with() === 'xmlhttprequest');
1034 * Gets or sets the HTTP method. Usually GET, POST, PUT or DELETE in
1035 * traditional CRUD applications.
1037 * @param string $method Method to use for this request
1038 * @return mixed
1040 public function method($method = NULL)
1042 if ($method === NULL)
1044 // Act as a getter
1045 return $this->_method;
1048 // Act as a setter
1049 $this->_method = strtoupper($method);
1051 return $this;
1055 * Gets or sets the HTTP protocol. If there is no current protocol set,
1056 * it will use the default set in HTTP::$protocol
1058 * @param string $protocol Protocol to set to the request
1059 * @return mixed
1061 public function protocol($protocol = NULL)
1063 if ($protocol === NULL)
1065 if ($this->_protocol)
1066 return $this->_protocol;
1067 else
1068 return $this->_protocol = HTTP::$protocol;
1071 // Act as a setter
1072 $this->_protocol = strtoupper($protocol);
1073 return $this;
1077 * Getter/Setter to the security settings for this request. This
1078 * method should be treated as immutable.
1080 * @param boolean $secure is this request secure?
1081 * @return mixed
1083 public function secure($secure = NULL)
1085 if ($secure === NULL)
1086 return $this->_secure;
1088 // Act as a setter
1089 $this->_secure = (bool) $secure;
1090 return $this;
1094 * Gets or sets HTTP headers oo the request. All headers
1095 * are included immediately after the HTTP protocol definition during
1096 * transmission. This method provides a simple array or key/value
1097 * interface to the headers.
1099 * @param mixed $key Key or array of key/value pairs to set
1100 * @param string $value Value to set to the supplied key
1101 * @return mixed
1103 public function headers($key = NULL, $value = NULL)
1105 if ($key instanceof HTTP_Header)
1107 // Act a setter, replace all headers
1108 $this->_header = $key;
1110 return $this;
1113 if (is_array($key))
1115 // Act as a setter, replace all headers
1116 $this->_header->exchangeArray($key);
1118 return $this;
1121 if ($this->_header->count() === 0 AND $this->is_initial())
1123 // Lazy load the request headers
1124 $this->_header = HTTP::request_headers();
1127 if ($key === NULL)
1129 // Act as a getter, return all headers
1130 return $this->_header;
1132 elseif ($value === NULL)
1134 // Act as a getter, single header
1135 return ($this->_header->offsetExists($key)) ? $this->_header->offsetGet($key) : NULL;
1138 // Act as a setter for a single header
1139 $this->_header[$key] = $value;
1141 return $this;
1145 * Set and get cookies values for this request.
1147 * @param mixed $key Cookie name, or array of cookie values
1148 * @param string $value Value to set to cookie
1149 * @return string
1150 * @return mixed
1152 public function cookie($key = NULL, $value = NULL)
1154 if (is_array($key))
1156 // Act as a setter, replace all cookies
1157 $this->_cookies = $key;
1158 return $this;
1160 elseif ($key === NULL)
1162 // Act as a getter, all cookies
1163 return $this->_cookies;
1165 elseif ($value === NULL)
1167 // Act as a getting, single cookie
1168 return isset($this->_cookies[$key]) ? $this->_cookies[$key] : NULL;
1171 // Act as a setter for a single cookie
1172 $this->_cookies[$key] = (string) $value;
1174 return $this;
1178 * Gets or sets the HTTP body of the request. The body is
1179 * included after the header, separated by a single empty new line.
1181 * @param string $content Content to set to the object
1182 * @return mixed
1184 public function body($content = NULL)
1186 if ($content === NULL)
1188 // Act as a getter
1189 return $this->_body;
1192 // Act as a setter
1193 $this->_body = $content;
1195 return $this;
1199 * Returns the length of the body for use with
1200 * content header
1202 * @return integer
1204 public function content_length()
1206 return strlen($this->body());
1210 * Renders the HTTP_Interaction to a string, producing
1212 * - Protocol
1213 * - Headers
1214 * - Body
1216 * If there are variables set to the `Kohana_Request::$_post`
1217 * they will override any values set to body.
1219 * @return string
1221 public function render()
1223 if ( ! $post = $this->post())
1225 $body = $this->body();
1227 else
1229 $body = http_build_query($post, NULL, '&');
1230 $this->body($body)
1231 ->headers('content-type', 'application/x-www-form-urlencoded; charset='.Kohana::$charset);
1234 // Set the content length
1235 $this->headers('content-length', (string) $this->content_length());
1237 // If Kohana expose, set the user-agent
1238 if (Kohana::$expose)
1240 $this->headers('user-agent', Kohana::version());
1243 // Prepare cookies
1244 if ($this->_cookies)
1246 $cookie_string = array();
1248 // Parse each
1249 foreach ($this->_cookies as $key => $value)
1251 $cookie_string[] = $key.'='.$value;
1254 // Create the cookie string
1255 $this->_header['cookie'] = implode('; ', $cookie_string);
1258 $output = $this->method().' '.$this->uri().' '.$this->protocol()."\r\n";
1259 $output .= (string) $this->_header;
1260 $output .= $body;
1262 return $output;
1266 * Gets or sets HTTP query string.
1268 * @param mixed $key Key or key value pairs to set
1269 * @param string $value Value to set to a key
1270 * @return mixed
1271 * @uses Arr::path
1273 public function query($key = NULL, $value = NULL)
1275 if (is_array($key))
1277 // Act as a setter, replace all query strings
1278 $this->_get = $key;
1280 return $this;
1283 if ($key === NULL)
1285 // Act as a getter, all query strings
1286 return $this->_get;
1288 elseif ($value === NULL)
1290 // Act as a getter, single query string
1291 return Arr::path($this->_get, $key);
1294 // Act as a setter, single query string
1295 $this->_get[$key] = $value;
1297 return $this;
1301 * Gets or sets HTTP POST parameters to the request.
1303 * @param mixed $key Key or key value pairs to set
1304 * @param string $value Value to set to a key
1305 * @return mixed
1306 * @uses Arr::path
1308 public function post($key = NULL, $value = NULL)
1310 if (is_array($key))
1312 // Act as a setter, replace all fields
1313 $this->_post = $key;
1315 return $this;
1318 if ($key === NULL)
1320 // Act as a getter, all fields
1321 return $this->_post;
1323 elseif ($value === NULL)
1325 // Act as a getter, single field
1326 return Arr::path($this->_post, $key);
1329 // Act as a setter, single field
1330 $this->_post[$key] = $value;
1332 return $this;