【问题标题】:Copy remote file using Guzzle使用 Guzzle 复制远程文件
【发布时间】:2013-06-01 03:29:17
【问题描述】:

我正在尝试将远程文件(图像 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 时是否有更好/合适的解决方案?

【问题讨论】:

    标签: php guzzle


    【解决方案1】:

    使用 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"
        );
    }
    

    【讨论】:

      【解决方案2】:

      用帖子看这个:

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

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

      并用get

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

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

      【讨论】:

      • 这适用于 Guzzle 5.3.x,使用 save_to 选项完成了这项工作。谢谢!
      • 请注意 - 在 Guzzle 6 中,“save_to 请求选项已被弃用,取而代之的是 sink 请求选项。提供 save_to 选项现在是 sink 的别名”。
      【解决方案3】:

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

      <?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 等错误响应抛出异常。无需禁用此功能。只需捕获一个异常并在那里处理错误。

      【讨论】:

      • 非常感谢!我会试试这个。我希望它保持适当的 mime 类型(原始 mime 类型)。
      • 你需要做一些事情来更新磁盘上的文件以使用某种 mime 类型。不过我从来没有听说过。
      • 不,我的意思是我这样做的方式破坏/松开了 mime 类型。您的解决方案工作正常。感谢您的帮助。
      猜你喜欢
      • 2012-05-31
      • 2021-03-25
      • 2016-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多