Can PHP cURL retrieve response headers AND body in a single request?
Asked Answered
R

16

407

Is there any way to get both headers and body for a cURL request using PHP? I found that this option:

curl_setopt($ch, CURLOPT_HEADER, true);

is going to return the body plus headers, but then I need to parse it to get the body. Is there any way to get both in a more usable (and secure) way?

Note that for "single request" I mean avoiding issuing a HEAD request prior of GET/POST.

Ruano answered 7/2, 2012 at 20:13 Comment(4)
There is a built in solution for this, see this answer: https://mcmap.net/q/86326/-can-php-curl-retrieve-response-headers-and-body-in-a-single-request (added this comment 'coz this post still gets many views)Fun
Look at this nice comment: secure.php.net/manual/en/book.curl.php#117138Parabasis
a-curl_multi-working-example---that-actually-worksBevatron
I was told my question was a duplicate to this question. If it is not a duplicate can someone please reopen it? #43770746 In my question I have a concrete requirement to use a method that returns an object with headers and body separate and not one string.Environmentalist
B
566

One solution to this was posted in the PHP documentation comments: http://www.php.net/manual/en/function.curl-exec.php#80442

Code example:

$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);

Warning: As noted in the comments below, this may not be reliable when used with proxy servers or when handling certain types of redirects. @Geoffrey's answer may handle these more reliably.

Borden answered 7/2, 2012 at 20:21 Comment(11)
Is this reliable? I mean using header size. Thanks.Ruano
You can also list($header, $body) = explode("\r\n\r\n", $response, 2), but this might take a bit longer, depending on your request size.Borden
Thanks, answer accepted. So bad headers are in raw format btw. Looking for a good parsing function.Ruano
this is bad solution because if you use proxy server and your proxy server(fiddler for example) add own headers to response - this headers broke all offsets and you should use list($header, $body) = explode("\r\n\r\n", $response, 2) as only working variantMeader
This is not my fault. It's a bug in PHP. See bugs.php.net/bug.php?id=63894. If you send a code sample to them, they will probably fix it.Borden
@Meader Your solution doesn't work when there are multiple headers in the response, such as when the server does a 302 redirect. Any suggestions?Tybie
@Nate, yes, i know this. AFAIK, but there is only one possible additional header - with code 100 (Continue). For this header you can go around with correctly defining request option: curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); , disabling sending this header response. As for 302, this should not be happened, because 302 header is redirect, it not expecting body, however i know, sometimes servers send some body with 302 response, but it will be anyway ignored by browsers, so far, why curl should handle this?)Meader
@Nate, In your case, most possible, that you have CURLOPT_FOLLOWLOCATION setted to true, so far, you have two http queries pre one curl query.Meader
CURLOPT_VERBOSE is intended to output process information to STDERR (may bother in CLI) and for discussed problem is useless.Getraer
msangel's poroblem with iblue's solution has been fixed in lib_curl 7.30.0 github.com/curl/curl/pull/60 -- curl now correctly includes any proxy headers in the CURLINFO_HEADER_SIZE calculation.Attenborough
Note also that proxies could add a second http response code with something like "Connection established" so that's all you'll get in header, and the body will contain the actual header then the body if you use the explode trick above (bit me before).Purim
M
409

Many of the other solutions offered this thread are not doing this correctly.

  • Splitting on \r\n\r\n is not reliable when CURLOPT_FOLLOWLOCATION is on or when the server responds with a 100 code RFC-7231, MDN.
  • Not all servers are standards compliant and transmit just a \n for new lines (and a recipient may discard the \r in the line terminator) Q&A.
  • Detecting the size of the headers via CURLINFO_HEADER_SIZE is also not always reliable, especially when proxies are used Curl-1204 or in some of the same redirection scenarios.

The most correct method is using CURLOPT_HEADERFUNCTION.

Here is a very clean method of performing this using PHP closures. It also converts all headers to lowercase for consistent handling across servers and HTTP versions.

This version will retain duplicated headers

This complies with RFC822 and RFC2616, please do not make use of the mb_ (and similar) string functions, it is a not only incorrect but even a security issue 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);
Marquisette answered 14/12, 2016 at 5:38 Comment(28)
IMO this is the best answer in this thread and fixes problems with redirects that occurred with other answers. Best to read the documentation for CURLOPT_HEADERFUNCTION to understand how it works and potential gotchas. I've also made some improvements to the answer to help others out.Arvie
Great, I have updated the answer to cater for duplicated headers. In future do not re-format the code to what you believe it should be. This is written in a way to make it clear where the closure function boundaries are.Marquisette
@Marquisette Is $headers = []; valid php?Dewittdewlap
@Dewittdewlap Yes it is as of PHP 5.4, see: php.net/manual/en/migration54.new-features.phpMarquisette
This answer is highly underrated for such a neat and RFC compliant approach. This should be made sticky answer and moved to the top. I just wish there were a faster approach to get value of a desired header instead of parsing all headers first.Realpolitik
@Realpolitik thanks for the comments, unfortunately I do not think there is a way to stop curl calling the function once you find the header you're interested in, but you could always throw an if (array_key_exists('my-header', $headers)) return $len into it to ignore the rest of them once you find your target.Marquisette
@Marquisette Thanks for responding. I agree with you and also understand that it will hardly make any difference if there are only a few headers (which usually is the case unless you communicate with quite shitty URL :P). Was just hoping that there was an inbuilt way of catching a response header for code legibility. :)Realpolitik
@Marquisette Is the following code is proper why to fetch body content? $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $body = substr($response, $headerSize);Demisec
@Demisec no, $data = curl_exec($ch); returns the content when CURLOPT_RETURNTRANSFER is set as per the provided example.Marquisette
$a['foo'] = ['bar']; is literally the same thing as $a['foo'][] = 'bar';. I've simplified your code somewhat.Anode
@Mike: It most certainly is not. $a['foo'] = ['bar'] will assign a new array with only one element, where as `$a['foo'][] = 'bar'; will append an element. Also the check for an existing key is required on PHP 5.7 and above to avoid spamming the log with PHP warnings. You're edits are incorrect.Marquisette
@Marquisette I'm not sure what you're talking about with PHP warnings and checking that keys exist before assigning them, but you're wrong. In your case they are exactly the same thing because you have already determined that array_key_exists is false.Anode
Also, PHP 5.7 doesn't exist. It goes from 5.6 to 7.0.Anode
@mike sorry, yes, 5.6 was when the notices were introduced attempting to use an unassigned array index as an array, it plagued our servers while our clients updated the code, however as of testing now it seems that this behaviour is no longer the case. So yes, I am sorry, you are completely correct here.Marquisette
@Marquisette That's very interesting. You're sure it was PHP and not another server-side language producing the error (like CGI scripts)? I wonder if there is anything in the config that you can change to enable this behavior in PHP. If there is, I haven't heard of it. Did you compile PHP yourselves, or install from binaries?Anode
@Anode I am sorry, this was many years ago now when 5.6 was still new, they were E_NOTICE warnings. Beyond ensuring our staff were aware of the issue and how to resolve it, I do not remember.Marquisette
@Marquisette Maybe the error was about trying to access an unset array key, not setting one. However that should have thrown an E_NOTICE before 5.6, but your config could have changed during the upgrade as well.Anode
Using above code, we are getting our reqeust's headers instead of the response headers. Any clue to get that.Intrigant
@NaveedRamzan post a SO question about it with a code example, this is not the right place to ask for support. This works for literally hundreds of people without issue indicating something else is wrong with your code.Marquisette
@Marquisette Can you help me with https://mcmap.net/q/87545/-shopify-rest-api-pagination-link-empty/6792962 I used your code to parse the Header but having error.Chaw
@Marquisette how do you work with CURLOPT_HEADERFUNCTION when doing curl multi init?Thrice
@Thrice exactly the same way, just use a different variable for each CURLOPT_HEADERFUNCTION instead of $headers. How you do this is up to you.Marquisette
@Marquisette ... Take my money!Intersect
Very useful answer! In the line, "function($curl, $header) use (&$headers)", what is $curl? I don’t see $curl used anywhere else. Should that be $ch? I think the "static size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata)" [from curl.se/libcurl/c/CURLOPT_HEADERFUNCTION.html] requires it, but does it do anything? Is it just a dummy variable?Meloniemelony
@Meloniemelony it's correct as it stands. The php curl callback function expects two arguments, the first is the curl handle itself (same value as $ch), the second value is the header. In the above example it's simply unused but must be present or the callback prototype wont match. It could however be used for a generic handler across your entire code base where access to the handle is required per request for extra curl processing inside the callback.Marquisette
@Marquisette @Anode $a['foo'] = ['bar']; is not the same as $a['foo'][] = 'bar'; First stores an Array containing one item 'bar' under key 'foo'. Second stores string 'bar' in a NEW item under key 'foo'. The purpose of creating another array dimension here, is to keep duplicated headers. Former statement would overwrite value under 'foo' key. In your test, duplicate your two lines. (to imitate two headers with the same name). Current edit is OK. Originally I came to post a note explaining why [] is there. As it seemed confusing to me, before seeing it's for duplicates.Wilkey
@papo, Yes. You're right. I wrote that comment 4 years ago and my edit was rolled back shortly after.Anode
I checked the history, I see now there was a conditional block with both of them and you were talking about the first run, where it was indeed weird and unnecessary to not use "add to array" even on an empty array. Before I was just reading the comments and from those came to a conclusion you mean those two are identical in general. That's why I commented, to not keep others confused. @Anode suggestion was OK and the rollback was rollbacked so that's what we see now.Wilkey
F
148

Curl has a built in option for this, called CURLOPT_HEADERFUNCTION. The value of this option must be the name of a callback function. Curl will pass the header (and the header only!) to this callback function, line-by-line (so the function will be called for each header line, starting from the top of the header section). Your callback function then can do anything with it (and must return the number of bytes of the given line). Here is a tested working code:

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); 

The above works with everything, different protocols and proxies too, and you dont need to worry about the header size, or set lots of different curl options.

P.S.: To handle the header lines with an object method, do this:

curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($object, 'methodName'))
Fun answered 4/8, 2014 at 11:51 Comment(7)
As a note, the callback function is called for each header and it seems they are not trimmed. You can use a global variable to hold all headers or you can use an anonymous function for the callback and use a local variable (local for the parent scope, not the anonymous function).Dittany
@MV Thanks, yes, by "line-by-line" I meant "each header". I edited my answer for clarity. To get the entire header section (aka. all headers), you can also use an object method for the callback so an object property can hold all of them.Fun
This is the best answer IMO. It doesn't cause problems with multiple "\r\n\r\n" when using CURLOPT_FOLLOWLOCATION and I guess it won't be affected by additional headers from proxies.Thimble
Worked very well for me, also see #6482568 in case of issuesHandsome
Yes, this is the best approach however @Geoffrey's answer makes this cleaner by using an anonymous function with no need for global variables and such.Arvie
This was the first answer to suggest using CURLOPT_HEADERFUNCTION, so I think it should be the highest rated.Ossie
@Ossie first doesn't mean best... this website is about finding and providing the highest quality answer. It's not a contest where the first answer wins.Marquisette
E
38

is this what are you looking to?

curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
$response = curl_exec($ch); 
list($header, $body) = explode("\r\n\r\n", $response, 2);
Eyeshade answered 7/2, 2012 at 20:21 Comment(5)
This works normally except when there's a HTTP/1.1 100 Continue followed by a break then HTTP/1.1 200 OK. I'd go with the other method.Melainemelamed
Take a look to the selected answer of #14460204 before implementing something like this. w3.org/Protocols/rfc2616/rfc2616-sec14.html (14.20) 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.Warmth
@ghostfly, i have the solution for 100 in comment under "correct" answer.Meader
This method also fails on 302 redirects when curl is set to follow the location header.Arvie
This doesn't work on some POST requests too.Connally
D
18

If you specifically want the Content-Type, there's a special cURL option to retrieve it:

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
$content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
Delirium answered 24/3, 2014 at 21:41 Comment(5)
The OP asked if there is a way to retrieve the headers, not one specific header, this doesn't answer the OP's question.Marquisette
@Marquisette no, it can be useful for others who needs to get only Content-TypeCapello
@Capello it doesn't matter how useful it is, it does not answer the OPs question!Marquisette
@Marquisette yes, but all answers are useful for other users too, don't forget about it, and OP has found an answer too, so everybody is satisfiedCapello
@Delirium thanks for posting the answer. It was exactly what I needed. I was downloading an image with no file extension in the URL. Use content type header to find the image type.Biarritz
E
13

Just set options :

  • CURLOPT_HEADER, 0

  • CURLOPT_RETURNTRANSFER, 1

and use curl_getinfo with CURLINFO_HTTP_CODE (or no opt param and you will have an associative array with all the informations you want)

More at : http://php.net/manual/fr/function.curl-getinfo.php

Echeverria answered 20/6, 2014 at 11:3 Comment(1)
This does not seem to return the response headers to you at all. Or at least there's no way to retrieve them using curl_getinfo().Arvie
W
2
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);

Works with HTTP/1.1 100 Continue before other headers.

If you need work with buggy servers which sends only LF instead of CRLF as line breaks you can use preg_split as follows:

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);
Windflower answered 31/7, 2013 at 13:25 Comment(9)
Shouldn't $parts = explode("\r\n\r\nHTTP/", $response); have 3rd parameter for explode as 2?Eleventh
@Eleventh No. It allow find last HTTP message. HTTP/1.1 100 Continue can appear many times.Windflower
But he says something else: #9183678 which one of you are correct?Eleventh
HTTP/1.1 100 Continue can appear many times. He view case if it appear only one time, but it wrong in common case. For example for 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... his code don't work properlyWindflower
Splitting on \r\n is not reliable, some servers do not conform to HTTP specifications and will only send a \n. The RFC standard states that applications should ignore \r and split on \n for greatest reliability.Marquisette
@Marquisette This is only recommendation in RFC 2616. But you can use preg_split if you want it is slower but work for your case.Windflower
@Windflower the better solution is to split on \n and then trim the output, this is both fast and 100% compatible.Marquisette
I'd suggest not using preg_split for such a simple operation. Split by \n and then remove the \r, much faster.Elmoelmore
I recommend not mucking around with newline sequences with \ns and optional \rs -- regex already has a metacharacter to cover these things: \R. In this case \R{2}.Ales
B
1

My way is

$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];
}

If needed apply a for loop and remove the explode limit.

Bis answered 29/5, 2014 at 17:55 Comment(0)
B
1

Here is my contribution to the debate ... This returns a single array with the data separated and the headers listed. This works on the basis that CURL will return a headers chunk [ blank line ] data

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;
    }
}
Babism answered 28/2, 2019 at 11:52 Comment(0)
S
0

The problem with many answers here is that "\r\n\r\n" can legitimately appear in the body of the html, so you can't be sure that you're splitting headers correctly.

It seems that the only way to store headers separately with one call to curl_exec is to use a callback as is suggested above in https://mcmap.net/q/86326/-can-php-curl-retrieve-response-headers-and-body-in-a-single-request

And then to (reliably) get just the body of the request, you would need to pass the value of the Content-Length header to substr() as a negative start value.

Spadefish answered 15/7, 2016 at 14:41 Comment(1)
It can appear legitimately, but your answer is incorrect. Content-Length does not have to be present in a HTTP response. The correct method to manually parse the headers is to look for the first instance of \r\n (or \n\n). This could be done simply by limiting explode to return only two elements, ie: list($head, $body) = explode("\r\n\r\n", $response, 2);, however CURL already does this for you if you use curl_setopt($ch, CURLOPT_HEADERFUNCTION, $myFunction);Marquisette
P
0

Just in case you can't / don't use CURLOPT_HEADERFUNCTION or other solutions;

$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));
}
Pulliam answered 4/8, 2017 at 11:36 Comment(0)
C
0

A better way is to use the verbose CURL response which can be piped to a temporary stream. Then you can search the response for the header name. This could probably use a few tweaks but it works for me:

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;
        
    }
}
Capuano answered 9/3, 2021 at 14:16 Comment(0)
C
-1

Improvement of Geoffreys answer:

I couldn't get the right length for header with $headerSize = curl_getinfo($this->curlHandler, CURLINFO_HEADER_SIZE);- i had to calculate header size on my own.

In addition some improvements for better readability.

       $headerSize = 0;
        $headers['status'] = '';
        curl_setopt_array($this->curlHandler, [
            CURLOPT_URL => $yourURL,
            CURLOPT_POST => 0,
            CURLOPT_HEADER => 1,
            // this function is called by curl for each header received
            // source: https://mcmap.net/q/86326/-can-php-curl-retrieve-response-headers-and-body-in-a-single-request and improved
            CURLOPT_HEADERFUNCTION =>
                function ($curl, $header) use (&$headers, &$headerSize) {
                    $lenghtCurrentLine = strlen($header);
                    $headerSize += $lenghtCurrentLine;
                    $header = explode(':', $header, 2);
                    if (count($header) > 1) { // store only valid headers
                        $headers[strtolower(trim($header[0]))] = trim($header[1]);
                    } elseif (substr($header[0], 0, 8) === 'HTTP/1.1') {
                        // get status code
                        $headers['status'] = intval(substr($header[0], 9, 3));
                    }
                    return $lenghtCurrentLine;
                },
        ]);

        $fullResult = curl_exec($this->curlHandler);
Cohobate answered 19/8, 2021 at 6:30 Comment(2)
Don't you need to set CURLOPT_HEADER for it to return the headers when using CURLOPT_RETURNTRANSFER? If your'e using CURLOPT_HEADERFUNCTION without CURLOPT_HEADER, you shouldn't need to skip the headers with substr(). And then counting the aggregated length won't be necessary either. Have you even tried your code example?Leticia
You're right CURLOPT_HEADER was missing. I'm using this code here: github.com/sneakyx/wordpressApiClient/blob/master/src/…Cohobate
P
-2

Return response headers with a reference parameter:

<?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;
         }
?>
Pennsylvanian answered 12/11, 2014 at 11:32 Comment(4)
Are you sure $rtn=explode("\r\n\r\nHTTP/", $rtn, 2); is correct? Shouldn't 3rd parameter of explode be removed?Eleventh
@user4271704, the 3rd param is to deal with "HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 200 OK...\r\n\r\n..." headerPennsylvanian
But he said something else: #9183678 which one of you are correct?Eleventh
@Eleventh the link you are referring to also use: explode("\r\n\r\n", $parts, 2); so both are right.Grave
D
-2

Try this if you are using 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);
Diskin answered 12/1, 2021 at 8:46 Comment(0)
P
-5

If you don't really need to use curl;

$body = file_get_contents('http://example.com');
var_export($http_response_header);
var_export($body);

Which outputs

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>...

See http://php.net/manual/en/reserved.variables.httpresponseheader.php

Playacting answered 24/2, 2015 at 20:39 Comment(1)
uhm, you don't really need PHP either, but that just happens to be what the question is about...Bucentaur

© 2022 - 2024 — McMap. All rights reserved.