'error', 'm' => 'simulate-nis2.php non trovato']) . "\n\n"; echo 'data: ' . json_encode(['t' => 'done', 'stats' => ['pass' => 0, 'fail' => 1, 'skip' => 0, 'warn' => 0]]) . "\n\n"; flush(); exit; } // ── Ambiente subprocess ─────────────────────────────────────────────────────── // NIS2_SSE=1 → il simulatore usa output SSE anche quando php_sapi_name()='cli' // NIS2_SIM=SIM06 → esegue solo lo scenario B2B (opzionale) $env = []; foreach ($_ENV ?: [] as $k => $v) { if (is_string($v)) $env[$k] = $v; } $env['NIS2_SSE'] = '1'; if ($simParam === 'sim06') { $env['NIS2_SIM'] = 'SIM06'; } // ── Avvia subprocess (pattern lg231 runCommand) ─────────────────────────────── $descriptors = [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']]; $cwd = dirname($scriptPath); // PHP_BINARY in PHP-FPM punta a php-fpm, non al CLI → cerca il binario CLI corretto $phpBin = PHP_BINARY; if (str_contains($phpBin, 'fpm') || !is_executable($phpBin)) { foreach (['/usr/bin/php' . PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION, '/usr/bin/php', 'php'] as $try) { if (is_executable($try) || shell_exec("which $try 2>/dev/null")) { $phpBin = $try; break; } } } $cmd = $phpBin . ' ' . escapeshellarg($scriptPath); $proc = proc_open($cmd, $descriptors, $pipes, $cwd, $env); if (!is_resource($proc)) { echo 'data: ' . json_encode(['t' => 'error', 'm' => 'Impossibile avviare il simulatore']) . "\n\n"; echo 'data: ' . json_encode(['t' => 'done', 'stats' => ['pass' => 0, 'fail' => 1, 'skip' => 0, 'warn' => 0]]) . "\n\n"; flush(); exit; } fclose($pipes[0]); stream_set_blocking($pipes[1], false); stream_set_blocking($pipes[2], false); // ── Streaming riga per riga ────────────────────────────────────────────────── // Il simulatore emette direttamente eventi SSE (data: {...}\n\n). // Il wrapper li passa al browser immediatamente senza buffering. while (true) { $chunk = fread($pipes[1], 8192); if ($chunk !== false && $chunk !== '') { echo $chunk; flush(); } // Stderr → errori PHP fatali visibili nel terminale SSE $err = fread($pipes[2], 1024); if ($err !== false && $err !== '') { foreach (explode("\n", trim($err)) as $errLine) { if (trim($errLine) !== '') { echo 'data: ' . json_encode(['t' => 'error', 'm' => '[stderr] ' . trim($errLine)]) . "\n\n"; } } flush(); } $status = proc_get_status($proc); if (!$status['running']) { // Leggi eventuale output residuo dopo la fine del processo $tail = stream_get_contents($pipes[1]); if ($tail) { echo $tail; flush(); } fclose($pipes[1]); fclose($pipes[2]); proc_close($proc); break; } usleep(50000); // 50ms — bilanciamento latenza/CPU (come lg231) }