• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

bin/H03-May-2022-

examples/H03-May-2022-304178

lib/H03-May-2022-3,5291,628

tests/H03-May-2022-2,5231,912

.gitignoreH A D03-Oct-202089 97

.php_cs.distH A D03-Oct-2020194 1210

.travis.ymlH A D03-Oct-20201.4 KiB5245

CHANGELOG.mdH A D03-Oct-202010.4 KiB339236

LICENSEH A D03-Oct-20201.5 KiB2823

README.mdH A D03-Oct-202015.9 KiB748595

composer.jsonH A D03-Oct-20201.7 KiB6564

phpstan.neonH A D03-Oct-202023 32

README.md

1sabre/http
2==========
3
4This library provides a toolkit to make working with the [HTTP protocol](https://tools.ietf.org/html/rfc2616) easier.
5
6Most PHP scripts run within a HTTP request but accessing information about the
7HTTP request is cumbersome at least.
8
9There's bad practices, inconsistencies and confusion. This library is
10effectively a wrapper around the following PHP constructs:
11
12For Input:
13
14* `$_GET`,
15* `$_POST`,
16* `$_SERVER`,
17* `php://input` or `$HTTP_RAW_POST_DATA`.
18
19For output:
20
21* `php://output` or `echo`,
22* `header()`.
23
24What this library provides, is a `Request` object, and a `Response` object.
25
26The objects are extendable and easily mockable.
27
28Build status
29------------
30
31| branch | status |
32| ------ | ------ |
33| master | [![Build Status](https://travis-ci.org/sabre-io/http.svg?branch=master)](https://travis-ci.org/sabre-io/http) |
34| 4.2    | [![Build Status](https://travis-ci.org/sabre-io/http.svg?branch=4.2)](https://travis-ci.org/sabre-io/http) |
35| 3.0    | [![Build Status](https://travis-ci.org/sabre-io/http.svg?branch=3.0)](https://travis-ci.org/sabre-io/http) |
36
37Installation
38------------
39
40Make sure you have [composer][1] installed. In your project directory, create,
41or edit a `composer.json` file, and make sure it contains something like this:
42
43```json
44{
45    "require" : {
46        "sabre/http" : "~5.0.0"
47    }
48}
49```
50
51After that, just hit `composer install` and you should be rolling.
52
53Quick history
54-------------
55
56This library came to existence in 2009, as a part of the [`sabre/dav`][2]
57project, which uses it heavily.
58
59It got split off into a separate library to make it easier to manage
60releases and hopefully giving it use outside of the scope of just `sabre/dav`.
61
62Although completely independently developed, this library has a LOT of
63overlap with [Symfony's `HttpFoundation`][3].
64
65Said library does a lot more stuff and is significantly more popular,
66so if you are looking for something to fulfill this particular requirement,
67I'd recommend also considering [`HttpFoundation`][3].
68
69
70Getting started
71---------------
72
73First and foremost, this library wraps the superglobals. The easiest way to
74instantiate a request object is as follows:
75
76```php
77use Sabre\HTTP;
78
79include 'vendor/autoload.php';
80
81$request = HTTP\Sapi::getRequest();
82```
83
84This line should only happen once in your entire application. Everywhere else
85you should pass this request object around using dependency injection.
86
87You should always typehint on it's interface:
88
89```php
90function handleRequest(HTTP\RequestInterface $request) {
91
92    // Do something with this request :)
93
94}
95```
96
97A response object you can just create as such:
98
99```php
100use Sabre\HTTP;
101
102include 'vendor/autoload.php';
103
104$response = new HTTP\Response();
105$response->setStatus(201); // created !
106$response->setHeader('X-Foo', 'bar');
107$response->setBody(
108    'success!'
109);
110
111```
112
113After you fully constructed your response, you must call:
114
115```php
116HTTP\Sapi::sendResponse($response);
117```
118
119This line should generally also appear once in your application (at the very
120end).
121
122Decorators
123----------
124
125It may be useful to extend the `Request` and `Response` objects in your
126application, if you for example would like them to carry a bit more
127information about the current request.
128
129For instance, you may want to add an `isLoggedIn` method to the Request
130object.
131
132Simply extending Request and Response may pose some problems:
133
1341. You may want to extend the objects with new behaviors differently, in
135   different subsystems of your application,
1362. The `Sapi::getRequest` factory always returns a instance of
137   `Request` so you would have to override the factory method as well,
1383. By controlling the instantation and depend on specific `Request` and
139   `Response` instances in your library or application, you make it harder to
140   work with other applications which also use `sabre/http`.
141
142In short: it would be bad design. Instead, it's recommended to use the
143[decorator pattern][6] to add new behavior where you need it. `sabre/http`
144provides helper classes to quickly do this.
145
146Example:
147
148```php
149use Sabre\HTTP;
150
151class MyRequest extends HTTP\RequestDecorator {
152
153    function isLoggedIn() {
154
155        return true;
156
157    }
158
159}
160```
161
162Our application assumes that the true `Request` object was instantiated
163somewhere else, by some other subsystem. This could simply be a call like
164`$request = Sapi::getRequest()` at the top of your application,
165but could also be somewhere in a unittest.
166
167All we know in the current subsystem, is that we received a `$request` and
168that it implements `Sabre\HTTP\RequestInterface`. To decorate this object,
169all we need to do is:
170
171```php
172$request = new MyRequest($request);
173```
174
175And that's it, we now have an `isLoggedIn` method, without having to mess
176with the core instances.
177
178
179Client
180------
181
182This package also contains a simple wrapper around [cURL][4], which will allow
183you to write simple clients, using the `Request` and `Response` objects you're
184already familiar with.
185
186It's by no means a replacement for something like [Guzzle][7], but it provides
187a simple and lightweight API for making the occasional API call.
188
189### Usage
190
191```php
192use Sabre\HTTP;
193
194$request = new HTTP\Request('GET', 'http://example.org/');
195$request->setHeader('X-Foo', 'Bar');
196
197$client = new HTTP\Client();
198$response = $client->send($request);
199
200echo $response->getBodyAsString();
201```
202
203The client emits 3 event using [`sabre/event`][5]. `beforeRequest`,
204`afterRequest` and `error`.
205
206```php
207$client = new HTTP\Client();
208$client->on('beforeRequest', function($request) {
209
210    // You could use beforeRequest to for example inject a few extra headers.
211    // into the Request object.
212
213});
214
215$client->on('afterRequest', function($request, $response) {
216
217    // The afterRequest event could be a good time to do some logging, or
218    // do some rewriting in the response.
219
220});
221
222$client->on('error', function($request, $response, &$retry, $retryCount) {
223
224    // The error event is triggered for every response with a HTTP code higher
225    // than 399.
226
227});
228
229$client->on('error:401', function($request, $response, &$retry, $retryCount) {
230
231    // You can also listen for specific error codes. This example shows how
232    // to inject HTTP authentication headers if a 401 was returned.
233
234    if ($retryCount > 1) {
235        // We're only going to retry exactly once.
236    }
237
238    $request->setHeader('Authorization', 'Basic xxxxxxxxxx');
239    $retry = true;
240
241});
242```
243
244### Asynchronous requests
245
246The `Client` also supports doing asynchronous requests. This is especially handy
247if you need to perform a number of requests, that are allowed to be executed
248in parallel.
249
250The underlying system for this is simply [cURL's multi request handler][8],
251but this provides a much nicer API to handle this.
252
253Sample usage:
254
255```php
256
257use Sabre\HTTP;
258
259$request = new Request('GET', 'http://localhost/');
260$client = new Client();
261
262// Executing 1000 requests
263for ($i = 0; $i < 1000; $i++) {
264    $client->sendAsync(
265        $request,
266        function(ResponseInterface $response) {
267            // Success handler
268        },
269        function($error) {
270            // Error handler
271        }
272    );
273}
274
275// Wait for all requests to get a result.
276$client->wait();
277
278```
279
280Check out `examples/asyncclient.php` for more information.
281
282Writing a reverse proxy
283-----------------------
284
285With all these tools combined, it becomes very easy to write a simple reverse
286http proxy.
287
288```php
289use
290    Sabre\HTTP\Sapi,
291    Sabre\HTTP\Client;
292
293// The url we're proxying to.
294$remoteUrl = 'http://example.org/';
295
296// The url we're proxying from. Please note that this must be a relative url,
297// and basically acts as the base url.
298//
299// If youre $remoteUrl doesn't end with a slash, this one probably shouldn't
300// either.
301$myBaseUrl = '/reverseproxy.php';
302// $myBaseUrl = '/~evert/sabre/http/examples/reverseproxy.php/';
303
304$request = Sapi::getRequest();
305$request->setBaseUrl($myBaseUrl);
306
307$subRequest = clone $request;
308
309// Removing the Host header.
310$subRequest->removeHeader('Host');
311
312// Rewriting the url.
313$subRequest->setUrl($remoteUrl . $request->getPath());
314
315$client = new Client();
316
317// Sends the HTTP request to the server
318$response = $client->send($subRequest);
319
320// Sends the response back to the client that connected to the proxy.
321Sapi::sendResponse($response);
322```
323
324The Request and Response API's
325------------------------------
326
327### Request
328
329```php
330
331/**
332 * Creates the request object
333 *
334 * @param string $method
335 * @param string $url
336 * @param array $headers
337 * @param resource $body
338 */
339public function __construct($method = null, $url = null, array $headers = null, $body = null);
340
341/**
342 * Returns the current HTTP method
343 *
344 * @return string
345 */
346function getMethod();
347
348/**
349 * Sets the HTTP method
350 *
351 * @param string $method
352 * @return void
353 */
354function setMethod($method);
355
356/**
357 * Returns the request url.
358 *
359 * @return string
360 */
361function getUrl();
362
363/**
364 * Sets the request url.
365 *
366 * @param string $url
367 * @return void
368 */
369function setUrl($url);
370
371/**
372 * Returns the absolute url.
373 *
374 * @return string
375 */
376function getAbsoluteUrl();
377
378/**
379 * Sets the absolute url.
380 *
381 * @param string $url
382 * @return void
383 */
384function setAbsoluteUrl($url);
385
386/**
387 * Returns the current base url.
388 *
389 * @return string
390 */
391function getBaseUrl();
392
393/**
394 * Sets a base url.
395 *
396 * This url is used for relative path calculations.
397 *
398 * The base url should default to /
399 *
400 * @param string $url
401 * @return void
402 */
403function setBaseUrl($url);
404
405/**
406 * Returns the relative path.
407 *
408 * This is being calculated using the base url. This path will not start
409 * with a slash, so it will always return something like
410 * 'example/path.html'.
411 *
412 * If the full path is equal to the base url, this method will return an
413 * empty string.
414 *
415 * This method will also urldecode the path, and if the url was incoded as
416 * ISO-8859-1, it will convert it to UTF-8.
417 *
418 * If the path is outside of the base url, a LogicException will be thrown.
419 *
420 * @return string
421 */
422function getPath();
423
424/**
425 * Returns the list of query parameters.
426 *
427 * This is equivalent to PHP's $_GET superglobal.
428 *
429 * @return array
430 */
431function getQueryParameters();
432
433/**
434 * Returns the POST data.
435 *
436 * This is equivalent to PHP's $_POST superglobal.
437 *
438 * @return array
439 */
440function getPostData();
441
442/**
443 * Sets the post data.
444 *
445 * This is equivalent to PHP's $_POST superglobal.
446 *
447 * This would not have been needed, if POST data was accessible as
448 * php://input, but unfortunately we need to special case it.
449 *
450 * @param array $postData
451 * @return void
452 */
453function setPostData(array $postData);
454
455/**
456 * Returns an item from the _SERVER array.
457 *
458 * If the value does not exist in the array, null is returned.
459 *
460 * @param string $valueName
461 * @return string|null
462 */
463function getRawServerValue($valueName);
464
465/**
466 * Sets the _SERVER array.
467 *
468 * @param array $data
469 * @return void
470 */
471function setRawServerData(array $data);
472
473/**
474 * Returns the body as a readable stream resource.
475 *
476 * Note that the stream may not be rewindable, and therefore may only be
477 * read once.
478 *
479 * @return resource
480 */
481function getBodyAsStream();
482
483/**
484 * Returns the body as a string.
485 *
486 * Note that because the underlying data may be based on a stream, this
487 * method could only work correctly the first time.
488 *
489 * @return string
490 */
491function getBodyAsString();
492
493/**
494 * Returns the message body, as it's internal representation.
495 *
496 * This could be either a string or a stream.
497 *
498 * @return resource|string
499 */
500function getBody();
501
502/**
503 * Updates the body resource with a new stream.
504 *
505 * @param resource $body
506 * @return void
507 */
508function setBody($body);
509
510/**
511 * Returns all the HTTP headers as an array.
512 *
513 * @return array
514 */
515function getHeaders();
516
517/**
518 * Returns a specific HTTP header, based on it's name.
519 *
520 * The name must be treated as case-insensitive.
521 *
522 * If the header does not exist, this method must return null.
523 *
524 * @param string $name
525 * @return string|null
526 */
527function getHeader($name);
528
529/**
530 * Updates a HTTP header.
531 *
532 * The case-sensitity of the name value must be retained as-is.
533 *
534 * @param string $name
535 * @param string $value
536 * @return void
537 */
538function setHeader($name, $value);
539
540/**
541 * Resets HTTP headers
542 *
543 * This method overwrites all existing HTTP headers
544 *
545 * @param array $headers
546 * @return void
547 */
548function setHeaders(array $headers);
549
550/**
551 * Adds a new set of HTTP headers.
552 *
553 * Any header specified in the array that already exists will be
554 * overwritten, but any other existing headers will be retained.
555 *
556 * @param array $headers
557 * @return void
558 */
559function addHeaders(array $headers);
560
561/**
562 * Removes a HTTP header.
563 *
564 * The specified header name must be treated as case-insenstive.
565 * This method should return true if the header was successfully deleted,
566 * and false if the header did not exist.
567 *
568 * @return bool
569 */
570function removeHeader($name);
571
572/**
573 * Sets the HTTP version.
574 *
575 * Should be 1.0, 1.1 or 2.0.
576 *
577 * @param string $version
578 * @return void
579 */
580function setHttpVersion($version);
581
582/**
583 * Returns the HTTP version.
584 *
585 * @return string
586 */
587function getHttpVersion();
588```
589
590### Response
591
592```php
593/**
594 * Returns the current HTTP status.
595 *
596 * This is the status-code as well as the human readable string.
597 *
598 * @return string
599 */
600function getStatus();
601
602/**
603 * Sets the HTTP status code.
604 *
605 * This can be either the full HTTP status code with human readable string,
606 * for example: "403 I can't let you do that, Dave".
607 *
608 * Or just the code, in which case the appropriate default message will be
609 * added.
610 *
611 * @param string|int $status
612 * @throws \InvalidArgumentExeption
613 * @return void
614 */
615function setStatus($status);
616
617/**
618 * Returns the body as a readable stream resource.
619 *
620 * Note that the stream may not be rewindable, and therefore may only be
621 * read once.
622 *
623 * @return resource
624 */
625function getBodyAsStream();
626
627/**
628 * Returns the body as a string.
629 *
630 * Note that because the underlying data may be based on a stream, this
631 * method could only work correctly the first time.
632 *
633 * @return string
634 */
635function getBodyAsString();
636
637/**
638 * Returns the message body, as it's internal representation.
639 *
640 * This could be either a string or a stream.
641 *
642 * @return resource|string
643 */
644function getBody();
645
646
647/**
648 * Updates the body resource with a new stream.
649 *
650 * @param resource $body
651 * @return void
652 */
653function setBody($body);
654
655/**
656 * Returns all the HTTP headers as an array.
657 *
658 * @return array
659 */
660function getHeaders();
661
662/**
663 * Returns a specific HTTP header, based on it's name.
664 *
665 * The name must be treated as case-insensitive.
666 *
667 * If the header does not exist, this method must return null.
668 *
669 * @param string $name
670 * @return string|null
671 */
672function getHeader($name);
673
674/**
675 * Updates a HTTP header.
676 *
677 * The case-sensitity of the name value must be retained as-is.
678 *
679 * @param string $name
680 * @param string $value
681 * @return void
682 */
683function setHeader($name, $value);
684
685/**
686 * Resets HTTP headers
687 *
688 * This method overwrites all existing HTTP headers
689 *
690 * @param array $headers
691 * @return void
692 */
693function setHeaders(array $headers);
694
695/**
696 * Adds a new set of HTTP headers.
697 *
698 * Any header specified in the array that already exists will be
699 * overwritten, but any other existing headers will be retained.
700 *
701 * @param array $headers
702 * @return void
703 */
704function addHeaders(array $headers);
705
706/**
707 * Removes a HTTP header.
708 *
709 * The specified header name must be treated as case-insenstive.
710 * This method should return true if the header was successfully deleted,
711 * and false if the header did not exist.
712 *
713 * @return bool
714 */
715function removeHeader($name);
716
717/**
718 * Sets the HTTP version.
719 *
720 * Should be 1.0, 1.1 or 2.0.
721 *
722 * @param string $version
723 * @return void
724 */
725function setHttpVersion($version);
726
727/**
728 * Returns the HTTP version.
729 *
730 * @return string
731 */
732function getHttpVersion();
733```
734
735Made at fruux
736-------------
737
738This library is being developed by [fruux](https://fruux.com/). Drop us a line for commercial services or enterprise support.
739
740[1]: http://getcomposer.org/
741[2]: http://sabre.io/
742[3]: https://github.com/symfony/HttpFoundation
743[4]: http://php.net/curl
744[5]: https://github.com/fruux/sabre-event
745[6]: http://en.wikipedia.org/wiki/Decorator_pattern
746[7]: http://guzzlephp.org/
747[8]: http://php.net/curl_multi_init
748