Návštěvník na webu někdy potřebuje nahrát soubor: fotku k poptávce, PDF s podklady nebo obrázek profilu. PHP to umí, ale právě soubory od cizích lidí patří k nejrizikovějším částem webu. Proto postupujeme krok za krokem.
Formulář pro soubor
<form action="nahrat.php" method="post" enctype="multipart/form-data">
<input type="file" name="soubor" accept="image/*">
<button type="submit">Nahrát</button>
</form>
Dvě věci jsou nutné. Atribut enctype="multipart/form-data" říká prohlížeči, že se posílá soubor, a bez něj PHP nic nedostane. Atribut accept nabídne jen vhodné typy, ale je to pomůcka pro uživatele, ne ochrana.
Co PHP dostane: $_FILES
<?php
$soubor = $_FILES["soubor"];
echo $soubor["name"]; // původní název souboru
echo $soubor["size"]; // velikost v bajtech
echo $soubor["tmp_name"]; // dočasná cesta na serveru
echo $soubor["error"]; // 0 znamená v pořádku
Údaje o souboru nejsou v $_POST, ale v $_FILES. Soubor je zatím jen v dočasné složce, dokud ho nepřesuneme na místo, kam patří.
Kontrola: chyba, velikost a typ
<?php
$soubor = $_FILES["soubor"];
if ($soubor["error"] !== UPLOAD_ERR_OK) {
exit("Soubor se nepodařilo nahrát.");
}
if ($soubor["size"] > 2 * 1024 * 1024) {
exit("Soubor je větší než 2 MB.");
}
$typ = mime_content_type($soubor["tmp_name"]);
$povolene = ["image/jpeg", "image/png"];
if (!in_array($typ, $povolene, true)) {
exit("Povolené jsou jen JPEG a PNG.");
}
Typ kontrolujeme podle obsahu souboru, ne podle přípony. Příponu lze snadno přejmenovat, takže soubor obrazek.jpg může být ve skutečnosti spustitelný skript.
Bezpečné uložení
<?php
$pripona = $typ === "image/png" ? "png" : "jpg";
$novyNazev = bin2hex(random_bytes(16)) . "." . $pripona;
$cil = __DIR__ . "/uploads/" . $novyNazev;
move_uploaded_file($soubor["tmp_name"], $cil);
Původní název souboru nepoužívejte. Může obsahovat cokoli, třeba ../, a přepsat cizí soubor. Náhodný název je bezpečnější. Funkce move_uploaded_file přesune soubor jen tehdy, pokud pochází z nahrání přes formulář.
uploads by neměla umožňovat spouštění PHP. Nahrané soubory ukládejte mimo kód, nebo na serveru zakažte spouštění skriptů v této složce.Časté chyby
- Chybějící enctype. Formulář pošle jen název souboru a PHP obsah nedostane.
- Důvěra v příponu. Kontrola podle přípony nestačí. Používejte MIME typ z obsahu souboru.
- Původní název souboru. Může přepsat existující soubor nebo obsahovat cesty. Vždy generujte nový název.
- Žádná kontrola velikosti. Velký soubor zaplní disk a zpomalí server.
Teď umíte přijmout soubor z formuláře a uložit ho bezpečně. Stejný postup, tedy nejdřív kontrola a teprve potom uložení, se hodí u každých dat od návštěvníka. 👍
Všechny návodyNechcete web řešit sami a chcete ho mít hotový a profesionální?
Podívejte se na tvorbu webů →© Ondřej Šteigl. Návody vznikají ve spolupráci s Claude (AI) a jsou upravovány autorem. Autorská práva k vlastním úpravám a příkladům náleží Ondřeji Šteiglovi. Kopírování nebo šíření celých textů bez písemného souhlasu je zakázáno. Výukové použití je vítáno, uveďte prosím zdroj (osteigl.cz).