我知道可以使用CURL来轻松完成这个任务,但我想知道是否可以使用http流上下文将文件上传到远程Web服务器,如果可以的话,如何实现?
首先,multipart
Content-Type 的第一条规则是定义一个边界,用作分隔每个部分的分界符(因为如其名称所示,它可以有多个部分)。边界可以是 任何不包含在内容体中的字符串。我通常会使用时间戳:
define('MULTIPART_BOUNDARY', '--------------------------'.microtime(true));
一旦您定义了边界,您就必须使用Content-Type
头将其发送,以告诉Web服务器应该期望什么分隔符:
$header = 'Content-Type: multipart/form-data; boundary='.MULTIPART_BOUNDARY;
一旦完成了这一步骤,您必须构建一个符合HTTP规范和您发送的标题的适当内容主体。正如您所知,当从表单中POST文件时,通常会有一个表单字段名称。我们将其定义为:
// equivalent to <input type="file" name="uploaded_file"/>
define('FORM_FIELD', 'uploaded_file');
然后我们构建内容主体:
$filename = "/path/to/uploaded/file.zip";
$file_contents = file_get_contents($filename);
$content = "--".MULTIPART_BOUNDARY."\r\n".
"Content-Disposition: form-data; name=\"".FORM_FIELD."\"; filename=\"".basename($filename)."\"\r\n".
"Content-Type: application/zip\r\n\r\n".
$file_contents."\r\n";
// add some POST fields to the request too: $_POST['foo'] = 'bar'
$content .= "--".MULTIPART_BOUNDARY."\r\n".
"Content-Disposition: form-data; name=\"foo\"\r\n\r\n".
"bar\r\n";
// signal end of request (note the trailing "--")
$content .= "--".MULTIPART_BOUNDARY."--\r\n";
正如您所看到的,我们正在使用form-data
属性和name
参数(表单字段名称)以及filename
参数(原始文件名),发送Content-Disposition
头。 如果您想要正确填充$_FILES [] ['type']
,则还重要发送带有正确MIME类型的Content-Type
头。
如果您要上传多个文件,只需为每个文件使用不同的FORM_FIELD
,并重复使用$content部分进行该过程。
现在,构建上下文:
$context = stream_context_create(array(
'http' => array(
'method' => 'POST',
'header' => $header,
'content' => $content,
)
));
然后执行:
file_get_contents('http://url/to/upload/handler', false, $context);
注意:发送二进制文件之前无需对其进行编码。HTTP 可以很好地处理二进制文件。
name=\"foo\"\r\n\r\n"."bar\r\n";
这部分吗?它不应该只是 foo=bar
吗?我对这部分非常困惑。 - bryan或者你可以只做:
$postdata = http_build_query(
array(
'var1' => 'some content',
'file' => file_get_contents('path/to/file')
)
);
$opts = array('http' =>
array(
'method' => 'POST',
'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => $postdata
)
);
$context = stream_context_create($opts);
$result = file_get_contents('http://example.com/submit.php', false, $context);
你需要把 '/path/to/file' 修改为正确的路径