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

时间:2021-05-08 20:33:11

标签: javascript php ajax stream xmlhttprequest

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

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
我的帖子最大和上传最大大小为 4G

我正在使用 apache2

1 个答案:

答案 0 :(得分:0)

如果您不需要文件,则不应使用 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)
}
相关问题