1<?php 2 3namespace GuzzleHttp\Psr7; 4 5use InvalidArgumentException; 6use Psr\Http\Message\RequestInterface; 7use Psr\Http\Message\StreamInterface; 8use Psr\Http\Message\UriInterface; 9 10/** 11 * PSR-7 request implementation. 12 */ 13class Request implements RequestInterface 14{ 15 use MessageTrait; 16 17 /** @var string */ 18 private $method; 19 20 /** @var string|null */ 21 private $requestTarget; 22 23 /** @var UriInterface */ 24 private $uri; 25 26 /** 27 * @param string $method HTTP method 28 * @param string|UriInterface $uri URI 29 * @param array $headers Request headers 30 * @param string|resource|StreamInterface|null $body Request body 31 * @param string $version Protocol version 32 */ 33 public function __construct( 34 $method, 35 $uri, 36 array $headers = [], 37 $body = null, 38 $version = '1.1' 39 ) { 40 $this->assertMethod($method); 41 if (!($uri instanceof UriInterface)) { 42 $uri = new Uri($uri); 43 } 44 45 $this->method = strtoupper($method); 46 $this->uri = $uri; 47 $this->setHeaders($headers); 48 $this->protocol = $version; 49 50 if (!isset($this->headerNames['host'])) { 51 $this->updateHostFromUri(); 52 } 53 54 if ($body !== '' && $body !== null) { 55 $this->stream = Utils::streamFor($body); 56 } 57 } 58 59 public function getRequestTarget() 60 { 61 if ($this->requestTarget !== null) { 62 return $this->requestTarget; 63 } 64 65 $target = $this->uri->getPath(); 66 if ($target == '') { 67 $target = '/'; 68 } 69 if ($this->uri->getQuery() != '') { 70 $target .= '?' . $this->uri->getQuery(); 71 } 72 73 return $target; 74 } 75 76 public function withRequestTarget($requestTarget) 77 { 78 if (preg_match('#\s#', $requestTarget)) { 79 throw new InvalidArgumentException( 80 'Invalid request target provided; cannot contain whitespace' 81 ); 82 } 83 84 $new = clone $this; 85 $new->requestTarget = $requestTarget; 86 return $new; 87 } 88 89 public function getMethod() 90 { 91 return $this->method; 92 } 93 94 public function withMethod($method) 95 { 96 $this->assertMethod($method); 97 $new = clone $this; 98 $new->method = strtoupper($method); 99 return $new; 100 } 101 102 public function getUri() 103 { 104 return $this->uri; 105 } 106 107 public function withUri(UriInterface $uri, $preserveHost = false) 108 { 109 if ($uri === $this->uri) { 110 return $this; 111 } 112 113 $new = clone $this; 114 $new->uri = $uri; 115 116 if (!$preserveHost || !isset($this->headerNames['host'])) { 117 $new->updateHostFromUri(); 118 } 119 120 return $new; 121 } 122 123 private function updateHostFromUri() 124 { 125 $host = $this->uri->getHost(); 126 127 if ($host == '') { 128 return; 129 } 130 131 if (($port = $this->uri->getPort()) !== null) { 132 $host .= ':' . $port; 133 } 134 135 if (isset($this->headerNames['host'])) { 136 $header = $this->headerNames['host']; 137 } else { 138 $header = 'Host'; 139 $this->headerNames['host'] = 'Host'; 140 } 141 // Ensure Host is the first header. 142 // See: http://tools.ietf.org/html/rfc7230#section-5.4 143 $this->headers = [$header => [$host]] + $this->headers; 144 } 145 146 private function assertMethod($method) 147 { 148 if (!is_string($method) || $method === '') { 149 throw new \InvalidArgumentException('Method must be a non-empty string.'); 150 } 151 } 152} 153