Problem: upload je najbolj občutljiv vektor varnosti
Vsak upload je potencialno nevaren. Zlonameren uporabnik lahko naloži PHP datoteko z malicious kode in jo izvaja na strežniku. Slika je lahko zip bomba, PDF lahko vsebuje JavaScript, ki ga ranljivi PDF reader izvaja. Upload modul mora biti hkrati prijazen in varen.
Validacija – več plasti
1. Whitelisting extension
Sprejmemo SAMO tiste extensije, ki jih pričakujemo:
$allowed = ['stl', 'jpg', 'jpeg', 'png', 'pdf', 'ai', 'eps'];
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if (!in_array($ext, $allowed)) {
throw new RuntimeException('Format datoteke ni podprt.');
}
2. MIME type check
Brskalnik lahko laže o MIME tipu. Preverimo s `finfo`:
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $tmp_name);
finfo_close($finfo);
$allowed_mimes = [
'application/sla', // STL ASCII
'application/octet-stream', // STL binary
'image/jpeg',
'image/png',
'application/pdf',
'application/postscript', // AI, EPS
];
if (!in_array($mime, $allowed_mimes)) {
throw new RuntimeException('MIME tip ne ustreza.');
}
3. Velikost
Max 50 MB v PHP-ju + na strežniku (post_max_size, upload_max_filesize). Pri STL datotekah pogosto več kot 100 MB – obvestilo stranki, da raje pošlje compressed ZIP.
4. STL header check (za 3D datoteke)
STL ima specifičen format. Binary STL začenja z 80-byte header, ASCII STL pa s "solid". Preverimo prvih nekaj bajtov:
$fp = fopen($tmp_name, 'rb');
$header = fread($fp, 100);
fclose($fp);
$isAsciiStl = str_starts_with(trim($header), 'solid');
$isBinaryStl = strlen($header) === 100; // dovolj dolg za header
if (!$isAsciiStl && !$isBinaryStl) {
throw new RuntimeException('STL datoteka ni veljavna.');
}
Antivirus – ClamAV
Pri produkcijskih sistemih z file uploadom močno priporočamo antivirus skener. Najpogosteje ClamAV:
exec('clamscan --no-summary ' . escapeshellarg($tmp_name), $output, $code);
if ($code !== 0) {
unlink($tmp_name);
throw new RuntimeException('Datoteka je okužena z virusom.');
}
Varna hramba
- IZVEN webroot-a: `/private/uploads/`, ne `/public_html/uploads/`. Tako PHP ne more izvajati naloženih datotek.
- Naključno ime: ne `
.stl`, ampak ` - .stl`. Preprečuje overwrite napada. - Brez izvedbenih pravic: chmod 644 (rw-r--r--), brez x bit-a.
- .htaccess v upload mapi: `php_flag engine off` – tudi če pride PHP datoteka, se ne izvede.
Pretvorba in optimizacija
JPG / PNG → WebP
$image = imagecreatefromjpeg($source);
imagewebp($image, $destination, 80); // kakovost 80
imagedestroy($image);
STL → 3D preview slika
Pri Originate.direct smo uporabili Three.js za 3D preview v brskalniku + server-side render z OpenSCAD ali Blender CLI za statične preview slike.
PDF → JPG preview
S `imagick` ali `pdftoppm`:
$im = new Imagick();
$im->setResolution(150, 150);
$im->readImage($pdf_path . '[0]'); // prva stran
$im->setImageFormat('jpeg');
$im->writeImage($preview_path);
UX – kar stranka vidi
Drag & drop
Vlečenje datotek v polje + klik-za-izbiro fallback. HTML5 native:
<input type="file" id="upload" multiple accept=".stl,.jpg,.png,.pdf">
Progress bar
Pri večjih datotekah (STL > 10 MB) prikažemo upload progress. XMLHttpRequest s progress event-om.
Preview pred submitom
Pri slikah: thumbnail v brskalniku. Pri STL: 3D preview z Three.js (opcijsko).
Realne implementacije
- Originate.direct: STL upload za 3D tisk, PayPal plačilo, e-mail prodajalcu.
- 3DKristal.si: foto upload za pregled. Brezplačen pregled pred plačilom.
- Broška.si: grafika za broške – PDF, AI, EPS, JPG, PNG.
- Cut.si: grafika za tisk na majice ali izrez folije.
