fascicolo["codice"] ?? 0; $scheda = $this->scheda["codice"] ?? 0; $subPath = "{$fascicolo}"; if ($scheda > 0) { $subPath .= "/{$scheda}"; } $domain = $_SESSION["ente"]->getInfo()["dominio"] ?? "global"; $folder = "{$config["npaFolder"]}/smartLog/{$domain}/{$subPath}"; if ($create) { if (!file_exists($folder)) mkdir($folder, 0777, true); } return $folder; } /** * Ottiene i log disponibili per questa scheda o fascicolo * * @return array ["endpoint::method" => "filename"] */ public function getAvailableLogs(): array { $filePath = $this->getAtomicLogPath(); if(!file_exists($filePath)) return []; $scan = scandir($filePath); $retval = []; foreach ($scan as $file) { if (is_dir("{$filePath}/$file")) continue; $file = explode(".", $file)[0]; $friendlyName = str_replace("_", "::", $file); $retval[$friendlyName] = $file; } if(!empty($retval)) { $retval["Tutti i log"] = "combined"; } return $retval; } /** * Aggiunge un nuovo log * * @param string $endpoint Endpoint di riferimento * @param string $method Metodo di riferimento * @param array $data Dati da loggare * @param string|null $error Errore, se presente, da loggare * @return void */ public function appendLog(string $endpoint, string $method, array $data, ?string $error = null): void { if ($this->disableLogs) return; if ($error) $data["error"] = $error; foreach ($data as $name => $entry) { if (is_string($entry)) { if ($name === "request") { preg_match_all("/(^.*(GovWay|Agid|Authorization|GET \/|Host:|HTTP\/).*$)/m", $entry, $matches); $data[$name] = implode("\n", $matches[0] ?? []); } elseif (valid_json($entry, $rawEntry, true)) { $data[$name] = $rawEntry; } } } // Log consultabili $filePath = $this->getAtomicLogPath(true) . "/{$endpoint}_{$method}.gz"; $data["_datetime"] = (new \DateTime())->format(DateTime::ATOM); $jsonData = json_encode($data) . "\n"; $fp = fopen("compress.zlib://{$filePath}", 'ab'); if ($fp) { fwrite($fp, $jsonData); fclose($fp); } else { throw new Exception("Impossibile scrivere sui log."); } // Log legacy per archivio global $config; $domain = $_SESSION["ente"]->getInfo()["dominio"] ?? "global"; $filename = date('Ymd') . ".log"; $npaFolder = $config["npaFolder"] . "/" . $domain; if (!is_dir($npaFolder)) { mkdir($npaFolder, 0755, true); } $legacyLog = "[" . date('Y-m-d H:i:s') . "]" . PHP_EOL; $legacyLog .= "\tURL: {$endpoint}::{$method}" . PHP_EOL; foreach ($data as $name => $entry) { if ($name[0] === "_") continue; $legacyLog .= "\t" . substr(strtoupper($name), 0, 3) . ": " . ($name === "request" ? base64_encode($entry) : json_encode($entry)) . PHP_EOL; } error_log($legacyLog . PHP_EOL, 3, "{$npaFolder}/{$filename}"); } /** * Ruota i log di piattaforma * * @return void */ public static function rotateLogs() { if (!defined("__CMDS_JOB_EXEC")) { return; } global $config; // Elimina i log più vecchi di 3 mesi $smartLogFolder = "{$config["npaFolder"]}/smartLog"; $it = new RecursiveDirectoryIterator($smartLogFolder); $toDelete = []; foreach (new RecursiveIteratorIterator($it) as $file) { if ($file->getExtension() == 'gz') { if ($file->getmTime() < (time() - (90 * 24 * 60 * 60))) { $toDelete[] = $file->getPathname(); } } } // Comprime i vecchi log legacy $today = date('Ymd'); $it = new RecursiveDirectoryIterator($config["npaFolder"]); foreach (new RecursiveIteratorIterator($it) as $file) { if ($file->getExtension() == 'log') { if ($file->getBasename() !== "{$today}.log") { exec("cd {$file->getPath()} && tar -czvf \"{$file->getBasename()}.tar.gz\" \"{$file->getFilename()}\""); $toDelete[] = $file->getPathname(); } } } foreach(array_unique($toDelete) as $filePath) { try{ unlink($filePath); } catch(\Exception $e) { alertManager::printCliAlert("Impossibile eliminare il file '{$filePath}'"); alertManager::printCliException($e); } } } /** * Ottiene i log da un file dei log atomici * * @param string $path Path da caricare * @return array Ritorna un array con le entry di log */ public function retrieveLogs(string $requestedPath): array { if($requestedPath === "combined") { $filePath = $this->getAtomicLogPath(); if(!file_exists($filePath)) return []; $scan = scandir($filePath); $entries = []; foreach ($scan as $file) { if(str_ends_with($file, ".gz")) { $logs = $this->retrieveLogs(str_replace(".gz", "", $file)); foreach($logs as &$entry) { $entry = array_merge(["file" => $file], $entry); } $entries = array_merge($entries, $logs); } } usort($entries, function($a, $b) { return $a["_datetime"] < $b["_datetime"]; }); return $entries; } $logFolder = $this->getAtomicLogPath(); // Preveniamo directory trasversal $realBase = realpath($logFolder); $browsingPath = $logFolder . "/" . ltrim($requestedPath, "/") . ".gz" ; $browsingPath = realpath($browsingPath); if ($browsingPath === false || strpos($browsingPath, $realBase) !== 0) { // Path non valido $requestedPath = ""; $browsingPath = $logFolder; } $requestedPath = substr($browsingPath, strlen($logFolder)); $data = []; $fp = fopen("compress.zlib://{$browsingPath}", 'rb'); if ($fp) { while (($line = fgets($fp)) !== false) { $data[] = json_decode($line, true); } fclose($fp); } return array_reverse($data); } }