# Validare e filtrare gli input in PHP con filter_var

> Validare gli input in PHP con filter_var e filter_input_array: numeri, e-mail, URL, booleani, liste consentite e limiti. Con esempi di codice.

Fonte: https://phpsos.de/it/blog/eingaben-validieren-php/  
Stato: 25/10/2026  
Fornitore: PHP SOS, Assistenza di emergenza PHP e sicurezza dei server. Assistenza immediata su WhatsApp: https://wa.me/491736494914?text=Buongiorno%20PHP%20SOS%2C%20abbiamo%20bisogno%20di%20aiuto%20con%20il%20nostro%20server%20PHP.%20Azienda%3A%20%E2%80%A6%20Sito%20web%3A%20%E2%80%A6

**In breve:** gli input in PHP si validano con `filter_var()` o `filter_input_array()` e con regole chiare per ogni campo: tipo, intervallo, lunghezza e valori consentiti. Ciò che non corrisponde viene rifiutato, non rimaneggiato in silenzio. La validazione è importante per dati puliti e meno superficie di attacco, ma non sostituisce né i prepared statement contro la SQL injection né la codifica adeguata al contesto contro l'XSS.

## Perché «filtrare tutto» non è un concetto

In molti progetti PHP più vecchi, all'inizio di ogni file si trova un ciclo che fa passare tutti i valori di `$_GET` e `$_POST` attraverso una funzione di pulizia. Dà una sensazione di sicurezza. Nella pratica a volte rimuove troppo, ad esempio gli apostrofi nei cognomi, e a volte troppo poco, perché la stessa funzione dovrebbe valere contemporaneamente per SQL, HTML e nomi di file.

Una validazione sensata funziona diversamente: per ogni campo si chiede che cosa vi sia consentito. Una quantità ordinata è un numero intero tra 1 e un limite superiore. Un campo di ordinamento è uno di tre valori fissi. Una data ha un formato determinato e viene dopo un'altra data. Tutto il resto viene rifiutato.

OWASP distingue due livelli: la verifica **sintattica**, cioè se un valore ha la forma giusta, e la verifica **semantica**, cioè se nel contesto ha senso. Entrambe appartengono al server; le verifiche nel browser servono solo all'usabilità.

## Quali filtri offre PHP

L'estensione dei filtri è inclusa in PHP per impostazione predefinita. I principali filtri di validazione secondo il manuale PHP:

| Filtro | Verifica | Opzioni e note importanti |
|---|---|---|
| `FILTER_VALIDATE_INT` | Numero intero | `min_range`, `max_range` |
| `FILTER_VALIDATE_FLOAT` | Numero decimale | `decimal` per il separatore |
| `FILTER_VALIDATE_BOOL` | Valore di verità | Con `FILTER_NULL_ON_FAILURE` distinguibile da «falso» |
| `FILTER_VALIDATE_EMAIL` | Forma di un indirizzo e-mail | Non dimostra che la casella esista |
| `FILTER_VALIDATE_URL` | Forma di un URL | Controllare lo schema da sé, nessun dominio internazionalizzato |
| `FILTER_VALIDATE_IP` | Indirizzo IP | Flag per intervalli privati e riservati |
| `FILTER_VALIDATE_REGEXP` | Schema proprio | Ancorare lo schema con `^` e `$` |

Il filtro di pulizia `FILTER_SANITIZE_STRING` è obsoleto da PHP 8.1. Chi lo usa ancora dovrebbe passare per la validazione a filtri adatti e usare `htmlspecialchars()` per l'output.

## filter_var in PHP: verificare bene un modulo

Con `filter_input_array()` si può verificare un intero modulo in un solo passaggio rispetto a una definizione. I campi sconosciuti non vengono acquisiti:

```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);
    // Mostrare un messaggio di errore per campo, non elaborare gli input
}
```

Faccia attenzione ai confronti rigorosi con `===`: un valore valido `0` o una stringa vuota non vanno scambiati con un fallimento. Perché qui i confronti laschi siano pericolosi lo spiega [Type juggling: i confronti laschi come rischio di sicurezza](https://phpsos.de/it/blog/type-juggling-php/). Come PHP metta a disposizione i dati della richiesta lo descrive [Superglobali: $_GET, $_POST, $_FILES e simili](https://phpsos.de/it/php/superglobals/).

## Insidie con e-mail, URL e testi liberi

Alcuni filtri fanno meno di quanto il nome lasci supporre:

1. **URL:** `FILTER_VALIDATE_URL` accetta anche schemi diversi da http e https. Controlli poi lo schema con `parse_url()` rispetto a un elenco fisso. Se l'URL viene richiamato dal server, valgono regole aggiuntive, vedi [Prevenire il Server-Side Request Forgery in PHP](https://phpsos.de/it/blog/ssrf-in-php/).
2. **Indirizzi e-mail:** il filtro verifica la forma, non il possesso. Chi deve esserne certo invia un link di conferma.
3. **Testo libero:** nomi, messaggi e indirizzi difficilmente si possono limitare in modo sensato a certi caratteri. Verifichi lunghezza e codifica dei caratteri, ad esempio con `mb_check_encoding($wert, 'UTF-8')`, e in fase di output si affidi alla codifica.
4. **Espressioni regolari:** senza `^` e `$` uno schema verifica solo se compare da qualche parte nel testo, non se corrisponde l'intero valore.
5. **Array al posto di stringhe:** un aggressore può inviare un array invece di un testo. Senza verifica del tipo ciò porta ad avvisi o a comportamenti imprevisti.

> **Consiglio:**
> Per valori di scelta fissi come ordinamento, lingua o modalità di spedizione, una lista consentita con `in_array($wert, $erlaubt, true)` o un'espressione `match` è più semplice e più rigorosa di qualsiasi espressione regolare.

Un altro errore frequente riguarda i numeri con un significato, come prezzi, quantità o sconti. Il fatto che un valore sia un numero valido non dice nulla sul fatto che nel contesto sia consentito. Una quantità negativa, uno sconto superiore al valore della merce o un prezzo ripreso dal modulo anziché dal database sono classici errori logici. Prezzi, autorizzazioni e valori di stato appartengono perciò sempre al server e mai a campi nascosti del modulo.

## JSON, webhook e importazioni: validazione oltre i moduli

Oggi molti ingressi non sono più moduli, ma richieste JSON da app, webhook di servizi di pagamento o file di importazione dei fornitori. Anche lì vale: prima leggere in sicurezza, poi verificare. OWASP consiglia di limitare dimensione e profondità di annidamento prima ancora di leggere i dati. In PHP `json_decode()` con una profondità massima e `JSON_THROW_ON_ERROR` se ne occupa in parte:

```php
<?php
$roh = file_get_contents('php://input', false, null, 0, 65536); // al massimo 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;
}
```

Per i webhook, prima della verifica del contenuto c'è la domanda se il messaggio provenga davvero dal servizio indicato. Se il servizio offre una firma, la verifichi e la confronti con `hash_equals()`. Per i file di importazione verifichi ogni riga come un modulo e interrompa in modo pulito in caso di errori, anziché acquisire record a metà.

I messaggi di errore dovrebbero nominare il campo interessato, ma non restituire senza filtro il valore rifiutato. Altrimenti nel messaggio di errore stesso nasce un nuovo punto di output, che va a sua volta codificato.

## Che cosa la validazione non può fare

La validazione riduce la superficie di attacco, ma secondo OWASP non è la difesa principale contro l'injection. Un cognome con apostrofo è valido e deve comunque arrivare in sicurezza in un database. Ciò riesce solo con i prepared statement, come mostra la guida [Prevenire la SQL injection in PHP](https://phpsos.de/it/ratgeber/sql-injection-php/). E un testo di commento valido diventa innocuo solo con una codifica adeguata al contesto in fase di output.

L'ordine giusto è dunque: validare alla ricezione, parametrizzare nell'elaborazione, codificare nell'output. In più, prima di tutto ciò vanno posti limiti di dimensione: richieste decisamente troppo grandi non dovrebbero nemmeno essere elaborate per intero da server web e PHP. A questo servono impostazioni come `post_max_size`, che dopo PHP2Shell andrebbero comunque verificate.

## Come aiuta concretamente PHP SOS?

- Rileviamo tutti gli ingressi della sua applicazione: moduli, interfacce, upload, importazioni e webhook.
- Stabiliamo per ogni campo che cosa è consentito e sostituiamo le funzioni di pulizia generiche con verifiche chiare.
- Verifichiamo se accessi al database e output sono messi in sicurezza indipendentemente dalla validazione.
- Documentiamo le regole in modo che il suo team possa proseguirle con le nuove funzioni.

Una verifica sistematica è descritta nel servizio [audit di sicurezza e penetration test](https://phpsos.de/it/leistungen/sicherheitsaudit-penetrationstest/).


## Domande frequenti

**Qual è la differenza tra validare e ripulire?**  
Validare verifica se un valore corrisponde alle aspettative e, in caso contrario, lo rifiuta. Ripulire modifica il valore, ad esempio rimuovendo caratteri. Per le decisioni di sicurezza rifiutare è quasi sempre meglio, perché un valore modificato in silenzio può generare nuovi errori.

**FILTER_SANITIZE_STRING è ancora utilizzabile?**  
Il filtro è contrassegnato come obsoleto da PHP 8.1. Il manuale PHP raccomanda invece htmlspecialchars() in fase di output. Il codice esistente andrebbe aggiornato, perché le funzioni obsolete possono essere eliminate nelle versioni future.

**FILTER_VALIDATE_URL basta per rendere sicuri i link?**  
No. Il filtro verifica solo la forma dell'indirizzo. Secondo il manuale un URL valido non deve necessariamente iniziare con http, quindi lo schema va controllato da sé rispetto a una lista consentita come https. Il filtro rifiuta i nomi di dominio internazionalizzati.

**Devo validare anche i dati del mio database?**  
In fase di output sono considerati non affidabili e vengono codificati in modo adatto. Una nuova validazione ha senso se i dati provenivano originariamente dall'esterno e ora vengono usati in un nuovo contesto, ad esempio come nome di file o parte di un comando.

**La validazione aiuta contro PHP2Shell?**  
No. PHP2Shell riguarda l'elaborazione delle richieste nell'interprete PHP, prima ancora che giri il codice della sua applicazione. Contro di esso aiuta solo l'aggiornamento di PHP con il successivo riavvio di tutti i processi PHP.

## Fonti

- [Manuale PHP: costanti dei filtri](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/)
