PHP
PHP7
PHP7.2

【PHP7】 CURLOPT_POST=true を付与する場合は CURLOPT_POSTFIELDS は必須

罠にハマってなかなか辛かったので残しておきます。


curl が飛ばない?

プロダクトの目立たない機能で API を叩いている実装があったのですが、今日になってそれが死んでいることが判明。

開発環境やステージング環境では同じコードで正常に動いているので、うーん・・・ :thinking:


調査

ということで調査。

手元で実際に叩いている URL に curl コマンドでリクエストすると正常なレスポンスが返ってきた。

本番サーバーで叩いてみても正常だった。

仕方なくプロダクトコードにログを仕込んでデプロイ。

ログを見てみると curl が false を返している :thinking:

しかも実行速度が早いのでリクエストが飛んでいない様子。

本番サーバーは最近 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 の本番サーバー上で配置して実行してみると $resultfalse になります。

そもそも 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);

正常なレスポンスが取得できました :tada:

ちなみに、 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 がおかしくなったら疑ってみましょう。

あと、本番サーバーとステージングサーバーのバージョンは合わせましょう。

(古のコードと付き合うのはつらい)