🐈

【PHP】AMPHP の Socket クラスで HTTP/1 サーバーをつくる

2024/07/02に公開

まず Composer でダウンロードする

composer require amphp/socket

次のコードを用意する

server.php
<?php
// https://github.com/amphp/socket/blob/58e0422221825b79681b72c50c47a930be7bf1e1/examples/simple-http-server.php

use Amp\Socket;
use function Amp\async;

require __DIR__ . '/vendor/autoload.php';

$server = Socket\listen('0.0.0.0:8000');

echo 'Listening for new connections on ' . $server->getAddress() . ' ...' . PHP_EOL;
echo 'Open your browser and visit http://' . $server->getAddress() . '/' . PHP_EOL;

while ($socket = $server->accept()) {
    async(function () use ($socket) {
        $address = $socket->getRemoteAddress();
        assert($address instanceof Socket\InternetAddress);

        $ip = $address->getAddress();
        $port = $address->getPort();

        echo "Accepted connection from {$address}." . PHP_EOL;

        $body = "Hey, your IP is {$ip} and your local port used is {$port}.";
        $bodyLength = strlen($body);

        $socket->write("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: {$bodyLength}\r\n\r\n{$body}");
        $socket->end();
    });
}

スクリプトを実行して HTTP/1 サーバーを起動させる

php server.php

http://localhost:8000 にアクセスするとレスポンスが表示される

Listening for new connections on 0.0.0.0:8000 ...
Open your browser and visit https://0.0.0.0:8000/
Accepted connection from 127.0.0.1:36878.
Accepted connection from 127.0.0.1:36884.
Accepted connection from 127.0.0.1:35510.
Accepted connection from 127.0.0.1:35526.

ほかに TLS 対応を試してみたが curl ではレスポンスが返ってくるものの Chrome ブラウザーではクラッシュしてしまった

$cert = new Socket\Certificate(
  'localhost.pem',
  'localhost-key.pem'
);

$context = (new Socket\BindContext)
  ->withTlsContext(
    (new Socket\ServerTlsContext)->withDefaultCertificate($cert)
  );

$server = Socket\listen('0.0.0.0:8000', $context);
while ($socket = $server->accept()) {
    async(function () use ($socket) {
        $socket->setupTls();
    }
}

Discussion