php guzzlehttp 流从 fopen('php://input', "r") 上传到远程端点

问题描述

我有一个可以在 server1 中接收文件上传PHP 应用程序。该文件预计会非常大。我需要保存文件(在 server1 的本地磁盘中)并将文件发送到 server2 中的另一个 API 端点(目前我尝试使用 guzzle,但答案不是必须的)。

我想最小化加载时间。在我的假设中,可以假设磁盘 I/O(将上传文件写入磁盘)可以忽略不计(因为网络是瓶颈)。

这是我对加载时间的假设(串行):

start |----------uploading to server1----------|
                                                |----------uploading to server2----------| end

我想通过将不完整的文件上传流式传输到 server2 来缩短加载时间,以便获得此加载时间(并行):

start |----------uploading to server1----------|
       bbb|----------uploading to server2----------| end
where bbb is the buffer read delay

所以我的尝试是尝试使用 PHPfopen('PHP://input',"r"),因为它返回一个流,然后在 guzzle 请求正文中使用该流。

server1 中的代码

<?PHP
require_once("vendor/autoload.PHP");

$length = $_SERVER['CONTENT_LENGTH'];
$client = new \GuzzleHttp\Client();
$fileReader = fopen('PHP://input',"r");
$streamPsr7 =  \GuzzleHttp\Psr7\stream_for($fileReader);
$multipartStreamPsr7 = new \GuzzleHttp\Psr7\MultipartStream([["name"=>"bigfile","contents"=>$streamPsr7]]);
$requestPsr7 = new \GuzzleHttp\Psr7\Request(
    'POST',// method
    'http://xxx.xxx.xxx.xxx/test-stream-upload/upload.PHP?filename=bigfile',// endpoint
    ['Content-Length'=>$length],// header
    $multipartStreamPsr7
);
$response = $client->send($requestPsr7);

var_dump($response->getStatusCode());
var_dump(strval($response->getBody()));

server2 中的代码

if(empty($_GET['filename'])) $_GET['filename'] = 'file';

$fileReader = fopen('PHP://input',"r");
$fileWriter = fopen('data/'.$_GET['filename'],"w+");

while(true) {
    $buffer = fgets($fileReader,4096);
    if (strlen($buffer) == 0) {
        fclose($fileReader);
        fclose($fileWriter);
        return true;
    }

    fwrite($fileWriter,$buffer);
}

但它不起作用。当我检查 server2 请求正文为空时,我收到 408 请求超时。

我的问题:

  • 这种方法(从 PHP://input 流式上传)在 PHP 中是否可行?
  • 如果可能,该怎么做?请给出可重现的 PHP 示例来做到这一点
  • 如果在 PHP 中不可能,那么如何在其他语言/应用程序堆栈中做到这一点?

注意:

  • 我知道它不安全(用户可以为文件编写任何名称,使其对远程代码执行开放等),这仅用于演示/复制目的

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)