chillerlan/php-httpinterface

A PSR-7/17/18 http message/client implementation

Fund package maintenance!
Ko Fi

6.0.0 2024-03-15 22:17 UTC

This package is auto-updated.

Last update: 2024-04-15 22:47:34 UTC


README

A PSR-7/PSR-17/PSR-18 HTTP message/client implementation.

PHP Version Support version license Continuous Integration Coverage Codacy Packagist downloads

Documentation

An API documentation created with phpDocumentor can be found at https://chillerlan.github.io/php-httpinterface/ (WIP).

Requirements

Installation with composer

Terminal

composer require chillerlan/php-httpinterface

composer.json

{
	"require": {
		"php": "^8.1",
		"chillerlan/php-httpinterface": "dev-main#<commit_hash>"
	}
}

Note: replace dev-main with a version constraint, e.g. ^6.0 - see releases for valid versions.

Profit!

Quickstart

The HTTP clients CurlClient and StreamClient are invoked with a ResponseFactoryInterface instance as the first parameter, followed by optional HTTPOptions and PSR-3 LoggerInterface instances. You can then send a request via the implemented PSR-18 method ClientInterface::sendRequest(), using a PSR-7 RequestInterface and expect a PSR-7 ResponseInterface.

CurlClient, StreamClient

$options                 = new HTTPOptions;
$options->ca_info        = '/path/to/cacert.pem';
$options->user_agent     = 'my cool user agent 1.0';
$options->dns_over_https = 'https://cloudflare-dns.com/dns-query';

$httpClient = new CurlClient($responseFactory, $options, $logger);
$request    = $requestFactory->createRequest('GET', 'https://www.example.com?foo=bar');

$httpClient->sendRequest($request);

CurlMultiClient

The CurlMultiClient client implements asynchronous multi requests ("rolling-curl"). It needs a MultiResponseHandlerInterface that parses the incoming responses, the callback may return a failed request to the stack:

$handler = new class () implements MultiResponseHandlerInterface{

	public function handleResponse(
		ResponseInterface $response,  // the incoming response
		RequestInterface  $request,   // the corresponding request
		int               $id,        // the request id
		array|null        $curl_info, // the curl_getinfo() result for this request
	):RequestInterface|null{
	
		if($response->getStatusCode() !== 200){
			// return the failed request back to the stack
			return $request;
		}
		
		try{
			$body = $response->getBody();
			
			// the response body is empty for some reason, we pretend that's fine and exit
			if($body->getSize() === 0){
				return null;
			}
			
			// parse the response body, store the result etc.
			$data = $body->getContents();
			
			// save data to file, database or whatever...
			// ...
	
		}
		catch(Throwable){
			// something went wrong, return the request to the stack for another try
			return $request;
		}
		
		// everything ok, nothing to return
		return null;
	}

};

You can then invoke the multi request client - the MultiResponseHandlerInterface and ResponseFactoryInterface are mandatory, HTTPOptions and LoggerInterface are optional:

$options              = new HTTPOptions;
$options->ca_info     = '/path/to/cacert.pem';
$options->user_agent  = 'my cool user agent 1.0';
$options->sleep       = 750000; // microseconds, see usleep()
$options->window_size = 5;
$options->retries     = 1;

$multiClient = new CurlMultiClient($handler, $responseFactory, $options, $logger);

// create and add the requests
foreach(['..', '...', '....'] as $item){
	$multiClient->addRequest($factory->createRequest('GET', $endpoint.'/'.$item));
}

// process the queue
$multiClient->process();

URLExtractor

The URLExtractor wraps a PSR-18 ClientInterface to extract and follow shortened URLs to their original location.

$options                 = new HTTPOptions;
$options->user_agent     = 'my cool user agent 1.0';
$options->ssl_verifypeer = false;
$options->curl_options   = [
	CURLOPT_FOLLOWLOCATION => false,
	CURLOPT_MAXREDIRS      => 25,
];

$httpClient   = new CurlClient($responseFactory, $options, $logger);
$urlExtractor = new URLExtractor($httpClient, $responseFactory);

$request = $factory->createRequest('GET', 'https://t.co/ZSS6nVOcVp');

$urlExtractor->sendRequest($request); // -> response from the final location

// you can retrieve an array with all followed locations afterwards
$responses = $this->http->getResponses(); // -> ResponseInterface[]

// if you just want the URL of the final location, you can use the extract method: 
$url = $this->http->extract('https://t.co/ZSS6nVOcVp'); // -> https://api.guildwars2.com/v2/build

LoggingClient

The LoggingClient wraps a ClientInterface and outputs the HTTP messages in a readable way through a LoggerInterface (do NOT use in production!).

$loggingClient = new LoggingClient($httpClient, $logger);

$loggingClient->sendRequest($request); // -> log to output given via logger

Auto generated API documentation

The API documentation can be auto generated with phpDocumentor. There is an online version available via the gh-pages branch that is automatically deployed on each push to main.

Locally created docs will appear in the directory .build/phpdocs/. If you'd like to create local docs, please follow these steps:

  • download phpDocumentor v3+ as .phar archive
  • run it in the repository root directory:
    • on Windows c:\path\to\php.exe c:\path\to\phpDocumentor.phar --config=phpdoc.xml
    • on Linux just php /path/to/phpDocumentor.phar --config=phpdoc.xml
  • open index.html in a browser
  • profit!

Disclaimer

Use at your own risk!