Quale versione di PHP sto usando? Cinque modi per scoprirlo su server, CLI e PHP-FPM

Riga di comando, PHP-FPM e web server, pacchetti installati, applicazione e intestazioni HTTP: cinque controlli, con i comandi per le distribuzioni più diffuse, per capire quale versione di PHP esegue davvero ogni sito.

Copertina con il logo php∞, la categoria PHP End of Life, il titolo Quale versione di PHP sto usando? e il numero 03

“Che versione di PHP avete in produzione?” sembra una domanda da un minuto. Chi apre un terminale e digita php -v ottiene un numero e una risposta tranquillizzante, ma quel numero riguarda solo la riga di comando. Il sito può essere servito da un’altra versione, attraverso PHP-FPM o un modulo di Apache, e sullo stesso server possono convivere tre o quattro versioni diverse, alcune aggiornate e altre ferme da anni.

In questo articolo vediamo cinque modi per rispondere con certezza: la riga di comando, il web server con PHP-FPM o mod_php, i pacchetti installati, l’applicazione stessa e le intestazioni HTTP viste dall’esterno. Per ciascuno indichiamo i comandi da usare sulle distribuzioni più diffuse, cosa dice davvero il risultato e dove può trarre in inganno.

Perché la risposta non è una sola

PHP non è un programma unico. Lo stesso interprete viene eseguito attraverso diverse SAPI, le interfacce con cui PHP riceve il lavoro da fare: la CLI per i comandi da terminale, i cron e Composer; PHP-FPM, un gestore di processi a cui il web server inoltra le richieste; mod_php, il modulo che fa girare PHP dentro Apache; più raramente CGI. Ognuna può essere installata in versioni diverse, e i repository di terze parti come Remi o deb.sury.org rendono semplicissimo avere più versioni affiancate.

Schema di uno scenario illustrativo con tre versioni di PHP sullo stesso server. Le richieste del browser arrivano a nginx, che con la direttiva fastcgi_pass le inoltra a due socket: /run/php/php7.4-fpm.sock porta a PHP-FPM 7.4 che serve il sito del negozio, /run/php/php8.2-fpm.sock porta a PHP-FPM 8.2 che serve il sito aziendale. Separatamente, terminale e cron usano /usr/bin/php, per cui php -v restituisce PHP 8.3, usato da Composer e dagli script. Una nota evidenzia che php -v risponde 8.3 mentre il negozio online gira su PHP-FPM 7.4, fuori supporto dal 2022
Lo stesso server, tre risposte diverse: quella che conta è la versione che serve ogni sito.

Immaginiamo un server su cui, anni fa, è stato installato PHP 7.4 per un negozio online. In seguito è arrivato un secondo sito, messo su PHP 8.2, e più di recente qualcuno ha aggiornato il comando php alla 8.3 per far funzionare una versione nuova di Composer. Chi controlla con php -v vede 8.3 e conclude che il server è aggiornato, mentre il negozio, la parte più esposta e più delicata, gira ancora su un ramo fuori supporto dal novembre 2022. Lo scenario è inventato, ma la configurazione è molto comune.

1. La riga di comando

È il punto di partenza, perché dice quale PHP usano i cron, gli script di manutenzione e Composer. Va solo letto per quello che è.

# Versione del PHP della riga di comando
php -v

# Tutti gli eseguibili php presenti nel PATH, nell'ordine in cui vengono trovati
which -a php

# File php.ini caricati dalla riga di comando (diversi da quelli del sito)
php --ini

# Debian e Ubuntu: quale versione è collegata al comando php
update-alternatives --display php

Sulle distribuzioni Debian e Ubuntu il numero mostrato include spesso la revisione del pacchetto, per esempio 8.1.2-1ubuntu2.28: la parte dopo il trattino indica le correzioni applicate dalla distribuzione, ed è un’informazione preziosa per il terzo metodo. Ricorda anche che un cron può richiamare un eseguibile con il percorso completo, come /usr/bin/php7.4, e usare quindi una versione diversa da quella del terminale.

2. Il web server e PHP-FPM

Questo è il metodo che dice quale PHP esegue ogni sito. Si procede in due passi, prima individuando le istanze di PHP-FPM attive, poi ricostruendo a quale istanza il web server inoltra le richieste di ciascun sito.

Le istanze di PHP-FPM

# Processi master di PHP-FPM: tra parentesi il file di configurazione,
# che di solito rivela la versione (/etc/php/7.4/fpm/..., /etc/opt/remi/php74/...)
ps -eo pid,args | grep '[p]hp-fpm: master'

# Servizi PHP-FPM attivi (php8.2-fpm, php-fpm, php74-php-fpm...)
systemctl list-units --type=service | grep -i fpm

# Versione di ciascun eseguibile
php-fpm8.2 -v                               # Debian e Ubuntu
/usr/sbin/php-fpm -v                        # RHEL, Rocky Linux, AlmaLinux
/opt/remi/php74/root/usr/sbin/php-fpm -v    # Software Collection di Remi

Il collegamento tra sito e pool

Ogni istanza di PHP-FPM ha uno o più pool, ciascuno in ascolto su un socket o su una porta. Il web server indica, sito per sito, a quale socket o porta inviare le richieste PHP. Mettendo insieme le due configurazioni si ottiene la mappa completa.

# nginx: per ogni sito, il nome e il socket o la porta di PHP-FPM
nginx -T 2>/dev/null | grep -E 'server_name|fastcgi_pass'

# Su quale socket o porta ascolta ogni pool di PHP-FPM
grep -R '^listen' /etc/php/*/fpm/pool.d/ /etc/php-fpm.d/ /etc/opt/remi/*/php-fpm.d/ 2>/dev/null

# Apache: siti che inoltrano a PHP-FPM con proxy_fcgi
grep -R 'proxy:unix' /etc/apache2/ /etc/httpd/ 2>/dev/null

# Apache: moduli PHP caricati direttamente (mod_php)
apachectl -M 2>/dev/null | grep -i php

Se apachectl -M mostra un modulo come php7_module o php_module, una parte dei siti è servita da mod_php, e la versione è quella del modulo caricato. In pratica Apache carica un solo modulo PHP alla volta: se sullo stesso server ci sono siti su versioni diverse, gli altri passano da PHP-FPM o da CGI. Le differenze di sicurezza tra queste SAPI sono un tema a parte, che riprenderemo in un articolo dedicato.

3. I pacchetti installati e la loro origine

Sapere che un sito gira su PHP 7.4 è metà della risposta. L’altra metà è chi ha costruito quel pacchetto e se lo sta ancora correggendo: lo stesso numero di versione può essere protetto su un server e scoperto su un altro. Il gestore dei pacchetti dice versione, revisione e repository di provenienza.

# Famiglia Red Hat: pacchetti PHP installati, con il repository di origine
dnf list installed 'php*'
yum list installed 'php*'      # CentOS 7 e sistemi senza dnf

# RHEL 8 e 9 e derivate: stream di PHP abilitato, indicato con [e]
dnf module list php

# Debian e Ubuntu: pacchetti installati e repository di origine
dpkg -l 'php*' | grep '^ii'
apt-cache policy php8.2-cli

Nella colonna del repository troverai nomi come appstream o @System per i pacchetti della distribuzione, remi o remi-modular per il repository di Remi, mentre su Debian e Ubuntu apt-cache policy mostra l’indirizzo del repository, per esempio quello di packages.sury.org o un PPA. Con questa informazione puoi verificare se il pacchetto riceve ancora correzioni, leggendo il suo changelog come abbiamo mostrato nell’articolo su cosa significa PHP End of Life, e fino a quando le riceverà secondo il ciclo di vita della distribuzione.

4. Dall’interno dell’applicazione

La prova definitiva è chiedere la versione al codice in esecuzione, attraverso lo stesso percorso di una richiesta reale. Basta un file di una riga, con un nome difficile da indovinare, da aprire nel browser e cancellare subito dopo:

# Crea il file di prova nella cartella pubblica del sito
echo '<?php echo PHP_VERSION, " ", PHP_SAPI, " ", php_ini_loaded_file();' > /var/www/sito/verifica-7f3a.php

# Apri https://www.tuosito.it/verifica-7f3a.php, annota il risultato, per esempio:
# 7.4.33 fpm-fcgi /etc/php/7.4/fpm/php.ini

# Poi cancellalo subito
rm /var/www/sito/verifica-7f3a.php

Il risultato riporta la versione, la SAPI (fpm-fcgi per PHP-FPM, apache2handler per mod_php, cgi-fcgi per CGI e FastCGI) e il file di configurazione caricato. Evita di usare phpinfo() per questo scopo, o almeno non lasciarlo mai online: mostra percorsi, moduli e variabili d’ambiente che fanno comodo a un attaccante.

Se non hai accesso al server, molti CMS mostrano la versione nel pannello di amministrazione: WordPress, per esempio, la riporta nella schermata Salute del sito, tra le informazioni sul server. Il dato è affidabile perché viene letto dal PHP che esegue il CMS. Diverso è il caso del file composer.json: il vincolo "php" indica le versioni con cui l’applicazione dichiara di funzionare, non quella in uso.

5. Dall’esterno, con le intestazioni HTTP

Quando la direttiva expose_php è attiva, PHP aggiunge alle risposte l’intestazione X-Powered-By con la propria versione. È il dato che leggono molti scanner di sicurezza, ed è utile per un controllo rapido su un sito di cui non gestisci il server:

# Intestazioni della risposta, filtrando quella con la versione di PHP
curl -sI https://www.tuosito.it/ | grep -i '^x-powered-by'

Va considerato un indizio. L’intestazione manca se expose_php è disattivata, può essere rimossa da un proxy o da una CDN, e su una pagina servita dalla cache non c’è PHP di mezzo. Mostra inoltre il numero di versione senza la revisione della distribuzione: un pacchetto corretto da Debian o da Red Hat può apparire “vecchio” a uno scanner pur avendo le patch. In produzione è buona pratica disattivarla, perché regala informazioni gratuite a chi cerca bersagli.

Container, pannelli e hosting condiviso

Alcune configurazioni spostano la domanda in un posto diverso. Se l’applicazione gira in un container, la versione di PHP è quella dell’immagine, non quella del server che la ospita: i comandi visti sopra vanno eseguiti dentro il container, per esempio con docker exec, e il pacchetto da verificare è l’immagine di base indicata nel Dockerfile. Un’immagine costruita anni fa e mai ricostruita resta ferma alla versione di allora, anche se l’host viene aggiornato con regolarità.

Sui server gestiti con un pannello di controllo, o sugli hosting condivisi, la versione si sceglie spesso cartella per cartella o dominio per dominio, e il pannello installa le proprie build di PHP in percorsi separati da quelli della distribuzione. In questi casi il metodo più affidabile resta il quarto, il file di prova eseguito dal sito, perché attraversa esattamente la catena configurata dal pannello. Per sapere chi corregge quelle build bisogna chiedere al fornitore del pannello o dell’hosting.

Mettere insieme i risultati

Nessun metodo, da solo, dà il quadro completo. La riga di comando e le intestazioni sono rapide ma parziali; la risposta affidabile nasce dall’incrocio tra il processo che serve il sito, il pacchetto da cui arriva e quello che dichiara il codice in esecuzione.

Tabella con i cinque modi per scoprire la versione di PHP. Uno, riga di comando con php -v e php --ini: dice la versione usata da cron, script e Composer, ma spesso non è quella del sito. Due, web server e PHP-FPM con ps, nginx -T e apachectl -M: dice quale PHP serve ogni sito e con quale SAPI, ma più pool e più versioni possono convivere. Tre, pacchetti installati con rpm, dpkg, dnf e apt-cache: dice versione, revisione e repository di origine, da verificare chi mantiene il pacchetto e fino a quando. Quattro, dentro l’applicazione con PHP_VERSION e PHP_SAPI: dice la versione che esegue davvero il codice, cancellando subito il file di prova. Cinque, dall’esterno con l’intestazione X-Powered-By: un indizio quando expose_php è attivo, spesso assente o filtrata e quindi non una prova
I cinque metodi a confronto: i più rapidi sono anche i meno affidabili.

Per ogni server conviene compilare un piccolo inventario, da aggiornare a ogni modifica, con queste informazioni per ciascun sito o applicazione:

  • nome del sito e cartella dell’applicazione;
  • versione di PHP e SAPI con cui viene eseguito, verificate dall’interno;
  • pool di PHP-FPM o modulo di Apache, con il relativo file di configurazione;
  • pacchetto installato, con revisione e repository di origine;
  • stato del ramo secondo il ciclo di vita ufficiale di PHP e stato del pacchetto secondo chi lo mantiene;
  • versione di PHP della riga di comando e dei cron che lavorano su quel sito.

Con pochi server il lavoro richiede qualche ora; con un parco più grande conviene automatizzarlo con uno strumento come Ansible, che può eseguire gli stessi comandi ovunque e raccogliere i risultati in un unico report. Se dall’inventario emergono versioni fuori supporto esposte su Internet, quello è il punto da cui partire, e possiamo aiutarti a valutarlo: scrivici indicando le versioni trovate e il sistema operativo.

Per concludere

Sullo stesso server possono convivere più versioni di PHP, e php -v mostra soltanto quella della riga di comando. Per sapere cosa esegue davvero un sito servono cinque controlli complementari: la riga di comando, per cron e script; i processi di PHP-FPM e la configurazione del web server, per collegare ogni sito alla sua versione e alla sua SAPI; i pacchetti installati, per capire chi li mantiene e se ricevono ancora correzioni; un file di prova temporaneo o il pannello del CMS, per la conferma dall’interno; le intestazioni HTTP, solo come indizio. Messi insieme in un inventario, questi dati dicono quali applicazioni sono su rami fuori supporto e da dove cominciare.

IL PROSSIMO PASSO

Mettiamo
in sicurezza.

Indicaci versione di PHP, sistema operativo e cosa ti preoccupa. Ti risponderemo con una valutazione dell’esposizione e una proposta di intervento.

Richiedi supporto

Ti porta al modulo di richiesta, in quattro passi.

PHP LEGACY · MANAGED SERVER S.R.L.info@phplegacy.it +39 02 5656 9681

Lunedì – venerdì · 09:30 – 19:30

Urgenza in corso? Reperibilità H24
+39 340 985 4556 ↗