我的网站上有一个文件上传表单,当用户将其文件上传到我的服务器时,我想将这个上传的文件从我的服务器传输到云服务器。文件可能很大,所以我决定将文件以100KB的份数发送到云端。
这是我的PHP代码示例,它尝试将文件从我的服务器发送到云端:
<?php
$cloud_server = '%my_server%';
$uploading_file_name = '%folders%/file.mp3';
$auth_token = '%token%';
$file_path = $_SERVER["DOCUMENT_ROOT"] . '/file.mp3';
$file_handler = fopen($file_path, 'rb');
$file_size = filesize($file_path);
$chunk_size = 100 * 1024;
$start_byte_position = 0;
while (!feof($file_handler)) {
$chunk_content = fread($file_handler, $chunk_size);
$chunk_content_length = strlen($chunk_content);
$final_byte_position = $start_byte_position + $chunk_content_length;
$socket_handler = fsockopen($cloud_server, 80, $errno, $errstr);
if (!$socket_handler)
die ($errstr);
//Headers
$request = "PUT /{$uploading_file_name} HTTP/1.1\r\n";
$request .= "Connection: Close\r\n";
$request .= "Host: {$cloud_server}\r\n";
$request .= "X-Auth-Token: {$auth_token}\r\n";
$request .= "Content-Range: {$start_byte_position}-{$final_byte_position}/{$file_size}\r\n";
$request .= "Content-Length: {$chunk_content_length}\r\n";
$request .= "\r\n";
//Body
$request .= $chunk_content;
$request .= "\r\n";
fwrite($socket_handler, $request);
$server_response = '';
while (!feof($socket_handler))
$server_response .= fgets($socket_handler, 128);
echo $server_response, '<br><br>';
$start_byte_position = $final_byte_position;
fclose($socket_handler);
}
该代码实际上有效,除了一件事 - 每个部分都会覆盖以前的内容。 在第一个循环的迭代中,在云上创建100KB文件,在第二次迭代中,这些100KB被另一个100KB替换。在最后一次迭代上传大约28KB,所以最后我在云服务器上有28KB文件而不是整个文件。我究竟做错了什么?我希望这些部分能够互相跟随,而不是替换。
以下是服务器响应,如果这会有所帮助:
HTTP / 1.1 201创建日期:2013年8月13日星期二15:11:09 GMT连接: 关闭服务器:Selectel_Storage / 1.0最后修改:2013年8月13日星期二 15:11:09 GMT内容长度:0 etag:ea64231f21c952cdb57a5d3109415d09 content-type:text / html; charset = UTF-8
HTTP / 1.1 201创建日期:2013年8月13日星期二15:11:10 GMT连接: 关闭服务器:Selectel_Storage / 1.0最后修改:2013年8月13日星期二 15:11:09 GMT内容长度:0 etag:01ab42f6ad58b401284540d6631dae9d content-type:text / html; charset = UTF-8
HTTP / 1.1 201创建日期:2013年8月13日星期二15:11:10 GMT连接: 关闭服务器:Selectel_Storage / 1.0最后修改:2013年8月13日星期二 15:11:10 GMT内容长度:0 etag:99bd6f0d3cefd75abc140b9359464d6d content-type:text / html; charset = UTF-8
HTTP / 1.1 201创建日期:2013年8月13日星期二15:11:10 GMT连接: 关闭服务器:Selectel_Storage / 1.0最后修改:2013年8月13日星期二 15:11:10 GMT内容长度:0 etag:07cf64ef10e96710b8cb48022ee5dd16 content-type:text / html; charset = UTF-8
................................
HTTP / 1.1 201创建日期:2013年8月13日星期二15:11:33 GMT连接: 关闭服务器:Selectel_Storage / 1.0最后修改:2013年8月13日星期二 15:11:33 GMT content-length:0 etag:f01e66c96b21665bbbd19ee5e283a4e1 content-type:text / html;字符集= UTF-8
提前致谢!
答案 0 :(得分:1)
好吧,我终于找到了合适的解决方案。当Marc B响应时,不可能执行部分PUT请求(因为根据定义,这种类型的请求必须是幂等的)。但是,如果我们谈论将文件上传到庞大的云服务器,则可以使用适当的服务器API。据我所知,OpenStack(其Swift组件准确)在文件存储中非常流行。
所以here是简明扼要的官方文件。
我使用的云服务器只允许使用DLO(动态大对象)方法上传大文件,所以您只需要:
1)将大文件拆分成段(或简单地使用fseek和fread)。
2)将这些段发送到一个指定的目录,该名称将进一步被视为整个文件的名称。
3)发送特殊请求(创建所谓的清单文件),将所有下载的段打包在一个文件中。
非常简单!
以下是使用the documentation page的CURL的一个很好的示例:
# First, upload the segments
curl -X PUT -H 'X-Auth-Token: <token>' \
http://<storage_url>/container/myobject/1 --data-binary '1'
curl -X PUT -H 'X-Auth-Token: <token>' \
http://<storage_url>/container/myobject/2 --data-binary '2'
curl -X PUT -H 'X-Auth-Token: <token>' \
http://<storage_url>/container/myobject/3 --data-binary '3'
# Next, create the manifest file
curl -X PUT -H 'X-Auth-Token: <token>' \
-H 'X-Object-Manifest: container/myobject/' \
http://<storage_url>/container/myobject --data-binary ''
# And now we can download the segments as a single object
curl -H 'X-Auth-Token: <token>' \
http://<storage_url>/container/myobject
希望这会对某人有所帮助。