# Preverjanje in filtriranje vnosov v PHP s filter_var

> Preverjanje vnosov v PHP s filter_var in filter_input_array: števila, e-pošta, URL, bool, dovoljeni seznami in meje. S primeri kode in opozorili o pastih.

Vir: https://phpsos.de/sl/blog/eingaben-validieren-php/  
Stanje: 25.10.2026  
Ponudnik: PHP SOS, Nujna pomoč za PHP in varnost strežnikov. Takojšnja pomoč po WhatsAppu: https://wa.me/491736494914?text=Pozdravljeni%2C%20PHP%20SOS%2C%20potrebujemo%20pomo%C4%8D%20z%20na%C5%A1im%20stre%C5%BEnikom%20PHP.%20Podjetje%3A%20%E2%80%A6%20Spletna%20stran%3A%20%E2%80%A6

**Na kratko:** Vnose v PHP preverjate s `filter_var()` ali `filter_input_array()` in jasnimi pravili za vsako polje: tip, obseg, dolžina in dovoljene vrednosti. Kar ne ustreza, se zavrne, ne pa tiho predela. Preverjanje je pomembno za čiste podatke in manjšo napadalno površino, a ne nadomesti niti pripravljenih stavkov (prepared statements) proti SQL injection niti kodiranja, ustreznega kontekstu, proti XSS.

## Zakaj „filtriraj vse“ ni zasnova

V mnogih starejših projektih PHP je na začetku vsake datoteke zanka, ki vse vrednosti iz `$_GET` in `$_POST` pošlje skozi funkcijo za čiščenje. To daje občutek varnosti. V praksi včasih odstrani preveč, na primer opuščaje v priimkih, včasih premalo, ker naj bi ista funkcija hkrati veljala za SQL, HTML in imena datotek.

Smiselno preverjanje deluje drugače: za vsako polje se vpraša, kaj je tam dovoljeno. Naročena količina je celo število med 1 in zgornjo mejo. Polje za razvrščanje je ena od treh stalnih vrednosti. Datum je v določeni obliki in pred drugim datumom ali po njem. Vse drugo se zavrne.

OWASP pri tem razlikuje dve ravni: **sintaktično** preverjanje, ali ima vrednost pravo obliko, in **semantično** preverjanje, ali v kontekstu ima smisel. Obe sodita na strežnik; preverjanja v brskalniku služijo samo uporabnosti.

## Kateri filtri so vgrajeni v PHP

Razširitev filter je privzeto vključena v PHP. Najpomembnejši filtri za preverjanje po priročniku PHP:

| Filter | Preverja | Pomembne možnosti in opombe |
|---|---|---|
| `FILTER_VALIDATE_INT` | celo število | `min_range`, `max_range` |
| `FILTER_VALIDATE_FLOAT` | število z decimalko | `decimal` za ločilo |
| `FILTER_VALIDATE_BOOL` | logična vrednost | z `FILTER_NULL_ON_FAILURE` ločljivo od „false“ |
| `FILTER_VALIDATE_EMAIL` | oblika e-poštnega naslova | ne dokazuje, da nabiralnik obstaja |
| `FILTER_VALIDATE_URL` | oblika URL | shemo preverite sami, brez mednarodnih domen |
| `FILTER_VALIDATE_IP` | naslov IP | zastavice za zasebna in rezervirana območja |
| `FILTER_VALIDATE_REGEXP` | lasten vzorec | vzorec zasidrajte z `^` in `$` |

Filter za čiščenje `FILTER_SANITIZE_STRING` je od PHP 8.1 zastarel. Kdor ga še uporablja, naj preverjanje prestavi na ustrezne filtre in za izpis uporabi `htmlspecialchars()`.

## filter_var v PHP: pravilno preverjanje obrazca

S `filter_input_array()` je mogoče cel obrazec preveriti v enem koraku glede na definicijo. Neznana polja se pri tem ne prevzamejo:

```php
<?php
declare(strict_types=1);

$regeln = [
    'menge'   => ['filter' => FILTER_VALIDATE_INT,
                  'options' => ['min_range' => 1, 'max_range' => 50]],
    'email'   => FILTER_VALIDATE_EMAIL,
    'agb'     => ['filter' => FILTER_VALIDATE_BOOL, 'flags' => FILTER_NULL_ON_FAILURE],
    'versand' => ['filter' => FILTER_VALIDATE_REGEXP,
                  'options' => ['regexp' => '/^(standard|express)$/']],
];

$daten  = filter_input_array(INPUT_POST, $regeln) ?? [];
$fehler = [];

foreach ($regeln as $feld => $_) {
    if (!array_key_exists($feld, $daten) || $daten[$feld] === false || $daten[$feld] === null) {
        $fehler[] = $feld;
    }
}

if ($fehler !== []) {
    http_response_code(422);
    // Izpišite sporočilo o napaki za vsako polje, vnosov ne obdelujte
}
```

Upoštevajte stroge primerjave z `===`: veljavne vrednosti `0` ali praznega niza ne smete zamenjati z neuspehom. Zakaj so ohlapne primerjave tu nevarne, pojasnjuje [Type juggling: ohlapne primerjave kot varnostno tveganje](https://phpsos.de/sl/blog/type-juggling-php/). Kako PHP sploh daje na voljo podatke zahtev, opisuje [Superglobals: $_GET, $_POST, $_FILES in drugi](https://phpsos.de/sl/php/superglobals/).

## Pasti pri e-pošti, URL in prostem besedilu

Nekateri filtri naredijo manj, kot bi sklepali po imenu:

1. **URL-ji:** `FILTER_VALIDATE_URL` sprejme tudi druge sheme kot http in https. Shemo nato s `parse_url()` preverite proti stalnemu seznamu. Če strežnik URL pridobiva, veljajo dodatna pravila, glejte [Preprečevanje Server-Side Request Forgery v PHP](https://phpsos.de/sl/blog/ssrf-in-php/).
2. **E-poštni naslovi:** Filter preverja obliko, ne lastništva. Kdor mora biti prepričan, pošlje potrditveno povezavo.
3. **Prosto besedilo:** Imen, sporočil in naslovov skoraj ni smiselno omejiti na znake. Preverite dolžino in kodiranje znakov, na primer z `mb_check_encoding($wert, 'UTF-8')`, pri izpisu pa se zanesite na kodiranje.
4. **Regularni izrazi:** Brez `^` in `$` vzorec preveri samo, ali se nekje v besedilu pojavlja, ne pa ali ustreza celotna vrednost.
5. **Polja namesto nizov:** Napadalec lahko namesto besedila pošlje polje. Brez preverjanja tipa to vodi do opozoril ali nepričakovanega obnašanja.

> **Nasvet:**
> Za stalne izbirne vrednosti, kot so razvrščanje, jezik ali način dostave, je dovoljeni seznam z `in_array($wert, $erlaubt, true)` ali izrazom `match` preprostejši in strožji od vsakega regularnega izraza.

Druga pogosta napaka zadeva števila s pomenom, na primer cene, količine ali popuste. Dejstvo, da je vrednost veljavno število, ne pove ničesar o tem, ali je v kontekstu dovoljena. Negativna količina, popust nad vrednostjo blaga ali cena, prevzeta iz obrazca namesto iz baze podatkov, so klasične logične napake. Cene, pooblastila in vrednosti stanja zato vedno sodijo na strežnik in nikoli v skrita polja obrazca.

## JSON, webhooki in uvozi: preverjanje onkraj obrazcev

Mnogi vhodi danes niso več obrazci, ampak zahteve JSON iz aplikacij, webhooki ponudnikov plačil ali uvozne datoteke dobaviteljev. Tudi tam velja: najprej varno prebrati, nato preveriti. OWASP svetuje, da se velikost in globina gnezdenja omejita, še preden se podatki sploh preberejo. V PHP del tega prevzame `json_decode()` z največjo globino in `JSON_THROW_ON_ERROR`:

```php
<?php
$roh = file_get_contents('php://input', false, null, 0, 65536); // največ 64 KB
try {
    $daten = json_decode($roh, true, 16, JSON_THROW_ON_ERROR);
} catch (JsonException) {
    http_response_code(400);
    exit;
}
if (!is_array($daten) || !is_string($daten['bestellnummer'] ?? null)) {
    http_response_code(422);
    exit;
}
```

Pri webhookih pred vsebinskim preverjanjem stoji vprašanje, ali sporočilo res prihaja od navedene storitve. Če storitev ponuja podpis, ga preverite in primerjajte s `hash_equals()`. Pri uvoznih datotekah vsako vrstico preverite kot obrazec in ob napakah čisto prekinite, namesto da bi prevzeli napol zapise.

Sporočila o napakah naj navedejo prizadeto polje, zavrnjene vrednosti pa naj ne vračajo nefiltrirane. Sicer nastane na samem sporočilu o napaki novo mesto izpisa, ki ga je treba spet kodirati.

## Česa preverjanje ne zmore

Preverjanje zmanjša napadalno površino, a po OWASP ni glavna obramba pred injection. Priimek z opuščajem je veljaven in vseeno mora varno priti v bazo podatkov. To uspe samo s pripravljenimi stavki, kot kaže vodnik [Preprečevanje SQL injection v PHP](https://phpsos.de/sl/ratgeber/sql-injection-php/). In veljavno besedilo komentarja postane neškodljivo šele s kodiranjem, ustreznim kontekstu, pri izpisu.

Pravilni vrstni red je torej: ob prejemu preveriti, pri obdelavi parametrizirati, pri izpisu kodirati. Dodatno sodijo pred to omejitve velikosti: zahtev, ki so veliko prevelike, spletni strežnik in PHP sploh ne bi smela v celoti obdelati. Za to služijo nastavitve, kot je `post_max_size`, ki bi jih bilo po PHP2Shell tako ali tako treba preveriti.

## Kako konkretno pomaga PHP SOS?

- Zajamemo vse vhode vaše aplikacije: obrazce, vmesnike, nalaganja, uvoze in webhooke.
- Za vsako polje določimo, kaj je dovoljeno, in splošne funkcije za čiščenje nadomestimo z jasnimi preverjanji.
- Preverimo, ali so dostopi do baze podatkov in izpisi zavarovani neodvisno od preverjanja.
- Pravila dokumentiramo tako, da jih vaša ekipa lahko nadaljuje pri novih funkcijah.

Sistematičen pregled opisuje storitev [Varnostni pregled in penetracijski test](https://phpsos.de/sl/leistungen/sicherheitsaudit-penetrationstest/).


## Pogosta vprašanja

**Kakšna je razlika med preverjanjem in čiščenjem?**  
Preverjanje ugotovi, ali vrednost ustreza pričakovanjem, in jo sicer zavrne. Čiščenje vrednost spremeni, na primer z odstranitvijo znakov. Za varnostne odločitve je skoraj vedno bolje zavrniti, ker lahko tiho spremenjena vrednost povzroči nove napake.

**Ali je FILTER_SANITIZE_STRING še uporaben?**  
Filter je od PHP 8.1 označen kot zastarel. Priročnik PHP namesto tega priporoča htmlspecialchars() pri izpisu. Obstoječo kodo naj prilagodite, ker lahko zastarele funkcije v prihodnjih različicah odpadejo.

**Ali FILTER_VALIDATE_URL zadošča za varne povezave?**  
Ne. Filter preverja samo obliko naslova. Po priročniku veljavni URL ni nujno, da se začne s http, zato morate shemo sami preveriti proti dovoljenemu seznamu, kot je https. Mednarodnih domenskih imen filter ne sprejme.

**Ali moram preverjati tudi podatke iz lastne baze?**  
Pri izpisu veljajo za nezaupanja vredne in se ustrezno kodirajo. Ponovno preverjanje je smiselno, če so podatki izvirno prišli od zunaj in se zdaj uporabljajo v novem okviru, na primer kot ime datoteke ali del ukaza.

**Ali preverjanje pomaga proti PHP2Shell?**  
Ne. PHP2Shell zadeva obdelavo zahtev v interpreterju PHP, še preden sploh teče koda vaše aplikacije. Proti temu pomaga samo posodobitev PHP s sledečim ponovnim zagonom vseh procesov PHP.

## Viri

- [Priročnik PHP: konstante filtrov](https://www.php.net/manual/de/filter.constants.php)
- [OWASP Input Validation Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html)
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
