Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I asynchronously download files with Guzzle 6?

I am trying to asynchronously download files with Guzzle 6, but the documentation seems vague and couldn't find any useful examples.

The thing I am not sure about is - how am I supposed to save the received data?

Currently I am doing it like this:

$successHandler = function (Response $response, $index) use ($files) {
    $file = fopen($files[$index], 'a');
    $handle = $response->getBody();

    while (!$handle->eof()) {
        fwrite($file, $handle->read(2048));
    }

    fclose($file);
};

Is this really asynchronous?

Since if we get into one callback and start looping, how can we get the data from the other ones at the same time?

Is there a more direct way to tell, when creating a Request, where should the response be stored? (or directly passing a stream for that).

like image 300
M. Ivanov Avatar asked Aug 23 '15 22:08

M. Ivanov


2 Answers

The sink option should be your friend here:

$client->request('GET', '/stream/20', [
    'sink' => '/path/to/file',
]);

For reference, see http://docs.guzzlephp.org/en/latest/request-options.html#sink.

like image 184
localheinz Avatar answered Oct 11 '22 17:10

localheinz


use function GuzzleHttp\Psr7\stream_for;
use GuzzleHttp\RequestOptions;
use GuzzleHttp\Client;

$tmpFile  = tempnam(sys_get_temp_dir(), uniqid(strftime('%G-%m-%d')));
$resource = fopen($tmpFile, 'w');
$stream   = stream_for($resource);

$client   = new Client();
$options  = [
    RequestOptions::SINK            => $stream, // the body of a response
    RequestOptions::CONNECT_TIMEOUT => 10.0,    // request
    RequestOptions::TIMEOUT         => 60.0,    // response
];

$response = $client->request('GET', 'https://github.com/robots.txt', $options);

$stream->close();
fclose($resource);

if ($response->getStatusCode() === 200) {
    echo file_get_contents($tmpFile); // content
}
like image 25
serghei Avatar answered Oct 11 '22 15:10

serghei