0
votes

When calling curl with php, I'm able to hook callback on CURLOPT_PROGRESSFUNCTION and read headers during the request progress using curl_multi_getcontent($handle)

$handle = curl_init()
curl_setopt(CURLOPT_NOPROGRESS, false)
curl_setopt(CURLOPT_RETURNTRANSFER, true)
curl_setopt(CURLOPT_PROGRESSFUNCTION, function($handle) {
   $response = curl_multi_getcontent($handle);
   // some logic here
})
curl_exec($handle)

How can I do that with Guzzle?

The problem is that I cannot use curl_multi_getcontent($handle) without setting CURLOPT_RETURNTRANSFER to true.

But when I set CURLOPT_RETURNTRANSFER to guzzle' curl config, I can read headers in progress function $response = curl_multi_getcontent($handle); However the response stream contains empty content.

$request->getResponse()->getBody()->getContents(); // always outputs ""

Edit: I have made this change https://github.com/guzzle/guzzle/pull/2173 so I can access handle in progress callback with progress settings:

'progress' => function($handle) {
   $response = curl_multi_getcontent($handle);
   // some logic here
})

That works as long as CURLOPT_RETURNTRANSFER is true. However as I mentioned earlier, the response contents is "" then.

2

2 Answers

0
votes

There is a progress request option.

// Send a GET request to /get?foo=bar
$result = $client->request(
    'GET',
    '/',
    [
        'progress' => function(
            $downloadTotal,
            $downloadedBytes,
            $uploadTotal,
            $uploadedBytes
        ) {
            //do something
        },
    ]
);

http://docs.guzzlephp.org/en/stable/request-options.html#progress

0
votes

I found the solution or rather an explanation why it is happening.

Guzzle by default sets CURLOPT_FILE option when no custom sink is defined (or CURLOPT_WRITEFUNCTION when sink is defined but that doesn't really matter actually).

However, setting CURLOPT_RETURNTRANSFER to true negates both of those options -> they're not applied anymore.

Two things happen then after setting CURLOPT_RETURNTRANSFER:

  1. Response can be read in PROGRESSFUNCTION with $response = curl_multi_getcontent($handle). For that this Guzzle modification is necessary https://github.com/guzzle/guzzle/pull/2173
  2. Response is returned when Guzzle calls curl_exec($handle) as return value of this call. But Guzzle doesn't assign it to any variable because it expects that the response is not returned there but through WRITEFUNCTION that was however neutralized by setting CURLOPT_RETURNTRANSFER.

So my solution is not the cleanest one but I don't find any other way to go around it with Guzzle. Guzzle is simply not built to be able to handle that.

I forked Guzzle. Then created custom Stream class that behaves like default sink -> that writes to php://temp. And when my custom Stream class is set as sink I write the result of curl_exec into stream:

$result = curl_exec($easy->handle);
$easy->sink->write($result);