【发布时间】:2011-01-21 18:26:22
【问题描述】:
我编写了一个 File API 上传器,它主要执行以下操作:
- 用户选择要上传的文件
- 文件被分割成 20 kb 的块
- 块被异步发送到 php 脚本
- PHP 等待所有块上传完毕,然后将所有临时文件粘合在一起
- 文件 - 粘合在一起 - 已保存
但是,PHP 不能很好地将它们粘合在一起。有时,文件很好地粘合在一起,但大多数时候(尤其是在具有很多块的文件上)文件的粘合在一起是错误的。
js 代码:(仅适用于 Firefox 4 beta):
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 方法中使用错误的 start 和 length 参数发送了错误的块。
【问题讨论】:
-
您应该格式化您的代码以提高可读性! ;-)
-
也许使用 $_FILES 而不是从标准输入读取会更容易。
-
好吧,那行不通,因为我不将它作为 multipart/form-data 发送
-
这是一个非常好的主意(分块发送)。也许您可以将 ajax 请求排队,以便一次只发送一个?另外,您是否检查数据确实是服务器端的图像,如果是,如何检查?
标签: php javascript upload