PHP的cURL可以检索单个请求中的响应标题和正文吗?
有什么办法来使用PHP的cURL请求获得标题和正文? 我发现这个选项:
curl_setopt($ch, CURLOPT_HEADER, true);
将返回身体加头 ,但是然后我需要parsing它来获得身体。 有没有办法让这两种方式更有用(和安全)?
请注意,对于“单个请求”,我的意思是避免在GET / POST之前发出HEAD请求。
一个解决scheme是张贴在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);
警告:正如以下注释中所述,与代理服务器一起使用或处理某些types的redirect时,这可能不可靠。 @杰弗里的答案可以更可靠地处理这些问题。
curl有一个内置的选项,称为CURLOPT_HEADERFUNCTION。 该选项的值必须是callback函数的名称。 Curl会逐行传递这个callback函数(所以这个函数将会从每个头部行开始,从头部的顶部开始)。 你的callback函数可以做任何事情(并且必须返回给定行的字节数)。 这是一个经过testing的工作代码:
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选项。
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);
许多提供此线程的其他解决scheme都没有正确执行此操作。
- 当
CURLOPT_FOLLOWLOCATION
打开或服务器以100代码响应时,\r\n\r\n
分割不可靠。 - 并非所有的服务器都符合标准,只需传输一个新的线路。
- 通过
CURLINFO_HEADER_SIZE
检测头文件的大小也并不总是可靠的,特别是当使用代理或在一些相同的redirect场景中。
最正确的方法是使用CURLOPT_HEADERFUNCTION
。
这是一个非常干净的使用PHP闭包执行此操作的方法。 它还将所有标题转换为小写字母,以便跨服务器和HTTP版本进行一致的处理。
这个版本将保留重复的标题
这符合RFC822和RFC2616,请不要build议编辑使用mb_
string函数,这是不正确的!
$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);
如果您特别需要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_RETURNTRANSFER,1
并使用curl_getinfo与CURLINFO_HTTP_CODE(或没有select参数,你将有一个关联数组与你想要的所有信息)
更多: 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
在其他标题之前HTTP/1.1 100 Continue
。
如果您需要使用只发送LF代替CRLF作为换行符的越野车服务器,则可以使用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循环并删除爆炸限制。
这里有很多答案的问题是, "\r\n\r\n"
可以合法地出现在HTML的正文中,所以你不能确定你是否正确地分割头。
似乎只有一个调用curl_exec
来分别存储标题的方法是使用一个callback,如上面在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'=>'testingtestingtest' ); $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