Ondřej Šteigl - Logo ONDŘEJ ŠTEIGL
PHP

Nahrávání souborů v PHP (bezpečně)

Jak přijmout obrázek nebo PDF z formuláře, zkontrolovat ho a uložit tak, aby z toho nevznikla bezpečnostní díra.

Čtení 8 min začátečník Naposledy upraveno 2. 11. 2026

Předtím: Přihlášení v PHP: hesla, session a chráněné stránky

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ář.

💡 Tip: Složka 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

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ávody

Nechcete 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).

← Zpět na všechny návody

Nezmeškejte nový návod

Když vyjde nový návod, pošleme vám krátký e-mail. Žádný spam, odhlásit se jde jedním klikem.

QR platba – dobrovolný příspěvek

☕ Byl návod užitečný?

Můžete mě podpořit dobrovolným příspěvkem – nepovinně, třeba stovkou na provoz a na kafe. Načtěte QR v bankovní aplikaci, nebo pošlete na účet 6048546800/6363. Díky!