comment obtenir les cookies d'une curl php dans une variable


126

Donc, un gars d'une autre entreprise a pensé que ce serait génial si au lieu d'utiliser soap ou xml-rpc ou rest ou tout autre protocole de communication raisonnable, il intégrait simplement toute sa réponse sous forme de cookies dans l'en-tête.

Je dois retirer ces cookies comme, espérons-le, un tableau de cette réponse curl. Si je dois perdre une partie de ma vie à écrire un analyseur pour cela, je serai très malheureux.

Est-ce que quelqu'un sait comment cela peut être fait simplement, de préférence sans rien écrire dans un fichier?

Je serai très reconnaissant si quelqu'un peut m'aider avec cela.

Réponses:


174
$ch = curl_init('http://www.google.com/');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// get headers too with this line
curl_setopt($ch, CURLOPT_HEADER, 1);
$result = curl_exec($ch);
// get cookie
// multi-cookie variant contributed by @Combuster in comments
preg_match_all('/^Set-Cookie:\s*([^;]*)/mi', $result, $matches);
$cookies = array();
foreach($matches[1] as $item) {
    parse_str($item, $cookie);
    $cookies = array_merge($cookies, $cookie);
}
var_dump($cookies);

31
Malheureusement, j'ai le sentiment que c'est la bonne réponse. Je pense que c'est ridicule que curl ne puisse pas simplement me donner un tableau mappé.
thirsty93

3
Je vais vous le donner mais le preg_match était faux. Je ne voulais pas seulement la session, mais je comprends pourquoi vous penseriez cela. Mais le génie qui a créé son système charge le cookie avec une carte de réponse entière, comme un get ou un post. Merde comme ça: Set-Cookie: price = 1 Set-Cookie: status = accept J'avais besoin d'un preg_match_all avec '/ ^ Set-Cookie: (. *?) = (. *?) $ /
Sm

7
@ thirsty93 Curl ne peut pas vous donner un tableau mappé. Mais vous montre un moyen de le sauvercurl_setopt($ch, CURLOPT_HEADERFUNCTION, 'callback_SaveHeaders');
Shiplu Mokaddim

2
Selon la structure des cookies renvoyée, la dernière ligne devra peut-être être modifiée en quelque chose comme parse_str($m[1], $cookies), ce qui remplira les cookies dans un tableau associatif dans la $cookiesvariable ....
random_user_name

7
Pour les correctifs combinés qui attrapent plus d'un cookie: preg_match_all('/^Set-Cookie:\s*([^;]*)/mi', $result, $matches); $cookies = array(); foreach($matches[1] as $item) { parse_str($item, $cookie); $cookies = array_merge($cookies, $cookie); }
Combuster

39

Bien que cette question soit assez ancienne et que la réponse acceptée soit valide, je la trouve un peu inconfortable car le contenu de la réponse HTTP (HTML, XML, JSON, binaire ou autre) se mélange avec les en-têtes.

J'ai trouvé une alternative différente. CURL fournit une option ( CURLOPT_HEADERFUNCTION) pour définir un rappel qui sera appelé pour chaque ligne d'en-tête de réponse. La fonction recevra l'objet curl et une chaîne avec la ligne d'en-tête.

Vous pouvez utiliser un code comme celui-ci (adapté de la réponse TML):

$cookies = Array();
$ch = curl_init('http://www.google.com/');
// Ask for the callback.
curl_setopt($ch, CURLOPT_HEADERFUNCTION, "curlResponseHeaderCallback");
$result = curl_exec($ch);
var_dump($cookies);

function curlResponseHeaderCallback($ch, $headerLine) {
    global $cookies;
    if (preg_match('/^Set-Cookie:\s*([^;]*)/mi', $headerLine, $cookie) == 1)
        $cookies[] = $cookie;
    return strlen($headerLine); // Needed by curl
}

Cette solution a l'inconvénient d'utiliser une variable globale, mais je suppose que ce n'est pas un problème pour les scripts courts. Et vous pouvez toujours utiliser des méthodes et des attributs statiques si curl est encapsulé dans une classe.


10
Au lieu d'un global, vous pouvez utiliser une fermeture contenant une référence à $cookies. $curlResponseHeaderCallback = function ($ch, $headerLine) use (&$cookies) {alors curl_setopt($ch, CURLOPT_HEADERFUNCTION, $curlResponseHeaderCallback);.
Seph

Que se passe-t-il si vous avez tout cela dans une classe? Comment référencez-vous la fonction de classe $class->curlResponseHeaderCallback()? Ou avez-vous juste en curlResponseHeaderCallbackdehors de la classe?
Sevenearths

13

Cela le fait sans regexps, mais nécessite l' extension HTTP PECL .

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
$result = curl_exec($ch);
curl_close($ch);

$headers = http_parse_headers($result);
$cookobjs = Array();
foreach($headers AS $k => $v){
    if (strtolower($k)=="set-cookie"){
        foreach($v AS $k2 => $v2){
            $cookobjs[] = http_parse_cookie($v2);
        }
    }
}

$cookies = Array();
foreach($cookobjs AS $row){
    $cookies[] = $row->cookies;
}

$tmp = Array();
// sort k=>v format
foreach($cookies AS $v){
    foreach ($v  AS $k1 => $v1){
        $tmp[$k1]=$v1;
    }
}

$cookies = $tmp;
print_r($cookies);

2
Merci pour cela. Une solution claire et sémantique vaut la peine d'installer une extension.
Ben Jacobs

2
Ce serait la meilleure solution, si elle pecl installfonctionnait réellement. Grrr.
Robin Winslow

11

Si vous utilisez CURLOPT_COOKIE_FILE et CURLOPT_COOKIE_JAR, curl lira / écrira les cookies depuis / dans un fichier. Vous pouvez, une fois curl terminé, le lire et / ou le modifier comme vous le souhaitez.


12
Je pense que le but n'est pas d'utiliser ce fichier
Nicolas Thery

3

libcurl fournit également CURLOPT_COOKIELIST qui extrait tous les cookies connus. Tout ce dont vous avez besoin est de vous assurer que la liaison PHP / CURL peut l'utiliser.


12
Il n'est pas utilisable via l'API PHP.
Emre Yazici

1

quelqu'un ici peut le trouver utile. hhb_curl_exec2 fonctionne à peu près comme curl_exec, mais arg3 est un tableau qui sera rempli avec les en-têtes http renvoyés (index numérique), et arg4 est un tableau qui sera rempli avec les cookies renvoyés ($ cookies ["expires"] => " Ven, 06-May-2016 05:58:51 GMT "), et arg5 sera rempli avec ... des informations sur la requête brute faite par curl.

l'inconvénient est que CURLOPT_RETURNTRANSFER doit être activé, sinon l'erreur est supprimée et qu'il écrasera CURLOPT_STDERR et CURLOPT_VERBOSE, si vous les utilisiez déjà pour autre chose .. (je pourrais corriger cela plus tard)

exemple d'utilisation:

<?php
header("content-type: text/plain;charset=utf8");
$ch=curl_init();
$headers=array();
$cookies=array();
$debuginfo="";
$body="";
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
$body=hhb_curl_exec2($ch,'https://www.youtube.com/',$headers,$cookies,$debuginfo);
var_dump('$cookies:',$cookies,'$headers:',$headers,'$debuginfo:',$debuginfo,'$body:',$body);

et la fonction elle-même.

function hhb_curl_exec2($ch, $url, &$returnHeaders = array(), &$returnCookies = array(), &$verboseDebugInfo = "")
{
    $returnHeaders    = array();
    $returnCookies    = array();
    $verboseDebugInfo = "";
    if (!is_resource($ch) || get_resource_type($ch) !== 'curl') {
        throw new InvalidArgumentException('$ch must be a curl handle!');
    }
    if (!is_string($url)) {
        throw new InvalidArgumentException('$url must be a string!');
    }
    $verbosefileh = tmpfile();
    $verbosefile  = stream_get_meta_data($verbosefileh);
    $verbosefile  = $verbosefile['uri'];
    curl_setopt($ch, CURLOPT_VERBOSE, 1);
    curl_setopt($ch, CURLOPT_STDERR, $verbosefileh);
    curl_setopt($ch, CURLOPT_HEADER, 1);
    $html             = hhb_curl_exec($ch, $url);
    $verboseDebugInfo = file_get_contents($verbosefile);
    curl_setopt($ch, CURLOPT_STDERR, NULL);
    fclose($verbosefileh);
    unset($verbosefile, $verbosefileh);
    $headers       = array();
    $crlf          = "\x0d\x0a";
    $thepos        = strpos($html, $crlf . $crlf, 0);
    $headersString = substr($html, 0, $thepos);
    $headerArr     = explode($crlf, $headersString);
    $returnHeaders = $headerArr;
    unset($headersString, $headerArr);
    $htmlBody = substr($html, $thepos + 4); //should work on utf8/ascii headers... utf32? not so sure..
    unset($html);
    //I REALLY HOPE THERE EXIST A BETTER WAY TO GET COOKIES.. good grief this looks ugly..
    //at least it's tested and seems to work perfectly...
    $grabCookieName = function($str)
    {
        $ret = "";
        $i   = 0;
        for ($i = 0; $i < strlen($str); ++$i) {
            if ($str[$i] === ' ') {
                continue;
            }
            if ($str[$i] === '=') {
                break;
            }
            $ret .= $str[$i];
        }
        return urldecode($ret);
    };
    foreach ($returnHeaders as $header) {
        //Set-Cookie: crlfcoookielol=crlf+is%0D%0A+and+newline+is+%0D%0A+and+semicolon+is%3B+and+not+sure+what+else
        /*Set-Cookie:ci_spill=a%3A4%3A%7Bs%3A10%3A%22session_id%22%3Bs%3A32%3A%22305d3d67b8016ca9661c3b032d4319df%22%3Bs%3A10%3A%22ip_address%22%3Bs%3A14%3A%2285.164.158.128%22%3Bs%3A10%3A%22user_agent%22%3Bs%3A109%3A%22Mozilla%2F5.0+%28Windows+NT+6.1%3B+WOW64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F43.0.2357.132+Safari%2F537.36%22%3Bs%3A13%3A%22last_activity%22%3Bi%3A1436874639%3B%7Dcab1dd09f4eca466660e8a767856d013; expires=Tue, 14-Jul-2015 13:50:39 GMT; path=/
        Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT;
        //Cookie names cannot contain any of the following '=,; \t\r\n\013\014'
        //
        */
        if (stripos($header, "Set-Cookie:") !== 0) {
            continue;
            /**/
        }
        $header = trim(substr($header, strlen("Set-Cookie:")));
        while (strlen($header) > 0) {
            $cookiename                 = $grabCookieName($header);
            $returnCookies[$cookiename] = '';
            $header                     = substr($header, strlen($cookiename) + 1); //also remove the = 
            if (strlen($header) < 1) {
                break;
            }
            ;
            $thepos = strpos($header, ';');
            if ($thepos === false) { //last cookie in this Set-Cookie.
                $returnCookies[$cookiename] = urldecode($header);
                break;
            }
            $returnCookies[$cookiename] = urldecode(substr($header, 0, $thepos));
            $header                     = trim(substr($header, $thepos + 1)); //also remove the ;
        }
    }
    unset($header, $cookiename, $thepos);
    return $htmlBody;
}

function hhb_curl_exec($ch, $url)
{
    static $hhb_curl_domainCache = "";
    //$hhb_curl_domainCache=&$this->hhb_curl_domainCache;
    //$ch=&$this->curlh;
    if (!is_resource($ch) || get_resource_type($ch) !== 'curl') {
        throw new InvalidArgumentException('$ch must be a curl handle!');
    }
    if (!is_string($url)) {
        throw new InvalidArgumentException('$url must be a string!');
    }

    $tmpvar = "";
    if (parse_url($url, PHP_URL_HOST) === null) {
        if (substr($url, 0, 1) !== '/') {
            $url = $hhb_curl_domainCache . '/' . $url;
        } else {
            $url = $hhb_curl_domainCache . $url;
        }
    }
    ;

    curl_setopt($ch, CURLOPT_URL, $url);
    $html = curl_exec($ch);
    if (curl_errno($ch)) {
        throw new Exception('Curl error (curl_errno=' . curl_errno($ch) . ') on url ' . var_export($url, true) . ': ' . curl_error($ch));
        // echo 'Curl error: ' . curl_error($ch);
    }
    if ($html === '' && 203 != ($tmpvar = curl_getinfo($ch, CURLINFO_HTTP_CODE)) /*203 is "success, but no output"..*/ ) {
        throw new Exception('Curl returned nothing for ' . var_export($url, true) . ' but HTTP_RESPONSE_CODE was ' . var_export($tmpvar, true));
    }
    ;
    //remember that curl (usually) auto-follows the "Location: " http redirects..
    $hhb_curl_domainCache = parse_url(curl_getinfo($ch, CURLINFO_EFFECTIVE_URL), PHP_URL_HOST);
    return $html;
}

1

La réponse acceptée semble rechercher dans tout le message de réponse. Cela pourrait vous donner de fausses correspondances pour les en-têtes de cookies si le mot "Set-Cookie" est au début d'une ligne. Bien que cela devrait être bien dans la plupart des cas. Le moyen le plus sûr pourrait être de lire le message du début jusqu'à la première ligne vide qui indique la fin des en-têtes de message. Ceci est juste une solution alternative qui devrait rechercher la première ligne vide et ensuite utiliser preg_grep sur ces lignes uniquement pour trouver "Set-Cookie".

    curl_setopt($ch, CURLOPT_HEADER, 1);
    //Return everything
    $res = curl_exec($ch);
    //Split into lines
    $lines = explode("\n", $res);
    $headers = array();
    $body = "";
    foreach($lines as $num => $line){
        $l = str_replace("\r", "", $line);
        //Empty line indicates the start of the message body and end of headers
        if(trim($l) == ""){
            $headers = array_slice($lines, 0, $num);
            $body = $lines[$num + 1];
            //Pull only cookies out of the headers
            $cookies = preg_grep('/^Set-Cookie:/', $headers);
            break;
        }
    }

1
La réponse acceptée semble rechercher dans tout le message de réponse. Cela pourrait vous donner de fausses correspondances pour les en-têtes de cookies si le mot "Set-Cookie" est au début d'une ligne. Bien que cela devrait être bien dans la plupart des cas. La manière la plus sûre pourrait être de lire le message du début jusqu'à la première ligne vide qui indique la fin des en-têtes de message. Ceci est juste une solution alternative qui devrait rechercher la première ligne vide et ensuite utiliser preg_grep sur ces lignes uniquement pour trouver "Set-Cookie".
Rich Wandell

0

Je crois comprendre que les cookies de curldoivent être écrits dans un fichier ( curl -c cookie_file). Si vous utilisez curlPHP execou des systemfonctions (ou tout autre élément de cette famille), vous devriez pouvoir enregistrer les cookies dans un fichier, puis ouvrir le fichier et les lire.


4
Il fait presque certainement référence à php.net/curl :)
TML
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.