用PHP粘贴文件块

时间:2011-01-21 18:26:23

标签: php javascript upload

我编写了一个File API上传器,它基本上执行以下操作:

  1. 用户选择要上传的文件
  2. 将文件切成20 kb块
  3. 将这些块异步发送到php脚本
  4. PHP等待所有块上传,然后将所有临时文件粘合在一起
  5. 文件 - 粘在一起 - 已保存
  6. 然而,PHP并没有很好地将它们粘合在一起。有时,文件很好地粘在一起,但大多数时候(特别是在有很多块的文件上)文件粘在一起是错误的。

    js代码:(仅适用于Firefox 4测试版):

     sendChunk: function(file, start, length) {
        var raw  = file.raw;
        var name  = file.name;
        var total  = file.size;
    
        var url = 'upload.php?name=' + encodeURIComponent(name) + '&total=' + total + '&start=' + start + '&length=' + length;
        var slice = raw.slice(start, length);
        var reader  = new FileReader();
    
        reader.readAsBinaryString(slice);
        reader.onload = function(e) {
            if(e.target.readyState === FileReader.DONE) {
                var xhr = new XMLHttpRequest();
                xhr.open("POST", url);
                xhr.overrideMimeType('text/plain; charset=x-user-defined-binary');
                xhr.sendAsBinary(e.target.result);
            }
        };
    };
    

    PHP代码:

    <?php
    $filename = $_GET['name'];
    $total = $_GET['total'];
    $start = $_GET['start'];
    $length = $_GET['length'];
    
    $uploaded = $start + $length;
    $percentage = round($uploaded / ($total / 100));
    $remaining = $total - $uploaded;
    
    $fd = fopen("php://input", "r");
    while($data = fread( $fd, 10000000)) file_put_contents("./tmp/$filename.$start", $data, FILE_APPEND);
    
    if($remaining <= 0) {
        $handle  = opendir('tmp/');
        $data   = '';
        $collection = array();
    
        while(($file = readdir($handle)) !== false) {
            $arr  = explode('.', $file);
            $name  = '';
            $start  = $arr[count($arr) - 1];
    
            for($i = 0; $i < (count($arr) - 1); $i++) {
                if($name == '') $name .= $arr[$i];
                else $name .= '.' . $arr[$i];
            }
    
            if($name == $filename) {
                $collection[$start] = file_get_contents('./tmp/' . $file);
            }
    
            @unlink('./tmp/' . $file);
        }
    
        ksort($collection);
    
        foreach($collection as $key => $bin) {
            echo "(Added) $key: (binary data)\n";
            $data .= $bin;
        }
    
        if($data !== '') {
            file_put_contents('./uploads/' . $filename, $data);
        }
    
        closedir($handle);
    } else {
        echo "Uploaded: $uploaded / $total ($percentage%)\n";
        echo "Remaining: " . $remaining . " (". (100 - $percentage) ."%)\n";
    }
    ?>
    

    有人有任何想法吗?我的猜测是FileReader异步工作,它以某种方式发错了错误的start&amp; length方法中的sendChunk参数。

1 个答案:

答案 0 :(得分:0)

我不熟悉您将数据发送到服务器的方式,但我的第一个猜测是改变

$fd = fopen("php://input", "r");

$fd = fopen("php://input", "rb");

所以流阅读器是二元安全的。

修改

由于我不熟悉php://输入流,我不知道它包含哪些数据以及采用何种格式,我建议在客户端和服务器端使用POST数据。

所以我会像这样改变JS:

            var xhr = new XMLHttpRequest();
            xhr.open("POST", url);
            xhr.overrideMimeType("Content-type", "application/x-www-form-urlencoded");
            xhr.send('data='+encodeURIComponent(e.target.result));

和PHP这样:

file_put_contents("./tmp/$filename.$start", $_POST['data']);