Bagaimana untuk Membaca dan Gema Menulis Saiz Fail yang Dimuat Naik Pada Masa Sedang Dalam Pelayan dalam Masa Nyata Tanpa Menyekat Pelayan dan Pelanggan?

DDD
Lepaskan: 2024-10-20 22:02:30
asal
757 orang telah melayarinya

How to Read and Echo Currently Writing Size of Uploaded File in Server in Realtime Without Blocking Server and Client?

Bagaimana untuk membaca dan mencetak saiz fail yang dimuat naik yang ditulis pada bahagian pelayan dalam masa nyata tanpa menyekat pelayan dan klien?

Mari kita meluaskan isu ini:

Untuk mendapatkan kemajuan muat naik fail dalam masa nyata, kami menetapkannya daripada objek Blob, File, TypedArray atau ArrayBuffer melalui pengambilan () dalam permintaan POST Objek badan.

Pelaksanaan semasa menetapkan objek Fail sebagai hujah kedua untuk mengambil() dihantar ke objek badan.

Keperluan:

Sebagai teks/strim-acara membaca saiz fail yang ditulis ke sistem fail pelayan dan menggemakannya kembali kepada klien. Berhenti apabila semua bait yang disediakan oleh parameter rentetan pertanyaan var dalam permintaan GET telah ditulis. Pembacaan fail pada masa ini berlaku dalam persekitaran skrip yang berasingan, di mana panggilan GET dibuat ke skrip yang membaca fail, dan kemudian POST dibuat pada skrip yang menulis fail ke pelayan.

Tunggu sehingga anda melengkapkan bahagian bergema saiz fail sebelum cuba menyelesaikan isu yang mungkin berlaku dengan mengendalikan penulisan fail sebelah pelayan atau bacaan fail untuk mendapatkan saiz fail semasa.

Pada masa ini cuba menggunakan php untuk memenuhi keperluan. Tetapi juga berminat dengan c, bash, nodejs, python atau bahasa lain atau kaedah yang boleh digunakan untuk melaksanakan tugas yang sama.

Bahagian javascript sisi klien baik. Saya hanya tidak mahir dalam php (salah satu bahasa bahagian pelayan yang paling banyak digunakan di dunia) untuk melaksanakan corak tanpa memasukkan bahagian yang tidak perlu.

Motivasi:

Penunjuk kemajuan untuk diambil?

Berkaitan:

Ambil dengan ReadableStream

Soalan:

Dapatkan

PHP Notice:  Undefined index: HTTP_LAST_EVENT_ID in stream.php on line 7
Salin selepas log masuk

di terminal.

Selain itu, jika anda menggantikan

while(file_exists($_GET["filename"]) 
  &amp;&amp; filesize($_GET["filename"]) < intval($_GET["filesize"]))
Salin selepas log masuk

dengan

while(true)
Salin selepas log masuk

ia akan menjana ralat di EventSource.

Tanpa panggilan sleep(), saiz fail yang betul dihantar ke acara mesej untuk fail bersaiz 3.3MB, 3321824, 61921, 26214 dan 38093 masing-masing dicetak apabila fail yang sama dimuat naik tiga kali. Hasil yang dijangkakan ialah untuk mendapatkan saiz fail semasa menulis fail di:

stream_copy_to_stream($input, $file);
Salin selepas log masuk

dan bukannya saiz fail objek fail yang dimuat naik. Adakah fopen() atau stream_copy_to_stream() akan menghalang proses php lain daripada mengakses stream.php?

Perkara yang dicuba setakat ini:

Petikan php daripada

  • Melebihi $_POST, $_GET dan $_FILE: Dalam JavaScriptPHP Handling Blobs
  • Pengenalan kepada Acara Dihantar Pelayan dengan Contoh PHP

php

// 能否合并 `data.php`、`stream.php` 为同一个文件?
// 能否使用 `STREAM_NOTIFY_PROGRESS` 
// "Indicates current progress of the stream transfer 
// in bytes_transferred and possibly bytes_max as well" to read bytes?
// do we need to call `stream_set_blocking` to `false`
// data.php
<?php

  $filename = $_SERVER["HTTP_X_FILENAME"];
  $input = fopen("php://input", "rb");
  $file = fopen($filename, "wb"); 
  stream_copy_to_stream($input, $file);
  fclose($input);
  fclose($file);
  echo "upload of " . $filename . " successful";

?>
Salin selepas log masuk
// stream.php
<?php

  header("Content-Type: text/event-stream");
  header("Cache-Control: no-cache");
  header("Connection: keep-alive");
  // `PHP Notice:  Undefined index: HTTP_LAST_EVENT_ID in stream.php on line 7` ?
  $lastId = $_SERVER["HTTP_LAST_EVENT_ID"] || 0;
  if (isset($lastId) &amp;&amp; !empty($lastId) &amp;&amp; is_numeric($lastId)) {
      $lastId = intval($lastId);
      $lastId++;
  }
  // else {
  //  $lastId = 0;
  // }

  // while current file size read is less than or equal to 
  // `$_GET["filesize"]` of `$_GET["filename"]`
  // how to loop only when above is `true`
  while (true) {
    $upload = $_GET["filename"];
    // is this the correct function and variable to use
    // to get written bytes of `stream_copy_to_stream($input, $file);`?
    $data = filesize($upload);
    // $data = $_GET["filename"] . " " . $_GET["filesize"];
    if ($data) {
      sendMessage($lastId, $data);
      $lastId++;
    } 
    // else {
    //   close stream 
    // }
    // not necessary here, though without thousands of `message` events
    // will be dispatched
    // sleep(1);
    }

    function sendMessage($id, $data) {
      echo "id: $id\n";
      echo "data: $data\n\n";
      ob_flush();
      flush();
    }
?>
Salin selepas log masuk

javascript

<!DOCTYPE html>
<html>
<head>
</head>
<body>
<input type="file">
<progress value="0" max="0" step="1"></progress>
<script>

const [url, stream, header] = ["data.php", "stream.php", "x-filename"];

const [input, progress, handleFile] = [
        document.querySelector("input[type=file]")
      , document.querySelector("progress")
      , (event) => {
          const [file] = input.files;
          const [{size:filesize, name:filename}, headers, params] = [
                  file, new Headers(), new URLSearchParams()
                ];
          // set `filename`, `filesize` as search parameters for `stream` URL
          Object.entries({filename, filesize})
          .forEach(([...props]) => params.append.apply(params, props));
          // set header for `POST`
          headers.append(header, filename);
          // reset `progress.value` set `progress.max` to `filesize`
          [progress.value, progress.max] = [0, filesize];
          const [request, source] = [
            new Request(url, {
                  method:"POST", headers:headers, body:file
                })
            // https://stackoverflow.com/a/42330433/
          , new EventSource(`${stream}?${params.toString()}`)
          ];
          source.addEventListener("message", (e) => {
            // update `progress` here,
            // call `.close()` when `e.data === filesize` 
            // `progress.value = e.data`, should be this simple
            console.log(e.data, e.lastEventId);
          }, true);

          source.addEventListener("open", (e) => {
            console.log("fetch upload progress open");
          }, true);

          source.addEventListener("error", (e) => {
            console.error("fetch upload progress error");
          }, true);
          // sanity check for tests, 
          // we don't need `source` when `e.data === filesize`;
          // we could call `.close()` within `message` event handler
          setTimeout(() => source.close(), 30000);
          // we don't need `source' to be in `Promise` chain, 
          // though we could resolve if `e.data === filesize`
          // before `response`, then wait for `.text()`; etc.
          // TODO: if and where to merge or branch `EventSource`,
          // `fetch` to single or two `Promise` chains
          const upload = fetch(request);
          upload
          .then(response => response.text())
          .then(res => console.log(res))
          .catch(err => console.error(err));
        }
];

input.addEventListener("change", handleFile, true);
</script>
</body>
</html>
Salin selepas log masuk

Atas ialah kandungan terperinci Bagaimana untuk Membaca dan Gema Menulis Saiz Fail yang Dimuat Naik Pada Masa Sedang Dalam Pelayan dalam Masa Nyata Tanpa Menyekat Pelayan dan Pelanggan?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:php
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!