Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】CURLPIPE_MULTIPLEX定数の使い方

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

作成日: 更新日:

基本的な使い方

CURLPIPE_MULTIPLEX定数は、PHPのcURL拡張機能において、HTTP/2プロトコルの多重化(multiplexing)機能を有効にするために使用される特別な値を表す定数です。

この定数は、HTTP/2対応のサーバーとの通信効率を向上させる上で重要な役割を担います。HTTP/2は、ウェブの高速化を目指して開発されたプロトコルであり、その大きな特徴の一つが多重化です。多重化とは、これまでのHTTP/1.xのようにリクエストごとに新しい接続を確立したり、順番に処理したりするのではなく、一つのTCP接続上で複数のHTTPリクエストとレスポンスを同時に、かつ非同期にやり取りできる技術のことです。これにより、ページの読み込み速度が向上したり、多くのAPIリクエストを効率的に処理したりすることが可能になります。

PHPでcURLライブラリを利用してHTTP/2の多重化機能を活用するには、curl_setopt()関数を用いてCURLOPT_PIPEWAITオプションに対し、このCURLPIPE_MULTIPLEX定数を設定します。この設定を行うことで、cURLはHTTP/2の多重化を利用した通信を試み、複数のHTTPリクエストをより効率的に処理できるようになります。結果として、ネットワークのオーバーヘッドが削減され、特に多数の小さなリソースを一度に取得するような場面で、より高速でスムーズなデータ転送が期待できます。システム開発において高性能な通信処理を実現するために理解しておくべき定数の一つです。

構文(syntax)

1<?php
2$ch = curl_init();
3curl_setopt($ch, CURLOPT_PIPEWAIT, CURLPIPE_MULTIPLEX);
4curl_close($ch);
5?>

引数(parameters)

引数なし

引数はありません

戻り値(return)

int

CURLPIPE_MULTIPLEXは、CURLのマルチプレックス接続を有効にするための整数定数です。この定数は、複数のHTTPリクエストを単一のTCP接続上で並列に送信する際に使用されます。

サンプルコード

PHP CURLMOPT_PIPELINING CURLPIPE_MULTIPLEXで並列実行

1<?php
2
3/**
4 * CURLPIPE_MULTIPLEX を使用して複数のHTTPリクエストを並列に実行する関数。
5 * HTTP/2 の多重化(multiplexing)を活用し、単一の接続で複数のリクエストを効率的に処理します。
6 *
7 * @param array $urls リクエストを送信するURLの配列
8 * @return array 各リクエストの結果を含む配列
9 */
10function executeParallelHttpRequests(array $urls): array
11{
12    // 1. マルチCURLハンドルの初期化
13    // 複数のCURLリクエストを同時に管理するためのハンドルを作成します。
14    $multi_handle = curl_multi_init();
15    if ($multi_handle === false) {
16        error_log("CURLマルチハンドルの初期化に失敗しました。");
17        return [];
18    }
19
20    // 2. HTTP/2パイプライン多重化を有効にする
21    // CURLMOPT_PIPELINING オプションに CURLPIPE_MULTIPLEX を設定することで、
22    // libcurlがHTTP/2の多重化パイプライン(単一のTCP接続で複数のリクエスト/レスポンスを並行処理)
23    // を試みるようになります。これにより、パフォーマンスが向上する可能性があります。
24    if (!curl_multi_setopt($multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX)) {
25        // 設定に失敗した場合(例: 古いcURLバージョン)、エラーログを出力しますが、処理は続行可能です。
26        error_log("CURLMOPT_PIPELINING を CURLPIPE_MULTIPLEX に設定できませんでした。cURLバージョンを確認してください。");
27    }
28
29    $curl_handles = []; // 個々のCURLハンドルを格納する配列
30    $results = [];      // 各リクエストの結果を格納する配列
31
32    // 3. 各URLに対してCURLハンドルを作成し、マルチハンドルに追加
33    foreach ($urls as $index => $url) {
34        $ch = curl_init(); // 個別のCURLハンドルを初期化
35        if ($ch === false) {
36            error_log("URL: '{$url}' のCURLハンドル初期化に失敗しました。");
37            continue;
38        }
39
40        // 個別のCURLオプションを設定
41        curl_setopt($ch, CURLOPT_URL, $url);             // リクエスト先のURL
42        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);  // レスポンスを文字列として返す
43        curl_setopt($ch, CURLOPT_HEADER, false);         // レスポンスヘッダーを含めない
44        curl_setopt($ch, CURLOPT_TIMEOUT, 15);           // リクエストのタイムアウトを15秒に設定
45
46        // 個々のCURLハンドルをマルチハンドルに追加します。
47        // これにより、これらのリクエストが並列に実行される準備が整います。
48        curl_multi_add_handle($multi_handle, $ch);
49        $curl_handles[$index] = $ch; // 後で結果を取得するためにハンドルを保存
50    }
51
52    $running_handles = null; // 現在実行中のCURLハンドルの数を追跡
53
54    // 4. すべてのリクエストが完了するまでループ
55    do {
56        // curl_multi_exec() を呼び出し、追加されたすべてのCURLハンドルに対するデータ転送を試みます。
57        // この関数は、まだ実行中のリクエストがある限り、データを転送しようとします。
58        // $running_handles には、まだ処理が完了していないリクエストの数が設定されます。
59        $mrc = curl_multi_exec($multi_handle, $running_handles);
60
61        // エラーチェック: curl_multi_exec() がエラーを返した場合
62        if ($mrc != CURLM_OK) {
63            error_log("curl_multi_exec エラー: " . curl_multi_strerror($mrc));
64            break; // エラーが発生した場合はループを中断
65        }
66
67        // まだ実行中のリクエストがある場合、イベントを待機してCPU負荷を軽減します。
68        if ($running_handles > 0) {
69            // curl_multi_select() は、何らかのアクティビティ(データ受信、エラーなど)
70            // が発生するまで、指定された秒数(ここでは1.0秒)まで待機します。
71            // これにより、CPUを占有することなく効率的に待機できます。
72            curl_multi_select($multi_handle, 1.0);
73        }
74
75    } while ($running_handles > 0); // 実行中のハンドルがなくなるまでループを続けます
76
77    // 5. 各リクエストの結果を処理
78    foreach ($curl_handles as $index => $ch) {
79        $error_message = curl_error($ch); // エラーメッセージを取得
80        $http_info = curl_getinfo($ch);   // HTTPに関する情報を取得
81        $response_content = curl_multi_getcontent($ch); // レスポンスボディを取得
82
83        if ($error_message) {
84            // エラーが発生した場合
85            $results[$index] = [
86                'url' => $http_info['url'] ?? $urls[$index],
87                'status' => 'error',
88                'error_message' => $error_message,
89                'http_code' => $http_info['http_code'] ?? 0,
90            ];
91        } else {
92            // リクエストが成功した場合
93            $results[$index] = [
94                'url' => $http_info['url'],
95                'status' => 'success',
96                'http_code' => $http_info['http_code'],
97                'response_length' => strlen($response_content),
98                // 'response_body' => $response_content, // デバッグ時のみ含めることを推奨 (大量データに注意)
99            ];
100        }
101
102        // 個々のCURLハンドルをマルチハンドルから削除し、閉じます。
103        curl_multi_remove_handle($multi_handle, $ch);
104        curl_close($ch);
105    }
106
107    // 6. マルチCURLハンドルを閉じる
108    // すべてのリクエストが完了したら、マルチハンドルを解放します。
109    curl_multi_close($multi_handle);
110
111    return $results;
112}
113
114// --- 使用例 ---
115$target_urls = [
116    'https://www.example.com/',
117    'https://www.google.com/',
118    'https://www.php.net/',
119    'https://api.github.com/zen', // 比較的軽量なAPI
120    'https://httpbin.org/delay/2', // 2秒遅延するエンドポイント
121];
122
123echo "--- 並列HTTPリクエストの開始 ---\n";
124$start_time = microtime(true);
125
126// 関数を呼び出して並列リクエストを実行
127$request_results = executeParallelHttpRequests($target_urls);
128
129$end_time = microtime(true);
130$duration = round($end_time - $start_time, 3);
131echo "--- 並列HTTPリクエストの完了 ---\n";
132echo "合計所要時間: {$duration} 秒\n\n";
133
134// 結果の表示
135foreach ($request_results as $index => $result) {
136    echo "--- リクエスト " . ($index + 1) . " の結果 ---\n";
137    echo "URL: " . ($result['url'] ?? 'N/A') . "\n";
138    echo "ステータス: " . ($result['status'] ?? 'N/A') . "\n";
139    if ($result['status'] === 'success') {
140        echo "HTTPコード: " . ($result['http_code'] ?? 'N/A') . "\n";
141        echo "レスポンス長: " . ($result['response_length'] ?? 'N/A') . " バイト\n";
142    } else {
143        echo "エラーメッセージ: " . ($result['error_message'] ?? 'N/A') . "\n";
144    }
145    echo "\n";
146}
147
148?>

PHPのこのサンプルコードは、cURL拡張機能を利用して複数のHTTPリクエストを並列に実行する方法を示しています。特に注目すべきは、CURLPIPE_MULTIPLEX定数の使用です。この定数は、curl_multi_setopt()関数のCURLMOPT_PIPELININGオプションに設定することで、HTTP/2の多重化(multiplexing)機能を有効にします。多重化とは、単一のTCP接続上で複数のリクエストとレスポンスを同時に処理する技術であり、これにより通信のオーバーヘッドを削減し、特に多数の小さなリクエストを送信する際のパフォーマンス向上に貢献します。

コードはまずcurl_multi_init()で複数のリクエストを管理する「マルチCURLハンドル」を作成し、上記CURLPIPE_MULTIPLEXを設定します。その後、引数として渡されるURLの配列($urls)の各要素に対し、個別のCURLハンドルをcurl_init()で作成し、URLや取得方法などのオプションを設定します。これらの個々のハンドルはcurl_multi_add_handle()によってマルチハンドルに追加され、並列実行の準備が整います。

リクエストの実行は、curl_multi_exec()curl_multi_select()を組み合わせたループで行われます。curl_multi_exec()は転送処理を試み、curl_multi_select()は次のアクティビティ発生まで効率的に待機します。全てのリクエストが完了すると、各ハンドルからcurl_multi_getcontent()などで結果を取得し、成功やエラー情報、HTTPステータスコードなどを含む配列として返されます。最後に、使用した全てのハンドルは適切に解放されます。

このサンプルコードは、CURLPIPE_MULTIPLEX定数を用いて複数のHTTPリクエストを並列に処理し、HTTP/2多重化による効率的な通信を試みるものです。利用する際は、サーバーとクライアント(PHPのcURL拡張機能が依存するlibcurlライブラリ)の両方がHTTP/2プロトコルに対応しているか確認してください。対応していない環境ではCURLPIPE_MULTIPLEXの設定が機能せず、パフォーマンス向上の恩恵を受けられない可能性があります。また、並列処理においては、curl_multi_execのループ内で適切にエラーを検出し、各CURLハンドルやマルチハンドルをcurl_closeおよびcurl_multi_closeで確実に解放することが、リソースリークを防ぐ上で非常に重要となります。curl_multi_selectは、CPU負荷を抑えつつ効率的にイベントを待機するために必要です。

PHP cURL並行リクエスト CURLPIPE_MULTIPLEX設定

1<?php
2
3/**
4 * 複数のURLにHTTPリクエストを並行して送信し、そのレスポンスを取得します。
5 * CURLPIPE_MULTIPLEX定数を使用して、HTTP/2のパイプライン処理やプッシュの利用をcURLに指示します。
6 * ただし、実際の利用はサーバーがHTTP/2をサポートし、それに対応する動作をする場合に限られます。
7 *
8 * @param array $urls リクエストを送信するURLの配列(例: ['key1' => 'http://example.com', 'key2' => 'http://test.com'])
9 * @return array 各URLに対するレスポンスコンテンツを格納した配列
10 */
11function fetchUrlsConcurrentlyWithMultiplex(array $urls): array
12{
13    // cURLマルチハンドルを初期化し、複数のリクエストを並行して扱えるようにします。
14    $multi_handle = curl_multi_init();
15    if ($multi_handle === false) {
16        throw new RuntimeException("Failed to initialize cURL multi handle.");
17    }
18
19    $curl_handles = []; // 各リクエストのcURLハンドルを保持する配列
20    $results = [];      // 各リクエストの結果を格納する配列
21
22    // 各URLに対して個別のcURLハンドルを設定します。
23    foreach ($urls as $key => $url) {
24        $ch = curl_init();
25        if ($ch === false) {
26            error_log("Failed to initialize cURL handle for URL: $url");
27            continue;
28        }
29
30        // リクエストURLを設定
31        curl_setopt($ch, CURLOPT_URL, $url);
32        // レスポンスデータを文字列として返すように設定
33        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
34        // レスポンスにHTTPヘッダーを含めないように設定
35        curl_setopt($ch, CURLOPT_HEADER, false);
36
37        // CURLPIPE_MULTIPLEX定数を使用し、cURLにHTTP/2のパイプライン処理やプッシュを待機するよう指示します。
38        // これにより、HTTP/2サーバーとの通信効率が向上する可能性があります。
39        curl_setopt($ch, CURLOPT_PIPEWAIT, CURLPIPE_MULTIPLEX);
40
41        // 設定済みのcURLハンドルをマルチハンドルに追加します。
42        curl_multi_add_handle($multi_handle, $ch);
43        $curl_handles[$key] = $ch;
44    }
45
46    $running_handles = null; // 実行中のハンドルの数を保持
47
48    // 全てのリクエストが完了するまでループを続けます。
49    do {
50        // 全ての追加されたcURLハンドルを実行します。
51        // $running_handlesには現在実行中のハンドルの数が設定されます。
52        curl_multi_exec($multi_handle, $running_handles);
53
54        // 実行中のハンドルがある場合、新しいアクティビティを待機します。
55        // curl_multi_selectは、ソケットアクティビティがあるまでブロックします。
56        if ($running_handles > 0 && curl_multi_select($multi_handle) === -1) {
57            // エラーが発生した場合、無限ループを避けるために短いスリープを入れます。
58            usleep(100);
59        }
60    } while ($running_handles > 0); // 実行中のハンドルがなくなるまで繰り返します。
61
62    // 全てのリクエストが完了したら、各ハンドルの結果を取得し、ハンドルをクローズします。
63    foreach ($curl_handles as $key => $ch) {
64        $results[$key] = curl_multi_getcontent($ch); // レスポンスコンテンツを取得
65        curl_multi_remove_handle($multi_handle, $ch); // マルチハンドルから削除
66        curl_close($ch); // cURLハンドルをクローズ
67    }
68
69    // cURLマルチハンドルをクローズします。
70    curl_multi_close($multi_handle);
71
72    return $results;
73}
74
75// --- サンプルコードの実行例 ---
76if (php_sapi_name() == 'cli') { // コマンドラインからの実行時のみ表示
77    $target_urls = [
78        'example_com' => 'https://example.com/',
79        'php_net'     => 'https://www.php.net/',
80        'httpbin_get' => 'https://httpbin.org/get?param=test_multiplex', // テスト用のechoサービス
81    ];
82
83    echo "--- 複数のURLを並行して取得中 (CURLPIPE_MULTIPLEX 使用) ---\n";
84    try {
85        $responses = fetchUrlsConcurrentlyWithMultiplex($target_urls);
86
87        foreach ($responses as $key => $content) {
88            echo "\n--- レスポンス for {$key} ---\n";
89            // 実際のコンテンツは非常に長くなる可能性があるので、先頭の200文字だけ表示
90            echo substr($content, 0, 200) . "...\n";
91        }
92        echo "\n--- 全てのリクエストが完了しました ---\n";
93
94    } catch (RuntimeException $e) {
95        echo "エラーが発生しました: " . $e->getMessage() . "\n";
96    }
97}
98
99?>

このPHPサンプルコードは、fetchUrlsConcurrentlyWithMultiplex関数を利用して、複数のURLに対してHTTPリクエストを並行して送信し、それぞれのレスポンスを取得する方法を示しています。引数には、キーにURLを識別する文字列、値に実際のURLを指定した連想配列$urlsを渡します。戻り値としては、各URLに対するレスポンスコンテンツを格納した連想配列が得られます。

処理は、まずcurl_multi_initで複数のリクエストを同時に管理するためのマルチハンドルを初期化することから始まります。次に、指定された各URLごとにcurl_initで個別のcURLハンドルを作成し、リクエストの準備を行います。ここで特に重要な設定は、curl_setopt関数でCURLOPT_PIPEWAITオプションにCURLPIPE_MULTIPLEX定数を指定する点です。この定数を設定することで、cURLはHTTP/2プロトコルにおいて、サーバーからのパイプライン処理やサーバープッシュ機能の利用を待機し、通信効率を向上させることが期待されます。ただし、これはサーバー側がHTTP/2をサポートし、その機能に対応している場合に有効です。

個別のcURLハンドルが設定された後、curl_multi_add_handleでそれらをマルチハンドルに追加します。その後、curl_multi_execcurl_multi_selectを組み合わせたループ処理により、全てのリクエストが並行して実行され、完了するまで待機します。全てのリクエストが終了すると、curl_multi_getcontentで各URLからのレスポンスコンテンツを取得し、最終的に全てのcURLハンドルおよびマルチハンドルを適切にクローズしてリソースを解放します。これにより、外部APIへの同時アクセスなど、多くのネットワークリクエストを効率良く処理することが可能になります。

CURLPIPE_MULTIPLEXは、HTTP/2プロトコルをサポートするサーバーとの通信において、リクエストの効率を高めるためのオプションです。この設定はサーバーがHTTP/2に対応し、パイプライン処理やプッシュ機能が利用可能な場合にのみ効果を発揮しますので、設定したからといって常に高速化するわけではない点に注意が必要です。複数のリクエストを並行処理するマルチcURLのコードは、単一のリクエストと比べて複雑になりがちです。特に、エラー発生時のハンドルのクローズやリソースの解放が適切に行われるか、無限ループに陥らないかなど、堅牢なエラーハンドリングとリソース管理が重要になります。利用の際は、サーバー側のHTTP/2対応状況と動作を十分に確認することが大切です。

関連コンテンツ

関連IT用語

関連プログラミング言語