118 lines
2.5 KiB
PHP
118 lines
2.5 KiB
PHP
<?php
|
|
|
|
namespace JoopSchilder\Http2;
|
|
|
|
use RuntimeException;
|
|
|
|
/**
|
|
* Class Http2
|
|
*/
|
|
class Http2
|
|
{
|
|
/** @var resource */
|
|
private $multihandle;
|
|
|
|
/** @var callable */
|
|
private $responseHandler;
|
|
|
|
|
|
/**
|
|
* Http2 constructor.
|
|
*/
|
|
public function __construct()
|
|
{
|
|
$this->multihandle = curl_multi_init();
|
|
curl_multi_setopt($this->multihandle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
|
|
curl_multi_setopt($this->multihandle, CURLMOPT_MAX_HOST_CONNECTIONS, 1);
|
|
curl_multi_setopt($this->multihandle, CURLMOPT_MAX_TOTAL_CONNECTIONS, 1);
|
|
}
|
|
|
|
|
|
/**
|
|
* Http2 destructor.
|
|
*/
|
|
public function __destruct()
|
|
{
|
|
if (is_resource($this->multihandle)) {
|
|
curl_multi_close($this->multihandle);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @param string $url
|
|
* @param bool $priorKnowledge
|
|
* @return Request
|
|
*/
|
|
public function createRequest(string $url, bool $priorKnowledge = true): Request
|
|
{
|
|
return (new Request($url))->setOptions([
|
|
CURLOPT_AUTOREFERER => 1,
|
|
CURLOPT_FOLLOWLOCATION => 1,
|
|
CURLOPT_HEADER => 1,
|
|
CURLOPT_HTTP_VERSION => ($priorKnowledge ? CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE : CURL_HTTP_VERSION_2),
|
|
CURLOPT_MAXREDIRS => 5,
|
|
CURLOPT_PIPEWAIT => 1,
|
|
CURLOPT_RETURNTRANSFER => 1,
|
|
CURLOPT_SSL_VERIFYPEER => 0,
|
|
CURLOPT_TIMEOUT => 10,
|
|
]);
|
|
}
|
|
|
|
|
|
/**
|
|
* @param Request $request
|
|
*/
|
|
public function addRequest(Request $request): void
|
|
{
|
|
$handle = curl_init($request->getUri());
|
|
curl_setopt_array($handle, $request->getOptions());
|
|
curl_multi_add_handle($this->multihandle, $handle);
|
|
}
|
|
|
|
|
|
/**
|
|
* @param callable $responseHandler
|
|
*/
|
|
public function onResponse(callable $responseHandler): void
|
|
{
|
|
$this->responseHandler = $responseHandler;
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
*/
|
|
public function execute(): void
|
|
{
|
|
$this->guardNoResponseHandler();
|
|
do {
|
|
curl_multi_exec($this->multihandle, $stillRunning);
|
|
while (false !== ($message = curl_multi_info_read($this->multihandle))) {
|
|
$handle = $message['handle'];
|
|
$content = curl_multi_getcontent($handle);
|
|
|
|
$header = substr($content, 0, curl_getinfo($handle, CURLINFO_HEADER_SIZE));
|
|
$content = str_replace($header, '', $content);
|
|
$url = curl_getinfo($handle, CURLINFO_EFFECTIVE_URL);
|
|
call_user_func($this->responseHandler, new Response($url, $header, $content));
|
|
curl_multi_remove_handle($this->multihandle, $handle);
|
|
curl_close($handle);
|
|
}
|
|
usleep(5);
|
|
} while ($stillRunning > 0);
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
*/
|
|
private function guardNoResponseHandler(): void
|
|
{
|
|
if (!is_callable($this->responseHandler)) {
|
|
throw new RuntimeException('No valid response handler found');
|
|
}
|
|
}
|
|
|
|
}
|