PHP 本身不自带cacert.pem,这个文件来自 curl 项目,是从 Mozilla NSS 根证书库 (certdata.txt) 提取导出的根证书束 bundle。PHP 的 curl.cainfo / openssl.cafile 配置项指向它,用于 HTTPS 校验服务器证书链,解决 cURL error 60 问题。
定期更新,Mozilla 撤销、新增根证书后 curl 会同步发布新版本,PHP 环境建议定期替换,避免老根证书过期导致 HTTPS 报错。
下面是windows PowerShell代码,用于定时任务,更新cacert.pem文件,可以设置每月检查一次。
param(
[string]$CertUrl = "https://curl.se/ca/cacert.pem",
[string]$TargetPath = "D:\php832\extras\ssl\cacert.pem",
[string]$LogPath = "D:\php832\logs\cacert-update.log",
[int]$RenewThresholdDays = 90 # 文件超过90天未更新就重新下载
)
$LogDir = Split-Path $LogPath -Parent
if (!(Test-Path $LogDir)) { New-Item -ItemType Directory -Path $LogDir -Force | Out-Null }
function Write-Log {
param([string]$Message, [string]$Level = "INFO")
$Line = "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] [$Level] $Message"
Write-Host $Line
Add-Content -Path $LogPath -Value $Line -Encoding UTF8
}
try {
Write-Log "开始检查 cacert.pem..."
# 1. 检查文件是否存在及修改时间
if (Test-Path $TargetPath) {
$LastWrite = (Get-Item $TargetPath).LastWriteTime
$DaysSinceUpdate = ((Get-Date) - $LastWrite).Days
if ($DaysSinceUpdate -lt $RenewThresholdDays) {
Write-Log "证书包 $DaysSinceUpdate 天前更新,小于阈值 $RenewThresholdDays 天,无需更新" "INFO"
exit 0
} else {
Write-Log "证书包已 $DaysSinceUpdate 天未更新,开始下载..." "INFO"
}
} else {
Write-Log "本地证书不存在,需要下载" "WARN"
}
# 2. 下载
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$TempFile = "$env:TEMP\cacert.pem.tmp"
Invoke-WebRequest -Uri $CertUrl -OutFile $TempFile -UseBasicParsing -TimeoutSec 30
$Content = Get-Content $TempFile -Raw
if ($Content -notmatch "BEGIN CERTIFICATE") { throw "下载内容不是有效 PEM" }
# 3. 验证下载成功(简单检查大小)
$FileSize = (Get-Item $TempFile).Length
if ($FileSize -lt 100000) { throw "下载文件过小($FileSize 字节),可能不完整" }
Write-Log "下载成功,文件大小: $FileSize 字节"
# 4. 备份旧证书(覆盖式,只保留一个)
if (Test-Path $TargetPath) {
Copy-Item $TargetPath "$TargetPath.backup" -Force
Write-Log "旧证书已备份到: $TargetPath.backup"
}
# 5. 替换
Copy-Item $TempFile $TargetPath -Force
Remove-Item $TempFile -Force
Write-Log "证书已替换,立即生效 ✅"
} catch {
if (Test-Path "$env:TEMP\cacert.pem.tmp") { Remove-Item "$env:TEMP\cacert.pem.tmp" -Force }
Write-Log "更新失败 ❌: $_" "ERROR"
exit 1
}