• Stars
    star
    695
  • Rank 62,531 (Top 2 %)
  • Language
    PHP
  • License
    MIT License
  • Created about 12 years ago
  • Updated 8 days ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

An advanced async HTTP client library for PHP, enabling efficient, non-blocking, and concurrent requests and responses.

amphp/http-client

AMPHP is a collection of event-driven libraries for PHP designed with fibers and concurrency in mind. This package provides an asynchronous HTTP client for PHP based on Revolt. Its API simplifies standards-compliant HTTP resource traversal and RESTful web service consumption without obscuring the underlying protocol. The library manually implements HTTP over TCP sockets; as such it has no dependency on ext/curl.

Features

Installation

This package can be installed as a Composer dependency.

composer require amphp/http-client

Additionally, you might want to install the nghttp2 library to take advantage of FFI to speed up and reduce the memory usage.

Usage

The main interaction point with this library is the HttpClient class. HttpClient instances can be built using HttpClientBuilder without knowing about the existing implementations.

HttpClientBuilder allows to register two kinds of interceptors, which allows customizing the HttpClient behavior in a composable fashion.

In its simplest form, the HTTP client takes a request with a URL as string and interprets that as a GET request to that resource without any custom headers. Standard headers like Accept, Connection or Host will automatically be added if not present.

use Amp\Http\Client\HttpClientBuilder;

$client = HttpClientBuilder::buildDefault();

$response = $client->request(new Request("https://httpbin.org/get"));

var_dump($response->getStatus());
var_dump($response->getHeaders());
var_dump($response->getBody()->buffer());

Request

The HttpClient requires a Request being passed as first argument to request(). The Request class can be used to specify further specifics of the request such as setting headers or changing the request method.

Note Request objects are mutable (instead of immutable as in amphp/artax / PSR-7).

Cloning Request objects will result in a deep clone, but doing so is usually only required if requests are retried or cloned for sub-requests.

Request URI

The constructor requires an absolute request URI. Request::setUri(string $uri) allows changing the request URI.

$request = new Request("https://httpbin.org/post", "POST");
$request->setBody("foobar");
$request->setUri("https://google.com/");

Request::getUri() exposes the request URI of the given Request object.

Request Method

The constructor accepts an optional request method, it defaults to GET. Request::setMethod(string $method) allows changing the request method.

$request = new Request("https://httpbin.org/post", "POST");
$request->setBody("foobar");
$request->setMethod("PUT");

Request::getMethod() exposes the request method of the given Request object.

Request Headers

Request::setHeader(string $field, string $value) allows changing the request headers. It will remove any previous values for that field. Request::addHeader(string $field, string $value) allows adding an additional header line without removing existing lines.

Request::setHeaders(array $headers) allows adding multiple headers at once with the array keys being the field names and the values being the header values. The header values can also be arrays of strings to set multiple header lines.

Request::hasHeader(string $field) checks whether at least one header line with the given name exists.

Request::getHeader(string $field) returns the first header line with the given name or null if no such header exists.

Request::getHeaderArray(string $field) returns an array of header lines with the given name. An empty array is returned if no header with the given name exists.

Request::getHeaders() returns an associative array with the keys being the header names and the values being arrays of header lines.

$request = new Request("https://httpbin.org/post", "POST");
$request->setHeader("X-Foobar", "Hello World");
$request->setBody("foobar");

Request Bodies

Request::setBody($body) allows changing the request body. Accepted types are string, null, and RequestBody. string and null are automatically converted to an instance of RequestBody.

Note RequestBody is basically a factory for request bodies. We cannot simply accept streams here, because a request body might have to be sent again on a redirect / retry. Additionally, RequestBody allows the body to set headers, which can be used to automatically set headers such as Content-Type: application/json for a JsonBody. Note that headers set via RequestBody::getHeaders() are only applied if the Request doesn't have such a header. This allows overriding the default body header in a request.

$request = new Request("https://httpbin.org/post", "POST");
$request->setBody("foobar");

Request::getBody() exposes the request body of the given Request object and will always return a RequestBody.

Response

HttpClient::request() returns a Response as soon as the response headers are successfully received.

Note Response objects are mutable (instead of immutable as in Artax v3 / PSR-7)

Response Status

You can retrieve the response's HTTP status using getStatus(). It returns the status as an integer. The optional (and possibly empty) reason associated with the status can be retrieved using getReason().

$response = $client->request($request);

var_dump($response->getStatus(), $response->getReason());

Response Protocol Version

You can retrieve the response's HTTP protocol version using getProtocolVersion().

$response = $client->request($request);

var_dump($response->getProtocolVersion());

Response Headers

Response headers can be accessed by a set of methods.

  • hasHeader(string) returns whether a given header is present.
  • getHeader(string) returns the first header with the given name or null if no such header is present.
  • getHeaderArray(string) returns all headers with the given name, possibly an empty array.
  • getHeaders() returns all headers as an associative array, see below.

getHeaders() Format

[
    "header-1" => [
        "value-1",
        "value-2",
    ],
    "header-2" => [
        "value-1",
    ],
]

Response Body

getBody() returns a Payload, which allows simple buffering and streaming access.

Warning $chunk = $response->getBody()->read(); reads only a single chunk from the body while $contents = $response->getBody()->buffer() buffers the complete body. Please refer to the Payload documentation for more information.

Request, Original Request and Previous Response

getRequest() allows access to the request corresponding to the response. This might not be the original request in case of redirects. getOriginalRequest() returns the original request sent by the client. This might not be the same request that was passed to Client::request(), because the client might normalize headers or assign cookies. getPreviousResponse allows access to previous responses in case of redirects, but the response bodies of these responses won't be available, as they're discarded. If you need access to these, you need to disable auto redirects and implement them yourself.

Interceptors

Interceptors allow customizing the HttpClient behavior in a composable fashion. Use cases range from adding / removing headers from a request / response and recording timing information to more advanced use cases like a fully compliant HTTP cache that intercepts requests and serves them from the cache if possible.

use Amp\Http\Client\Client;
use Amp\Http\Client\HttpClientBuilder;
use Amp\Http\Client\Interceptor\SetRequestHeader;
use Amp\Http\Client\Interceptor\SetResponseHeader;
use Amp\Http\Client\Request;

$client = (new HttpClientBuilder)
    ->intercept(new SetRequestHeader('x-foo', 'bar'))
    ->intercept(new SetResponseHeader('x-tea', 'now'))
    ->build();

$response = $client->request(new Request("https://httpbin.org/get"));
$body = $response->getBody()->buffer();

There are two kinds of interceptors with separate interfaces named ApplicationInterceptor and NetworkInterceptor.

Choosing the right interceptor

Most interceptors should be implemented as ApplicationInterceptor. However, there's sometimes the need to have access to the underlying connection properties. In such a case, a NetworkInterceptor can be implemented to access the used IPs and TLS settings.

Another use-case for implementing a NetworkInterceptor is an interceptor, that should only ever run if the request is sent over the network instead of served from a cache or similar. However, that should usually be solved with the configuration order of the application interceptors.

The big disadvantage of network interceptors is that they have to be rather quick and can't take too long, because they're only invoked after the connection has been created and the client will run into a timeout if there's no activity within a reasonable time.

List of Interceptors

  • AddRequestHeader
  • AddResponseHeader
  • ConditionalInterceptor
  • DecompressResponse
  • FollowRedirects
  • ForbidUriUserInfo
  • IfOrigin
  • ModifyRequest
  • ModifyResponse
  • RemoveRequestHeader
  • RemoveResponseHeader
  • RetryRequests
  • SetRequestHeader
  • SetRequestHeaderIfUnset
  • SetResponseHeader
  • SetResponseHeaderIfUnset
  • CookieHandler
  • PrivateCache

Redirects

If you use HttpClientBuilder, the resulting HttpClient will automatically follow up to ten redirects by default. Automatic following can be customized or disabled (using a limit of 0) using HttpClientBuilder::followRedirects().

Redirect Policy

The FollowRedirects interceptor will only follow redirects with a GET method. If another request method is used and a 307 or 308 response is received, the response will be returned as is, so another interceptor or the application can take care of it. Cross-origin redirects will be attempted without any headers set, so any application headers will be discarded. If HttpClientBuilder is used to configure the client, the FollowRedirects interceptor is the outermost interceptor, so any headers set by interceptors will still be present in the response. It is therefore recommended to set headers via interceptors instead of directly in the request.

Examining the Redirect Chain

All previous responses can be accessed from the resulting Response via Response::getPreviousResponse(). However, the response body is discarded on redirects, so it can no longer be consumed. If you want to consume redirect response bodies, you need to implement your own interceptor.

Cookies

See amphp/http-client-cookies.

Logging

The LogHttpArchive interceptor allows logging all requests / responses including detailed timing information to an HTTP archive (HAR).

These log files can then be imported into the browsers developer tools or online tools like HTTP Archive Viewer or Google's HAR Analyzer.

Warning Be careful if your log files might contain sensitive information in URLs or headers if you submit these files to third parties like the linked services above.

use Amp\Http\Client\HttpClientBuilder;
use Amp\Http\Client\Interceptor\LogHttpArchive;

$httpClient = (new HttpClientBuilder)
    ->intercept(new LogHttpArchive('/tmp/http-client.har'))
    ->build();

$httpClient->request(...);

HAR Viewer Screenshot

Proxies

See amphp/http-tunnel.

Versioning

amphp/http-client follows the semver semantic versioning specification like all other amphp packages.

Everything in an Internal namespace or marked as @internal is not public API and therefore not covered by BC guarantees.

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

License

The MIT License (MIT). Please see LICENSE for more information.

More Repositories

1

amp

A non-blocking concurrency framework for PHP applications. 🐘
PHP
4,135
star
2

http-server

An advanced async HTTP server library for PHP, perfect for real-time apps and APIs with high concurrency demands.
PHP
1,276
star
3

parallel

An advanced parallelization library for PHP, enabling efficient multitasking, optimizing resource use, and application responsiveness through multiple CPU threads.
PHP
745
star
4

byte-stream

A non-blocking stream abstraction for PHP based on Amp.
PHP
357
star
5

mysql

An async MySQL client for PHP, optimizing database interactions with efficient non-blocking capabilities. Perfect for responsive, high-performance applications.
PHP
346
star
6

thread

Unmaintained. Use https://github.com/amphp/parallel.
PHP
297
star
7

parallel-functions

Simplified parallel processing for PHP based on Amp.
PHP
264
star
8

ext-fiber

PHP Fiber extension
Assembly
238
star
9

process

An async process dispatcher for Amp.
PHP
225
star
10

socket

Non-blocking socket and TLS functionality for PHP based on Amp.
PHP
214
star
11

ext-uv

C
186
star
12

sync

Non-blocking synchronization primitives for PHP based on Amp and Revolt.
PHP
155
star
13

dns

Async DNS resolution for PHP based on Amp.
PHP
149
star
14

redis

Efficient asynchronous communication with Redis servers, enabling scalable and responsive data storage and retrieval.
PHP
146
star
15

websocket-client

Async WebSocket client for PHP based on Amp.
PHP
138
star
16

parser

A generator parser to make streaming parsers simple.
PHP
121
star
17

websocket-server

WebSocket component for PHP based on the Amp HTTP server.
PHP
112
star
18

serialization

Serialization tools for IPC and data storage in PHP.
PHP
105
star
19

cache

A fiber-aware cache API based on Amp and Revolt.
PHP
95
star
20

windows-registry

Windows Registry Reader.
PHP
92
star
21

file

An abstraction layer and non-blocking file access solution that keeps your application responsive.
PHP
90
star
22

hpack

HPack - HTTP/2 header compression implementation in PHP.
PHP
90
star
23

postgres

Async Postgres client for PHP based on Amp.
PHP
88
star
24

http

HTTP primitives which can be shared by servers and clients.
PHP
87
star
25

beanstalk

Asynchronous Beanstalk Client for PHP.
PHP
63
star
26

cluster

Building multi-core network applications with PHP.
PHP
56
star
27

aerys

A non-blocking HTTP application, WebSocket and file server for PHP based on Amp.
PHP
52
star
28

pipeline

Concurrent iterators and pipeline operations.
PHP
43
star
29

http-server-router

A router for Amp's HTTP Server.
PHP
37
star
30

green-thread

PHP
37
star
31

getting-started

A getting started guide for Amp.
PHP
36
star
32

websocket

Shared code for websocket servers and clients.
PHP
34
star
33

ssh

Async SSH client for PHP based on Amp.
PHP
33
star
34

injector

A recursive dependency injector used to bootstrap and wire together S.O.L.I.D., object-oriented PHP applications.
PHP
32
star
35

log

Non-blocking logging for PHP based on Amp and Monolog.
PHP
31
star
36

uri

Uri Parser and Resolver.
PHP
24
star
37

amphp.github.io

Main website repository.
HTML
23
star
38

react-adapter

Makes any ReactPHP library compatible with Amp.
PHP
23
star
39

artax

An async HTTP/1.1 client for PHP based on Amp.
PHP
21
star
40

phpunit-util

Helper package to ease testing with PHPUnit.
PHP
21
star
41

http-server-static-content

An HTTP server plugin to serve static files like HTML, CSS, JavaScript, and images effortlessly.
PHP
21
star
42

http-server-session

An HTTP server plugin that simplifies session management for your applications. Effortlessly handle user sessions, securely managing data across requests.
PHP
17
star
43

mysql-dbal

PHP
16
star
44

http-server-form-parser

An HTTP server plugin that simplifies form data handling. Effortlessly parse incoming form submissions and extracting its data.
HTML
16
star
45

stomp

A non-blocking STOMP client built on the amp concurrency framework
PHP
15
star
46

aerys-reverse

Reverse HTTP proxy handler for Aerys
PHP
15
star
47

sql

Common interfaces for Amp based SQL drivers.
PHP
14
star
48

loop

Discontinued. Merged into https://github.com/amphp/amp.
PHP
12
star
49

http-tunnel

This package provides an HTTP CONNECT tunnel for PHP based on Amp.
PHP
11
star
50

http-client-cookies

Automatic cookie handling for Amp's HTTP client.
PHP
10
star
51

rpc

Remote procedure calls for PHP based on Amp.
PHP
9
star
52

http-client-psr7

PSR-7 adapter for amphp/http-client.
PHP
8
star
53

http-client-cache

An async HTTP cache for Amp's HTTP client.
PHP
7
star
54

sql-common

Implementations shared by amphp/postgres and amphp/mysql
PHP
7
star
55

php-cs-fixer-config

Common code style configuration for all @amphp projects.
PHP
6
star
56

react-stream-adapter

Adapters to make React's and Amp's streams compatible.
PHP
6
star
57

windows-process-wrapper

Child process wrapper to support non-blocking process pipes on Windows.
C
5
star
58

amphp.org

Documentation for AMPHP v3 based libraries.
HTML
5
star
59

quic

PHP
4
star
60

logo

Repository to store the logo and other assets.
3
star
61

dbus

A non-blocking DBus Connector with message serialization based on Amp.
PHP
2
star
62

website-tools

Website administration tools for amphp.org.
PHP
1
star
63

template

This repository serves as template for new amphp projects.
1
star
64

website-shared

Unmaintained. Has been merged into https://github.com/amphp/amphp.github.io.
1
star
65

.github

1
star