файл получает содержимое(): Операция 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
- Предупреждение: файл_гет_контенты(
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:
- extension=php_openssl.dll
- разрешить_url_fopen = Вкл
Он сказал мне, что, поскольку мы находимся на Gentoo, openssl компилируется при сборке; и это не устанавливается в файле php.ini.
Я также подтвердил, что allow_url_fopen
работает. Из-за специфического характера этой проблемы; Я не нахожу много информации для помощи. Кто-нибудь из вас сталкивался с чем-то подобным? Спасибо.
14 answers
Это была чрезвычайно полезная ссылка для поиска:
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; ?>
Вы не должны просто отключать проверку. Скорее вам следует загрузить пакет сертификатов, возможно, подойдет пакет curl?
Затем вам просто нужно поместить его на свой веб-сервер, предоставив пользователю, который запускает 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));
Надеюсь, корневой сертификат сайта, к которому вы пытаетесь получить доступ, находится в пакете curl. Если это не так, это все равно не будет работать, пока вы не получите корневой сертификат сайта и поместите его в свой файл сертификата.
Я исправил это, убедившись, что OpenSSL был установлен на моей машине, а затем добавил это в мой php.ini:
openssl.cafile=/usr/local/etc/openssl/cert.pem
Вы можете обойти эту проблему, написав пользовательскую функцию, использующую 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.
Если ваша версия PHP 5, попробуйте установить cURL, введя следующую команду в терминале:
sudo apt-get install php5-curl
В основном вам нужно установить переменную среды SSL_CERT_FILE в путь к файлу PEM ssl-сертификата, загруженного по следующей ссылке: http://curl.haxx.se/ca/cacert.pem.
Мне потребовалось много времени, чтобы понять это.
Следующие ниже шаги устранят эту проблему,
- Загрузите сертификат центра сертификации по этой ссылке: https://curl.haxx.se/ca/cacert.pem
- Найдите и откройте php.ini
- Найдите
curl.cainfo
и вставьте абсолютный путь , по которому вы загрузили сертификат.curl.cainfo ="C:\wamp\htdocs\cert\cacert.pem"
- Перезапустите WAMP/XAMPP (сервер apache).
- Это работает!
Надеюсь, это поможет!!
Просто хотел добавить к этому, так как я столкнулся с той же проблемой, и ничего, что я мог бы найти где угодно, не сработало бы (например, загрузка файла cacert.pem, установка файла cafile в php.ini и т. Д.)
Если вы используете NGINX и ваш SSL-сертификат поставляется с "промежуточным сертификатом", вам необходимо объединить промежуточный файл сертификата с вашим основным файлом "mydomain.com.crt", и он должен работать. В Apache есть настройки, специфичные для промежуточных сертификатов, но в NGINX их нет, поэтому они должны находиться в одном файле как ваш обычный сертификат.
Причина этой ошибки в том, что PHP не имеет списка доверенных центров сертификации.
PHP 5.6 и более поздние версии пытаются автоматически загрузить доверенные системой центры сертификации. Проблемы с этим можно исправить. См. http://php.net/manual/en/migration56.openssl.php для получения дополнительной информации.
PHP 5.5 и более ранние версии действительно сложно правильно настроить, так как вам вручную нужно указывать пакет CA в каждом контексте запроса, что вы не хотите разбрасывать ваш код. Поэтому я решил для своего кода, что для версий PHP
$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);
}
У меня была такая же проблема с ssl на моей машине разработчика (php 7, xampp в Windows) с самозаверяющим сертификатом, пытающимся открыть "https://localhost /..." - файл. Очевидно, что сборка корневого сертификата (cacert.pem) не работала. Я просто скопировал вручную код из файла apache server.crt в загруженном файле cacert.pem и сделал запись openssl.cafile=путь/к/cacert.pem в php.ini
Была та же ошибка с PHP 7 на XAMPP и OSX.
Вышеупомянутый ответ в https://stackoverflow.com / хорошо, но это не полностью решило проблему для меня. Мне пришлось предоставить полную цепочку сертификатов, чтобы снова заставить file_get_contents() работать. Вот как я это сделал:
Получить корневой/промежуточный сертификат
Прежде всего мне нужно было выяснить, что такое корневой и промежуточный сертификат.
Самый удобным способом может быть онлайн-сертификат-инструмент, такой как ssl-покупатель
Там я нашел три сертификата, один сертификат сервера и два сертификата цепочки (один является корневым, другой, по-видимому, промежуточным).
Все, что мне нужно сделать, это просто поискать их обоих в Интернете. В моем случае это корень:
Протокол 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(), где искать файлы сертификатов. Может быть, сработают оба способа. Я предпочел другой способ. (По сравнению с решением, упомянутым выше).
Итак, теперь это мой 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() снова работает. Без ЗАВИТКОВ и, надеюсь, без недостатков в системе безопасности.
Став жертвой этой проблемы в CentOS после обновления php до php5.6, я нашел решение, которое сработало для меня.
Укажите правильный каталог для размещения ваших сертификатов по умолчанию с помощью этого
php -r 'print_r(openssl_get_cert_locations());' | grep '\[default_cert_file\]' | awk '{print $3}'
Затем используйте это, чтобы получить сертификат и поместить его в расположение по умолчанию, найденное в приведенном выше коде
wget http://curl.haxx.se/ca/cacert.pem -O <default location>
Относительно ошибок, подобных
[11-мая-2017 19:19:13 Америка/Чикаго] Предупреждение PHP: 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) ""
}
Эта проблема некоторое время расстраивала меня, пока я не понял, что у моей папки "сертификаты" было 700 разрешений, тогда как у нее должно было быть 755 разрешений. Помните, что это папка не для ключей, а для сертификатов. Я рекомендую прочитать эту ссылку на разрешения ssl.
Однажды я сделал
chmod 755 certs
Проблема была решена, по крайней мере, для меня в любом случае.
У меня была такая же проблема с другой защищенной страницей при использовании wget
или file_get_contents
. Множество исследований (включая некоторые ответы на этот вопрос) привели к простому решению - установке Curl и PHP-Curl - Если я правильно понял, у Curl есть корневой центр сертификации для Comodo, который решил проблему
Установите дополнение Curl и PHP-Curl, затем перезапустите Apache
sudo apt-get install curl
sudo apt-get install php-curl
sudo /etc/init.d/apache2 reload
Все теперь работает.