【PHP8.x】curl_multi_info_read()関数の使い方
curl_multi_info_read関数の使い方について、初心者にもわかりやすく解説します。
基本的な使い方
curl_multi_info_read関数は、複数のcURLリクエストを同時に管理するためのマルチハンドルから、完了した転送に関する情報を読み取る関数です。PHPで複数のウェブサイトへのデータ取得やAPI呼び出しなど、複数のHTTPリクエストを並行して処理したい場合に、curl_multi_init()で初期化したマルチハンドルを利用します。この関数は、curl_multi_exec()によって実行された複数のリクエストのうち、どれか一つが完了した際に、その完了した転送の詳細情報を取得するために使われます。
具体的には、この関数を呼び出すと、完了した個々のcURLハンドルの情報が配列として返されます。この配列には、完了したcURLハンドルそのものや、転送結果を示すステータスコード、エラーコードなどが含まれています。システムエンジニアを目指す方は、この情報を受け取ることで、どのリクエストが完了したのかを特定し、その転送が成功したのか、それとも何らかのエラーが発生したのかを判断できます。
また、一度の呼び出しで得られる情報は一つの完了した転送に関するものだけです。そのため、複数のリクエストが同時に完了している可能性がある場合は、情報がなくなるまでcurl_multi_info_read関数を繰り返し呼び出す必要があります。これにより、並行処理されたすべてのリクエストの結果を効率的に収集し、適切な後処理やエラーハンドリングを行うことが可能になります。
構文(syntax)
1<?php 2 3function curl_multi_info_read(CurlMultiHandle $multi_handle, ?int &$msgs_in_queue = null): array|false {} 4
引数(parameters)
CurlMultiHandle $multi_handle, int &$queued_messages = null
- CurlMultiHandle $multi_handle: 複数のcURL転送を管理するCurlMultiHandleオブジェクト
- int &$queued_messages = null: キューに入れられたメッセージの数を受け取る整数への参照
戻り値(return)
array|false
実行が完了した転送に関する情報を含む配列、またはエラーが発生した場合は false を返します。
サンプルコード
PHP curl_multi_info_readで転送結果を取得する
1<?php 2 3/** 4 * 複数のURLに対して並行してHTTPリクエストを実行し、結果を処理するサンプルコードです。 5 * curl_multi_init と curl_multi_info_read を中心に使用します。 6 */ 7function executeMultiCurlRequests(): void 8{ 9 // 1. マルチCURLハンドルを初期化します。複数のCURLリクエストを並行して管理するためのコンテナです。 10 $multi_handle = curl_multi_init(); 11 if ($multi_handle === false) { 12 echo "エラー: マルチCURLハンドルを初期化できませんでした。\n"; 13 return; 14 } 15 16 // 実行するURLのリスト 17 $urls = [ 18 'https://jsonplaceholder.typicode.com/todos/1', 19 'https://jsonplaceholder.typicode.com/posts/1', 20 'https://jsonplaceholder.typicode.com/users/1', 21 // 意図的に存在しないURLを追加してエラー時の動作も確認できます 22 // 'https://example.com/nonexistent-page', 23 ]; 24 25 // 個々のCURLハンドルを保存する配列 26 $curl_handles = []; 27 28 // 2. 各URLに対して個別のCURLハンドルを初期化し、オプションを設定します。 29 foreach ($urls as $key => $url) { 30 $ch = curl_init(); 31 if ($ch === false) { 32 echo "エラー: URL '{$url}' のCURLハンドルを初期化できませんでした。\n"; 33 continue; 34 } 35 36 // リクエストURLを設定 37 curl_setopt($ch, CURLOPT_URL, $url); 38 // レスポンスヘッダを含めない 39 curl_setopt($ch, CURLOPT_HEADER, 0); 40 // レスポンスボディを文字列として返すように設定 41 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 42 // タイムアウトを短めに設定 (例: 5秒) 43 curl_setopt($ch, CURLOPT_TIMEOUT, 5); 44 45 // 3. 設定した個別のCURLハンドルをマルチCURLハンドルに追加します。 46 // これにより、これらのリクエストが並行処理の対象となります。 47 curl_multi_add_handle($multi_handle, $ch); 48 $curl_handles[$key] = $ch; // 後で参照できるように保存 49 echo "CURLハンドルをマルチハンドルに追加しました: {$url}\n"; 50 } 51 52 // 4. すべてのリクエストが完了するまでループを続けます。 53 $running_handles = null; // 現在実行中のハンドルの数 54 do { 55 // 並行リクエストを実行し、実行中のハンドルの数を更新します。 56 // CURLM_CALL_MULTI_PERFORM が返された場合、すぐに再度 curl_multi_exec を呼び出す必要があります。 57 $status = curl_multi_exec($multi_handle, $running_handles); 58 59 // CPUの使用率を抑えるため、進行中のリクエストがある場合はイベントを待ちます。 60 if ($running_handles > 0) { 61 curl_multi_select($multi_handle, 1.0); // 最大1秒間イベントを待機 62 } 63 64 // 5. 完了したリクエストに関する情報を読み取ります。 65 // このループは、curl_multi_exec が完了したリクエストのシグナルを生成するたびに実行されます。 66 while ($info = curl_multi_info_read($multi_handle)) { 67 echo "\n--- 完了した転送を検出しました ---\n"; 68 echo "メッセージタイプ: " . $info['msg'] . "\n"; // CURLMSG_DONE (リクエスト完了) 69 echo "結果コード: " . $info['result'] . " (CURLM_OK = 0, エラーコード)\n"; 70 71 // 完了した個別のCURLハンドルを取得し、その詳細情報を取得します。 72 $completed_ch = $info['handle']; 73 $http_code = curl_getinfo($completed_ch, CURLINFO_HTTP_CODE); 74 $url_fetched = curl_getinfo($completed_ch, CURLINFO_EFFECTIVE_URL); 75 $error_num = curl_errno($completed_ch); 76 $error_msg = curl_error($completed_ch); 77 78 echo "リクエストURL: " . $url_fetched . "\n"; 79 echo "HTTPステータスコード: " . $http_code . "\n"; 80 81 if ($error_num !== 0) { 82 echo "CURLエラー発生: ({$error_num}) {$error_msg}\n"; 83 } else { 84 // 取得したレスポンスボディを取得します。 85 $content = curl_multi_getcontent($completed_ch); 86 echo "レスポンスの一部: " . substr($content, 0, 100) . "...\n"; 87 } 88 89 // 完了したCURLハンドルをマルチCURLハンドルから削除します。 90 curl_multi_remove_handle($multi_handle, $completed_ch); 91 // 個別のCURLハンドルをクローズし、リソースを解放します。 92 curl_close($completed_ch); 93 echo "個別のCURLハンドルを削除し、クローズしました。\n"; 94 } 95 96 } while ($running_handles > 0 || $status === CURLM_CALL_MULTI_PERFORM); // 実行中のハンドルがあるか、再実行が必要な限りループを続ける 97 98 // 6. すべてのリクエストが完了したら、マルチCURLハンドルをクローズします。 99 curl_multi_close($multi_handle); 100 echo "\nすべての並行CURL転送が終了しました。\n"; 101} 102 103// 関数を実行します。 104executeMultiCurlRequests(); 105 106?>
このサンプルコードは、PHPのCURL拡張機能を用いて、複数のHTTPリクエストを並行して実行し、その結果を効率的に処理する方法を示しています。
まず、curl_multi_init関数で複数のCURLリクエストを同時に管理するためのマルチCURLハンドルを初期化します。次に、アクセスしたい各URLに対して個別のCURLハンドルをcurl_initで作成し、必要なオプションを設定した後、curl_multi_add_handleでマルチCURLハンドルに追加していきます。
追加されたリクエストは、ループ内でcurl_multi_execを呼び出すことで並行して実行されます。この処理中に重要な役割を果たすのがcurl_multi_info_read関数です。この関数は、引数として渡されたCurlMultiHandle $multi_handleから、完了した個々の転送に関する情報を読み取ります。
curl_multi_info_readは、転送が完了したCURLハンドル、メッセージタイプ(通常は転送完了を示すCURLMSG_DONE)、そして転送の結果コードなどを含む連想配列を戻り値として返します。まだ完了した転送がない場合はfalseを返します。この情報を受け取ることで、どのリクエストが完了したか、そのHTTPステータスコードやエラーなどの結果を特定し、curl_multi_getcontentでレスポンスボディを取得できます。処理を終えた個別のCURLハンドルは、curl_multi_remove_handleでマルチハンドルから削除し、最終的にcurl_closeでリソースを解放します。
この仕組みにより、複数のネットワーク処理を同時に進め、アプリケーションの応答性やスループットを向上させることが可能になります。
curl_multi_info_read 関数は、完了したCURLリクエストの情報を順次読み取ります。すべての情報を確実に処理するため、戻り値がなくなるまでループ内で繰り返し呼び出す点が重要です。
マルチCURL処理では、curl_multi_init で作成したマルチハンドルと、curl_init で作成した各リクエストハンドルを、処理完了後に必ず curl_multi_close および curl_close で閉じてリソースを解放してください。特に、個々のCURLハンドルはマルチハンドルから削除した後も curl_close が必要です。
また、CPU使用率を抑えるため、curl_multi_exec 実行後には curl_multi_select を利用してイベントを待機するようにしてください。エラー発生時もリソースが適切に解放されるよう、エラーハンドリングを丁寧に行うことが堅牢なシステム開発に繋がります。
PHP cURLマルチで複数URLコンテンツ取得
1<?php 2 3/** 4 * 複数のURLから並行してコンテンツを取得します。 5 * 6 * この関数は、PHPのcURLマルチハンドル機能を使用して、複数のHTTPリクエストを同時に実行します。 7 * 主に `curl_multi_info_read` を使って完了したリクエストを検出し、 8 * その後 `curl_multi_getcontent` で各リクエストのレスポンスボディを取得する方法を示します。 9 * 10 * @param array<string> $urls 取得するURLの配列。 11 * @return array<string, array{status_code: int, content: string|false, error: string|null}> 12 * URLをキーとし、HTTPステータスコード、取得されたコンテンツ、または発生したエラー情報を含む配列の配列。 13 */ 14function fetchMultipleUrlsConcurrently(array $urls): array 15{ 16 $results = []; // 最終的な結果を格納する配列 17 $curly_handles = []; // 各URLに対応するcURLハンドルを格納する配列 18 $multi_handle = curl_multi_init(); // cURLマルチハンドルを初期化 19 20 // 各URLに対して個別のcURLハンドルを準備し、マルチハンドルに追加します。 21 foreach ($urls as $id => $url) { 22 $curly_handles[$id] = curl_init(); // cURLハンドルを初期化 23 curl_setopt($curly_handles[$id], CURLOPT_URL, $url); // リクエスト先のURLを設定 24 curl_setopt($curly_handles[$id], CURLOPT_HEADER, 0); // レスポンスにHTTPヘッダーを含めない 25 curl_setopt($curly_handles[$id], CURLOPT_RETURNTRANSFER, true); // レスポンスを文字列として返すように設定 26 curl_setopt($curly_handles[$id], CURLOPT_TIMEOUT, 10); // 10秒でタイムアウトするように設定 27 curl_multi_add_handle($multi_handle, $curly_handles[$id]); // 個々のハンドルをマルチハンドルに追加 28 } 29 30 $running_handles = null; // 実行中のcURLハンドル数を追跡する変数 31 32 // 全てのリクエストが完了するまでループを続けます。 33 do { 34 // cURLリクエストを実行し、実行中のハンドル数を更新します。 35 // $running_handles は参照渡しで、現在実行中のハンドル数が設定されます。 36 curl_multi_exec($multi_handle, $running_handles); 37 38 // 完了したリクエストに関する情報を読み取ります。 39 // curl_multi_info_read は、完了した個々のcURLハンドルに関する情報(例: エラー、結果)を返します。 40 while ($info = curl_multi_info_read($multi_handle)) { 41 // 完了したハンドルがどのURLのリクエストだったかを特定します。 42 $completed_handle_id = array_search($info['handle'], $curly_handles, true); 43 44 // 完了したcURLハンドルからレスポンスボディ(コンテンツ)を取得します。 45 // curl_multi_getcontent は、転送が完了したcURLハンドルの内容を文字列で返します。 46 $content = curl_multi_getcontent($info['handle']); 47 48 // HTTPステータスコードや発生したエラー情報を取得します。 49 $http_status = curl_getinfo($info['handle'], CURLINFO_HTTP_CODE); 50 $error = curl_error($info['handle']) ?: null; 51 52 // 結果を$results配列に格納します。 53 $original_url = $urls[$completed_handle_id]; 54 $results[$original_url] = [ 55 'status_code' => $http_status, 56 'content' => $content, 57 'error' => $error, 58 ]; 59 60 // 完了したcURLハンドルをマルチハンドルから削除し、クローズします。 61 curl_multi_remove_handle($multi_handle, $info['handle']); 62 curl_close($info['handle']); 63 unset($curly_handles[$completed_handle_id]); // 完了したハンドルを追跡リストから削除 64 } 65 66 // まだ実行中のリクエストがある場合、ソケットのアクティビティを待ちます。 67 // これによりCPU使用率を抑え、効率的にリクエスト完了を待機します。 68 if ($running_handles > 0) { 69 curl_multi_select($multi_handle, 1.0); // 最大1秒間待機 70 } 71 } while ($running_handles > 0); // 実行中のハンドルがなくなるまでループを続けます 72 73 curl_multi_close($multi_handle); // cURLマルチハンドルをクローズ 74 75 return $results; 76} 77 78// --- サンプルコードの実行例 --- 79// 実際に存在するURLを使用することをお勧めします。 80// テスト用のダミーAPIエンドポイントなど: https://jsonplaceholder.typicode.com/ 81$urls_to_fetch = [ 82 'https://jsonplaceholder.typicode.com/posts/1', 83 'https://jsonplaceholder.typicode.com/comments/1', 84 'https://jsonplaceholder.typicode.com/users/1', 85 'https://httpstat.us/500', // HTTPエラーレスポンスの例 86 'https://example.com/', // シンプルなウェブサイトの例 87 'https://nonexistent-domain-12345.com/' // 存在しないURLの例(ネットワークエラー) 88]; 89 90echo "--- 複数のURLから並行してコンテンツを取得中 ---\n"; 91$responses = fetchMultipleUrlsConcurrently($urls_to_fetch); 92 93foreach ($responses as $url => $data) { 94 echo "\nURL: " . $url . "\n"; 95 echo " HTTP Status Code: " . $data['status_code'] . "\n"; 96 if ($data['error']) { 97 echo " Error: " . $data['error'] . "\n"; 98 } else { 99 // 取得したコンテンツの最初の100文字を表示(コンテンツが長い場合を考慮) 100 // contentはstring|false の可能性があるため、(string)でキャストして安全にsubstrを使用 101 echo " Content (first 100 chars): " . substr((string)$data['content'], 0, 100) . "...\n"; 102 } 103} 104echo "\n--- 処理完了 ---\n";
このPHPコードは、複数のURLからコンテンツを並行して効率的に取得する方法を示しています。cURLのマルチハンドル機能を利用することで、複数のHTTPリクエストを同時に実行し、全体の処理時間を短縮できます。
まず、curl_multi_init関数で複数のリクエストを管理するための「マルチハンドル」を初期化します。次に、取得したいURLごとにcurl_initで個別のcURLハンドルを作成し、それぞれのURLやレスポンスの形式などの設定を行います。設定済みの個別のハンドルはcurl_multi_add_handleを使ってマルチハンドルに追加されます。
全てのリクエストが完了するまでループを回し、その中でcurl_multi_execを実行してリクエストの転送を進行させます。リクエストが完了すると、curl_multi_info_read($multi_handle)関数が完了した個々のcURLハンドルに関する情報(例: エラーの有無や完了の種類)を返します。この関数は、引数にマルチハンドルを受け取り、完了したリクエストの情報が配列として返されますが、完了メッセージがない場合はfalseを返します。
完了したリクエストが検知されると、そのハンドルのレスポンスボディをcurl_multi_getcontent($handle)関数で取得します。curl_multi_getcontentは、引数として指定された完了済みcURLハンドルから、ウェブページのHTMLやAPIのJSONデータなどの転送されたコンテンツを文字列として返します。その後、curl_getinfoでHTTPステータスコードなどを確認し、個別のハンドルはcurl_multi_remove_handleでマルチハンドルから削除され、curl_closeで閉じられます。
全ての要求が完了するまでこのプロセスを繰り返し、curl_multi_selectを使って効率的にソケットのアクティビティを待機し、CPU使用率を抑えます。最終的に、curl_multi_closeでマルチハンドル自体も閉じられます。このコードは、複数のAPIへの同時アクセスなど、並行処理が必要なシナリオで非常に役立ちます。
このPHPコードはcURLマルチハンドルで並行リクエストを処理します。curl_closeとcurl_multi_closeでリソースは必ず解放しましょう。怠るとリソース枯渇に繋がります。curl_multi_info_readは完了リクエストを識別し、curl_multi_getcontentでレスポンスボディを取得します。通信エラーが多いため、curl_errorやHTTPステータスコードによるエラーハンドリングは重要です。多数リクエストはサーバー負荷に注意しましょう。