【PHP8.x】stream_set_timeout関数の使い方

stream_set_timeout関数の使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

stream_set_timeout関数は、ストリームリソースに対するタイムアウトを設定する関数です。具体的には、ソケット、ファイル、パイプなどのストリームに対して、読み込みまたは書き込み操作が指定された秒数内に完了しない場合にタイムアウトとみなされるように設定します。

この関数は、ストリームがブロックモードで動作している場合に特に重要です。ブロックモードでは、読み込みまたは書き込み操作は、データが利用可能になるか、またはタイムアウトが発生するまで処理を停止します。stream_set_timeout関数を使用することで、長時間応答のないストリームを適切に処理し、プログラムが無限に停止するのを防ぐことができます。

引数には、タイムアウトを設定するストリームリソース、タイムアウトの秒数(seconds)、およびマイクロ秒(microseconds)を指定します。マイクロ秒は、秒数未満の精度でタイムアウトを設定するために使用されます。

タイムアウトが発生した場合、ストリームリソースに関連付けられたメタデータが更新され、timed_outフラグが設定されます。このフラグは、stream_get_meta_data関数を使用して確認できます。タイムアウトが発生しても、エラーが発生するわけではありません。プログラムは処理を継続できますが、タイムアウトが発生したことを認識し、適切な対応を行う必要があります。

stream_set_timeout関数は、ネットワークソケットやファイルI/Oなど、様々なストリーム処理において、システムの安定性と応答性を維持するために不可欠な機能を提供します。システムエンジニアは、この関数を適切に使用することで、信頼性の高いアプリケーションを開発することができます。

構文(syntax)

1stream_set_timeout(resource $stream, int $seconds, int $microseconds = 0): bool

引数(parameters)

$stream, int $seconds, int $microseconds = 0

  • resource|object $stream: タイムアウトを設定するストリームリソースまたはオブジェクト
  • int $seconds: 秒単位のタイムアウト値
  • int $microseconds = 0: マイクロ秒単位のタイムアウト値(デフォルトは0)

戻り値(return)

bool

stream_set_timeout関数は、ストリーム操作のタイムアウトを設定し、成功した場合はtrueを、失敗した場合はfalseを返します。

サンプルコード

PHP stream_set_timeout で読み取りタイムアウトを設定する

1<?php
2
3declare(strict_types=1);
4
5/**
6 * stream_set_timeout() を使用してネットワークストリームのタイムアウトを設定するサンプルです。
7 *
8 * 外部のサーバーに接続し、意図的に短いタイムアウトを設定することで、
9 * 読み取り操作がタイムアウトする様子を確認します。
10 */
11function checkStreamTimeout(): void
12{
13    $host = 'example.com';
14    $port = 80;
15    $timeoutSeconds = 5;
16
17    // fsockopen() でTCPソケット接続を確立します。
18    // 接続自体にもタイムアウトを設定しています ($timeoutSeconds)。
19    // @ は、接続エラー時にPHPの警告を出さず、if文でエラーをハンドリングするためのものです。
20    $stream = @fsockopen($host, $port, $errno, $errstr, $timeoutSeconds);
21
22    if (!$stream) {
23        echo "サーバーへの接続に失敗しました: ({$errno}) {$errstr}" . PHP_EOL;
24        return;
25    }
26
27    try {
28        echo "サーバー ({$host}:{$port}) に接続しました。" . PHP_EOL;
29
30        // ストリームのタイムアウトを1秒に設定します。
31        // これ以降、このストリームからの読み取り操作は1秒以内に完了しないとタイムアウトします。
32        if (stream_set_timeout($stream, 1, 0)) {
33            echo "ストリームの読み取りタイムアウトを1秒に設定しました。" . PHP_EOL;
34        } else {
35            echo "タイムアウトの設定に失敗しました。" . PHP_EOL;
36            return;
37        }
38
39        // サーバーに簡単なHTTPリクエストを送信します。
40        fwrite($stream, "GET / HTTP/1.0\r\nHost: {$host}\r\n\r\n");
41        echo "HTTPリクエストを送信しました。レスポンスを待機します..." . PHP_EOL;
42
43        $response = '';
44        // feof() はストリームの終端に達するまでループします。
45        while (!feof($stream)) {
46            // ストリームから1行読み取ります。
47            $line = fgets($stream, 1024);
48            
49            // ストリームのメタ情報を取得します。
50            $metaData = stream_get_meta_data($stream);
51
52            // メタ情報の 'timed_out' が true の場合、タイムアウトが発生したことを示します。
53            if ($metaData['timed_out']) {
54                echo "エラー: データの読み取りがタイムアウトしました。" . PHP_EOL;
55                break; // ループを抜けます。
56            }
57
58            // 読み取ったデータを追記します。
59            $response .= $line;
60        }
61
62        if (!empty($response)) {
63            echo "レスポンスを正常に受信しました。(最初の100文字のみ表示)" . PHP_EOL;
64            echo substr($response, 0, 100) . '...' . PHP_EOL;
65        }
66
67    } finally {
68        // 処理が成功しても失敗しても、必ずストリームを閉じます。
69        fclose($stream);
70        echo "ストリームを閉じました。" . PHP_EOL;
71    }
72}
73
74// サンプル関数を実行します。
75checkStreamTimeout();

stream_set_timeout()は、指定したストリームの読み取り操作に対してタイムアウトを設定するPHP関数です。ネットワーク通信などで、相手からの応答が長時間ない場合にプログラムが停止し続けるのを防ぐために使用します。

この関数は3つの引数を取ります。第1引数$streamには、fsockopen()などで作成したストリームリソースを指定します。第2引数$secondsにタイムアウトまでの秒数を、第3引数$microsecondsにマイクロ秒を指定します。関数の実行が成功すると戻り値としてtrueを、失敗した場合はfalseを返します。

サンプルコードでは、fsockopen()で確立したネットワーク接続に対し、stream_set_timeout()で読み取りタイムアウトを1秒に設定しています。その後、whileループ内でfgets()を使いサーバーからの応答を読み取りますが、1秒以内にデータを受信できないとタイムアウトが発生します。タイムアウトが発生したかどうかは、stream_get_meta_data()で取得したメタ情報の'timed_out'キーがtrueになることで確認できます。これにより、応答がない場合に処理を安全に中断させることが可能です。

stream_set_timeout関数は、fgetsfreadといったストリームからのデータ読み取り操作にのみタイムアウトを設定します。サーバーへの接続時やデータ書き込み時のタイムアウトは、fsockopenの引数などで別途指定が必要です。この関数を呼び出しただけでは、タイムアウト時に処理は自動で中断されません。タイムアウトが発生したかどうかは、読み取り処理の直後にstream_get_meta_data関数でストリームの状態を確認し、その中のtimed_outキーがtrueになっているかで判断します。また、ネットワーク接続のようなリソースは、処理が正常に完了した場合もタイムアウトで中断した場合も、必ずfcloseで閉じるようにしてください。サンプルコードのようにtry...finallyを使うと、リソースの解放漏れを防ぐことができ安全です。

関連コンテンツ

【PHP8.x】stream_set_timeout関数の使い方 | いっしー@Webエンジニア