Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copy remote file using Guzzle

Tags:

I'm trying to copy a remote file (image PNG, GIF, JPG ...) to my server. I use Guzzle since I sometimes get 404 with copy() even if the file exists and I also need to do a basic auth. This script is within a long script launched in command triggered by a cron job. I'm pretty new to Guzzle and I successfully copy the image but my files have wrong mime type. I must be doing something wrong here. Please suggest me a good way to do this (including checking success/failure of copy and mime type check). If file has no mime type I would pop an error with details informations.

Here is the code:

$remoteFilePath = 'http://example.com/path/to/file.jpg';
$localFilePath = '/home/www/path/to/file.jpg';
try {
    $client = new Guzzle\Http\Client();
    $response = $client->send($client->get($remoteFilePath)->setAuth('login', 'password'));
    if ($response->getBody()->isReadable()) {
        if ($response->getStatusCode()==200) {
            // is this the proper way to retrieve mime type?
            //$mime = array_shift(array_values($response->getHeaders()->get('Content-Type')));
            file_put_contents ($localFilePath , $response->getBody()->getStream());
            return true;
        }
    }
} catch (Exception $e) {
    return $e->getMessage();
}

When I do this my mime type is set to application/x-empty

Also it looks like when status is different from 200 Guzzle will automatically throw an exception. How can I stop this behaviour and check status myself so I can custom error message?

EDIT: This was for Guzzle 3.X Now this is how you can do it using Guzzle v 4.X (works as well with Guzzle 6)

$client = new \GuzzleHttp\Client();
$client->get(
    'http://path.to/remote.file',
    [
        'headers' => ['key'=>'value'],
        'query'   => ['param'=>'value'],
        'auth'    => ['username', 'password'],
        'save_to' => '/path/to/local.file',
    ]);

Or using Guzzle stream:

use GuzzleHttp\Stream;

$original = Stream\create(fopen('https://path.to/remote.file', 'r')); 
$local = Stream\create(fopen('/path/to/local.file', 'w')); 
$local->write($original->getContents());

This looks great. Is there better/proper solution when using Guzzle 4?

like image 330
Spir Avatar asked Jun 05 '13 12:06

Spir


2 Answers

Your code can be simplified a great deal. My example code below will stream the body of the response directly to the filesystem.

<?php

function copyRemote($fromUrl, $toFile) {
    try {
        $client = new Guzzle\Http\Client();
        $response = $client->get($fromUrl)
            ->setAuth('login', 'password') // in case your resource is under protection
            ->setResponseBody($toFile)
            ->send();
        return true;
    } catch (Exception $e) {
        // Log the error or something
        return false;
    }
}

When I do this my mime type is set to application/x-empty

A filesystem mimetype?

Also it looks like when status is different from 200 Guzzle will automatically throw an exception. How can I stop this behaviour and check status myself so I can custom error message?

Guzzle will throw an exception for bad responses like 4xx and 5xx. No need to disable this. Just catch an exception and deal with the error there.

like image 147
Michael Dowling Avatar answered Oct 09 '22 23:10

Michael Dowling


Look at this with post:

$myFile = fopen('path/to/file', 'w') or die('Problems');
$client = new \Guzzle\Service\Client();
$request = $client->post('https://www.yourdocumentpage.com', array(), ['pagePostField' => 'data'], ['save_to' => $myFile]);
$client->send($request);
fclose($myFile);

here you must send the request of your "post"

and with get

$myFile = fopen('path/to/file', 'w') or die('Problems');
$client = new \GuzzleHttp\Client();
$request = $client->get('https://www.yourdocumentpage.com', ['save_to' => $myFile]);

and here you don't need to send the request, and here you'll find a lot of documentation, you must have guzzle 6 for doing that, and if you are using GOUTTE at the same time you'll need goutte 3.1, update your require in your composer.json

like image 25
Jorgeeadan Avatar answered Oct 09 '22 21:10

Jorgeeadan