Request.php (16917B)
1 <?php 2 /** 3 * Slim - a micro PHP 5 framework 4 * 5 * @author Josh Lockhart <info@slimframework.com> 6 * @copyright 2011 Josh Lockhart 7 * @link http://www.slimframework.com 8 * @license http://www.slimframework.com/license 9 * @version 2.4.2 10 * @package Slim 11 * 12 * MIT LICENSE 13 * 14 * Permission is hereby granted, free of charge, to any person obtaining 15 * a copy of this software and associated documentation files (the 16 * "Software"), to deal in the Software without restriction, including 17 * without limitation the rights to use, copy, modify, merge, publish, 18 * distribute, sublicense, and/or sell copies of the Software, and to 19 * permit persons to whom the Software is furnished to do so, subject to 20 * the following conditions: 21 * 22 * The above copyright notice and this permission notice shall be 23 * included in all copies or substantial portions of the Software. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 */ 33 namespace Slim\Http; 34 35 /** 36 * Slim HTTP Request 37 * 38 * This class provides a human-friendly interface to the Slim environment variables; 39 * environment variables are passed by reference and will be modified directly. 40 * 41 * @package Slim 42 * @author Josh Lockhart 43 * @since 1.0.0 44 */ 45 class Request 46 { 47 const METHOD_HEAD = 'HEAD'; 48 const METHOD_GET = 'GET'; 49 const METHOD_POST = 'POST'; 50 const METHOD_PUT = 'PUT'; 51 const METHOD_PATCH = 'PATCH'; 52 const METHOD_DELETE = 'DELETE'; 53 const METHOD_OPTIONS = 'OPTIONS'; 54 const METHOD_OVERRIDE = '_METHOD'; 55 56 /** 57 * @var array 58 */ 59 protected static $formDataMediaTypes = array('application/x-www-form-urlencoded'); 60 61 /** 62 * Application Environment 63 * @var \Slim\Environment 64 */ 65 protected $env; 66 67 /** 68 * HTTP Headers 69 * @var \Slim\Http\Headers 70 */ 71 public $headers; 72 73 /** 74 * HTTP Cookies 75 * @var \Slim\Helper\Set 76 */ 77 public $cookies; 78 79 /** 80 * Constructor 81 * @param \Slim\Environment $env 82 */ 83 public function __construct(\Slim\Environment $env) 84 { 85 $this->env = $env; 86 $this->headers = new \Slim\Http\Headers(\Slim\Http\Headers::extract($env)); 87 $this->cookies = new \Slim\Helper\Set(\Slim\Http\Util::parseCookieHeader($env['HTTP_COOKIE'])); 88 } 89 90 /** 91 * Get HTTP method 92 * @return string 93 */ 94 public function getMethod() 95 { 96 return $this->env['REQUEST_METHOD']; 97 } 98 99 /** 100 * Is this a GET request? 101 * @return bool 102 */ 103 public function isGet() 104 { 105 return $this->getMethod() === self::METHOD_GET; 106 } 107 108 /** 109 * Is this a POST request? 110 * @return bool 111 */ 112 public function isPost() 113 { 114 return $this->getMethod() === self::METHOD_POST; 115 } 116 117 /** 118 * Is this a PUT request? 119 * @return bool 120 */ 121 public function isPut() 122 { 123 return $this->getMethod() === self::METHOD_PUT; 124 } 125 126 /** 127 * Is this a PATCH request? 128 * @return bool 129 */ 130 public function isPatch() 131 { 132 return $this->getMethod() === self::METHOD_PATCH; 133 } 134 135 /** 136 * Is this a DELETE request? 137 * @return bool 138 */ 139 public function isDelete() 140 { 141 return $this->getMethod() === self::METHOD_DELETE; 142 } 143 144 /** 145 * Is this a HEAD request? 146 * @return bool 147 */ 148 public function isHead() 149 { 150 return $this->getMethod() === self::METHOD_HEAD; 151 } 152 153 /** 154 * Is this a OPTIONS request? 155 * @return bool 156 */ 157 public function isOptions() 158 { 159 return $this->getMethod() === self::METHOD_OPTIONS; 160 } 161 162 /** 163 * Is this an AJAX request? 164 * @return bool 165 */ 166 public function isAjax() 167 { 168 if ($this->params('isajax')) { 169 return true; 170 } elseif (isset($this->headers['X_REQUESTED_WITH']) && $this->headers['X_REQUESTED_WITH'] === 'XMLHttpRequest') { 171 return true; 172 } else { 173 return false; 174 } 175 } 176 177 /** 178 * Is this an XHR request? (alias of Slim_Http_Request::isAjax) 179 * @return bool 180 */ 181 public function isXhr() 182 { 183 return $this->isAjax(); 184 } 185 186 /** 187 * Fetch GET and POST data 188 * 189 * This method returns a union of GET and POST data as a key-value array, or the value 190 * of the array key if requested; if the array key does not exist, NULL is returned, 191 * unless there is a default value specified. 192 * 193 * @param string $key 194 * @param mixed $default 195 * @return array|mixed|null 196 */ 197 public function params($key = null, $default = null) 198 { 199 $union = array_merge($this->get(), $this->post()); 200 if ($key) { 201 return isset($union[$key]) ? $union[$key] : $default; 202 } 203 204 return $union; 205 } 206 207 /** 208 * Fetch GET data 209 * 210 * This method returns a key-value array of data sent in the HTTP request query string, or 211 * the value of the array key if requested; if the array key does not exist, NULL is returned. 212 * 213 * @param string $key 214 * @param mixed $default Default return value when key does not exist 215 * @return array|mixed|null 216 */ 217 public function get($key = null, $default = null) 218 { 219 if (!isset($this->env['slim.request.query_hash'])) { 220 $output = array(); 221 if (function_exists('mb_parse_str') && !isset($this->env['slim.tests.ignore_multibyte'])) { 222 mb_parse_str($this->env['QUERY_STRING'], $output); 223 } else { 224 parse_str($this->env['QUERY_STRING'], $output); 225 } 226 $this->env['slim.request.query_hash'] = Util::stripSlashesIfMagicQuotes($output); 227 } 228 if ($key) { 229 if (isset($this->env['slim.request.query_hash'][$key])) { 230 return $this->env['slim.request.query_hash'][$key]; 231 } else { 232 return $default; 233 } 234 } else { 235 return $this->env['slim.request.query_hash']; 236 } 237 } 238 239 /** 240 * Fetch POST data 241 * 242 * This method returns a key-value array of data sent in the HTTP request body, or 243 * the value of a hash key if requested; if the array key does not exist, NULL is returned. 244 * 245 * @param string $key 246 * @param mixed $default Default return value when key does not exist 247 * @return array|mixed|null 248 * @throws \RuntimeException If environment input is not available 249 */ 250 public function post($key = null, $default = null) 251 { 252 if (!isset($this->env['slim.input'])) { 253 throw new \RuntimeException('Missing slim.input in environment variables'); 254 } 255 if (!isset($this->env['slim.request.form_hash'])) { 256 $this->env['slim.request.form_hash'] = array(); 257 if ($this->isFormData() && is_string($this->env['slim.input'])) { 258 $output = array(); 259 if (function_exists('mb_parse_str') && !isset($this->env['slim.tests.ignore_multibyte'])) { 260 mb_parse_str($this->env['slim.input'], $output); 261 } else { 262 parse_str($this->env['slim.input'], $output); 263 } 264 $this->env['slim.request.form_hash'] = Util::stripSlashesIfMagicQuotes($output); 265 } else { 266 $this->env['slim.request.form_hash'] = Util::stripSlashesIfMagicQuotes($_POST); 267 } 268 } 269 if ($key) { 270 if (isset($this->env['slim.request.form_hash'][$key])) { 271 return $this->env['slim.request.form_hash'][$key]; 272 } else { 273 return $default; 274 } 275 } else { 276 return $this->env['slim.request.form_hash']; 277 } 278 } 279 280 /** 281 * Fetch PUT data (alias for \Slim\Http\Request::post) 282 * @param string $key 283 * @param mixed $default Default return value when key does not exist 284 * @return array|mixed|null 285 */ 286 public function put($key = null, $default = null) 287 { 288 return $this->post($key, $default); 289 } 290 291 /** 292 * Fetch PATCH data (alias for \Slim\Http\Request::post) 293 * @param string $key 294 * @param mixed $default Default return value when key does not exist 295 * @return array|mixed|null 296 */ 297 public function patch($key = null, $default = null) 298 { 299 return $this->post($key, $default); 300 } 301 302 /** 303 * Fetch DELETE data (alias for \Slim\Http\Request::post) 304 * @param string $key 305 * @param mixed $default Default return value when key does not exist 306 * @return array|mixed|null 307 */ 308 public function delete($key = null, $default = null) 309 { 310 return $this->post($key, $default); 311 } 312 313 /** 314 * Fetch COOKIE data 315 * 316 * This method returns a key-value array of Cookie data sent in the HTTP request, or 317 * the value of a array key if requested; if the array key does not exist, NULL is returned. 318 * 319 * @param string $key 320 * @return array|string|null 321 */ 322 public function cookies($key = null) 323 { 324 if ($key) { 325 return $this->cookies->get($key); 326 } 327 328 return $this->cookies; 329 // if (!isset($this->env['slim.request.cookie_hash'])) { 330 // $cookieHeader = isset($this->env['COOKIE']) ? $this->env['COOKIE'] : ''; 331 // $this->env['slim.request.cookie_hash'] = Util::parseCookieHeader($cookieHeader); 332 // } 333 // if ($key) { 334 // if (isset($this->env['slim.request.cookie_hash'][$key])) { 335 // return $this->env['slim.request.cookie_hash'][$key]; 336 // } else { 337 // return null; 338 // } 339 // } else { 340 // return $this->env['slim.request.cookie_hash']; 341 // } 342 } 343 344 /** 345 * Does the Request body contain parsed form data? 346 * @return bool 347 */ 348 public function isFormData() 349 { 350 $method = isset($this->env['slim.method_override.original_method']) ? $this->env['slim.method_override.original_method'] : $this->getMethod(); 351 352 return ($method === self::METHOD_POST && is_null($this->getContentType())) || in_array($this->getMediaType(), self::$formDataMediaTypes); 353 } 354 355 /** 356 * Get Headers 357 * 358 * This method returns a key-value array of headers sent in the HTTP request, or 359 * the value of a hash key if requested; if the array key does not exist, NULL is returned. 360 * 361 * @param string $key 362 * @param mixed $default The default value returned if the requested header is not available 363 * @return mixed 364 */ 365 public function headers($key = null, $default = null) 366 { 367 if ($key) { 368 return $this->headers->get($key, $default); 369 } 370 371 return $this->headers; 372 // if ($key) { 373 // $key = strtoupper($key); 374 // $key = str_replace('-', '_', $key); 375 // $key = preg_replace('@^HTTP_@', '', $key); 376 // if (isset($this->env[$key])) { 377 // return $this->env[$key]; 378 // } else { 379 // return $default; 380 // } 381 // } else { 382 // $headers = array(); 383 // foreach ($this->env as $key => $value) { 384 // if (strpos($key, 'slim.') !== 0) { 385 // $headers[$key] = $value; 386 // } 387 // } 388 // 389 // return $headers; 390 // } 391 } 392 393 /** 394 * Get Body 395 * @return string 396 */ 397 public function getBody() 398 { 399 return $this->env['slim.input']; 400 } 401 402 /** 403 * Get Content Type 404 * @return string|null 405 */ 406 public function getContentType() 407 { 408 return $this->headers->get('CONTENT_TYPE'); 409 } 410 411 /** 412 * Get Media Type (type/subtype within Content Type header) 413 * @return string|null 414 */ 415 public function getMediaType() 416 { 417 $contentType = $this->getContentType(); 418 if ($contentType) { 419 $contentTypeParts = preg_split('/\s*[;,]\s*/', $contentType); 420 421 return strtolower($contentTypeParts[0]); 422 } 423 424 return null; 425 } 426 427 /** 428 * Get Media Type Params 429 * @return array 430 */ 431 public function getMediaTypeParams() 432 { 433 $contentType = $this->getContentType(); 434 $contentTypeParams = array(); 435 if ($contentType) { 436 $contentTypeParts = preg_split('/\s*[;,]\s*/', $contentType); 437 $contentTypePartsLength = count($contentTypeParts); 438 for ($i = 1; $i < $contentTypePartsLength; $i++) { 439 $paramParts = explode('=', $contentTypeParts[$i]); 440 $contentTypeParams[strtolower($paramParts[0])] = $paramParts[1]; 441 } 442 } 443 444 return $contentTypeParams; 445 } 446 447 /** 448 * Get Content Charset 449 * @return string|null 450 */ 451 public function getContentCharset() 452 { 453 $mediaTypeParams = $this->getMediaTypeParams(); 454 if (isset($mediaTypeParams['charset'])) { 455 return $mediaTypeParams['charset']; 456 } 457 458 return null; 459 } 460 461 /** 462 * Get Content-Length 463 * @return int 464 */ 465 public function getContentLength() 466 { 467 return $this->headers->get('CONTENT_LENGTH', 0); 468 } 469 470 /** 471 * Get Host 472 * @return string 473 */ 474 public function getHost() 475 { 476 if (isset($this->env['HTTP_HOST'])) { 477 if (strpos($this->env['HTTP_HOST'], ':') !== false) { 478 $hostParts = explode(':', $this->env['HTTP_HOST']); 479 480 return $hostParts[0]; 481 } 482 483 return $this->env['HTTP_HOST']; 484 } 485 486 return $this->env['SERVER_NAME']; 487 } 488 489 /** 490 * Get Host with Port 491 * @return string 492 */ 493 public function getHostWithPort() 494 { 495 return sprintf('%s:%s', $this->getHost(), $this->getPort()); 496 } 497 498 /** 499 * Get Port 500 * @return int 501 */ 502 public function getPort() 503 { 504 return (int)$this->env['SERVER_PORT']; 505 } 506 507 /** 508 * Get Scheme (https or http) 509 * @return string 510 */ 511 public function getScheme() 512 { 513 return $this->env['slim.url_scheme']; 514 } 515 516 /** 517 * Get Script Name (physical path) 518 * @return string 519 */ 520 public function getScriptName() 521 { 522 return $this->env['SCRIPT_NAME']; 523 } 524 525 /** 526 * LEGACY: Get Root URI (alias for Slim_Http_Request::getScriptName) 527 * @return string 528 */ 529 public function getRootUri() 530 { 531 return $this->getScriptName(); 532 } 533 534 /** 535 * Get Path (physical path + virtual path) 536 * @return string 537 */ 538 public function getPath() 539 { 540 return $this->getScriptName() . $this->getPathInfo(); 541 } 542 543 /** 544 * Get Path Info (virtual path) 545 * @return string 546 */ 547 public function getPathInfo() 548 { 549 return $this->env['PATH_INFO']; 550 } 551 552 /** 553 * LEGACY: Get Resource URI (alias for Slim_Http_Request::getPathInfo) 554 * @return string 555 */ 556 public function getResourceUri() 557 { 558 return $this->getPathInfo(); 559 } 560 561 /** 562 * Get URL (scheme + host [ + port if non-standard ]) 563 * @return string 564 */ 565 public function getUrl() 566 { 567 $url = $this->getScheme() . '://' . $this->getHost(); 568 if (($this->getScheme() === 'https' && $this->getPort() !== 443) || ($this->getScheme() === 'http' && $this->getPort() !== 80)) { 569 $url .= sprintf(':%s', $this->getPort()); 570 } 571 572 return $url; 573 } 574 575 /** 576 * Get IP 577 * @return string 578 */ 579 public function getIp() 580 { 581 $keys = array('X_FORWARDED_FOR', 'HTTP_X_FORWARDED_FOR', 'CLIENT_IP', 'REMOTE_ADDR'); 582 foreach ($keys as $key) { 583 if (isset($this->env[$key])) { 584 return $this->env[$key]; 585 } 586 } 587 588 return $this->env['REMOTE_ADDR']; 589 } 590 591 /** 592 * Get Referrer 593 * @return string|null 594 */ 595 public function getReferrer() 596 { 597 return $this->headers->get('HTTP_REFERER'); 598 } 599 600 /** 601 * Get Referer (for those who can't spell) 602 * @return string|null 603 */ 604 public function getReferer() 605 { 606 return $this->getReferrer(); 607 } 608 609 /** 610 * Get User Agent 611 * @return string|null 612 */ 613 public function getUserAgent() 614 { 615 return $this->headers->get('HTTP_USER_AGENT'); 616 } 617 }