web-dev-qa-db-fra.com

php curl: comment puis-je émuler une requête get exactement comme un navigateur Web?

il existe des sites Web qui, lorsque j'ouvre une demande ajax spécifique sur le navigateur, j'obtiens la page résultante, mais lorsque j'essaie de les charger avec curl, je reçois une erreur du serveur.

comment puis-je émuler correctement une requête get vers le serveur qui simulera un navigateur?

c'est ce que je suis en train de faire:

$url="https://new.aol.com/productsweb/subflows/ScreenNameFlow/AjaxSNAction.do?s=username&f=firstname&l=lastname";
ini_set('user_agent', 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT
5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)');
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL,$url);
$result=curl_exec($ch);
print $result;
46
ufk

Êtes-vous sûr que le module curl honore ini_set ('user_agent', ...)? Il existe une option CURLOPT_USERAGENT décrite à http://docs.php.net/function.curl-setopt .
Peut-il y avoir également un cookie testé par le serveur? Vous pouvez gérer cela en utilisant CURLOPT_COOKIE, CURLOPT_COOKIEFILE et/ou CURLOPT_COOKIEJAR.

modifier: Étant donné que la demande utilise https, il peut également y avoir une erreur lors de la vérification du certificat, voir CURLOPT_SSL_VERIFYPEER.

$url="https://new.aol.com/productsweb/subflows/ScreenNameFlow/AjaxSNAction.do?s=username&f=firstname&l=lastname";
$agent= 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)';

$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, $agent);
curl_setopt($ch, CURLOPT_URL,$url);
$result=curl_exec($ch);
var_dump($result);
66
VolkerK

je vais faire un exemple, d'abord décider quel navigateur vous voulez émuler, dans ce cas j'ai choisi Firefox 60.6.1esr (64-bit), et vérifier quelle demande GET il émet, cela peut être obtenu avec un simple serveur netcat (bundles MacOS netcat , la plupart des distributions linux regroupent netcat, et les utilisateurs de Windows peuvent obtenir netcat auprès de .. Cygwin.org, entre autres),

configuration du serveur netcat pour écouter sur le port 9999: nc -l 9999

frapper maintenant http://127.0.0.1:9999 dans Firefox, j'obtiens:

$ nc -l 9999
GET / HTTP/1.1
Host: 127.0.0.1:9999
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1

comparons maintenant cela avec ce simple script:

<?php
$ch=curl_init("http://127.0.0.1:9999");
curl_exec($ch);

je reçois:

$ nc -l 9999
GET / HTTP/1.1
Host: 127.0.0.1:9999
Accept: */*

il y a plusieurs en-têtes manquants ici, ils peuvent tous être ajoutés avec l'option CURLOPT_HTTPHEADER de curl_setopt, mais le User-Agent doit être défini spécifiquement avec CURLOPT_USERAGENT à la place (il sera persistant sur plusieurs appels à curl_exec () et si vous utilisez CURLOPT_FOLLOWLOCATION, il persistera également sur les redirections http), et le Accept-Encoding l'en-tête doit être défini avec CURLOPT_ENCODING à la place (s'ils sont définis avec CURLOPT_ENCODING, curl décompressera automatiquement la réponse si le serveur choisit de la compresser, mais si vous la définissez via CURLOPT_HTTPHEADER, vous devez manuellement détecter et décompresser le contenu vous-même, ce qui est une douleur dans le cul et complètement inutile, de manière générale), donc en ajoutant ceux que nous obtenons:

<?php
$ch=curl_init("http://127.0.0.1:9999");
curl_setopt_array($ch,array(
        CURLOPT_USERAGENT=>'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0',
        CURLOPT_ENCODING=>'gzip, deflate',
        CURLOPT_HTTPHEADER=>array(
                'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                'Accept-Language: en-US,en;q=0.5',
                'Connection: keep-alive',
                'Upgrade-Insecure-Requests: 1',
        ),
));
curl_exec($ch);

exécutant maintenant ce code, notre serveur netcat obtient:

$ nc -l 9999
GET / HTTP/1.1
Host: 127.0.0.1:9999
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept-Encoding: gzip, deflate
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Connection: keep-alive
Upgrade-Insecure-Requests: 1

et le tour est joué! notre requête GET browser émulée par php devrait maintenant être impossible à distinguer de la vraie requête GET firefox :)

cette partie suivante est juste une sélection, mais si vous regardez de très près, vous verrez que les en-têtes sont empilés dans le mauvais ordre, firefox a mis le Accept-Encoding en-tête à la ligne 6, et notre requête GET émulée le place à la ligne 3 .. pour résoudre ce problème, nous pouvons mettre manuellement l'en-tête Accept-Encoding dans la bonne ligne,

<?php
$ch=curl_init("http://127.0.0.1:9999");
curl_setopt_array($ch,array(
        CURLOPT_USERAGENT=>'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0',
        CURLOPT_ENCODING=>'gzip, deflate',
        CURLOPT_HTTPHEADER=>array(
                'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                'Accept-Language: en-US,en;q=0.5',
                'Accept-Encoding: gzip, deflate',
                'Connection: keep-alive',
                'Upgrade-Insecure-Requests: 1',
        ),
));
curl_exec($ch);

exécutant cela, notre serveur netcat obtient:

$ nc -l 9999
GET / HTTP/1.1
Host: 127.0.0.1:9999
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1

problème résolu, maintenant les en-têtes sont même dans le bon ordre, et la demande semble être COMPLÈTEMENT INDISTABLE de la vraie demande firefox :) (je ne ' Je recommande en fait cette dernière étape, c'est un fardeau de maintenance de garder CURLOPT_ENCODING en synchronisation avec l'en-tête Accept-Encoding personnalisé, et je n'ai jamais rencontré de situation où l'ordre des en-têtes est significatif)

1
hanshenrik