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_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의 답변은 이러한 문제를 보다 확실하게 처리할 수 있을 것이다.
이 스레드에 제공된 다른 솔루션 중 많은 수가 이 작업을 제대로 수행하지 않습니다.
-
\r\n\r\n
할 수CURLOPT_FOLLOWLOCATION
가 켜져 있는 경우 또는 서버가 RFC-7231, MDN 100 코드로 응답하는 경우. - 것은 아니고, 「」의 「」의 「1」의 「1」의 「1」의 「1」의 「1」의 「1」의 「1」의 「1」의 「1」의 「1」의 「1」의 「1」의 「1」의 「1」의 「D」의 「1개의 서버만이 되는 것은 아닙니다.
\n
행의 할 수 ).\r
행 Q&A터미네이터로 설정합니다. - 를 검출하기 , 「」를 참조해 주세요.
CURLINFO_HEADER_SIZE
는 특히 프록시를 사용하거나 Curl-1204 동일한 리다이렉션시나리오에서 항상 신뢰할 수 있는 것은 아닙니다.
가장 올바른 방법은 을 사용하는 것입니다.
다음은 PHP 클로저를 사용하여 이를 수행하는 매우 깨끗한 방법입니다.또한 서버 및 HTTP 버전 간에 일관된 처리를 위해 모든 헤더를 소문자로 변환합니다.
이 버전에서는 중복된 헤더가 유지됩니다.
및 RFC822 RFC2616을 .용하사mb_
(및 유사한) 문자열 함수는 부정확할 뿐만 아니라 보안상의 RFC-7230 문제이기도 합니다!
$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_HEADER FUNCTION이라고 하는 옵션이 내장되어 있습니다.이 옵션의 값은 콜백 함수의 이름이어야 합니다.컬은 헤더(및 헤더만!)를 이 콜백 함수에 한 줄씩 전달합니다(따라서 이 함수는 헤더 섹션의 맨 위에서 시작하여 각 헤더 행에 대해 호출됩니다).콜백 함수는 콜백 함수로 모든 작업을 수행할 수 있습니다(및 지정된 회선의 바이트 수를 반환해야 합니다).테스트 완료 동작 코드는 다음과 같습니다.
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);
특히 필요한 경우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);
옵션만 설정:
CURLOPT_HEADER, 0
CURLOPT_RETURN TRANSFER, 1
CURLINFO_에는 curl_getinfo를 사용합니다.HTTP_CODE(또는 opt param을 사용하지 않으면 원하는 모든 정보를 포함하는 관련 배열이 생성됩니다.)
자세한 것은, http://php.net/manual/fr/function.curl-getinfo.php 를 참조해 주세요.
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이 헤더 청크[블랭크 라인]데이터를 반환하는 것에 근거해 동작합니다.
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 본문에 합법적으로 표시될 수 있으므로 헤더를 올바르게 분할하고 있는지 확인할 수 없습니다.
1개의 콜로 헤더를 개별적으로 보존하는 유일한 것 같습니다.curl_exec
https://stackoverflow.com/a/25118032/3326494 에서 상기와 같이 콜백을 사용하는 것입니다.
그런 다음 (신뢰할 수 있게) 요청 본문만 가져오려면 다음 값을 전달해야 합니다.Content-Length
헤더를 로 향하다.substr()
음수 시작값으로 표시됩니다.
사용할 수 없는 경우/사용하지 않는 경우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));
}
더 나은 방법은 임시 스트림에 파이핑할 수 있는 상세 CURL 응답을 사용하는 것입니다.그런 다음 응답에서 헤더 이름을 검색할 수 있습니다.몇 가지 수정이 필요할 수 있지만 나에게는 효과가 있습니다.
class genericCURL {
/**
* NB this is designed for getting data, or for posting JSON data
*/
public function request($url, $method = 'GET', $data = array()) {
$ch = curl_init();
if($method == 'POST') {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $string = json_encode($data));
}
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_VERBOSE, true);
//open a temporary stream to output the curl log, which would normally got to STDERR
$err = fopen("php://temp", "w+");
curl_setopt($ch, CURLOPT_STDERR, $err);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$server_output = curl_exec ($ch);
//rewind the temp stream and put it into a string
rewind($err);
$this->curl_log = stream_get_contents($err);
curl_close($ch);
fclose($err);
return $server_output;
}
/**
* use the curl log to get a header value
*/
public function getReturnHeaderValue($header) {
$log = explode("\n", str_replace("\r\n", "\n", $this->curl_log));
foreach($log as $line) {
//is the requested header there
if(stripos($line, '< ' . $header . ':') !== false) {
$value = trim(substr($line, strlen($header) + 3));
return $value;
}
}
//still here implies not found so return false
return false;
}
}
Geoffreys의 개선 답변:
헤더의 올바른 길이를 얻을 수 없었습니다.$headerSize = curl_getinfo($this->curlHandler, CURLINFO_HEADER_SIZE);
·헤더 사이즈는 스스로 계산해야 했습니다.
또한 가독성을 높이기 위해 몇 가지 개선 사항이 있습니다.
$headerSize = 0;
curl_setopt_array($this->curlHandler, [
CURLOPT_URL => $yourUrl,
CURLOPT_POST => 0,
CURLOPT_RETURNTRANSFER => 1,
// this function is called by curl for each header received
CURLOPT_HEADERFUNCTION =>
function ($curl, $header) use (&$headers, &$headerSize) {
$lenghtCurrentLine = strlen($header);
$headerSize += $lenghtCurrentLine;
$header = explode(':', $header, 2);
if (count($header) > 1) { // store only vadid headers
$headers[strtolower(trim($header[0]))][] = trim($header[1]);
}
return $lenghtCurrentLine;
},
]);
$fullResult = curl_exec($this->curlHandler);
$result = substr($fullResult, $headerSize);
GET 를 사용하고 있는 경우는, 다음의 조작을 실시해 주세요.
$curl = curl_init($url);
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => array(
"Cache-Control: no-cache"
),
));
$response = curl_exec($curl);
curl_close($curl);
참조 매개 변수를 사용하여 응답 헤더를 반환합니다.
<?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;
}
?>
굳이 컬을 사용할 필요가 없다면
$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 를 참조해 주세요.
언급URL : https://stackoverflow.com/questions/9183178/can-php-curl-retrieve-response-headers-and-body-in-a-single-request
'programing' 카테고리의 다른 글
PHP에서 이중 물음표(?) 연산자는 무엇을 의미합니까? (0) | 2022.09.15 |
---|---|
vuex 스토어가 빌드에 포함되도록 하려면 어떻게 해야 합니까? (0) | 2022.09.15 |
preg_replace를 사용하여 영숫자가 아닌 모든 문자 제거 (0) | 2022.09.15 |
Android에서 색 정수를 16진수 문자열로 변환하는 방법 (0) | 2022.09.15 |
MySQL 프로세스 목록을 찾아서 프로세스를 종료하려면 어떻게 해야 합니까? (0) | 2022.09.15 |