Windowsでは、
の2つのファイルにPATHが通っていなければなりません。これらのファイルは既定ではphp.exeと同一のディレクトリにあります。もしcURLの関数の呼び出し時に「PHP Fatal error: Call to undefined function curl_init()」のようにエラーとなるならば、この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