Condividere la sessione

Ciao a tutti, sono appena entrato nel mondo di Yii e mi ritrovo gia’ a chiedervi aiuto, arrivo da cakephp, quindi qualche base dovrei gia’ averla :P

come molte persone prima di me sto cercando di implementare un’applicazione Yii con un forum phpBB3, l’interazione e’ a livello di condivisione user/password e sessione in modo da poter fare login e logout da entrambe le piattaforme.

Ho letto di molta gente che e’ riuscita nell’impresa ma ho trovato davvero poca documentazione su come ci sono riuscite e mi ritrovo costretto a chiedervi aiuto.

Quello che vorrei fare e’ mantenere le tabelle di user e password del forum, fin qui tutto bene, riesco a fare il login da Yii utilizzando le credenziali del forum ma ora il secondo step mi frena.

Il passo successivo prevede l’integrazione delle sessioni, phpBB3 immagazzina gli ID delle sessioni nella tabella phpbb_sessions, anche questa facilmente leggibile da Yii, quello che dovrei fare e’ fare in modo che la mia applicazione utilizzi le informazioni immagazzinate in quella tabella ma qui mi sono fermato… Non riesco nemmeno a cambiare il nome del cookie generato da Yii :unsure:

C’e’ qualche anima pia che potrebbe gentilmente guidarmi nella risoluzione di questo problema?

Grazie mille,

Dado.

Ho studiato un po’ di materiale, da quello che ho capito devo sfruttare CDbHttpSession solo che utilizza tabelle e variabili proprietari di Yii.

Ho quindi creato un componente con una copia di CDbHttpSession ma con le funzioni modificate in modo da utilizzare i dati della tabella preesistente di phpBB3.

Il problema ora e’ che non sono molto ferrato su come poter utilizzare correttamente le sessioni in Yii, l’apertura, la chiusura e il controllo vanno fatti nella funzione authenticate() di UserIdentity oppure nella funzione login() di LoginForm?

A naso direi di mettere tutto in authenticate()… B)

La prossima domanda e’: come faccio a sovrascrivere le funzioni di Yii con le mie senza modificare il core code?

Grazie mille,

Dado.

senza modificare nulla, puoi definire la tabella delle sessioni dentro il file di config (main.php) aggiungendo un


'sessionTableName' => 'tabellaSessioniPHPBB3',

Hai provato a creare una classe ‘MyDbHttpSession’ che estende la classe CDbHttpSession e chiamare quella nel file di configurazione? Se funziona (e dovrebbe) basta che riscrivi gli stessi metodi con le tue correzioni nella tua nuova classe.

Un pò come si fa con CWebUser per intenderci :)

Edit: qua hanno gia fatto qualcosa del genere, puoi prendere spunto :)

http://www.yiiframework.com/extension/session/

Si la tabella l’ho gia’ definita, il problema e’ che utilizzano campi diversi e devo quindi modificare le funzioni di Yii in modo da leggere i campi che utilizza phpBB3.

Grazie mille, avevo gia’ creato una nuova classe ma non sapevo come richiamarla, ora sto usando la mia e spero di poter finalmente risolvere questo problema ::)

Ho messo un po’ di ordine tra le idee, ho giocato un po’ con le funzioni integrate in Yii ma penso che non vadano bene al mio scopo, devo scrivermi qualcosa ad hoc.

Mi devo quindi focalizzare su tre diversi scenari:

[size="3"]Apertura Browser:[/size]

Prelievo l’ID della sessione dal cookie (se presente):


$id = Yii::app()->request->cookies['CookieName']->value;

Controllo se e’ presente nel database e in caso positivo rigenero l’ID

[size="3"]Login:[/size]

Apro una session:


$session=new CHttpSession;

$session->open();

Prelevo l’ID:


$session_ID = Yii::app()->session->setSessionID($_POST['sessionid']);

Scrivo nel cookie:


Yii::app()->request->cookies['CookieName'] = new CHttpCookie('CookieName', $session_ID);

$cookie = new CHttpCookie('CookieName', $session_ID);

$cookie->expire = time() + (60*60*24); // 24 hours

Yii::app()->request->cookies['name'] = $cookie;

Scrivo i dati nella tabella del forum.

[size="3"]Logout:[/size]

Prelievo l’ID della sessione dal cookie:


$id = Yii::app()->request->cookies['CookieName']->value;

Controllo se e’ presente in tabella e in caso positivo la cancello.

Elimino il cookie corrispondente:


unset(Yii::app()->request->cookies['cookie_name']);

Ho fatto qualche errore?

Grazie,

Dado.

Io fossi in te estenderei la classe CHttpSession per farle fare le cose che servono a te. Ed a questo punto la utilizzerei dirattamente nella classe UserIdentity.

Ed e’ quello che ho fatto, mi sono creato un nuovo component estendendo la classe CHttpSession.

Il mio problema e’ che non ho ancora ben capito in che modo io posso sovrascrivere le funzioni gia’ esistenti, mi sono quindi creato delle mie funzioni che fanno gli step scritti nel mio post precedente e poi le richiamo all’interno della login form.

Funziona tutto tranne se faccio il login dal forum, la sessione non viene estesa alla mia applicazione ma non e’ un problema visto che disabilitero’ il login/logout dal forum.

Il passo successivo ora sarebbe quello di creare dei ruoli (admin, registered, guest) prelevando i dati da "user_group_id". Sapreste consigliarmi qualcosa a riguardo?

Ricapitolando, per chi vuole la versione breve :P

[list=1]

[*]Come faccio a sovrascrivere le funzioni esistenti (ad esempio in CHttpSession)?

[*]Come faccio a creare dei ruoli per gli utenti avendo gia’ a disposizione un group_id?

[/list]

Alla prima mi rispondo da solo:


'components' => array(

    'session' => array(

        'class' => 'application.components.MyCHttpSession',

    ),

),

Corretto?

Pero’ questo mi sovrascrive tutte le funzioni, se io ne volessi modificare solo alcune lasciando intatte le altre devo per forza ricopiarle o esiste un modo piu elegante?

Grazie,

Dado.

Se hai un


class MyCHttpSession extend CHttpSession {

//tue variabili

//tue funzioni/metodi

}



i metodi di CHttpsession che non sovrascrivi sono utilizzabili, non capisco il problema del ricopiarli…

Esattamente. Se tu crei una classe vuota che estende da CHttpSession, vengono mantenuti tutti i metodi di CHttpSession. E’ il bello dell’ereditarietà. Se vuoi sovrascrivere un solo metodo, scrivi solo quello dentro la tua classe. Verrà richiamato il tuo e non quello della classe padre.

Ok, allora provo a estendere semplicemente la classe e a sovrascrivere le funzioni interessate, grazie per la spiegazione!

Ora vorrei capire come poter integrare un controllo dei ruoli, ho letto un po’ di wiki ma sembra ancora un po’ tutto fumoso…

La struttura e’ molto semplice, avro’ essenzialmente tre ruoli: Admin, Registered, Guest.

Quello che non mi e’ ancora molto chiaro e’ in che modo user e ruoli sono collegati, mi spiego meglio: io ho i miei user all’interno di una tabella chiamata “User” con il relativo id, username ecc…

In che modo configuro il modulo interno di Yii in modo da prelevare gli utenti da quella tabella e configurare i ruoli di conseguenza?

Grazie,

Dado.

Yii ha un suo RBAC, ovvero Role Based Access Control. Non devi implementare nulla: è già tutto compreso dentro al framework.

Ecco qui quello che ti serve: http://www.yiiframework.com/doc/guide/1.1/en/topics.auth

Possono venirti in aiuto tante estensioni. La più completa di tutte (ma anche la più complessa in fatto di feature e dimensioni…) è rights.

In alternativa, visto che hai in mente di usare 3 soli ruoli…

http://www.yiiframework.com/wiki/65/how-to-setup-rbac-with-a-php-file/

(ovviamente va letto per bene, e configurato meglio ;)

Grazie mille ragazzi!

Oggi ho provato a fare come mi avete consigliato voi, cioè a estendere la classe CDbHttpSession e sovrascrivere le funzioni quando carico il sito mi si blocca con un errore strano nella funzione:




public function readSession($id)

{

	$now=time();

	$sql="

SELECT session_data FROM {$this->sessionTableName}

WHERE session_start<$now AND session_id=:id

";

	$data=$this->getDbConnection()->createCommand($sql)->bindValue(':id',$id)->queryScalar();

	return $data===false?'':$data;

}

mi si blocca quando esegue la riga $data=… e l’errore è:


CDbCommand failed to prepare the SQL statement: SQLSTATE[HY000]: General error: 1 no such column: session_data

Ho provato a buttare fuori la variabile $sql ed è:


SELECT session_data FROM phpbb_sessions WHERE session_start<1331189894 AND session_id=:id

che eseguita come query in PhpMyAdmin non da alcun problema…

Sapete darmi qualche hint su come risolvere questo mio dilemma?

Grazie,

Dado

Un momento. Come mai non usi l’ORM di Yii e scrivi le query a mano? C’è una ragione particolare?

Quella funzione l’ho presa cosi com’e’ da CDbHttpSession, scusa l’ignoranza ma cosa intendi per ORM?

Credo che alla fine rimarro’ col mio componente, ho creato due funzioni: generateSession() e destroySession()

la prima la richiamo una volta che il login e’ avvenuto, crea i cookie con la session ID e riempie i campi in tabella di conseguenza, la seconda viene richiamata al logout e semplicemente elimina i cookie e il riferimento in tabella.

L’unica cosa che non funziona e’ che se faccio il login dal forum la sessione non viene aperta dal sito essenzialmente perche’ non so bene come e dove richiamare una funzione che controlla la sessione all’avvio, ma posso tranquillamente conviverci facendo gestire il login/logout a Yii.

Appena posso vi incollo il codice delle due funzioni cosi mi dite se ho fatto qualche errore (cosa altamente probabile :D )

Rieccomi, vi copio le funzioni:

[size="4"]generateSession($duration, $user)[/size]




public function generateSession($duration, $user)

{

	// set session variable

	$this->browser				= (!empty($_SERVER['HTTP_USER_AGENT'])) ? htmlspecialchars((string) $_SERVER['HTTP_USER_AGENT']) : '';

	$this->referer				= (!empty($_SERVER['HTTP_REFERER'])) ? htmlspecialchars((string) $_SERVER['HTTP_REFERER']) : '';

	$this->forwarded_for		= (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) ? htmlspecialchars((string) $_SERVER['HTTP_X_FORWARDED_FOR']) : '';

	$this->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? (string) $_SERVER['REMOTE_ADDR'] : '';

	$this->ip = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->ip));

	$user_id=$user->id;

	$admin=0;


	$current_user=User::model()->findByAttributes(array('user_id'=>$user_id));

	$user_group=$current_user->group_id;

	if($user_group=='5') $admin=1;

	else $admin=0;

		

	$time=time();

		

	$session_id=Yii::app()->session->getSessionID();

	Yii::app()->request->cookies[$this->cookieName] = new CHttpCookie($this->cookieName, $session_id);

	$cookie = new CHttpCookie($this->cookieName, $session_id);

	$cookie->expire = $duration;

	Yii::app()->request->cookies[$this->cookieName] = $cookie;

	Yii::app()->request->cookies[$this->cookieNameU] = new CHttpCookie($this->cookieNameU, $user_id);

		

	$expire=time()+$this->getTimeout();

	$db=Yii::app()->db;

	$sql="SELECT session_id FROM {$this->sessionTableName} WHERE session_id=:id";

	if($db->createCommand($sql)->bindValue(':id',$session_id)->queryScalar()===false)

		$sql="INSERT INTO {$this->sessionTableName} (`session_id`, `session_user_id`, `session_forum_id`, `session_last_visit`, `session_start`, `session_time`, `session_ip`, `session_browser`, `session_forwarded_for`, `session_page`, `session_viewonline`, `session_autologin`, `session_admin`) 

			VALUES (:id, '$user_id', '0', '$expire', '$time', '$time', '$this->ip', '$this->browser', '$this->forwarded_for', 'index.php', '1', '', '$admin')";

	else

		$sql="UPDATE {$this->sessionTableName} SET session_last_visit=$expire WHERE session_id=:id";

	$db->createCommand($sql)->bindValue(':id',$session_id)->execute();


	return true;

}



La richiamo dal LoginForm nella funzione login() se l’autenticazione e’ andata a buon fine:




if($this->_identity->errorCode===UserIdentity::ERROR_NONE)

{

	$duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days

	Yii::app()->user->login($this->_identity,$duration);

	$session= new phpBBSession();

	$session->generateSession($duration, $this->_identity);

	return true;

}



In fine:

[size="4"]destroySession()[/size]




public function destroySession()

{

	$session_id=Yii::app()->request->cookies[$this->cookieName]->value;

	$sql="DELETE FROM {$this->sessionTableName} WHERE session_id=:id";

	$db=Yii::app()->db;

	$db->createCommand($sql)->bindValue(':id',$session_id)->execute();

	unset(Yii::app()->request->cookies[$this->cookieName]);

	return true;

}



La richiamo all’interno del controller SiteController nella funzione actionLogout()




public function actionLogout()

{

	$session=new phpBBSession();

	$session->destroySession();

	Yii::app()->user->logout();

	$this->redirect(Yii::app()->homeUrl);

}



Eheheh Guarda qui e ti innamorerai di Yii.