# Kuidas PHP failide üleslaadimist töötleb

> Kuidas PHP failide üleslaadimist seespidiselt töötleb: multipart/form-data, ajutised failid kaustas upload_tmp_dir, $_FILES, piirangud ja veakoodid.

Allikas: https://phpsos.de/et/php/datei-uploads-intern/  
Seis: 25.10.2026  
Pakkuja: PHP SOS, PHP hädaabi ja serveri turvalisus. Kohene abi WhatsAppis: https://wa.me/491736494914?text=Tere%2C%20PHP%20SOS%2C%20vajame%20abi%20oma%20PHP-serveriga.%20Ettev%C3%B5te%3A%20%E2%80%A6%20Veebisait%3A%20%E2%80%A6

**Lühidalt:** Kui brauser faili üles laadib, saadab ta POST-päringu vormingus `multipart/form-data`, milles vormiväljad ja failide sisu on üksteise järel eraldi osadena. PHP lahutab selle päringu ise osadeks, kirjutab iga faili osa ajutisse faili kataloogi `upload_tmp_dir`, kannab andmed massiivi `$_FILES` ja käivitab alles seejärel teie skripti. Skript teisaldab faili funktsiooniga `move_uploaded_file()`; kõik, mida ei teisaldata, kustutab PHP päringu lõpus.

## Faili tee brauserist skriptini

Otsustajale on kõige olulisem üks asi: üleslaadimine ei ole üksnes rakenduse tegevus. Suur osa tööst toimub PHP interpretaatoris, enne kui CMS-i või poe kood üldse kaasa tuleb. Seetõttu mõjutavad selle PHP osa vead iga veebisaiti, olenemata sellest, kas sel on üleslaadimisvorm või mitte.

Kulg lühidalt:

1. Vorm, milles on `method="POST"` ja `enctype="multipart/form-data"`, saadetakse ära.
2. Veebiserver võtab päringu vastu ja annab selle edasi PHP-le, olenevalt töörežiimist PHP-FPM-i, mod_php või mõne muu liidese kaudu.
3. PHP kontrollib piiranguid, näiteks `post_max_size`, ja jaotab sisu osadeks eraldusmärgijada, nn boundary, järgi.
4. Tavalised väljad satuvad massiivi `$_POST`, failiosad kirjutatakse ajutistesse failidesse ja kirjeldatakse massiivis `$_FILES`.
5. Alles nüüd käivitub skript, kontrollib faili ja teisaldab selle sihtkohta.
6. Päringu lõpus kustutab PHP kõik ajutised failid, mida ei teisaldatud.

## multipart/form-data: üleslaadimispäringu ülesehitus

Üleslaadimispäring on puhas tekst, millesse on põimitud failiandmed. Päis `Content-Type` nimetab boundary, ja sisus eraldab see märgijada üksikud osad. Igal osal on oma päisread välja nime ja vajaduse korral failinimega. Tugevalt lühendatud, kahjutu näide:

```http
POST /bewerbung HTTP/1.1
Content-Type: multipart/form-data; boundary=----trenner42

------trenner42
Content-Disposition: form-data; name="vorname"

Erika
------trenner42
Content-Disposition: form-data; name="lebenslauf"; filename="lebenslauf.pdf"
Content-Type: application/pdf

%PDF-1.7 ... Dateiinhalt ...
------trenner42--
```

Kõik selle teksti andmed pärinevad saatjalt, ka failinimi ja osa `Content-Type`. PHP võtab need üle massiivi `$_FILES`, kuid ei kontrolli nende usutavust.

## Massiiv $_FILES

Välja nimega `lebenslauf` korral sisaldab `$_FILES['lebenslauf']` PHP käsiraamatu järgi järgmisi võtmeid:

| Võti | Sisu | Usaldusväärne? |
|---|---|---|
| `name` | algne failinimi saatja juures | ei |
| `full_path` | brauseri teatatud tee, alates PHP 8.1.0-st | ei |
| `type` | MIME-tüüp brauseri järgi, PHP ei kontrolli seda | ei |
| `size` | suurus baitides | PHP arvutab |
| `tmp_name` | ajutise faili tee serveris | PHP annab |
| `error` | üleslaadimise töötluse veakood | PHP seab |

Väljade korral, mille nimes on nurksulud, näiteks `bilder[]`, sisaldab iga võti massiivi, kus on iga faili kohta üks kirje. Rakendus käib siis läbi näiteks `$_FILES['bilder']['error']` ja pöördub sama indeksi kaudu `tmp_name` ja `name` poole.

Vorm võib enne failivälja saata ka peidetud välja `MAX_FILE_SIZE`. Käsiraamatu järgi on see üksnes vihje brauserile, mida on lihtne mööda minna. Toetuda saate ainult piirangutele, mida server jõustab: PHP-s, veebiserveris ja rakenduses endas.

## Piirangud: php.ini direktiivid üleslaadimiste jaoks

Need direktiivid juhivad üleslaadimiste töötlemist. Vaikeväärtused pärinevad PHP käsiraamatust ja kehtivad, kui php.ini neid üle ei kirjuta.

| Direktiiv | Vaikeväärtus | Muudetav kohas |
|---|---|---|
| `file_uploads` | `1` | ainult süsteemi seadistuses |
| `upload_tmp_dir` | tühi (süsteemi ajutine kataloog) | ainult süsteemi seadistuses |
| `upload_max_filesize` | `2M` | php.ini, pool, kataloogi seadistus |
| `post_max_size` | `8M` | php.ini, pool, kataloogi seadistus |
| `max_file_uploads` | `20` | php.ini, pool, kataloogi seadistus |
| `enable_post_data_reading` | `1` | php.ini, pool, kataloogi seadistus |

`post_max_size` peab olema suurem kui `upload_max_filesize` ja `memory_limit` peaks käsiraamatu järgi tavaliselt olema suurem kui `post_max_size`. Kui `upload_tmp_dir` ei ole kirjutatav, kasutab PHP selle asemel süsteemi ajutist kataloogi. Sätte `open_basedir` korral peab ajutine kataloog olema lubatud, muidu üleslaadimised ebaõnnestuvad. Praktilisi väärtusi ja nende tagajärgi kirjeldab artikkel [post_max_size ja upload_max_filesize mõistlik piiramine](https://phpsos.de/et/blog/post-max-size-upload-limits/).

## Veakoodide õige hindamine

Väli `error` ütleb, mis töötluse käigus juhtus. Konstandid ulatuvad väärtusest `UPLOAD_ERR_OK` (0) läbi `UPLOAD_ERR_INI_SIZE` (1), `UPLOAD_ERR_FORM_SIZE` (2), `UPLOAD_ERR_PARTIAL` (3) ja `UPLOAD_ERR_NO_FILE` (4) kuni `UPLOAD_ERR_NO_TMP_DIR` (6), `UPLOAD_ERR_CANT_WRITE` (7) ja `UPLOAD_ERR_EXTENSION` (8).

```php
<?php
declare(strict_types=1);

$datei = $_FILES['lebenslauf'] ?? null;
if ($datei === null) {
    exit('Keine Upload-Daten, eventuell wurde post_max_size überschritten.');
}

$meldung = match ($datei['error']) {
    UPLOAD_ERR_OK => null,
    UPLOAD_ERR_INI_SIZE, UPLOAD_ERR_FORM_SIZE => 'Datei zu groß.',
    UPLOAD_ERR_NO_FILE => 'Keine Datei gewählt.',
    default => 'Upload fehlgeschlagen.',
};

if ($meldung === null && is_uploaded_file($datei['tmp_name'])) {
    $ziel = '/srv/app/uploads/' . bin2hex(random_bytes(16)) . '.pdf';
    move_uploaded_file($datei['tmp_name'], $ziel);
}
```

Näide näitab ainult mehhanismi. Failitüübi kontrolli, salvestamist väljaspool veebijuurt ja skriptide käivitamise keelamist kirjeldab juhend [Failide üleslaadimine PHP-s turvaliselt](https://phpsos.de/et/ratgeber/datei-upload-sicher/).

## Üleslaadimised ja PHP2Shell: mida ajutised meetmed tähendavad

PHP2Shelli turvaaugud CVE-2026-109618 ja CVE-2026-109619 puudutavad päringu ümber toimuvat töötlust PHP interpretaatoris. Seetõttu nimetab php.net ajutiste meetmetena muu hulgas `post_max_size = 8M` (ilma üleslaadimisteta) või `32M` (üleslaadimistega), `upload_max_filesize` sellest väiksemana ning `session.upload_progress.enabled=0`. Need väärtused kuuluvad php.ini-sse, FPM-poolile või serveri seadistusse, pärast seda tuleb kõik workerid uuesti käivitada.

Erialaautorid soovitavad lisaks blokeerida `multipart/form-data` päringud väljaspool tegelikke üleslaadimisteid puhverserveris või WAF-is. See on mitteametlik meede, mille risk on vormide katkemine; kaalumist kirjeldab artikkel [Üleslaadimispäringute filtreerimine serveri serval](https://phpsos.de/et/blog/upload-anfragen-am-rand-filtern/). Ükski neist meetmetest ei asenda uuendust versioonile PHP 8.5.12, 8.4.27, 8.3.36 või 8.2.35.

## Kuidas PHP SOS konkreetselt aitab?

- Selgitame välja, millised teie veebisaidid üleslaadimisi tegelikult vajavad ja millistel teedel.
- Seame piirangud ja ajutised meetmed pooli kaupa, käivitame kõik workerid uuesti ja testime vorme.
- Kontrollime üleslaadimiskatalooge käivitatavate failide suhtes ja keelame skriptide käivitamise [serveri karastamise](https://phpsos.de/et/leistungen/server-haertung/) raames.
- Paigaldame PHP uuenduse ja dokumenteerime paigatud seisu iga veebisaidi kohta.


## Korduma kippuvad küsimused

**Kuhu PHP üleslaaditud failid esmalt salvestab?**  
Ajutisse kataloogi. Vaikimisi on selleks süsteemi ajutine kataloog; seda saab muuta sättega upload_tmp_dir. Kui skript faili ei teisalda, kustutab PHP selle päringu lõpus.

**Kas ma võin usaldada välja type massiivis $_FILES?**  
Ei. MIME-tüübi teatab brauser ja PHP ei kontrolli seda käsiraamatu järgi. Ka name ja full_path pärinevad saatjalt. Faili tegeliku tüübi tuvastate serveri poolel sisu põhjal.

**Miks on $_FILES tühi, kuigi fail saadeti?**  
Enamasti oli kogu päring suurem kui post_max_size. Siis tühjendab PHP $_POST ja $_FILES täielikult, massiivi veakoodi jätmata. Muud põhjused on vormis puuduv enctype või väljalülitatud file_uploads.

**Kas aitab PHP2Shelli vastu üleslaadimiste keelamine rakenduses?**  
Ei. Päringuandmete töötlemine toimub PHP-s enne, kui rakenduse kood üldse käivitub. Tõhusad on PHP uuendus ja kõigi workerite taaskäivitus; kitsamad piirangud on vaid ajutine meede.

**Mis vahe on upload_max_filesize'il ja post_max_size'il?**  
upload_max_filesize piirab iga üksikut faili, post_max_size kogu päringu sisu koos kõigi failide ja väljadega. post_max_size peab seetõttu olema suurem kui upload_max_filesize.

## Allikad

- [PHP käsiraamat: üleslaadimised POST-meetodiga](https://www.php.net/manual/de/features.file-upload.post-method.php)
- [PHP käsiraamat: üleslaadimise veateated](https://www.php.net/manual/de/features.file-upload.errors.php)
- [PHP käsiraamat: php.ini direktiivid](https://www.php.net/manual/de/ini.core.php)
- [php.net: turvateated](https://www.php.net/)
