Skip to content

Instantly share code, notes, and snippets.

@masakielastic
Last active July 10, 2025 18:37
Show Gist options
  • Save masakielastic/b7a13d6316409a671c9cef13b677a44d to your computer and use it in GitHub Desktop.
Save masakielastic/b7a13d6316409a671c9cef13b677a44d to your computer and use it in GitHub Desktop.
stream_socket_server で TLS 対応の HTTP/1 サーバー
<?php
// 1. 秘密鍵と CSR(証明書署名要求)のオプションを設定
$config = [
"config" => "/etc/ssl/openssl.cnf", // 必要に応じて openssl.cnf へのパスを調整
"private_key_bits" => 2048, // 鍵長
"private_key_type" => OPENSSL_KEYTYPE_RSA, // 鍵タイプ
];
// 2. 秘密鍵の生成
$privateKey = openssl_pkey_new($config);
if ($privateKey === false) {
die("秘密鍵の生成に失敗: " . openssl_error_string());
}
// 3. CSR の生成(ここでは DN 情報を簡易に指定)
$dn = [
"countryName" => "JP",
"stateOrProvinceName" => "Tokyo",
"localityName" => "Chiyoda-ku",
"organizationName" => "Example Co., Ltd.",
"organizationalUnitName" => "IT",
"commonName" => "example.local",
"emailAddress" => "[email protected]",
];
$csr = openssl_csr_new($dn, $privateKey, $config);
if ($csr === false) {
die("CSR の生成に失敗: " . openssl_error_string());
}
// 4. 自己署名証明書の生成(有効期間365日)
$serial = random_int(1, PHP_INT_MAX);
$validDays = 365;
$x509 = openssl_csr_sign($csr, null, $privateKey, $validDays, $config, $serial);
if ($x509 === false) {
die("証明書の署名に失敗: " . openssl_error_string());
}
// 5. 生成した秘密鍵・証明書を PEM 形式で文字列に出力
openssl_pkey_export($privateKey, $privateKeyPem);
openssl_x509_export($x509, $certPem);
// 6. ファイルへの保存
file_put_contents('key.pem', $privateKeyPem);
file_put_contents('cert.pem', $certPem);
echo "自己署名証明書と秘密鍵を生成しました。\n";
echo " - key.pem\n";
echo " - cert.pem\n";
<?php
// SSL コンテキストの設定
$context = stream_context_create([
'ssl' => [
'local_cert' => 'cert.pem', // サーバ証明書+中間証明書
'local_pk' => 'vkey.pem', // サーバ秘密鍵
'allow_self_signed' => true, // テスト用に自己署名証明書を許可
'verify_peer' => false, // クライアント証明書検証なし
'verify_peer_name' => false,
],
]);
// TLS:// を使ってポート 8443 で待ち受け
$server = stream_socket_server(
'tls://0.0.0.0:8443',
$errno,
$errstr,
STREAM_SERVER_BIND|STREAM_SERVER_LISTEN,
$context
);
if (!$server) {
die("サーバの起動に失敗: $errstr ($errno)\n");
}
echo "Listening on https://0.0.0.0:8443\n";
while ($client = @stream_socket_accept($server, -1)) {
// リクエストを読み込む
$request = '';
while (!feof($client) && strpos($request, "\r\n\r\n") === false) {
$request .= fgets($client, 1024);
}
// 簡易にリクエスト行だけを取得
if (preg_match('#^(GET|POST)\s+([^\s]+)\s+HTTP/1\.[01]#', $request, $m)) {
list(, $method, $path) = $m;
// ログ表示
echo "[" . date('Y-m-d H:i:s') . "] $method $path\n";
}
// レスポンスを送信
$body = "<html><body><h1>こんにちは、世界!</h1><p>あなたは {$method} {$path} をリクエストしました。</p></body></html>";
$response = "HTTP/1.1 200 OK\r\n";
$response .= "Content-Type: text/html; charset=UTF-8\r\n";
$response .= "Content-Length: " . strlen($body) . "\r\n";
$response .= "Connection: close\r\n";
$response .= "\r\n";
$response .= $body;
fwrite($client, $response);
fclose($client);
}
fclose($server);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment