Zend_Session: Session ID in URL übergeben

Vor kurzem stand ich vor dem Problem, die Session ID in meiner Zend Framework-Anwendung nicht wie üblich in einem Cookie zu speichern, sondern sie sollte immer an die URL drangehängt werden. Aber natürlich ohne hässliches Fragezeichen (z.B. ?PHPSESSID=joegulp976uvrevvbdkleksme3). Da dies gar nicht so leicht war, schreibe ich hier einfach mal eine Schritt-für-Schritt-Anleitung. Vorausgesetzt wird eine richtige ZF-Anwendung mit Bootstrap-Klasse und der Verwendung der Resource-Komponenten.

Wofür braucht man so eine Funktion?
Sinnvoll ist das natürlich nur für geschlossene Bereiche wie beispielsweise Administrationsoberflächen oder bei Webseiten mit stark individualisierten Content (Browsergames).
Der große Vorteil dieser Methode besteht vor allem darin, dass mehrere verschiedene Sessions für eine Anwendung im selben Browser geöffnet werden können. Bei Cookies ist dies nicht möglich.

Schritt 1: Konfig-Datei (ini)

Als erstes muss die Session-Komponente in der ini-Datei konfiguriert werden:

; Controller-Plugin registrieren (dazu mehr in Schritt 4)
resources.frontController.plugins.Dispatch = "ControllerDispatchPlugin"
 
; Cookies deaktivieren
resources.session.use_cookies = Off 
resources.session.use_only_cookies = Off
 
; Der Name kann nach belieben geändert werden
resources.session.name = "sid"
 
; Gültigkeitsdauer der Session in Sekunden
resources.session.gc_maxlifetime = 28800
 
; Die Session wird in der Datenbank abgelegt
resources.session.saveHandler.class = Zend_Session_SaveHandler_DbTable
; Name der Tabelle
resources.session.saveHandler.options.name = session
; Feldernamen der Tabelle
resources.session.saveHandler.options.primary = session_id
resources.session.saveHandler.options.modifiedColumn = modified
resources.session.saveHandler.options.dataColumn = data
resources.session.saveHandler.options.lifetimeColumn = life_time

Schritt 2: Datenbanktabelle anlegen

SQL-Skript ausführen…

DROP TABLE IF EXISTS `session`;
CREATE TABLE IF NOT EXISTS `session` (
  `session_id` varchar(64) NOT NULL,
  `modified` int(10) unsigned default NULL,
  `data` text,
  `life_time` int(10) unsigned default NULL,
  PRIMARY KEY  (`session_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Schritt 3: Router konfigurieren

Jetzt wird es langsam komplizierter, der Router muss umgestellt werden. Dazu muss der Bootstrap-Klasse eine neue Methode hinzugefügt werden:

	protected function _initRouter()
	{
		$front = $this->getResource('frontController');
		$front->getRouter()->addRoute('intern', new Zend_Controller_Router_Route('intern/:sid/:controller/:action/*', array(
			'module'	=> 'intern',
			'controller'=> 'index',
			'action'	=> 'index',
			'sid'		=> false
		)));
		return $this;
	}

Hier legen wir eine neue Route fest, die unsere Session-ID auslesen kann.
Sollte es beim Ausführen zu einem Fehler kommen, dann kann es daran liegen, dass der Front-Controller noch nicht initialisiert wurde. Am besten im Konstruktor der Bootstrap-Klasse eine Reihenfolge für die Komponenten festlegen. Hier mal ein Beispiel:

	public function __construct($application)
	{
		parent::__construct($application);
 
		$this->bootstrap('frontController'); // Erst der Front-Controller
		$this->bootstrap('router'); // Dann der Router
 
		// Und die restlichen Komponenten... Je nachdem was ihr braucht
		$this->bootstrap('db');
		$this->bootstrap('locale');
		$this->bootstrap('translate');
		$this->bootstrap('session');
		$this->bootstrap('view');
	}

Schritt 4: Controller-Plugin

Kommen wir nun zum magischen Teil der Programmierung – dem alles entscheidenden Controller-Plugin.

require_once 'Zend/Controller/Plugin/Abstract.php';
 
class ControllerDispatchPlugin extends Zend_Controller_Plugin_Abstract
{
	public function preDispatch(Zend_Controller_Request_Abstract $request)
	{
		if($request->getModuleName() == 'intern')
		{
			Zend_Session::setId($request->getParam('sid'));
			Zend_Registry::set('session', new Zend_Session_Namespace());
			$session = Zend_Registry::get('session');
			// Session überprüfen?!
		}
		return $this;
	}
}

Das Controller-Plugin macht eigentlich nichts anderes, als vor dem Ausführen des Action-Controllers den GET-Parameter sid auszulesen und damit eine Session aufzurufen. Die Session wird allerdings nur dann aufgerufen, wenn wir uns im Modul intern befinden.

Schritt 5: Authentifizierung

Bevor wir die Session abfragen können, muss sie allerdings erst einmal gestartet werden. Dazu verwenden wir natürlich die Zend_Auth-Komponente, die wir über eine normale Action ausführen (z.B. im IndexController):

	public function authAction()
	{
		if($this->getRequest()->isPost())
		{
			$username = $this->_getParam('username');
			$password = $this->_getParam('password');
			if(!empty($username))
			{
				// Wir melden uns über eine Datenbank-Tabelle "user" an mit den Felder
				// username und password. Das Passwort wird mit MD5 verschlüsselt.
				$authAdapter = new Zend_Auth_Adapter_DbTable(Zend_Db_Table::getDefaultAdapter(), 'user', 'username', 'password', 'MD5(?)');
				$authAdapter->setIdentity($username)
					->setCredential($password);
 
				// Authentifizierung durchführen und überprüfen
				$result = $authAdapter->authenticate();
				if($result->isValid())
				{
					// Die Login-Daten sind gültig, wir legen ein Session-Namespace an,
					// das die Benutzerdaten beinhalten soll
					$sessionSpace = new Zend_Session_Namespace('User');
 
					// Die Benutzerdaten holen wir uns aus dem 
					$sessionSpace->data = $authAdapter->getResultRowObject();
 
					// Session starten
					Zend_Session::start($sessionSpace);
 
					// Jetzt leiten wir den Benutzer weiter in den internen Bereich
					$this->_redirect('intern/'.Zend_Session::getId().'/index/index');
				}
				// Fehler verarbeiten...
				$errors = $result->getMessages();
			}
		}
		// Hier folgt die Ausgabe des Login-Formulars
		return $this;
	}

Sobald die Session mit Zend_Session::start($sessionSpace); gestartet wurde, werden die Benutzerdaten + SessionID in die Datenbank-Tabelle session abgelegt – so wie wir es in der Konfigurationsdatei angegeben haben.

So, das waren jetzt vorerst genug Artikel über das Zend Framework für die nächste Zeit.
Wer noch Fragen zu dem Session-Thema hat, kann einfach einen Kommentar hinterlassen oder mir eine Mail schreiben (steht im Impressum).

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.