合并 PHP 中的文件块
Merging file chunks in PHP
出于教育目的,我想创建文件块上传。你们怎么知道所有块何时上传?
我尝试从 temp
移动块并重命名它们以使其顺序正确,然后与最后一个块将它们合并在一起。然而,最后发送的不是最后收到的,我猜。因此 fopen()
块失败,因为它们尚未创建,我得到的最终文件的大小与最后一个块的大小完全相同。
我相信我可以使用 xhr
上的 .onload
事件一个接一个地发送数据块,这样我什至不必将它们从 PHP 临时移动,但是我'我想知道是否有不同的解决方案。
一些基本的代码来取悦你:
function upload(file) {
var BYTES_PER_CHUNK = parseInt(2097152, 10),
size = file.size,
NUM_CHUNKS = Math.max(Math.ceil(SIZE / BYTES_PER_CHUNK), 1),
start = 0, end = BYTES_PER_CHUNK, num = 1;
var chunkUpload = function(blob) {
var fd = new FormData();
var xhr = new XMLHttpRequest();
fd.append('upload', blob, file.name);
fd.append('num', num);
fd.append('num_chunks', NUM_CHUNKS);
xhr.open('POST', '/somedir/upload.php', true);
xhr.send(fd);
}
while (start < size) {
chunkUpload(file.slice(start, end));
start = end;
end = start + BYTES_PER_CHUNK;
num++;
}
}
和PHP:
$target_path = ROOT.'/upload/';
$tmp_name = $_FILES['upload']['tmp_name'];
$filename = $_FILES['upload']['name'];
$target_file = $target_path.$filename;
$num = $_POST['num'];
$num_chunks = $_POST['num_chunks'];
move_uploaded_file($tmp_name, $target_file.$num);
if ($num === $num_chunks) {
for ($i = 1; $i <= $num_chunks; $i++) {
$file = fopen($target_file.$i, 'rb');
$buff = fread($file, 2097152);
fclose($file);
$final = fopen($target_file, 'ab');
$write = fwrite($final, $buff);
fclose($final);
unlink($target_file.$i);
}
}
抱歉我之前的评论,我误解了一个问题。这个问题很有趣,玩起来很有趣。
你要找的表达是这样的:
$target_path = ROOT.'/upload/';
$tmp_name = $_FILES['upload']['tmp_name'];
$filename = $_FILES['upload']['name'];
$target_file = $target_path.$filename;
$num = $_POST['num'];
$num_chunks = $_POST['num_chunks'];
move_uploaded_file($tmp_name, $target_file.$num);
// count ammount of uploaded chunks
$chunksUploaded = 0;
for ( $i = 1, i <= $num; $i++ ) {
if ( file_exists( $target_file.$i ) ) {
++$chunksUploaded;
}
}
// and THAT's what you were asking for
// when this triggers - that means your chunks are uploaded
if ($chunksUploaded === $num_chunks) {
/* here you can reassemble chunks together */
for ($i = 1; $i <= $num_chunks; $i++) {
$file = fopen($target_file.$i, 'rb');
$buff = fread($file, 2097152);
fclose($file);
$final = fopen($target_file, 'ab');
$write = fwrite($final, $buff);
fclose($final);
unlink($target_file.$i);
}
}
必须要提到的是:
我的版本的脆弱点 - 是你需要文件的时候
'tmp-1',
'tmp-2',
'tmp-3'
但是,让我们假设在发送 'tmp-2' 之后我们被打断了 - tmp-2 污染了 tmp 文件夹,并且它会干扰以后使用相同文件名的上传 - 那将是一个沉睡的炸弹。
为了解决这个问题 - 您必须找到一种方法将 tmp 更改为更原始的内容。
'tmp-ABCew-1',
'tmp-ABCew-2',
'tmp-ABCew-3'
好一点 - 'ABCew' 可以称为 'chunksSessionId' - 你在发送 POST 时提供它,你随机生成它。尽管如此,冲突仍然是可能的——因为 space 的随机名称耗尽。您可以将时间添加到等式中 - 例如 - 您可以看到
'tmp-ABCew-2016-03-17-00-11-22--1',
'tmp-ABCew-2016-03-17-00-11-22--2',
'tmp-ABCew-2016-03-17-00-11-22--3'
更抗碰撞,但难以实施 - 这里有一大堆蠕虫 - 客户端日期和时间由客户端控制并且可能被欺骗 - 此数据不可靠。
所以让 tmp-name 独一无二是一项复杂的任务。设计一个使其可靠的系统 - 是一个有趣的问题 ^ ^ 你可以尝试一下。
出于教育目的,我想创建文件块上传。你们怎么知道所有块何时上传?
我尝试从 temp
移动块并重命名它们以使其顺序正确,然后与最后一个块将它们合并在一起。然而,最后发送的不是最后收到的,我猜。因此 fopen()
块失败,因为它们尚未创建,我得到的最终文件的大小与最后一个块的大小完全相同。
我相信我可以使用 xhr
上的 .onload
事件一个接一个地发送数据块,这样我什至不必将它们从 PHP 临时移动,但是我'我想知道是否有不同的解决方案。
一些基本的代码来取悦你:
function upload(file) {
var BYTES_PER_CHUNK = parseInt(2097152, 10),
size = file.size,
NUM_CHUNKS = Math.max(Math.ceil(SIZE / BYTES_PER_CHUNK), 1),
start = 0, end = BYTES_PER_CHUNK, num = 1;
var chunkUpload = function(blob) {
var fd = new FormData();
var xhr = new XMLHttpRequest();
fd.append('upload', blob, file.name);
fd.append('num', num);
fd.append('num_chunks', NUM_CHUNKS);
xhr.open('POST', '/somedir/upload.php', true);
xhr.send(fd);
}
while (start < size) {
chunkUpload(file.slice(start, end));
start = end;
end = start + BYTES_PER_CHUNK;
num++;
}
}
和PHP:
$target_path = ROOT.'/upload/';
$tmp_name = $_FILES['upload']['tmp_name'];
$filename = $_FILES['upload']['name'];
$target_file = $target_path.$filename;
$num = $_POST['num'];
$num_chunks = $_POST['num_chunks'];
move_uploaded_file($tmp_name, $target_file.$num);
if ($num === $num_chunks) {
for ($i = 1; $i <= $num_chunks; $i++) {
$file = fopen($target_file.$i, 'rb');
$buff = fread($file, 2097152);
fclose($file);
$final = fopen($target_file, 'ab');
$write = fwrite($final, $buff);
fclose($final);
unlink($target_file.$i);
}
}
抱歉我之前的评论,我误解了一个问题。这个问题很有趣,玩起来很有趣。
你要找的表达是这样的:
$target_path = ROOT.'/upload/';
$tmp_name = $_FILES['upload']['tmp_name'];
$filename = $_FILES['upload']['name'];
$target_file = $target_path.$filename;
$num = $_POST['num'];
$num_chunks = $_POST['num_chunks'];
move_uploaded_file($tmp_name, $target_file.$num);
// count ammount of uploaded chunks
$chunksUploaded = 0;
for ( $i = 1, i <= $num; $i++ ) {
if ( file_exists( $target_file.$i ) ) {
++$chunksUploaded;
}
}
// and THAT's what you were asking for
// when this triggers - that means your chunks are uploaded
if ($chunksUploaded === $num_chunks) {
/* here you can reassemble chunks together */
for ($i = 1; $i <= $num_chunks; $i++) {
$file = fopen($target_file.$i, 'rb');
$buff = fread($file, 2097152);
fclose($file);
$final = fopen($target_file, 'ab');
$write = fwrite($final, $buff);
fclose($final);
unlink($target_file.$i);
}
}
必须要提到的是:
我的版本的脆弱点 - 是你需要文件的时候
'tmp-1',
'tmp-2',
'tmp-3'
但是,让我们假设在发送 'tmp-2' 之后我们被打断了 - tmp-2 污染了 tmp 文件夹,并且它会干扰以后使用相同文件名的上传 - 那将是一个沉睡的炸弹。
为了解决这个问题 - 您必须找到一种方法将 tmp 更改为更原始的内容。
'tmp-ABCew-1',
'tmp-ABCew-2',
'tmp-ABCew-3'
好一点 - 'ABCew' 可以称为 'chunksSessionId' - 你在发送 POST 时提供它,你随机生成它。尽管如此,冲突仍然是可能的——因为 space 的随机名称耗尽。您可以将时间添加到等式中 - 例如 - 您可以看到
'tmp-ABCew-2016-03-17-00-11-22--1',
'tmp-ABCew-2016-03-17-00-11-22--2',
'tmp-ABCew-2016-03-17-00-11-22--3'
更抗碰撞,但难以实施 - 这里有一大堆蠕虫 - 客户端日期和时间由客户端控制并且可能被欺骗 - 此数据不可靠。
所以让 tmp-name 独一无二是一项复杂的任务。设计一个使其可靠的系统 - 是一个有趣的问题 ^ ^ 你可以尝试一下。