Archive for the ‘session.save_handler’ tag
Speichern der Session-Daten im Memcached
Normalerweise speichert PHP die Session-Daten lokal auf der Festplatte, und zwar im Verzeichnis das in der php.ini unter session.save_path eingetragen ist (z.B. /tmp unter Linux). Das sollte man jedoch dringend anpassen wenn man mehrere Applikationen auf einem Webserver laufen hat, da sonst alle Applikationen dort ihre Session-Daten im selben Verzeichnis ablegen. Wer sich in Applikation 1 einloggt ist auch direkt in Applikation 2 eingeloggt (natürlich nur wenn beide Applikationen ähnliche Daten in der Session speichern, zum Beispiel die UserId).
Also sollte man für jede Applikation einen eigenen Pfad angeben, um die Daten zu trennen. Das macht man normalerweise mit
ini_set('session.save_path', '/application1/sessiondata/);
Der Webserver muß dort selbstverständlich Lese- und Schreibrechte besitzen.
Doch das lokale Speichern auf der Festplatte hat auch Nachteile. Einerseits ist die Geschwindigkeit nicht so berauschend, andererseits möchte man eventuell einen zentralen Speicher nutzen falls man mehrere Webserver hinter einem einfachen Loadbalancer hat, der die einzelnen Requests jeweils auf einen zufälligen Webserver verteilt.
Spätestens dann benötigt man einen zentralen Session-Speicher. Im Zend Framework gibt es bereits eine Lösung mit Hilfe einer Datenbank. Ich möchte hier die Memcached-Lösung vorstellen in Verbindung mit Zend_Session. Ganz ähnlich funktioniert auch die native Lösung mit Hilfe der session_set_save_handler() Funktion.
Wir benötigen zuerst eine Klasse, die einige wichtige Funktionen zur Verfügung stellt:
<?php class App_Session_SaveHandler_Memcached implements Zend_Session_SaveHandler_Interface { /** * @var int */ private $_maxlifetime = 3600; /** * @var Zend_Cache_Core */ private $_cache; public function __construct(Zend_Cache_Core $cacheHandler) { $this->_cache = $cacheHandler; } public function open($save_path, $name) { return true; } public function close() { return true; } public function read($id) { if (!($data = $this->_cache->load('SessionData_'.$id))) { return ''; } else { return $data; } } public function write($id, $sessionData) { $this->_cache->save($sessionData, 'SessionData_'.$id, array(), $this->_maxlifetime); return true; } public function destroy($id) { $this->_cache->remove('SessionData_'.$id); return true; } public function gc($notusedformemcache) { return true; } }
Nun können wir diese Klasse als SaveHandler nutzen:
$cache = Zend_Cache::factory( 'Core', $backend, $frontendOptions, $backendOptions ); Zend_Session::setSaveHandler(new App_Session_SaveHandler_Memcached($cache)); Zend_Session::setOptions( array( //'cookie_secure' => true, // only for https 'name' => 'AppName1', 'cookie_httponly' => true, //'gc_maxlifetime' => 60*60, )); Zend_Session::start();
Nun werden die Session-Daten nicht mehr auf der Festplatte gespeichert, sondern im zentralen Memcached abgelegt. Falls die PHP-Session-Funktionen genutzt werden statt Zend_Session, ist die Lösung fast genauso einfach und die App_Session_SaveHandler_Memcached Klasse mit ein paar Anpassungen nutzbar.
EDIT: Statt dieses in PHP geschriebenen Save-Handlers kann man auch direkt den Handler auf „memcache“ setzen und den Server mittels „save_path“ definieren. Funktioniert genauso, es hat nur den einzigen Nachteil dass man den Key nicht frei wählen kann. Mehrere Memcached-Server kann man einfach kommasepariert auflisten:
Zend_Session::setOptions( array( 'name' => 'App1', 'save_handler' => 'memcache', 'save_path' => 'tcp://'.$this->_applicationIni->cache->memcached->ip.':' . $this->_applicationIni->cache->memcached->port. '?persistent=1&weight=1&timeout=1&retry_interval=15', 'cookie_httponly'=> true, 'gc_maxlifetime'=> 60*60, ) ); Zend_Session::start();
Falls die Fehlermeldung „Cannot find save handler ‚memcache'“ kommt mußt man die memcache-Extension neu kompilieren, dann mit Session-Handler-Support:
pecl uninstall memcache pecl install memcache Enable memcache session handler support? [yes] : yes
Danke an Ulf für den Druck, dass ich das auch mal ausprobiere 😉