PHP探针无法直接检测SSL证书状态,仅能确认OpenSSL扩展是否启用及当前请求是否为HTTPS;真正检测需用stream_socket_client或cURL主动连接并解析证书有效期等信息。

PHP探针本身不直接检测SSL证书状态,它只能告诉你服务器是否启用了OpenSSL扩展、是否支持HTTPS协议,但无法主动连接远程站点并解析其证书有效期、链完整性或域名匹配问题——这些必须由你主动发起HTTPS请求并处理响应才能获得。
PHP探针能查到的SSL基础信息
典型PHP探针(如雅黑探针、OneBase探针)会调用 extension_loaded('openssl') 和 function_exists('openssl_x509_parse') 来判断OpenSSL是否可用;也会读取 $_SERVER['HTTPS'] 或 $_SERVER['SERVER_PORT'] === '443' 判断当前页面是否走HTTPS。但这只是“本机环境支持”和“当前请求协议”,和“目标证书是否有效”是两回事。
- ✅ 能确认:
php_openssl.dll是否已启用(检查php.ini中;extension=php_openssl.dll是否去掉了分号) - ✅ 能看到:当前页面 URL 是
https://还是http:// - ❌ 不能知道:你调用的
file_get_contents('https://api.example.com')会不会因证书过期而失败 - ❌ 不能发现:Nginx 配置漏了中间证书,导致安卓/iOS客户端握手失败
用PHP代码真正检测远程SSL证书状态
要让探针具备“检测证书”能力,得自己补一段逻辑:用 stream_context_create() 建立带证书校验的HTTPS连接,并捕获错误;再用 openssl_x509_parse() 解析证书内容。关键不是“有没有SSL”,而是“连不连得上、证不证得实”。
- 必须启用
CURLOPT_SSL_VERIFYPEER和CURLOPT_SSL_VERIFYHOST(设为true),否则等于没校验 - 若系统CA缺失(如 Alpine 容器),需显式指定
CURLOPT_CAINFO指向cacert.pem文件 - 证书解析后,
$parsed['validTo_time_t']是Unix时间戳,对比time()就能判断是否过期 - 注意:
openssl_x509_parse()只能解析本地证书文件或从资源中提取的证书,不能直接解析远程URL——得先用stream_socket_client()或cURL抓取原始证书
function checkRemoteCert($host, $port = 443) {
$context = stream_context_create([
'ssl' => [
'verify_peer' => true,
'cafile' => '/path/to/cacert.pem',
'capture_peer_cert' => true,
'SNI_enabled' => true,
]
]);
$socket = @stream_socket_client("tls://{$host}:{$port}", $errno, $errstr, 5, STREAM_CLIENT_CONNECT, $context);
if (!$socket) return ['error' => "Connection failed: {$errstr} ({$errno})"];
$params = stream_context_get_params($socket);
if (!isset($params['options']['ssl']['peer_certificate'])) {
return ['error' => 'No certificate received'];
}
$cert = openssl_x509_parse($params['options']['ssl']['peer_certificate']);
if (!$cert) return ['error' => 'Failed to parse certificate'];
return [
'subject' => $cert['subject']['CN'] ?? 'N/A',
'issuer' => $cert['issuer']['CN'] ?? 'N/A',
'expires_at' => date('Y-m-d H:i:s', $cert['validTo_time_t']),
'expired' => $cert['validTo_time_t'] < time(),
];
}
为什么探针里加了检测还是不准?常见坑点
很多自建探针把检测写成“能 file_get_contents('https://baidu.com') 就算通过”,这非常误导——因为默认上下文可能关闭了证书验证,或者系统自动 fallback 到旧TLS版本,掩盖真实问题。
立即学习“PHP免费学习笔记(深入)”;
- ⚠️
file_get_contents()默认不校验证书,除非你传入了带'verify_peer' => true的stream_context - ⚠️ 使用
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false)测试通不通,结果为“通”≠“证书正常”,只是绕过了验证 - ⚠️ 检测时用了
www.example.com,但证书只签了example.com,CURLOPT_SSL_VERIFYHOST设为2才会报错,设为1或false就漏掉 - ⚠️ 在Docker Alpine镜像里跑探针,
/etc/ssl/certs/ca-certificates.crt根本不存在,必须手动挂载或指定CAINFO
真正有用的SSL状态检测,从来不是“探针有没有显示绿色对勾”,而是你明确控制了验证开关、指定了可信CA路径、并解析了证书里的 validTo_time_t 字段——其他都是障眼法。











