LoginSignup
123
123

More than 5 years have passed since last update.

PHP+cURLのエラーハンドリング

Posted at

エラーハンドリングの基本

PHPのlibcurl拡張でHTTPリクエストをする際、色々なエラーが起きることが考えられる。
curl_errnocurl_errorで直近のexecで発生したエラーを調べることができる。

curl_exec()の戻り値がfalseだったらエラーだと判定できるのだけど、詳細なところがわからないので、明示的にエラーが起きたかを調べた方がよさそう。

例外を使いたいなら、ラッパークラス/関数でハンドリングして適当なException型を投げればよいだろう。

<?php
// 単純なcurl関数のラッパー
// 毎回コネクションを切断するので非効率かも
function getHttpContent($url)
{
  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  $body = curl_exec($ch);
  $info = curl_getinfo($ch);

  $errno = curl_errno($ch);
  $error = curl_error($ch);
  curl_close($ch);
  if (CURLE_OK !== $errno) {
    throw new RuntimeException($error, $errno);
  }

  return [$body, $info];
}

後で「どんなURLにアクセスしようとしてエラーが起きたのか?」とか調べたいだろうから、もう少し例外型には情報を含めるよう工夫した方がいいかもしれない。

cURLは何をエラーとみなすのか?

libcurl公式ページに、エラー一覧が載っている。
libcurl - Error Codes

  • サポートしていないプロトコルを指定した
  • URLがURLの形式になっていない

などなど、基本的なところと、HTTP通信は成功したけれど40X系のステータスコードが返ってきた場合などが書いてある。

デフォルト状態だと、400系が返ってきたとしてもlibcurlはエラーとみなしてくれない。
冒頭のサンプルコードは404 Not Foundが返ってきたとしても例外は発生しない。

オプションでCURLOPT_FAILONERRORをtrueにセットすると、400以上のステータスコードの場合にエラーとみなしてくれるようになる。
が、この場合、400以上のステータスコードならレスポンスボディを読めなくなる。

400で詳細なエラーの理由をボディに送ってくるケースもあるので、FAILONERRORをfalseにして(デフォルト状態である)、手動でハンドリングした方がいいと思う。

<?php
// ステータスコードが400以上だった場合も例外が発生するバージョン
// ただしレスポンスボディがわからない
function getHttpContent($url)
{
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FAILONERROR => true,
    ]);
    $body = curl_exec($ch);
    $info = curl_getinfo($ch);

    $errno = curl_errno($ch);
    $error = curl_error($ch);
    curl_close($ch);
    if (CURLE_OK !== $errno) {
        throw new RuntimeException($error, $errno);
    }

    return [$body, $info];
}

CURLOPT_HTTP200ALIASESオプションの正体

なんか謎のオプションがあるが、思ってたのと違った。最初見たとき、DELETEのときは404も200 OKとみなしてくれるように設定したりできる便利な何かかと思ったんですが。。
PHP: curl_setopt - Manual

  • CURLOPT_HTTP200ALIASES
    • エラーではなく正常な応答として扱われる、HTTP 200 レスポンスの配列。

404とか400を200扱いしてくれるとかではなく、HTTPのRFCに従わないレスポンスが返ってきた時に、200とみなしてくれるオプションの模様。HTTPを上書きすることはできないようだった。

例として、SHOUTcastというストリーミングサーバーではHTTP/1.1 200 OKではなくICY 200 OKを返すことがあるらしい。これを200扱いしたい場合は以下のようにセットしておくとよいようだ。

curl_setopt($ch, CURLOPT_HTTP200ALIASES, ['ICY 200 OK']);

配列で渡すものはステータスラインの文字列。

123
123
2

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
123
123