Users send large Excel files from the site. I cut the file into chunks, upload to the server (PHP).
On the server side, merged chunks into a single file.xls, but when opening the message “content that could not be read was found in the book”.
I would appreciate it if you could answer my questions:
Question 1: Am I splitting the file correctly .xls in chunks and upload to server?
Question 2: How to assemble chunks into a single file .xls on the server side (PHP)?
My code example
HTML
<form>
<div>
<input type="file" name="upload_file" id="upload_file">
</div>
<br>
<div>
<buttton class="btn btn-secondary mt-3" id="but">Send</buttton>
</div>
</form>
JS
let chunkList = [];
let fileInput = document.getElementById('upload_file');
fileInput.addEventListener('change', function (event) {
let file = event.target.files[0];
let chunkSize = 1048576;
let currentChunk = 0;
let countChunks = Math.ceil(file.size / chunkSize)
let suffix = 'xls';
const hash = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
for(let i = 0; i < countChunks; i++){
const item = {
chunk: file.slice(currentChunk, currentChunk + chunkSize),
fileName: `${hash}_${i}.${suffix}`
}
currentChunk += chunkSize
chunkList.push(item)
}
})
let token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
let my_but = document.getElementById('but');
my_but.addEventListener('click', async function (event) {
let file = document.getElementById('upload_file').files[0];
if (file === undefined || chunkList.length < 1) return;
for (const item of chunkList) {
const formData = new FormData()
formData.append('chunk', item.chunk)
formData.append('filename', item.fileName)
let resp = await sendChunkFile(formData);
console.log(resp)
}
})
async function sendChunkFile(formData){
let response = await fetch('/api/chunks-file-upload', {
headers: {"X-CSRF-TOKEN": token},
method: 'POST',
credentials: "same-origin",
body: formData
});
return await response.json();
}
Server PHP (Laravel)
$pathChunks = 'chunks/';
$pathMerge = 'merge-file-chunks/';
$chunkNames = Storage::disk('local')->files($pathChunks);
foreach ($chunkNames as $chunkName) {
$result = Storage::disk('local')->append(
$pathMerge.'file.xls',
Storage::disk('local')->get($pathChunks.basename($chunkName))
);
}