php 使用 Guzzle 复制远程文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16939794/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 11:56:17  来源:igfitidea点击:

Copy remote file using Guzzle

phpguzzle

提问by Spir

I'm trying to copy a remote file (image PNG, GIF, JPG ...) to my server. I use Guzzlesince 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.

我正在尝试将远程文件(图像 PNG、GIF、JPG ...)复制到我的服务器。我使用Guzzle,因为即使文件存在,有时我也会通过copy()获得 404,而且我还需要进行基本身份验证。此脚本位于由 cron 作业触发的命令中启动的长脚本中。我对 Guzzle 很陌生,我成功复制了图像,但我的文件有错误的 MIME 类型。我一定在这里做错了什么。请建议我这样做的好方法(包括检查复制的成功/失败和 mime 类型检查)。如果文件没有 MIME 类型,我会弹出一个包含详细信息的错误。

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

当我这样做时,我的 mime 类型设置为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?

此外,当 status 与 200 Guzzle 不同时,它看起来会自动抛出异常。如何停止这种行为并自己检查状态,以便我可以自定义错误消息?

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)

编辑:这是针对 Guzzle 3.X 现在这是使用 Guzzle v 4.X 的方法(也适用于 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:

或者使用 Guzzle 流:

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?

这看起来很棒。使用 Guzzle 4 时是否有更好/合适的解决方案?

回答by Michael Dowling

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

当我这样做时,我的 mime 类型设置为 application/x-empty

A filesystem mimetype?

文件系统 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?

此外,当 status 与 200 Guzzle 不同时,它看起来会自动抛出异常。如何停止这种行为并自己检查状态,以便我可以自定义错误消息?

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.

Guzzle 会针对 4xx 和 5xx 等不良响应抛出异常。无需禁用此功能。只需捕获一个异常并处理那里的错误。

回答by Jorgeeadan

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 hereyou'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

在这里你不需要发送请求,在这里你会找到很多文档,你必须有 guzzle 6 才能做到这一点,如果你同时使用 GOUTTE,你需要 goutte 3.1,更新你在 composer.json 中的需求

回答by Furqan Freed

using Guzzle 6 just use SINK option. see below detailed function

使用 Guzzle 6 只需使用 SINK 选项。详细功能见下文

Extra:

额外的:

use GuzzleHttp\Client; Guzzle namespace included

使用 GuzzleHttp\Client; 包含 Guzzle 命名空间

$access_token = if you need auth else simply remove this option

$access_token = 如果您需要身份验证,则只需删除此选项

ReportFileDownloadException = custom exception

ReportFileDownloadException = 自定义异常

/**
 * download report file and read data to database
 * @param remote url
 * @return N/A
 * @throws ReportFileDownloadException
 */
protected function getReportFile($report_file_url)
{
    $file = $this->tempDirectory . "/" . basename($report_file_url);
    $fileHandle = fopen($file, "w+");

    try {
        $client = new Client();
        $response = $client->get($report_file_url, [
            RequestOptions::SINK => $fileHandle,
            RequestOptions::HEADERS => [
                "Authorization" => "Bearer $access_token"
            ]
        ]);
    } catch (RequestException $e) {
        throw new ReportFileDownloadException(
            "Can't download report file $report_file_url"
        );
    } finally {
        @fclose($fileHandle);
    }

    throw new ReportFileDownloadException(
        "Can't download report file $report_file_url"
    );
}