prima versione corretta; null = nessuna release ufficiale con la correzione
const CORRETTE = ['8.5' => '8.5.12', '8.4' => '8.4.27', '8.3' => '8.3.36', '8.2' => '8.2.35',
'8.1' => null, '8.0' => null, '7.4' => null, '7.3' => null];
header('X-Robots-Tag: noindex, nofollow');
header('Cache-Control: no-store');
header('Content-Type: text/html; charset=utf-8');
$lang = (isset($_GET['lang']) && $_GET['lang'] === 'en') ? 'en'
: ((isset($_GET['lang']) && $_GET['lang'] === 'it') ? 'it'
: (str_starts_with(strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? ''), 'it') ? 'it' : 'en'));
$T = [
'it' => [
'titolo' => 'PHP2Shell Check', 'sotto' => 'Il PHP che serve davvero le tue pagine, e se è al sicuro.',
'scaduto' => 'Questo controllo è scaduto (60 minuti) e il file si è cancellato da solo. Ricaricalo se ti serve ancora.',
'eliminato' => 'File eliminato. Il tuo sito non espone più questa pagina.',
'v_ok' => 'AL SICURO', 'v_ok_t' => 'PHP %s contiene la correzione di PHP2Shell.',
'v_no' => 'VULNERABILE', 'v_no_t' => 'PHP %s è sotto la prima versione corretta (%s). Aggiorna dal pannello dell\'hosting.',
'v_mit' => 'VULNERABILE, MITIGATO IN PARTE', 'v_mit_t' => 'PHP %s è sotto la %s. La mitigazione temporanea è attiva, ma copre solo una delle due falle: aggiorna appena puoi.',
'v_eol' => 'NESSUNA CORREZIONE UFFICIALE', 'v_eol_t' => 'Il ramo %s non riceve più release da php.net. Passa a 8.3 o 8.4 dal pannello dell\'hosting, o chiedi all\'hosting se ha applicato una correzione propria.',
'v_boh' => 'VERSIONE NON RICONOSCIUTA', 'v_boh_t' => 'Non so valutare PHP %s. Confronta con le versioni corrette qui sotto.',
'distro' => 'Se PHP arriva dai pacchetti di Debian, Ubuntu o RHEL, il numero può restare uguale e la correzione arriva dal pacchetto: verifica con apt changelog php%s-cli | grep CVE-2026-1096.',
'h_php' => 'Il PHP che serve le pagine', 'h_cfg' => 'Mitigazioni temporanee', 'h_host' => 'Come aggiornare davvero', 'h_az' => 'Azioni',
'sapi' => 'Modalità', 'bin' => 'Binario', 'root' => 'Cartella del sito', 'cli_nota' => '«php -v» in SSH legge un altro binario: conta questo.',
'c_up' => 'session.upload_progress.enabled', 'c_up_t' => 'Spento blocca la via confermata della CVE-2026-109619.',
'c_post' => 'post_max_size', 'c_post_t' => 'Entro 32M limita la CVE-2026-109618 (8M se il sito non carica file).',
'c_upl' => 'upload_max_filesize', 'c_upl_t' => 'Deve restare sotto post_max_size.',
'c_mem' => 'memory_limit', 'c_mem_t' => 'Il consiglio di php.net è -1 (nessun limite) via php_admin_value: solo chi gestisce il server può farlo.',
'c_exp' => 'expose_php', 'c_exp_t' => 'Spento nasconde la versione negli header: non protegge, riduce il rumore.',
'c_fb' => 'fatal_error_backtraces', 'c_fb_t' => 'Solo PHP 8.5: spento blocca la seconda via confermata della CVE-2026-109619.',
'ok' => 'ok', 'ko' => 'da sistemare', 'nd' => 'n/d',
'mit_btn' => 'Attiva la mitigazione (.user.ini)', 'mit_desc' => 'Scrive session.upload_progress.enabled = 0 e post_max_size = 32M in .user.ini in questa cartella (copia di riserva accanto). Con FPM e CGI può servire fino a 5 minuti e un riavvio dei worker: ricontrolla. Non sostituisce l\'aggiornamento.',
'mit_fatto' => 'Mitigazione scritta in %s. Ricarica fra qualche minuto e guarda i valori qui sopra: contano quelli, non il file.',
'mit_err' => 'Non riesco a scrivere %s (permessi). Fallo a mano con il contenuto qui sotto.',
'undo_btn' => 'Togli la mitigazione', 'undo_fatto' => 'Ripristinato il .user.ini precedente.',
'del_btn' => 'Elimina questo file', 'del_desc' => 'Fallo appena hai finito: questa pagina mostra la configurazione del tuo server.',
'root_warn' => 'Questo file non è nella cartella principale del sito: il .user.ini scritto qui vale solo per questa cartella. Spostalo in %s.',
'c_ui_t' => 'Se è vuoto il server ignora i .user.ini: le mitigazioni si impostano solo dal pannello (es. hPanel → Configurazione PHP → opzioni) o in php.ini.',
'noini' => 'Questo server ignora i file .user.ini (user_ini.filename vuoto): il pulsante non avrebbe effetto. Imposta i valori dal pannello dell\'hosting o in php.ini, oppure aggiorna PHP, che è la vera correzione.',
'fonti' => 'Fonti', 'da' => 'Uno strumento gratuito di', 'scade' => 'Si cancella da solo tra %d minuti.',
'host_hostinger' => 'Hostinger: hPanel → Siti web → Gestisci → Avanzate → Configurazione PHP → scegli 8.3 o 8.4, salva. Il numero esatto (es. 8.3.36) lo decide Hostinger: ricarica questa pagina dopo il cambio per vedere se è arrivato.',
'host_cpanel' => 'cPanel: Software → Select PHP Version (o MultiPHP Manager) → scegli il ramo più recente e salva. Poi ricarica questa pagina.',
'host_plesk' => 'Plesk: Siti web e domini → Impostazioni PHP → versione PHP → scegli la più recente e applica.',
'host_siteground' => 'SiteGround: Site Tools → Dev → PHP Manager → Set PHP version → scegli la più recente.',
'host_own' => 'Server tuo (VPS, Docker, cloud): aggiorna il pacchetto php o l\'immagine (8.3.36 / 8.4.27 / 8.5.12), riavvia PHP-FPM o il web server, poi ricarica questa pagina.',
'host_generic' => 'Pannello non riconosciuto: cerca «Versione PHP» nel pannello dell\'hosting, scegli 8.3 o 8.4, salva, ricarica questa pagina.',
'dopo' => 'Dopo l\'aggiornamento ricarica questa pagina: se dice «AL SICURO», elimina il file. Se il tuo sito accetta caricamenti sopra 32 MB, puoi poi togliere la mitigazione.',
],
'en' => [
'titolo' => 'PHP2Shell Check', 'sotto' => 'The PHP that actually serves your pages, and whether it is safe.',
'scaduto' => 'This check expired (60 minutes) and the file removed itself. Upload it again if you still need it.',
'eliminato' => 'File deleted. Your site no longer exposes this page.',
'v_ok' => 'SAFE', 'v_ok_t' => 'PHP %s contains the PHP2Shell fix.',
'v_no' => 'VULNERABLE', 'v_no_t' => 'PHP %s is below the first fixed version (%s). Update from your hosting panel.',
'v_mit' => 'VULNERABLE, PARTLY MITIGATED', 'v_mit_t' => 'PHP %s is below %s. The temporary mitigation is on, but it covers only one of the two flaws: update as soon as you can.',
'v_eol' => 'NO OFFICIAL FIX', 'v_eol_t' => 'Branch %s no longer gets releases from php.net. Switch to 8.3 or 8.4 in your hosting panel, or ask your host whether it applied its own backport.',
'v_boh' => 'UNKNOWN VERSION', 'v_boh_t' => 'I cannot assess PHP %s. Compare with the fixed versions below.',
'distro' => 'If PHP comes from Debian, Ubuntu or RHEL packages the number may stay the same and the fix ships in the package: check with apt changelog php%s-cli | grep CVE-2026-1096.',
'h_php' => 'The PHP serving your pages', 'h_cfg' => 'Temporary mitigations', 'h_host' => 'How to really update', 'h_az' => 'Actions',
'sapi' => 'Mode', 'bin' => 'Binary', 'root' => 'Site folder', 'cli_nota' => '"php -v" over SSH reads a different binary: this one counts.',
'c_up' => 'session.upload_progress.enabled', 'c_up_t' => 'Off blocks the confirmed path of CVE-2026-109619.',
'c_post' => 'post_max_size', 'c_post_t' => 'At most 32M limits CVE-2026-109618 (8M if the site takes no uploads).',
'c_upl' => 'upload_max_filesize', 'c_upl_t' => 'Must stay below post_max_size.',
'c_mem' => 'memory_limit', 'c_mem_t' => 'php.net suggests -1 (no limit) via php_admin_value: only whoever runs the server can do that.',
'c_exp' => 'expose_php', 'c_exp_t' => 'Off hides the version in headers: no protection, less noise.',
'c_fb' => 'fatal_error_backtraces', 'c_fb_t' => 'PHP 8.5 only: off blocks the second confirmed path of CVE-2026-109619.',
'ok' => 'ok', 'ko' => 'fix', 'nd' => 'n/a',
'mit_btn' => 'Enable mitigation (.user.ini)', 'mit_desc' => 'Writes session.upload_progress.enabled = 0 and post_max_size = 32M into .user.ini in this folder (backup kept next to it). With FPM and CGI it can take up to 5 minutes and a worker restart: check again. It does not replace the update.',
'mit_fatto' => 'Mitigation written to %s. Reload in a few minutes and read the values above: those count, not the file.',
'mit_err' => 'Cannot write %s (permissions). Do it by hand with the content below.',
'undo_btn' => 'Remove mitigation', 'undo_fatto' => 'Previous .user.ini restored.',
'del_btn' => 'Delete this file', 'del_desc' => 'Do it as soon as you are done: this page shows your server configuration.',
'root_warn' => 'This file is not in the site root: a .user.ini written here applies to this folder only. Move it to %s.',
'c_ui_t' => 'If empty, the server ignores .user.ini files: mitigations can only be set in the hosting panel (e.g. hPanel → PHP Configuration → options) or php.ini.',
'noini' => 'This server ignores .user.ini files (user_ini.filename is empty): the button would have no effect. Set the values in your hosting panel or php.ini, or update PHP, which is the real fix.',
'fonti' => 'Sources', 'da' => 'A free tool by', 'scade' => 'Self-deletes in %d minutes.',
'host_hostinger' => 'Hostinger: hPanel → Websites → Manage → Advanced → PHP Configuration → pick 8.3 or 8.4, save. The exact number (e.g. 8.3.36) is up to Hostinger: reload this page after the switch to see whether it arrived.',
'host_cpanel' => 'cPanel: Software → Select PHP Version (or MultiPHP Manager) → pick the newest branch and save. Then reload this page.',
'host_plesk' => 'Plesk: Websites & Domains → PHP Settings → PHP version → pick the newest and apply.',
'host_siteground' => 'SiteGround: Site Tools → Dev → PHP Manager → Set PHP version → pick the newest.',
'host_own' => 'Your own server (VPS, Docker, cloud): update the php package or image (8.3.36 / 8.4.27 / 8.5.12), restart PHP-FPM or the web server, then reload this page.',
'host_generic' => 'Panel not recognised: look for "PHP version" in your hosting panel, pick 8.3 or 8.4, save, reload this page.',
'dopo' => 'After updating, reload this page: if it says "SAFE", delete the file. If your site accepts uploads above 32 MB you can then remove the mitigation.',
],
][$lang];
$t = static fn(string $k, ...$a): string => $a ? sprintf($T[$k], ...$a) : $T[$k];
$h = static fn(?string $s): string => htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8');
// ---- scadenza: primo avvio registrato in un file accanto; dopo 60 minuti il file si toglie da solo
$dir = __DIR__;
$marker = $dir . '/.php2shell-check.run';
$primo = is_file($marker) ? (int)@file_get_contents($marker) : 0;
if ($primo === 0) {
$primo = time();
@file_put_contents($marker, (string)$primo);
if (!is_file($marker)) { $primo = (int)filemtime(__FILE__); }
}
$token = hash('sha256', $primo . '|' . __FILE__ . '|' . ($_SERVER['DOCUMENT_ROOT'] ?? ''));
$elimina = static function () use ($marker): void { @unlink($marker); @unlink(__FILE__); };
if (time() - $primo > SCADENZA_SECONDI) {
$elimina();
exit('
' . $h($t('scaduto')) . '
');
}
// ---- azioni (POST + token)
$msg = '';
$userini = $dir . '/.user.ini';
$bak = $dir . '/.user.ini.bak-php2shell';
$blocco = "; PHP2Shell temporary mitigation (astraai.it/php2shell) " . date('Y-m-d') . "\n"
. "session.upload_progress.enabled = 0\npost_max_size = 32M\nupload_max_filesize = 16M\n";
if ($_SERVER['REQUEST_METHOD'] === 'POST' && hash_equals($token, (string)($_POST['token'] ?? ''))) {
$az = (string)($_POST['azione'] ?? '');
if ($az === 'mitiga' && ini_get('user_ini.filename') !== '') {
$vecchio = is_file($userini) ? (string)file_get_contents($userini) : '';
if (!is_file($bak)) { @file_put_contents($bak, $vecchio); }
$nuovo = str_contains($vecchio, 'session.upload_progress.enabled') ? $vecchio : $vecchio . (($vecchio && !str_ends_with($vecchio, "\n")) ? "\n" : '') . $blocco;
$msg = (@file_put_contents($userini, $nuovo) !== false) ? $t('mit_fatto', '.user.ini') : $t('mit_err', '.user.ini');
} elseif ($az === 'ripristina') {
if (is_file($bak)) {
$prev = (string)file_get_contents($bak);
$prev === '' ? @unlink($userini) : @file_put_contents($userini, $prev);
@unlink($bak);
}
$msg = $t('undo_fatto');
} elseif ($az === 'elimina') {
$elimina();
exit('' . $h($t('eliminato')) . '
');
}
}
// ---- lettura
$ver = PHP_VERSION;
$ramo = implode('.', array_slice(explode('.', $ver), 0, 2));
$minima = array_key_exists($ramo, CORRETTE) ? CORRETTE[$ramo] : 'boh';
$bool = static fn(string $k): ?bool => ($v = ini_get($k)) === false ? null : filter_var($v, FILTER_VALIDATE_BOOLEAN);
$bytes = static function (string $v): int {
$v = trim($v); if ($v === '' ) return 0; $n = (int)$v; $u = strtolower(substr($v, -1));
return $u === 'g' ? $n << 30 : ($u === 'm' ? $n << 20 : ($u === 'k' ? $n << 10 : $n));
};
$up = $bool('session.upload_progress.enabled');
$post = (string)ini_get('post_max_size');
$upl = (string)ini_get('upload_max_filesize');
$mem = (string)ini_get('memory_limit');
$exp = $bool('expose_php');
$fb = version_compare($ver, '8.5.0', '>=') ? $bool('fatal_error_backtraces') : null;
$uiname = (string)ini_get('user_ini.filename');
$leggeUserIni = $uiname !== '' && PHP_SAPI !== 'apache2handler' && PHP_SAPI !== 'cli-server';
$mitigato = ($up === false) && $bytes($post) > 0 && $bytes($post) <= 32 << 20;
if ($minima === 'boh') { $stato = 'boh'; }
elseif ($minima === null) { $stato = 'eol'; }
elseif (version_compare($ver, $minima, '>=')) { $stato = 'ok'; }
else { $stato = $mitigato ? 'mit' : 'no'; }
$colori = ['ok' => '#16a34a', 'mit' => '#d97706', 'no' => '#dc2626', 'eol' => '#dc2626', 'boh' => '#64748b'];
$testi = ['ok' => $t('v_ok_t', $ver), 'no' => $t('v_no_t', $ver, (string)$minima), 'mit' => $t('v_mit_t', $ver, (string)$minima),
'eol' => $t('v_eol_t', $ramo), 'boh' => $t('v_boh_t', $ver)];
// ---- hosting riconosciuto da binario, cartella e server
$root = (string)($_SERVER['DOCUMENT_ROOT'] ?? '');
$srv = (string)($_SERVER['SERVER_SOFTWARE'] ?? '');
$bin = PHP_BINARY ?: '';
$hostk = 'generic';
if (preg_match('#/home/u\d+/domains/#', $root) || str_contains(strtolower($srv . ' ' . gethostname()), 'hostinger') || str_contains(gethostname(), 'main-hosting.eu')) $hostk = 'hostinger';
elseif (preg_match('#/home/(customer|u\d+-\w+)/www/#', $root)) $hostk = 'siteground';
elseif (str_contains($root, '/var/www/vhosts/')) $hostk = 'plesk';
elseif (preg_match('#^/home/[^/]+/public_html#', $root) || str_contains($bin, '/opt/cpanel/') || str_contains($bin, '/opt/alt/')) $hostk = 'cpanel';
elseif (str_contains($root, '/var/www/') || str_contains($root, '/srv/') || str_contains($root, '/usr/share/nginx') || PHP_SAPI === 'cli-server') $hostk = 'own';
$inRoot = $root !== '' && realpath($root) === realpath($dir);
$minuti = max(1, (int)ceil((SCADENZA_SECONDI - (time() - $primo)) / 60));
$riga = static function (string $nome, string $valore, ?bool $ok, string $nota) use ($h, $t): string {
$tag = $ok === null ? ['#64748b', $t('nd')] : ($ok ? ['#16a34a', $t('ok')] : ['#dc2626', $t('ko')]);
return "{$h($nome)} {$nota} | {$h($valore)} | "
. "{$h($tag[1])} |
";
};
?>
= $h($t('titolo')) ?> · = $h($ver) ?>
IT · EN
= $h($t('titolo')) ?>
= $h($t('sotto')) ?> · = $h($t('scade', $minuti)) ?>
= $h($msg) ?>
= $h($t('v_' . $stato)) ?>
PHP = $h($ver) ?>
= $h($testi[$stato]) ?>
= $t('distro', $ramo) ?>
= $h($t('h_php')) ?>
| = $h($t('sapi')) ?> | = $h(PHP_SAPI) ?> · = $h($srv ?: '?') ?> = $h($t('cli_nota')) ?> |
| = $h($t('bin')) ?> | = $h($bin ?: '?') ?> |
| = $h($t('root')) ?> | = $h($root ?: '?') ?> = $h($t('root_warn', $root)) ?> |
| php.net | 8.5 → 8.5.12 · 8.4 → 8.4.27 · 8.3 → 8.3.36 · 8.2 → 8.2.35 · ≤ 8.1: — |
= $h($t('h_cfg')) ?>
= $riga('session.upload_progress.enabled', $up === null ? '?' : ($up ? 'On' : 'Off'), $up === null ? null : !$up, $h($t('c_up_t'))) ?>
= $riga('post_max_size', $post, $bytes($post) > 0 && $bytes($post) <= 32 << 20, $h($t('c_post_t'))) ?>
= $riga('upload_max_filesize', $upl, $bytes($upl) > 0 && $bytes($upl) <= $bytes($post), $h($t('c_upl_t'))) ?>
= $riga('memory_limit', $mem, null, $h($t('c_mem_t'))) ?>
= $riga('user_ini.filename', $uiname === '' ? '(vuoto)' : $uiname, $uiname !== '', $h($t('c_ui_t'))) ?>
= $riga('expose_php', $exp === null ? '?' : ($exp ? 'On' : 'Off'), $exp === null ? null : !$exp, $h($t('c_exp_t'))) ?>
=')): ?>= $riga('fatal_error_backtraces', $fb === null ? '?' : ($fb ? 'On' : 'Off'), $fb === null ? null : !$fb, $h($t('c_fb_t'))) ?>
= $h($t('h_host')) ?>
= $h($t('host_' . $hostk)) ?>
= $h($t('dopo')) ?>
= $h($t('h_az')) ?>
= $t('mit_desc') ?>
= $h($t('noini')) ?>
= $h($t('del_desc')) ?>
= $h($blocco) ?>