$v) { if (!is_numeric($k)) $vals[] = "$k=$v"; else $vals[] = $v; } return $vals ? implode(', ', $vals) : null; } function extractIssuerCN(array $cert_info): ?string { if (empty($cert_info['issuer']) || !is_array($cert_info['issuer'])) return null; $issuer = $cert_info['issuer']; // prima prova CN (Common Name) $keys = ['CN', 'commonName', 'O', 'o', 'OU', 'organizationName']; foreach ($keys as $k) { if (isset($issuer[$k]) && !empty($issuer[$k])) { return $issuer[$k]; } } // fallback: unisci tutti $vals = []; foreach ($issuer as $k => $v) { if (!is_numeric($k)) $vals[] = "$k=$v"; else $vals[] = $v; } return $vals ? implode(', ', $vals) : null; } // Ottieni informazioni certificato via stream_socket_client (SNI) function getCertInfo(string $host, int $port = 443, int $timeout = 10): array { $result = [ 'status' => 0, 'issued' => null, 'expiry' => null, 'company' => null, 'error' => null ]; $ctx = stream_context_create([ 'ssl' => [ 'capture_peer_cert' => true, 'verify_peer' => false, // non forziamo la verifica CA per garantire il fetch del cert 'verify_peer_name' => false, 'peer_name' => $host, 'SNI_enabled' => true, ] ]); $address = "ssl://{$host}:{$port}"; $client = @stream_socket_client($address, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $ctx); if ($client !== false) { $params = stream_context_get_params($client); @fclose($client); if (!empty($params['options']['ssl']['peer_certificate'])) { $cert = $params['options']['ssl']['peer_certificate']; $cert_info = @openssl_x509_parse($cert); if ($cert_info !== false) { $issued = isset($cert_info['validFrom_time_t']) ? date('d/m/Y', $cert_info['validFrom_time_t']) : null; $expiry = isset($cert_info['validTo_time_t']) ? date('d/m/Y', $cert_info['validTo_time_t']) : null; $company = extractIssuerCN($cert_info) ?? null; $isValid = (isset($cert_info['validTo_time_t']) && time() < $cert_info['validTo_time_t']) ? 1 : 0; $result = [ 'status' => $isValid, 'issued' => $issued, 'expiry' => $expiry, 'company' => $company, 'error' => null ]; return $result; } else { $result['error'] = 'openssl_x509_parse failed'; return $result; } } else { $result['error'] = 'no peer_certificate found'; return $result; } } // fallback: prova con openssl s_client se disponibile (solo se exec abilitato) $escHost = escapeshellarg($host); $cmd = sprintf("timeout %d openssl s_client -connect %s:443 -servername %s -showcerts /dev/null | openssl x509 -noout -dates -issuer", $timeout, $escHost, $escHost); @exec($cmd, $out, $ret); if ($ret === 0 && !empty($out)) { $joined = implode("\n", $out); // notBefore / notAfter if (preg_match('/notBefore=(.+)/i', $joined, $m1)) { $issuedRaw = trim($m1[1]); $issuedTs = strtotime($issuedRaw); $issued = $issuedTs ? date('d/m/Y', $issuedTs) : $issuedRaw; } else { $issued = null; } if (preg_match('/notAfter=(.+)/i', $joined, $m2)) { $expiryRaw = trim($m2[1]); $expiryTs = strtotime($expiryRaw); $expiry = $expiryTs ? date('d/m/Y', $expiryTs) : $expiryRaw; } else { $expiry = null; } if (preg_match('/issuer=.*O=([^,\/]+)/i', $joined, $m3)) { $company = trim($m3[1]); } elseif (preg_match('/issuer=.*CN=([^,\/]+)/i', $joined, $m4)) { $company = trim($m4[1]); } else { $company = null; } $isValid = 0; if ($expiry) { $dt = DateTime::createFromFormat('d/m/Y', $expiry); if ($dt) $isValid = (time() < $dt->getTimestamp()) ? 1 : 0; } return [ 'status' => $isValid, 'issued' => $issued, 'expiry' => $expiry, 'company' => $company, 'error' => null ]; } $result['error'] = "stream_socket_client failed: $errstr ($errno)"; return $result; } // Fetch content con cURL (supporta basic auth), ritorna array con body, http_code, error function fetchWithCurl(string $url, ?string $user, ?string $pass, int $timeout = 10) { if (!function_exists('curl_init')) return ['ok' => false, 'error' => 'curl missing']; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); // se vuoi abilitare la verifica CA, metti true e assicurati che PHP abbia CA bundle curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); if ($user !== null && $pass !== null) { curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_USERPWD, $user . ':' . $pass); } $body = curl_exec($ch); $err = curl_error($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($body === false) return ['ok' => false, 'error' => $err, 'http_code' => $code]; return ['ok' => true, 'body' => $body, 'http_code' => $code]; } // Controlla presenza stringa (1/0) e ritorna anche eventuale debug function checkContentMatch(string $url, string $match, ?string $user, ?string $pass, int $timeout = 10): array { $resp = fetchWithCurl($url, $user, $pass, $timeout); if (!$resp['ok']) { return ['ok' => 0, 'http_code' => $resp['http_code'] ?? null, 'error' => $resp['error'] ?? 'fetch failed']; } $found = (strpos($resp['body'], $match) !== false) ? 1 : 0; return ['ok' => $found, 'http_code' => $resp['http_code'] ?? null, 'error' => null]; } // --- Leggi input JSON --- if (!file_exists($inputFile)) { echo "File $inputFile non trovato\n"; exit(1); } $raw = file_get_contents($inputFile); $domains = json_decode($raw, true); if ($domains === null) { echo "Errore parsing JSON di input\n"; exit(1); } $results = []; $totalSSLok = 0; $totalContentOk = 0; foreach ($domains as $entry) { $host = $entry['host'] ?? null; $domain = $entry['domain'] ?? null; // es. wiki.sld-server.org $path = $entry['path'] ?? ''; // es. /doku.php?id=start oppure "" $word = $entry['word-to-check'] ?? ''; $basicAuth = $entry['basic_auth'] ?? false; // supporta sia basic_auth_password che basic_auth_pass (tolleranza nomi) $user = ($basicAuth && !empty($entry['basic_auth_name'])) ? $entry['basic_auth_name'] : null; $pass = null; if ($basicAuth) { if (!empty($entry['basic_auth_password'])) $pass = $entry['basic_auth_password']; elseif (!empty($entry['basic_auth_pass'])) $pass = $entry['basic_auth_pass']; elseif (!empty($entry['basic_auth_passwd'])) $pass = $entry['basic_auth_passwd']; } // costruisci URL (https://domain + path). se path vuoto -> '/' $domainClean = preg_replace('#^https?://#i', '', rtrim($domain, '/')); $pathClean = $path === '' ? '/' : (strpos($path, '/') === 0 ? $path : '/' . $path); $url = 'https://' . $domainClean . $pathClean; // estrai host per SSL (rimuove eventuale port/path) $sslHost = normalizeDomainHost($domain); // --- SSL info --- $sslInfo = getCertInfo($sslHost, 443, $timeout); // --- content check --- $contentCheck = checkContentMatch($url, $word, $user, $pass, $timeout); $word_ok = $contentCheck['ok']; $http_code = $contentCheck['http_code'] ?? null; $content_error = $contentCheck['error'] ?? null; if ($sslInfo['status'] === 1) $totalSSLok++; if ($word_ok === 1) $totalContentOk++; $results[] = [ 'host' => $host, 'domain' => $domain, 'path' => $path, 'wordtocheck' => $word, 'wordcheck_ok' => $word_ok, 'sslcheck_ok' => $sslInfo['status'], 'ssl-released' => $sslInfo['issued'], 'ssl-expiry' => $sslInfo['expiry'], 'ssl-company' => $sslInfo['company'], // campi di debug utili per capire perché auth/content falliscono 'content_http_code' => $http_code, 'content_error' => $content_error, 'ssl_error' => $sslInfo['error'] ?? null ]; } // salva output (unescaped slashes) file_put_contents($outputFile, json_encode($results, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); // stampa sommario echo "Check completato. Risultati salvati in $outputFile\n"; echo "Totali: SSL ok = $totalSSLok, Content ok = $totalContentOk\n"; ?>