Да будет код...
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/uploads
|
||||||
29
index.html
Normal file
29
index.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<script src="lib_chunk_file.js"></script>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Document</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<input type="file" name="file_name">
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const fileInput = document.querySelector('input[type="file"]');
|
||||||
|
|
||||||
|
fileInput.addEventListener('change', (event) => {
|
||||||
|
|
||||||
|
const files = event.target.files;
|
||||||
|
const file = files[0]
|
||||||
|
if (file) {
|
||||||
|
uploadFileInChunks(file);
|
||||||
|
}else{
|
||||||
|
alert("no file")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
31
lib_chunk_file.js
Normal file
31
lib_chunk_file.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
// Размер чанка в байтах
|
||||||
|
const CHUNK_SIZE = 1024 * 1024; // 1MB
|
||||||
|
|
||||||
|
async function uploadFileInChunks(file) {
|
||||||
|
|
||||||
|
const totalChunks = Math.ceil(file.size / CHUNK_SIZE);
|
||||||
|
|
||||||
|
for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
|
||||||
|
|
||||||
|
// Вычисляем начало и конец текущего чанка
|
||||||
|
const start = chunkIndex * CHUNK_SIZE;
|
||||||
|
const end = Math.min(start + CHUNK_SIZE, file.size);
|
||||||
|
|
||||||
|
// Извлекаем чанк из файла
|
||||||
|
const chunk = file.slice(start, end);
|
||||||
|
|
||||||
|
// Создаём FormData для отправки чанка
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file_chunk', chunk);
|
||||||
|
formData.append('chunk_index', chunkIndex);
|
||||||
|
formData.append('total_chunks', totalChunks);
|
||||||
|
formData.append('filename', file.name);
|
||||||
|
|
||||||
|
// Отправляем чанк на сервер
|
||||||
|
await fetch('upload.php', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
38
upload.php
Normal file
38
upload.php
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
$uploadDir = __DIR__ . '/uploads/';
|
||||||
|
if (!is_dir($uploadDir)) mkdir($uploadDir, 0755, true);
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$fileChunk = $_FILES['file_chunk'];
|
||||||
|
$chunkIndex = (int)$_POST['chunk_index'];
|
||||||
|
$totalChunks = (int)$_POST['total_chunks'];
|
||||||
|
$originalFilename = basename($_POST['filename']);
|
||||||
|
|
||||||
|
// Временный файл для хранения склеиваемых частей
|
||||||
|
$tempFilePath = $uploadDir . $originalFilename . '.part';
|
||||||
|
|
||||||
|
// Открываем временный файл для дозаписи (режим append)
|
||||||
|
$out = fopen($tempFilePath, 'ab');
|
||||||
|
if ($out) {
|
||||||
|
// Открываем переданную часть файла для чтения
|
||||||
|
$in = fopen($fileChunk['tmp_name'], 'rb');
|
||||||
|
if ($in) {
|
||||||
|
// Переносим данные из части в общий файл
|
||||||
|
stream_copy_to_stream($in, $out);
|
||||||
|
fclose($in);
|
||||||
|
}
|
||||||
|
fclose($out);
|
||||||
|
} else {
|
||||||
|
exit(json_encode(['status' => 'error', 'message' => 'Не удалось открыть временный файл']));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если это последняя часть, переименовываем файл в итоговый
|
||||||
|
if ($chunkIndex === $totalChunks - 1) {
|
||||||
|
$finalFilePath = $uploadDir . $originalFilename;
|
||||||
|
rename($tempFilePath, $finalFilePath);
|
||||||
|
echo json_encode(['status' => 'success', 'message' => 'Файл успешно собран', 'path' => $finalFilePath]);
|
||||||
|
} else {
|
||||||
|
echo json_encode(['status' => 'uploading', 'chunk' => $chunkIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
Reference in New Issue
Block a user