come ottenere i cookie da un php curl in una variabile


126

Quindi un ragazzo di un'altra azienda ha pensato che sarebbe stato fantastico se invece di usare soap o xml-rpc o rest o qualsiasi altro protocollo di comunicazione ragionevole avesse semplicemente incorporato tutte le sue risposte come cookie nell'intestazione.

Ho bisogno di estrarre questi biscotti come si spera un array da questa risposta di ricciolo. Se dovessi sprecare un po 'della mia vita a scrivere un parser per questo, sarei molto infelice.

Qualcuno sa come questo può essere fatto semplicemente, preferibilmente senza scrivere nulla su un file?

Sarò molto grato se qualcuno mi potrà aiutare in questo.

Risposte:


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
Purtroppo ho la sensazione che questa sia la risposta giusta. Penso che sia ridicolo che il ricciolo non possa semplicemente consegnarmi un array mappato.
assetato93

3
Te lo darò ma il preg_match era sbagliato. Non volevo solo la sessione, anche se capisco perché lo pensi. Ma il genio che ha creato il loro sistema sta caricando il cookie con un'intera mappa di risposta come con un get o un post. Merda come questa: Set-Cookie: price = 1 Set-Cookie: status = accept Ho bisogno di un preg_match_all con '/ ^ Set-Cookie: (. *?) = (. *?) $ /
Sm

7
@ assetato93 Curl non può darti un array mappato. Ma ti mostra un modo per salvarlocurl_setopt($ch, CURLOPT_HEADERFUNCTION, 'callback_SaveHeaders');
Shiplu Mokaddim

2
A seconda della struttura del cookie restituita, l'ultima riga potrebbe dover essere modificata in qualcosa di simile parse_str($m[1], $cookies), che inserirà i cookie in un array associativo nella $cookiesvariabile ....
random_user_name

7
Per le correzioni combinate che afferrano più di 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

Sebbene questa domanda sia piuttosto vecchia e la risposta accettata sia valida, la trovo un po 'scomoda perché il contenuto della risposta HTTP (HTML, XML, JSON, binario o altro) si mescola con le intestazioni.

Ho trovato un'alternativa diversa. CURL fornisce un'opzione ( CURLOPT_HEADERFUNCTION) per impostare una richiamata che verrà chiamata per ciascuna riga di intestazione della risposta. La funzione riceverà l'oggetto curl e una stringa con la riga di intestazione.

Puoi usare un codice come questo (adattato dalla risposta 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
}

Questa soluzione presenta lo svantaggio di utilizzare una variabile globale, ma immagino che questo non sia un problema per gli script brevi. E puoi sempre usare metodi e attributi statici se curl viene racchiuso in una classe.


10
Invece di un globale, puoi usare una chiusura contenente un riferimento a $cookies. $curlResponseHeaderCallback = function ($ch, $headerLine) use (&$cookies) {allora curl_setopt($ch, CURLOPT_HEADERFUNCTION, $curlResponseHeaderCallback);.
Settembre

Cosa succede se hai tutto questo in una classe? Come si fa riferimento alla funzione di classe $class->curlResponseHeaderCallback()? O hai appena curlResponseHeaderCallbackfuori dalla classe?
Sevenearths

13

Questo lo fa senza regexps, ma richiede l' estensione 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
Grazie per questo. Una soluzione semantica e chiara vale la pena di installare un'estensione.
Ben Jacobs

2
Questa sarebbe la soluzione migliore, se solo pecl installfunzionasse effettivamente. Grrr.
Robin Winslow

11

Se utilizzi CURLOPT_COOKIE_FILE e CURLOPT_COOKIE_JAR, curl leggerà / scriverà i cookie da / in un file. Puoi, dopo aver finito di curl, leggerlo e / o modificarlo come preferisci.


12
Penso che l'obiettivo non sia quello di utilizzare questo file
Nicolas Thery

3

libcurl fornisce anche CURLOPT_COOKIELIST che estrae tutti i cookie conosciuti. Tutto ciò di cui hai bisogno è assicurarti che il binding PHP / CURL possa usarlo.


12
Non è utilizzabile tramite API PHP.
Emre Yazici

1

qualcuno qui potrebbe trovarlo utile. hhb_curl_exec2 funziona più o meno come curl_exec, ma arg3 è un array che verrà popolato con le intestazioni http restituite (indice numerico), e arg4 è un array che sarà popolato con i cookie restituiti ($ cookies ["expires"] => " Fri, 06-May-2016 05:58:51 GMT ") e arg5 verranno popolati con ... informazioni sulla richiesta non elaborata effettuata da curl.

lo svantaggio è che richiede che CURLOPT_RETURNTRANSFER sia attivo, altrimenti si verifica un errore e che sovrascriverà CURLOPT_STDERR e CURLOPT_VERBOSE, se li stavi già usando per qualcos'altro .. (potrei aggiustarlo più tardi)

esempio di come usarlo:

<?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);

e la funzione stessa ..

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 risposta accettata sembra che cercherà nell'intero messaggio di risposta. Ciò potrebbe fornire false corrispondenze per le intestazioni dei cookie se la parola "Set-Cookie" è all'inizio di una riga. Anche se dovrebbe andare bene nella maggior parte dei casi. Il modo più sicuro potrebbe essere leggere il messaggio dall'inizio fino alla prima riga vuota che indica la fine delle intestazioni del messaggio. Questa è solo una soluzione alternativa che dovrebbe cercare la prima riga vuota e quindi utilizzare preg_grep su quelle righe solo per trovare "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 risposta accettata sembra che cercherà nell'intero messaggio di risposta. Ciò potrebbe fornire false corrispondenze per le intestazioni dei cookie se la parola "Set-Cookie" è all'inizio di una riga. Anche se dovrebbe andare bene nella maggior parte dei casi. Il modo più sicuro potrebbe essere leggere il messaggio dall'inizio fino alla prima riga vuota che indica la fine delle intestazioni del messaggio. Questa è solo una soluzione alternativa che dovrebbe cercare la prima riga vuota e quindi utilizzare preg_grep su quelle righe solo per trovare "Set-Cookie".
Rich Wandell

0

La mia comprensione è che i cookie di curldevono essere scritti in un file ( curl -c cookie_file). Se stai eseguendo curlPHP execo systemfunzioni (o qualsiasi altra cosa in quella famiglia), dovresti essere in grado di salvare i cookie in un file, quindi aprire il file e leggerli.


4
Si riferisce quasi certamente a php.net/curl :)
TML
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.