用PHP将文件块粘合在一起

用PHP将文件块粘合在一起,php,javascript,upload,Php,Javascript,Upload,我已经编写了一个文件API上载程序,它基本上执行以下操作: 用户选择要上载的文件 这些文件被切成20 kb的块 块被异步发送到php脚本 PHP会等待所有的块被上传,然后将所有的临时文件粘在一起 文件-粘在一起-被保存 然而,PHP并不能很好地将它们粘合在一起。有时,文件可以很好地粘合在一起,但大多数情况下,尤其是在有大量块的文件上,文件的粘合错误 js代码:仅适用于Firefox 4测试版: sendChunk: function(file, start, length) { var

我已经编写了一个文件API上载程序,它基本上执行以下操作:

用户选择要上载的文件 这些文件被切成20 kb的块 块被异步发送到php脚本 PHP会等待所有的块被上传,然后将所有的临时文件粘在一起 文件-粘在一起-被保存 然而,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是异步工作的,它在sendChunk方法中以某种方式发送了错误的数据块,并且使用了错误的开始和长度参数。

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

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

因此流读取器是二进制安全的

编辑:

因为我不熟悉php://input 流,我不知道它包含什么数据以及以什么格式,我建议在客户端和服务器端都使用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));
file_put_contents("./tmp/$filename.$start", $_POST['data']);
PHP是这样的:

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

你应该把你的代码格式化以便可读-也许使用$\u文件和不从stdin读取会更容易。好吧,这不起作用,因为我不以多部分/表单数据的形式发送它,这是一个非常好的主意,将其分块发送。也许您可以对ajax请求进行排队,以便一次只发送一个请求?另外,您是否正在检查数据是否确实是服务器端的一个映像,如果是,如何检查?嗯,它做了一些事情。。。现在看一下输出:是否可以使用diff这样的工具查看数据的更改位置?如果您还没有解决方案,可以添加新的想法