web-dev-qa-db-fra.com

Impossible de file_get_contents ou cURL via HTTPS

J'utilise file_get_contents pour récupérer le contenu d'un site pendant des années.

Récemment, ils ont mis à jour leur URL sur HTTPS et file_get_contents a cessé de fonctionner.

J'ai lu les questions précédentes et essayé des solutions marquées, mais rien n'a fonctionné.

Par exemple, j'ai essayé this , et il a renvoyé ce qui suit:

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', )

Alors j'ai essayé cette solution avec file_get_contents, en vain.

J'ai ensuite essayé cette solution avec cURL d'ignorer totalement le cryptage, en vain

Quelle que soit la solution que j'essaie, rien est renvoyé.

J'ai not ajouté extension=php_openssl.dll et allow_url_include = On à PHP.ini conformément à this car ce site particulier se trouve sur un hôte partagé et que la société d’hébergement ne permet pas la modification du fichier PHP.ini, bien être déjà activé par défaut.

J'ai essayé d'autres sites HTTPS, et certains fonctionnent, d'autres pas, et je ne sais pas pourquoi.

J'ai essayé à partir d'un serveur différent (et d'une adresse IP différente) sur le même hôte Web, mais cela ne fonctionnait pas non plus avec le site cible HTTPS.

Comment puis-je déboguer et résoudre ce problème?

UPDATE:

phpinfo montre:

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

9
ProgrammerGirl

RÉPONSE FINALE

Si votre FAI ne met pas OpenSSL à niveau vers TLS 1.2, vous devez sérieusement envisager un autre FAI. Vous devriez tester votre serveur avec le lien "TEST DU SERVEUR SSL" ci-dessous. Votre serveur a probablement des vulnérabilités de sécurité SSL. 

Le serveur avec lequel vous essayez de vous connecter ne prend en charge que TLS 1.2 et TLS 1.1.
Ne supporte pas: TLS 1.0, SSL 3, SSL2.

Lorsqu'une demande SSL est faite, dans le cadre du protocole SSL, curl présente une liste de codes de chiffrement au serveur hôte. Le serveur choisit ensuite le protocole de chiffrement à utiliser en fonction de la liste présentée par curl. 

L'hôte que vous essayez de contacter prend en charge ces suites cryptées

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) 

Parce que votre openSSL a été publié en juillet 2008 et que TLSv1.2 a été publié le mois suivant, en août 2008, le mieux que vous ayez est TLSv1.1.

FIX TEMPORAIRE POSSIBLE jusqu'à la mise à niveau

Je n'ai pas beaucoup de confiance que cela fonctionnera pour vous

Vous devriez tester le SSL de votre propre serveur avec quelque chose comme ceci SSL SERVER TEST

Si votre serveur prend en charge TLS1.1, vous pouvez essayer les solutions suivantes. Je ne peux pas tester cela car je n'ai pas la même version de curl que vous sur l'ancien serveur avec votre version d'openSSL.

Utilisez l'option curl, CURLOPT_SSL_CIPHER_LIST pour empêcher le serveur hôte d'utiliser autre chose que TLS 1.1.

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

Si non, alors essayez:

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

LIGNE INFÉRIEURE

Pour plus de raisons que ce problème, vous devez mettre à jour votre openSSL.

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


 -

DÉPANNAGE ANTÉRIEUR SOUS CE POINT

La première chose que je fais est de désactiver javascript dans le navigateur. Si je peux récupérer la page avec un navigateur sans javascript, je sais que je peux l'obtenir avec PHP.

Je construis la demande pour qu'elle ressemble exactement à dans le navigateur. Je vais à l'onglet Réseau de l'inspecteur et édite l'en-tête de demande et le copie et le colle dans mon code.

 enter image description here

 enter image description here

$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';

Initalize curl

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

Ajouter les paramètres de la demande

curl_setopt($ch, CURLOPT_HTTPHEADER, $request);

Indique à curl d'inclure les en-têtes

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

Retourne la réponse

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

Suivre les redirections Les redirections peuvent être un piège. Vous devrez peut-être PAS suivre et analyser la réponse. Les redirections servent souvent à créer des cookies. 

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

Laisse curl gérer la compression  

curl_setopt($ch, CURLOPT_ENCODING,"");

Définir les paramètres de délai d'attente

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

Faites la demande et obtenez une réponse

Ce qui suit vous donnera tout ce que vous devez savoir sur les demandes. Le $ info aura aussi tous les en-têtes de redirection. Si des redirections ont été effectuées, $ responseHeader aura tous les en-têtes de réponse.

UPDATE: Nouveau code entièrement testé

Cela n'a peut-être pas d'importance, car cela fonctionne également sur ma machine:

echo file_get_contents($url);

Si curl échoue, ce code devrait vous indiquer pourquoi il a échoué.

Change l'URL. Celui-ci appartient à un client.

<?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";
}  
?>

Si ce qui précède n'a pas fonctionné, lancez phpinfo ()

<?php
phpinfo();
?>  

Il devrait y avoir une section curl et openSSL.

 enter image description here

 phpinfo openSSL

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

MISE À JOUR DEUX

Bonne nouvelle

Je connais le problème et j'ai pu reproduire les erreurs que vous avez eues. 

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

NOTE xxx était le site à partir du lien que vous m'avez donné, vous pouvez supprimer ce message maintenant.

C'est drôle, j'ai un serveur que je ne mets pas à jour. Et par chance, il avait la même version d’openSSL de juillet 2008. 

Vous devez mettre à jour votre openSSL. File_get_contents () a également échoué sur ce serveur. Cela a fonctionné sur une version de openSSL de février 2013 ainsi que sur celle de juin 2014.

Je ne peux pas dire s'il est nécessaire de mettre à niveau autre chose, comme les fonctions qui utilisent openSSL peuvent (ou non) être mises à jour. 

Je vais avec l'adage si ce n'est pas cassé ne le répare pas. Je crois que certaines mises à niveau sont en fait des notes négatives. Je suis toujours sous XP. Mais il est cassé et vous devez le réparer. 

Au moins, ce n'est pas une solution miracle. Je suis convaincu que vous devez mettre à niveau. Il s'agissait d'une procédure de dépannage méthodique capable de dupliquer vos erreurs. Vous pouvez également utiliser file_get_contents() également.

2
Misunderstood

utiliser curl avec curl vous pouvez facilement importer n'importe quelle page sur https.

notez ces lignes: 

curl_setopt($ch, CURLOPT_SSLVERSION, 4);

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

voici du code de travail, testé pour Twitter et 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');

UPDATE 1: utilise ce code pour enregistrer le fichier

   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/');

espérons que cela résout votre problème !!

voici la démo sur mon serveur: http://54.167.121.86/curl/curl.php

1
EaBangalore

Parfois, il est utile de ne pas valider le certificat et l'hôte, mais simplement de faire confiance à la cryptographie en 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);
0
powtac

Le site HTTPS dispose-t-il d'un certificat auto-signé? Pouvez-vous fournir les noms de domaine de certains des sites qui fonctionnent et d'autres qui ne fonctionnent pas? 

Avez-vous essayé d'utiliser "allow_self_signed" => true dans la configuration du contexte de flux? 

Donc ça ressemble à: 

$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));
0
peiiion

si par nothing, vous entendez un corps de réponse vide, cela ne ressemble pas à un problème httpS. Si c'était le cas, alors curl_exec se plaindrait, curl_exec () renverrait bool (false) et curl_error () indiquerait un problème SSL.

How can I debug and fix this?

examinez la demande envoyée par votre navigateur lorsque vous obtenez une réponse valide (utilisez les outils de développement de votre navigateur pour cela. par exemple, l'onglet "Réseau" dans Ctrl + Maj + i de Google Chrome), puis comparez-la avec la demande envoyée par curl lorsque vous obtenez une réponse invalide (utilisez CURLOPT_VERBOSE pour cela), et 1 par 1, ajoutez tous les en-têtes que le navigateur envoie,

par exemple, vous remarquerez que libcurl n'envoie pas d'en-tête user-agent, alors que votre navigateur envoie quelque chose comme 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, ajoutez donc cet en-tête. vous remarquerez également que par défaut libcurl envoie Accept: */*, alors que votre navigateur envoie Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 - corrigez-le, faites en sorte que curl envoie les mêmes en-têtes. 

continuez comme cela, jusqu'à ce que les 2 demandes soient indiscernables, et tout au long du chemin, vous trouverez la différence qui fait que curl est bloqué.

mon pari est sur l'en-tête user-agent.

0
hanshenrik

Comme cela semble être un problème avec la version SSL, vous pouvez configurer CURL pour qu’il l’ignore à l’aide de CURLOPT_SSL_VERIFYPEER .

Voici un script fonctionnant avec l'URL que vous avez posté

$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);
0
Iñaki Soria