Это сценарий, работающий на моей машине dev:
$certPath = SITE_ROOT.'/certs/GoDaddyRootCertificateAuthority-G2.crt'; $options = [ CURLOPT_POST => 1, CURLOPT_URL => 'https://uat.dwolla.com/oauth/rest/offsitegateway/checkouts', CURLOPT_RETURNTRANSFER => 1, CURLOPT_POSTFIELDS => json_encode(['name'=>'value']), CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_SSL_VERIFYPEER => true, CURLOPT_CAINFO => $certPath, ]; $ch = curl_init(); curl_setopt_array($ch, $options); if( ! $result = curl_exec($ch)) $err = curl_error($ch); curl_close($ch); if(!$result) echo $err; else print_r(json_decode($result,true)); echo '<br/><br/>'; readfile($certPath); //output cert on screen echo '<br/><br/>';
Без вопросов. Как только я переведу его в свою производственную среду, cURL-соединение завершится с ошибкой:
Ошибка сертификата SSL: невозможно получить сертификат локального эмитента
.crt
содержимое .crt
напечатано, поэтому я знаю, что путь к сертификату не является проблемой. PHP 5.6.23
на Apache 2.4
Win 7 x64
, prod машина Linux CentOS 7
Я не знаю, с чего начать искать причину. Почему сценарий не работает в производстве?
ОБНОВЛЕНИЕ. Благодаря замечанию @ blackpen в комментариях, я узнал о параметре CURLOPT_VERBOSE
используемом для создания журнала соединения. Вот результат в сломанной производственной среде:
- Имя хоста не было найдено в кеше DNS
- Попытка 104.20.47.245 …
- Подключен к uat.dwolla.com (104.20.47.245) порт 443 (# 0)
- успешно установите места для проверки сертификатов:
- CAfile: /path/to/GoDaddyRootCertificateAuthority-G2.crt CApath: none
- Ошибка сертификата SSL: невозможно получить сертификат локального эмитента
- Закрывающее соединение 0
Вот журнал из того же скрипта, но из рабочей среды разработки:
- Имя хоста в кэше DNS было устаревшим, zapped
- Попытка 104.20.48.245 …
- Подключен к uat.dwolla.com (104.20.48.245) порт 443 (# 0)
- Cipher selection: ALL:! EXPORT:! EXPORT40:! EXPORT56:! ANULL:! LOW:! RC4: @STRENGTH
- успешно установите места для проверки сертификатов:
- CAfile: /path/to/GoDaddyRootCertificateAuthority-G2.crt
CApath: none- NPN, согласованный HTTP1.1
- SSL-соединение с использованием TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
- Сертификат сервера:
- … (информация о сертификате)
- SSL-сертификат подтвердите.
- … (подробнее о POST)
Я смог заставить скрипт работать в обеих средах, заменив .crt
который работал только в средах dev, с файлом cacert.pem
взятым здесь
Я все еще не знаю, что именно происходит, но я подозреваю, что это может иметь какое-то отношение к форматированию сертификата. Возможно, PHP на Windows может иметь дело с .crt
, но PHP на Linux не смог. Я получил идею от самого высокого рейтинга ответа на другой вопрос.