首页 文章

PHP HTTP 1.1无法执行部分PUT请求

提问于
浏览
0

我的网站上有一个文件上传表单,当用户将其文件上传到我的服务器时,我想将这个上传的文件从我的服务器传输到 Cloud 服务器 . 文件可能很大,所以我决定将文件以100KB的份数发送到 Cloud 端 .

这是我的PHP代码示例,它尝试将文件从我的服务器发送到 Cloud :

<?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);
}

该代码几乎可以工作,除了一件事 - 每个部分都会覆盖以前的内容 . 在第一个循环的迭代中,在 Cloud 上创建100KB文件,在第二次迭代中,这些100KB被另一个100KB替换 . 在最后一次迭代上传大约28KB,所以最后我在 Cloud 服务器上有28KB文件而不是整个文件 . 我究竟做错了什么?我希望这些部件互相跟随,而不是替换 .

以下是服务器响应,如果这将有所帮助:

HTTP / 1.1 201创建日期:星期二,2013年8月13日15:11:09 GMT连接:关闭服务器:Selectel_Storage / 1.0 last-modified:Tue,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连接:关闭服务器:Selectel_Storage / 1.0最后修改:2013年8月13日星期二15:11:33 GMT内容长度:0 etag:f01e66c96b21665bbbd19ee5e283a4e1 content-type:text / html;字符集= UTF-8

提前致谢!

1 回答

  • 1

    好吧,我终于找到了合适的解决方案 . 当Marc B回复时,它是's impossible to perform partial PUT request (because this type of request must be idempotent by definition). However, if we speak about uploading files to the huge cloud server, it is possible to use appropriate server'的API . 据我所知,OpenStack(其Swift组件准确)在文件存储中非常流行 .

    所以here是简短明了的官方文件 .

    我使用的 Cloud 服务器只允许使用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
    

    希望这会对某人有所帮助 .

相关问题