
サーバーとクライアントをブロックせずに、サーバー側(cè)で書き込まれているアップロードされたファイルのサイズをリアルタイムで読み取り、出力するにはどうすればよいですか?
この問題をさらに詳しく見てみましょう:
ファイルのアップロードの進(jìn)行狀況をリアルタイムで取得するために、フェッチを通じて Blob、File、TypedArray、または ArrayBuffer オブジェクトから設(shè)定します。 POST リクエストの () 本文オブジェクト。
現(xiàn)在の実裝では、body オブジェクトに渡される fetch() の 2 番目の引數(shù)として File オブジェクトが設(shè)定されます。
要件:
テキスト/イベント ストリームとして、サーバーのファイル システムに書き込まれるファイルのサイズを読み取り、クライアントにエコー バックします。 GET リクエストの var クエリ文字列パラメータで指定されたすべてのバイトが書き込まれると停止します?,F(xiàn)在、ファイルの読み取りは別のスクリプト環(huán)境で行われ、ファイルを読み取るスクリプトに対して GET 呼び出しが行われ、次にファイルをサーバーに書き込むスクリプトに対して POST が行われます。
現(xiàn)在のファイル サイズを取得するためのサーバー側(cè)のファイル書き込みまたはファイル読み取りの処理に関する潛在的な問題を解決する前に、ファイル サイズのエコー部分が完了するまで待ってください。
現(xiàn)在、要件を満たすために php を使用しようとしています。しかし、C、bash、nodejs、Python、または同じタスクを?qū)g行するために使用できる他の言語やメソッドにも興味があります。
クライアント側(cè)の JavaScript 部分は問題ありません。私は、不必要な部分を含めずにパターンを?qū)g裝するための php (世界で最も広く使用されているサーバーサイド言語の 1 つ) に精通していません。
動(dòng)機(jī):
フェッチの進(jìn)行狀況インジケーター?
関連:
ReadableStream によるフェッチ
質(zhì)問:
Get
PHP Notice: Undefined index: HTTP_LAST_EVENT_ID in stream.php on line 7
ターミナル內(nèi)の
。
また、
while(file_exists($_GET["filename"])
&& filesize($_GET["filename"]) < intval($_GET["filesize"]))
を
while(true)
に置き換えると、EventSource でエラーが生成されます。
sleep() 呼び出しがない場(chǎng)合、サイズ 3.3MB のファイルのメッセージ イベントに正しいファイル サイズが送出され、同じファイルが 3 回アップロードされると、それぞれ 3321824、61921、26214、および 38093 が出力されます。期待される結(jié)果は、アップロードされたファイル オブジェクトのファイル サイズではなく、
stream_copy_to_stream($input, $file);
にファイルを書き込むときのファイル サイズを取得することです。 fopen() または stream_copy_to_stream() は、他の php プロセスが stream.php にアクセスするのを防ぎますか?
これまでに試したこと:
php
- からの引用 $_POST、$_GET、$_FILE を超えて: JavaScriptPHP の BLOB 処理
- PHP の例によるサーバー送信イベントの概要
php
// 能否合并 `data.php`、`stream.php` 為同一個(gè)文件?
// 能否使用 `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";
?>
// 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) && !empty($lastId) && 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();
}
?>
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>
以上がサーバーとクライアントをブロックせずに、サーバーにアップロードされたファイルの現(xiàn)在書き込みサイズをリアルタイムで読み取り、エコーする方法は?の詳細(xì)內(nèi)容です。詳細(xì)については、PHP 中國語 Web サイトの他の関連記事を參照してください。