LoginSignup
46
38

More than 5 years have passed since last update.

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

Posted at

まちがいさがし

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を書くのはもうやめよう)。

46
38
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
46
38