Невозможно file_get_contents или cURL через HTTPS

Я использую file_get_contents захватить содержимое сайта в течение многих лет.

Недавно они обновили свой URL HTTPS а также file_get_contents перестал работать.

Я читал предыдущие вопросы и пробовал отмеченные решения, но ничего не помогло.

Например, я попробовал это, и он вернул следующее:

openssl: yes http wrapper: yes https wrapper: yes wrappers: array ( 0 => 'https', 1 => 'ftps', 2 => 'compress.zlib', 3 => 'compress.bzip2', 4 => 'php', 5 => 'file', 6 => 'data', 7 => 'http', 8 => 'ftp', 9 => 'zip', )

Итак, я попробовал это решение с file_get_contents, но безрезультатно.

Затем я попробовал это решение с cURL вообще игнорировать шифрование, но безрезультатно

Независимо от того, какое решение я пробую, ничего не возвращается.

Я не добавила extension=php_openssl.dll а также allow_url_include = On в PHP.ini в соответствии с этим, поскольку данный конкретный сайт находится на общем хосте, и хостинговая компания не разрешает редактировать файл PHP.ini, хотя они могут быть уже включены по умолчанию.

Я пробовал другие HTTPS сайты, а некоторые работают, а некоторые нет, и я не уверен, почему.

Я пытался с другого сервера (и другого IP) на том же веб-хосте, и он также не работал с целью HTTPS сайт.

Как я могу отладить и исправить это?

ОБНОВИТЬ:

phpinfo показывает:

curl cURL support enabled cURL Information libcurl/7.36.0 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5 libssh2/1.8.0

openssl OpenSSL support enabled OpenSSL Version OpenSSL 0.9.8e-fips-rhel5 01 Jul 2008

6 ответов

Решение

ЗАКЛЮЧИТЕЛЬНЫЙ ОТВЕТ

Если ваш провайдер не будет обновлять openSSL до TLS 1.2, вам следует серьезно подумать о другом провайдере. Вы должны проверить свой сервер с помощью ссылки "SSL SERVER TEST" ниже. Ваш сервер, вероятно, имеет уязвимости безопасности SSL.

Сервер, к которому вы пытаетесь подключиться, поддерживает только TLS 1.2 и TLS 1.1
Не поддерживает:TLS 1.0, SSL 3, SSL2.

Когда выполняется запрос SSL, как часть протокола SSL, curl представляет список шифров на хост-сервер. Затем сервер выбирает, какой протокол шифрования использовать, на основе списка, представленного curl.

Хост, к которому вы пытаетесь подключиться, поддерживает эти наборы шифров

TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)  
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)  
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x9f) 
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x9e)  
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028)  
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)  
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (0x6b)  
TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x39) 
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027) 
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)  
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (0x67)  
TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x33) 
TLS_RSA_WITH_AES_256_GCM_SHA384 (0x9d) 
TLS_RSA_WITH_AES_128_GCM_SHA256 (0x9c) 
TLS_RSA_WITH_AES_256_CBC_SHA256 (0x3d) 
TLS_RSA_WITH_AES_256_CBC_SHA (0x35) 
TLS_RSA_WITH_AES_128_CBC_SHA256 (0x3c) 
TLS_RSA_WITH_AES_128_CBC_SHA (0x2f) 

Поскольку ваш openSSL был выпущен в июле 2008 года, а TLSv1.2 был выпущен в следующем месяце, августе 2008 года, лучше всего использовать TLSv1.1.

ВОЗМОЖНО ВРЕМЕННОЕ ИСПРАВЛЕНИЕ, пока вы не обновите

У меня нет высокого уровня уверенности, это будет работать для вас

Вы должны проверить SSL своего собственного сервера с чем-то вроде этого SSL SERVER TEST

Если ваш сервер поддерживает TLS1.1, вы можете попробовать следующее. Я не могу проверить это, потому что у меня нет той же версии curl, что и у вас на старом сервере с вашей версией openSSL.

Используйте параметр curl, CURLOPT_SSL_CIPHER_LIST, чтобы запретить хост-серверу использовать что-либо кроме TLS 1.1

curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'TLSv1');
curl_setopt($ch, CURL_SSLVERSION_TLSv1_1);

Если нет, то попробуйте:

curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'DEFAULT');
curl_setopt($ch, CURL_SSLVERSION_TLSv1_1);

НИЖНЯЯ ЛИНИЯ

По нескольким причинам, чем эта проблема, вам необходимо обновить ваш openSSL.

-------------------------------------------------------------------------


 -

ПРЕДЫДУЩАЯ УСТРАНЕНИЕ НЕИСПРАВНОСТЕЙ НИЖЕ

Первое, что я делаю, это отключаю JavaScript в браузере. Если я могу получить страницу с помощью браузера без JavaScript, я ЗНАЮ, что могу получить ее с помощью PHP.

Я строю запрос, чтобы он выглядел точно так же, как в браузере. Я перехожу на вкладку "Сеть" Инспектора и редактирую заголовок запроса и копирую его, вставляя в мой код.

$request = array();
$request[] = 'Host: example.com';
$request[] = 'Connection: keep-alive';
$request[] = 'Pragma: no-cache';
$request[] = 'Cache-Control: no-cache';
$request[] = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8';
$request[] = 'User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36';
$request[] = 'DNT: 1';
$request[] = 'Origin: https://example.com';
$request[] = 'Referer: https://example.com/entry/login';
$request[] = 'Accept-Encoding: gzip, deflate';
$request[] = 'Accept-Language: en-US,en;q=0.8';

Инициализировать локон

$url = 'https://example.com/entry/login';
$ch = curl_init($url);

Добавьте параметры запроса

curl_setopt($ch, CURLOPT_HTTPHEADER, $request);

Скажите curl, чтобы включить заголовки

curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_HEADER, true);

Вернуть ответ

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

Следуйте за редиректами Перенаправления могут быть ловушкой. Возможно, вам не придется следить и анализировать ответ. Часто перенаправления существуют, чтобы установить куки.

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_COOKIESESSION , true );

Пусть завиток справится со сжатием

curl_setopt($ch, CURLOPT_ENCODING,"");

Установить параметры тайм-аута

curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_TIMEOUT,10);
curl_setopt($ch, CURLOPT_FAILONERROR,true);

Сделайте запрос и получите ответ

Далее вы получите все, что вам нужно знать о запросах. $ Info также будет иметь все заголовки перенаправления. Если перенаправления были сделаны, у $ responseHeader будут все заголовки ответа.

ОБНОВЛЕНИЕ: новый полностью протестированный код

Это может не иметь значения, потому что это также работает на моей машине:

echo file_get_contents($url);

Если curl не удается, этот код должен дать вам причину, почему он не прошел.

Измените URL. Этот принадлежит клиенту.

<?php
header('content-type: text/plain');

$url = 'https://amxemr.com';
$ch = curl_init($url);

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_ENCODING,"");
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_TIMEOUT,10);
curl_setopt($ch, CURLOPT_FAILONERROR,true);
curl_setopt($ch, CURLOPT_ENCODING,"");
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_HEADER, true);


$data = curl_exec($ch);
if (curl_errno($ch)){
    echo 'Retreive Base Page Error: ' . curl_error($ch);
}
else {
  $info = rawurldecode(var_export(curl_getinfo($ch),true));

 // Get the cookies:

  $skip = intval(curl_getinfo($ch, CURLINFO_HEADER_SIZE)); 
  $responseHeader= substr($data,0,$skip);
  $data= substr($data,$skip);
  echo "HEADER: $responseHeader\n";
  echo "\n\nINFO: $info\n\nDATA: $data";
}  
?>

Если вышеописанное не сработало, запустите phpinfo()

<?php
phpinfo();
?>  

Там должен быть раздел curl и openSSL.

phpinfo openSSL

--------------------------------------------------------------------

ОБНОВЛЕНИЕ ВТОРОЕ

Хорошие новости

Я знаю проблему и смог повторить ошибки, которые вы получили.

Retreive Base Page Error: 
Unknown SSL protocol error in connection to www.xxxx.com:443 

ПРИМЕЧАНИЕ xxx был сайтом по ссылке, которую вы мне дали, вы можете удалить это сообщение сейчас.

Забавно, у меня один сервер я не обновляю. И, к счастью, у него была та же версия openSSL с июля 2008 года.

Вам нужно обновить ваш openSSL. Также file_get_contents() не удалось на этом сервере тоже. Он работал над версией openSSL в феврале 2013 года, а также с июня 2014 года.

Я не могу сказать, нужно ли обновлять что-либо еще, например, функции, которые используют openSSL, могут (или не могут) обновляться.

Я иду с пословицей, если она не сломана, не чините ее. Я действительно считаю, что некоторые обновления на самом деле являются более низкими. Я все еще на XP. Но он сломался, и вам нужно это исправить.

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

Использование curl с curl Вы можете легко ввести любую страницу поверх https,

обратите внимание на следующие строки:

curl_setopt($ch, CURLOPT_SSLVERSION, 4);

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

вот рабочий код, проверенный на twitter а также facebook

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
//ini_set('display_errors',1);
//$crawled = [];
set_time_limit(0);// to infinity for example
ob_start();
$output;
function grabAll($url){

$ch = curl_init();

// 2. set the options, including the url
curl_setopt($ch, CURLOPT_URL,$url);
// curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// curl_setopt($ch, CURLOPT_HEADER, 0);


//curl_setopt ($ch, CURLOPT_CAINFO, "ca-cert/cacert.pem");

curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSLVERSION, 4);
//curl_setopt($ch, CURLOPT_HEADER, 1);
  curl_setopt($ch, CURLOPT_MAXREDIRS, '1L');

curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//curl_setopt($ch, CURLOPT_TIMEOUT, 400);   
//curl_setopt ($ch, CURLOPT_POST, 1);

// 3. execute and fetch the resulting HTML output
//curl_exec($ch);
$output = curl_exec($ch);
ob_flush();//Flush the data here
if ($output === FALSE) {

    echo "cURL Error: " . curl_error($ch);

}

$info = curl_getinfo($ch);



//echo 'Took ' . $info['total_time'] . ' seconds for url ' . $info['url'];


// 4. free up the curl handle
curl_close($ch);
//print_r($crawled);    


//return $output ;

echo $output;
}


grabAll('https://twitter.com/?lang=en');

ОБНОВЛЕНИЕ 1: используйте этот код для сохранения файла

   function grab_image($url,$saveto){
        $ch = curl_init ($url);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_SSLVERSION, 4);
        curl_setopt($ch, CURLOPT_BINARYTRANSFER,1);
        $raw=curl_exec($ch);
        curl_close ($ch);
        if(file_exists($saveto)){
            unlink($saveto);
        }
        $fp = fopen($saveto,'x');
        fwrite($fp, $raw);
        fclose($fp);
    }






  grab_image('i.imgur.com/85wsoLI.jpg','download/');

надеюсь, это решило вашу проблему!!

вот демо на моем сервере: http://54.167.121.86/curl/curl.php

Если по nothing, вы имеете в виду пустое тело ответа, это не похоже на проблему httpS. в противном случае curl_exec будет жаловаться, curl_exec() вернет bool(false), а curl_error() укажет на проблему SSL.

How can I debug and fix this?

исследуйте запрос, отправленный вашим браузером, когда вы получите действительный ответ (для этого используйте инструменты разработчика вашего браузера. Например, на вкладке "Сеть" в Ctrl+shift+i в Google Chrome), затем сравните его с запросом, отправленным curl, когда вы получаете неверный ответ (для этого используйте CURLOPT_VERBOSE) и 1 на 1 добавляете все заголовки, которые посылает браузер,

например, вы заметите, что libcurl отправляет нет user-agent заголовок, в то время как ваш браузер отправляет что-то вроде user-agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 так что добавьте этот заголовок. вы также заметите, что libcurl по умолчанию отправляет Accept: */* пока ваш браузер отправляет Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 - так что исправь, заставь curl отправлять одинаковые заголовки.

продолжайте делать это, пока 2 запроса не станут неразличимыми, и по пути вы обнаружите разницу, которая делает curl заблокированным.

моя ставка на заголовок агента пользователя.

Поскольку это похоже на проблему с версией SSL, вы можете настроить CURL на ее игнорирование, используя CURLOPT_SSL_VERIFYPEER.

Вот скрипт, работающий с размещенным вами URL

$url = 'https://XXX/YYY/view-all';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
$response = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
print_r($response);

Иногда это помогает не проверять сертификат и хост, а просто доверять криптографии в SSL.

$context = stream_context_create(
    array('http' => array(
            'follow_location' => true
        ),
        'ssl' => array(
            'verify_peer' => false, 
            'verify_peer_name' => false
        )
    )
);

$content = @file_get_contents($file, FALSE, $context);

Есть ли у сайта HTTPS самозаверяющий сертификат? Можете ли вы предоставить доменные имена для некоторых сайтов, которые работают, а некоторые - нет?

Вы пытались использовать "allow_self_signed" => true в настройках контекста потока?

Итак, это выглядит так:

$arrContextOptions=array(
    "ssl"=>array(
        "verify_peer"=>false,
        "verify_peer_name"=>false,
        "allow_self_signed"=>true,
    ),
);  

$response = file_get_contents($url, false, stream_context_create($arrContextOptions));
Другие вопросы по тегам