Nahrávání souborů - Dropzone
Systém pro nahrávání PDF souborů, SVG obrázků, fotografií a jiných typů souborů s drag-and-drop interfacem.
Využíváme knihovnu Dropzone.js.
Postup implementace
- Definice pole v YAML
- Vykreslení pomocí Form.php
- Dropzone.js posílá fetch dle action
- Metoda "action" v kontroleru
- Volá se
DropzoneHandler::upload()
Příklad: Fotogalerie
Praktický příklad je dostupný v Adminu ve fotogalerii.
1. Definice pole v YAML
form_fields_add_photos:
-
section: start
title: Photos
-
name: file1
label: Photos
action: uploadPhoto
id: 101
text: "Přetáhněte sem soubory nebo klikněte pro nahrání."
element:
type: files
description: ...
Důležitá pole:
- id - ID elementu v DOM pro Dropzone
- action - Metoda kontroleru volaná z JS pomocí fetch
- element.type: files - Typ prvku pro vykreslení ve třídě Form
2. Vykreslení prvku ve formuláři
V třídě Form v metodě element_files():
private function element_files(array $element): void
{
if ($this->uploadAfterFirstSave($element)) {
return;
}
$queryParams = [
'page' => PAGE,
'lang' => LANG,
'action' => array_get_str($element, 'action', ''),
'id' => array_get_str($this->_CMS['url'], 'id', ''),
'PID' => array_get_str($this->_CMS['url'], 'PID', ''),
'width' => array_get_str($element['element'], 'width', ''),
'height' => array_get_str($element['element'], 'height', ''),
'prefix' => array_get_str($element['element'], 'prefix', ''),
];
$href = URL_APP_ADMIN . 'index.php?' . http_build_query($queryParams);
echo '<div id="dropzone' . $element['id'] . '" class="dropzone" data-url="' . $href . '">';
echo '<div class="dz-default dz-message"><span>{S ' . add_nbsp($element['text']) . '}</span></div>';
echo '</div>';
}
Vygeneruje <div id="dropzone101" class="dropzone" data-url="...">.
3. JS konfiguraci pro Dropzone
V src/backend/js/dropzone/files.js:
import {Dropzone} from 'dropzone';
import {i18n} from '../translations.js';
const id = 'dropzone101';
const element = document.getElementById(id);
if (element) {
new Dropzone(
'#' + id,
{
url: element.getAttribute('data-url'),
paramName: 'dzFile',
maxFilesize: 50, // MB
maxThumbnailFilesize: 50,
// omezení typů souborů
acceptedFiles: 'image/webp,image/jpeg,image/png',
// zmenšení obrázků
//resizeWidth: 1300,
//resizeHeight: 1300,
// překlady
dictFileTooBig: i18n('dropzoneBigFile', '{{filesize}}', '{{maxFilesize}}'),
dictInvalidFileType: i18n('dropzoneInvalidFileType'),
// chunking (pro velké soubory)
chunking: true,
forceChunking: true,
chunkSize: 1048576, // 1 MB
retryChunks: true,
retryChunksLimit: 3,
parallelUploads: 1,
init: function () {
this.on('success', function (file, response) {
console.log('File uploaded:', response);
});
this.on('error', function (file, errorMessage) {
console.error(file.name + ' / ' + errorMessage);
});
}
}
);
}
Viz dokumentace Dropzone.
4-5. PHP metoda v kontroleru
public function uploadPhoto(): void
{
// Defaultní options
$response = DropzoneHandler::upload();
// Nebo s vlastními options
/*
$options = [
'path' => DIR . '/var/tmp/',
'maxFileSizeMB' => 50,
'paramName' => 'dzFile',
'allowedExtensions' => ['pdf', 'jpg', 'png'],
];
$response = DropzoneHandler::upload($options);
*/
if (!empty($response['error'])) {
Debugger::log($response['error'], Debugger::ERROR);
echo $response['error'];
}
if (!empty($response['status'])) {
echo $response['status'];
}
if (!empty($response['name'])) {
// Zde se mění specifická logika pro zpracování souboru
if ($this->savePhoto($response)) {
if (!is_file($this->path . 'main-th.webp')) {
$this->mainPhoto(false);
}
$this->write_gallery($this->gallery, false);
$this->change_count_photos();
}
}
exit;
}
private function savePhoto($file): bool
{
$in = $file['path'];
// ... vaše logika pro uložení, resize, atd.
}
Pozn.: Tento základ by měl být všude stejný. Mění se jen blok po vrácení $response['name']. Metoda musí být vždy ukončena exitem.
DropzoneHandler
Statická metoda DropzoneHandler::upload() z core/Upload/DropzoneHandler.php:
- Vyřešení spojování částí souborů (chunking)
- Provádění bezpečnostních kontrol
- Uložení souboru do definované cesty (defaultně
/var/tmp/)
Vrací pole s:
[
'name' => 'filename.jpg',
'path' => '/var/tmp/filename.jpg',
'error' => null,
'status' => 'success'
]
Možnosti DropzoneHandler::upload()
$options = [
'path' => DIR . '/var/tmp/', // Kde uložit soubor
'maxFileSizeMB' => 50, // Max velikost MB
'paramName' => 'dzFile', // Param jméno
'allowedExtensions' => ['pdf', 'jpg', 'png'], // Povolené koncovky
];
Poznámky
- Soubory se nejdřív ukládají do dočasného adresáře
/var/tmp/ - Odtud si je kontroler zpracuje, zkrátí, uloží do finálního místa
- Chunking je užitečný pro obcházení
post_max_sizeomezení PHP - V DevTools konzoli se vypisují response odpovědi pro ladění