PHPを使用してcURLリクエストのヘッダーと本文の両方を取得する方法はありますか?このオプションが見つかりました:
curl_setopt($ch, CURLOPT_HEADER, true);
を返すつもりです 本文とヘッダーますが、解析して本文を取得する必要があります。両方をより使いやすい(そして安全な)方法で取得する方法はありますか?
「単一リクエスト」の場合、GET / POSTの前にHEADリクエストを発行しないようにすることを意味することに注意してください。
PHPを使用してcURLリクエストのヘッダーと本文の両方を取得する方法はありますか?このオプションが見つかりました:
curl_setopt($ch, CURLOPT_HEADER, true);
を返すつもりです 本文とヘッダーますが、解析して本文を取得する必要があります。両方をより使いやすい(そして安全な)方法で取得する方法はありますか?
「単一リクエスト」の場合、GET / POSTの前にHEADリクエストを発行しないようにすることを意味することに注意してください。
回答:
これに対する1つの解決策は、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の回答は、これらをより確実に処理する可能性があります。
list($header, $body) = explode("\r\n\r\n", $response, 2)
ますが、リクエストのサイズによっては少し時間がかかる場合があります。
list($header, $body) = explode("\r\n\r\n", $response, 2)
100
(続き)。このヘッダーについては、リクエストオプションを正しく定義して回避できますcurl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
。このヘッダー応答の送信を無効にします。については302
、これは起こらないはずです.302ヘッダーはリダイレクトであるため、本文を予期していませんが、サーバーが302
応答付きの本文を送信することがありますが、ブラウザーによって無視されますが、これまでのところ、curlがこれを処理する必要があるのはなぜですか? )
CURLOPT_VERBOSE
プロセス情報をSTDERR
(CLIでわざわざ)に出力することを目的としており、議論された問題には役に立たない。
このスレッドを提供する他のソリューションの多くは、これを正しく行っていません。
\r\n\r\n
は信頼できませんCURLOPT_FOLLOWLOCATION
。\n
、新しい回線のみを送信します。CURLINFO_HEADER_SIZE
特にプロキシが使用されている場合や同じリダイレクトシナリオの一部である場合は、経由でヘッダーのサイズを検出することは必ずしも信頼できるとは限りません。最も正しい方法は、を使用することCURLOPT_HEADERFUNCTION
です。
これは、PHPクロージャーを使用してこれを実行する非常にクリーンな方法です。また、すべてのヘッダーを小文字に変換して、サーバー間およびHTTPバージョン間で一貫した処理を行います。
このバージョンは重複したヘッダーを保持します
これはRFC822とRFC2616に準拠してい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;
$headers[strtolower(trim($header[0]))][] = trim($header[1]);
return $len;
}
);
$data = curl_exec($ch);
print_r($headers);
$headers = [];
有効なphpですか?
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);
上記はすべて、さまざまなプロトコルとプロキシでも機能し、ヘッダーサイズを心配したり、さまざまなカールオプションをたくさん設定したりする必要はありません。
PS:オブジェクトメソッドでヘッダー行を処理するには、次のようにします。
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);
A server that does not understand or is unable to comply with any of the expectation values in the Expect field of a request MUST respond with appropriate error status. The server MUST respond with a 417 (Expectation Failed) status if any of the expectations cannot be met or, if there are other problems with the request, some other 4xx status.
100
コメントの「正しい」答えの下に解決策を持っています。
オプションを設定するだけです:
CURLOPT_HEADER、0
CURLOPT_RETURNTRANSFER、1
CURLINFO_HTTP_CODEを指定してcurl_getinfoを使用します(またはopt paramを使用しないと、必要なすべての情報を含む連想配列になります)
curl_getinfo()
。
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);
$parts = explode("\r\n\r\nHTTP/", $response);
爆発の3番目のパラメーターを2にすべきではありませんか?
HTTP/1.1 100 Continue
何度も現れることができます。
HTTP/1.1 100 Continue
何度も現れることができます。彼は、それが一度だけ現れるならケースを見るが、一般的なケースではそれは間違っている。たとえば、HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 200 OK...\r\n\r\n...
彼のコードが適切に機能しない
これが議論への私の貢献です...これは、データが分離され、ヘッダーがリストされた単一の配列を返します。これは、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;
}
}
ここでの多くの回答の問題"\r\n\r\n"
は、HTMLの本文に正当に表示される可能性があるため、ヘッダーを正しく分割していることを確認できないことです。
curl_exec
上記のhttps://stackoverflow.com/a/25118032/3326494で提案されているように、1回の呼び出しでヘッダーを個別に保存する唯一の方法はコールバックを使用することのようです
そして、(確実に)リクエストの本文だけを取得するには、Content-Length
ヘッダーの値をsubstr()
負の開始値として渡す必要があります。
list($head, $body) = explode("\r\n\r\n", $response, 2);
、explodeを2つの要素のみを返すように制限することで簡単に実行できます。つまり、を使用する場合、CURLはすでにこれを実行していますcurl_setopt($ch, CURLOPT_HEADERFUNCTION, $myFunction);
万が一CURLOPT_HEADERFUNCTION
、他のソリューションを使用できない/使用しない場合。
$nextCheck = function($body) {
return ($body && strpos($body, 'HTTP/') === 0);
};
[$headers, $body] = explode("\r\n\r\n", $result, 2);
if ($nextCheck($body)) {
do {
[$headers, $body] = explode("\r\n\r\n", $body, 2);
} while ($nextCheck($body));
}
参照パラメーター付きの応答ヘッダーを返します。
<?php
$data=array('device_token'=>'5641c5b10751c49c07ceb4',
'content'=>'测试测试test'
);
$rtn=curl_to_host('POST', 'http://test.com/send_by_device_token', array(), $data, $resp_headers);
echo $rtn;
var_export($resp_headers);
function curl_to_host($method, $url, $headers, $data, &$resp_headers)
{$ch=curl_init($url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $GLOBALS['POST_TO_HOST.LINE_TIMEOUT']?$GLOBALS['POST_TO_HOST.LINE_TIMEOUT']:5);
curl_setopt($ch, CURLOPT_TIMEOUT, $GLOBALS['POST_TO_HOST.TOTAL_TIMEOUT']?$GLOBALS['POST_TO_HOST.TOTAL_TIMEOUT']:20);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_HEADER, 1);
if ($method=='POST')
{curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
}
foreach ($headers as $k=>$v)
{$headers[$k]=str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $k)))).': '.$v;
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$rtn=curl_exec($ch);
curl_close($ch);
$rtn=explode("\r\n\r\nHTTP/", $rtn, 2); //to deal with "HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 200 OK...\r\n\r\n..." header
$rtn=(count($rtn)>1 ? 'HTTP/' : '').array_pop($rtn);
list($str_resp_headers, $rtn)=explode("\r\n\r\n", $rtn, 2);
$str_resp_headers=explode("\r\n", $str_resp_headers);
array_shift($str_resp_headers); //get rid of "HTTP/1.1 200 OK"
$resp_headers=array();
foreach ($str_resp_headers as $k=>$v)
{$v=explode(': ', $v, 2);
$resp_headers[$v[0]]=$v[1];
}
return $rtn;
}
?>
$rtn=explode("\r\n\r\nHTTP/", $rtn, 2);
正しいですか?explodeの3番目のパラメーターを削除すべきではありませんか?
explode("\r\n\r\n", $parts, 2);
ので、両方が正しいです。
curlを使用する必要がない場合。
$body = file_get_contents('http://example.com');
var_export($http_response_header);
var_export($body);
どの出力
array (
0 => 'HTTP/1.0 200 OK',
1 => 'Accept-Ranges: bytes',
2 => 'Cache-Control: max-age=604800',
3 => 'Content-Type: text/html',
4 => 'Date: Tue, 24 Feb 2015 20:37:13 GMT',
5 => 'Etag: "359670651"',
6 => 'Expires: Tue, 03 Mar 2015 20:37:13 GMT',
7 => 'Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT',
8 => 'Server: ECS (cpm/F9D5)',
9 => 'X-Cache: HIT',
10 => 'x-ec-custom-error: 1',
11 => 'Content-Length: 1270',
12 => 'Connection: close',
)'<!doctype html>
<html>
<head>
<title>Example Domain</title>...
http://php.net/manual/en/reserved.variables.httpresponseheader.phpを参照してください