0

I am encountering an issue where once curl is explicitly set to use CURLOPT_HEADER, all the responses I get from a REST Endpoint (SugarCRM 7) will include the full HTTP Header. I did this so I can get and store Cookies for session management, but the immediate downside is the response I receive from curl_exec() is that it includes all headers, effectively breaking any attempt to interpret the returned result as valid JSON. The actual response from a POST call is posted below.

"HTTP/1.1 200 OK
Date: Thu, 25 Feb 2016 03:23:35 GMT
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.1e-fips mod_fcgid/2.3.9 PHP/5.4.16
X-Powered-By: PHP/5.4.16
Set-Cookie: PHPSESSID=f0bsbjelfa9c0ada7qj1816986; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 75
Content-Type: application/json; charset=UTF-8

{"examplekey":"examplevalue"}"

If CURLOPT_HEADER is disabled, the response sends a valid JSON object, but then there is no effective way to track the life of the session. It should be fairly predictable to pull the JSON data out through splitting across CRLFs, but there has to be a way to have cURL send both the body response, and the headers (cookies and all) without having to take a risk with regexing CRLFs with the whole response. Unfortunately, I have had no luck accessing cookies without CURLOPT_HEADER disabled.

To summarize -- what would be the best approach to preserve the headers from a cURL request, while leaving a valid JSON-serialized String that I can process?

Below is the method being used for this process.

public function RunCurl() {
  ob_start();

  //Set x-www-form-urlencoded header
  $Headers[] = 'Content-Type: application/x-www-form-urlencoded';
  $Headers[] = 'cache-control: no-cache';

  curl_setopt($this->CurlRequest, CURLOPT_VERBOSE, true);
  curl_setopt($this->CurlRequest, CURLOPT_URL, $this->SourceURL);
  curl_setopt($this->CurlRequest, CURLOPT_HEADER, 1);

  curl_setopt($this->CurlRequest, CURLOPT_RETURNTRANSFER, TRUE);
  curl_setopt($this->CurlRequest, CURLOPT_POSTFIELDS, http_build_query($this->EncapsulatedPostData));

  curl_setopt($this->CurlRequest, CURLOPT_HEADER, 1);
  curl_setopt($this->CurlRequest, CURLOPT_HTTPHEADER, $this->Cookie);

  try {
      $Results = curl_exec($this->CurlRequest);
      preg_match_all('/^Set-Cookie:\s*([^\r\n]*)/mi', $Results, $ms);
      $this->Cookie = $ms;
      curl_close($this->CurlRequest);
  } catch (Exception $ex) {
      echo 'Caught exception: ',  $ex->getMessage(), "\n";
      return false;
  }

  ob_end_flush();

  return json_decode(utf8_decode($Results));
}
Cameron Kilgore
  • 383
  • 7
  • 25

3 Answers3

2

Add these two line after curl_exec Body will contain your json response.

$Results = curl_exec($this->CurlRequest);

$header_size = curl_getinfo($this->CurlRequest, CURLINFO_HEADER_SIZE);
$body = substr($Results, $header_size);
Vinie
  • 2,983
  • 1
  • 18
  • 29
  • 1
    You just need to watch out for some versions of curl [incorrectly handling the header size when there is a proxy](http://stackoverflow.com/questions/34743545/php-curl-incorrect-header-size-when-use-proxy) – John C Feb 25 '16 at 22:29
1

An alternative is to use the CURLOPT_HEADERFUNCTION option - this allows you to send the headers to a callback function. A quick example that should get close to what you are after would go as follows:

public function RunCurl() {
  ob_start();

  //Set x-www-form-urlencoded header
  $Headers[] = 'Content-Type: application/x-www-form-urlencoded';
  $Headers[] = 'cache-control: no-cache';

  curl_setopt($this->CurlRequest, CURLOPT_VERBOSE, true);
  curl_setopt($this->CurlRequest, CURLOPT_URL, $this->SourceURL);

  curl_setopt($this->CurlRequest, CURLOPT_RETURNTRANSFER, TRUE);
  curl_setopt($this->CurlRequest, CURLOPT_POSTFIELDS, http_build_query($this->EncapsulatedPostData));

  curl_setopt($this->CurlRequest, CURLOPT_HTTPHEADER, $this->Cookie);
  curl_setopt($this->CurlRequest, CURLOPT_HEADERFUNCTION, array($this, 'readHeader'));

  try {
      $Results = curl_exec($this->CurlRequest);
      curl_close($this->CurlRequest);
  } catch (Exception $ex) {
      echo 'Caught exception: ',  $ex->getMessage(), "\n";
      return false;
  }

  ob_end_flush();

  return json_decode(utf8_decode($Results));
}

private function readHeader($ch, $header) {
    $found = preg_match_all('/^Set-Cookie:\s*([^\r\n]*)/mi', $header, $ms);
    if ($found !== 0) {
        $this->Cookie = $ms;
    }
    return strlen($header);
}
John C
  • 8,223
  • 2
  • 36
  • 47
0

According to HTTP Specification (RFC7230), CRLF ("\r\n\r\n") is used as a separator for header and body sections. So you can get the body section of the response just by :

$body = substr($response, strpos($response, "\r\n\r\n")+4);

or

list($header, $body) = explode("\r\n\r\n", $response, 2);
Community
  • 1
  • 1
pumbo
  • 3,646
  • 2
  • 25
  • 27