2012-10-14 20 views
26

Ho qualche problema con PHP Curl e Cookies Authentication.PHP Curl and Cookies

Ho un file Connector.php che autentica gli utenti su un altro server e restituisce cookie con l'utente corrente.

Il problema è che voglio autenticare migliaia di utenti con il ricciolo, ma autentica e salva i COOKIES solo per un utente alla volta.

il codice per connector.php è questo:

<?php 
    if(!count($_REQUEST)) { 
     die("No Access!"); 
    } 


    //Core Url For Services 
    define ('ServiceCore', 'http://example.com/core/'); 


    //Which Internal Service Should Be Called 
    $path = $_GET['service']; 


    //Service To Be Queried 
    $url = ServiceCore.$path; 

    //Open the Curl session 
    $session = curl_init($url); 

    // If it's a GET, put the GET data in the body 
    if ($_GET['service']) { 
     //Iterate Over GET Vars 
     $postvars = ''; 
     foreach($_GET as $key=>$val) { 
      if($key!='service') { 
       $postvars.="$key=$val&"; 
      } 
     } 
     curl_setopt ($session, CURLOPT_POST, true); 
     curl_setopt ($session, CURLOPT_POSTFIELDS, $postvars); 
    } 


    //Create And Save Cookies 
    $tmpfname = dirname(__FILE__).'/cookie.txt'; 
    curl_setopt($session, CURLOPT_COOKIEJAR, $tmpfname); 
    curl_setopt($session, CURLOPT_COOKIEFILE, $tmpfname); 

    curl_setopt($session, CURLOPT_HEADER, false); 
    curl_setopt($session, CURLOPT_RETURNTRANSFER, true); 
    curl_setopt($session, CURLOPT_FOLLOWLOCATION, true); 

    // EXECUTE 
    $json = curl_exec($session); 
     echo $json; 
    curl_close($session); 
?> 

Qui è il processo di autenticazione:

  1. utente inserisce username e password:? Connector.php servizio = accesso & USER_NAME = user32 & user_pass = 123
  2. Connector.php? service = logosessionInfo questo restituisce informazioni sull'utente in base ai cookie salvati in precedenza con il servizio di accesso.

Il problema è che questo codice salva Cookie in un file per un utente e non può gestire l'autenticazione di più utenti.

+2

ho risolto il mio problema con la creazione di diversi file cookie per i diversi utenti con PHPSESSID unico. '$ tmpfname = dirname (__ FILE __). '/'. $ _ COOKIE ['PHPSESSID']. '. txt';' – Shark

+0

è una buona idea se ci sono molti utenti? – trainoasis

+0

No Se hai molti utenti questo è male. Provoca crash del server Apache. Ho risolto questo problema con il proxy apache. E rimosso tutto il mio codice CURL. – Shark

risposta

0

soluzioni che sono descritti sopra, anche con nomi CookieFile unici, può causare molti problemi su scala.

Abbiamo dovuto eseguire molte autenticazioni con questa soluzione e il nostro server è andato giù a causa di azioni di scrittura di lettura file elevate.

La soluzione per questo era utilizzare Apache Reverse Proxy e omettere le richieste CURL.

Dettagli come utilizzare proxy su Apache può essere trovato qui: https://httpd.apache.org/docs/2.4/howto/reverse_proxy.html

22

È possibile specificare il file cookie con un ricciolo opt. È possibile utilizzare un file univoco per ciascun utente.

curl_setopt($curl_handle, CURLOPT_COOKIESESSION, true); 
curl_setopt($curl_handle, CURLOPT_COOKIEJAR, uniquefilename); 
curl_setopt($curl_handle, CURLOPT_COOKIEFILE, uniquefilename); 

Il modo migliore per gestire la cosa potrebbe essere quella di attaccare la logica richiesta in una funzione curl e solo passare il nome di file univoco come parametro.

function fetch($url, $z=null) { 
      $ch = curl_init(); 

      $useragent = isset($z['useragent']) ? $z['useragent'] : 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.2) Gecko/20100101 Firefox/10.0.2'; 

      curl_setopt($ch, CURLOPT_URL, $url); 
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
      curl_setopt($ch, CURLOPT_AUTOREFERER, true); 
      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 
      curl_setopt($ch, CURLOPT_POST, isset($z['post'])); 

      if(isset($z['post']))   curl_setopt($ch, CURLOPT_POSTFIELDS, $z['post']); 
      if(isset($z['refer']))  curl_setopt($ch, CURLOPT_REFERER, $z['refer']); 

      curl_setopt($ch, CURLOPT_USERAGENT, $useragent); 
      curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, (isset($z['timeout']) ? $z['timeout'] : 5)); 
      curl_setopt($ch, CURLOPT_COOKIEJAR, $z['cookiefile']); 
      curl_setopt($ch, CURLOPT_COOKIEFILE, $z['cookiefile']); 

      $result = curl_exec($ch); 
      curl_close($ch); 
      return $result; 
    } 

Io uso questo in palio veloci. Prende l'url e una serie di opzioni.

+0

grazie, risolto il mio problema! – user3236289

1

È possibile definire i cookie diversi per ogni utente con CURLOPT_COOKIEFILE e CURLOPT_COOKIEJAR. Crea file diversi per ogni utente in modo che ognuno abbia la propria sessione basata su cookie sul server remoto.

+0

Che dire quando questa pagina viene utilizzata da molti utenti (10 mila in più)? Non è un carico enorme sul server? – trainoasis

10

Innanzitutto creare cookie temporaneo utilizzando tempnam) la funzione (:

$ckfile = tempnam ("/tmp", "CURLCOOKIE"); 

Than eseguire ricciolo biscotto init strega salva come file temporaneo:

$ch = curl_init ("http://uri.com/"); 
curl_setopt ($ch, CURLOPT_COOKIEJAR, $ckfile); 
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true); 
$output = curl_exec ($ch); 

o visitare i dati dei cookie in cui è vendite di dati temporanei :

$ch = curl_init ("http://somedomain.com/cookiepage.php"); 
curl_setopt ($ch, CURLOPT_COOKIEFILE, $ckfile); 
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true); 
$output = curl_exec ($ch); 

Questa operazione caricherà la pagina di inizializzazione del cookie:

+0

Che dire se un numero enorme di utenti tenta di accedere alla pagina in una volta e hai già alcuni file in/tmp per esempio? Documento PHP dice: Nota: se PHP non può creare un file nel parametro dir specificato, ricade nei valori predefiniti del sistema. Su NTFS questo succede anche se la directory specificata contiene più di 65534 file. – trainoasis

+0

Rimuovi i file cookie se conservati per più di 24 ore. Memorizza i dati di un cookie per $ ckfile separati per controllare tutti i file all'interno di/tmp. –

+0

Dopo 3 anni, sei ancora un salvatore di vita Marin per le persone non-PHP come me. Dopo aver esaminato un carico di risposte StackOverflow, eccone uno ben spiegato in modo ordinato. –

20

Lavorando con un problema simile ho creato la seguente funzione dopo aver combinato un sacco di risorse che ho incontrato sul web e aggiunto la mia gestione dei cookie. Spero che questo sia utile a qualcun altro.

 function get_web_page($url, $cookiesIn = ''){ 
     $options = array(
      CURLOPT_RETURNTRANSFER => true,  // return web page 
      CURLOPT_HEADER   => true,  //return headers in addition to content 
      CURLOPT_FOLLOWLOCATION => true,  // follow redirects 
      CURLOPT_ENCODING  => "",  // handle all encodings 
      CURLOPT_AUTOREFERER => true,  // set referer on redirect 
      CURLOPT_CONNECTTIMEOUT => 120,  // timeout on connect 
      CURLOPT_TIMEOUT  => 120,  // timeout on response 
      CURLOPT_MAXREDIRS  => 10,  // stop after 10 redirects 
      CURLINFO_HEADER_OUT => true, 
      CURLOPT_SSL_VERIFYPEER => true,  // Validate SSL Certificates 
      CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, 
      CURLOPT_COOKIE   => $cookiesIn 
     ); 

     $ch  = curl_init($url); 
     curl_setopt_array($ch, $options); 
     $rough_content = curl_exec($ch); 
     $err  = curl_errno($ch); 
     $errmsg = curl_error($ch); 
     $header = curl_getinfo($ch); 
     curl_close($ch); 

     $header_content = substr($rough_content, 0, $header['header_size']); 
     $body_content = trim(str_replace($header_content, '', $rough_content)); 
     $pattern = "#Set-Cookie:\\s+(?<cookie>[^=]+=[^;]+)#m"; 
     preg_match_all($pattern, $header_content, $matches); 
     $cookiesOut = implode("; ", $matches['cookie']); 

     $header['errno'] = $err; 
     $header['errmsg'] = $errmsg; 
     $header['headers'] = $header_content; 
     $header['content'] = $body_content; 
     $header['cookies'] = $cookiesOut; 
    return $header; 
} 
+0

Codice molto utile. Funziona. Grazie. Se le persone vogliono che il codice di stato HTTP usi questa sintassi: $ header ['http_code']; – jedema

+0

@Doug, ho controllato la regex '# Set-Cookie: \\ s + (? [^ =] + = [^;] +) # m' del tuo codice in [here] (https: // regex101 .com/r/dU3nD8/1) e il motore regex spiega questa parte '\\ s +' come: '\\' corrisponde al carattere \ letteralmente 's +' corrisponde letteralmente al carattere s (distinzione tra maiuscole e minuscole) - non è è un errore in questa parte della regex, non dovrebbe essere '\ s +' (solo una barra rovesciata)? –

+2

@Igor, il \\ è perché quando si ha a che fare con le stringhe in PHP [il \ è visto come un carattere di escape] (http://php.net/manual/en/language.types.string.php). Di conseguenza sono necessarie due barre per eguagliare una barra nella stringa valutata (che verrà quindi utilizzata per la corrispondenza RegEx). Sei corretto da un punto di vista RegEx Voglio solo una barra. – Doug

2

Qui potete trovare alcune informazioni utili su CURL & cookie http://docstore.mik.ua/orelly/webprog/pcook/ch11_04.htm.

È inoltre possibile utilizzare questo metodo ben fatto https://github.com/alixaxel/phunction/blob/master/phunction/Net.php#L89 come una funzione:

function CURL($url, $data = null, $method = 'GET', $cookie = null, $options = null, $retries = 3) 
{ 
    $result = false; 

    if ((extension_loaded('curl') === true) && (is_resource($curl = curl_init()) === true)) 
    { 
     curl_setopt($curl, CURLOPT_URL, $url); 
     curl_setopt($curl, CURLOPT_FAILONERROR, true); 
     curl_setopt($curl, CURLOPT_AUTOREFERER, true); 
     curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 
     curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); 
     curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); 

     if (preg_match('~^(?:DELETE|GET|HEAD|OPTIONS|POST|PUT)$~i', $method) > 0) 
     { 
      if (preg_match('~^(?:HEAD|OPTIONS)$~i', $method) > 0) 
      { 
       curl_setopt_array($curl, array(CURLOPT_HEADER => true, CURLOPT_NOBODY => true)); 
      } 

      else if (preg_match('~^(?:POST|PUT)$~i', $method) > 0) 
      { 
       if (is_array($data) === true) 
       { 
        foreach (preg_grep('~^@~', $data) as $key => $value) 
        { 
         $data[$key] = sprintf('@%s', rtrim(str_replace('\\', '/', realpath(ltrim($value, '@'))), '/') . (is_dir(ltrim($value, '@')) ? '/' : '')); 
        } 

        if (count($data) != count($data, COUNT_RECURSIVE)) 
        { 
         $data = http_build_query($data, '', '&'); 
        } 
       } 

       curl_setopt($curl, CURLOPT_POSTFIELDS, $data); 
      } 

      curl_setopt($curl, CURLOPT_CUSTOMREQUEST, strtoupper($method)); 

      if (isset($cookie) === true) 
      { 
       curl_setopt_array($curl, array_fill_keys(array(CURLOPT_COOKIEJAR, CURLOPT_COOKIEFILE), strval($cookie))); 
      } 

      if ((intval(ini_get('safe_mode')) == 0) && (ini_set('open_basedir', null) !== false)) 
      { 
       curl_setopt_array($curl, array(CURLOPT_MAXREDIRS => 5, CURLOPT_FOLLOWLOCATION => true)); 
      } 

      if (is_array($options) === true) 
      { 
       curl_setopt_array($curl, $options); 
      } 

      for ($i = 1; $i <= $retries; ++$i) 
      { 
       $result = curl_exec($curl); 

       if (($i == $retries) || ($result !== false)) 
       { 
        break; 
       } 

       usleep(pow(2, $i - 2) * 1000000); 
      } 
     } 

     curl_close($curl); 
    } 

    return $result; 
} 

E passare questo come $cookie parametro:

$cookie_jar = tempnam('/tmp','cookie');