Help us understand the problem. What is going on with this article?

PHPでcURL POSTするときは、ちゃんとエンコードしましょう(しなくても動くからこそ!!)

More than 3 years have passed since last update.

まちがいさがし

bad.php
$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => 'http://hoge.com/fuga',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => ['hoge' => 'fuga'],
]);

$response = curl_exec($ch);
curl_close($ch);

どこにでもあるPHPコードに見えるけど、間違いがあります。

good.php
$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => 'http://hoge.com/fuga',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => http_build_query(['hoge' => 'fuga']),
]);

$response = curl_exec($ch);
curl_close($ch);

正解は、http_build_query するだけ!

なんで?

一番の問題は、どちらのコードも動いてしまうこと。ただ、 bad.php はすごく時間がかかるので、やっちゃだめ。

headerを見てみると、good.php は Content-Type: application/x-www-form-urlencoded なのに対して、bad.phpContent-Type: multipart/form-data; boundary=------------------------ffe0ce1791e44a80 みたいになっているはず。

要するに、(別に http_build_query じゃなくてもいいけど)ちゃんとエンコードしてあげないと multipart/form-data で通信してしまう。これはファイルの転送とかに使うプロトコルで、オーバーヘッドが大きい。

実際、

echo curl_getinfo($ch, CURLINFO_STARTTRANSFER_TIME);

とかやってみてほしい。good.php は数ミリ秒とかなのに、 bad.php は1秒以上かかっているのがわかると思う。

もう一度言う

そんな初心者みたいなこと。と思うかもしれない。ただ、これは案外発見が難しいことだと思う。

なぜなら、どちらもPHPとしては正常に動くし、アプリケーションとしても仕様通りの動作をするから。

ただ、少しばかり転送に時間がかかる。

一番厄介なのが、動作はしているということ。cURLの部分なのでUnitTestでは検査しにくいし、開発環境では多少の遅延はあまり気にならない。このミスにQA環境なりにあげるまでに気づけるタイミングがあるとしたらコードレビューだけど、いつもの馴染みのcURLだと思ってレビューすると、http_build_query してるかどうかなんてほとんど気にしない。

で、QA環境なりに入れて、結合試験のフェーズになって、「あれ?HTTPタイムアウトしてんぞ」と気づく。

そうなると、ミドルウェアとかRTTとか、低レイヤーなところを疑ってしまって、あまりコードに目がいかない。(なんたって、開発環境で動いているし、UnitTestもちゃんと書いているし、コードレビューも通っているんだから!!)

ということで、cURLのオプションはちゃんと気にして実装しよう&ちゃんと気にしてレビューしよう(あるいは生のcURLを書くのはもうやめよう)。

mochieer
必殺おうち仕事人👨🏻‍💻
https://mochieer.tech
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away