PHP code example of mikepultz / php-quic

1. Go to this page and download the library: Download mikepultz/php-quic library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

mikepultz / php-quic example snippets


// open a QUIC connection and exchange data on a stream
$conn   = new Quic\Connection('example.com', 443, ['alpn' => 'myproto']);
$stream = $conn->openStream();

// send the data, then conclude the stream (FIN)
$stream->write("hello", true);

$reply = $stream->read(65535);

$conn->close();

Quic\poll(array $items, ?float $timeout = null): array

try
{
    $ready = Quic\poll($items, 1.0);

    if (count($ready) == 0)
    {
        // timed out: nothing became ready within 1.0s
    }

    foreach ($ready as $i => $revents)
    {
        if (($revents & Quic\POLL_ERROR) != 0)
        {
            // this object errored or closed
        }

        if (($revents & Quic\POLL_READ) != 0)
        {
            // readable
        }
    }
} catch (Quic\Exception $e)
{
    // the poll call itself failed
}

$info = $conn->getCloseInfo();

if ($info !== null && $info['transport'] == true
        && $info['error_code'] === Quic\ERR_PROTOCOL_VIOLATION)
{
    // the peer tore down the connection for a QUIC protocol violation
}

$host = 'cloudflare-quic.com';
$conn = new Quic\Connection($host, 443, ['alpn' => 'h3']);

//
// HTTP/3 needs a control stream with SETTINGS plus QPACK encoder/decoder
// streams. Keep these references for the connection's lifetime: closing the
// control stream is a fatal H3 error.
//

// unidirectional control stream: type 0x00 (control) + empty SETTINGS
$control = $conn->openStream(false);
$control->write("\x00\x04\x00");

// QPACK encoder (0x02) and decoder (0x03) streams
$qpackEnc = $conn->openStream(false);
$qpackEnc->write("\x02");

$qpackDec = $conn->openStream(false);
$qpackDec->write("\x03");

//
// a GET is a HEADERS frame holding a QPACK field section. Pseudo-headers come
// from the QPACK static table: GET=17, https=23, :path /=1, :authority=0.
//

// QPACK prefix
$fields  = "\x00\x00";

// :method GET
$fields .= "\xD1";

// :scheme https
$fields .= "\xD7";

// :authority (literal)
$fields .= "\x50" . chr(strlen($host)) . $host;

// :path /
$fields .= "\xC1";

// HEADERS frame
$request = "\x01" . chr(strlen($fields)) . $fields;

// request stream (bidirectional): send the request + FIN (GET has no body)
$stream = $conn->openStream(true);
$stream->write($request, true);

$resp = '';

while (($chunk = $stream->read(65535)) !== null)
{
    if ($chunk !== '')
    {
        $resp .= $chunk;
    }
}

//
// parse the HTTP/3 frames and collect DATA frames (the body)
//
$read_varint = function (string $_d, int &$_o): int
{
    $b = ord($_d[$_o]);
    $n = 1 << ($b >> 6);
    $v = $b & 0x3f;

    for ($i = 1; $i < $n; $i++)
    {
        $v = ($v << 8) | ord($_d[$_o + $i]);
    }

    $_o += $n;

    return $v;
};

$off  = 0;
$body = '';

while ($off < strlen($resp))
{
    $type    = $read_varint($resp, $off);
    $len     = $read_varint($resp, $off);
    $payload = substr($resp, $off, $len);
    $off    += $len;

    // type 0x00 is a DATA frame; 0x01 is the response HEADERS frame (QPACK)
    if ($type === 0x00)
    {
        $body .= $payload;
    }
}

// e.g. "<!DOCTYPE html>"
echo strlen($body), " bytes: ", strtok($body, "\n"), "\n";

$conn->close();

$conn   = new Quic\Connection('dns.adguard-dns.com', 853, ['alpn' => 'doq']);
$stream = $conn->openStream();

// a wire-format DNS message (id 0), e.g. from a DNS library
$query = "...";

// frame with a 2-octet length prefix and conclude (FIN)
$stream->write(pack('n', strlen($query)) . $query, true);

$len  = unpack('n', $stream->read(2))[1];
$resp = $stream->read($len);

$conn->close();

$listener = new Quic\Listener('0.0.0.0', 4433, [
    'local_cert' => '/etc/ssl/server.crt',
    'local_pk'   => '/etc/ssl/server.key',
    'alpn'       => 'myproto',
]);

while (true)
{
    // blocking accept of a connection and its first stream
    $conn   = $listener->accept();
    $stream = $conn->acceptStream();

    $data = '';

    while (($chunk = $stream->read(65535)) !== null)
    {
        if ($chunk !== '')
        {
            $data .= $chunk;
        }
    }

    $stream->write("echo: $data", true);
    $conn->close();
}

$conn = new Quic\Connection($host, $port, ['alpn' => 'myproto']);
$conn->setBlocking(false);

$stream = $conn->openStream();

// send the request + FIN
$stream->write($request, true);

$response = '';

while (true)
{
    // wait until the stream is readable (or a QUIC timer needs servicing)
    Quic\poll([[$stream, Quic\POLL_READ | Quic\POLL_ERROR]], 1.0);

    $chunk = $stream->read(65535);

    // end of stream
    if ($chunk === null)
    {
        break;
    }

    if ($chunk !== '')
    {
        $response .= $chunk;
    }
}

$conn->close();

$conn->setBlocking(false);

$sock  = fopen('php://fd/' . $conn->getFd(), 'r');
$items = [[$stream, Quic\POLL_READ | Quic\POLL_ERROR]];

while (true)
{
    //
    // never sleep past the connection's own deadline
    //
    $quic = $conn->getTimeout();
    $wait = $quic === null ? $deadline : min($quic, $deadline);

    $r = [$sock, ...$yourOtherDescriptors];
    $w = $conn->wantsWrite() == true ? [$sock] : [];
    $e = [];

    @stream_select($r, $w, $e, (int)$wait, (int)(fmod($wait, 1.0) * 1000000));

    //
    // pump the QUIC engine and collect stream readiness in one call
    //
    foreach (Quic\poll($items, 0.0) as $key => $revents)
    {
        // ... read/write the ready streams
    }

    // ... your own descriptors, handled exactly as they always were
}

$conn = new Quic\Connection('cloudflare-quic.com', 443, ['alpn' => 'h3']);

$info = $conn->getCryptoInfo();
// ['protocol' => 'QUICv1', 'cipher_name' => 'TLS_AES_256_GCM_SHA384',
//  'cipher_bits' => 256, 'cipher_version' => 'TLSv1.3', 'alpn_protocol' => 'h3']

// bridge the PEM leaf certificate to ext-openssl
$cert = openssl_x509_read($conn->getPeerCertificate());
$meta = openssl_x509_parse($cert);

echo $meta['subject']['CN'], "\n";

// prints "ok" on success
echo "verify: ", $conn->getVerifyResultString(), "\n";

$conn = new Quic\Connection($host, $port, [
    'alpn' => 'myproto',

    // throws Quic\Exception on mismatch
    'peer_fingerprint' => ['sha256' => 'aabbcc...'],
]);
sh
pie install mikepultz/php-quic