Chris@0
|
1 <?php
|
Chris@0
|
2 /**
|
Chris@0
|
3 * Zend Framework (http://framework.zend.com/)
|
Chris@0
|
4 *
|
Chris@0
|
5 * @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
Chris@0
|
6 * @copyright Copyright (c) 2015-2016 Zend Technologies USA Inc. (http://www.zend.com)
|
Chris@0
|
7 * @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
Chris@0
|
8 */
|
Chris@0
|
9
|
Chris@0
|
10 namespace Zend\Diactoros\Request;
|
Chris@0
|
11
|
Chris@0
|
12 use InvalidArgumentException;
|
Chris@0
|
13 use Psr\Http\Message\RequestInterface;
|
Chris@0
|
14 use Psr\Http\Message\StreamInterface;
|
Chris@0
|
15 use UnexpectedValueException;
|
Chris@0
|
16 use Zend\Diactoros\AbstractSerializer;
|
Chris@0
|
17 use Zend\Diactoros\Request;
|
Chris@0
|
18 use Zend\Diactoros\Stream;
|
Chris@0
|
19 use Zend\Diactoros\Uri;
|
Chris@0
|
20
|
Chris@16
|
21 use function preg_match;
|
Chris@16
|
22 use function sprintf;
|
Chris@16
|
23
|
Chris@0
|
24 /**
|
Chris@0
|
25 * Serialize (cast to string) or deserialize (cast string to Request) messages.
|
Chris@0
|
26 *
|
Chris@0
|
27 * This class provides functionality for serializing a RequestInterface instance
|
Chris@0
|
28 * to a string, as well as the reverse operation of creating a Request instance
|
Chris@0
|
29 * from a string/stream representing a message.
|
Chris@0
|
30 */
|
Chris@0
|
31 final class Serializer extends AbstractSerializer
|
Chris@0
|
32 {
|
Chris@0
|
33 /**
|
Chris@0
|
34 * Deserialize a request string to a request instance.
|
Chris@0
|
35 *
|
Chris@0
|
36 * Internally, casts the message to a stream and invokes fromStream().
|
Chris@0
|
37 *
|
Chris@0
|
38 * @param string $message
|
Chris@0
|
39 * @return Request
|
Chris@0
|
40 * @throws UnexpectedValueException when errors occur parsing the message.
|
Chris@0
|
41 */
|
Chris@0
|
42 public static function fromString($message)
|
Chris@0
|
43 {
|
Chris@0
|
44 $stream = new Stream('php://temp', 'wb+');
|
Chris@0
|
45 $stream->write($message);
|
Chris@0
|
46 return self::fromStream($stream);
|
Chris@0
|
47 }
|
Chris@0
|
48
|
Chris@0
|
49 /**
|
Chris@0
|
50 * Deserialize a request stream to a request instance.
|
Chris@0
|
51 *
|
Chris@0
|
52 * @param StreamInterface $stream
|
Chris@0
|
53 * @return Request
|
Chris@0
|
54 * @throws UnexpectedValueException when errors occur parsing the message.
|
Chris@0
|
55 */
|
Chris@0
|
56 public static function fromStream(StreamInterface $stream)
|
Chris@0
|
57 {
|
Chris@0
|
58 if (! $stream->isReadable() || ! $stream->isSeekable()) {
|
Chris@0
|
59 throw new InvalidArgumentException('Message stream must be both readable and seekable');
|
Chris@0
|
60 }
|
Chris@0
|
61
|
Chris@0
|
62 $stream->rewind();
|
Chris@0
|
63
|
Chris@0
|
64 list($method, $requestTarget, $version) = self::getRequestLine($stream);
|
Chris@0
|
65 $uri = self::createUriFromRequestTarget($requestTarget);
|
Chris@0
|
66
|
Chris@0
|
67 list($headers, $body) = self::splitStream($stream);
|
Chris@0
|
68
|
Chris@0
|
69 return (new Request($uri, $method, $body, $headers))
|
Chris@0
|
70 ->withProtocolVersion($version)
|
Chris@0
|
71 ->withRequestTarget($requestTarget);
|
Chris@0
|
72 }
|
Chris@0
|
73
|
Chris@0
|
74 /**
|
Chris@0
|
75 * Serialize a request message to a string.
|
Chris@0
|
76 *
|
Chris@0
|
77 * @param RequestInterface $request
|
Chris@0
|
78 * @return string
|
Chris@0
|
79 */
|
Chris@0
|
80 public static function toString(RequestInterface $request)
|
Chris@0
|
81 {
|
Chris@0
|
82 $httpMethod = $request->getMethod();
|
Chris@0
|
83 if (empty($httpMethod)) {
|
Chris@0
|
84 throw new UnexpectedValueException('Object can not be serialized because HTTP method is empty');
|
Chris@0
|
85 }
|
Chris@0
|
86 $headers = self::serializeHeaders($request->getHeaders());
|
Chris@0
|
87 $body = (string) $request->getBody();
|
Chris@0
|
88 $format = '%s %s HTTP/%s%s%s';
|
Chris@0
|
89
|
Chris@0
|
90 if (! empty($headers)) {
|
Chris@0
|
91 $headers = "\r\n" . $headers;
|
Chris@0
|
92 }
|
Chris@0
|
93 if (! empty($body)) {
|
Chris@0
|
94 $headers .= "\r\n\r\n";
|
Chris@0
|
95 }
|
Chris@0
|
96
|
Chris@0
|
97 return sprintf(
|
Chris@0
|
98 $format,
|
Chris@0
|
99 $httpMethod,
|
Chris@0
|
100 $request->getRequestTarget(),
|
Chris@0
|
101 $request->getProtocolVersion(),
|
Chris@0
|
102 $headers,
|
Chris@0
|
103 $body
|
Chris@0
|
104 );
|
Chris@0
|
105 }
|
Chris@0
|
106
|
Chris@0
|
107 /**
|
Chris@0
|
108 * Retrieve the components of the request line.
|
Chris@0
|
109 *
|
Chris@0
|
110 * Retrieves the first line of the stream and parses it, raising an
|
Chris@0
|
111 * exception if it does not follow specifications; if valid, returns a list
|
Chris@0
|
112 * with the method, target, and version, in that order.
|
Chris@0
|
113 *
|
Chris@0
|
114 * @param StreamInterface $stream
|
Chris@0
|
115 * @return array
|
Chris@0
|
116 */
|
Chris@0
|
117 private static function getRequestLine(StreamInterface $stream)
|
Chris@0
|
118 {
|
Chris@0
|
119 $requestLine = self::getLine($stream);
|
Chris@0
|
120
|
Chris@0
|
121 if (! preg_match(
|
Chris@0
|
122 '#^(?P<method>[!\#$%&\'*+.^_`|~a-zA-Z0-9-]+) (?P<target>[^\s]+) HTTP/(?P<version>[1-9]\d*\.\d+)$#',
|
Chris@0
|
123 $requestLine,
|
Chris@0
|
124 $matches
|
Chris@0
|
125 )) {
|
Chris@0
|
126 throw new UnexpectedValueException('Invalid request line detected');
|
Chris@0
|
127 }
|
Chris@0
|
128
|
Chris@0
|
129 return [$matches['method'], $matches['target'], $matches['version']];
|
Chris@0
|
130 }
|
Chris@0
|
131
|
Chris@0
|
132 /**
|
Chris@0
|
133 * Create and return a Uri instance based on the provided request target.
|
Chris@0
|
134 *
|
Chris@0
|
135 * If the request target is of authority or asterisk form, an empty Uri
|
Chris@0
|
136 * instance is returned; otherwise, the value is used to create and return
|
Chris@0
|
137 * a new Uri instance.
|
Chris@0
|
138 *
|
Chris@0
|
139 * @param string $requestTarget
|
Chris@0
|
140 * @return Uri
|
Chris@0
|
141 */
|
Chris@0
|
142 private static function createUriFromRequestTarget($requestTarget)
|
Chris@0
|
143 {
|
Chris@0
|
144 if (preg_match('#^https?://#', $requestTarget)) {
|
Chris@0
|
145 return new Uri($requestTarget);
|
Chris@0
|
146 }
|
Chris@0
|
147
|
Chris@0
|
148 if (preg_match('#^(\*|[^/])#', $requestTarget)) {
|
Chris@0
|
149 return new Uri();
|
Chris@0
|
150 }
|
Chris@0
|
151
|
Chris@0
|
152 return new Uri($requestTarget);
|
Chris@0
|
153 }
|
Chris@0
|
154 }
|