罠にハマってなかなか辛かったので残しておきます。
curl が飛ばない?
プロダクトの目立たない機能で API を叩いている実装があったのですが、今日になってそれが死んでいることが判明。
開発環境やステージング環境では同じコードで正常に動いているので、うーん・・・
調査
ということで調査。
手元で実際に叩いている URL に curl コマンドでリクエストすると正常なレスポンスが返ってきた。
本番サーバーで叩いてみても正常だった。
仕方なくプロダクトコードにログを仕込んでデプロイ。
ログを見てみると curl が false を返している
しかも実行速度が早いのでリクエストが飛んでいない様子。
本番サーバーは最近 PHP のバージョンを 7.2 に上げたということで、開発環境とステージング環境の PHP のバージョンを確認してみたところ、 5.6 だった。
ここで、 PHP 7.2 では問題がある実装になっているのかも?と気付く。
問題のコード
こんな感じ
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $api_url);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
$result = curl_exec($ch);
これが PHP 5.6 では動作しました。
これを PHP 7.2 の本番サーバー上で配置して実行してみると $result
が false
になります。
そもそも GET でリクエストする API なんだから CURLOPT_POST
は不要では?と思い、コメントアウトしてみたところ
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $api_url);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// curl_setopt($ch, CURLOPT_POST, true);
$result = curl_exec($ch);
正常なレスポンスが取得できました
ちなみに、 CURLOPT_POSTFIELDS
を指定すると動作します。
PHP のバージョンによる違い
この POST=true, POSTFIELDS なしのコードをいくつかの環境で確認したところこんな感じでした。
動作する
- 5.6.11
- 5.6.26
- 7.1.16
動作しない
- 7.2.4
- 7.2.14
ということで、 7.2 系ではだめっぽいです。
結論
CURLOPT_POST=true を付与する場合は CURLOPT_POSTFIELDS は必須。
PHP 7.2 にして curl がおかしくなったら疑ってみましょう。
あと、本番サーバーとステージングサーバーのバージョンは合わせましょう。
(古のコードと付き合うのはつらい)