使用cURL通过POST和MULTIPART/FORM-DATA上传文件时进行流式(line by line)传输

6
我想将本地文件上传到一个特定URL的远程服务器上的PHP表单中。上传表单是一个文件上传表单 (Multipart/form-data),我的脚本应该获取本地文件并将其发送到该表单。
这些文件有点大,但表单文件大小限制为1GB,这不是问题。但更紧迫的是,由于某些情况,我必须将文件作为流发送!
这意味着逐行读取文件,然后以不创建临时文件来分配通过CURLOPTS_POSTFILDS的方式进行上传。
所以简而言之:
- 我需要使用CURLOPTS_READFUNCTION(我想)逐行获取文件内容 - 方法必须是POST - 这必须模拟远程服务器上传表单上的常规文件上传(因此我想我需要某种虚拟文件名)
我尝试了很多方法,但都失败了。我对非常陌生,我尝试了很多其他StackOverflow问题和其他论坛的信息,但都没有成功。
我得出结论,可能不可能,但正如我所说,我对自己在做什么方面知之甚少,因此我需要一些来自经验更丰富的人的信息或指导。到目前为止,我认为CURLOPT_INFILECURLOPT_READFUNCTION仅适用于PUT方法,但我必须使用POST
抱歉问题很长,希望有意义。提前感谢任何帮助或信息。
编辑
这里是一些建议的代码:
$fh = fopen('php://memory','rw');
fwrite( $fh, $content); //maybe write the contents to memory here?
rewind($fh);


$options = array(
    CURLOPT_RETURNTRANSFER  => true
    ,CURLOPT_SSL_VERIFYPEER => false
    ,CURLOPT_SSL_VERIFYHOST => 1
    ,CURLOPT_FOLLOWLOCATION => 0
    ,CURLOPT_HTTPHEADER     => array(
        'Content-type: multipart/form-data'
    )
    ,CURLOPT_INFILE         => $fh //I want to read the contents from this file
    ,CURLOPT_INFILESIZE     => sizeof($content)
);
    $ch = curl_init();
    curl_setopt ($ch, CURLOPT_URL, 'remote_form_url_here');
    curl_setopt ($ch, CURLOPT_POST, true);
    $post = array(
         'userfile' => '@i_do_not_have_a_file_to_put_here;filename=myfile.txt'
    );
    curl_setopt ($ch, CURLOPT_POSTFIELDS, $post);
    curl_setopt_array ($ch, $options);


    //have the reading occur line by line when making the infile
    curl_setopt($ch, CURLOPT_READFUNCTION, function($ch, $fd, $length) use ($fh) {
    $line = fgets($fh);
    if ($line !== false) return $line; else return false;
    });


    $response = curl_exec($ch);

    echo $response;
    fclose($fh);

这段代码主要是从找到的答案进行组合而成的,但使用文件处理器的部分似乎不太适合。我想使用文件处理器,但似乎没有办法让表单混淆内容为文件并传递一些随机文件名。
这段代码甚至不能正常工作(根本无法提交表单),或者有些变体会显示"forbidden"。
仅供参考,这是我用来模拟真实情况的测试表单,在使其正常工作之前(不想向真实服务器发送大量请求):
<form enctype="multipart/form-data" action="up.php" method="POST">


                Send this file: <input name="userfile" type="file" />
                    <input type="submit" value="Send File" />
            </form> 

这是后台代码:

$target_path = "./ups/";

$target_path = $target_path . basename( $_FILES['userfile']['name']); 

if(move_uploaded_file($_FILES['userfile']['tmp_name'], $target_path)) {
    echo "The file ".  basename( $_FILES['userfile']['name']). 
    " has been uploaded";
} else{
    echo "There was an error uploading the file, please try again!";
}

var_dump($_FILES['userfile']);

1
不,这不是重复的问题,如之前所述,我已经阅读了这些问题,它们并不涉及我的情况。我不想一次性上传整个文件,我已经知道如何做到这一点。我想要的是,如之前所述,逐行读取文件(使用CURLOPTS_READFUNCTION),但保留POST方法!!!编辑:将其视为没有文件,只有一个字符串变量,并且我无法保存临时文件。或者将其视为必须使用文件处理程序而没有实际文件路径。 - todoubled
展示你的不工作的代码(即使是简化版),可能有助于其他人缩小问题范围。除非你指定一个有效的(但虚拟的?)INFILE,否则你所尝试的可能是不可能的,因为它似乎被传递为流处理程序到你的回调函数中(但你不一定需要使用它来读取数据的“块”)。 - Jacob S
当您无法控制接收端时,似乎不可能实现这一点。此外,PHP没有实现curl的全部功能(即HTTPPOST和curl_formadd)。或者,您可以使用fsockopen手动构造HTTP POST请求,以您想要的方式进行。 - Jacob S
我明白,解释得很清楚。但是,我想知道我是否仍然需要一次性发送整个帖子数据? - todoubled
也许吧,这完全取决于接收端的实现。你可以尝试使用多部分和分块数据,但不确定是否可行。不过,这种方法可能无法在 Apache/FastCGI 上工作,具体情况我也不清楚。 - Jacob S
1个回答

1

如果在浏览器上运行正常,您可以使用Chrome开发工具。在“网络”选项卡中,找到提交请求。右键单击->复制为cURL。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接