file_get_contents (): операция SSL завершилась неудачно с кодом 1. И еще

Я пытаюсь получить доступ к этой конкретной службе REST со страницы PHP, созданной на нашем сервере. Я сузил проблему до этих двух строк. Итак, моя страница PHP выглядит так:

<?php $response = file_get_contents("https://maps.co.weber.ut.us/arcgis/rest/services/SDE_composite_locator/GeocodeServer/findAddressCandidates?Street=&SingleLine=3042+N+1050+W&outFields=*&outSR=102100&searchExtent=&f=json"); echo $response; ?> 

Страница замирает в строке 2 со следующими ошибками:

  • Предупреждение: file_get_contents (): Ошибка операции SSL с кодом 1. OpenSSL Сообщения об ошибках: ошибка: 14090086: SSL-процедуры: SSL3_GET_SERVER_CERTIFICATE: проверка сертификата не выполнена … php в строке 2
    • Предупреждение: file_get_contents (): Не удалось включить криптографию в … php в строке 2
    • Предупреждение: file_get_contents ( https://maps.co.weber.ut.us/arcgis/rest/services/SDE_composite_locator/GeocodeServer/findAddressCandidates?Street=&SingleLine=3042+N+1050+W&outFields=*&outSR=102100&searchExtent=&f=json ): не удалось открыть поток: операция завершилась неудачно … php в строке 2

Мы используем сервер Gentoo. Недавно мы обновили версию PHP 5.6. Это было после обновления, когда эта проблема появилась.

Когда я заменил службу REST, я обнаружил адрес, например https://www.google.com ; моя страница работает отлично.

В более ранней попытке я установил “verify_peer”=>false и передал это как аргумент file_get_contents, как описано здесь: file_get_contents, игнорируя verify_peer => false? Но, как заметил писатель; это не имело никакого значения.

Я спросил одного из наших администраторов серверов, есть ли эти строки в нашем файле php.ini:

  • расширение = php_openssl.dll
  • allow_url_fopen = Вкл.

Он сказал мне, что, поскольку мы на Gentoo, openssl скомпилируется, когда мы создаем; и он не установлен в файле php.ini.

Я также подтвердил, что allow_url_fopen работает. В связи с особым характером этой проблемы; Я не нахожу много информации для помощи. Кто-нибудь из вас сталкивался с чем-то подобным? Благодарю.

Это была чрезвычайно полезная ссылка, чтобы найти:

http://php.net/manual/en/migration56.openssl.php

Официальный документ, описывающий изменения, сделанные для открытия ssl в PHP 5.6. Здесь я узнал о еще одном параметре, который я должен был установить как false: «verify_peer_name» => false

Поэтому мой рабочий код выглядит так:

 <?php $arrContextOptions=array( "ssl"=>array( "verify_peer"=>false, "verify_peer_name"=>false, ), ); $response = file_get_contents("https://maps.co.weber.ut.us/arcgis/rest/services/SDE_composite_locator/GeocodeServer/findAddressCandidates?Street=&SingleLine=3042+N+1050+W&outFields=*&outSR=102100&searchExtent=&f=json", false, stream_context_create($arrContextOptions)); echo $response; ?> 

Вы не должны просто отключать проверку. Скорее, вы должны скачать комплект сертификатов, возможно, это сделает скручивание ?

Затем вам просто нужно разместить его на своем веб-сервере, предоставляя пользователю, который запускает php-разрешение для чтения файла. Тогда этот код должен работать на вас:

 $arrContextOptions=array( "ssl"=>array( "cafile" => "/path/to/bundle/cacert.pem", "verify_peer"=> true, "verify_peer_name"=> true, ), ); $response = file_get_contents("https://maps.co.weber.ut.us/arcgis/rest/services/SDE_composite_locator/GeocodeServer/findAddressCandidates?Street=&SingleLine=3042+N+1050+W&outFields=*&outSR=102100&searchExtent=&f=json", false, stream_context_create($arrContextOptions)); 

Надеемся, что корневой сертификат сайта, к которому вы пытаетесь получить доступ, находится в комплекте с завитки. Если это не так, это все равно не будет работать, пока вы не получите корневой сертификат сайта и не поместите его в файл сертификата.

Я исправил это, убедившись, что этот OpenSSL был установлен на моей машине, а затем добавив это в мой php.ini:

 openssl.cafile=/usr/local/etc/openssl/cert.pem 

Если ваша версия php равна 5. Затем попробуйте это fix.Install curl, набрав следующие команды в терминале.
sudo apt-get install php5-curl

Вы можете обойти эту проблему, написав пользовательскую функцию, которая использует завиток, например:

 function file_get_contents_curl( $url ) { $ch = curl_init(); curl_setopt( $ch, CURLOPT_AUTOREFERER, TRUE ); curl_setopt( $ch, CURLOPT_HEADER, 0 ); curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); curl_setopt( $ch, CURLOPT_URL, $url ); curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, TRUE ); $data = curl_exec( $ch ); curl_close( $ch ); return $data; } 

Затем просто используйте file_get_contents_curl вместо file_get_contents всякий раз, когда вы вызываете URL-адрес, начинающийся с https.

В основном вы должны установить переменную среды SSL_CERT_FILE на путь файла PEM сертификата ssl, загруженного по следующей ссылке: http://curl.haxx.se/ca/cacert.pem .

Мне потребовалось много времени, чтобы понять это.

Просто хотел добавить к этому, так как я столкнулся с одной и той же проблемой, и ничто из того, что я мог найти в любом месте, не будет работать (например, загрузка файла cacert.pem, установка cafile в php.ini и т. Д.)

Если вы используете NGINX, а ваш сертификат SSL поставляется с «промежуточным сертификатом», вам необходимо объединить промежуточный файл сертификата с вашим основным файлом «mydomain.com.crt», и он должен работать. У Apache есть параметр, специфичный для промежуточных сертификатов, но NGINX не так, он должен находиться в том же файле, что и ваш обычный сертификат.

Имел ту же самую ssl-проблему на моей машине разработчика (php 7, xampp на окнах) с самоподписанным сертификатом, пытающимся открыть файл « https: // localhost / …». Очевидно, что root-certificate-assembly (cacert.pem) не работает. Я просто скопировал код из файла apache server.crt в загруженном файле cacert.pem и выполнил запись openssl.cafile = path / to / cacert.pem в php.ini

Причина этой ошибки заключается в том, что PHP не имеет списка доверенных центров сертификации.

PHP 5.6 и более поздние версии попытаются загрузить ЦС, которым доверяет система автоматически. Проблемы с этим могут быть исправлены. См. http://php.net/manual/en/migration56.openssl.php для получения дополнительной информации.

PHP 5.5 и более ранние версии очень трудно настроить правильно, так как вам вручную нужно указать пакет CA в каждом контексте запроса, что вы не хотите посыпать своим кодом. Поэтому я решил для своего кода, что для версий PHP <5.6 проверка SSL просто отключается:

 $req = new HTTP_Request2($url); if (version_compare(PHP_VERSION, '5.6.0', '<')) { //correct ssl validation on php 5.5 is a pain, so disable $req->setConfig('ssl_verify_host', false); $req->setConfig('ssl_verify_peer', false); } 

Что касается ошибок, подобных

[11-May-2017 19:19:13 America / Chicago] PHP Warning: file_get_contents (): операция SSL завершилась неудачно с кодом 1. OpenSSL Сообщения об ошибках: ошибка: 14090086: Подпрограммы SSL: ssl3_get_server_certificate: проверка сертификата не выполнена

Вы проверили разрешения сертификатов и каталогов, на которые ссылается openssl?

Вы можете сделать это

 var_dump(openssl_get_cert_locations()); 

Чтобы получить что-то подобное этому

 array(8) { ["default_cert_file"]=> string(21) "/usr/lib/ssl/cert.pem" ["default_cert_file_env"]=> string(13) "SSL_CERT_FILE" ["default_cert_dir"]=> string(18) "/usr/lib/ssl/certs" ["default_cert_dir_env"]=> string(12) "SSL_CERT_DIR" ["default_private_dir"]=> string(20) "/usr/lib/ssl/private" ["default_default_cert_area"]=> string(12) "/usr/lib/ssl" ["ini_cafile"]=> string(0) "" ["ini_capath"]=> string(0) "" } 

Эта проблема несколько раз разочаровала меня, пока я не понял, что в моей папке «certs» было 700 разрешений, когда у нее должно было быть 755 разрешений. Помните, что это не папка для ключей, а сертификатов. Я рекомендую прочитать эту ссылку на разрешениях ssl.

Когда я это сделал

 chmod 755 certs 

Проблема была исправлена, по крайней мере, для меня.

Имела ту же ошибку с PHP 7 на XAMPP и OSX.

Вышеупомянутый ответ в https://stackoverflow.com/ хорош, но он не полностью решил проблему для меня. Я должен был предоставить полную цепочку сертификатов, чтобы файл file_get_contents () снова работал. Вот как я это сделал:

Получить корневой / промежуточный сертификат

Прежде всего мне нужно было выяснить, что такое корень и промежуточный сертификат.

Самый удобный способ – это, возможно, онлайн-сертификат, например, ssl-shopper

Там я нашел три сертификата, один сервер-сертификат и два цепных сертификата (один из них – корень, другой – промежуточный).

Все, что мне нужно сделать, это просто искать в Интернете для них обоих. В моем случае это корень:

thawte DV SSL SHA256 CA

И это приводит к его url thawte.com . Поэтому я просто помещал этот сертификат в текстовый файл и делал то же самое для промежуточного. Готово.

Получить сертификат хоста

Следующее, что я должен был, это загрузить мой серверный сертификат. В Linux или OS X это можно сделать с помощью openssl:

 openssl s_client -showcerts -connect whatsyoururl.de:443 </dev/null 2>/dev/null|openssl x509 -outform PEM > /tmp/whatsyoururl.de.cert 

Теперь приведите их всех вместе

Теперь просто объедините все их в один файл. (Может быть, хорошо просто положить их в одну папку, я просто объединил их в один файл). Вы можете сделать это следующим образом:

 cat /tmp/thawteRoot.crt > /tmp/chain.crt cat /tmp/thawteIntermediate.crt >> /tmp/chain.crt cat /tmp/tmp/whatsyoururl.de.cert >> /tmp/chain.crt 

скажите PHP, где найти цепочку

Есть эта удобная функция openssl_get_cert_locations (), которая сообщит вам, где PHP ищет файлы сертификатов. И есть этот параметр, который скажет file_get_contents (), где искать файлы cert. Возможно, оба пути будут работать. Я предпочел параметр параметр. (По сравнению с упомянутым выше решением).

Итак, теперь это мой PHP-код

 $arrContextOptions=array( "ssl"=>array( "cafile" => "/Applications/XAMPP/xamppfiles/share/openssl/certs/chain.pem", "verify_peer"=> true, "verify_peer_name"=> true, ), ); $response = file_get_contents($myHttpsURL, 0, stream_context_create($arrContextOptions)); 

Это все. file_get_contents () снова работает. Без CURL и, надеюсь, без недостатков безопасности.