1<?php 2/** 3 * Session handler for persistent requests and default parameters 4 * 5 * @package Requests 6 * @subpackage Session Handler 7 */ 8 9/** 10 * Session handler for persistent requests and default parameters 11 * 12 * Allows various options to be set as default values, and merges both the 13 * options and URL properties together. A base URL can be set for all requests, 14 * with all subrequests resolved from this. Base options can be set (including 15 * a shared cookie jar), then overridden for individual requests. 16 * 17 * @package Requests 18 * @subpackage Session Handler 19 */ 20class Requests_Session { 21 /** 22 * Base URL for requests 23 * 24 * URLs will be made absolute using this as the base 25 * 26 * @var string|null 27 */ 28 public $url = null; 29 30 /** 31 * Base headers for requests 32 * 33 * @var array 34 */ 35 public $headers = array(); 36 37 /** 38 * Base data for requests 39 * 40 * If both the base data and the per-request data are arrays, the data will 41 * be merged before sending the request. 42 * 43 * @var array 44 */ 45 public $data = array(); 46 47 /** 48 * Base options for requests 49 * 50 * The base options are merged with the per-request data for each request. 51 * The only default option is a shared cookie jar between requests. 52 * 53 * Values here can also be set directly via properties on the Session 54 * object, e.g. `$session->useragent = 'X';` 55 * 56 * @var array 57 */ 58 public $options = array(); 59 60 /** 61 * Create a new session 62 * 63 * @param string|null $url Base URL for requests 64 * @param array $headers Default headers for requests 65 * @param array $data Default data for requests 66 * @param array $options Default options for requests 67 */ 68 public function __construct($url = null, $headers = array(), $data = array(), $options = array()) { 69 $this->url = $url; 70 $this->headers = $headers; 71 $this->data = $data; 72 $this->options = $options; 73 74 if (empty($this->options['cookies'])) { 75 $this->options['cookies'] = new Requests_Cookie_Jar(); 76 } 77 } 78 79 /** 80 * Get a property's value 81 * 82 * @param string $key Property key 83 * @return mixed|null Property value, null if none found 84 */ 85 public function __get($key) { 86 if (isset($this->options[$key])) { 87 return $this->options[$key]; 88 } 89 90 return null; 91 } 92 93 /** 94 * Set a property's value 95 * 96 * @param string $key Property key 97 * @param mixed $value Property value 98 */ 99 public function __set($key, $value) { 100 $this->options[$key] = $value; 101 } 102 103 /** 104 * Remove a property's value 105 * 106 * @param string $key Property key 107 */ 108 public function __isset($key) { 109 return isset($this->options[$key]); 110 } 111 112 /** 113 * Remove a property's value 114 * 115 * @param string $key Property key 116 */ 117 public function __unset($key) { 118 if (isset($this->options[$key])) { 119 unset($this->options[$key]); 120 } 121 } 122 123 /**#@+ 124 * @see request() 125 * @param string $url 126 * @param array $headers 127 * @param array $options 128 * @return Requests_Response 129 */ 130 /** 131 * Send a GET request 132 */ 133 public function get($url, $headers = array(), $options = array()) { 134 return $this->request($url, $headers, null, Requests::GET, $options); 135 } 136 137 /** 138 * Send a HEAD request 139 */ 140 public function head($url, $headers = array(), $options = array()) { 141 return $this->request($url, $headers, null, Requests::HEAD, $options); 142 } 143 144 /** 145 * Send a DELETE request 146 */ 147 public function delete($url, $headers = array(), $options = array()) { 148 return $this->request($url, $headers, null, Requests::DELETE, $options); 149 } 150 /**#@-*/ 151 152 /**#@+ 153 * @see request() 154 * @param string $url 155 * @param array $headers 156 * @param array $data 157 * @param array $options 158 * @return Requests_Response 159 */ 160 /** 161 * Send a POST request 162 */ 163 public function post($url, $headers = array(), $data = array(), $options = array()) { 164 return $this->request($url, $headers, $data, Requests::POST, $options); 165 } 166 167 /** 168 * Send a PUT request 169 */ 170 public function put($url, $headers = array(), $data = array(), $options = array()) { 171 return $this->request($url, $headers, $data, Requests::PUT, $options); 172 } 173 174 /** 175 * Send a PATCH request 176 * 177 * Note: Unlike {@see post} and {@see put}, `$headers` is required, as the 178 * specification recommends that should send an ETag 179 * 180 * @link https://tools.ietf.org/html/rfc5789 181 */ 182 public function patch($url, $headers, $data = array(), $options = array()) { 183 return $this->request($url, $headers, $data, Requests::PATCH, $options); 184 } 185 /**#@-*/ 186 187 /** 188 * Main interface for HTTP requests 189 * 190 * This method initiates a request and sends it via a transport before 191 * parsing. 192 * 193 * @see Requests::request() 194 * 195 * @throws Requests_Exception On invalid URLs (`nonhttp`) 196 * 197 * @param string $url URL to request 198 * @param array $headers Extra headers to send with the request 199 * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests 200 * @param string $type HTTP request type (use Requests constants) 201 * @param array $options Options for the request (see {@see Requests::request}) 202 * @return Requests_Response 203 */ 204 public function request($url, $headers = array(), $data = array(), $type = Requests::GET, $options = array()) { 205 $request = $this->merge_request(compact('url', 'headers', 'data', 'options')); 206 207 return Requests::request($request['url'], $request['headers'], $request['data'], $type, $request['options']); 208 } 209 210 /** 211 * Send multiple HTTP requests simultaneously 212 * 213 * @see Requests::request_multiple() 214 * 215 * @param array $requests Requests data (see {@see Requests::request_multiple}) 216 * @param array $options Global and default options (see {@see Requests::request}) 217 * @return array Responses (either Requests_Response or a Requests_Exception object) 218 */ 219 public function request_multiple($requests, $options = array()) { 220 foreach ($requests as $key => $request) { 221 $requests[$key] = $this->merge_request($request, false); 222 } 223 224 $options = array_merge($this->options, $options); 225 226 // Disallow forcing the type, as that's a per request setting 227 unset($options['type']); 228 229 return Requests::request_multiple($requests, $options); 230 } 231 232 /** 233 * Merge a request's data with the default data 234 * 235 * @param array $request Request data (same form as {@see request_multiple}) 236 * @param boolean $merge_options Should we merge options as well? 237 * @return array Request data 238 */ 239 protected function merge_request($request, $merge_options = true) { 240 if ($this->url !== null) { 241 $request['url'] = Requests_IRI::absolutize($this->url, $request['url']); 242 $request['url'] = $request['url']->uri; 243 } 244 245 if (empty($request['headers'])) { 246 $request['headers'] = array(); 247 } 248 $request['headers'] = array_merge($this->headers, $request['headers']); 249 250 if (empty($request['data'])) { 251 if (is_array($this->data)) { 252 $request['data'] = $this->data; 253 } 254 } 255 elseif (is_array($request['data']) && is_array($this->data)) { 256 $request['data'] = array_merge($this->data, $request['data']); 257 } 258 259 if ($merge_options !== false) { 260 $request['options'] = array_merge($this->options, $request['options']); 261 262 // Disallow forcing the type, as that's a per request setting 263 unset($request['options']['type']); 264 } 265 266 return $request; 267 } 268} 269