1: <?php
2:
3: namespace PHPixie\HTTP\Messages;
4:
5: use Psr\Http\Message\StreamInterface;
6: use Psr\Http\Message\MessageInterface;
7: use InvalidArgumentException;
8:
9: 10: 11:
12: abstract class Message implements MessageInterface
13: {
14: 15: 16:
17: protected $protocolVersion;
18:
19: 20: 21:
22: protected $headers;
23:
24: 25: 26:
27: protected $body;
28:
29: 30: 31:
32: protected $processedHeaders = false;
33:
34: 35: 36:
37: protected $headerNames = array();
38:
39: 40: 41:
42: public function getProtocolVersion()
43: {
44: $this->requireProtocolVersion();
45: return $this->protocolVersion;
46: }
47:
48: 49: 50:
51: public function withProtocolVersion($version)
52: {
53: $new = clone $this;
54: $new->protocolVersion = $version;
55: return $new;
56: }
57:
58: 59: 60:
61: public function getHeaders()
62: {
63: $this->requireHeaders();
64: return $this->headers;
65: }
66:
67: 68: 69:
70: public function hasHeader($header)
71: {
72: $this->requireHeaders();
73: $lower = strtolower($header);
74: return array_key_exists($lower, $this->headerNames);
75: }
76:
77: 78: 79:
80: public function getHeaderLine($header)
81: {
82: $this->requireHeaders();
83: $lines = $this->getHeader($header);
84:
85: if (count($lines) === 0) {
86: return null;
87: }
88:
89: return implode(',', $lines);
90: }
91:
92: 93: 94:
95: public function getHeader($header)
96: {
97: $this->requireHeaders();
98: $lower = strtolower($header);
99:
100: if(!array_key_exists($lower, $this->headerNames)) {
101: return array();
102: }
103:
104: $normalized = $this->headerNames[$lower];
105: return $this->headers[$normalized];
106: }
107:
108: 109: 110:
111: public function withHeader($header, $value)
112: {
113: return $this->modifyHeader($header, $value);
114: }
115:
116: 117: 118:
119: public function withAddedHeader($header, $value)
120: {
121: return $this->modifyHeader($header, $value, true);
122: }
123:
124:
125: 126: 127: 128: 129: 130: 131:
132: protected function modifyHeader($header, $value, $append = false, $clone = true)
133: {
134: $this->requireHeaders();
135: if (!is_array($value)) {
136: $value = array($value);
137: }
138:
139: $headers = $this->headers;
140: $lower = strtolower($header);
141:
142: if(array_key_exists($lower, $this->headerNames)) {
143: $normalized = $this->headerNames[$lower];
144: $currentValue = $headers[$normalized];
145:
146: if($append) {
147: $value = array_merge($currentValue, $value);
148: $header = $normalized;
149: }else{
150: unset($headers[$normalized]);
151: }
152: }
153:
154: $headers[$header] = $value;
155:
156: if($clone) {
157: $message = clone $this;
158:
159: }else{
160: $message = $this;
161: }
162:
163: $message->headers = $headers;
164: $message->headerNames[$lower] = $header;
165:
166: return $message;
167: }
168:
169: 170: 171:
172: public function withoutHeader($header)
173: {
174: $this->requireHeaders();
175: $lower = strtolower($header);
176:
177: $new = clone $this;
178:
179: if(array_key_exists($lower, $this->headerNames)) {
180: $normalized = $this->headerNames[$lower];
181: unset($new->headers[$normalized]);
182: unset($new->headerNames[$lower]);
183: }
184:
185: return $new;
186: }
187:
188: 189: 190:
191: public function getBody()
192: {
193: $this->requireBody();
194: return $this->body;
195: }
196:
197: 198: 199:
200: public function withBody(StreamInterface $body)
201: {
202: $new = clone $this;
203: $new->body = $body;
204: return $new;
205: }
206:
207: 208: 209:
210: protected function populateHeaderNames()
211: {
212: $headers = array_keys($this->headers);
213: foreach($headers as $header) {
214: $this->headerNames[strtolower($header)] = $header;
215: }
216: }
217:
218: 219: 220:
221: protected function validateHeaders($headers)
222: {
223: foreach($headers as $name => $lines) {
224: if(empty($lines)) {
225: throw new InvalidArgumentException("Header values for '$name' are empty");
226: }
227: }
228: }
229:
230: 231: 232:
233: protected function requireHeaders()
234: {
235: if(!$this->processedHeaders) {
236: $this->populateHeaderNames();
237: $this->processedHeaders = true;
238: }
239: }
240:
241: 242: 243:
244: protected function requireProtocolVersion()
245: {
246:
247: }
248:
249: 250: 251:
252: protected function requireBody()
253: {
254:
255: }
256: }