20

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

这是代码:

$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();
}

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

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

编辑:这适用于 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',
    ]);

或使用 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());

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

4

3 回答 3

22

您的代码可以大大简化。我下面的示例代码会将响应的主体直接流式传输到文件系统。

<?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;
    }
}

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

文件系统 mimetype?

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

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

于 2013-06-05T18:28:26.077 回答
12

用帖子看这个:

$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);

在这里您必须发送您的“帖子”请求

并得到

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

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

于 2015-08-28T20:23:48.437 回答
5

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

额外的:

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

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

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"
    );
}
于 2018-10-15T09:14:06.147 回答