2009-05-21 11 views
103

Quindi qualcuno in un'altra azienda ha pensato che sarebbe stato grandioso se invece di usare soap o xml-rpc o resto o qualsiasi altro ragionevole protocollo di comunicazione avesse appena incorporato tutti i suoi risposta come cookie nell'intestazione.come ottenere i cookie da un curl di php in una variabile

Ho bisogno di estrarre questi cookie come auspicabilmente un array da questa risposta di arricciatura. Se dovessi sprecare un po 'della mia vita scrivendo un parser per questo, sarò molto infelice.

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

Sarò molto grato se qualcuno mi può aiutare con questo.

risposta

138
$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); 
+24

Purtroppo ho la sensazione che questa sia la risposta giusta. Penso che sia ridicolo che il ricciolo non mi dia solo un array mappato. – thirsty93

+3

Te lo darò ma il preg_match era sbagliato. Non volevo solo la sessione, capisco perché lo pensereste. Ma il genio che ha fatto il loro sistema sta caricando il cookie con un'intera mappa di risposta come con un get o post. Cazzo del genere: Set-Cookie: prezzo = 1 Set-Cookie: stato = accetta Avevo bisogno di un preg_match_all con '/^Set-Cookie: (. *?) = (. *?) $/Sm' – thirsty93

+0

Non abbastanza vicino per accettare, allora? – TML

9

Se si utilizza CURLOPT_COOKIE_FILE e CURLOPT_COOKIE_JAR curl legge/scrive i cookie da/a un file. Puoi, dopo che l'arricciatura è finita, leggere e/o modificarlo come vuoi.

+9

Credo che l'obiettivo non è quello di utilizzare questo file –

0

La mia comprensione è che i cookie da curl devono essere scritti su un file (curl -c cookie_file). Se stai usando curl attraverso exec o system funzioni di PHP (o qualcosa in quella famiglia), si dovrebbe essere in grado di salvare i cookie in un file, quindi aprire il file e leggerli in.

+4

Si riferisce quasi certamente a php.net/curl :) – TML

3

libcurl anche fornisce CURLOPT_COOKIELIST che estrae tutti i cookie noti. Tutto ciò che serve è assicurarsi che il binding PHP/CURL possa usarlo.

+11

Non è utilizzabile tramite API PHP. –

11

Questo lo fa senza regexps, ma richiede il PECL HTTP extension.

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); 
+1

Grazie per questo. Una soluzione semantica chiara vale la pena di installare un'estensione. – Benmj

+0

Questa sarebbe la soluzione migliore, se solo 'pecl install' funzionasse effettivamente. Grrr. –

27

Anche se questa domanda è molto vecchio, e la risposta accettata è valida, lo trovo un po 'scomodo perché il contenuto della risposta HTTP (HTML, XML, JSON, binario o qualsiasi altra cosa) si mescola con le intestazioni .

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

è possibile utilizzare 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 ha l'inconveniente di utilizzare una variabile globale, ma credo che questo non è un problema per gli script brevi. E puoi sempre usare metodi e attributi statici se il ricciolo viene inserito in una classe.

+4

Invece di un globale, è possibile utilizzare una chiusura con un riferimento a '$ cookie'. '$ curlResponseHeaderCallback = function ($ ch, $ headerLine) usa (& $ cookies) {' quindi 'curl_setopt ($ ch, CURLOPT_HEADERFUNCTION, $ curlResponseHeaderCallback);'. – Seph

1

qualcuno qui potrebbe trovare utile. hhb_curl_exec2 funziona come curl_exec, ma arg3 è un array che verrà popolato con le intestazioni HTTP restituite (indice numerico) e arg4 è un array che verrà popolato con i cookie restituiti ($ cookies ["expires"] => " Ven, 06-May-2016 05:58:51 GMT "), e arg5 verrà popolato con ... informazioni sulla richiesta grezza fatta da curl.

il rovescio della medaglia è che richiede CURLOPT_RETURNTRANSFER di essere su, altrimenti errore fuori, e che sovrascriverà CURLOPT_STDERR e CURLOPT_VERBOSE, se si sta già li utilizza per qualcos'altro ..(Potrei risolvere questo problema in seguito)

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
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; 
     } 
    } 
+0

meglio condividere alcune spiegazioni del codice – Mostafiz

+1

La risposta accettata sembra che cercherà attraverso l'intero messaggio di risposta. Questo potrebbe darti false corrispondenze per le intestazioni dei cookie se la parola "Set-Cookie" è all'inizio di una riga. Mentre dovrebbe andare bene nella maggior parte dei casi. Il modo più sicuro potrebbe essere quello di leggere il messaggio dall'inizio fino alla prima riga vuota che indica la fine delle intestazioni dei messaggi.Questa è solo una soluzione alternativa che dovrebbe cercare la prima riga vuota e quindi usare preg_grep su quelle linee solo per trovare "Set-Cookie". –

Problemi correlati