【问题标题】:Guzzle 6 Large file uploads / ChunkingGuzzle 6 大文件上传/分块
【发布时间】:2018-01-20 07:36:03
【问题描述】:

我了解到,如果 Guzzle 无法确定 Content-Length,它将发送 Transfer-Encoding: Chunked 标头,后端的 cURL 将处理分块。但我显然达到了 post_max_size 限制。 (“524288375 字节的 POST 内容长度超过了 8388608 字节的限制)当 POST 到工作的 uploadChunkerController 时。我知道上传处理程序(端点)适用于较小的文件。我觉得我的 Guzzle 选项配置有问题。我有将verify 设置为false,我需要在请求中发布api_key

    $client = new Client();
    $fh     = fopen('../storage/random-500M.pdf', 'r');
    $url    = 'https://local:8443/app_dev.php/_uploader/bigupload/upload';

    $request = $client->request(
        'POST',
        $url,
        [
            'verify'    => false,
            'multipart' => [
                [
                    'name' => 'api_key',
                    'contents' => 'abc123'
                ],
                [
                    'name'     => 'file',
                    'contents' => $fh,
                    'filename' => 'bigupload.pdf'
                ]
            ]
        ]
    );

编辑 php.ini 设置不是一种选择,也不是解决方案。我发现了很多似乎适用于旧版本 Guzzle 的“解决方案”。我是不是想太多了?有没有更简单的解决方案?

【问题讨论】:

  • 您发布到的服务器/脚本说您只能上传 8MB 的文件,如果您有权访问该服务器/脚本,您将需要更改限制.
  • 这就是使用分块的全部原因。 BlueImp jQuery File Uploader 在前端/UI 端工作。我正在从另一个 PHP 脚本发布到相同的控制器操作。因此,如之前所述,使用 POST 的操作处理分块上传,只要我可以让 Guzzle/cURL 对文件进行分块并提供正确的标题,一切都应该是金色的。
  • @cmorrissey 是的,我关注了那篇博文。它适用于旧版本。当前 Guzzle 6 git repo 中不存在 EntityBody 类。我用它作为模型来达到我现在的位置。甚至尝试使用'$body = \GuzzleHttp\Psr7\stream_for($fh);'并将其作为资源传递。

标签: php guzzle blueimp uploading


【解决方案1】:

在挖掘 Guzzle 和 cURL 源代码后,他们没有“自动”方式发送“块”。未设置标头,他们无法分割正在发送的文件。我使用 Guzzle 与原始 PHP cURL 调用提出了自己的解决方案。

/**
 * @Route("/chunks", name="chunks")
 */
public function sendFileAction()
{
    $jar       = new \GuzzleHttp\Cookie\SessionCookieJar('SESSION_STORAGE', true);
    $handler   = new CurlHandler();
    $stack     = HandlerStack::create($handler);
    $client    = new Client(['cookies'=>true, 'handler' => $stack]);
    $filename  = 'files/huge-1gig-file.jpg';
    $filesize  = filesize($filename);
    $fh        = fopen($filename, 'r');
    $chunkSize = 1024 * 2000;
    $boundary  = '----iCEBrkUploaderBoundary' . uniqid();
    $url       = 'https://localhost/app_dev.php/_uploader/bigupload/upload';

    rewind($fh); // probably not necessary
    while (! feof($fh)) {
        $pos   = ftell($fh);
        $chunk = fread($fh, $chunkSize);
        $calc  = $pos + strlen($chunk)-1;

        // Not sure if this is needed.
        //if (ftell($fh) > $chunkSize) {
        //    $pos++;
        //}

        $request = $client->request(
            'POST',
            $url,
            [
                'cookies' => $jar,
                'debug'   => false,
                'verify'  => false,
                'headers' => [
                    'Transfer-Encoding'   => 'chunked',
                    'Accept-Encoding'     => 'gzip, deflate, br',
                    'Accept'              => 'application/json, text/javascript, */*; q=0.01',
                    'Connection'          => 'keep-alive',
                    'Content-disposition' => 'attachment; filename="' . basename($filename) . '"',
                    'Content-length'      => $calc - $pos,
                    'Content-Range'       => 'bytes ' . $pos . '-' . $calc . '/' . $filesize
                ],
                'multipart' => [
                    [
                        'name'     => 'api_key,
                        'contents' => 'aaabbbcc-deff-ffed-dddd-1234567890123'
                    ],
                    [
                        'name'     => 'file',
                        'contents' => $chunk,
                        'filename' => basename($filename),
                        'headers' => [
                            'Content-Type' => 'multipart/form-data; boundary=' . $boundary
                        ]
                    ]
                ]
            ]
        );
    }

    return new Response('ok', 200);
}

我希望这对其他人有所帮助。欢迎评论/建议。

【讨论】:

  • 此函数复制了前端 github.com/blueimp/jQuery-File-Upload 文件上传器的功能,因此您能够以编程方式 (CLI) 发布到同一端点,并且您的文件将使用相同的逻辑进行处理。跨度>
【解决方案2】:

分块传输编码在这种情况下没有帮助。

它用于通过部分发送(和生成)内容来尽快提供内容。它与大小限制无关(就像在您的场景中一样)。

你唯一的办法就是增加服务器的限制。

【讨论】:

  • 如果Javascript可以做到link,PHP也可以做到。 @cmorrissey 引用了声称可以进行分块的旧版本的 Guzzle。我只能假设一个更新的版本也可以。我尝试使用原始 cURL (CURLOP_READFUNCTION),但没有成功。
  • 同一个问题的答案似乎说 Guzzle 可以发布块。 [使用 Guzzle PHP 将文件分块上传到 URL 端点](stackoverflow.com/questions/45182654/…)
  • Guzzle 能够做到这一点(我的意思是块),但它不会帮助你。正如我之前所说,它不是按设计工作的。尝试用 JS 或任何其他语言/库来实现它,看看。
  • 您正在尝试上传大于服务器限制的文件。这在设计上是不可能的(这就是为什么该功能被称为 limits)。
  • 那您能解释一下 BlueImp jQuery File 上传器的工作原理吗?你能解释为什么存在分块吗? (github.com/blueimp/jQuery-File-Upload/wiki/Chunked-file-uploads)
猜你喜欢
  • 1970-01-01
  • 2017-12-24
  • 2016-04-04
  • 2021-10-27
  • 2016-03-19
  • 1970-01-01
  • 1970-01-01
  • 2019-12-25
  • 2018-03-24
相关资源
最近更新 更多