質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
cURL

cURLはHTTP, FTPやTelnetなど複数のプロトコルを用いてデータを転送するライブラリとコマンドラインツールを提供します。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

0回答

735閲覧

curl_multi_exec で「どのリクエストによるレスポンスか?」を照合する方法

DryCleaning

総合スコア0

cURL

cURLはHTTP, FTPやTelnetなど複数のプロトコルを用いてデータを転送するライブラリとコマンドラインツールを提供します。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2020/09/27 07:47

編集2020/09/27 08:10

前提・実現したいこと

curl_multi_execで並列処理を実装しました。
並列で得られた個々のレスポンスについて、「どのリクエストによるレスポンスか?」を照合したいです。

発生している問題・エラーメッセージ

基本的な流れは実装でき、照合も成功しました。
しかしリダイレクトが発生したときに照合させる方法がわかりません。

具体的には以下のソースコードにコメントがある通り
// ➀ api_urlがリダイレクトされる場合、この$info['url']はリダイレクト後のものになってしまう(106行目)
// ➁ この一致が➀によって成り立たず、どのリクエストによるレスポンスなのかが照合できない(40行目)
という問題です。

この問題によって
// 照合されたリクエスト情報を使って下記のようにいろいろやりたい(47行目)
という処理に続くことができないでいます。

該当のソースコード

// まず前提としてcURLの実行情報がある $all_requests = [ [ 'api_url'=>'https://example.com/api-A', 'kind'=>'xxx', 'date'=>'2020-01-10 02:20:22.123456'], ]; get_results( $all_requests ); // cURLを実行し、レスポンスをいろいろやりたい function get_results( $all_requests ){ // cURLのオプション配列を作る $all_options = []; foreach ( $all_requests as $requests ) { $api_url = $requests['api_url']; $kind = $requests['kind']; if ( $kind === 'xxx' ) { $headers = []; } elseif ( $kind === 'yyy' ){ $headers = []; } $all_options[] = [ CURLOPT_URL => $api_url, CURLOPT_HTTPHEADER => $headers, CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, // リダイレクト先を取得 CURLOPT_MAXREDIRS => 5, // リダイレクトの最大回数を指定 ]; } // cURLを実行 $multi_curl_responses = get_multi_curl_responses( $all_options ); // 各レスポンスを処理 foreach ( $multi_curl_responses['responses'] as $info ) { $api_url = $info['url']; $response = $info['response']; $requests2 = []; foreach ( $all_requests as $requests ) { // ➁ この一致が➀によって成り立たず、どのリクエストによるレスポンスなのかが照合できない if( $requests['api_url'] === $api_url ){ $requests2 = $requests; break; } } // 照合されたリクエスト情報を使って下記のようにいろいろやりたい $kind = $requests2['kind']; $date = $response2['date']; $file = "response-{$date}.txt"; file_put_contents($file, $response); } return 'Good job'; } // cURLを実行 function get_multi_curl_responses( $all_options ){ $mh = curl_multi_init(); foreach ( $all_options as $options ) { $ch = curl_init(); curl_setopt_array( $ch, $options ); curl_multi_add_handle($mh, $ch); } // リクエスト実行 do { $stat = curl_multi_exec($mh, $running); } while ($stat === CURLM_CALL_MULTI_PERFORM); if ( ! $running || $stat !== CURLM_OK) { throw new RuntimeException('error'); } do switch (curl_multi_select($mh, 10)) { case -1: // curl_multi_select の失敗 usleep(10); do { $stat = curl_multi_exec($mh, $running); } while ($stat === CURLM_CALL_MULTI_PERFORM); continue 2; case 0: // タイムアウトなら continue でもう一度 continue 2; default: // 成功 or 失敗 do { $stat = curl_multi_exec($mh, $running); } while ($stat === CURLM_CALL_MULTI_PERFORM); do if ($raised = curl_multi_info_read($mh, $remains)) { $info = curl_getinfo($raised['handle']); $response = curl_multi_getcontent($raised['handle']); if ($response !== false) { $response = json_decode($response); } $responses[] = [ 'response' => $response // ➀ api_urlがリダイレクトされる場合、この$info['url']はリダイレクト後のものになってしまう 'url' => $info['url'] ?? '', ]; curl_multi_remove_handle($mh, $raised['handle']); curl_close($raised['handle']); } while ($remains); } while ($running); curl_multi_close($mh); return $responses; }

試したこと

基本的にはリダイレクトしない場合であれば照合できる方法、つまり実行urlによる照合を目指しています。
リダイレクトしない場合であれば$info['url']にそれが入っているので、リダイレクトした場合はどこに入っているかを見つけるべく、以下default以降のコードにerrog_logを4か所書いて値をチェックしてみました。

しかし結果は次の通りで、どうしても見つけられません。
・$mhをチェック→空
・$runningをチェック→1
・$infoをチェック→リダイレクト前のurlは見当たらず
・$raisedをチェック→空

どこかに入っているのでしょうか。
それとも実行urlによる照合以外で可能な方法がありますでしょうか。

php

1 default: // 成功 or 失敗 2 do { 3 error_log( '$mh = ' . json_encode($mh) ); // $mhをチェック→空 4 error_log( '$running = ' . json_encode($running) ); // $runningをチェック→1 5 6 $stat = curl_multi_exec($mh, $running); 7 } while ($stat === CURLM_CALL_MULTI_PERFORM); 8 9 do if ($raised = curl_multi_info_read($mh, $remains)) { 10 11 $info = curl_getinfo($raised['handle']); 12 $response = curl_multi_getcontent($raised['handle']); 13 14 if ($response !== false) { 15 $response = json_decode($response); 16 } 17 18 error_log( '$info = ' . json_encode($info) ); // $infoをチェック→リダイレクト前のurlは見当たらず 19 error_log( '$raised = ' . json_encode($raised) ); // $raisedをチェック→空 20 21 $responses[] = [ 22 'response' => $response 23 // ➀ api_urlがリダイレクトされる場合、この$info['url']はリダイレクト後のものになってしまう 24 'url' => $info['url'] ?? '', 25 ]; 26 27 curl_multi_remove_handle($mh, $raised['handle']); 28 curl_close($raised['handle']); 29 } while ($remains); 30 31 } while ($running); 32 33 curl_multi_close($mh); 34 return $responses; 35}

補足情報(FW/ツールのバージョンなど)

最新バージョンである PHP 7.4.7 を使用しています。

あとワガママかもしれませんが、
get_results( $all_requests )
get_multi_curl_responses( $all_options )
という関数と引数の関係は崩したくないと思っています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問