PHP를 사용하여 cURL 요청을 위해 헤더와 본문을 모두 얻는 방법이 있습니까? 나는이 옵션을 발견했다 :
curl_setopt($ch, CURLOPT_HEADER, true);
본문과 헤더 를 반환 하지만 본문을 얻으려면 구문 분석해야합니다. 보다 유용하고 안전한 방법으로 둘 다 얻을 수있는 방법이 있습니까?
"단일 요청"의 경우 GET / POST 이전에 HEAD 요청을 발행하지 않는 것을 의미합니다.
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의 답변은 이러한 것들을보다 안정적으로 처리 할 수 있습니다.
list($header, $body) = explode("\r\n\r\n", $response, 2)
있지만 요청 크기에 따라 시간이 조금 더 걸릴 수 있습니다.
list($header, $body) = explode("\r\n\r\n", $response, 2)
만 작동 변형으로
100
(계속). 이 헤더의 경우 request 옵션을 올바르게 정의 curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
하여이 헤더 응답 전송을 비활성화 할 수 있습니다 . 에 관해서는 302
,이 그러나 난 서버가 일부 신체를 보내 때때로 알고, 302 헤더 리디렉션을하기 때문에, 그것은 몸을 기대하지 않고, 일이되어서는 안 302
응답 있지만 어쨌든 브라우저에 의해 무시됩니다, 지금까지 컬이 왜 처리해야합니까? )
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은 헤더 (및 헤더 만!)를이 콜백 함수에 한 줄씩 전달합니다 (따라서 헤더 섹션의 맨 위에서 시작하여 각 헤더 행에 대해 함수가 호출됩니다). 콜백 함수는 그와 함께 무엇이든 할 수 있습니다 (그리고 주어진 줄의 바이트 수를 반환해야합니다). 테스트 된 작업 코드는 다음과 같습니다.
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);
위의 내용은 모든 프로토콜과 프록시에서도 작동하며 헤더 크기에 대해 걱정하거나 다른 컬 옵션을 많이 설정할 필요가 없습니다.
추신 : 객체 메소드로 헤더 라인을 처리하려면 다음을 수행하십시오.
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 매개 변수가 없으면 원하는 모든 정보가 포함 된 연관 배열이 있습니다)
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);
2로 폭발 3 번째 매개 변수가?
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이 헤더 청크 [blank line] 데이터를 반환한다는 사실에 근거하여 작동합니다.
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에 제안 된대로 콜백을 사용하는 것 같습니다.
그런 다음 요청 본문을 (신뢰하게) 얻으려면 Content-Length
헤더 값을 substr()
음의 시작 값 으로 전달해야 합니다.
list($head, $body) = explode("\r\n\r\n", $response, 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를 참조 하십시오.