Sessione di CodeIgniter che si occupa di chiamate ajax

La mia app CodeIgniter utilizza la libreria di sessione e salva i dati nel DB.

Ho avuto alcuni problemi in cui vengono create sessioni vuote dopo una determinata chiamata Ajax.

A seguito di indagini, sembra che siano state triggerste 2 chiamate simultanee che richiedono una convalida della sessione. Uno fallirebbe e l’altro andrebbe bene.

Sono stato in grado di risolvere il problema non facendoli esplodere simultaneamente. Ma ancora non capisco la ragione per cui fallisce. Ha a che fare con una chiamata che aggiorna il cookie dell’utente e la seconda chiamata invalidante? O forse quando legge il DB muore in qualche modo?

Ho esaminato un po ‘la core class Session e non ho trovato alcun indizio per la causa.

Se qualcuno ha avuto lo stesso problema prima vorrei apprezzare qualsiasi consiglio su come eseguire il debug o quale sia la causa.

Grazie!

MODIFICARE:

Originariamente ho detto che c’era un ritorno di stato 408. Quello era un caso non correlato.

Questa è la funzione che spara MyVar.refresh () in parallelo:

function (event) { var self$ = this.a$; var uid = this.b$.val(); var tid = this.c$.val(); var jqxhr = $.post('/controller1/index',{'uid':uid,'tid':tid,'action':true},function(re) { if(re.message != 'success') { MyVar.alert('' + re.error); MyVar.refresh(); } },'json'); MyVar.refresh(); return stopDefault(event); }; 

POSSIBILI SOLUZIONI:

Trovato questo: http://codeigniter.com/forums/viewthread/102456/

Apparentemente non gioca bene con Ajax. Una soluzione è disabilitare l’aggiornamento della sessione se si tratta di una chiamata Ajax; l’unico problema è che il nostro sito è in gran parte realizzato con ajax ..

Inoltre, ho appena abbassato il sess_time_to_update a qualcosa di molto frequente e Ajax stava andando bene. Inoltre ha fatto un aggiornamento del browser e non ha scaduto. Non sono sicuro del motivo per cui se l’ID di sessione è già cambiato in una chiamata ajax e i cookie del browser non sono mai stati aggiornati.

Prova questo

 input->is_ajax_request()) { parent::sess_update(); } } } // ------------------------------------------------------------------------ /* End of file MY_Session.php */ /* Location: ./application/libraries/MY_Session.php */ 

Il problema è nella funzione sess_update della sessione session, che genera un nuovo session_id dopo X secondi. Ogni pagina ha un session_id, se session_id scade prima della chiamata ajax, quella chiamata fallirà.

Crea un file php in / application / libraries / con il nome MY_Session (o qualunque prefisso tu abbia impostato), incolla questo codice lì e questo è tutto. Questa funzione sovrascrive la funzione sess_update nella class session, controllando ogni richiesta se tale richiesta è stata fatta da ajax, saltando la funzione sess_update.

È una ctriggers idea impostare la sess_expiration a valori più alti. Questa è una funzione di sicurezza che ti proteggerà da hijaking di sessione

PD: non sono molto fluente in inglese, se non capisci qualcosa fammelo sapere.

Finché non viene unito al ramo stabile, la soluzione (finalmente!) È quella di utilizzare il commit 245bef5 di Areson combinato con lo schema del database:

 CREATE TABLE IF NOT EXISTS `ci_sessions` ( session_id varchar(40) DEFAULT '0' NOT NULL, ip_address varchar(45) DEFAULT '0' NOT NULL, user_agent varchar(120) NOT NULL, last_activity int(10) unsigned DEFAULT 0 NOT NULL, user_data text NOT NULL, prevent_update int(10) DEFAULT NULL, PRIMARY KEY (session_id), KEY `last_activity_idx` (`last_activity`) ); 

Per ulteriori informazioni, leggi pull 1283 commenti dall’alto al basso.

Abbiamo avuto questo problema, era dovuto al parametro sess_time_to_update in config.php. CI usa questo per aggiornare l’ID di sessione a uno nuovo. Se il cambiamento avviene in una chiamata Ajax, CI invia un nuovo cookie per comunicare al browser il nuovo ID di sessione. Sfortunatamente, i browser sembrano ignorare questo cookie e mantenere il vecchio ID di sessione.

L’abbiamo risolto impostando il tempo sess_time_to_update su sess_expiration nella configurazione.

 $config['sess_time_to_update'] = $config['sess_expiration']; 

Ho avuto questo problema anche in codeigner versione 2.1.3, quando uso la seguente configurazione:

 $config['sess_use_database'] = TRUE; $config['sess_time_to_update'] = 300; 

Penso che non abbia nulla a che fare con le richieste di Ajax, ma piuttosto con un bug nel codeigniter.

Sembra che quando si memorizza la sessione nel database un logout viene forzato dopo 300 secondi. Dopo 3 ore di ricerca e analisi ho trovato un bug chiaro nel codice e uno non chiaro, ho risolto il bug come segue:

Crea un nuovo file: MY_Session.php nella cartella applicazioni / librerie

Aggiungi il seguente codice ad esso:

 userdata['last_activity'] + $this->sess_time_to_update) >= $this->now) { return; } // Save the old session id so we know which record to // update in the database if we need it $old_sessid = $this->userdata['session_id']; $new_sessid = ''; while (strlen($new_sessid) < 32) { $new_sessid .= mt_rand(0, mt_getrandmax()); } // To make the session ID even more secure we'll combine it with the user's IP $new_sessid .= $this->CI->input->ip_address(); // Turn it into a hash $new_sessid = md5(uniqid($new_sessid, TRUE)); // Update the session data in the session data array $this->userdata['session_id'] = $new_sessid; $this->userdata['last_activity'] = $this->now; // _set_cookie() will handle this for us if we aren't using database sessions // by pushing all userdata to the cookie. $cookie_data = NULL; // Update the session ID and last_activity field in the DB if needed if ($this->sess_use_database === TRUE) { // set cookie explicitly to only have our session data $cookie_data = array(); foreach (array('session_id','ip_address','user_agent','last_activity') as $val) { $cookie_data[$val] = $this->userdata[$val]; } $cookie_data['session_id'] = $new_sessid; // added to solve bug //added to solve bug if (!empty($this->userdata['user_data'])) $cookie_data['user_data'] = $this->userdata['user_data']; $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid))); } // Write the cookie $this->_set_cookie($cookie_data); } /** * Write the session cookie * * @access public * @return void */ public function _set_cookie($cookie_data = NULL) { if (is_null($cookie_data)) { $cookie_data = $this->userdata; } // Serialize the userdata for the cookie $cookie_data = $this->_serialize($cookie_data); if ($this->sess_encrypt_cookie == TRUE) { $cookie_data = $this->CI->encrypt->encode($cookie_data); } else { // if encryption is not used, we provide an md5 hash to prevent userside tampering $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key); } $_COOKIE[ $this->sess_cookie_name ] = $cookie_data; // added to solve bug $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time(); // Set the cookie setcookie( $this->sess_cookie_name, $cookie_data, $expire, $this->cookie_path, $this->cookie_domain, $this->cookie_secure ); } } ?> 

Il chiaro bug è che non ha memorizzato il ‘user_data’ nel cookie aggiornato. Il bug non chiaro è che esegue la funzione sess_read () nel file Session.php dopo aver aggiornato il nuovo id di sessione, non so perché questo accade, perché mi aspettavo che venisse eseguito prima dell’aggiornamento e non dopo come è scritto nel costruttore di Session.php. Quindi la funzione sess_read () inizia a leggere le vecchie informazioni sui cookie con il vecchio ID di sessione e vuole confrontarle con l’ID di sessione nel database, ma dopo l’aggiornamento session_id non è più presente nel database, quindi questo causa il logout.

Questa riga di codice nella funzione sess_read del file Session.php è responsabile della lettura delle informazioni del vecchio cookie:

 $session = $this->CI->input->cookie($this->sess_cookie_name); 

Quindi nella funzione _set_cookie di MY_Session.php ho aggiunto questa riga di codice per aggiornare le vecchie informazioni sui cookie del server con quella nuova:

 $_COOKIE[ $this->sess_cookie_name ] = $cookie_data; // added to solve bug 

Con questa correzione il ‘sess_time_to_update’ in combinazione con ‘sess_use_database’ dovrebbe funzionare bene. Questa è una correzione rapida e semplice.

Ho avuto lo stesso identico problema durante il caricamento delle immagini con ajax e ho impostato sess_expiration in config su:

 $config['sess_expiration'] = time()+10000000; 

E ha risolto il mio problema.

bene le buone soluzioni sono qui. fai qualsiasi cosa con sess_time_to_update etc prova le soluzioni qui sotto

  1. https://degreesofzero.com/article/fixing-the-expiring-session-problem-in-codeigniter.html
  2. http://ellislab.com/forums/viewthread/138823/#725078

al numero di soluzione “1.” aggiorno un piccolo script in più. dopo aver faticato parecchio con l’IC, ho i punti che ci sono due ragioni per la perdita delle SESSIONI CI. uno è quando vengono effettuate cattive chiamate ajax, la sessione viene AGGIORNATA e le sessioni vengono perse; il secondo è dopo una ctriggers chiamata ajax che effettua la funzione sess_destroy nella libreria SESSION di CI. COSÌ HO FATTO UN PICCOLO CAMBIAMENTO PER “1.” SOLUZIONE CHE È

 /*add this code to MY_Session.php*/ function sess_destroy() { // Do NOT update an existing session on AJAX calls. if (!$this->CI->input->is_ajax_request()) { return parent::sess_destroy(); } /* WHEN USER HIS/HER SELF DO A LOGOUT AND ALSO IF PROGRAMMER SET TO LOGOUT USING AJAX CALLS*/ $firsturlseg = $this->CI->security->xss_clean( $this->CI->uri->segment(1) ); $securlseg = $this->CI->security->xss_clean( $this->CI->uri->segment(2) ); if((string)$firsturlseg==(string)'put ur controller name which u are using for login' && (string)$securlseg==(string)'put url controler function for logout') { return parent::sess_destroy(); } } 

Spero che ti aiuti anche le persone

Sembra esserci un difetto nella sessione di gestione delle sessioni della sessione CI centrale.

Trovato una libreria di sessione alternativa che funziona come un fascino.

Libreria di sessione alternativa CI

Raccomanderei di estendere la class CI_Session principale piuttosto che sostituirla.

Per estendere, creare un file MY_Session.php in application/libraries . Incollare il contenuto della libreria alternativa, sostituire la class CI_Session alla class MY_Session extends CI_Session .

Rimuovi protetto da _flashdata_mark() , _flashdata_sweep() , _get_time() , _set_cookie() , _serialize() , _unserialize() , _sess_gc() funzioni.

Spero che sia d’aiuto.

Sembra che ci siano ancora molte vecchie versioni di CI in uso e volevo aggiungere i miei due centesimi, anche se questo thread è vecchio. Ho appena trascorso alcuni giorni a risolvere il problema delle chiamate AJAX in Code Igniter e ho una soluzione che copre i problemi principali, sebbene alcune delle soluzioni non siano “meravigliose”. La versione CI che sto usando (ancora) è 2.1.3

La mia applicazione richiede che le chiamate AJAX aggiornino il campo last_activity per mantenere una sessione valida, quindi non è sufficiente per me abbandonare semplicemente l’aggiornamento della sessione sulle chiamate AJAX.

Il controllo degli errori per sess_update e sess_read è inadeguato in questa versione di CI (non ho esaminato le versioni più recenti) e molti dei problemi iniziano da lì.

Prima parte: sess_update()

Più chiamate AJAX creano condizioni di gara che determinano il blocco del database per le chiamate successive. Se proviamo a eseguire una query di aggiornamento ma il database è bloccato, otteniamo un errore, la query restituisce false, ma il cookie è ancora aggiornato con nuovi dati? … BAD! Inoltre, non abbiamo bisogno di un nuovo session_id per ogni chiamata Ajax. Abbiamo solo bisogno di aggiornare last_activity. Prova questo:

  function sess_update() { // We only update the session every five minutes by default if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now) { return; } // Save the old session id so we know which record to // update in the database if we need it $old_sessid = $this->userdata['session_id']; //Assume this is an AJAX call... keep the same session_id $new_sessid = $old_sessid; if( !$this->CI->input->is_ajax_request() ){ //Then create a new session id while (strlen($new_sessid) < 32) { $new_sessid .= mt_rand(0, mt_getrandmax()); } // To make the session ID even more secure we'll combine it with the user's IP $new_sessid .= $this->CI->input->ip_address(); // Turn it into a hash $new_sessid = md5(uniqid($new_sessid, TRUE)); } // _set_cookie() will handle this for us if we aren't using database sessions // by pushing all userdata to the cookie. $cookie_data = NULL; // Update the session ID and last_activity field in the DB if needed if ($this->sess_use_database === TRUE) { //TRY THE QUERY FIRST! //Multiple simultaneous AJAX calls will not be able to update because the Database will be locked. ( Race Conditions ) //Besides... We don't want to update the cookie if the database didn't update $query = $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid))); if( $query ){ // Update the session data in the session data array $this->userdata['session_id'] = $new_sessid; $this->userdata['last_activity'] = $this->now; // set cookie explicitly to only have our session data $cookie_data = array(); foreach (array('session_id','ip_address','user_agent','last_activity') as $val) { $cookie_data[$val] = $this->userdata[$val]; } // Write the cookie $this->_set_cookie($cookie_data); }else{ //do nothing... we don't care, we still have an active retreivable session and the update didn't work //debug: error_log( "ERROR::" . $this->CI->db->_error_message() ); //Shows locked session database } }else{ // Update the session data in the session data array $this->userdata['session_id'] = $new_sessid; $this->userdata['last_activity'] = $this->now; // Write the cookie $this->_set_cookie($cookie_data); } } 

parte 2: sess_read()

Problema molto simile qui … Il database a volte è bloccato durante una query. Tranne che non possiamo ignorare gli errori questa volta. Stiamo provando a leggere la sessione per vedere se esiste … quindi se otteniamo un errore del database bloccato, possiamo controllare l’errore e riprovare (un paio di volte se necessario). Nei miei test non l’ho mai fatto più di 2 tentativi). Inoltre, non so voi, ma non voglio che PHP fallisca in un errore fatale non controllando il risultato di una query falsa. Avrai bisogno di questo nella parte superiore del file session.php se vuoi provare questo codice direttamente:

var $sess_query_attempts = 5;

Inoltre, questa non è l’intera funzione sess_read

 $query = $this->CI->db->get($this->sess_table_name); //Multiple AJAX calls checking //But adding add a loop to check a couple more times has stopped premature session breaking $counter = 0; while( !$query && $counter < $this->sess_query_attempts ){ usleep(100000);//wait a tenth of a second $this->CI->db->where('session_id', $session['session_id']); if ($this->sess_match_ip == TRUE) { $this->CI->db->where('ip_address', $session['ip_address']); } if ($this->sess_match_useragent == TRUE) { $this->CI->db->where('user_agent', $session['user_agent']); } $query = $this->CI->db->get($this->sess_table_name); $counter++; } if ( !$query || $query->num_rows() == 0) { $this->CI->db->where('session_id', $session['session_id']); $query = $this->CI->db->get( $this->sess_table_name ); $this->sess_destroy(); return FALSE; } 

Ad ogni modo, non c’è una risposta completa a questo problema e ho sentito di dover condividere le mie scoperte con coloro che potrebbero ancora sperimentare timeout di sessioni iniziali su siti che usano tonnellate di AJAX come le mie.

scrivi session_start() in tutto il tuo costruttore di controller