Как прервать XMLHttpRequest.upload из внешнего скрипта? - PullRequest
2 голосов
/ 08 апреля 2020

Как результат до Почему $ _FILES [] всегда пусто? :

При загрузке файла через AJAX с PhP обычно выполняется следующее (I Я новичок в этом, поэтому, пожалуйста, скажите мне, если есть лучший способ сделать это):

  • Есть один файл с формой и javascript, где вы настраиваете и отправляете свой XMLHttpRequest, например upload_form. php
  • Есть еще один внешний php файл для обработки запроса на загрузку, например, upload. php

У меня такой вопрос:

Можно ли прервать запрос XMLHttpRequest из во внешней загрузке. php файл? .

Причина, по которой вы хотите это сделать, заключается в том, что если файл уже существует на сервере, я бы хотел прервать XMLHttpRequest, а не заставлять пользователя ждать завершения загрузки, чтобы сообщил о сбое.


Некоторые изображения, иллюстрирующие проблему:

Я ограничил скорость на вкладке сети, чтобы преувеличить проблему .

Пользователь загружает файл, который НЕ существует на сервере в каталоге uploads :

Success

Пользователь загружает файл, который DOES существует на сервере в каталоге uploads :

Failure

Некоторый код для иллюстрации проблемы:

upload_form. php:

<!-- enctype and method added on suggestions from previous question -->
<form class="form" id="upload_form" enctype="multipart/form-data" method="POST">
    <input type="file" name="file_to_upload" id="file_to_upload"><br>
    <input class="button" type="submit" value="Upload">
</form>

<script>
  const upload_form  = document.getElementById('upload_form');
  var file_to_upload = document.getElementById('file_to_upload');

  upload_form.addEventListener("submit", upload_file);

  function upload_file (e) {
    e.preventDefault();

    const xhr = new XMLHttpRequest()

    xhr.open("POST", "upload.php");
    xhr.upload.addEventListener("progress", e => {
      const percent = e.lengthComputable ? (e.loaded / e.total) * 100 : 0;
      console.log(percent.toFixed(0) + "%");
    });

    // ================= MAIN PART OF QUESTION ===================
    // Can I force this to fire from upload.php if file exists?
    xhr.addEventListener("abort", e => {
      console.log(e);
    });
    // ===========================================================

    xhr.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        // update some response area here
      }
    };

    xhr.send(new FormData(upload_form));
  }
</script>

upload. php:

<?php

$target_path = "uploads/".basename($_FILES["file_to_upload"]["name"]);
$uploaded_file = $_FILES['file_to_upload']['tmp_name'];

$upload_ok = true;
$errors = [];

// ================= MAIN PART OF QUESTION ==========================
// I want this to cause the abort event to fire on the XMLHttpRequest
if (file_exists($target_path)) {
  $upload_ok = false;
  array_push($errors, 'The file already exists on the server. Please rename the file and try again.');
}
// ==================================================================

if(!$upload_ok) {
  echo 'The file was not uploaded because:<br>';
  foreach ($errors as $err) {
    echo $err.'<br>';
  }
} else {
  if(move_uploaded_file($_FILES["file_to_upload"]["tmp_name"], $target_path)) {
    echo 'File uploaded successfully';
  } else {
    echo 'Something went wrong. Please try again.';
  }
}
?>

Я пробовал проверять различные комбинации readyState и status в upload_form. php но это не он lped.

1 Ответ

1 голос
/ 13 апреля 2020

К тому моменту, когда код PHP начинается, файл уже полностью загружен, поэтому нет смысла прерывать его таким образом, что означало бы просто вернуть сообщение. Вместо этого вы можете сделать перед загрузкой AJAX вызов и проверить, существует ли файл, и только если он не загружает файл, или же сообщить пользователю об этом.

Создать простое exists.php со следующим кодом

<?php

$target_path = "uploads/".$_GET['file'];
$file_exists = file_exists($target_path);

header('Content-Type: application/json');

// Return a JSON object with a single boolean property to indicate if the file exists
echo json_encode(['exists' => $file_exists]);

Создайте обещание сделать XHR-вызов и получите exists.php результат

function check_file_exists() {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();

    xhr.open("GET", `exists.php?file=${encodeURIComponent(file_to_upload.files[0].name)}`);
    xhr.responseType = 'json';
    xhr.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        resolve(this.response && this.response.exists);
      }
    };

    xhr.send();
  });
}

Рефакторируйте функцию upload_file для первого вызова check_file_exists обещание

// An element to display a message to the user
const message = document.getElementById('message');

function upload_file(e) {
  e.preventDefault();

  message.textContent = '';

  // Call the promise to check if the selected file exists on the server
  check_file_exists().then(exists => {
    if(exists) {
      // If it exists message the user about it and do nothing else
      message.textContent = `File "${file_to_upload.files[0].name} already exists`;
    } else {
      // If it does not exists upload the file
      const xhr = new XMLHttpRequest();

      xhr.open("POST", "upload.php");
      xhr.upload.addEventListener("progress", e => {
        const percent = e.lengthComputable ? (e.loaded / e.total) * 100 : 0;
        console.log(percent.toFixed(0) + "%");
      });

      xhr.onreadystatechange = function() {

        if (this.readyState == 4 && this.status == 200) {
          // update some response area here
          message.textContent = this.responseText;
        }
      };

      xhr.send(new FormData(upload_form));
    }
  });
}
...