PHP cURL이 단일 요청으로 응답 헤더와 본문을 검색 할 수 있습니까?
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의 답변은이를보다 안정적으로 처리 할 수 있습니다.
이 스레드를 제공하는 다른 많은 솔루션 이 올바르게 수행 하지 않습니다 .
- 서버가 켜져 있거나 서버가 100 코드로 응답 할
\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);
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);
옵션을 설정하십시오.
CURLOPT_HEADER, 0
CURLOPT_RETURNTRANSFER, 1
CURLINFO_HTTP_CODE와 함께 curl_getinfo를 사용하십시오 (또는 opt 매개 변수가 없으면 원하는 모든 정보가 포함 된 연관 배열이 있습니다)
자세한 내용은 http://php.net/manual/fr/function.curl-getinfo.php
을 구체적으로 원한다면 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);
내 길은
$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 루프를 적용하고 분해 한계를 제거하십시오.
토론에 대한 나의 기여는 다음과 같습니다. 이것은 데이터가 분리되고 헤더가 나열된 단일 배열을 반환합니다. 이것은 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($headers, $body) = explode("\r\n\r\n", $result, 2);
최종 머리글과 본문 부분을 얻는 간단한 방법은 다음과 같습니다.
$result = explode("\r\n\r\n", $result);
// drop redirect etc. headers
while (count($result) > 2) {
array_shift($result);
}
// split headers / body parts
@ list($headers, $body) = $result;
참조 매개 변수를 사용하여 응답 헤더를 리턴하십시오.
<?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;
}
?>
실제로 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를 참조 하십시오.
'development' 카테고리의 다른 글
작업과 스레드 차이 (0) | 2020.03.16 |
---|---|
“<:] {%>”수염이있는 웃는 표현은 무엇입니까? (0) | 2020.03.16 |
C #에서 "사용"의 용도는 무엇입니까 (0) | 2020.03.16 |
JVM을 원격으로 디버깅 할 수 있도록 설정하는 Java 명령 행 옵션은 무엇입니까? (0) | 2020.03.16 |
목록을 표 형식의 데이터로 인쇄 (0) | 2020.03.16 |