PHP continua a essere uno dei linguaggi più utilizzati per sviluppare applicazioni Web, gestire contenuti dinamici e costruire servizi accessibili attraverso Internet. Dietro piattaforme come WordPress, PrestaShop, Magento, Moodle, Nextcloud, Joomla e numerose applicazioni aziendali opera un motore PHP che riceve richieste, elabora informazioni, interroga database e genera risposte destinate ai browser o ad altri programmi.
Installare PHP non significa installare un server Web; allo stesso modo, avere PHP installato sul computer non garantisce che Apache, Nginx o IIS sappiano come utilizzarlo.
Esistono diverse modalità per eseguire gli script PHP, ciascuna con caratteristiche differenti in termini di prestazioni, gestione dei processi, consumo di memoria e sicurezza. Espressioni come mod_php, CGI, FastCGI, PHP-FPM e SAPI identificano componenti e meccanismi distinti, che è importante comprendere prima di configurare un server o intervenire su un’installazione esistente.
Vediamo quindi cos’è PHP, come viene eseguito, come installarlo su Windows, Linux e altri ambienti, come configurarlo e aggiornarlo, approfondendo anche le differenze tra le principali architetture disponibili e gli accorgimenti necessari per utilizzarlo correttamente in produzione.
Cos’è PHP e a cosa serve
PHP è un linguaggio di programmazione general purpose, particolarmente adatto allo sviluppo Web lato server. La sigla, inizialmente associata all’espressione Personal Home Page, indica oggi PHP: Hypertext Preprocessor, un acronimo ricorsivo che richiama la sua funzione originaria di elaborazione dei contenuti prima che raggiungano il browser.
A differenza di HTML, che descrive la struttura di una pagina, PHP permette di eseguire istruzioni, elaborare dati, applicare condizioni, accedere al filesystem, interrogare database e comunicare con altri servizi. Uno script PHP può generare HTML, ma anche produrre documenti JSON, file XML, immagini, documenti PDF e altri tipi di contenuto.
Il linguaggio comprende funzioni, classi, interfacce, enumerazioni, gestione delle eccezioni, dichiarazioni di tipo e numerose caratteristiche tipiche della programmazione moderna.
Un’applicazione PHP può gestire l’autenticazione degli utenti, elaborare ordini, fornire API REST (interfacce che permettono ad applicazioni e servizi di comunicare attraverso richieste HTTP, scambiando dati generalmente in formato JSON), effettuare operazioni pianificate o comunicare con servizi esterni.
L’esecuzione non richiede necessariamente un browser: mediante l’interfaccia a riga di comando, PHP può essere utilizzato anche per sviluppare script di amministrazione, procedure automatizzate e strumenti destinati all’esecuzione su server.
Qual è la differenza tra PHP, JavaScript e HTML
Le tre tecnologie svolgono funzioni differenti, pur potendo collaborare nella stessa applicazione.
Come già osservato in precedenza, HTML definisce la struttura dei documenti visualizzati dal browser. JavaScript permette di gestire interazioni, aggiornare elementi della pagina e comunicare con servizi remoti; può inoltre essere eseguito lato server attraverso runtime come Node.js.
PHP opera sul server, dove accede alle risorse necessarie per elaborare la richiesta e generare la risposta.
Il browser non riceve il codice sorgente PHP, ma soltanto il risultato della sua esecuzione: un sito può quindi utilizzare PHP per recuperare i dati di un prodotto, HTML per rappresentarli e JavaScript per aggiornare dinamicamente un carrello virtuale (si pensi alle piattaforme di ecommerce) senza ricaricare l’intera pagina.
Le credenziali di accesso al database, le chiavi private e la logica applicativa riservata devono rimanere sul server, senza finire nel contenuto HTML o JavaScript inviato al client.
Perché PHP è così utilizzato
Una delle ragioni della diffusione di PHP risiede nella disponibilità di strumenti, librerie e applicazioni sviluppati nel corso del tempo.
WordPress rappresenta uno degli esempi più conosciuti, ma il linguaggio trova impiego anche in CMS, software gestionali, piattaforme per il commercio elettronico e applicazioni realizzate su misura.
PHP si integra con server Web diffusi come Apache e Nginx, dispone di driver per numerosi database e può funzionare su Windows, Linux e macOS. Framework come Laravel e Symfony consentono di organizzare applicazioni complesse con architetture modulari, sistemi di routing, gestione delle dipendenze e procedure di test.
Con il passare del tempo, PHP continua ad evolvere anche in termini di funzionalità: le versioni della famiglia PHP 8, ad esempio, hanno introdotto e perfezionato caratteristiche quali union types, attributi, enumerazioni, proprietà di sola lettura e numerosi miglioramenti al sistema dei tipi e al motore di esecuzione.
L’utilità di PHP dipende soprattutto dall’applicazione da realizzare: non esiste una ragione tecnica per considerarlo sempre preferibile a Python, JavaScript, Go o Java. Certo che è PHP resta super adatto per lo sviluppo di applicazioni e servizi Web.
Come funziona PHP quando si apre una pagina Web
Supponiamo che l’utente visiti l’indirizzo https://www.esempio.it/prodotti.php?id=42: il browser stabilisce una connessione con il server e invia una richiesta HTTP.
Il server Web, per esempio Apache o Nginx, identifica la risorsa richiesta e determina come gestirla. Se si tratta di un’immagine o di un documento statico, il server può inviare direttamente il contenuto. Se invece la richiesta riguarda uno script PHP, deve affidarne l’elaborazione al runtime PHP attraverso una delle modalità di integrazione disponibili.
Il codice dell’applicazione potrebbe recuperare il prodotto con identificativo 42 (vedere l’URL di esempio citato in precedenza) da un database, verificarne la disponibilità, calcolare il prezzo e costruire una pagina HTML. Il risultato dell’elaborazione torna al server Web, che lo trasmette al browser all’interno di una risposta HTTP.
Nelle applicazioni moderne non sempre esiste un file PHP corrispondente all’indirizzo richiesto: framework e CMS possono utilizzare un unico punto di ingresso, spesso chiamato index.php, al quale il server inoltra richieste destinate a percorsi differenti. Un indirizzo come /prodotti/42 può quindi attivare codice PHP senza contenere l’estensione .php.

Zend Engine: come PHP trasforma il codice in istruzioni eseguibili
Il componente fondamentale del runtime è lo Zend Engine, che si occupa delle operazioni necessarie per eseguire i programmi PHP.
Il motore analizza il codice sorgente, ne verifica la struttura sintattica e lo compila in una rappresentazione intermedia composta da opcode. Queste istruzioni sono poi elaborate dalla macchina virtuale di PHP, spesso indicata come Zend VM.
Descrivere PHP come un linguaggio interpretato è quindi una semplificazione: il codice non viene necessariamente riletto ed eseguito direttamente riga per riga, perché interviene una fase di compilazione intermedia.
Per evitare di ripetere inutilmente parte di tale lavoro, PHP dispone di OPcache, un componente che mantiene in memoria condivisa gli opcode già compilati e permette di riutilizzarli nelle richieste successive.
PHP include inoltre un compilatore Just-In-Time (JIT), capace, quando configurato, di tradurre determinate porzioni di codice in istruzioni macchina. I vantaggi che scaturiscono da quest’approccio dipendono dal tipo di elaborazione e non corrispondono a un miglioramento generalizzato delle prestazioni di WordPress o di qualsiasi applicazione Web.
Un semplice esempio di script PHP
Un programma PHP può essere contenuto in un normale file di testo con estensione .php. Il seguente esempio utilizza un parametro ricevuto dalla richiesta, ne controlla il contenuto e lo inserisce in una pagina HTML:
<?php
$nome = $_GET['nome'] ?? 'Visitatore';
if (!is_string($nome)) {
$nome = 'Visitatore';
}
$nome = htmlspecialchars(
$nome,
ENT_QUOTES | ENT_SUBSTITUTE,
'UTF-8'
);
?>
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<title>Esempio PHP</title>
</head>
<body>
<h1>Ciao, <?= $nome ?></h1>
</body>
</html>
Salvando il codice nel file index.php e richiamando l’indirizzo http://localhost:8000/?nome=Marco, la pagina mostrerà il messaggio Ciao, Marco.
L’espressione $_GET['nome'] legge il parametro dalla query string. L’operatore ?? permette di utilizzare un valore predefinito quando il parametro non esiste, mentre il controllo sul tipo impedisce di trattare un array come una semplice stringa. La funzione htmlspecialchars() converte determinati caratteri speciali in entità HTML, riducendo il rischio che il contenuto fornito dall’utente sia interpretato come markup o codice eseguibile nel browser. Il costrutto <?= $nome ?> rappresenta una forma abbreviata di echo.
Eseguire PHP senza Apache o Nginx
Una volta installato il runtime, il programma può essere lanciato direttamente dal terminale:
php script.php
PHP comprende anche un piccolo server HTTP integrato, utile per verificare il comportamento delle applicazioni durante lo sviluppo. Spostandosi nella directory che contiene index.php, basta eseguire:
php -S 127.0.0.1:8000
Il browser può quindi collegarsi all’indirizzo locale http://127.0.0.1:8000/. È importante sottolineare che il server HTTP integrato in PHP non è destinato agli ambienti di produzione. Anche la documentazione ufficiale lo considera uno strumento di sviluppo e test, non un sostituto di server come Apache, Nginx o di un application server adeguatamente configurato.
Come installare PHP su Windows 11 e Windows Server
Su Windows, PHP può funzionare come interprete a riga di comando, essere collegato al server Apache oppure essere utilizzato attraverso IIS e FastCGI.
Per effettuare un’installazione manuale, il punto di partenza è la pagina ufficiale di download di PHP, dalla quale si possono raggiungere anche i pacchetti compilati per Windows.
Basta scegliere la versione compatibile con il sistema e con le applicazioni che si intendono eseguire: per le normali installazioni x64, va usata una build a 64 bit, verificando anche la presenza del runtime Microsoft Visual C++ richiesto.
Un aspetto spesso trascurato riguarda la distinzione tra le distribuzioni Thread Safe (TS) e Non Thread Safe (NTS).
Le build TS comprendono il supporto necessario per l’esecuzione in ambienti multithread, come determinate configurazioni di PHP caricato come modulo di Apache.
Le build NTS sono invece adatte all’esecuzione tramite FastCGI e comunemente utilizzate con IIS o dalla riga di comando.
Installazione manuale e configurazione del PATH
Dopo aver scaricato l’archivio ZIP della versione scelta, si possono estrarre i file, per esempio, nella directory C:\PHP. All’interno sono disponibili l’eseguibile php.exe, destinato anche alla riga di comando, php-cgi.exe, utilizzato per CGI/FastCGI, e gli altri componenti della distribuzione.
Per permettere a Windows di individuare PHP da qualsiasi directory, si può aggiungere C:\PHP alla variabile d’ambiente Path, attraverso le impostazioni avanzate del sistema. Aprendo un nuovo terminale PowerShell o Prompt dei comandi, il controllo avviene mediante:
php -v
Il comando deve riportare la versione e le informazioni relative alla build in uso. Per individuare l’eseguibile effettivamente richiamato, su PowerShell si può utilizzare:
Get-Command php
La verifica è particolarmente utile quando sul computer sono già presenti altri ambienti di sviluppo che distribuiscono una propria copia di PHP.
Preparare il file php.ini su Windows
La distribuzione PHP include normalmente due modelli di configurazione: php.ini-development e php.ini-production. Il primo propone impostazioni più orientate allo sviluppo, mentre il secondo applica valori più adatti a un server di produzione. Le configurazioni vanno comunque adattate all’utilizzo effettivo.
Per creare una configurazione iniziale, ad esempio, si può copiare il modello di sviluppo:
Copy-Item C:\PHP\php.ini-development C:\PHP\php.ini
Successivamente si modifica php.ini con un editor di testo e si controllano le direttive necessarie, tra cui:
date.timezone = Europe/Rome
memory_limit = 256M
extension_dir = "ext"
extension=pdo_mysql
La direttiva extension_dir indica dove PHP deve cercare le estensioni dinamiche, mentre extension=pdo_mysql abilita il driver PDO per MySQL se disponibile nella distribuzione. Il comando php --ini mostra i percorsi nei quali PHP cerca i file di configurazione e identifica il php.ini effettivamente caricato. Per elencare i moduli attivi si utilizza php -m.
Installare correttamente l’interprete consente già di eseguire script PHP dal terminale. Per pubblicare applicazioni Web occorre invece configurare il collegamento con il server HTTP.
Utilizzare PHP con IIS
Windows Server include IIS, il server Web Microsoft, che può eseguire applicazioni PHP attraverso FastCGI.
In questo caso, la configurazione prevede l’abilitazione del componente CGI nelle funzionalità di IIS e l’associazione dei file .php al gestore FastCGI, utilizzando php-cgi.exe e non php.exe.
Una volta attivato il ruolo o la funzionalità necessaria, tramite IIS Manager si può creare la corrispondenza tra le richieste dirette ai file PHP e l’eseguibile del runtime. Occorre inoltre configurare i permessi, il file php.ini e il numero di processi disponibili secondo il carico applicativo.
Il manuale ufficiale descrive la configurazione di PHP con IIS e FastCGI.
XAMPP, Laragon e altri ambienti pronti all’uso
Per chi desidera sviluppare applicazioni PHP sul proprio PC senza configurare manualmente tutti i componenti, esistono pacchetti che comprendono PHP, un server Web e spesso un database. XAMPP e Laragon sono esempi di ambienti concepiti per semplificare le attività di sviluppo locale.
Il vantaggio principale consiste nella possibilità di iniziare rapidamente a lavorare, ma è essenziale distinguere il PHP distribuito dal pacchetto da eventuali altre installazioni presenti nel sistema.
Gli ambienti preconfigurati devono inoltre essere mantenuti aggiornati e non dovrebbero essere esposti direttamente sulla rete Internet senza un’adeguata configurazione di sicurezza.
Come installare PHP su Linux: Ubuntu, Debian, Fedora e AlmaLinux
Nelle distribuzioni Linux, PHP è generalmente distribuito attraverso pacchetti gestiti da APT o DNF. Questa modalità semplifica l’installazione delle dipendenze e consente di ricevere aggiornamenti attraverso i repository configurati. Su Ubuntu e Debian, dopo aver aggiornato gli indici dei pacchetti, è possibile installare l’interprete CLI con:
sudo apt update
sudo apt install php-cli
Per utilizzare PHP con un server Web attraverso PHP-FPM e con alcune estensioni comuni:
sudo apt install php-fpm php-mysql php-mbstring \
php-xml php-curl php-zip
I nomi dei pacchetti e le versioni disponibili dipendono dalla distribuzione e dalla release utilizzata. Su sistemi appartenenti alla famiglia Fedora/RHEL, la procedura si basa generalmente su DNF:
sudo dnf install php-cli php-fpm php-mysqlnd \
php-mbstring php-xml php-gd
Nei sistemi RHEL e compatibili è possibile avvalersi di repository AppStream, moduli o repository aggiuntivi. Prima di installare una specifica versione di PHP è quindi opportuno verificare quali pacchetti siano effettivamente disponibili e quali politiche di aggiornamento vengano adottate.
Dove si trova PHP su Linux
L’eseguibile è spesso disponibile come /usr/bin/php, ma il percorso non deve essere dato per scontato. Per individuarlo si utilizza command -v php; per conoscerne la versione, php -v; per identificare i file di configurazione, php --ini.
Nelle distribuzioni Debian e Ubuntu si incontrano frequentemente percorsi come:
/etc/php/8.x/cli/php.ini
/etc/php/8.x/fpm/php.ini
/etc/php/8.x/fpm/pool.d/www.conf
La notazione 8.x è indicativa e va sostituita con la versione realmente installata. Nei sistemi RHEL e Fedora, invece, la configurazione può risiedere in /etc/php.ini, mentre le impostazioni di PHP-FPM si trovano abitualmente sotto /etc/php-fpm.d/.
Un errore comune consiste nel modificare il file php.ini della CLI aspettandosi di cambiare il comportamento degli script eseguiti dal server Web. PHP può caricare configurazioni differenti a seconda della modalità di esecuzione.
Avviare e controllare PHP-FPM su Linux
PHP-FPM opera come servizio separato e deve essere attivo affinché Apache o Nginx possano utilizzarlo. Su Ubuntu, dove il servizio è spesso identificato dalla versione, il comando può essere:
sudo systemctl status php8.4-fpm
Su Fedora e in alcune configurazioni RHEL il nome del servizio è invece semplicemente:
sudo systemctl status php-fpm
Per riavviare il servizio si sostituisce status con restart. È necessario verificare il nome effettivo dell’unità systemd installata; prima di intervenire su un server in produzione consigliamo di controllare la sintassi delle configurazioni e distinguere i riavvii completi dalle operazioni di reload supportate dal servizio.
Installare PHP su macOS, WSL2 e Docker
Su macOS uno degli strumenti più pratici per installare PHP è Homebrew. Dopo aver predisposto il gestore di pacchetti, è possibile utilizzare:
brew install php
La disponibilità di formule per specifiche versioni e le eventuali operazioni di collegamento degli eseguibili dipendono dai pacchetti presenti nei repository Homebrew.
Su Windows 11 è possibile ricorrere anche a Windows Subsystem for Linux (WSL2), installando una distribuzione Linux ed eseguendo PHP al suo interno. Il vantaggio consiste nell’utilizzare strumenti e procedure simili a quelli di un server Linux reale, pur continuando a lavorare dal desktop Windows.
Per gli ambienti di sviluppo isolati e riproducibili, Docker rappresenta un’altra possibilità. Le immagini ufficiali PHP comprendono varianti destinate a impieghi differenti, tra cui cli, apache e fpm. Un esempio per verificare la versione del runtime tramite un container temporaneo è:
docker run --rm php:8.5-cli php -v
Il comando utilizza l’immagine della famiglia PHP 8.5 e avvia l’interprete senza installarlo direttamente nel sistema operativo.
Per utilizzare PHP-FPM con Docker, invece, si configura normalmente un container dedicato al runtime e un altro per Nginx, collegati attraverso una rete privata.
Il server Web deve conoscere l’indirizzo del servizio FastCGI e condividere, quando necessario, l’accesso ai file dell’applicazione. Nei container è particolarmente importante non pubblicare direttamente su Internet la porta FastCGI di PHP-FPM: tale interfaccia è destinata alla comunicazione con componenti fidati, non ai browser.
PHP SAPI: perché lo stesso linguaggio può essere eseguito in modi differenti
Una volta installato PHP, bisogna stabilire come eseguire gli script: si parla quindi di SAPI, acronimo di Server Application Programming Interface.
Una SAPI costituisce l’interfaccia attraverso la quale il motore PHP interagisce con l’ambiente che ne richiede l’esecuzione. Stabilisce, tra le altre cose, come inizializzare una richiesta, rendere disponibili i parametri, gestire l’input e l’output e comunicare il risultato al componente chiamante.
Le SAPI non coincidono con i protocolli di comunicazione. CGI e FastCGI, ad esempio, definiscono meccanismi di interazione tra server Web e applicazioni; PHP-FPM aggiunge un sistema di gestione dei processi che utilizza FastCGI. Il medesimo codice PHP può quindi operare in ambienti differenti pur sfruttando sempre lo Zend Engine.
Per identificare la SAPI in uso, PHP fornisce la funzione seguente:
<?php
echo PHP_SAPI;
È disponibile anche la funzione php_sapi_name(), che restituisce un risultato equivalente. Tra i valori possibili figurano cli, apache2handler, cgi-fcgi e fpm-fcgi.
PHP eseguito tramite FPM identifica generalmente la propria SAPI come fpm-fcgi, mentre una richiesta gestita direttamente da php-cgi attraverso FastCGI può riportare cgi-fcgi. Non bisogna tuttavia dedurre l’intera architettura del server da una sola stringa, soprattutto quando sono presenti proxy, container e ulteriori livelli applicativi.
mod_php: PHP caricato direttamente dentro Apache
Una delle modalità storiche di esecuzione di PHP consiste nel caricare il runtime come modulo del server Apache. Questa soluzione è comunemente indicata con il nome mod_php. Il codice PHP è eseguito all’interno dei processi Apache, senza ricorrere a un servizio PHP-FPM separato.
Quando Apache riceve una richiesta associata a uno script PHP, l’handler del modulo attiva il motore PHP e restituisce il risultato al sistema di elaborazione delle risposte HTTP.
La configurazione risulta concettualmente semplice perché PHP e Apache condividono lo stesso processo, ma presenta implicazioni importanti in termini di memoria e concorrenza.
Il rapporto tra mod_php e Apache MPM
Apache supporta differenti modelli di gestione dei processi e dei thread, denominati Multi-Processing Modules (MPM). Tra i più conosciuti figurano prefork, worker ed event.
Con prefork, Apache utilizza processi separati per gestire le connessioni, evitando di affidarsi a più thread all’interno dello stesso processo per l’elaborazione delle richieste. worker ed event adottano invece un’architettura multithread, con caratteristiche differenti nella gestione delle connessioni.
Sulle comuni distribuzioni Linux, il modulo PHP tradizionale viene generalmente utilizzato con Apache MPM prefork. La ragione non è che lo Zend Engine moderno sia incapace di utilizzare thread, ma che le normali build e le estensioni PHP non devono essere considerate automaticamente sicure in qualunque configurazione multithread.
L’impiego di mod_php può quindi vincolare la scelta dell’MPM e impedire di sfruttare pienamente i vantaggi architetturali di event. Per verificare quale MPM stia utilizzando Apache:
apachectl -V
La voce Server MPM permette di identificare il modello attivo. Per controllare i moduli caricati:
apachectl -M
A seconda della distribuzione, il comando potrebbe richiedere privilegi amministrativi oppure essere disponibile come apache2ctl.
Quando mod_php diventa uno svantaggio
Con mod_php, i processi Apache incorporano anche il runtime PHP. Ciò può aumentare il consumo di memoria rispetto a configurazioni nelle quali il server Web gestisce direttamente contenuti statici e connessioni, delegando a processi separati soltanto l’esecuzione degli script.
Inoltre, il codice PHP condivide il contesto operativo del processo Apache, rendendo più complessa la separazione dei privilegi tra applicazioni ospitate sullo stesso server.
Il modello non è intrinsecamente insicuro e può continuare a funzionare correttamente in ambienti semplici o esistenti. Tuttavia, per nuove installazioni Linux che utilizzano Apache, PHP-FPM rappresenta spesso una scelta più flessibile, soprattutto quando bisogna ospitare più applicazioni, separare utenti e ottimizzare la gestione dei processi.
php-cgi: cosa significa eseguire PHP tramite CGI
CGI, acronimo di Common Gateway Interface, è uno standard storico che permette a un server Web di interagire con programmi esterni. Nel modello CGI tradizionale, il server può avviare un processo per gestire una richiesta dinamica. Le informazioni necessarie vengono comunicate attraverso variabili d’ambiente e flussi di input/output.
PHP dispone dell’eseguibile php-cgi, che può operare in questo ambiente. Il principale limite del modello CGI classico è il costo associato alla creazione e alla terminazione dei processi. Quando il traffico cresce, ripetere continuamente queste operazioni introduce un overhead che può incidere significativamente sulle prestazioni.
Non bisogna però identificare php-cgi esclusivamente con il vecchio modello di un processo per ogni richiesta: lo stesso eseguibile può operare anche come applicazione FastCGI, utilizzando processi persistenti quando viene avviato e gestito in modo appropriato.
La differenza è fondamentale per comprendere perché php-cgi.exe è ancora impiegato su Windows con IIS, nonostante il CGI tradizionale sia considerato una soluzione poco efficiente per applicazioni Web sottoposte a carico.
FastCGI: come separare il server Web dall’esecuzione di PHP
FastCGI nasce per superare alcune limitazioni del CGI tradizionale. Invece di richiedere necessariamente la creazione di un nuovo processo a ogni richiesta, FastCGI consente al server Web di comunicare con processi applicativi che rimangono attivi e possono gestire più richieste successive.
Il server Web si occupa delle connessioni HTTP, della gestione dei contenuti statici e dell’instradamento; i processi FastCGI eseguono invece il codice dell’applicazione. La comunicazione avviene generalmente attraverso un socket Unix oppure una connessione TCP.
Nella configurazione con TCP, il server Web può comunicare, ad esempio, con un servizio FastCGI in ascolto su 127.0.0.1:9000. Con un socket Unix, invece, la comunicazione utilizza un percorso del filesystem, come /run/php/php8.4-fpm.sock.
La scelta non cambia il linguaggio PHP e non impone modifiche alla logica dell’applicazione, ma influenza il modo in cui i componenti comunicano, sono isolati e amministrati.
PHP-FPM: come funziona il gestore dei processi PHP
PHP-FPM, abbreviazione di PHP FastCGI Process Manager, è il sistema di gestione dei processi FastCGI incluso nelle distribuzioni PHP moderne. Invece di caricare l’interprete all’interno del server Web, PHP-FPM mantiene un insieme di processi dedicati all’esecuzione delle applicazioni PHP.
L’architettura è generalmente composta da un processo principale, chiamato master, e da vari processi figli, denominati worker. Il master supervisiona il servizio, gestisce la configurazione e coordina i processi disponibili. I worker ricevono ed eseguono le richieste inoltrate dal server Web. Il server HTTP e il runtime PHP rimangono quindi componenti distinti.
La stessa documentazione ufficiale descrive PHP-FPM come un’implementazione FastCGI dotata di funzionalità avanzate per la gestione dei processi, dei pool, dei log, delle richieste lente e delle informazioni di stato.
Cosa sono i pool PHP-FPM
Un pool identifica un gruppo di processi PHP con una propria configurazione: è possibile creare pool differenti per siti o applicazioni diverse, assegnando a ciascuno utenti di sistema, permessi, socket, limiti e parametri di gestione dei processi.
Supponiamo che sullo stesso server siano presenti due siti, sito-a.it e sito-b.it. Si possono creare due pool denominati sito_a e sito_b, ciascuno con un utente Unix dedicato e un socket separato: Apache o Nginx inoltreranno quindi le richieste al pool corrispondente.
In tal modo diventa possibile ridurre le interferenze tra applicazioni e contenere gli effetti di alcuni problemi di configurazione o di consumo delle risorse.
L’isolamento rimane tuttavia limitato: pool differenti non equivalgono a macchine virtuali o container separati. I processi possono condividere kernel, filesystem e altre risorse del sistema, a seconda dei permessi assegnati.
I tre modelli di gestione dei processi PHP-FPM
PHP-FPM supporta tre modalità principali, definite dalla direttiva pm:
| Modalità | Funzionamento | Quando utilizzarla |
|---|---|---|
static |
Mantiene un numero fisso di worker | Carichi prevedibili e memoria adeguata |
dynamic |
Aumenta o riduce i worker entro i limiti definiti | Server con traffico variabile |
ondemand |
Crea i worker quando arrivano richieste | Siti poco trafficati e molti pool |
Con pm = static, il numero dei worker è stabilito dalla direttiva pm.max_children. La configurazione è prevedibile, ma può impegnare memoria anche nei periodi di inattività. Con pm = dynamic, PHP-FPM mantiene un insieme di processi disponibili e ne crea altri quando necessario, rispettando i limiti configurati. Le direttive pm.start_servers, pm.min_spare_servers e pm.max_spare_servers controllano il comportamento del pool.
Con pm = ondemand, invece, i processi vengono avviati in risposta alle richieste e possono essere terminati dopo un periodo di inattività, gestito attraverso pm.process_idle_timeout. La modalità ondemand permette di ridurre il consumo di memoria per applicazioni scarsamente utilizzate, ma può introdurre latenza quando è necessario creare nuovi processi.
Esempio di configurazione PHP-FPM
Un pool dedicato potrebbe essere configurato con direttive come le seguenti:
[sito_a]
user = sito_a
group = sito_a
listen = /run/php/sito_a.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = dynamic
pm.max_children = 12
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 5
pm.max_requests = 500
request_terminate_timeout = 60s
L’esempio presuppone che l’utente sito_a esista e che il server Web operi come www-data, circostanza comune in alcune distribuzioni Debian/Ubuntu ma non universale. Il numero massimo di processi, impostato a 12, non costituisce un valore consigliato per qualsiasi server: deve essere calcolato considerando la memoria disponibile e il consumo effettivo dei worker.
La direttiva pm.max_requests permette inoltre di riciclare i processi dopo un determinato numero di richieste, caratteristica utile per limitare gli effetti di eventuali perdite di memoria nel codice o nelle estensioni. request_terminate_timeout impone invece un limite alla durata dell’elaborazione di una richiesta, con alcune eccezioni e comportamenti da considerare, ad esempio nel caso di fastcgi_finish_request().
Il pool deve essere completato con le impostazioni appropriate per la distribuzione utilizzata e verificato prima di essere attivato.
Come dimensionare PHP-FPM in base alla memoria
Una delle scelte più importanti riguarda pm.max_children, che definisce il numero massimo di worker disponibili per un pool.
Se il valore è troppo basso, le richieste possono accumularsi in attesa di un processo libero. Se è troppo alto, i worker possono utilizzare una quantità di memoria superiore a quella effettivamente disponibile.
Un criterio iniziale consiste nello stimare quanta RAM può essere dedicata ai processi PHP, sottraendo dal totale la memoria necessaria al sistema operativo, al server Web, ai database, alla cache e agli altri servizi.
Supponiamo di poter destinare circa 2 GB di RAM a un pool PHP e di misurare un consumo medio effettivo di 100 MB per worker, considerando correttamente la memoria condivisa. Una prima stima porterebbe a un limite teorico di circa 20 worker. In produzione sarebbe comunque opportuno mantenere un margine di sicurezza, verificare il consumo nei momenti di picco e controllare le altre applicazioni presenti.
Come controllare gli script PHP che rallentano il server
PHP-FPM permette di registrare le richieste che richiedono un tempo eccessivo. Le direttive seguenti consentono di registrare informazioni diagnostiche relative agli script che superano la soglia indicata:
slowlog = /var/log/php-fpm/sito_a-slow.log
request_slowlog_timeout = 5s
Il percorso deve essere accessibile al servizio e predisposto con i permessi corretti. I log possono aiutare a individuare query SQL lente, chiamate a servizi esterni che non rispondono e operazioni applicative particolarmente costose.
PHP-FPM dispone anche di una pagina di stato configurabile attraverso pm.status_path, che permette di osservare il numero dei processi occupati, quelli inattivi e le richieste in attesa. L’endpoint che restituisce informazioni di stato non deve essere pubblicato liberamente su Internet, perché può esporre informazioni operative utili anche a un attaccante.
mod_php, CGI, FastCGI e PHP-FPM: quale soluzione scegliere
La tabella seguente riepiloga le principali distinzioni delle quali abbiamo brevemente parlato:
| Soluzione | Processo PHP | Caratteristica principale |
|---|---|---|
| mod_php | Integrato in Apache | Semplicità nelle configurazioni tradizionali |
| CGI classico | Avviato per richiesta | Overhead elevato di creazione dei processi |
| php-cgi con FastCGI | Separato dal server Web | Processi riutilizzabili con gestione esterna |
| PHP-FPM | Pool dedicati | Gestione avanzata di worker, risorse e isolamento |
| LSAPI | Processi applicativi dedicati | Integrazione con LiteSpeed |
| FrankenPHP | Runtime integrato con modalità worker | Esecuzione tradizionale o persistente |
| RoadRunner | Worker PHP persistenti | Application server per applicazioni compatibili |
| PHP CLI | Eseguito dal terminale | Automazione, script e operazioni pianificate |
Per un nuovo server Linux basato su Apache o Nginx, PHP-FPM costituisce generalmente una scelta solida e flessibile. Per un hosting basato su LiteSpeed, invece, è naturale utilizzare la modalità di esecuzione prevista dal relativo server.
Soluzioni come FrankenPHP e RoadRunner meritano un discorso separato, perché consentono di adottare architetture nelle quali i worker possono mantenere attivo il processo applicativo tra richieste successive.
LSAPI e LiteSpeed
LSAPI, o LiteSpeed Server Application Programming Interface, è un’interfaccia progettata per l’integrazione tra applicazioni e server LiteSpeed. Attraverso LSAPI, il server Web può comunicare con processi PHP gestiti secondo le caratteristiche della piattaforma. L’implementazione PHP associata è spesso identificata con il nome lsphp.
Si tratta di una soluzione particolarmente diffusa negli hosting che utilizzano LiteSpeed Web Server o OpenLiteSpeed. LSAPI non è però affatto un altro nome per PHP-FPM: i due sistemi utilizzano meccanismi di integrazione e gestione differenti.
FrankenPHP, RoadRunner e i worker persistenti
Una parte dell’evoluzione recente di PHP riguarda i sistemi che consentono di mantenere attiva un’applicazione tra richieste successive. Nel modello tradizionale PHP-FPM, un processo worker può essere riutilizzato, ma il normale ciclo di vita della richiesta PHP prevede che lo stato applicativo della singola esecuzione sia inizializzato e successivamente ripulito.
Un sistema con worker applicativi persistenti può invece mantenere in memoria componenti già inizializzati, riducendo parte del lavoro necessario per elaborare ogni richiesta. FrankenPHP, basato su tecnologie come Caddy e sul runtime PHP, supporta anche una modalità worker. RoadRunner utilizza invece un application server scritto in Go che coordina processi PHP persistenti. OpenSwoole e Swoole adottano ulteriori modelli orientati all’elaborazione concorrente e alle operazioni asincrone.
Il vantaggio potenziale riguarda la riduzione dell’overhead di inizializzazione e la possibilità di sviluppare applicazioni con caratteristiche differenti dal classico ciclo richiesta-risposta. Il principale rischio deriva dalla persistenza involontaria dello stato: variabili, oggetti e risorse che nel modello tradizionale sarebbero ricreati a ogni richiesta possono sopravvivere ed essere riutilizzati, se il codice non gestisce correttamente il proprio ciclo di vita.
Un’applicazione PHP progettata per PHP-FPM non può quindi essere trasferita automaticamente a un worker persistente senza verificarne la compatibilità.
Configurare PHP con Apache e PHP-FPM
Apache può inoltrare gli script PHP a PHP-FPM attraverso il modulo mod_proxy_fcgi, che consente la comunicazione con un backend FastCGI. In una configurazione Linux con socket Unix, un esempio di associazione può essere:
<FilesMatch "\.php$">
SetHandler "proxy:unix:/run/php/php8.4-fpm.sock|fcgi://localhost/"
</FilesMatch>
Il percorso deve corrispondere al socket effettivamente utilizzato da PHP-FPM e la configurazione va collocata nel virtual host appropriato. Sono inoltre necessari i moduli Apache pertinenti, tra cui proxy e proxy_fcgi, e permessi che consentano al processo del server Web di accedere al socket.
La documentazione di Apache descrive l’utilizzo di SetHandler per inoltrare le richieste PHP a un backend FastCGI.
L’esempio rappresenta soltanto il collegamento tra i componenti: in una configurazione completa bisogna verificare anche la corretta risoluzione dei percorsi, l’esistenza degli script, la gestione dei virtual host e le regole di accesso. Su un server Apache moderno la combinazione MPM event + proxy_fcgi + PHP-FPM consente di separare la gestione delle connessioni HTTP dall’esecuzione del codice PHP.
Configurare PHP con Nginx e PHP-FPM
Nginx non utilizza il tradizionale mod_php di Apache. Per eseguire PHP in un’architettura convenzionale, inoltra le richieste a un backend FastCGI, tipicamente PHP-FPM.
Un esempio essenziale di virtual host può essere il seguente:
server {
listen 80;
server_name esempio.test;
root /var/www/esempio/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME
$realpath_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
}
}
La configurazione è un esempio per un ambiente di prova, non un virtual host completo pronto per Internet. Presuppone che la directory, il sito e il pool PHP-FPM siano già configurati.
La direttiva fastcgi_pass identifica il backend al quale Nginx inoltra le richieste. SCRIPT_FILENAME indica il percorso effettivo dello script PHP da eseguire. Un valore errato può provocare errori come Primary script unknown o, in determinate configurazioni insicure, consentire l’elaborazione di file indesiderati. try_files controlla l’esistenza delle risorse oppure applica il comportamento di instradamento definito.
La documentazione ufficiale del modulo FastCGI di Nginx chiarisce il ruolo di questi parametri e il meccanismo di inoltro delle richieste.
Un aspetto delicato riguarda i file caricati dagli utenti. Una directory destinata agli upload non dovrebbe consentire l’esecuzione di codice PHP, neppure quando un file possiede un’estensione apparentemente corretta. La configurazione del server dovrebbe quindi impedire che file caricati, documenti temporanei o directory non fidate possano essere trattati come script.
Come configurare PHP attraverso il file php.ini
Il file php.ini controlla numerosi aspetti del comportamento del runtime, dai limiti di memoria al trattamento degli errori, dalle sessioni alle estensioni.
Un server può utilizzare una configurazione per PHP CLI, un’altra per PHP-FPM e ulteriori impostazioni specifiche dei singoli pool. Alcune direttive possono inoltre essere sovrascritte attraverso i meccanismi consentiti dalla SAPI. Per questa ragione, prima di modificare un parametro, bisogna identificare quale configurazione utilizza il processo PHP interessato.
Le direttive più importanti di php.ini
| Direttiva | Funzione |
|---|---|
memory_limit |
Limita la memoria gestita da PHP per l’esecuzione dello script, con alcune eccezioni |
max_execution_time |
Definisce un limite al tempo di esecuzione secondo la SAPI e il sistema operativo |
max_input_time |
Controlla il tempo destinato all’elaborazione dei dati in ingresso |
upload_max_filesize |
Stabilisce la dimensione massima di un singolo file caricato |
post_max_size |
Limita la dimensione complessiva dei dati POST elaborati |
max_input_vars |
Limita il numero di variabili di input accettate |
display_errors |
Controlla la visualizzazione degli errori nell’output |
log_errors |
Abilita la registrazione degli errori |
error_reporting |
Stabilisce quali categorie di errori segnalare |
date.timezone |
Imposta il fuso orario predefinito |
expose_php |
Controlla l’esposizione della firma PHP nelle risposte |
session.cookie_httponly |
Impedisce l’accesso al cookie di sessione tramite JavaScript |
session.cookie_secure |
Richiede l’invio del cookie attraverso HTTPS |
opcache.enable |
Attiva la cache degli opcode |
Una configurazione di esempio per un’applicazione Web in produzione potrebbe comprendere:
date.timezone = Europe/Rome
memory_limit = 256M
max_execution_time = 30
max_input_time = 60
upload_max_filesize = 32M
post_max_size = 40M
max_input_vars = 2000
display_errors = Off
log_errors = On
error_reporting = E_ALL
expose_php = Off
session.cookie_httponly = On
session.cookie_secure = On
session.cookie_samesite = Lax
I valori non costituiscono impostazioni universalmente raccomandate: dipendono dalle necessità dell’applicazione, dal sistema di autenticazione, dalla quantità di memoria disponibile e dai requisiti di elaborazione. La direttiva session.cookie_secure = On, ad esempio, presuppone che l’applicazione utilizzi HTTPS. La scelta del valore SameSite deve invece tenere conto dei flussi di autenticazione e delle eventuali interazioni tra siti differenti.
Perché modificare upload_max_filesize potrebbe non bastare
Supponiamo di voler consentire il caricamento di un file da 30 MB. Impostare upload_max_filesize = 32M potrebbe non essere sufficiente, perché PHP applica anche il limite complessivo definito da post_max_size. Inoltre, il server Web, un reverse proxy o l’applicazione stessa possono imporre ulteriori restrizioni.
Nginx, ad esempio, dispone della direttiva client_max_body_size, che può impedire la ricezione di richieste oltre una determinata dimensione prima ancora che PHP sia coinvolto. Il limite effettivo deriva quindi dall’interazione tra più componenti, non da una singola impostazione di PHP.
Quali direttive possono essere modificate dall’applicazione
PHP supporta diversi livelli di configurabilità. Alcune direttive possono essere cambiate durante l’esecuzione mediante ini_set(), mentre altre richiedono modifiche al file di configurazione principale, al pool PHP-FPM o alle impostazioni del server.
La documentazione classifica le direttive attraverso modalità come INI_USER, INI_PERDIR, INI_SYSTEM e INI_ALL. Nei sistemi CGI/FastCGI può entrare in gioco anche .user.ini, attraverso il quale alcune impostazioni possono essere applicate a specifiche directory.
Nei pool PHP-FPM sono disponibili direttive come php_value, php_flag, php_admin_value e php_admin_flag, con differenti possibilità di sovrascrittura. Una direttiva imposta mediante php_admin_value, per esempio, non può essere normalmente modificata dal codice applicativo con ini_set().
Ne deriva che due applicazioni ospitate sullo stesso server possono utilizzare impostazioni PHP differenti, anche quando si appoggiano alla medesima installazione del runtime.
Come verificare la versione PHP utilizzata
Uno degli equivoci più frequenti riguarda il comando php -v: il risultato indica la versione dell’interprete PHP individuata dal terminale, ma non necessariamente quella utilizzata per elaborare le richieste HTTP.
Su un sistema con installazioni multiple potrebbero essere presenti PHP 8.3 per la CLI, PHP 8.4 per un sito Web e PHP 8.5 per un’altra applicazione.
Per conoscere la versione dalla riga di comando si utilizza php -v; per identificare la configurazione caricata, php --ini; per verificare le estensioni, php -m. Dal lato Web, in un ambiente di test controllato, si può utilizzare temporaneamente:
<?php
echo 'Versione PHP: ', PHP_VERSION, PHP_EOL;
echo 'SAPI: ', PHP_SAPI, PHP_EOL;
echo 'php.ini: ', php_ini_loaded_file();
Il codice restituisce le informazioni relative al runtime che sta effettivamente eseguendo quella richiesta. La funzione phpinfo() produce un riepilogo ancora più dettagliato, comprendente configurazione, estensioni, variabili e caratteristiche dell’ambiente.
Proprio per la quantità di informazioni potenzialmente sensibili che può rivelare, una pagina pubblica contenente phpinfo() non dovrebbe rimanere accessibile dopo le verifiche.
Su hosting condivisi o gestiti, è inoltre possibile che il pannello di controllo permetta di selezionare la versione PHP per ogni sito o dominio. In tali situazioni, il comando eseguito attraverso SSH potrebbe non identificare il runtime effettivamente utilizzato dal sito.
Come aggiornare PHP senza compromettere il funzionamento delle applicazioni
Aggiornare PHP è necessario per ricevere correzioni di sicurezza, risolvere errori del runtime e mantenere la compatibilità con le librerie supportate. L’aggiornamento, tuttavia, non consiste sempre nella semplice sostituzione di un eseguibile.
Vanno distinti gli aggiornamenti di manutenzione all’interno dello stesso ramo dalle migrazioni tra versioni differenti: passare da una release di manutenzione di PHP 8.4 alla successiva è un aggiornamento relativamente circoscritto. Migrare da PHP 8.2 a PHP 8.5 richiede invece una verifica più ampia, perché alcune funzionalità possono essere cambiate, non più ufficialmente supportate o rimosse.
Quali versioni PHP sono ancora supportate
Al 23 ottobre 2026, data di stesura del nostro articolo, le versioni PHP supportate ufficialmente sono 8.2, 8.3, 8.4 e 8.5. Il progetto PHP prevede 2 anni di supporto attivo e ulteriori 2 anni dedicati alle correzioni di sicurezza critiche, secondo il calendario ufficiale delle versioni supportate.
| Versione | Supporto attivo fino al | Supporto di sicurezza fino al |
|---|---|---|
| PHP 8.2 | 31 dicembre 2024 | 31 dicembre 2026 |
| PHP 8.3 | 31 dicembre 2025 | 31 dicembre 2027 |
| PHP 8.4 | 31 dicembre 2026 | 31 dicembre 2028 |
| PHP 8.5 | 31 dicembre 2027 | 31 dicembre 2029 |
Le date si riferiscono al supporto del progetto PHP. Le distribuzioni Linux possono applicare politiche differenti, distribuendo aggiornamenti di sicurezza mediante backport delle patch.
Per esempio, una distribuzione supportata può mantenere lo stesso numero di versione principale di PHP pur integrando correzioni pubblicate successivamente nel progetto upstream. Per stabilire se un sistema sia aggiornato non bisogna quindi confrontare esclusivamente la stringa restituita da php -v, ma verificare anche gli avvisi di sicurezza e la documentazione del fornitore della distribuzione.
Come aggiornare PHP su Ubuntu e Debian
Per aggiornare i pacchetti PHP già installati e disponibili nei repository configurati, si può utilizzare il normale sistema di gestione dei pacchetti:
sudo apt update
sudo apt upgrade
I comandi non garantiscono il passaggio a una nuova versione principale di PHP. Se il repository contiene soltanto PHP 8.3, un normale aggiornamento non installerà automaticamente PHP 8.5.
Per ottenere una versione più recente può essere necessario passare a una nuova release della distribuzione oppure utilizzare repository aggiuntivi affidabili e compatibili. Prima di modificare l’installazione occorre verificare l’elenco dei pacchetti disponibili, delle estensioni e dei servizi collegati.
Su sistemi Debian/Ubuntu, il comando apt policy php php-fpm consente di controllare i pacchetti candidati e i relativi repository. Se sono installate più versioni di PHP, può essere necessario aggiornare anche i riferimenti nei virtual host Apache/Nginx e modificare il servizio PHP-FPM associato.
Come aggiornare PHP su Fedora, RHEL e AlmaLinux
Nei sistemi che utilizzano DNF, gli aggiornamenti dei pacchetti installati possono essere gestiti mediante:
sudo dnf upgrade
Anche qui, un aggiornamento ordinario non implica necessariamente il passaggio a una nuova versione principale. Per conoscere le versioni disponibili bisogna controllare i repository abilitati e, quando pertinente, i meccanismi AppStream adottati dalla distribuzione.
In un server di produzione è preferibile evitare l’aggiunta indiscriminata di repository: le librerie, le estensioni e le dipendenze del runtime devono provenire da combinazioni compatibili.
Come aggiornare PHP su Windows
Su Windows, nel caso di un’installazione manuale, una procedura prudente consiste nel predisporre la nuova distribuzione PHP in una directory separata, anziché sovrascrivere immediatamente quella esistente.
Prima del passaggio occorre verificare i requisiti del runtime Visual C++, le estensioni utilizzate, la configurazione php.ini e la compatibilità con Apache o IIS. Nel caso di IIS e FastCGI bisogna modificare il percorso dell’eseguibile associato all’handler, verificando che punti al nuovo php-cgi.exe.
La separazione delle directory permette di conservare temporaneamente la versione precedente come possibile strumento di rollback. Il semplice ripristino dei vecchi binari, tuttavia, potrebbe non essere sufficiente qualora la migrazione abbia coinvolto database, file applicativi e dipendenze.
Come aggiornare PHP nei container Docker
Con Docker il runtime PHP è normalmente incluso nell’immagine sulla quale si basa il container. Un aggiornamento corretto consiste quindi nel selezionare l’immagine aggiornata, ricostruire gli eventuali livelli personalizzati e ricreare il container.
Per esempio, in un Dockerfile:
FROM php:8.5-fpm
si può adottare un ramo di PHP supportato, verificando però che tutte le estensioni e le dipendenze richieste dall’applicazione siano compatibili.
In produzione è consigliabile utilizzare riferimenti sufficientemente precisi alle versioni e, quando necessaria la riproducibilità rigorosa, digest delle immagini. Aggiornare l’immagine non deve significare perdere dati applicativi: database, file persistenti e contenuti caricati devono essere gestiti attraverso volumi o servizi dedicati.
Le verifiche indispensabili prima di migrare a una nuova versione
La fase più delicata di un aggiornamento riguarda la compatibilità del software applicativo. Un sito WordPress, un’applicazione Laravel o un CMS personalizzato possono dipendere da librerie e plugin che non supportano immediatamente la versione PHP più recente.
È quindi opportuno predisporre un ambiente di staging il più possibile simile alla produzione, aggiornare le dipendenze, eseguire test funzionali e controllare i log. Per le applicazioni gestite mediante Composer, il comando che segue permette di verificare i requisiti dichiarati dai pacchetti rispetto alla piattaforma PHP effettivamente in uso:
composer check-platform-reqs
Il controllo non sostituisce i test, perché una libreria può dichiarare compatibilità con una versione senza che tutte le funzionalità dell’applicazione risultino necessariamente corrette. Un piano di aggiornamento affidabile deve prevedere anche backup verificati, procedure di ripristino e una finestra di intervento adeguata.
PHP e le estensioni: come aggiungere nuove funzionalità al linguaggio
PHP dispone di numerose estensioni che permettono di utilizzare librerie, protocolli e servizi non necessariamente compresi nel nucleo fondamentale del linguaggio. Tra quelle più comuni figurano curl, per effettuare richieste attraverso vari protocolli; mbstring, per il trattamento delle stringhe multibyte; intl, per funzionalità di internazionalizzazione; gd, per elaborare immagini; e i driver PDO, utilizzati per comunicare con database differenti.
Non tutte le estensioni richiedono un’installazione separata: alcune possono essere già compilate nel runtime o distribuite insieme ai pacchetti principali. Su Ubuntu e Debian, per esempio, l’installazione di una determinata estensione può richiedere:
sudo apt install php-intl
Su Fedora o RHEL, il pacchetto corrispondente può essere disponibile con:
sudo dnf install php-intl
Dopo l’installazione bisogna assicurarsi che l’estensione sia effettivamente caricata dalla SAPI utilizzata dall’applicazione e, quando necessario, riavviare o ricaricare il servizio PHP-FPM.
PECL, PIE e Composer non sono la stessa cosa
È importante distinguere le estensioni native dalle librerie PHP. PECL è uno storico repository e strumento di distribuzione di estensioni PHP. PIE, PHP Installer for Extensions, rappresenta un sistema più recente per installare e gestire estensioni native.
Composer, invece, gestisce principalmente le dipendenze delle applicazioni scritte in PHP. Una libreria installata con Composer viene generalmente utilizzata come codice PHP dell’applicazione, mentre un’estensione nativa viene caricata dal runtime e può dipendere da librerie compilate e dalla compatibilità con l’ABI della specifica build di PHP.
È una tematica cruciale durante le migrazioni: aggiornare PHP può richiedere la sostituzione o la ricompilazione di alcune estensioni native.
Come migliorare le prestazioni di PHP con OPcache e JIT
Le prestazioni di PHP non dipendono esclusivamente dalla velocità del linguaggio: il tempo necessario per rispondere a una richiesta può essere influenzato dalle interrogazioni al database, dall’accesso ai file, dalle chiamate HTTP verso servizi esterni, dal numero di processi disponibili e dalla configurazione delle cache.
Uno degli strumenti più importanti per ridurre il lavoro svolto dal runtime è OPcache. Come abbiamo visto, PHP compila il codice sorgente in opcode prima di eseguirlo; senza un sistema di caching, parte di questa elaborazione dovrebbe essere ripetuta nelle richieste successive. OPcache conserva gli opcode compilati in memoria condivisa, permettendo ai worker di riutilizzarli senza ripetere continuamente la fase di compilazione.
Tra le direttive disponibili figurano:
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=2
I valori sono indicativi e devono essere adattati al numero di script caricati e alla memoria disponibile. La direttiva opcache.validate_timestamps determina se PHP debba verificare le modifiche ai file sorgenti. Disattivando tale controllo si può ridurre ulteriormente l’overhead, ma occorre prevedere un meccanismo affidabile di invalidazione della cache durante i rilasci applicativi.
In caso contrario, il server potrebbe continuare a eseguire una versione precedente del codice anche dopo la sostituzione dei file. Un aspetto da non trascurare è che OPcache non sostituisce una cache applicativa. Mantenere in memoria gli opcode non evita le interrogazioni SQL, non conserva automaticamente il risultato delle chiamate a servizi esterni e non equivale alla cache delle pagine HTML.
Per ridurre ulteriormente i tempi di risposta possono entrare in gioco Redis, Memcached, sistemi di caching applicativo o cache HTTP, ciascuno con un ruolo differente.
La compilazione JIT rende PHP più veloce?
Il compilatore JIT è una funzionalità distinta da OPcache, sebbene utilizzi parte della relativa infrastruttura. Quando abilitato, il JIT può tradurre porzioni di codice in istruzioni macchina, evitando in determinate circostanze il passaggio attraverso l’interpretazione degli opcode.
I benefici sono più evidenti in particolari elaborazioni intensive sulla CPU; per molte applicazioni Web, invece, il tempo di risposta dipende soprattutto da operazioni di I/O, query SQL, comunicazioni di rete e logica applicativa. Attivare il JIT non significa quindi ottenere automaticamente pagine WordPress più veloci.
Nelle versioni PHP moderne il comportamento del JIT e le impostazioni predefinite sono cambiati rispetto alle prime release della famiglia PHP 8; conviene verificare la documentazione aggiornata di OPcache prima di abilitarlo. Una corretta ottimizzazione dovrebbe partire dalle misurazioni: identificare le richieste lente, verificare i colli di bottiglia del database, analizzare i consumi dei worker e soltanto dopo intervenire sui parametri del runtime.
Sicurezza PHP: quali rischi comporta una configurazione sbagliata
La sicurezza di un’applicazione PHP dipende da più livelli: codice applicativo, runtime, estensioni, sistema operativo, server Web e servizi accessibili dall’applicazione. Aggiornare PHP è necessario, ma non sufficiente. Una versione recente del runtime non impedisce, da sola, a un’applicazione vulnerabile di esporre dati o eseguire operazioni non autorizzate.
Tra i problemi più frequenti figurano SQL injection, cross-site scripting (XSS), caricamento di file pericolosi, gestione inadeguata delle sessioni e utilizzo di input non verificati all’interno di percorsi o comandi di sistema.
SQL injection e utilizzo delle query parametrizzate
Quando un’applicazione costruisce una query SQL concatenando direttamente valori forniti dagli utenti, può consentire la modifica della struttura dell’istruzione. Con PHP è opportuno utilizzare driver moderni come PDO e ricorrere alle query parametrizzate.
<?php
$stmt = $pdo->prepare(
'SELECT id, nome FROM utenti WHERE id = :id'
);
$stmt->execute([
'id' => $id
]);
$utente = $stmt->fetch(PDO::FETCH_ASSOC);
Il valore associato a :id viene trasmesso come parametro, evitando che sia interpretato come parte arbitraria della sintassi SQL. Per nomi di tabelle, colonne e altri identificatori, che non possono generalmente essere parametrizzati allo stesso modo, occorre invece utilizzare valori consentiti e controllati dall’applicazione.
La protezione contro le SQL injection deve accompagnarsi all’applicazione del principio del privilegio minimo: l’account del database utilizzato dal sito dovrebbe disporre soltanto delle autorizzazioni necessarie.
Upload dei file ed esecuzione di codice
Il caricamento dei file rappresenta una funzionalità particolarmente delicata. Un’applicazione che consente agli utenti di caricare immagini o documenti non dovrebbe permettere che tali file vengano successivamente interpretati come codice PHP.
Non basta controllare l’estensione dichiarata dal browser. È necessario validare il tipo di contenuto, assegnare nomi sicuri, applicare limiti alle dimensioni e impedire l’esecuzione degli upload. Quando possibile, è preferibile archiviare i file caricati al di fuori della directory pubblica del sito e distribuirli attraverso un meccanismo controllato.
È inoltre importante configurare Apache o Nginx affinché i percorsi destinati agli upload non possano raggiungere l’handler PHP.
Perché disable_functions non è una sandbox
PHP mette a disposizione direttive come disable_functions e open_basedir. La prima consente di disabilitare determinate funzioni interne. La seconda limita alcune operazioni sul filesystem ai percorsi configurati.
Entrambe possono contribuire a ridurre particolari rischi, ma non costituiscono un sistema completo di isolamento. Non devono quindi sostituire i controlli sui privilegi dell’utente di sistema, la separazione dei servizi, i permessi del filesystem e gli strumenti di isolamento disponibili nel sistema operativo.
Un pool PHP-FPM dovrebbe operare con privilegi strettamente necessari. La possibilità di leggere o scrivere un file dipende dai permessi effettivi del processo, non semplicemente dalla presenza di direttive restrittive in php.ini.
PHP-FPM non deve essere accessibile direttamente da Internet
Un errore di configurazione particolarmente pericoloso consiste nell’esporre la porta FastCGI del servizio PHP-FPM verso reti non fidate. FastCGI non è HTTP e non offre le stesse garanzie derivanti dal normale passaggio attraverso un server Web correttamente configurato.
Un client capace di comunicare direttamente con PHP-FPM può inviare parametri FastCGI che influenzano l’esecuzione della richiesta, con conseguenze potenzialmente gravi. La documentazione ufficiale raccomanda di non rendere PHP-FPM raggiungibile da reti non fidate.
Quando PHP-FPM utilizza TCP, il servizio dovrebbe ascoltare soltanto su interfacce appropriate, con ulteriori controlli di rete e accesso. Quando utilizza socket Unix, occorre assegnare permessi coerenti con l’utente del server Web. La stessa attenzione va prestata alle configurazioni Docker e Kubernetes: pubblicare accidentalmente un servizio FastCGI può introdurre una superficie d’attacco evitabile.
Il caso PHP2Shell e l’importanza delle modalità di esecuzione
Le recenti discussioni (iniziate intorno al 20 ottobre 2026) relative a PHP2Shell mostrano quanto sia importante distinguere il linguaggio PHP dai meccanismi attraverso i quali un server inoltra richieste al runtime. Una vulnerabilità che interessa una particolare SAPI, una modalità di interpretazione dei parametri o uno specifico componente di integrazione non coinvolge necessariamente tutte le installazioni PHP allo stesso modo.
Per valutare l’esposizione bisogna conoscere la versione effettivamente in uso, la SAPI, il sistema operativo, la configurazione del server Web e gli eventuali componenti intermedi.
Su IlSoftware.it abbiamo già approfondito PHP2Shell e il funzionamento degli exploit e le tecniche per individuare installazioni PHP nascoste o potenzialmente vulnerabili.
Il principio generale rimane valido indipendentemente dalla vulnerabilità considerata: non basta sapere che un server utilizza PHP; bisogna capire quale PHP esegue realmente le richieste e attraverso quale architettura.
Composer e framework: come viene utilizzato PHP nelle applicazioni di oggi
PHP permette di scrivere semplici script autonomi, ma lo sviluppo di applicazioni complesse richiede strumenti per organizzare il codice e gestire le dipendenze. Uno dei più importanti è Composer, il gestore di dipendenze comunemente utilizzato nei progetti PHP.
Attraverso un file composer.json, un’applicazione può dichiarare le librerie necessarie e i requisiti relativi alla versione PHP. Un esempio minimale:
{
"require": {
"php": "^8.4"
}
}
Il vincolo indica le versioni PHP compatibili secondo le regole semantiche utilizzate da Composer. Non installa PHP e non modifica automaticamente la versione del runtime presente sul sistema.
Composer permette inoltre di gestire l’autoloading delle classi, evitando di includere manualmente ogni file sorgente. Framework come Laravel e Symfony utilizzano tali meccanismi per strutturare applicazioni con routing, controller, servizi, accesso ai database, middleware e componenti dedicati alla sicurezza.
Una caratteristica frequente delle applicazioni moderne consiste nell’esporre al server Web soltanto una directory pubblica, per esempio public, mantenendo il resto del codice al di fuori della document root. La separazione riduce il rischio che file di configurazione, sorgenti riservati e dipendenze possano essere scaricati direttamente attraverso HTTP.
È importante ricordare che Composer gestisce le dipendenze, non sostituisce il runtime PHP: una libreria può richiedere PHP 8.5, ma sarà comunque necessario installare e utilizzare una versione compatibile sul server.
PHP da riga di comando: automatizzare operazioni senza un server Web
L’esecuzione CLI (command-line interface) è utile per numerose attività che non richiedono un browser. PHP può elaborare file, interrogare database, inviare richieste HTTP, generare report e svolgere operazioni di manutenzione. Un semplice script, ad esempio, può caricare un documento JSON, elaborarne il contenuto e produrre un risultato destinato ad altri programmi.
L’esecuzione avviene mediante la seguente sintassi (esempio):
php elaborazione.php
Su Linux, uno script PHP può anche essere richiamato attraverso cron per effettuare operazioni periodiche. La modalità CLI presenta alcune differenze importanti rispetto all’esecuzione Web. Può utilizzare un file php.ini separato, impostazioni differenti per i limiti di esecuzione e un insieme diverso di estensioni.
Anche le variabili d’ambiente e l’utente di sistema possono cambiare: uno script che funziona correttamente attraverso il browser potrebbe quindi non funzionare se avviato tramite cron, oppure viceversa. Per diagnosticare i problemi occorre verificare il percorso assoluto dell’interprete utilizzato, la directory di lavoro, le autorizzazioni dell’utente e l’eventuale presenza di più versioni PHP.
Come risolvere i problemi più comuni con PHP
- Quando un’applicazione smette di funzionare, è utile identificare prima di tutto quale componente produce l’errore: server Web, collegamento FastCGI, runtime PHP oppure codice applicativo.
- Un errore HTTP 500 indica genericamente un problema interno al server. Può dipendere da un errore fatale PHP, da configurazioni non valide, da permessi insufficienti o da problemi del server Web. È quindi necessario consultare i log di PHP e del server, evitando di abilitare indiscriminatamente la visualizzazione pubblica degli errori.
- Un 502 Bad Gateway può indicare che il server Web non riesce a comunicare correttamente con PHP-FPM, per esempio perché il servizio è inattivo, il socket non esiste, i permessi sono errati o il backend interrompe la connessione.
- Un 504 Gateway Timeout segnala invece che un componente intermedio non ha ricevuto una risposta entro il tempo previsto. La causa potrebbe essere una richiesta PHP troppo lenta, una query SQL bloccata o un servizio esterno che non risponde.
Quando il browser scarica un file .php invece di visualizzare la pagina generata, il server potrebbe non avere associato correttamente il file all’handler PHP. La situazione richiede particolare attenzione, perché una configurazione errata potrebbe esporre il codice sorgente dell’applicazione.
Se un’estensione risulta mancante, bisogna controllare non soltanto che il pacchetto sia installato, ma anche che venga caricato dalla SAPI effettivamente utilizzata.
I comandi più utili per la diagnosi
Per una prima analisi su Linux possono essere utili:
php -v
php --ini
php -m
Per controllare il servizio PHP-FPM, adattando il nome alla distribuzione:
sudo systemctl status php8.4-fpm
Per leggere gli ultimi messaggi del servizio:
sudo journalctl -u php8.4-fpm -n 100
Per verificare la configurazione Nginx:
sudo nginx -t
Per controllare la sintassi Apache:
sudo apachectl configtest
La verifica del file di configurazione PHP-FPM può essere effettuata con l’eseguibile del servizio e l’opzione -t, tenendo conto del nome e del percorso effettivamente disponibili sul sistema. Nei sistemi Debian/Ubuntu, per esempio:
sudo php-fpm8.4 -t
Nei sistemi RHEL/Fedora, l’eseguibile potrebbe essere disponibile come php-fpm. L’analisi dovrebbe partire dai messaggi registrati e dai servizi realmente coinvolti, anziché procedere con modifiche casuali ai limiti di memoria o ai timeout.
Quale configurazione PHP scegliere oggi
La configurazione più adatta dipende dal tipo di progetto, dal sistema operativo e dal carico di lavoro. Per chi inizia a programmare su Windows 11, un’installazione locale del runtime e il server di sviluppo integrato possono essere sufficienti per imparare il linguaggio. Un ambiente come Laragon o XAMPP può semplificare ulteriormente le prime prove, soprattutto quando serve anche un database.
Per un’applicazione Web ospitata su Linux, Apache con PHP-FPM oppure Nginx con PHP-FPM rappresentano due soluzioni consolidate. Entrambe consentono di separare il server HTTP dall’esecuzione del codice PHP.
Nel caso di più siti sullo stesso server, l’utilizzo di pool PHP-FPM dedicati permette di differenziare utenti, limiti di risorse e configurazioni. Tale separazione deve comunque essere accompagnata da permessi e controlli appropriati a livello di sistema operativo.
Un’infrastruttura basata su IIS può invece utilizzare PHP attraverso FastCGI, mentre gli hosting LiteSpeed adottano comunemente LSAPI. I sistemi con worker persistenti, come FrankenPHP in modalità worker e RoadRunner, offrono possibilità interessanti per applicazioni progettate o adattate a quel modello, ma richiedono attenzione alla gestione dello stato e delle risorse tra richieste successive.
Conclusioni
PHP non è soltanto il linguaggio che permette a WordPress di generare pagine dinamiche. È un ambiente di esecuzione articolato, capace di operare sul Web, dalla riga di comando e attraverso architetture applicative differenti.
Comprendere il funzionamento dello Zend Engine, delle SAPI e dei sistemi di integrazione con i server Web permette di evitare molti equivoci. mod_php carica il runtime all’interno di Apache; CGI e FastCGI definiscono modalità di comunicazione con programmi esterni; PHP-FPM aggiunge un sistema specializzato per gestire i processi PHP e distribuirli in pool configurabili.
L’installazione del linguaggio rappresenta quindi soltanto il primo passaggio: per utilizzare PHP nel modo corretto occorre individuare la versione effettivamente eseguita, configurare le estensioni necessarie, dimensionare i processi, proteggere i file applicativi e predisporre procedure affidabili di aggiornamento.
Per le nuove installazioni Web su Linux, PHP-FPM rimane una soluzione generalmente consigliabile, grazie alla separazione dal server HTTP e alla flessibilità della gestione dei worker. Non è però l’unica architettura possibile, né rappresenta automaticamente la soluzione migliore per qualsiasi carico applicativo.
La conoscenza delle differenti modalità di esecuzione consente di affrontare con maggiore precisione problemi di prestazioni e sicurezza: una configurazione PHP non va valutata soltanto in base alla versione installata, ma considerando l’intero percorso attraverso il quale una richiesta raggiunge il runtime ed esegue il codice.