前提・実現したいこと
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 )
という関数と引数の関係は崩したくないと思っています。
あなたの回答
tips
プレビュー