PHP cURL使用P12证书调用接口报OpenSSL加载错误如何解决
报错根因
PHP cURL 的 CURLOPT_SSLCERT 配置项默认仅支持PEM格式的客户端证书,直接传入 .p12(PKCS#12)格式的证书文件无法被OpenSSL识别,因此抛出PEM格式校验失败的错误。Postman原生支持p12格式证书导入,所以不会触发该报错。
解决方案
方案1:提前将p12证书转换为PEM格式(推荐,性能更稳定)
- 执行如下openssl命令完成格式转换:
openssl pkcs12 -in 你的原证书.p12 -out 输出证书.pem -clcerts -nodes
执行时输入原p12证书的密码即可完成转换。
- 修改代码中
$certFile的值为转换后的PEM文件的绝对路径,其他配置无需调整即可正常运行。
方案2:代码中直接解析p12证书(无需提前转换格式)
如果不想额外保存PEM格式证书,可以通过PHP openssl扩展动态解析p12文件,生成临时PEM文件供cURL调用,示例代码如下:
// 读取p12证书内容,建议使用绝对路径 $p12Content = file_get_contents(__DIR__ . '/你的证书.p12'); $certPassword = '你的证书密码'; // 解析p12证书 if (!openssl_pkcs12_read($p12Content, $certs, $certPassword)) { die('p12证书解析失败:' . openssl_error_string()); } // 生成临时PEM文件,请求结束后会自动销毁 $tempPem = tmpfile(); $pemPath = stream_get_meta_data($tempPem)['uri']; fwrite($tempPem, $certs['cert'] . $certs['pkey']); rewind($tempPem); // cURL请求逻辑 $curl = curl_init(); curl_setopt_array( $curl, array( CURLOPT_URL => 'https://prufa.signet.is/SignetService2/v3/api/Signet/GetToken', CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS =>'{ "username": "username", "password": "password", "DocID": "", "GroupID": "", "SSN": "", "Onbehalf": "string", "Mobile": "", "ReturnURL": "https://prufa.signet.is/", "UserCert": "string", "Manadate": "string" }', CURLOPT_HTTPHEADER => array( 'Content-Type: application/json' ), CURLOPT_SSLCERT => $pemPath, CURLOPT_SSLCERTPASSWD => $certPassword )); $response = curl_exec($curl); if (curl_errno($curl)) { $error_msg = curl_error($curl); echo $error_msg; } curl_close($curl); // 销毁临时PEM文件 fclose($tempPem); echo $response;
注意事项
- 所有证书文件建议使用绝对路径,避免PHP运行时工作目录变化导致文件读取失败
- 确保PHP进程对证书文件有可读权限
- 提前确认PHP环境已开启openssl扩展
内容的提问来源于stack exchange,提问作者M Arslan
相关产品推荐
相关产品推荐

