PHPを使用してcURLリクエストのヘッダーとボディの両方を取得する方法はありますか?私はこのオプションを見つけました:
curl_setopt($ch, CURLOPT_HEADER, true);
ボディとヘッダ を返すつもりですが、それからボディを取得するためにそれを解析する必要があります。両方をより使いやすく(そして安全に)する方法はありますか?
"シングルリクエスト"の場合、GET/POSTの前にHEADリクエストを発行しないことを意味します。
これに対する一つの解決策はPHPドキュメントのコメントに投稿されています: http://www.php.net/manual/en/function.curl-exec.php#80442
コード例:
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
// ...
$response = curl_exec($ch);
// Then, after your curl_exec call:
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $header_size);
$body = substr($response, $header_size);
警告: 以下のコメントにあるように、これはプロキシサーバーで使用されたり、特定の種類のリダイレクトを処理する際には信頼できないかもしれません。 @ Geoffreyの答えはこれらをもっと確実に扱うかもしれません。
このスレッドで提供されている他の解決策の多くはnot正しくこれを行うこと)です。
\r\n\r\n
がオンになっているとき、またはサーバーが100コードで応答するときは、CURLOPT_FOLLOWLOCATION
で分割することは信頼できません。\n
だけを送信します。CURLINFO_HEADER_SIZE
を介してヘッダーのサイズを検出することは、特にプロキシが使用されている場合や、同じリダイレクトシナリオの中では特に信頼できるとは限りません。 最も正しい方法は CURLOPT_HEADERFUNCTION
を使うことです。
これはPHPクロージャを使ってこれを実行する非常にクリーンな方法です。また、サーバー間およびHTTPバージョン間で一貫した処理を行うために、すべてのヘッダーを小文字に変換します。
このバージョンは重複したヘッダを保持します
これはRFC 822とRFC 2616に準拠しています。mb_
文字列関数を利用するための編集を提案しないでください、それは誤りです!
$ch = curl_init();
$headers = [];
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// this function is called by curl for each header received
curl_setopt($ch, CURLOPT_HEADERFUNCTION,
function($curl, $header) use (&$headers)
{
$len = strlen($header);
$header = explode(':', $header, 2);
if (count($header) < 2) // ignore invalid headers
return $len;
$name = strtolower(trim($header[0]));
if (!array_key_exists($name, $headers))
$headers[$name] = [trim($header[1])];
else
$headers[$name][] = trim($header[1]);
return $len;
}
);
$data = curl_exec($ch);
print_r($headers);
CurlにはCURLOPT_HEADERFUNCTIONと呼ばれるこのための組み込みオプションがあります。このオプションの値はコールバック関数の名前でなければなりません。 Curlは、このコールバック関数にヘッダー(およびヘッダーのみ!)を1行ずつ渡します(そのため、この関数はヘッダー行の先頭から各ヘッダー行に対して呼び出されます)。それからあなたのコールバック関数はそれで何でもすることができます(そして与えられた行のバイト数を返さなければなりません)。これがテスト済みの作業コードです。
function HandleHeaderLine( $curl, $header_line ) {
echo "<br>YEAH: ".$header_line; // or do whatever
return strlen($header_line);
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://www.google.com");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADERFUNCTION, "HandleHeaderLine");
$body = curl_exec($ch);
上記はすべて、プロトコルやプロキシが異なる場合でも動作します。ヘッダサイズを気にしたり、さまざまなカールオプションを設定したりする必要はありません。
P.S .:オブジェクトメソッドでヘッダ行を処理するには、次のようにします。
curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(&$object, 'methodName'))
これはあなたが探しているものですか?
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
$response = curl_exec($ch);
list($header, $body) = explode("\r\n\r\n", $response, 2);
オプションを設定するだけです。
CURLOPT_HEADER、0
CURLOPT_RETURNTRANSFER、1
そしてcurl_getinfoをCURLINFO_HTTP_CODEと一緒に使用してください(またはopt paramを指定しなければ、必要なすべての情報を含む連想配列が得られます)
特にContent-Type
が必要な場合は、それを取得するための特別なcURLオプションがあります。
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
$content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
$parts = explode("\r\n\r\nHTTP/", $response);
$parts = (count($parts) > 1 ? 'HTTP/' : '').array_pop($parts);
list($headers, $body) = explode("\r\n\r\n", $parts, 2);
他のヘッダーより前にHTTP/1.1 100 Continue
を処理します。
改行としてCRLFの代わりにLFのみを送信するバグのあるサーバーで作業する必要がある場合は、次のようにpreg_split
を使用できます。
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
$parts = preg_split("@\r?\n\r?\nHTTP/@u", $response);
$parts = (count($parts) > 1 ? 'HTTP/' : '').array_pop($parts);
list($headers, $body) = preg_split("@\r?\n\r?\n@u", $parts, 2);
これが私の議論への貢献です...これは分離されたデータとリストされたヘッダを持つ単一の配列を返します。これはCURLがヘッダチャンク[空白行]データを返すことに基づいて機能します。
curl_setopt($ch, CURLOPT_HEADER, 1); // we need this to get headers back
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, true);
// $output contains the output string
$output = curl_exec($ch);
$lines = explode("\n",$output);
$out = array();
$headers = true;
foreach ($lines as $l){
$l = trim($l);
if ($headers && !empty($l)){
if (strpos($l,'HTTP') !== false){
$p = explode(' ',$l);
$out['Headers']['Status'] = trim($p[1]);
} else {
$p = explode(':',$l);
$out['Headers'][$p[0]] = trim($p[1]);
}
} elseif (!empty($l)) {
$out['Data'] = $l;
}
if (empty($l)){
$headers = false;
}
}
私のやり方は
$response = curl_exec($ch);
$x = explode("\r\n\r\n", $v, 3);
$header=http_parse_headers($x[0]);
if ($header=['Response Code']==100){ //use the other "header"
$header=http_parse_headers($x[1]);
$body=$x[2];
}else{
$body=$x[1];
}
必要に応じてforループを適用して爆発限界を取り除きます。
ここでの多くの答えの問題は、"\r\n\r\n"
が正当にhtmlの本体に現れることがあるということです、それであなたは正しくあなたがヘッダーを分割していることを確信できません。
curl_exec
の1回の呼び出しでヘッダーを別々に保存する唯一の方法は、 https://stackoverflow.com/a/25118032/3326494 で提案されているように、コールバックを使用することです。
そして(確実に)リクエストの本文だけを取得するには、Content-Length
ヘッダーの値を負の開始値としてsubstr()
に渡す必要があります。