├── .gitignore
├── .travis.yml
├── README.md
├── build
└── travis
│ ├── apache
│ └── virtual.host
│ └── scripts
│ ├── apache2-configure.sh
│ ├── apache2-vhost.sh
│ └── apt-get.sh
├── composer.json
├── phpunit.travis.xml
├── phpunit.xml.dist
├── src
├── AbstractMessage.php
├── AbstractRequest.php
├── Helper
│ ├── HeaderHelper.php
│ ├── ResponseHelper.php
│ ├── ServerHelper.php
│ └── StreamHelper.php
├── HttpClient.php
├── HttpClientInterface.php
├── Request.php
├── Response.php
├── ServerRequest.php
├── Stream
│ ├── PhpInputStream.php
│ ├── Stream.php
│ └── StringStream.php
├── Transport
│ ├── AbstractTransport.php
│ ├── CurlTransport.php
│ ├── StreamTransport.php
│ ├── TransportInterface.php
│ └── cacert.pem
├── UploadedFile.php
└── Uri
│ ├── AbstractUri.php
│ ├── PsrUri.php
│ ├── Uri.php
│ ├── UriHelper.php
│ └── UriInterface.php
└── test
├── AbstractBaseTestCase.php
├── AbstractMessageTest.php
├── AbstractRequestTest.php
├── HttpClientTest.php
├── Mock
└── MockTransport.php
├── RequestTest.php
├── ResponseTest.php
├── ServerRequestTest.php
├── Stream
├── StreamTest.php
└── StringStreamTest.php
├── Stub
├── StubMessage.php
├── StubRequest.php
├── download_stub.txt
└── http_stub.php
├── Transport
├── AbstractTransportTest.php
├── CurlTransportTest.php
├── StreamTransportTest.php
└── downloaded.tmp
├── UploadedFileTest.php
└── Uri
├── PsrUriTest.php
├── UriHelperTest.php
└── UriTest.php
/.gitignore:
--------------------------------------------------------------------------------
1 | # Development system files #
2 | .*
3 | !/.gitignore
4 | !/.travis.yml
5 |
6 | # Composer #
7 | vendor/*
8 | composer.lock
9 |
10 | # Test #
11 | phpunit.xml
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | sudo: true
4 |
5 | php:
6 | - 5.3
7 | - 5.4
8 | - 5.5
9 | - 5.6
10 | - 7.0
11 | - 7.1
12 | - 7.2
13 |
14 | matrix:
15 | allow_failures:
16 | - php: 7.0
17 | - php: 7.1
18 | - php: 7.2
19 |
20 | before_install:
21 | - composer self-update
22 | - sh -e build/travis/scripts/apt-get.sh
23 | - sh -e build/travis/scripts/apache2-vhost.sh
24 | - sh -e build/travis/scripts/apache2-configure.sh
25 |
26 | before_script:
27 | - composer update --dev
28 | - phpenv rehash
29 |
30 | script:
31 | - phpunit --configuration phpunit.travis.xml
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # The PSR7 Http Implementation [](https://github.com/igrigorik/ga-beacon)
2 |
3 | [](https://travis-ci.org/asika32764/http)
4 | [](https://packagist.org/packages/asika/http)
5 | [](https://packagist.org/packages/asika/http)
6 | [](https://packagist.org/packages/asika/http)
7 | [](https://packagist.org/packages/asika/http)
8 |
9 | This package provides PSR7 standard Http message objects, Uri objects, Stream objects and Client request object. **(PHP 5.3 Compatible)**
10 |
11 | > Some parts of this package based on [phly/http](https://github.com/phly/http) and [joomla/http](https://github.com/joomla-framework/http)
12 |
13 | **Project deprecated, please see [windwalker/http](https://github.com/ventoviro/windwalker-http)**
14 |
15 | ## Installation via Composer
16 |
17 | Add this to the require block in your `composer.json`.
18 |
19 | ``` json
20 | {
21 | "require": {
22 | "asika/http": "~1.0"
23 | }
24 | }
25 | ```
26 |
27 | ## Make A Request
28 |
29 | HttpClient is a simple class to make restful request.
30 |
31 | ``` php
32 | use Asika\Http\HttpClient;
33 |
34 | $http = new HttpClient;
35 |
36 | $response = $http->get('http://example.com/?foo=bar');
37 |
38 | // This is PSR7 ResponseInterface
39 | (string) $response->getBody();
40 | ```
41 |
42 | ### Other Methods
43 |
44 | ``` php
45 | $http = new HttpClient;
46 |
47 | // The post data can be query string or array
48 | $response = $http->post('http://example.com/?foo=bar', array('post_data' => 'data'));
49 | $response = $http->put('http://example.com/?foo=bar', array('post_data' => 'data'));
50 | $response = $http->patch('http://example.com/?foo=bar', array('post_data' => 'data'));
51 | $response = $http->delete('http://example.com/?foo=bar', array('post_data' => 'data'));
52 |
53 | $response = $http->head('http://example.com/?foo=bar');
54 | $response = $http->trace('http://example.com/?foo=bar');
55 | $response = $http->options('http://example.com/?foo=bar');
56 |
57 | // With headers
58 | $response = $http->get('http://example.com/', null, array('X-Foo' => 'Bar'));
59 |
60 | // Use request()
61 | $response = $http->request('POST', 'http://example.com/?foo=bar', 'this=is&post=data');
62 | ```
63 |
64 | ### Use Psr RequestInterface to Make Request
65 |
66 | Psr7 Request is a immutable object, you have to get the return object every operation.
67 |
68 | ``` php
69 | use Asika\Http\Request;
70 |
71 | $request = new Request;
72 |
73 | // Note: You have to get the return value.
74 | // Every change will return new object.
75 | $request = $request->withRequestTarget('http://example.com/flower/sakura')
76 | ->withMethod('POST')
77 | ->withAddedHeader('Authorization', 'Bearer ' . $token)
78 | ->withAddedHeader('Content-Type', 'application/text');
79 |
80 | // OR
81 | $request = new Request(
82 | 'http://example.com/flower/sakura',
83 | 'POST',
84 | 'php://memory',
85 | array(
86 | 'Authorization' => 'Bearer ' . $token,
87 | 'Content-Type' => 'application/json',
88 | )
89 | );
90 |
91 | // This is a POST request so we write post data to body
92 | $request->getBody()->write('this=is&post=data');
93 |
94 | $http = new HttpClient;
95 |
96 | // Send request
97 | $response = $http->send($request);
98 | ```
99 |
100 | Use Uri and Json output.
101 |
102 | ``` php
103 | use Asika\Http\Request;
104 | use Asika\Http\Uri\PsrUri;
105 |
106 | $request = (new Request)
107 | ->withUri(new PsrUri('http://example.com'))
108 | ->withMethod('POST')
109 | ->withAddedHeader('Authorization', 'Bearer ' . $token)
110 | ->withAddedHeader('Content-Type', 'application/json') // Use JSON
111 |
112 | // Note: Request will ignore path and query in Uri
113 | // So we have to set RequestTarget here
114 | ->withRequestTarget('/path/of/uri?flower=sakura');
115 |
116 | // If you want to set a non-origin-form request target, set the
117 | // request-target explicitly:
118 | $request = $request->withRequestTarget((string) $uri); // absolute-form
119 | $request = $request->withRequestTarget($uri->getAuthority(); // authority-form
120 | $request = $request->withRequestTarget('*'); // asterisk-form
121 |
122 | // This is JSON request so we encode data here
123 | $request->getBody()->write(json_encode($data));
124 | $response = $http->send($request);
125 |
126 | $response->getStatusCode(); // 200 is OK
127 | ```
128 |
129 | ### Custom Transports and Options
130 |
131 | Now support Curl and Steam 2 transports.
132 |
133 | ``` php
134 | use Asika\Http\Transport\CurlTransport;
135 |
136 | $options = array(
137 | 'certpath' => '/custom/cert.pem'
138 | );
139 |
140 | $transport = new CurlTransport($options);
141 |
142 | // Set transport when client new
143 | $http = new HttpClient(array(), $transport);
144 | ```
145 |
146 | Set custom CURL options:
147 |
148 | ``` php
149 | $options = array(
150 | 'options' => array(
151 | CURLOPT_SSL_VERIFYHOST => false,
152 | CURLOPT_SSL_VERIFYPEER => true
153 | )
154 | );
155 |
156 | $httpOptions = array(
157 | 'headers' => array(
158 | 'X-Foo' => 'Bar'
159 | )
160 | );
161 |
162 | $http = new HttpClient($httpOptions, new CurlTransport($options));
163 | ```
164 |
165 | ### Download Remote File
166 |
167 | ``` php
168 | $http = new HttpClient;
169 |
170 | $dest = '/path/to/local/file.zip';
171 |
172 | $response = $http->download('http://example.com/file.zip', $dest);
173 |
174 | if ($response->getStatusCode() != 200)
175 | {
176 | // Error
177 | }
178 | ```
179 |
180 | ### Response Interface
181 |
182 | Response object holds a Stream object to store returned string.
183 |
184 | ``` php
185 | // The return value is: 'FOO BAR'
186 | $body = $response->getBody();
187 |
188 | // Simply to string
189 | (string) $body; // FOO BAR
190 |
191 | $body->seek(2);
192 | $body->getContents(); // O BAR
193 |
194 | $body->rewind();
195 | $body->read(5); // FOO B
196 |
197 | $body->getSize(); // 7
198 | ```
199 |
200 | ## Uri
201 |
202 | `Uri` is a simple Uri object to modify URL but not Psr UriInterface.
203 |
204 | The methods provided in the `Uri` class allow you to manipulate all aspects of a uri. For example, suppose you wanted to set a new uri, add in a port, and then also post a username and password to authenticate a .htaccess security file. You could use the following syntax:
205 |
206 | ``` php
207 | // new uri object
208 | $uri = new Asika\Http\Uri\Uri;
209 |
210 | $uri->setHost('http://localhost');
211 | $uri->setPort('8888');
212 | $uri->setUser('myUser');
213 | $uri->setPass('myPass');
214 |
215 | echo $uri->__toString();
216 | ```
217 |
218 | This will output:
219 |
220 | ```
221 | myUser:myPass@http://localhost:8888
222 | ```
223 |
224 | If you wanted to add a specific filepath after the host you could use the `setPath()` method:
225 |
226 | ``` php
227 | // set path
228 | $uri->setPath('path/to/file.php');
229 | ```
230 |
231 | Which will output
232 |
233 | ```
234 | myUser:myPass@http://localhost:8888path/to/file.php
235 | ```
236 |
237 | Adding a URL query:
238 |
239 | ``` php
240 | // url query
241 | $uri->setQuery('foo=bar');
242 | ```
243 |
244 | Output:
245 |
246 | ```
247 | myUser:myPass@http://localhost:8888path/to/file.php?foo=bar
248 | ```
249 |
250 | ### PsrUri
251 |
252 | `PsrUri` is a Uri object implemented the Psr UriInterface.
253 |
254 | This object is also immutable, so we must get return value as new object every change.
255 |
256 | ``` php
257 | $uri = (new PsrUri('http://example.com'))
258 | ->withScheme('https')
259 | ->withUserInfo('user', 'pass')
260 | ->withPath('/path/to/target')
261 | ->withQuery('flower=sakura')
262 | ->withFragment('#hash');
263 |
264 | (string) $uri; // https://user:pass@example.com/path/to/target?flower=sakura#fragment
265 | ```
266 |
267 | ## Stream
268 |
269 | Stream is a powerful stream wrapper.
270 |
271 | Read write data to memory:
272 |
273 | ``` php
274 | $stream = new Stream('php://memory', 'wb+');
275 |
276 | $stream->write('Foo Bar');
277 |
278 | $stream->rewind(); // Back to begin
279 |
280 | // Now we take something we wrote into memory
281 |
282 | $stream->__toString(); // get: Foo Bar
283 |
284 | // OR
285 |
286 | $stream->rewind();
287 | $stream->getContents(); // get: Foo Bar
288 | ```
289 |
290 | Read data from `php://input`
291 |
292 | ``` php
293 | $stream = new PhpInputSteam;
294 |
295 | $data = $stream->__toString(); // foo=bar
296 |
297 | $query = \Asika\Http\Uri\UriHelper::parseQuery($data); // array('foo' => 'bar')
298 | ```
299 |
300 | Read file:
301 |
302 | ``` php
303 | $stream = new Stream('/path/to/file.txt', 'r+');
304 |
305 | $stream->__toString(); // Read
306 |
307 | $steam->seek($stream->getSize());
308 | $steam->write('new string'); // Write
309 | ```
310 |
311 | Quick copy stream.
312 |
313 | ``` php
314 | // Remote source
315 | $src = new Stream('http://example/test.txt');
316 |
317 | // Local store
318 | $dest = new Stream('/path/to/local/test.txt');
319 |
320 | // Do copy
321 | \Asika\Http\Helper\StreamHelper::copy($src, $dest);
322 |
323 | // Get Data
324 | $dest->rewind();
325 | $data = $dest->getContents();
326 | ```
327 |
328 | See: [Psr7 StreamInterface](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-7-http-message.md#13-streams)
329 | / [API](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-7-http-message.md#34-psrhttpmessagestreaminterface)
330 |
331 | ## Other Http Message Objects
332 |
333 | ### `ServerRequest`
334 |
335 | A Request object to store server data, like: `$_SERVER`, `$_COOKIE`, `$_REQUEST` etc.
336 |
337 | ### `UploadedFile`
338 |
339 | An object to store uploaded files, see: [Uploaded files interface](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-7-http-message.md#16-uploaded-files)
340 |
341 | ``` php
342 | $files = array();
343 |
344 | foreach ($_FILE as $name => $file)
345 | {
346 | $files[$name] = new UploadedFile($file['tmp_name'], $file['size'], $file['error'], $file['name'], $file['type']);
347 | }
348 |
349 | $request = new ServerRequest(
350 | $_SERVER,
351 | $_GET,
352 | $_POST,
353 | $_COOKIE,
354 | $files
355 | );
356 | ```
357 |
358 | ## More About Psr 7
359 |
360 | [PSR7 HTTP message interfaces](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-7-http-message.md) /
361 | [HTTP Message Meta Document](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-7-http-message-meta.md)
362 |
--------------------------------------------------------------------------------
/build/travis/apache/virtual.host:
--------------------------------------------------------------------------------
1 |
73 | * [user-info@]host[:port] 74 | *75 | * 76 | * If the port component is not set or is the standard port for the current 77 | * scheme, it SHOULD NOT be included. 78 | * 79 | * @see https://tools.ietf.org/html/rfc3986#section-3.2 80 | * 81 | * @return string The URI authority, in "[user-info@]host[:port]" format. 82 | */ 83 | public function getAuthority() 84 | { 85 | if (empty($this->host)) 86 | { 87 | return ''; 88 | } 89 | 90 | $authority = $this->host; 91 | 92 | $userInfo = $this->getUserInfo(); 93 | 94 | if ($userInfo) 95 | { 96 | $authority = $userInfo . '@' . $authority; 97 | } 98 | 99 | if (!$this->isStandardPort($this->scheme, $this->host, $this->port)) 100 | { 101 | $authority .= ':' . $this->port; 102 | } 103 | 104 | return $authority; 105 | } 106 | 107 | /** 108 | * Return an instance with the specified scheme. 109 | * 110 | * This method MUST retain the state of the current instance, and return 111 | * an instance that contains the specified scheme. 112 | * 113 | * Implementations MUST support the schemes "http" and "https" case 114 | * insensitively, and MAY accommodate other schemes if required. 115 | * 116 | * An empty scheme is equivalent to removing the scheme. 117 | * 118 | * @param string $scheme The scheme to use with the new instance. 119 | * 120 | * @return static A new instance with the specified scheme. 121 | * 122 | * @throws \InvalidArgumentException for invalid or unsupported schemes. 123 | */ 124 | public function withScheme($scheme) 125 | { 126 | $scheme = UriHelper::filterScheme($scheme); 127 | 128 | $new = clone $this; 129 | $new->scheme = $scheme; 130 | 131 | return $new; 132 | } 133 | 134 | /** 135 | * Return an instance with the specified user information. 136 | * 137 | * This method MUST retain the state of the current instance, and return 138 | * an instance that contains the specified user information. 139 | * 140 | * Password is optional, but the user information MUST include the 141 | * user; an empty string for the user is equivalent to removing user 142 | * information. 143 | * 144 | * @param string $user The user name to use for authority. 145 | * @param string $password The password associated with $user. 146 | * 147 | * @return static A new instance with the specified user information. 148 | */ 149 | public function withUserInfo($user, $password = null) 150 | { 151 | $new = clone $this; 152 | $new->user = $user; 153 | $new->pass = $password; 154 | 155 | return $new; 156 | } 157 | 158 | /** 159 | * Return an instance with the specified host. 160 | * 161 | * This method MUST retain the state of the current instance, and return 162 | * an instance that contains the specified host. 163 | * 164 | * An empty host value is equivalent to removing the host. 165 | * 166 | * @param string $host The hostname to use with the new instance. 167 | * 168 | * @return static A new instance with the specified host. 169 | * 170 | * @throws \InvalidArgumentException for invalid hostnames. 171 | */ 172 | public function withHost($host) 173 | { 174 | $new = clone $this; 175 | $new->host = $host; 176 | 177 | return $new; 178 | } 179 | 180 | /** 181 | * Return an instance with the specified port. 182 | * 183 | * This method MUST retain the state of the current instance, and return 184 | * an instance that contains the specified port. 185 | * 186 | * Implementations MUST raise an exception for ports outside the 187 | * established TCP and UDP port ranges. 188 | * 189 | * A null value provided for the port is equivalent to removing the port 190 | * information. 191 | * 192 | * @param int $port The port to use with the new instance; a null value 193 | * removes the port information. 194 | * 195 | * @return static A new instance with the specified port. 196 | * @throws \InvalidArgumentException for invalid ports. 197 | */ 198 | public function withPort($port) 199 | { 200 | if (is_object($port) || is_array($port)) 201 | { 202 | throw new \InvalidArgumentException('Invalid port type.'); 203 | } 204 | 205 | $port = (int) $port; 206 | 207 | if ($port < 1 || $port > 65535) 208 | { 209 | throw new \InvalidArgumentException(sprintf('Number of "%d" is not a valid TCP/UDP port', $port)); 210 | } 211 | 212 | $new = clone $this; 213 | $new->port = $port; 214 | 215 | return $new; 216 | } 217 | 218 | /** 219 | * Return an instance with the specified path. 220 | * 221 | * This method MUST retain the state of the current instance, and return 222 | * an instance that contains the specified path. 223 | * 224 | * The path can either be empty or absolute (starting with a slash) or 225 | * rootless (not starting with a slash). Implementations MUST support all 226 | * three syntaxes. 227 | * 228 | * If the path is intended to be domain-relative rather than path relative then 229 | * it must begin with a slash ("/"). Paths not starting with a slash ("/") 230 | * are assumed to be relative to some base path known to the application or 231 | * consumer. 232 | * 233 | * Users can provide both encoded and decoded path characters. 234 | * Implementations ensure the correct encoding as outlined in getPath(). 235 | * 236 | * @param string $path The path to use with the new instance. 237 | * 238 | * @return static A new instance with the specified path. 239 | * @throws \InvalidArgumentException for invalid paths. 240 | */ 241 | public function withPath($path) 242 | { 243 | if (!is_string($path)) 244 | { 245 | throw new \InvalidArgumentException('URI Path should be a string'); 246 | } 247 | 248 | $path = (string) $path; 249 | 250 | if (strpos($path, '?') !== false || strpos($path, '#') !== false ) 251 | { 252 | throw new \InvalidArgumentException('Path should not contain `?` and `#` symbols.'); 253 | } 254 | 255 | $path = UriHelper::cleanPath($path); 256 | $path = UriHelper::filterPath($path); 257 | 258 | $new = clone $this; 259 | $new->path = $path; 260 | 261 | return $new; 262 | } 263 | 264 | /** 265 | * Return an instance with the specified query string. 266 | * 267 | * This method MUST retain the state of the current instance, and return 268 | * an instance that contains the specified query string. 269 | * 270 | * Users can provide both encoded and decoded query characters. 271 | * Implementations ensure the correct encoding as outlined in getQuery(). 272 | * 273 | * An empty query string value is equivalent to removing the query string. 274 | * 275 | * @param string|array $query The query string to use with the new instance. 276 | * 277 | * @return static A new instance with the specified query string. 278 | * @throws \InvalidArgumentException for invalid query strings. 279 | */ 280 | public function withQuery($query) 281 | { 282 | if (!is_string($query)) 283 | { 284 | throw new \InvalidArgumentException('URI query should be a string or array'); 285 | } 286 | 287 | $query = UriHelper::filterQuery($query); 288 | 289 | $new = clone $this; 290 | $new->vars = UriHelper::parseQuery($query); 291 | $new->query = $query; 292 | 293 | return $new; 294 | } 295 | 296 | /** 297 | * Return an instance with the specified URI fragment. 298 | * 299 | * This method MUST retain the state of the current instance, and return 300 | * an instance that contains the specified URI fragment. 301 | * 302 | * Users can provide both encoded and decoded fragment characters. 303 | * Implementations ensure the correct encoding as outlined in getFragment(). 304 | * 305 | * An empty fragment value is equivalent to removing the fragment. 306 | * 307 | * @param string $fragment The fragment to use with the new instance. 308 | * 309 | * @return static A new instance with the specified fragment. 310 | */ 311 | public function withFragment($fragment) 312 | { 313 | $fragment = UriHelper::filterFragment($fragment); 314 | 315 | $new = clone $this; 316 | $new->fragment = $fragment; 317 | 318 | return $new; 319 | } 320 | 321 | /** 322 | * Is a given port non-standard for the current scheme? 323 | * 324 | * @param string $scheme 325 | * @param string $host 326 | * @param int $port 327 | * 328 | * @return boolean 329 | */ 330 | protected function isStandardPort($scheme, $host, $port) 331 | { 332 | if (!$scheme) 333 | { 334 | return false; 335 | } 336 | 337 | if (!$host || !$port) 338 | { 339 | return true; 340 | } 341 | 342 | return (isset($this->standardSchemes[$scheme]) && $port == $this->standardSchemes[$scheme]); 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /src/Uri/Uri.php: -------------------------------------------------------------------------------- 1 | vars[$name]) ? $this->vars[$name] : null; 32 | 33 | $this->vars[$name] = $value; 34 | 35 | // Empty the query 36 | $this->query = null; 37 | 38 | return $tmp; 39 | } 40 | 41 | /** 42 | * Removes an item from the query string variables if it exists. 43 | * 44 | * @param string $name Name of variable to remove. 45 | * 46 | * @return void 47 | * 48 | * @since 2.0 49 | */ 50 | public function delVar($name) 51 | { 52 | if (array_key_exists($name, $this->vars)) 53 | { 54 | unset($this->vars[$name]); 55 | 56 | // Empty the query 57 | $this->query = null; 58 | } 59 | } 60 | 61 | /** 62 | * Sets the query to a supplied string in format: 63 | * foo=bar&x=y 64 | * 65 | * @param mixed $query The query string or array. 66 | * 67 | * @return void 68 | * 69 | * @since 2.0 70 | */ 71 | public function setQuery($query) 72 | { 73 | if (is_array($query)) 74 | { 75 | $this->vars = $query; 76 | } 77 | else 78 | { 79 | if (strpos($query, '&') !== false) 80 | { 81 | $query = str_replace('&', '&', $query); 82 | } 83 | 84 | parse_str($query, $this->vars); 85 | } 86 | 87 | // Empty the query 88 | $this->query = null; 89 | } 90 | 91 | /** 92 | * Set URI scheme (protocol) 93 | * ie. http, https, ftp, etc... 94 | * 95 | * @param string $scheme The URI scheme. 96 | * 97 | * @return void 98 | * 99 | * @since 2.0 100 | */ 101 | public function setScheme($scheme) 102 | { 103 | $this->scheme = $scheme; 104 | } 105 | 106 | /** 107 | * Set URI username. 108 | * 109 | * @param string $user The URI username. 110 | * 111 | * @return void 112 | * 113 | * @since 2.0 114 | */ 115 | public function setUser($user) 116 | { 117 | $this->user = $user; 118 | } 119 | 120 | /** 121 | * Set URI password. 122 | * 123 | * @param string $pass The URI password. 124 | * 125 | * @return void 126 | * 127 | * @since 2.0 128 | */ 129 | public function setPass($pass) 130 | { 131 | $this->pass = $pass; 132 | } 133 | 134 | /** 135 | * Set URI host. 136 | * 137 | * @param string $host The URI host. 138 | * 139 | * @return void 140 | * 141 | * @since 2.0 142 | */ 143 | public function setHost($host) 144 | { 145 | $this->host = $host; 146 | } 147 | 148 | /** 149 | * Set URI port. 150 | * 151 | * @param integer $port The URI port number. 152 | * 153 | * @return void 154 | * 155 | * @since 2.0 156 | */ 157 | public function setPort($port) 158 | { 159 | $this->port = $port; 160 | } 161 | 162 | /** 163 | * Set the URI path string. 164 | * 165 | * @param string $path The URI path string. 166 | * 167 | * @return void 168 | * 169 | * @since 2.0 170 | */ 171 | public function setPath($path) 172 | { 173 | $this->path = UriHelper::cleanPath($path); 174 | } 175 | 176 | /** 177 | * Set the URI anchor string 178 | * everything after the "#". 179 | * 180 | * @param string $anchor The URI anchor string. 181 | * 182 | * @return void 183 | * 184 | * @since 2.0 185 | */ 186 | public function setFragment($anchor) 187 | { 188 | $this->fragment = $anchor; 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/Uri/UriHelper.php: -------------------------------------------------------------------------------- 1 | value pairs to return as a query string. 40 | * 41 | * @return string The resulting query string. 42 | * 43 | * @see parse_str() 44 | * @since 2.0 45 | */ 46 | public static function buildQuery(array $params) 47 | { 48 | return urldecode(http_build_query($params, '', '&')); 49 | } 50 | 51 | /** 52 | * Does a UTF-8 safe version of PHP parse_url function 53 | * 54 | * @param string $url URL to parse 55 | * 56 | * @return mixed Associative array or false if badly formed URL. 57 | * 58 | * @see http://us3.php.net/manual/en/function.parse-url.php 59 | * @since 2.0 60 | */ 61 | public static function parseUrl($url) 62 | { 63 | $result = false; 64 | 65 | // Build arrays of values we need to decode before parsing 66 | $entities = array('%21', '%2A', '%27', '%28', '%29', '%3B', '%3A', '%40', '%26', '%3D', '%24', '%2C', '%2F', '%3F', '%23', '%5B', '%5D'); 67 | $replacements = array('!', '*', "'", "(", ")", ";", ":", "@", "&", "=", "$", ",", "/", "?", "#", "[", "]"); 68 | 69 | // Create encoded URL with special URL characters decoded so it can be parsed 70 | // All other characters will be encoded 71 | $encodedURL = str_replace($entities, $replacements, urlencode($url)); 72 | 73 | // Parse the encoded URL 74 | $encodedParts = parse_url($encodedURL); 75 | 76 | // Now, decode each value of the resulting array 77 | if ($encodedParts) 78 | { 79 | foreach ($encodedParts as $key => $value) 80 | { 81 | $result[$key] = urldecode(str_replace($replacements, $entities, $value)); 82 | } 83 | } 84 | 85 | return $result; 86 | } 87 | 88 | /** 89 | * parseQuery 90 | * 91 | * @param string $query 92 | * 93 | * @return mixed 94 | */ 95 | public static function parseQuery($query) 96 | { 97 | parse_str($query, $vars); 98 | 99 | return $vars; 100 | } 101 | 102 | /** 103 | * filterScheme 104 | * 105 | * @param string $scheme 106 | * 107 | * @return string 108 | */ 109 | public static function filterScheme($scheme) 110 | { 111 | $scheme = strtolower($scheme); 112 | $scheme = preg_replace('#:(//)?$#', '', $scheme); 113 | 114 | if (empty($scheme)) 115 | { 116 | return ''; 117 | } 118 | 119 | return $scheme; 120 | } 121 | 122 | /** 123 | * Filter a query string to ensure it is propertly encoded. 124 | * 125 | * Ensures that the values in the query string are properly urlencoded. 126 | * 127 | * @param string $query 128 | * 129 | * @return string 130 | */ 131 | public static function filterQuery($query) 132 | { 133 | if (! empty($query) && strpos($query, '?') === 0) 134 | { 135 | $query = substr($query, 1); 136 | } 137 | 138 | $parts = explode('&', $query); 139 | foreach ($parts as $index => $part) 140 | { 141 | list($key, $value) = static::splitQueryValue($part); 142 | 143 | if ($value === null) 144 | { 145 | $parts[$index] = static::filterQueryOrFragment($key); 146 | 147 | continue; 148 | } 149 | 150 | $parts[$index] = sprintf( 151 | '%s=%s', 152 | static::filterQueryOrFragment($key), 153 | static::filterQueryOrFragment($value) 154 | ); 155 | } 156 | 157 | return implode('&', $parts); 158 | } 159 | 160 | /** 161 | * Split a query value into a key/value tuple. 162 | * 163 | * @param string $value 164 | * 165 | * @return array A value with exactly two elements, key and value 166 | */ 167 | public static function splitQueryValue($value) 168 | { 169 | $data = explode('=', $value, 2); 170 | 171 | if (1 === count($data)) 172 | { 173 | $data[] = null; 174 | } 175 | 176 | return $data; 177 | } 178 | 179 | /** 180 | * Filter a query string key or value, or a fragment. 181 | * 182 | * @param string $value 183 | * 184 | * @return string 185 | */ 186 | public static function filterQueryOrFragment($value) 187 | { 188 | return preg_replace_callback( 189 | '/(?:[^' . static::CHAR_UNRESERVED . static::CHAR_SUB_DELIMS . '%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/', 190 | function($matches) 191 | { 192 | return rawurlencode($matches[0]); 193 | }, 194 | $value 195 | ); 196 | } 197 | 198 | /** 199 | * Filter a fragment value to ensure it is properly encoded. 200 | * 201 | * @param string $fragment 202 | * 203 | * @return string 204 | */ 205 | public static function filterFragment($fragment) 206 | { 207 | if (null === $fragment) 208 | { 209 | $fragment = ''; 210 | } 211 | 212 | if (! empty($fragment) && strpos($fragment, '#') === 0) 213 | { 214 | $fragment = substr($fragment, 1); 215 | } 216 | 217 | return static::filterQueryOrFragment($fragment); 218 | } 219 | 220 | /** 221 | * Filters the path of a URI to ensure it is properly encoded. 222 | * 223 | * @param string $path 224 | * 225 | * @return string 226 | */ 227 | public static function filterPath($path) 228 | { 229 | return preg_replace_callback( 230 | '/(?:[^' . self::CHAR_UNRESERVED . ':@&=\+\$,\/;%]+|%(?![A-Fa-f0-9]{2}))/', 231 | function($matches) 232 | { 233 | return rawurlencode($matches[0]); 234 | }, 235 | $path 236 | ); 237 | } 238 | 239 | /** 240 | * Resolves //, ../ and ./ from a path and returns 241 | * the result. Eg: 242 | * 243 | * /foo/bar/../boo.php => /foo/boo.php 244 | * /foo/bar/../../boo.php => /boo.php 245 | * /foo/bar/.././/boo.php => /foo/boo.php 246 | * 247 | * @param string $path The URI path to clean. 248 | * 249 | * @return string Cleaned and resolved URI path. 250 | * 251 | * @since 2.0 252 | */ 253 | public static function cleanPath($path) 254 | { 255 | $path = explode('/', preg_replace('#(/+)#', '/', $path)); 256 | 257 | for ($i = 0, $n = count($path); $i < $n; $i++) 258 | { 259 | if ($path[$i] == '.' || $path[$i] == '..') 260 | { 261 | if (($path[$i] == '.') || ($path[$i] == '..' && $i == 1 && $path[0] == '')) 262 | { 263 | unset($path[$i]); 264 | $path = array_values($path); 265 | $i--; 266 | $n--; 267 | } 268 | elseif ($path[$i] == '..' && ($i > 1 || ($i == 1 && $path[0] != ''))) 269 | { 270 | unset($path[$i]); 271 | unset($path[$i - 1]); 272 | $path = array_values($path); 273 | $i -= 2; 274 | $n -= 2; 275 | } 276 | } 277 | } 278 | 279 | return implode('/', $path); 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /src/Uri/UriInterface.php: -------------------------------------------------------------------------------- 1 | value pair array. 67 | * 68 | * @return string Query string. 69 | * 70 | * @since 2.0 71 | */ 72 | public function getQuery($toArray = false); 73 | 74 | /** 75 | * Get URI scheme (protocol) 76 | * ie. http, https, ftp, etc... 77 | * 78 | * @return string The URI scheme. 79 | * 80 | * @since 2.0 81 | */ 82 | public function getScheme(); 83 | 84 | /** 85 | * Get URI username 86 | * Returns the username, or null if no username was specified. 87 | * 88 | * @return string The URI username. 89 | * 90 | * @since 2.0 91 | */ 92 | public function getUser(); 93 | 94 | /** 95 | * Get URI password 96 | * Returns the password, or null if no password was specified. 97 | * 98 | * @return string The URI password. 99 | * 100 | * @since 2.0 101 | */ 102 | public function getPass(); 103 | 104 | /** 105 | * Get URI host 106 | * Returns the hostname/ip or null if no hostname/ip was specified. 107 | * 108 | * @return string The URI host. 109 | * 110 | * @since 2.0 111 | */ 112 | public function getHost(); 113 | 114 | /** 115 | * Get URI port 116 | * Returns the port number, or null if no port was specified. 117 | * 118 | * @return integer The URI port number. 119 | * 120 | * @since 2.0 121 | */ 122 | public function getPort(); 123 | 124 | /** 125 | * Gets the URI path string. 126 | * 127 | * @return string The URI path string. 128 | * 129 | * @since 2.0 130 | */ 131 | public function getPath(); 132 | 133 | /** 134 | * Get the URI archor string 135 | * Everything after the "#". 136 | * 137 | * @return string The URI anchor string. 138 | * 139 | * @since 2.0 140 | */ 141 | public function getFragment(); 142 | 143 | /** 144 | * Checks whether the current URI is using HTTPS. 145 | * 146 | * @return boolean True if using SSL via HTTPS. 147 | * 148 | * @since 2.0 149 | */ 150 | public function isSSL(); 151 | } 152 | -------------------------------------------------------------------------------- /test/AbstractBaseTestCase.php: -------------------------------------------------------------------------------- 1 | assertEquals( 36 | StringHelper::clean($expected), 37 | StringHelper::clean($actual), 38 | $message, 39 | $delta, 40 | $maxDepth, 41 | $canonicalize, 42 | $ignoreCase 43 | ); 44 | } 45 | 46 | /** 47 | * assertStringDataEquals 48 | * 49 | * @param string $expected 50 | * @param string $actual 51 | * @param string $message 52 | * @param int $delta 53 | * @param int $maxDepth 54 | * @param bool $canonicalize 55 | * @param bool $ignoreCase 56 | * 57 | * @return void 58 | */ 59 | public function assertStringSafeEquals($expected, $actual, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false) 60 | { 61 | $this->assertEquals( 62 | trim(StringHelper::removeCRLF($expected)), 63 | trim(StringHelper::removeCRLF($actual)), 64 | $message, 65 | $delta, 66 | $maxDepth, 67 | $canonicalize, 68 | $ignoreCase 69 | ); 70 | } 71 | 72 | /** 73 | * assertExpectedException 74 | * 75 | * @param callable $closure 76 | * @param string $class 77 | * @param string $msg 78 | * @param int $code 79 | * @param string $message 80 | * 81 | * @return void 82 | */ 83 | public function assertExpectedException($closure, $class = 'Exception', $msg = null, $code = null, $message = '') 84 | { 85 | if (is_object($class)) 86 | { 87 | $class = get_class($class); 88 | } 89 | 90 | try 91 | { 92 | $closure(); 93 | } 94 | catch (\Exception $e) 95 | { 96 | $this->assertInstanceOf($class, $e, $message); 97 | 98 | if ($msg) 99 | { 100 | $this->assertStringStartsWith($msg, $e->getMessage(), $message); 101 | } 102 | 103 | if ($code) 104 | { 105 | $this->assertEquals($code, $e->getCode(), $message); 106 | } 107 | 108 | return; 109 | } 110 | 111 | $this->fail('No exception caught.'); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /test/AbstractMessageTest.php: -------------------------------------------------------------------------------- 1 | message = new StubMessage; 38 | } 39 | 40 | /** 41 | * Tears down the fixture, for example, closes a network connection. 42 | * This method is called after a test is executed. 43 | * 44 | * @return void 45 | */ 46 | protected function tearDown() 47 | { 48 | } 49 | 50 | /** 51 | * Method to test getProtocolVersion(). 52 | * 53 | * @return void 54 | * 55 | * @covers Asika\Http\AbstractMessage::getProtocolVersion 56 | * @covers Asika\Http\AbstractMessage::withProtocolVersion 57 | */ 58 | public function testWithAndSetProtocolVersion() 59 | { 60 | $this->assertEquals('1.1', $this->message->getProtocolVersion()); 61 | 62 | $message = $this->message->withProtocolVersion('1.0'); 63 | 64 | $this->assertNotSame($this->message, $message); 65 | $this->assertEquals('1.0', $message->getProtocolVersion()); 66 | } 67 | 68 | /** 69 | * Method to test getHeader(). 70 | * 71 | * @return void 72 | * 73 | * @covers Asika\Http\AbstractMessage::getHeader 74 | * @covers Asika\Http\AbstractMessage::withHeader 75 | */ 76 | public function testWithAndGetHeader() 77 | { 78 | $message = $this->message->withHeader('Content-Type', 'text/json'); 79 | 80 | $this->assertNotSame($this->message, $message); 81 | $this->assertEquals(array('text/json'), $message->getHeader('Content-Type')); 82 | $this->assertEquals(array('text/json'), $message->getHeader('content-type')); 83 | 84 | $message = $this->message->withHeader('X-Foo', array('Foo', 'Bar')); 85 | 86 | $this->assertNotSame($this->message, $message); 87 | $this->assertEquals(array('Foo', 'Bar'), $message->getHeader('X-Foo')); 88 | } 89 | 90 | /** 91 | * Method to test hasHeader(). 92 | * 93 | * @return void 94 | * 95 | * @covers Asika\Http\AbstractMessage::hasHeader 96 | */ 97 | public function testHasHeader() 98 | { 99 | $this->assertFalse($this->message->hasHeader('X-Foo')); 100 | 101 | $message = $this->message->withHeader('Content-Type', 'text/json'); 102 | 103 | $this->assertTrue($message->hasHeader('Content-Type')); 104 | $this->assertTrue($message->hasHeader('content-type')); 105 | } 106 | 107 | /** 108 | * Method to test getHeaders(). 109 | * 110 | * @return void 111 | * 112 | * @covers Asika\Http\AbstractMessage::getHeaders 113 | */ 114 | public function testGetHeaders() 115 | { 116 | $this->assertEquals(array(), $this->message->getHeaders()); 117 | 118 | $message = $this->message->withHeader('X-Foo', array('Foo', 'Bar')); 119 | $message = $message->withHeader('X-Bar', array('Flower', 'Sakura')); 120 | 121 | $expected = array( 122 | 'X-Foo' => array('Foo', 'Bar'), 123 | 'X-Bar' => array('Flower', 'Sakura'), 124 | ); 125 | 126 | $this->assertEquals($expected, $message->getHeaders()); 127 | } 128 | 129 | /** 130 | * Method to test getHeaderLine(). 131 | * 132 | * @return void 133 | * 134 | * @covers Asika\Http\AbstractMessage::getHeaderLine 135 | */ 136 | public function testGetHeaderLine() 137 | { 138 | $this->assertEquals('', $this->message->getHeaderLine('X-Foo')); 139 | 140 | $message = $this->message->withHeader('X-Foo', array('Foo', 'Bar')); 141 | 142 | $this->assertEquals('Foo,Bar', $message->getHeaderLine('X-Foo')); 143 | $this->assertEquals('Foo,Bar', $message->getHeaderLine('x-foo')); 144 | $this->assertSame('', $message->getHeaderLine('x-bar')); 145 | } 146 | 147 | /** 148 | * Method to test withAddedHeader(). 149 | * 150 | * @return void 151 | * 152 | * @covers Asika\Http\AbstractMessage::withAddedHeader 153 | */ 154 | public function testWithAddedHeader() 155 | { 156 | $message = $this->message->withAddedHeader('X-Foo', 'One'); 157 | 158 | $this->assertNotSame($this->message, $message); 159 | $this->assertEquals(array('One'), $message->getHeader('X-Foo')); 160 | 161 | $message = $message->withAddedHeader('X-Foo', 'Two'); 162 | 163 | $this->assertEquals(array('One', 'Two'), $message->getHeader('X-Foo')); 164 | 165 | $message = $message->withAddedHeader('X-Foo', array('Three', 'Four')); 166 | 167 | $this->assertEquals(array('One', 'Two', 'Three', 'Four'), $message->getHeader('X-Foo')); 168 | } 169 | 170 | /** 171 | * Method to test withoutHeader(). 172 | * 173 | * @return void 174 | * 175 | * @covers Asika\Http\AbstractMessage::withoutHeader 176 | */ 177 | public function testWithoutHeader() 178 | { 179 | $message = $this->message->withAddedHeader('X-Foo', 'One'); 180 | 181 | $this->assertNotSame($this->message, $message); 182 | $this->assertEquals(array('One'), $message->getHeader('X-Foo')); 183 | 184 | $message2 = $message->withoutHeader('X-Foo'); 185 | 186 | $this->assertNotSame($this->message, $message2); 187 | $this->assertEquals(array(), $message2->getHeader('X-Foo')); 188 | 189 | $message3 = $message->withoutHeader('x-foo'); 190 | 191 | $this->assertNotSame($this->message, $message3); 192 | $this->assertEquals(array(), $message3->getHeader('X-Foo')); 193 | } 194 | 195 | /** 196 | * Method to test getBody(). 197 | * 198 | * @return void 199 | * 200 | * @covers Asika\Http\AbstractMessage::getBody 201 | */ 202 | public function testWithAndGetBody() 203 | { 204 | $message = $this->message->withBody(new Stream); 205 | 206 | $this->assertNotSame($this->message, $message); 207 | $this->assertInstanceOf('Psr\Http\Message\StreamInterface', $message->getBody()); 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /test/AbstractRequestTest.php: -------------------------------------------------------------------------------- 1 | instance = new StubRequest; 39 | } 40 | 41 | /** 42 | * Tears down the fixture, for example, closes a network connection. 43 | * This method is called after a test is executed. 44 | * 45 | * @return void 46 | */ 47 | protected function tearDown() 48 | { 49 | } 50 | 51 | /** 52 | * testConstruct 53 | * 54 | * @return void 55 | */ 56 | public function testConstruct() 57 | { 58 | // Test no params 59 | $request = new StubRequest; 60 | 61 | $this->assertInstanceOf('Asika\Http\Uri\PsrUri', $request->getUri()); 62 | $this->assertEquals('', (string) $request->getUri()); 63 | $this->assertNull($request->getMethod()); 64 | $this->assertInstanceOf('Asika\Http\Stream\Stream', $request->getBody()); 65 | $this->assertEquals('php://memory', $request->getBody()->getMetadata('uri')); 66 | $this->assertEquals(array(), $request->getHeaders()); 67 | 68 | // Test with params 69 | $uri = 'http://example.com/?foo=bar#baz'; 70 | $method = 'post'; 71 | $body = fopen($tmpfile = tempnam(sys_get_temp_dir(), 'windwalker'), 'wb+'); 72 | $headers = array( 73 | 'X-Foo' => array('Flower', 'Sakura'), 74 | 'Content-Type' => 'application/json' 75 | ); 76 | 77 | $request = new StubRequest($uri, $method, $body, $headers); 78 | 79 | $this->assertInstanceOf('Asika\Http\Uri\PsrUri', $request->getUri()); 80 | $this->assertEquals('http://example.com/?foo=bar#baz', (string) $request->getUri()); 81 | $this->assertEquals('POST', $request->getMethod()); 82 | $this->assertInstanceOf('Asika\Http\Stream\Stream', $request->getBody()); 83 | $this->assertEquals($tmpfile, $request->getBody()->getMetadata('uri')); 84 | $this->assertEquals(array('Flower', 'Sakura'), $request->getHeader('x-foo')); 85 | $this->assertEquals(array('application/json'), $request->getHeader('content-type')); 86 | 87 | fclose($body); 88 | 89 | // Test with object params 90 | $uri = new PsrUri('http://example.com/flower/sakura?foo=bar#baz'); 91 | $body = new Stream; 92 | $request = new StubRequest($uri, null, $body); 93 | 94 | $this->assertSame($uri, $request->getUri()); 95 | $this->assertSame($body, $request->getBody()); 96 | } 97 | 98 | /** 99 | * Method to test getRequestTarget(). 100 | * 101 | * @return void 102 | * 103 | * @covers Asika\Http\AbstractRequest::getRequestTarget 104 | * @covers Asika\Http\AbstractRequest::withRequestTarget 105 | */ 106 | public function testWithAndGetRequestTarget() 107 | { 108 | $this->assertEquals('/', $this->instance->getRequestTarget()); 109 | 110 | $request = $this->instance->withUri(new PsrUri('http://example.com/flower/sakura?foo=bar#baz')); 111 | 112 | $this->assertNotSame($request, $this->instance); 113 | $this->assertEquals('/flower/sakura?foo=bar', (string) $request->getRequestTarget()); 114 | 115 | $request = $request->withUri(new PsrUri('http://example.com')); 116 | 117 | $this->assertEquals('/', (string) $request->getRequestTarget()); 118 | 119 | $request = $request->withRequestTarget('*'); 120 | 121 | $this->assertEquals('*', $request->getRequestTarget()); 122 | } 123 | 124 | /** 125 | * Method to test getMethod(). 126 | * 127 | * @return void 128 | * 129 | * @covers Asika\Http\AbstractRequest::getMethod 130 | * @covers Asika\Http\AbstractRequest::withMethod 131 | */ 132 | public function testWithAndGetMethod() 133 | { 134 | $this->assertNull($this->instance->getMethod()); 135 | 136 | $request = $this->instance->withMethod('patch'); 137 | 138 | $this->assertNotSame($request, $this->instance); 139 | $this->assertEquals('PATCH', $request->getMethod()); 140 | 141 | $this->assertExpectedException(function() use ($request) 142 | { 143 | $request->withMethod('FLY'); 144 | }, new \InvalidArgumentException); 145 | } 146 | 147 | /** 148 | * Method to test getUri(). 149 | * 150 | * @return void 151 | * 152 | * @covers Asika\Http\AbstractRequest::getUri 153 | * @covers Asika\Http\AbstractRequest::withUri 154 | */ 155 | public function testWithAndGetUri() 156 | { 157 | $this->assertInstanceOf('Asika\Http\Uri\PsrUri', $this->instance->getUri()); 158 | $this->assertEquals('', (string) $this->instance->getUri()); 159 | 160 | $request = $this->instance->withUri(new PsrUri('http://example.com/flower/sakura?foo=bar#baz'), true); 161 | 162 | $this->assertNotSame($request, $this->instance); 163 | $this->assertEquals('http://example.com/flower/sakura?foo=bar#baz', (string) $request->getUri()); 164 | $this->assertEquals(array(), $request->getHeader('host')); 165 | 166 | $request = $this->instance->withUri(new PsrUri('http://windwalker.io/flower/sakura?foo=bar#baz')); 167 | 168 | $this->assertEquals('http://windwalker.io/flower/sakura?foo=bar#baz', (string) $request->getUri()); 169 | $this->assertEquals(array('windwalker.io'), $request->getHeader('host')); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /test/Mock/MockTransport.php: -------------------------------------------------------------------------------- 1 | request = $request; 43 | 44 | return $this->doRequest($request); 45 | } 46 | 47 | /** 48 | * Send a request to the server and return a Response object with the response. 49 | * 50 | * @param RequestInterface $request The request object to store request params. 51 | * 52 | * @return ResponseInterface 53 | * 54 | * @since 2.1 55 | */ 56 | protected function doRequest(RequestInterface $request) 57 | { 58 | return new Response; 59 | } 60 | 61 | /** 62 | * Method to check if HTTP transport layer available for using 63 | * 64 | * @return boolean True if available else false 65 | * 66 | * @since 2.1 67 | */ 68 | public static function isSupported() 69 | { 70 | return true; 71 | } 72 | 73 | /** 74 | * Use stream to download file. 75 | * 76 | * @param RequestInterface $request The request object to store request params. 77 | * @param string|StreamInterface $dest The dest path to store file. 78 | * 79 | * @return ResponseInterface 80 | * @since 2.1 81 | */ 82 | public function download(RequestInterface $request, $dest) 83 | { 84 | $this->setOption('target_file', $dest); 85 | 86 | return $this->request($request); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /test/RequestTest.php: -------------------------------------------------------------------------------- 1 | instance = new Request; 37 | } 38 | 39 | /** 40 | * Tears down the fixture, for example, closes a network connection. 41 | * This method is called after a test is executed. 42 | * 43 | * @return void 44 | */ 45 | protected function tearDown() 46 | { 47 | } 48 | 49 | /** 50 | * Method to test getHeaders(). 51 | * 52 | * @return void 53 | * 54 | * @covers Asika\Http\Request::getHeaders 55 | */ 56 | public function testGetHeaders() 57 | { 58 | $this->assertEquals(array(), $this->instance->getHeaders()); 59 | 60 | $request = $this->instance->withUri(new PsrUri('http://windwalker.io/flower/sakura')); 61 | 62 | $this->assertEquals(array('Host' => array('windwalker.io')), $request->getHeaders()); 63 | } 64 | 65 | /** 66 | * Method to test getHeader(). 67 | * 68 | * @return void 69 | * 70 | * @covers Asika\Http\Request::getHeader 71 | */ 72 | public function testGetHeader() 73 | { 74 | $this->assertEquals(array(), $this->instance->getHeader('host')); 75 | 76 | $request = $this->instance->withUri(new PsrUri('http://windwalker.io/flower/sakura')); 77 | 78 | $this->assertEquals(array('windwalker.io'), $request->getHeader('host')); 79 | } 80 | 81 | /** 82 | * Method to test hasHeader(). 83 | * 84 | * @return void 85 | * 86 | * @covers Asika\Http\Request::hasHeader 87 | */ 88 | public function testHasHeader() 89 | { 90 | $request = new \Asika\Http\Request('http://example.com/foo', 'GET'); 91 | 92 | $this->assertTrue($request->hasHeader('host')); 93 | $this->assertTrue($request->hasHeader('Host')); 94 | $this->assertFalse($request->hasHeader('X-Foo')); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /test/ResponseTest.php: -------------------------------------------------------------------------------- 1 | instance = new Response; 37 | } 38 | 39 | /** 40 | * Tears down the fixture, for example, closes a network connection. 41 | * This method is called after a test is executed. 42 | * 43 | * @return void 44 | */ 45 | protected function tearDown() 46 | { 47 | } 48 | 49 | public function testConstruct() 50 | { 51 | // Test no params 52 | $res = new Response; 53 | 54 | $this->assertInstanceOf('Asika\Http\Stream\Stream', $res->getBody()); 55 | $this->assertEquals('php://memory', $res->getBody()->getMetadata('uri')); 56 | $this->assertEquals(200, $res->getStatusCode()); 57 | $this->assertEquals(array(), $res->getHeaders()); 58 | 59 | // Test with params 60 | $body = fopen($tmpfile = tempnam(sys_get_temp_dir(), 'http'), 'wb+'); 61 | $headers = array( 62 | 'X-Foo' => array('Flower', 'Sakura'), 63 | 'Content-Type' => 'application/json' 64 | ); 65 | 66 | $res = new Response($body, 404, $headers); 67 | 68 | $this->assertInstanceOf('Asika\Http\Stream\Stream', $res->getBody()); 69 | $this->assertEquals($tmpfile, $res->getBody()->getMetadata('uri')); 70 | $this->assertEquals(array('Flower', 'Sakura'), $res->getHeader('x-foo')); 71 | $this->assertEquals(array('application/json'), $res->getHeader('content-type')); 72 | 73 | fclose($body); 74 | 75 | // Test with object params 76 | $body = new Stream; 77 | $res = new Response($body); 78 | 79 | $this->assertSame($body, $res->getBody()); 80 | } 81 | 82 | /** 83 | * Method to test getStatusCode(). 84 | * 85 | * @return void 86 | * 87 | * @covers Asika\Http\Response::getStatusCode 88 | * @covers Asika\Http\Response::withStatus 89 | */ 90 | public function testWithAndGetStatusCode() 91 | { 92 | $this->assertEquals(200, $this->instance->getStatusCode()); 93 | 94 | $res = $this->instance->withStatus(403); 95 | 96 | $this->assertNotSame($res, $this->instance); 97 | $this->assertEquals(403, $res->getStatusCode()); 98 | 99 | $res = $res->withStatus(500, 'Unknown error'); 100 | 101 | $this->assertEquals(500, $res->getStatusCode()); 102 | $this->assertEquals('Unknown error', $res->getReasonPhrase()); 103 | } 104 | 105 | /** 106 | * Method to test getReasonPhrase(). 107 | * 108 | * @return void 109 | * 110 | * @covers Asika\Http\Response::getReasonPhrase 111 | */ 112 | public function testGetReasonPhrase() 113 | { 114 | $res = new Response; 115 | 116 | $res = $res->withStatus(200); 117 | 118 | $this->assertEquals('OK', $res->getReasonPhrase()); 119 | 120 | $res = $res->withStatus(400); 121 | 122 | $this->assertEquals('Bad Request', $res->getReasonPhrase()); 123 | 124 | $res = $res->withStatus(404); 125 | 126 | $this->assertEquals('Not Found', $res->getReasonPhrase()); 127 | 128 | $res = $res->withStatus(500); 129 | 130 | $this->assertEquals('Internal Server Error', $res->getReasonPhrase()); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /test/ServerRequestTest.php: -------------------------------------------------------------------------------- 1 | instance = new ServerRequest; 39 | } 40 | 41 | /** 42 | * Tears down the fixture, for example, closes a network connection. 43 | * This method is called after a test is executed. 44 | * 45 | * @return void 46 | */ 47 | protected function tearDown() 48 | { 49 | } 50 | 51 | /** 52 | * testConstruct 53 | * 54 | * @return void 55 | */ 56 | public function testConstruct() 57 | { 58 | $server = array( 59 | 'foo' => 'bar', 60 | 'baz' => 'bat', 61 | ); 62 | 63 | $server['server'] = true; 64 | 65 | $files = array( 66 | 'files' => new UploadedFile('php://temp', 0), 67 | ); 68 | 69 | $uri = new PsrUri('http://example.com'); 70 | $method = 'POST'; 71 | $headers = array( 72 | 'Host' => array('example.com'), 73 | ); 74 | 75 | $request = new ServerRequest( 76 | $server, 77 | $files, 78 | $uri, 79 | $method, 80 | 'php://memory', 81 | $headers 82 | ); 83 | 84 | $this->assertEquals($server, $request->getServerParams()); 85 | $this->assertEquals($files, $request->getUploadedFiles()); 86 | 87 | $this->assertSame($uri, $request->getUri()); 88 | $this->assertEquals($method, $request->getMethod()); 89 | $this->assertEquals($headers, $request->getHeaders()); 90 | 91 | $body = $request->getBody(); 92 | $stream = TestHelper::getValue($body, 'stream'); 93 | 94 | $this->assertEquals('php://memory', $stream); 95 | } 96 | 97 | /** 98 | * Method to test getServerParams(). 99 | * 100 | * @return void 101 | * 102 | * @covers Asika\Http\ServerRequest::getServerParams 103 | * @TODO Implement testGetServerParams(). 104 | */ 105 | public function testGetServerParams() 106 | { 107 | // Remove the following lines when you implement this test. 108 | $this->markTestIncomplete( 109 | 'This test has not been implemented yet.' 110 | ); 111 | } 112 | 113 | /** 114 | * Method to test getCookieParams(). 115 | * 116 | * @return void 117 | * 118 | * @covers Asika\Http\ServerRequest::getCookieParams 119 | * @TODO Implement testGetCookieParams(). 120 | */ 121 | public function testGetCookieParams() 122 | { 123 | // Remove the following lines when you implement this test. 124 | $this->markTestIncomplete( 125 | 'This test has not been implemented yet.' 126 | ); 127 | } 128 | 129 | /** 130 | * Method to test withCookieParams(). 131 | * 132 | * @return void 133 | * 134 | * @covers Asika\Http\ServerRequest::withCookieParams 135 | * @TODO Implement testWithCookieParams(). 136 | */ 137 | public function testWithCookieParams() 138 | { 139 | // Remove the following lines when you implement this test. 140 | $this->markTestIncomplete( 141 | 'This test has not been implemented yet.' 142 | ); 143 | } 144 | 145 | /** 146 | * Method to test getQueryParams(). 147 | * 148 | * @return void 149 | * 150 | * @covers Asika\Http\ServerRequest::getQueryParams 151 | * @TODO Implement testGetQueryParams(). 152 | */ 153 | public function testGetQueryParams() 154 | { 155 | // Remove the following lines when you implement this test. 156 | $this->markTestIncomplete( 157 | 'This test has not been implemented yet.' 158 | ); 159 | } 160 | 161 | /** 162 | * Method to test withQueryParams(). 163 | * 164 | * @return void 165 | * 166 | * @covers Asika\Http\ServerRequest::withQueryParams 167 | * @TODO Implement testWithQueryParams(). 168 | */ 169 | public function testWithQueryParams() 170 | { 171 | // Remove the following lines when you implement this test. 172 | $this->markTestIncomplete( 173 | 'This test has not been implemented yet.' 174 | ); 175 | } 176 | 177 | /** 178 | * Method to test getUploadedFiles(). 179 | * 180 | * @return void 181 | * 182 | * @covers Asika\Http\ServerRequest::getUploadedFiles 183 | * @TODO Implement testGetUploadedFiles(). 184 | */ 185 | public function testGetUploadedFiles() 186 | { 187 | // Remove the following lines when you implement this test. 188 | $this->markTestIncomplete( 189 | 'This test has not been implemented yet.' 190 | ); 191 | } 192 | 193 | /** 194 | * Method to test withUploadedFiles(). 195 | * 196 | * @return void 197 | * 198 | * @covers Asika\Http\ServerRequest::withUploadedFiles 199 | * @TODO Implement testWithUploadedFiles(). 200 | */ 201 | public function testWithUploadedFiles() 202 | { 203 | // Remove the following lines when you implement this test. 204 | $this->markTestIncomplete( 205 | 'This test has not been implemented yet.' 206 | ); 207 | } 208 | 209 | /** 210 | * Method to test getParsedBody(). 211 | * 212 | * @return void 213 | * 214 | * @covers Asika\Http\ServerRequest::getParsedBody 215 | * @TODO Implement testGetParsedBody(). 216 | */ 217 | public function testGetParsedBody() 218 | { 219 | // Remove the following lines when you implement this test. 220 | $this->markTestIncomplete( 221 | 'This test has not been implemented yet.' 222 | ); 223 | } 224 | 225 | /** 226 | * Method to test withParsedBody(). 227 | * 228 | * @return void 229 | * 230 | * @covers Asika\Http\ServerRequest::withParsedBody 231 | * @TODO Implement testWithParsedBody(). 232 | */ 233 | public function testWithParsedBody() 234 | { 235 | // Remove the following lines when you implement this test. 236 | $this->markTestIncomplete( 237 | 'This test has not been implemented yet.' 238 | ); 239 | } 240 | 241 | /** 242 | * Method to test getAttributes(). 243 | * 244 | * @return void 245 | * 246 | * @covers Asika\Http\ServerRequest::getAttributes 247 | * @TODO Implement testGetAttributes(). 248 | */ 249 | public function testGetAttributes() 250 | { 251 | // Remove the following lines when you implement this test. 252 | $this->markTestIncomplete( 253 | 'This test has not been implemented yet.' 254 | ); 255 | } 256 | 257 | /** 258 | * Method to test getAttribute(). 259 | * 260 | * @return void 261 | * 262 | * @covers Asika\Http\ServerRequest::getAttribute 263 | * @TODO Implement testGetAttribute(). 264 | */ 265 | public function testGetAttribute() 266 | { 267 | // Remove the following lines when you implement this test. 268 | $this->markTestIncomplete( 269 | 'This test has not been implemented yet.' 270 | ); 271 | } 272 | 273 | /** 274 | * Method to test withAttribute(). 275 | * 276 | * @return void 277 | * 278 | * @covers Asika\Http\ServerRequest::withAttribute 279 | * @TODO Implement testWithAttribute(). 280 | */ 281 | public function testWithAttribute() 282 | { 283 | // Remove the following lines when you implement this test. 284 | $this->markTestIncomplete( 285 | 'This test has not been implemented yet.' 286 | ); 287 | } 288 | 289 | /** 290 | * Method to test withoutAttribute(). 291 | * 292 | * @return void 293 | * 294 | * @covers Asika\Http\ServerRequest::withoutAttribute 295 | * @TODO Implement testWithoutAttribute(). 296 | */ 297 | public function testWithoutAttribute() 298 | { 299 | // Remove the following lines when you implement this test. 300 | $this->markTestIncomplete( 301 | 'This test has not been implemented yet.' 302 | ); 303 | } 304 | } 305 | -------------------------------------------------------------------------------- /test/Stream/StreamTest.php: -------------------------------------------------------------------------------- 1 | instance = new Stream('php://memory', Stream::MODE_READ_WRITE_RESET); 45 | } 46 | 47 | /** 48 | * Tears down the fixture, for example, closes a network connection. 49 | * This method is called after a test is executed. 50 | * 51 | * @return void 52 | */ 53 | protected function tearDown() 54 | { 55 | if ($this->tmpnam && is_file($this->tmpnam)) 56 | { 57 | unlink($this->tmpnam); 58 | } 59 | } 60 | 61 | public function testConstruct() 62 | { 63 | $resource = fopen('php://memory', Stream::MODE_READ_WRITE_RESET); 64 | $stream = new Stream($resource); 65 | 66 | $this->assertInstanceOf('Asika\Http\Stream\Stream', $stream); 67 | 68 | $stream = new Stream; 69 | 70 | $this->assertInternalType('resource', TestHelper::getValue($stream, 'resource')); 71 | $this->assertEquals('php://memory', TestHelper::getValue($stream, 'stream')); 72 | } 73 | 74 | /** 75 | * Method to test __toString(). 76 | * 77 | * @return void 78 | * 79 | * @covers Asika\Http\Stream::__toString 80 | */ 81 | public function test__toString() 82 | { 83 | $message = 'foo bar'; 84 | 85 | $this->instance->write($message); 86 | 87 | $this->assertEquals($message, (string) $this->instance); 88 | 89 | // Not readable should return empty string 90 | $this->createTempFile(); 91 | 92 | file_put_contents($this->tmpnam, 'FOO BAR'); 93 | 94 | $stream = new Stream($this->tmpnam, 'w'); 95 | 96 | $this->assertEquals('', $stream->__toString()); 97 | } 98 | 99 | /** 100 | * Method to test close(). 101 | * 102 | * @return void 103 | * 104 | * @covers Asika\Http\Stream::close 105 | */ 106 | public function testClose() 107 | { 108 | $this->createTempFile(); 109 | 110 | $resource = fopen($this->tmpnam, Stream::MODE_READ_WRITE_RESET); 111 | 112 | $stream = new Stream($resource); 113 | $stream->write('Foo Bar'); 114 | 115 | $stream->close(); 116 | 117 | $this->assertFalse(is_resource($resource)); 118 | $this->assertAttributeEmpty('resource', $stream); 119 | $this->assertEquals('', (string) $stream); 120 | } 121 | 122 | /** 123 | * Method to test detach(). 124 | * 125 | * @return void 126 | * 127 | * @covers Asika\Http\Stream::detach 128 | */ 129 | public function testDetach() 130 | { 131 | $resource = fopen('php://memory', Stream::MODE_READ_WRITE_RESET); 132 | $stream = new Stream($resource); 133 | 134 | $this->assertSame($resource, $stream->detach()); 135 | $this->assertAttributeEmpty('resource', $stream); 136 | $this->assertAttributeEmpty('stream', $stream); 137 | } 138 | 139 | /** 140 | * Method to test getSize(). 141 | * 142 | * @return void 143 | * 144 | * @covers Asika\Http\Stream::getSize 145 | */ 146 | public function testGetSize() 147 | { 148 | $this->createTempFile(); 149 | 150 | file_put_contents($this->tmpnam, 'FOO BAR'); 151 | $resource = fopen($this->tmpnam, Stream::MODE_READ_ONLY_FROM_BEGIN); 152 | 153 | $stream = new Stream($resource); 154 | 155 | $this->assertEquals(7, $stream->getSize()); 156 | } 157 | 158 | /** 159 | * Method to test tell(). 160 | * 161 | * @return void 162 | * 163 | * @covers Asika\Http\Stream::tell 164 | */ 165 | public function testTell() 166 | { 167 | $this->createTempFile(); 168 | 169 | file_put_contents($this->tmpnam, 'FOO BAR'); 170 | $resource = fopen($this->tmpnam, Stream::MODE_READ_WRITE_RESET); 171 | 172 | $stream = new Stream($resource); 173 | 174 | fseek($resource, 2); 175 | 176 | $this->assertEquals(2, $stream->tell()); 177 | 178 | $stream->detach(); 179 | 180 | $this->assertExpectedException(function() use ($stream) 181 | { 182 | $stream->tell(); 183 | }, new \RuntimeException); 184 | } 185 | 186 | /** 187 | * Method to test eof(). 188 | * 189 | * @return void 190 | * 191 | * @covers Asika\Http\Stream::eof 192 | */ 193 | public function testEof() 194 | { 195 | $this->createTempFile(); 196 | file_put_contents($this->tmpnam, 'FOO BAR'); 197 | $resource = fopen($this->tmpnam, Stream::MODE_READ_ONLY_FROM_BEGIN); 198 | $stream = new Stream($resource); 199 | 200 | fseek($resource, 2); 201 | $this->assertFalse($stream->eof()); 202 | 203 | while (! feof($resource)) 204 | { 205 | fread($resource, 4096); 206 | } 207 | 208 | $this->assertTrue($stream->eof()); 209 | } 210 | 211 | /** 212 | * Method to test isSeekable(). 213 | * 214 | * @return void 215 | * 216 | * @covers Asika\Http\Stream::isSeekable 217 | */ 218 | public function testIsSeekable() 219 | { 220 | $this->createTempFile(); 221 | 222 | file_put_contents($this->tmpnam, 'FOO BAR'); 223 | $resource = fopen($this->tmpnam, Stream::MODE_READ_WRITE_RESET); 224 | $stream = new Stream($resource); 225 | 226 | $this->assertTrue($stream->isSeekable()); 227 | } 228 | 229 | /** 230 | * Method to test seek(). 231 | * 232 | * @return void 233 | * 234 | * @covers Asika\Http\Stream::seek 235 | */ 236 | public function testSeek() 237 | { 238 | $this->createTempFile(); 239 | file_put_contents($this->tmpnam, 'FOO BAR'); 240 | 241 | $resource = fopen($this->tmpnam, Stream::MODE_READ_ONLY_FROM_BEGIN); 242 | $stream = new Stream($resource); 243 | 244 | $this->assertTrue($stream->seek(2)); 245 | $this->assertEquals(2, $stream->tell()); 246 | 247 | $this->assertTrue($stream->seek(2, SEEK_CUR)); 248 | $this->assertEquals(4, $stream->tell()); 249 | 250 | $this->assertTrue($stream->seek(-1, SEEK_END)); 251 | $this->assertEquals(6, $stream->tell()); 252 | } 253 | 254 | /** 255 | * Method to test rewind(). 256 | * 257 | * @return void 258 | * 259 | * @covers Asika\Http\Stream::rewind 260 | */ 261 | public function testRewind() 262 | { 263 | $this->createTempFile(); 264 | file_put_contents($this->tmpnam, 'FOO BAR'); 265 | $resource = fopen($this->tmpnam, Stream::MODE_READ_WRITE_RESET); 266 | 267 | $stream = new Stream($resource); 268 | 269 | $this->assertTrue($stream->seek(2)); 270 | 271 | $stream->rewind(); 272 | 273 | $this->assertEquals(0, $stream->tell()); 274 | } 275 | 276 | /** 277 | * Method to test isWritable(). 278 | * 279 | * @return void 280 | * 281 | * @covers Asika\Http\Stream::isWritable 282 | */ 283 | public function testIsWritable() 284 | { 285 | $stream = new Stream('php://memory', Stream::MODE_READ_ONLY_FROM_BEGIN); 286 | 287 | $this->assertFalse($stream->isWritable()); 288 | } 289 | 290 | /** 291 | * Method to test write(). 292 | * 293 | * @return void 294 | * 295 | * @covers Asika\Http\Stream::write 296 | */ 297 | public function testWrite() 298 | { 299 | $this->createTempFile(); 300 | $resource = fopen($this->tmpnam, Stream::MODE_READ_WRITE_RESET); 301 | 302 | $stream = new Stream($resource); 303 | $stream->write('flower'); 304 | 305 | $this->assertEquals('flower', file_get_contents($this->tmpnam)); 306 | 307 | $stream->write(' bloom'); 308 | 309 | $this->assertEquals('flower bloom', file_get_contents($this->tmpnam)); 310 | 311 | $stream->seek(4); 312 | 313 | $stream->write('test'); 314 | 315 | $this->assertEquals('flowtestloom', file_get_contents($this->tmpnam)); 316 | } 317 | 318 | /** 319 | * Method to test isReadable(). 320 | * 321 | * @return void 322 | * 323 | * @covers Asika\Http\Stream::isReadable 324 | */ 325 | public function testIsReadable() 326 | { 327 | $this->createTempFile(); 328 | 329 | $stream = new Stream($this->tmpnam, Stream::MODE_WRITE_ONLY_RESET); 330 | $this->assertFalse($stream->isReadable()); 331 | } 332 | 333 | /** 334 | * Method to test read(). 335 | * 336 | * @return void 337 | * 338 | * @covers Asika\Http\Stream::read 339 | */ 340 | public function testRead() 341 | { 342 | $this->createTempFile(); 343 | file_put_contents($this->tmpnam, 'FOO BAR'); 344 | $resource = fopen($this->tmpnam, Stream::MODE_READ_ONLY_FROM_BEGIN); 345 | 346 | $stream = new Stream($resource); 347 | 348 | $this->assertEquals('FO', $stream->read(2)); 349 | $this->assertEquals('O B', $stream->read(3)); 350 | 351 | $stream->rewind(); 352 | 353 | $this->assertEquals('FOO', $stream->read(3)); 354 | } 355 | 356 | /** 357 | * Method to test getContents(). 358 | * 359 | * @return void 360 | * 361 | * @covers Asika\Http\Stream::getContents 362 | */ 363 | public function testGetContents() 364 | { 365 | $this->createTempFile(); 366 | file_put_contents($this->tmpnam, 'FOO BAR'); 367 | $resource = fopen($this->tmpnam, Stream::MODE_READ_ONLY_FROM_BEGIN); 368 | 369 | $stream = new Stream($resource); 370 | 371 | $this->assertEquals('FOO BAR', $stream->getContents()); 372 | } 373 | 374 | /** 375 | * Method to test getMetadata(). 376 | * 377 | * @return void 378 | * 379 | * @covers Asika\Http\Stream::getMetadata 380 | */ 381 | public function testGetMetadata() 382 | { 383 | $this->createTempFile(); 384 | $resource = fopen($this->tmpnam, Stream::MODE_READ_WRITE_FROM_BEGIN); 385 | $this->instance->attach($resource); 386 | 387 | $this->assertEquals(stream_get_meta_data($resource), $this->instance->getMetadata()); 388 | 389 | $this->assertEquals(Stream::MODE_READ_WRITE_FROM_BEGIN, $this->instance->getMetadata('mode')); 390 | 391 | fclose($resource); 392 | } 393 | 394 | /** 395 | * createTempFile 396 | * 397 | * @return string 398 | */ 399 | protected function createTempFile() 400 | { 401 | return $this->tmpnam = tempnam(sys_get_temp_dir(), 'http'); 402 | } 403 | } 404 | -------------------------------------------------------------------------------- /test/Stream/StringStreamTest.php: -------------------------------------------------------------------------------- 1 | instance = new StringStream('', Stream::MODE_READ_WRITE_FROM_BEGIN); 46 | } 47 | 48 | /** 49 | * Tears down the fixture, for example, closes a network connection. 50 | * This method is called after a test is executed. 51 | * 52 | * @return void 53 | */ 54 | protected function tearDown() 55 | { 56 | if ($this->tmpnam && is_file($this->tmpnam)) 57 | { 58 | unlink($this->tmpnam); 59 | } 60 | } 61 | 62 | /** 63 | * testConstruct 64 | * 65 | * @return void 66 | */ 67 | public function testConstruct() 68 | { 69 | $stringObject = $this->getMockBuilder('stdClass') 70 | ->setMethods(array('__toString')) 71 | ->getMock(); 72 | 73 | $stringObject->expects($this->once()) 74 | ->method('__toString') 75 | ->willReturn('FOO'); 76 | 77 | $stream = new StringStream($stringObject); 78 | 79 | $this->assertEquals('FOO', TestHelper::getValue($stream, 'resource')); 80 | $this->assertInternalType('object', TestHelper::getValue($stream, 'stream')); 81 | } 82 | 83 | /** 84 | * Method to test __toString(). 85 | * 86 | * @return void 87 | * 88 | * @covers Asika\Http\Stream\StringStream::__toString 89 | */ 90 | public function test__toString() 91 | { 92 | $message = 'foo bar'; 93 | 94 | $this->instance->write($message); 95 | 96 | $this->assertEquals($message, (string) $this->instance); 97 | } 98 | 99 | /** 100 | * Method to test close(). 101 | * 102 | * @return void 103 | * 104 | * @covers Asika\Http\Stream\StringStream::close 105 | */ 106 | public function testClose() 107 | { 108 | $stream = new StringStream; 109 | $stream->write('Foo Bar'); 110 | 111 | $stream->close(); 112 | 113 | $this->assertEmpty($stream->getResource()); 114 | $this->assertAttributeEmpty('resource', $stream); 115 | $this->assertEquals('', (string) $stream); 116 | } 117 | 118 | /** 119 | * Method to test detach(). 120 | * 121 | * @return void 122 | * 123 | * @covers Asika\Http\Stream\StringStream::detach 124 | */ 125 | public function testDetach() 126 | { 127 | $stream = new StringStream('flower'); 128 | 129 | $this->assertEquals('flower', $stream->detach()); 130 | $this->assertAttributeEmpty('resource', $stream); 131 | $this->assertAttributeEmpty('stream', $stream); 132 | } 133 | 134 | /** 135 | * Method to test getSize(). 136 | * 137 | * @return void 138 | * 139 | * @covers Asika\Http\Stream\StringStream::getSize 140 | */ 141 | public function testGetSize() 142 | { 143 | $stream = new StringStream('FOO BAR'); 144 | 145 | $this->assertEquals(7, $stream->getSize()); 146 | } 147 | 148 | /** 149 | * Method to test tell(). 150 | * 151 | * @return void 152 | * 153 | * @covers Asika\Http\Stream\StringStream::tell 154 | */ 155 | public function testTell() 156 | { 157 | $stream = new StringStream('FOO BAR'); 158 | 159 | $stream->seek(2); 160 | 161 | $this->assertEquals(2, $stream->tell()); 162 | 163 | $stream->detach(); 164 | 165 | $this->assertExpectedException(function() use ($stream) 166 | { 167 | $stream->tell(); 168 | }, new \RuntimeException); 169 | } 170 | 171 | /** 172 | * Method to test eof(). 173 | * 174 | * @return void 175 | * 176 | * @covers Asika\Http\Stream\StringStream::eof 177 | */ 178 | public function testEof() 179 | { 180 | $stream = new StringStream('FOO BAR'); 181 | 182 | $stream->seek(2); 183 | $this->assertFalse($stream->eof()); 184 | 185 | $stream->seek(7); 186 | $this->assertTrue($stream->eof()); 187 | } 188 | 189 | /** 190 | * Method to test isSeekable(). 191 | * 192 | * @return void 193 | * 194 | * @covers Asika\Http\Stream\StringStream::isSeekable 195 | */ 196 | public function testIsSeekable() 197 | { 198 | $stream = new StringStream('FOO BAR'); 199 | 200 | $this->assertTrue($stream->isSeekable()); 201 | 202 | $stream->seekable(false); 203 | 204 | $this->assertFalse($stream->isSeekable()); 205 | } 206 | 207 | /** 208 | * Method to test seek(). 209 | * 210 | * @return void 211 | * 212 | * @covers Asika\Http\Stream\StringStream::seek 213 | */ 214 | public function testSeek() 215 | { 216 | $stream = new StringStream('FOO BAR'); 217 | 218 | $this->assertTrue($stream->seek(2)); 219 | $this->assertEquals(2, $stream->tell()); 220 | 221 | $this->assertTrue($stream->seek(2, SEEK_CUR)); 222 | $this->assertEquals(4, $stream->tell()); 223 | 224 | $this->assertTrue($stream->seek(-1, SEEK_END)); 225 | $this->assertEquals(6, $stream->tell()); 226 | } 227 | 228 | /** 229 | * Method to test rewind(). 230 | * 231 | * @return void 232 | * 233 | * @covers Asika\Http\Stream\StringStream::rewind 234 | */ 235 | public function testRewind() 236 | { 237 | $stream = new StringStream('FOO BAR'); 238 | 239 | $this->assertTrue($stream->seek(2)); 240 | 241 | $stream->rewind(); 242 | 243 | $this->assertEquals(0, $stream->tell()); 244 | } 245 | 246 | /** 247 | * Method to test isWritable(). 248 | * 249 | * @return void 250 | * 251 | * @covers Asika\Http\Stream\StringStream::isWritable 252 | */ 253 | public function testIsWritable() 254 | { 255 | $stream = new StringStream('php://memory', Stream::MODE_READ_ONLY_FROM_BEGIN); 256 | 257 | $this->assertFalse($stream->isWritable()); 258 | } 259 | 260 | /** 261 | * Method to test write(). 262 | * 263 | * @return void 264 | * 265 | * @covers Asika\Http\Stream\StringStream::write 266 | */ 267 | public function testWrite() 268 | { 269 | $stream = new StringStream(''); 270 | $stream->write('flower'); 271 | 272 | $this->assertEquals('flower', $stream->getResource()); 273 | 274 | $stream->write(' bloom'); 275 | 276 | $this->assertEquals('flower bloom', $stream->getResource()); 277 | 278 | $stream->seek(4); 279 | 280 | $stream->write('test'); 281 | 282 | $this->assertEquals('flowtestloom', $stream->getResource()); 283 | } 284 | 285 | /** 286 | * Method to test isReadable(). 287 | * 288 | * @return void 289 | * 290 | * @covers Asika\Http\Stream\StringStream::isReadable 291 | */ 292 | public function testIsReadable() 293 | { 294 | $stream = new StringStream; 295 | $this->assertTrue($stream->isReadable()); 296 | } 297 | 298 | /** 299 | * Method to test read(). 300 | * 301 | * @return void 302 | * 303 | * @covers Asika\Http\Stream\StringStream::read 304 | */ 305 | public function testRead() 306 | { 307 | $stream = new StringStream('FOO BAR'); 308 | 309 | $this->assertEquals('FO', $stream->read(2)); 310 | $this->assertEquals('O B', $stream->read(3)); 311 | 312 | $stream->rewind(); 313 | 314 | $this->assertEquals('FOO', $stream->read(3)); 315 | } 316 | 317 | /** 318 | * Method to test getContents(). 319 | * 320 | * @return void 321 | * 322 | * @covers Asika\Http\Stream\StringStream::getContents 323 | */ 324 | public function testGetContents() 325 | { 326 | $stream = new StringStream('FOO BAR'); 327 | 328 | $this->assertEquals('FOO BAR', $stream->getContents()); 329 | 330 | $stream = new StringStream('FOO BAR'); 331 | 332 | $stream->seek(2); 333 | 334 | $this->assertEquals('O BAR', $stream->getContents()); 335 | } 336 | 337 | /** 338 | * Method to test getMetadata(). 339 | * 340 | * @return void 341 | * 342 | * @covers Asika\Http\Stream\StringStream::getMetadata 343 | */ 344 | public function testGetMetadata() 345 | { 346 | $this->assertInternalType('array', $this->instance->getMetadata()); 347 | 348 | $this->assertTrue($this->instance->getMetadata('seekable')); 349 | $this->assertEquals('rb', $this->instance->getMetadata('mode')); 350 | } 351 | } 352 | -------------------------------------------------------------------------------- /test/Stub/StubMessage.php: -------------------------------------------------------------------------------- 1 | $value) 13 | { 14 | if ($key == 'GLOBALS' || $key == 'globals' || $key == 'value') 15 | { 16 | continue; 17 | } 18 | 19 | $globals[$key] = $value; 20 | } 21 | 22 | parse_str(file_get_contents('php://input'), $globals['data']); 23 | 24 | header('Content-Type: text/json'); 25 | echo json_encode($globals); 26 | -------------------------------------------------------------------------------- /test/Transport/AbstractTransportTest.php: -------------------------------------------------------------------------------- 1 | array() 33 | ); 34 | 35 | /** 36 | * Test instance. 37 | * 38 | * @var AbstractTransport 39 | */ 40 | protected $instance; 41 | 42 | /** 43 | * Property downloadFile. 44 | * 45 | * @var string 46 | */ 47 | protected $destFile; 48 | 49 | /** 50 | * setUpBeforeClass 51 | * 52 | * @return void 53 | */ 54 | public static function setUpBeforeClass() 55 | { 56 | if (!defined('ASIKA_HTTP_TEST_URL')) 57 | { 58 | static::markTestSkipped('No ASIKA_HTTP_TEST_URL provided'); 59 | } 60 | } 61 | 62 | /** 63 | * Sets up the fixture, for example, opens a network connection. 64 | * This method is called before a test is executed. 65 | * 66 | * @return void 67 | */ 68 | protected function setUp() 69 | { 70 | if (!$this->instance->isSupported()) 71 | { 72 | $this->markTestSkipped(get_class($this->instance) . ' driver not supported.'); 73 | } 74 | 75 | $this->destFile = __DIR__ . '/downloaded.tmp'; 76 | } 77 | 78 | /** 79 | * createRequest 80 | * 81 | * @param StreamInterface $stream 82 | * 83 | * @return Request 84 | */ 85 | protected function createRequest($stream = null) 86 | { 87 | return new Request($stream ? : new StringStream); 88 | } 89 | 90 | /** 91 | * testRequestGet 92 | * 93 | * @return void 94 | */ 95 | public function testRequestGet() 96 | { 97 | $request = $this->createRequest(); 98 | 99 | $request = $request->withUri(new PsrUri(ASIKA_HTTP_TEST_URL)) 100 | ->withMethod('GET'); 101 | 102 | $response = $this->instance->request($request); 103 | 104 | $this->assertEquals(200, $response->getStatusCode()); 105 | $this->assertJson($response->getBody()->getContents()); 106 | 107 | $request = $this->createRequest(); 108 | 109 | $request = $request->withUri(new PsrUri(ASIKA_HTTP_TEST_URL . '?foo=bar&baz[3]=yoo')) 110 | ->withMethod('GET'); 111 | 112 | $response = $this->instance->request($request); 113 | 114 | $data = json_decode($response->getBody()->getContents(), true); 115 | $this->assertEquals(array('foo' => 'bar', 'baz' => array(3 => 'yoo')), $data['_GET']); 116 | } 117 | 118 | /** 119 | * testBadDomainGet 120 | * 121 | * @return void 122 | * 123 | * @expectedException \RuntimeException 124 | */ 125 | public function testBadDomainGet() 126 | { 127 | $request = $this->createRequest(); 128 | 129 | $request = $request->withUri(new PsrUri('http://not.exists.url/flower.sakura')) 130 | ->withMethod('GET'); 131 | 132 | $this->instance->request($request); 133 | } 134 | 135 | /** 136 | * testBadPathGet 137 | * 138 | * @return void 139 | */ 140 | public function testBadPathGet() 141 | { 142 | $request = $this->createRequest(); 143 | 144 | $request = $request->withUri(new PsrUri(dirname(ASIKA_HTTP_TEST_URL) . '/wrong.php')) 145 | ->withMethod('POST'); 146 | 147 | $request->getBody()->write(UriHelper::buildQuery(array('foo' => 'bar'))); 148 | 149 | $response = $this->instance->request($request); 150 | 151 | $this->assertEquals(404, $response->getStatusCode()); 152 | $this->assertEquals('Not Found', $response->getReasonPhrase()); 153 | } 154 | 155 | /** 156 | * testRequestPost 157 | * 158 | * @return void 159 | */ 160 | public function testRequestPost() 161 | { 162 | $request = $this->createRequest(); 163 | 164 | $request = $request->withUri(new PsrUri(ASIKA_HTTP_TEST_URL)) 165 | ->withMethod('POST'); 166 | 167 | $request->getBody()->write(UriHelper::buildQuery(array('foo' => 'bar'))); 168 | 169 | $response = $this->instance->request($request); 170 | 171 | $data = json_decode($response->getBody()->getContents(), true); 172 | 173 | $this->assertEquals(array('foo' => 'bar'), $data['_POST']); 174 | } 175 | 176 | /** 177 | * testRequestPut 178 | * 179 | * @return void 180 | */ 181 | public function testRequestPut() 182 | { 183 | $request = $this->createRequest(); 184 | 185 | $request = $request->withUri(new PsrUri(ASIKA_HTTP_TEST_URL)) 186 | ->withMethod('PUT'); 187 | 188 | $request->getBody()->write(UriHelper::buildQuery(array('foo' => 'bar'))); 189 | 190 | $response = $this->instance->request($request); 191 | 192 | $data = json_decode($response->getBody()->getContents(), true); 193 | 194 | $this->assertEquals(array('foo' => 'bar'), $data['data']); 195 | $this->assertEquals('PUT', $data['_SERVER']['REQUEST_METHOD']); 196 | } 197 | 198 | /** 199 | * testRequestCredentials 200 | * 201 | * @return void 202 | */ 203 | public function testRequestCredentials() 204 | { 205 | $request = $this->createRequest(); 206 | 207 | $uri = new PsrUri(ASIKA_HTTP_TEST_URL); 208 | $uri = $uri->withUserInfo('username', 'pass1234'); 209 | 210 | $request = $request->withUri($uri) 211 | ->withMethod('GET'); 212 | 213 | $response = $this->instance->request($request); 214 | 215 | $data = json_decode($response->getBody()->getContents(), true); 216 | 217 | $this->assertEquals('username', $data['_SERVER']['PHP_AUTH_USER']); 218 | $this->assertEquals('pass1234', $data['_SERVER']['PHP_AUTH_PW']); 219 | } 220 | 221 | /** 222 | * testRequestPostScalar 223 | * 224 | * @return void 225 | */ 226 | public function testRequestPostScalar() 227 | { 228 | $request = $this->createRequest(); 229 | 230 | $request = $request->withUri(new PsrUri(ASIKA_HTTP_TEST_URL . '?foo=bar')) 231 | ->withMethod('POST'); 232 | 233 | $request->getBody()->write('flower=sakura'); 234 | 235 | $response = $this->instance->request($request); 236 | 237 | $data = json_decode($response->getBody()->getContents(), true); 238 | 239 | $this->assertEquals(array('foo' => 'bar'), $data['_GET']); 240 | $this->assertEquals(array('flower' => 'sakura'), $data['_POST']); 241 | } 242 | 243 | public function testDownload() 244 | { 245 | $this->unlinkDownloaded(); 246 | 247 | $this->assertFileNotExists((string) $this->destFile); 248 | 249 | $request = $this->createRequest(new Stream); 250 | 251 | $src = dirname(ASIKA_HTTP_TEST_URL) . '/download_stub.txt'; 252 | 253 | $request = $request->withUri(new PsrUri($src)) 254 | ->withMethod('GET'); 255 | 256 | $response = $this->instance->download($request, $this->destFile); 257 | 258 | $this->assertEquals('This is test download file.', trim(file_get_contents($this->destFile))); 259 | } 260 | 261 | /** 262 | * unlinkDownloaded 263 | * 264 | * @return void 265 | */ 266 | protected function unlinkDownloaded() 267 | { 268 | if (is_file($this->destFile)) 269 | { 270 | unlink($this->destFile); 271 | } 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /test/Transport/CurlTransportTest.php: -------------------------------------------------------------------------------- 1 | array(CURLOPT_SSL_VERIFYPEER => false) 27 | ); 28 | 29 | /** 30 | * Test instance. 31 | * 32 | * @var CurlTransport 33 | */ 34 | protected $instance; 35 | 36 | /** 37 | * Sets up the fixture, for example, opens a network connection. 38 | * This method is called before a test is executed. 39 | * 40 | * @return void 41 | */ 42 | protected function setUp() 43 | { 44 | $this->instance = new CurlTransport; 45 | 46 | parent::setUp(); 47 | } 48 | 49 | /** 50 | * Tears down the fixture, for example, closes a network connection. 51 | * This method is called after a test is executed. 52 | * 53 | * @return void 54 | */ 55 | protected function tearDown() 56 | { 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/Transport/StreamTransportTest.php: -------------------------------------------------------------------------------- 1 | array(CURLOPT_SSL_VERIFYPEER => false) 28 | ); 29 | 30 | /** 31 | * Test instance. 32 | * 33 | * @var CurlTransport 34 | */ 35 | protected $instance; 36 | 37 | /** 38 | * Sets up the fixture, for example, opens a network connection. 39 | * This method is called before a test is executed. 40 | * 41 | * @return void 42 | */ 43 | protected function setUp() 44 | { 45 | $this->instance = new StreamTransport; 46 | 47 | parent::setUp(); 48 | } 49 | 50 | /** 51 | * Tears down the fixture, for example, closes a network connection. 52 | * This method is called after a test is executed. 53 | * 54 | * @return void 55 | */ 56 | protected function tearDown() 57 | { 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /test/Transport/downloaded.tmp: -------------------------------------------------------------------------------- 1 | This is test download file. 2 | -------------------------------------------------------------------------------- /test/UploadedFileTest.php: -------------------------------------------------------------------------------- 1 | tmpFile) && file_exists($this->tmpFile)) 48 | { 49 | unlink($this->tmpFile); 50 | } 51 | } 52 | 53 | /** 54 | * Method to test getStream(). 55 | * 56 | * @return void 57 | * 58 | * @covers Asika\Http\UploadedFile::getStream 59 | * @TODO Implement testGetStream(). 60 | */ 61 | public function testGetStream() 62 | { 63 | // Remove the following lines when you implement this test. 64 | $this->markTestIncomplete( 65 | 'This test has not been implemented yet.' 66 | ); 67 | } 68 | 69 | /** 70 | * Method to test moveTo(). 71 | * 72 | * @return void 73 | * 74 | * @covers Asika\Http\UploadedFile::moveTo 75 | */ 76 | public function testMoveTo() 77 | { 78 | $stream = new Stream('php://temp', 'wb+'); 79 | $stream->write('Foo bar!'); 80 | $upload = new UploadedFile($stream, 0, UPLOAD_ERR_OK); 81 | 82 | $this->tmpFile = $to = sys_get_temp_dir() . '/http-' . uniqid(); 83 | 84 | $this->assertFalse(is_file($to)); 85 | 86 | $upload->moveTo($to); 87 | 88 | $this->assertTrue(is_file($to)); 89 | 90 | $contents = file_get_contents($to); 91 | 92 | $this->assertEquals($stream->__toString(), $contents); 93 | 94 | // Send string 95 | $uploadFile = sys_get_temp_dir() . '/upload-' . uniqid(); 96 | file_put_contents($uploadFile, 'Foo bar!'); 97 | $upload = new UploadedFile($uploadFile, 0, UPLOAD_ERR_OK); 98 | 99 | $this->tmpFile = $to = sys_get_temp_dir() . '/http-' . uniqid(); 100 | 101 | $this->assertFalse(is_file($to)); 102 | 103 | $upload->moveTo($to); 104 | 105 | $this->assertTrue(is_file($to)); 106 | 107 | $contents = file_get_contents($to); 108 | 109 | $this->assertEquals('Foo bar!', $contents); 110 | 111 | @unlink($uploadFile); 112 | } 113 | 114 | /** 115 | * testMoveInNotCli 116 | * 117 | * @return void 118 | */ 119 | public function testMoveInNotCli() 120 | { 121 | // Send stream 122 | $stream = new Stream('php://temp', 'wb+'); 123 | $stream->write('Foo bar!'); 124 | $upload = new UploadedFile($stream, 0, UPLOAD_ERR_OK); 125 | $upload->setSapi('cgi'); 126 | 127 | $this->tmpFile = $to = sys_get_temp_dir() . '/http-' . uniqid(); 128 | 129 | $this->assertFalse(is_file($to)); 130 | 131 | $upload->moveTo($to); 132 | 133 | $this->assertTrue(is_file($to)); 134 | 135 | $contents = file_get_contents($to); 136 | 137 | $this->assertEquals($stream->__toString(), $contents); 138 | 139 | // Send string 140 | $uploadFile = sys_get_temp_dir() . '/upload-' . uniqid(); 141 | file_put_contents($uploadFile, 'Foo bar!'); 142 | $upload = new UploadedFile($uploadFile, 0, UPLOAD_ERR_OK); 143 | $upload->setSapi('cgi'); 144 | 145 | $this->tmpFile = $to = sys_get_temp_dir() . '/http-' . uniqid(); 146 | 147 | $this->assertFalse(is_file($to)); 148 | 149 | $this->assertExpectedException(function() use ($upload, $to) 150 | { 151 | $upload->moveTo($to); 152 | }, 'RuntimeException', 'Error moving uploaded file'); 153 | } 154 | 155 | /** 156 | * Method to test getSize(). 157 | * 158 | * @return void 159 | * 160 | * @covers Asika\Http\UploadedFile::getSize 161 | * @TODO Implement testGetSize(). 162 | */ 163 | public function testGetSize() 164 | { 165 | // Remove the following lines when you implement this test. 166 | $this->markTestIncomplete( 167 | 'This test has not been implemented yet.' 168 | ); 169 | } 170 | 171 | /** 172 | * Method to test getError(). 173 | * 174 | * @return void 175 | * 176 | * @covers Asika\Http\UploadedFile::getError 177 | * @TODO Implement testGetError(). 178 | */ 179 | public function testGetError() 180 | { 181 | // Remove the following lines when you implement this test. 182 | $this->markTestIncomplete( 183 | 'This test has not been implemented yet.' 184 | ); 185 | } 186 | 187 | /** 188 | * Method to test getClientFilename(). 189 | * 190 | * @return void 191 | * 192 | * @covers Asika\Http\UploadedFile::getClientFilename 193 | * @TODO Implement testGetClientFilename(). 194 | */ 195 | public function testGetClientFilename() 196 | { 197 | // Remove the following lines when you implement this test. 198 | $this->markTestIncomplete( 199 | 'This test has not been implemented yet.' 200 | ); 201 | } 202 | 203 | /** 204 | * Method to test getClientMediaType(). 205 | * 206 | * @return void 207 | * 208 | * @covers Asika\Http\UploadedFile::getClientMediaType 209 | * @TODO Implement testGetClientMediaType(). 210 | */ 211 | public function testGetClientMediaType() 212 | { 213 | // Remove the following lines when you implement this test. 214 | $this->markTestIncomplete( 215 | 'This test has not been implemented yet.' 216 | ); 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /test/Uri/PsrUriTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('https', $uri->getScheme()); 30 | $this->assertEquals('user:pass', $uri->getUserInfo()); 31 | $this->assertEquals('local.example.com', $uri->getHost()); 32 | $this->assertEquals(3001, $uri->getPort()); 33 | $this->assertEquals('user:pass@local.example.com:3001', $uri->getAuthority()); 34 | $this->assertEquals('/foo', $uri->getPath()); 35 | $this->assertEquals('bar=baz', $uri->getQuery()); 36 | $this->assertEquals('quz', $uri->getFragment()); 37 | } 38 | 39 | /** 40 | * testToString 41 | * 42 | * @return void 43 | */ 44 | public function testToString() 45 | { 46 | $url = 'https://user:pass@local.example.com:3001/foo?bar=baz#quz'; 47 | $uri = new PsrUri($url); 48 | $this->assertEquals($url, (string) $uri); 49 | } 50 | 51 | /** 52 | * testWithScheme 53 | * 54 | * @return void 55 | */ 56 | public function testWithScheme() 57 | { 58 | $uri = new PsrUri('https://user:pass@local.example.com:3001/foo?bar=baz#quz'); 59 | $new = $uri->withScheme('http'); 60 | $this->assertNotSame($uri, $new); 61 | $this->assertEquals('http', $new->getScheme()); 62 | $this->assertEquals('http://user:pass@local.example.com:3001/foo?bar=baz#quz', (string) $new); 63 | 64 | $new = $uri->withScheme('https://'); 65 | $this->assertEquals('https', $new->getScheme()); 66 | } 67 | 68 | /** 69 | * testWithUserInfo 70 | * 71 | * @return void 72 | */ 73 | public function testWithUserInfo() 74 | { 75 | // User 76 | $uri = new PsrUri('https://user:pass@local.example.com:3001/foo?bar=baz#quz'); 77 | $new = $uri->withUserInfo('flower'); 78 | $this->assertNotSame($uri, $new); 79 | $this->assertEquals('flower', $new->getUserInfo()); 80 | $this->assertEquals('https://flower@local.example.com:3001/foo?bar=baz#quz', (string) $new); 81 | 82 | // User & Password 83 | $uri = new PsrUri('https://user:pass@local.example.com:3001/foo?bar=baz#quz'); 84 | $new = $uri->withUserInfo('flower', 'sakura'); 85 | $this->assertNotSame($uri, $new); 86 | $this->assertEquals('flower:sakura', $new->getUserInfo()); 87 | $this->assertEquals('https://flower:sakura@local.example.com:3001/foo?bar=baz#quz', (string) $new); 88 | } 89 | 90 | /** 91 | * testWithHost 92 | * 93 | * @return void 94 | */ 95 | public function testWithHost() 96 | { 97 | $uri = new PsrUri('https://user:pass@local.example.com:3001/foo?bar=baz#quz'); 98 | $new = $uri->withHost('windwalker.io'); 99 | $this->assertNotSame($uri, $new); 100 | $this->assertEquals('windwalker.io', $new->getHost()); 101 | $this->assertEquals('https://user:pass@windwalker.io:3001/foo?bar=baz#quz', (string) $new); 102 | } 103 | 104 | /** 105 | * testWithPort 106 | * 107 | * @return void 108 | */ 109 | public function testWithPort() 110 | { 111 | $uri = new PsrUri('https://user:pass@local.example.com:3001/foo?bar=baz#quz'); 112 | $new = $uri->withPort(3000); 113 | $this->assertNotSame($uri, $new); 114 | $this->assertEquals(3000, $new->getPort()); 115 | $this->assertEquals( 116 | sprintf('https://user:pass@local.example.com:%d/foo?bar=baz#quz', 3000), 117 | (string) $new 118 | ); 119 | } 120 | 121 | /** 122 | * testWithPath 123 | * 124 | * @return void 125 | */ 126 | public function testWithPath() 127 | { 128 | $uri = new PsrUri('https://user:pass@local.example.com:3001/foo?bar=baz#quz'); 129 | $new = $uri->withPath('/bar/baz'); 130 | $this->assertNotSame($uri, $new); 131 | $this->assertEquals('/bar/baz', $new->getPath()); 132 | $this->assertEquals('https://user:pass@local.example.com:3001/bar/baz?bar=baz#quz', (string) $new); 133 | 134 | $uri = new PsrUri('http://example.com'); 135 | $new = $uri->withPath('foo/bar'); 136 | $this->assertEquals('foo/bar', $new->getPath()); 137 | 138 | $uri = new PsrUri('http://example.com'); 139 | $new = $uri->withPath('foo/bar'); 140 | $this->assertEquals('http://example.com/foo/bar', $new->__toString()); 141 | 142 | // Encoded 143 | $uri = $uri->withPath('/foo^bar'); 144 | $expected = '/foo%5Ebar'; 145 | $this->assertEquals($expected, $uri->getPath()); 146 | 147 | // Not double encoded 148 | $uri = $uri->withPath('/foo%5Ebar'); 149 | $expected = '/foo%5Ebar'; 150 | $this->assertEquals($expected, $uri->getPath()); 151 | } 152 | 153 | /** 154 | * testWithQuery 155 | * 156 | * @return void 157 | */ 158 | public function testWithQuery() 159 | { 160 | $uri = new PsrUri('https://user:pass@local.example.com:3001/foo?bar=baz#quz'); 161 | $new = $uri->withQuery('baz=bat'); 162 | $this->assertNotSame($uri, $new); 163 | $this->assertEquals('baz=bat', $new->getQuery()); 164 | $this->assertEquals('https://user:pass@local.example.com:3001/foo?baz=bat#quz', (string) $new); 165 | 166 | // Strip query symbol 167 | $uri = new PsrUri('http://example.com'); 168 | $new = $uri->withQuery('?foo=bar'); 169 | $this->assertEquals('foo=bar', $new->getQuery()); 170 | } 171 | 172 | /** 173 | * testWithFragment 174 | * 175 | * @return void 176 | */ 177 | public function testWithFragment() 178 | { 179 | $uri = new PsrUri('https://user:pass@local.example.com:3001/foo?bar=baz#quz'); 180 | $new = $uri->withFragment('qat'); 181 | $this->assertNotSame($uri, $new); 182 | $this->assertEquals('qat', $new->getFragment()); 183 | $this->assertEquals('https://user:pass@local.example.com:3001/foo?bar=baz#qat', (string) $new); 184 | 185 | $uri = new PsrUri('http://example.com'); 186 | $new = $uri->withFragment('#/foo/bar'); 187 | $this->assertEquals('/foo/bar', $new->getFragment()); 188 | } 189 | 190 | /** 191 | * authorityProvider 192 | * 193 | * @return array 194 | */ 195 | public function authorityProvider() 196 | { 197 | return array( 198 | 'host-only' => array('http://foo.com/bar', 'foo.com'), 199 | 'host-port' => array('http://foo.com:3000/bar', 'foo.com:3000'), 200 | 'user-host' => array('http://me@foo.com/bar', 'me@foo.com'), 201 | 'user-host-port' => array('http://me@foo.com:3000/bar', 'me@foo.com:3000'), 202 | ); 203 | } 204 | 205 | /** 206 | * testAuthority 207 | * 208 | * @dataProvider authorityProvider 209 | * 210 | * @param string $url 211 | * @param string $expected 212 | */ 213 | public function testAuthority($url, $expected) 214 | { 215 | $uri = new PsrUri($url); 216 | $this->assertEquals($expected, $uri->getAuthority()); 217 | } 218 | 219 | public function queryStringsForEncoding() 220 | { 221 | return array( 222 | 'key-only' => array('k^ey', 'k%5Eey'), 223 | 'key-value' => array('k^ey=valu`', 'k%5Eey=valu%60'), 224 | 'array-key-only' => array('key[]', 'key%5B%5D'), 225 | 'array-key-value' => array('key[]=valu`', 'key%5B%5D=valu%60'), 226 | 'complex' => array('k^ey&key[]=valu`&f<>=`bar', 'k%5Eey&key%5B%5D=valu%60&f%3C%3E=%60bar'), 227 | ); 228 | } 229 | 230 | /** 231 | * @dataProvider queryStringsForEncoding 232 | * 233 | * @param string $query 234 | * @param string $expected 235 | */ 236 | public function testQueryEncoded($query, $expected) 237 | { 238 | $uri = new PsrUri; 239 | $uri = $uri->withQuery($query); 240 | $this->assertEquals($expected, $uri->getQuery()); 241 | 242 | // No double encoded 243 | $uri = $uri->withQuery($expected); 244 | $this->assertEquals($expected, $uri->getQuery()); 245 | } 246 | 247 | /** 248 | * testFragmentEncoded 249 | * 250 | * @return void 251 | */ 252 | public function testFragmentEncoded() 253 | { 254 | $uri = new PsrUri; 255 | $uri = $uri->withFragment('/p^th?key^=`bar#b@z'); 256 | $expected = '/p%5Eth?key%5E=%60bar%23b@z'; 257 | $this->assertEquals($expected, $uri->getFragment()); 258 | 259 | // No double encoded 260 | $expected = '/p%5Eth?key%5E=%60bar%23b@z'; 261 | $uri = $uri->withFragment($expected); 262 | $this->assertEquals($expected, $uri->getFragment()); 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /test/Uri/UriHelperTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($expected, $actual, 'Line: ' . __LINE__ . ' Results should be equal'); 34 | 35 | // Test all parts of query 36 | $url = 'https://john:doe@www.google.com:80/folder/page.html#id?var=kay&var2=key&true'; 37 | $expected = parse_url($url); 38 | $actual = UriHelper::parseUrl($url); 39 | $this->assertEquals($expected, $actual, 'Line: ' . __LINE__ . ' Results should be equal'); 40 | 41 | // Test special characters in URL 42 | $url = 'http://Windwalker.org/mytestpath/È'; 43 | $expected = parse_url($url); 44 | 45 | // Fix up path for UTF-8 characters 46 | $expected['path'] = '/mytestpath/È'; 47 | $actual = UriHelper::parseUrl($url); 48 | $this->assertEquals($expected, $actual, 'Line: ' . __LINE__ . ' Results should be equal'); 49 | 50 | // Test special characters in URL 51 | $url = 'http://mydomain.com/!*\'();:@&=+$,/?%#[]" \\'; 52 | $expected = parse_url($url); 53 | $actual = UriHelper::parseUrl($url); 54 | $this->assertEquals($expected, $actual, 'Line: ' . __LINE__ . ' Results should be equal'); 55 | 56 | // Test url encoding in URL 57 | $url = 'http://mydomain.com/%21%2A%27%28%29%3B%3A%40%26%3D%24%2C%2F%3F%25%23%5B%22%20%5C'; 58 | $expected = parse_url($url); 59 | $actual = UriHelper::parseUrl($url); 60 | $this->assertEquals($expected, $actual, 'Line: ' . __LINE__ . ' Results should be equal'); 61 | 62 | // Test a mix of the above 63 | $url = 'http://john:doe@mydomain.com:80/%È21%25È3*%('; 64 | $expected = parse_url($url); 65 | 66 | // Fix up path for UTF-8 characters 67 | $expected['path'] = '/%È21%25È3*%('; 68 | $actual = UriHelper::parseUrl($url); 69 | $this->assertEquals($expected, $actual, 'Line: ' . __LINE__ . ' Results should be equal'); 70 | 71 | // Test invalild URL 72 | $url = 'http:///mydomain.com'; 73 | $expected = parse_url($url); 74 | $actual = UriHelper::parseUrl($url); 75 | $this->assertEquals($expected, $actual, 'Line: ' . __LINE__ . ' Results should be equal'); 76 | } 77 | } 78 | --------------------------------------------------------------------------------