Windowsでは、
の2つのファイルにPATHが通っていなければなりません。これらのファイルは既定ではphp.exeと同一のディレクトリにあります。もしcURLの関数の呼び出しで「PHP Fatal error: Call to undefined function curl_init()」のように、または定数の呼び出しで「PHP Fatal error: Uncaught Error: Undefined constant "***"」のようにエラーとなるならば、このPATHの設定が原因です。PHP: インストール手順 - Manual
cURLは、基本的に次の手順で使用します。
同一のクエリでも異なる結果を返す場合、キャッシュの有効期限を指示するようにします。さもなくばブラウザなどのキャッシュが参照されてしまい、サーバにリクエストされないことがあります。
file_get_contents()ならば、
$response = file_get_contents( $url );
で$urlの内容を取得できます。curlでこれと同じ結果を得るには、
$ch = curl_init( $url ); curl_setopt( $ch, CURLOPT_RETURNTRANSFER, TRUE ); $response = curl_exec( $ch ); curl_close( $ch );
のようにします。
file_get_contents()のリクエスト先にはファイル名を使用できますが、curl_init()のそれはつねにURLです。よってホスト名から指定する必要があり、さもなくばcurl_error()では「Could not resolve host: xx; Host not found」というエラーとなります。
curl_setopt()で、転送時のオプションを設定できます。
bool curl_setopt ( resource $ch , int $option , mixed $value )PHP: curl_setopt - Manual
$optionには下表の値を、$valueにはそのオプションの値を指定します。
| オプション | 説明 |
|---|---|
| CURLOPT_RETURNTRANSFER | TRUEならば、curl_exec()の戻り値が文字列となる。さもなくばデータをそのまま出力する。 |
| CURLOPT_FAILONERROR | TRUEならば、HTTPステータス コードが400以上のとき処理失敗と判断する。
既定では、ステータス コードの値を無視してページの内容を取得する。 |
| CURLOPT_FOLLOWLOCATION | TRUEならば、"Location: "ヘッダの内容へリダイレクトする。
※CURLOPT_MAXREDIRSで、リダイレクトする回数の上限を指定する。さもなくば無限にリダイレクトする。 |
| CURLOPT_MAXREDIRS | リダイレクトする回数の上限 (CURLOPT_FOLLOWLOCATIONとあわせて使用) |
| CURLOPT_TIMEOUT | cURL関数がタイムアウトするまでの秒数 |
| CURLOPT_USERAGENT | "User-Agent: "ヘッダの内容 |
| CURLOPT_COOKIE | "Cookie: " ヘッダの内容 |
| CURLOPT_REFERER | "Referer: "ヘッダの内容 |
| CURLOPT_HTTPHEADER | 任意のHTTPヘッダ。ヘッダの情報はarray( 'Content-Type: text/plain', 'Content-Length: 100' )のように、ヘッダをそれぞれ文字列で指定する。 |
| 目的 | $optionの値 | $valueの値 |
|---|---|---|
| gzip | CURLOPT_ENCODING | 'gzip, deflate' |
| ETag | CURLOPT_HTTPHEADER | array( 'If-None-Match: 123' ) |
設定するオプションが大量にある場合には、それらを配列で一括して設定できるcurl_setopt_array()があります。
bool curl_setopt_array ( resource $ch , array $options )PHP: curl_setopt_array - Manual
直近に発生したエラーについて、curl_error()によって文字列でその情報を取得できます。
string curl_error ( resource $ch )PHP: curl_error - Manual
$response = curl_exec( $ch );
if( $response === FALSE )
{
// エラー文字列を出力する
echo curl_error( $ch );
}
エラー発生の判定は、curl_exec()の戻り値で行えます。しかしオプションでCURLOPT_RETURNTRANSFERを指定していると、成功時には文字列が返されるため
$response = curl_exec( $ch ); if( ! $response )
のようにエラーを判定しようとすると、文字列の'0'や空の文字列が返されたときに誤判定してしまいます。よって前述のように比較演算子 (===) を用いて、FALSEと厳密に判定するようにします。
既定でGETのため、これを使用するのに特別な指定は必要ありません。クエリもURLに含めるだけです。
$params = array( 'data1'=>123, 'data2'=>'foo' ); $ch = curl_init( $url.'?'.http_build_query( $params ) ); curl_exec( $ch ); curl_close( $ch );
POSTメソッドを使用するには、CURLOPT_POSTFIELDで送信するデータを指定します。
curl_setopt( $ch, CURLOPT_POSTFIELDS, $params );CURLOPT_POSTFIELDS
CURLOPT_POSTFIELDを指定するとCURLOPT_POSTも暗黙的に指定されるため、これを別に指定する必要はありません。逆にこれをFALSEとしてもその指定は無視されるため、POSTを用いないならばCURLOPT_POSTFIELDを削除します。
$params = array( 'data1'=>123, 'data2'=>'foo' ); $ch = curl_init( $url ); curl_setopt( $ch, CURLOPT_POSTFIELDS, $params ); curl_exec( $ch ); curl_close( $ch );
$paramsの型によって、リクエストされるときのContent-Typeが変化します。
| 引数の型 | Content-Type |
|---|---|
| 配列 | multipart/form-data |
| 文字列 | application/x-www-form-urlencoded |
パラメータの名前と値を「'name'=>value」とした連想配列とします。このとき値をURLエンコードする必要はありません。
$params = array( 'a'=>'abc', 'b'=>100, 'c'=>'&' );
POST /sample.php HTTP/1.1 Host: localhost Accept: */* Content-Length: 256 Expect: 100-continue Content-Type: multipart/form-data; boundary=----------------------------aaaaaaaaaaaa
配列でデータを渡すとき、その要素の文字列は「@」で始めてはなりません。それはファイルを指定するときの書式であり、そのファイルの指定が正しくなければ通信に失敗します。そしてcurl_error()では「failed creating formpost data」または「couldn't open file "xx"」が返されます。
フィールドを配列で渡すときは、curl_setopt()で
curl_setopt( $ch, CURLOPT_HTTPHEADER, array( 'Content-Type: application/x-www-form-urlencoded' ) );
のようにヘッダを明示的に指定しても、リクエストは
Content-Type: application/x-www-form-urlencoded; boundary=----------------------------xxxxxxxxxxxx
のようにmultipart/form-dataの形式になります。
パラメータの名前と値を「name=value」とした文字列とします。値はURLエンコードし、複数のパラメータは&で連結します。
$params = 'a=abc&b=100&c='.rawurlencode( '&' );
POST /sample.php HTTP/1.1 Host: localhost Accept: */* Content-Length: 256 Content-Type: application/x-www-form-urlencoded
ファイルを送信するには、ファイル名の先頭を@としてフルパスで指定します。そのときファイル タイプを明示するには、ファイル名の後に「;type=MIME Type」の形式で記述します。PHP: curl_setopt - Manual
データは必ず配列でなければなりません。
ファイルの指定に誤りがあるときは、curl_error()で「failed creating formpost data」というエラーとなります。
$params = array( 'foo'=>'@/home/user/sample.png' );
$params = array( 'foo'=>'@C:/sample.png' ); // Windows環境でのローカル
ファイルを受信する側は、$_FILESでデータにアクセスできます。
PHP: ファイルアップロードの処理 - ManualHEADメソッドを使用するには、curl_setopt()でCURLOPT_NOBODYをTRUEと指定します。こうすることで出力から本文が削除され、メソッドはHEADとなります。
curl_setopt( $ch, CURLOPT_NOBODY, TRUE );
DELETEメソッドを使用するには、curl_setopt()でCURLOPT_CUSTOMREQUESTを'DELETE'と指定します。
$ch = curl_init( $url ); curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, 'DELETE' ); curl_exec( $ch ); curl_close( $ch );
curl_getinfo()で、直近の通信に関する情報を取得できます。
mixed curl_getinfo ( resource $ch [, int $opt = 0 ] )PHP: curl_getinfo - Manual
$optで取得する情報を指定できます。それを省略すると、すべての値が配列で返されます。
なお取得対象のcURLハンドルがすでに閉じられていると、Warning: curl_getinfo(): 2 is not a valid cURL handle resourceのように警告され処理に失敗します。
| 戻り値の名前 | 引数$optの定数 | 説明 |
|---|---|---|
| url | CURLINFO_EFFECTIVE_URL | 直近の有効なURL。通常はリクエストしたURLが返されるが、リダイレクトされた場合にはその転送先のURL |
| content_type | CURLINFO_CONTENT_TYPE | 要求されたドキュメントのContent-Type。NULLはサーバが適切なContent-Typeヘッダを返さなかったことを示す |
| http_code | CURLINFO_HTTP_CODE | 最後に受け取ったHTTPステータスコード (HTTP status code) |
| header_size | CURLINFO_HEADER_SIZE | 受信したヘッダのサイズ |
| request_size | CURLINFO_REQUEST_SIZE | 発行されたリクエストのサイズ (現在はHTTPリクエストの場合のみ) |
| filetime | CURLINFO_FILETIME | ドキュメントを取得するのにかかった時間。取得できなかった場合は-1 |
| ssl_verify_result | CURLINFO_SSL_VERIFYRESULT | CURLOPT_SSL_VERIFYPEERを設定したときに要求される、SSL証明書の認証結果 |
| redirect_count | ||
| total_time | CURLINFO_TOTAL_TIME | 直近の伝送にかかった、秒数 |
| namelookup_time | CURLINFO_NAMELOOKUP_TIME | 名前解決が完了するまでにかかった、秒数 |
| connect_time | CURLINFO_CONNECT_TIME | 接続を確立するまでにかかった、秒数 |
| pretransfer_time | CURLINFO_PRETRANSFER_TIME | 開始からファイル伝送がはじまるまでにかかった、秒数 |
| size_upload | CURLINFO_SIZE_UPLOAD | アップロードされた、バイト数 |
| size_download | CURLINFO_SIZE_DOWNLOAD | ダウンロードされた、バイト数 |
| speed_download | CURLINFO_SPEED_DOWNLOAD | 平均のダウンロード速度 |
| speed_upload | CURLINFO_SPEED_UPLOAD | 平均のアップロード速度 |
| download_content_length | CURLINFO_CONTENT_LENGTH_DOWNLOAD | ダウンロードされるサイズ。Content-Lengthフィールドの内容を取得する |
| upload_content_length | CURLINFO_CONTENT_LENGTH_UPLOAD | アップロードされるサイズ |
| starttransfer_time | CURLINFO_STARTTRANSFER_TIME | 最初のバイトの伝送がはじまるまでの、秒数 |
| redirect_time | CURLINFO_REDIRECT_TIME | 伝送が始まるまでのリダイレクト処理の、秒数 |
| certinfo | ||
| request_header | CURLINFO_HEADER_OUT | 送信したリクエスト文字列
※この値を取得するには、事前に curl_setopt($ch, CURLINFO_HEADER_OUT, TRUE); としておく必要がある。 |
第2引数で取得する情報を指定すると、
$info = curl_getinfo( $ch, CURLINFO_EFFECTIVE_URL );
echo $info;
// http://www.yahoo.com/
のように結果を得られ、指定しないと次のようになります。
$info = curl_getinfo( $ch ); print_r( $info ); // Array // ( // [url] => http://www.yahoo.com/ // [content_type] => text/html;charset=utf-8 // [http_code] => 200 // [header_size] => 2402 // [request_size] => 52 // [filetime] => -1 // [ssl_verify_result] => 0 // [redirect_count] => 0 // [total_time] => 2.262 // [namelookup_time] => 0.031 // [connect_time] => 0.171 // [pretransfer_time] => 0.171 // [size_upload] => 0 // [size_download] => 226941 // [speed_download] => 100327 // [speed_upload] => 0 // [download_content_length] => -1 // [upload_content_length] => 0 // [starttransfer_time] => 0.593 // [redirect_time] => 0 // [request_header] => GET / HTTP/1.1\r\nHost: www.yahoo.com\r\nAccept: */*\r\n\r\n // )
期待する結果を得られない場合には、ヘッダを確認するのが有効です。
$ch = curl_init( 'http://example.com' ); curl_setopt( $ch, CURLOPT_HEADER, TRUE ); curl_setopt( $ch, CURLINFO_HEADER_OUT, TRUE ); curl_setopt( $ch, CURLOPT_RETURNTRANSFER, TRUE ); $response = curl_exec( $ch ); header( 'Content-Type: text/plain; charset=utf-8' ); echo curl_getinfo( $ch , CURLINFO_HEADER_OUT ); // リクエスト ヘッダ echo $response; // レスポンス ヘッダを最初に含む、すべての結果 curl_close( $ch );
resource curl_multi_init ( void )PHP: curl_multi_init - Manual
int curl_multi_add_handle ( resource $mh , resource $ch )PHP: curl_multi_add_handle - Manual
curl_multi_exec()で処理を実行します。
int curl_multi_exec ( resource $mh , int &$still_running )PHP: curl_multi_exec - Manual
$still_runningで、処理中のハンドルの数を確認できます。よってすべての処理の完了を待つには、これが0となるまでループさせます。
cURLハンドルからデータを文字列で取得するには、curl_setopt()でCURLOPT_RETURNTRANSFERを指定し、curl_multi_getcontent()で結果を取得します。
string curl_multi_getcontent ( resource $ch )PHP: curl_multi_getcontent - Manual
これはCURLOPT_RETURNTRANSFERが指定されているときの、curl_exec()の戻り値と同じです。
array curl_multi_info_read (
resource $mh
[, int &$msgs_in_queue = NULL ]
)
PHP: curl_multi_info_read - Manual
取得する結果が存在しないときは、FALSEが返されます。
print_r( curl_multi_info_read( $mh ) ); // Array // ( // [msg] => 1 // [result] => 0 // [handle] => Resource id #2 // )
['result']は下表の値のいずれかです。その値は定数「CURLE_*」で定義され、その意味はlibcurl - Error Codesにあります。
| 値 | 定数 |
|---|---|
| 0 | CURLE_OK |
| 1 | CURLE_UNSUPPORTED_PROTOCOL |
| 2 | CURLE_FAILED_INIT |
| 3 | CURLE_URL_MALFORMAT |
| 4 | CURLE_URL_MALFORMAT_USER |
| 5 | CURLE_COULDNT_RESOLVE_PROXY |
| 6 | CURLE_COULDNT_RESOLVE_HOST |
| 7 | CURLE_COULDNT_CONNECT |
| 8 | CURLE_FTP_WEIRD_SERVER_REPLY |
| 9 | CURLE_FTP_ACCESS_DENIED |
| 10 | CURLE_FTP_USER_PASSWORD_INCORRECT |
| 11 | CURLE_FTP_WEIRD_PASS_REPLY |
| 12 | CURLE_FTP_WEIRD_USER_REPLY |
| 13 | CURLE_FTP_WEIRD_PASV_REPLY |
| 14 | CURLE_FTP_WEIRD_227_FORMAT |
| 15 | CURLE_FTP_CANT_GET_HOST |
| 16 | CURLE_FTP_CANT_RECONNECT |
| 17 | CURLE_FTP_COULDNT_SET_BINARY |
| 18 | CURLE_PARTIAL_FILE |
| 19 | CURLE_FTP_COULDNT_RETR_FILE |
| 20 | CURLE_FTP_WRITE_ERROR |
| 21 | CURLE_FTP_QUOTE_ERROR |
| 22 | CURLE_HTTP_NOT_FOUND |
| 23 | CURLE_WRITE_ERROR |
| 24 | CURLE_MALFORMAT_USER |
| 25 | CURLE_FTP_COULDNT_STOR_FILE |
| 26 | CURLE_READ_ERROR |
| 27 | CURLE_OUT_OF_MEMORY |
| 28 | CURLE_OPERATION_TIMEOUTED |
| 29 | CURLE_FTP_COULDNT_SET_ASCII |
| 30 | CURLE_FTP_PORT_FAILED |
| 31 | CURLE_FTP_COULDNT_USE_REST |
| 32 | CURLE_FTP_COULDNT_GET_SIZE |
| 33 | CURLE_HTTP_RANGE_ERROR |
| 34 | CURLE_HTTP_POST_ERROR |
| 35 | CURLE_SSL_CONNECT_ERROR |
| 36 | CURLE_FTP_BAD_DOWNLOAD_RESUME |
| 37 | CURLE_FILE_COULDNT_READ_FILE |
| 38 | CURLE_LDAP_CANNOT_BIND |
| 39 | CURLE_LDAP_SEARCH_FAILED |
| 40 | CURLE_LIBRARY_NOT_FOUND |
| 41 | CURLE_FUNCTION_NOT_FOUND |
| 42 | CURLE_ABORTED_BY_CALLBACK |
| 43 | CURLE_BAD_FUNCTION_ARGUMENT |
| 44 | CURLE_BAD_CALLING_ORDER |
| 45 | CURLE_HTTP_PORT_FAILED |
| 46 | CURLE_BAD_PASSWORD_ENTERED |
| 47 | CURLE_TOO_MANY_REDIRECTS |
| 48 | CURLE_UNKNOWN_TELNET_OPTION |
| 49 | CURLE_TELNET_OPTION_SYNTAX |
| 50 | CURLE_OBSOLETE |
| 51 | CURLE_SSL_PEER_CERTIFICATE |
| 52 | CURLE_GOT_NOTHING |
| 53 | CURLE_SSL_ENGINE_NOTFOUND |
| 54 | CURLE_SSL_ENGINE_SETFAILED |
| 55 | CURLE_SEND_ERROR |
| 56 | CURLE_RECV_ERROR |
| 57 | CURLE_SHARE_IN_USE |
| 58 | CURLE_SSL_CERTPROBLEM |
| 59 | CURLE_SSL_CIPHER |
| 60 | CURLE_SSL_CACERT |
| 61 | CURLE_BAD_CONTENT_ENCODING |
| 62 | CURLE_LDAP_INVALID_URL |
| 63 | CURLE_FILESIZE_EXCEEDED |
| 64 | CURLE_FTP_SSL_FAILED |
次の3つの処理が必要です。
マルチハンドルからcURLハンドルを削除するには、curl_multi_remove_handle()を呼び出します。
int curl_multi_remove_handle ( resource $mh , resource $ch )PHP: curl_multi_remove_handle - Manual
void curl_multi_close ( resource $mh )PHP: curl_multi_close - Manual
cURLハンドルのクローズは、curl_close()で行います。
$ch1 = curl_init( $url1 );
$ch2 = curl_init( $url2 );
curl_setopt( $ch1, CURLOPT_RETURNTRANSFER, TRUE );
curl_setopt( $ch2, CURLOPT_RETURNTRANSFER, TRUE );
$mh = curl_multi_init();
curl_multi_add_handle( $mh, $ch1 );
curl_multi_add_handle( $mh, $ch2 );
$running = null;
do
{
curl_multi_exec( $mh, $running );
} while( $running );
$response1 = curl_multi_getcontent( $ch1 );
$response2 = curl_multi_getcontent( $ch1 );
curl_multi_remove_handle( $mh, $ch1 );
curl_multi_remove_handle( $mh, $ch2 );
curl_multi_close( $mh );
curl_close( $ch1 );
curl_close( $ch2 );
より汎用的には、次のようにします。
$urls = array( $url1, $url2 );
$chs = array();
foreach( $urls as $url ) $chs[] = curl_init( $url );
$mh = curl_multi_init();
foreach( $chs as $ch )
{
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, TRUE );
curl_setopt( $ch, CURLOPT_TIMEOUT, 1 );
curl_multi_add_handle( $mh, $ch );
}
$running = null;
do
{
curl_multi_exec( $mh, $running );
} while( $running );
$responses = array();
foreach( $chs as $ch )
{
$responses[] = curl_multi_getcontent( $ch );
curl_multi_remove_handle( $mh, $ch );
curl_close( $ch );
}
curl_multi_close( $mh );
前述の例ではすべての接続を同時に行おうとしますが、次の例では最大接続数を維持しながら、接続の完了を待って次の接続を行います。
次の関数は指定URLへ順次リクエストを送り、そのレスポンスのHTTPコードを出力します。
function CheckResponse( $urls, $maxConnection )
{
$mh = curl_multi_init();
$chs = array();
$running = 0;
do
{
if( $running < maxConnection && 0 < count( $urls ) )
{
$ch = curl_init( array_shift( $urls ) );
curl_setopt( $ch, CURLOPT_NOBODY, TRUE );
curl_setopt( $ch, CURLOPT_TIMEOUT, 30 );
curl_multi_add_handle( $mh, $ch );
$chs[] = $ch;
}
usleep( 1000 );
curl_multi_exec( $mh, $running );
foreach( $chs as $key=>$ch )
{
$info = curl_getinfo( $ch );
if( $info[ 'http_code' ] != 0 )
{
echo "{$info[ 'http_code' ]} : {$info[ 'url' ]}\n";
@ob_flush();
@flush();
curl_multi_remove_handle( $mh, $ch );
curl_close( $ch );
unset( $chs[ $key ] );
}
}
} while( 0 < $running );
print_r( curl_multi_info_read( $mh ) );
curl_multi_close( $mh );
}
次のように呼び出します。
$urls = array(
'http://example.com/1/',
'http://example.com/2/',
'http://example.com/3/',
'http://example.com/4/',
'http://example.com/5/',
);
CheckResponse( $urls, 3 );
cURLは既定ではすべての認証局 (Certificate Authority : CA) を信頼しないため、HTTPS接続できません。接続を試みても失敗し、curl_error()では
SSL certificate problem, verify that the CA cert is OK. Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
のように返されます。これを解決するには証明書を入手し、それを利用するように転送オプションで指示します。
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, TRUE ); curl_setopt( $ch, CURLOPT_CAINFO, 'ca.crt' );
もしくは証明書の検証が不要ならば、
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
として、検証自体を無効にします。
curl_setopt()で、CURLOPT_FILEに保存先のファイルのポインタを指定します。
$downloadPath = 'http://example.com/'; // ダウンロードするファイルのURL $savePath = 'sample.txt'; // 保存先のファイルのパス $ch = curl_init( $downloadPath ); $fp = fopen( $savePath, 'w' ); curl_setopt( $ch, CURLOPT_FILE, $fp ); curl_setopt( $ch, CURLOPT_HEADER, FALSE ); curl_close( $ch ); fclose( $fp );PHP: 基本的な curl の使用法 - Manual