上载大文件(~1 GB)时XMLHttpRequest流崩溃



我正试图与朋友为另一个项目制作一个在线文件管理器,当上传大于1GB的文件时,进程要么崩溃(firefox(,要么成功,但收到的文件重0字节(chromium(。

JS:

function uploadFile(fileInputId, fileIndex) {
//send file name
try {
var fileName = document.getElementById('fileUploader').files[0].name;
}
catch {
document.getElementById('uploadStatus').innerHTML = `<font color="red">Mettre un fichier serait une bonne idée.</font>`;
return false;
}
document.cookie = 'fname=' + fileName;
//take file from input
const file = document.getElementById(fileInputId).files[fileIndex];
const reader = new FileReader();
reader.readAsBinaryString(file);
reader.onloadend = function(event) {
ajax = new XMLHttpRequest();
//send data
ajax.open("POST", 'uploader.php', true);
//all browser supported sendAsBinary
XMLHttpRequest.prototype.mySendAsBinary = function(text) {
var data = new ArrayBuffer(text.length);
var ui8a = new Uint8Array(data, 0)
for (var i = 0; i < text.length; i++) ui8a[i] = (text.charCodeAt(i) & 0xff);
if (typeof window.Blob == "function") {
var blob = new Blob([data]);
}else {
var bb = new (window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder)();
bb.append(data);
var blob = bb.getBlob();
}
this.send(blob);
}
//track progress
var eventSource = ajax.upload || ajax;
eventSource.addEventListener('progress', function(e) {
//percentage
var position = e.position || e.loaded;
var total = e.totalSize || e.total;
var percentage = Math.round((position/total)*100);
document.getElementById('uploadStatus').innerHTML = `${percentage}%`;
});
ajax.onreadystatechange = function() {
if(ajax.readyState == 4 && ajax.status == 200) {
document.getElementById('uploadStatus').innerHTML = this.responseText;
}
}
ajax.mySendAsBinary(event.target.result);
}
}

PHP:

//mysql login
$conn = new PDO([Redacted]);
//file info
$fileName = $_COOKIE['fname'];
$targetDir = "uploads/";
$targetFile = $targetDir.$fileName;
$fileNameRaw = explode('.', $fileName)[0]; //file name with no extension
$tempFilePath = $targetDir.$fileNameRaw.'.tmp';
if (file_exists($targetFile)) {
echo '<font color="red">Un fichier du même nom existe déjà.</font>';
exit();
}
//read from stream
$inputHandler = fopen('php://input', 'r');
//create temp file to store data from stream
$fileHandler = fopen($tempFilePath, 'w+');
//store data from stream
while (true) {
$buffer = fgets($inputHandler, 4096);
if (strlen($buffer) == 0) {
fclose($inputHandler);
fclose($fileHandler);
break;
}
fwrite($fileHandler, $buffer);
}
//when finished
rename($tempFilePath, $targetFile);
chmod($targetFile, 0777);
echo 'Fichier envoyé avec succès !';
$bddInsert = $conn->prepare('INSERT INTO files(nom, chemin) VALUES(?,?)');
$bddInsert->execute(array($fileName, $targetFile));

在我的php.ini中,
max_execution_time设置为0
max_input_time为-1
,我的post-max和upload-max大小为4G

我正在使用apache2

如果您不需要fileReader,就不应该使用它来读取文件。

只需将文件(blob(直接发送到您的ajax请求,并避免FileReader

function uploadFile (fileInputId, fileIndex) {
// Send file name
try {
var fileName = document.getElementById('fileUploader').files[0].name;
}
catch {
document.getElementById('uploadStatus').innerHTML = `<font color="red">Mettre un fichier serait une bonne idée.</font>`;
return false;
}
document.cookie = 'fname=' + fileName;
// Take file from input
const file = document.getElementById(fileInputId).files[fileIndex];
const ajax = new XMLHttpRequest();
// send data
ajax.open("POST", 'uploader.php', true);
// track progress
ajax.upload.addEventListener('progress', function(e) {
// percentage
var position = e.position || e.loaded;
var total = e.totalSize || e.total;
var percentage = Math.round((position/total)*100);
document.getElementById('uploadStatus').innerHTML = `${percentage}%`;
});
ajax.onreadystatechange = function() {
if (ajax.readyState == 4 && ajax.status == 200) {
document.getElementById('uploadStatus').innerHTML = this.responseText;
}
}
ajax.send(file)
}

最新更新