Recipe 11.5. Storing Sessions in Shared Memory


11.5.1. Problem

You want to store session data in shared memory to maximize performance.

11.5.2. Solution

Use the pc_Shm_Session class shown in Example 11-3. For example:

<?php $s = new pc_Shm_Session(); ini_get('session.auto_start') or session_start(); ?>

11.5.3. Discussion

As discussed in Recipe 11.4, the session module allows users to define their own session handling methods. While this flexibility is most commonly used to store session data in a database, you may find that performance suffers with the overhead of the database connection and the subsequent queries. If sharing session data across a bunch of web servers is not a concern, you can boost session handling performance by storing that data in shared memory.

Before deciding to use shared memory for session storage, make sure that you can spare the amount of memory that your traffic plus your average session data size will consume. The performance boost of shared memory session storage won't matter if your site's sessions consume all available memory on your system!

To store session data in shared memory, you need to have the shared memory functions explicitly enabled by building PHP with --enable-shmop. You will also need the pc_Shm class shown in Example 11-3, as well as the pc_Shm_Session class shown in Example 11-3.

pc_Shm class

class pc_Shm {   var $tmp;   var $size;   var $shm;   var $keyfile;   function pc_Shm($tmp = '') {     if (!function_exists('shmop_open')) {       trigger_error('pc_Shm: shmop extension is required.', E_USER_ERROR);       return;     }     if ($tmp != '' && is_dir($tmp) && is_writable($tmp)) {       $this->tmp = $tmp;     } else {       $this->tmp = '/tmp';     }     // default to 16k     $this->size = 16384;     return true;   }   function __construct($tmp = '') {     return $this->pc_Shm($tmp);   }   function setSize($size) {     if (ctype_digit($size)) {       $this->size = $size;     }   }   function open($id) {     $key = $this->_getKey($id);     $shm = shmop_open($key, 'c', 0644, $this->size);     if (!$shm) {       trigger_error('pc_Shm: could not create shared memory segment', E_USER_ERROR);       return false;     }     $this->shm = $shm;     return true;   }   function write($data) {     $written = shmop_write($this->shm, $data, 0);     if ($written != strlen($data)) {       trigger_error('pc_Shm: could not write entire length of data', E_USER_ERROR);       return false;     }     return true;   }   function read() {     $data = shmop_read($this->shm, 0, $this->size);     if (!$data) {       trigger_error('pc_Shm: could not read from shared memory block', E_USER_ERROR);       return false;     }     return $data;   }   function delete() {     if (shmop_delete($this->shm)) {       if (file_exists($this->tmp . DIRECTORY_SEPARATOR . $this->keyfile)) {         unlink($this->tmp . DIRECTORY_SEPARATOR . $this->keyfile);       }     }     return true;   }   function close() {     return shmop_close($this->shm);   }   function fetch($id) {     $this->open($id);     $data = $this->read();     $this->close();     return $data;   }   function save($id, $data) {     $this->open($id);     $result = $this->write($data);     if (! (bool) $result) {       return false;     } else {       $this->close();       return $result;     }   }   function _getKey($id) {     $this->keyfile = 'pcshm_' . $id;     if (!file_exists($this->tmp . DIRECTORY_SEPARATOR . $this->keyfile)) {       touch($this->tmp . DIRECTORY_SEPARATOR . $this->keyfile);     }     return ftok($this->tmp . DIRECTORY_SEPARATOR . $this->keyfile, 'R');   } }

The pc_Shm class provides an object-oriented wrapper around PHP's shmop functions. The pc_Shm::_getKey( ) method provides a convenient way to transparently calculate a memory address, which is often the biggest obstacle for people getting familiar with the shmop functions. By abstracting the memory address, reading and writing from shared memory is as easy as manipulating a value in an associative array.

pc_Shm creates 16k memory blocks by default. To adjust the size of the blocks used, pass a value in bytes to the pc_Shm::setSize( ) method.

With pc_Shm defined, pc_Shm_Session has what it needs to easily provide custom methods for session_set_save_handler( ). Example 11-3 shows the pc_Shm_Session class.

pc_Shm_Session class

class pc_Shm_Session {   var $shm;   function pc_Shm_Session($tmp = '') {     if (!function_exists('shmop_open')) {       trigger_error("pc_Shm_Session: shmop extension is required.",E_USER_ERROR);       return;     }     if (! session_set_save_handler(array(&$this, '_open'),                      array(&$this, '_close'),                      array(&$this, '_read'),                      array(&$this, '_write'),                      array(&$this, '_destroy'),                      array(&$this, '_gc'))) {       trigger_error('pc_Shm_Session: session_set_save_handler() failed', E_USER_ERROR);       return;     }     $this->shm = new pc_Shm();     return true;   }   function __construct() {     return $this->pc_Shm_Session();   }   function setSize($size) {     if (ctype_digit($size)) {       $this->shm->setSize($size);     }   }   function _open() {     return true;   }   function _close() {     return true;   }   function _read($id) {     $this->shm->open($id);     $data = $this->shm->read();     $this->shm->close();     return $data;   }   function _write($id, $data) {     $this->shm->open($id);     $this->shm->write($data);     $this->shm->close();     return true;   }   function _destroy($id) {     $this->shm->open($id);     $this->shm->delete();     $this->shm->close();   }   function _gc($maxlifetime) {     $d = dir($this->tmp);     while (false !== ($entry = $d->read())) {       if (substr($entry, 0, 6) == 'pcshm_') {         $tmpfile = $this->tmp . DIRECTORY_SEPARATOR . $entry;         $id = substr($entry, 6);         $fmtime = filemtime($tmpfile);         $age = now() - $fmtime;         if ($age >= $maxlifetime) {           $this->shm->open($id);           $this->shm->delete();           $this->shm->close();         }       }     }     $d->close();     return true;   } }

Versions of Microsoft Windows prior to Windows 2000 do not support shared memory. Also, when using PHP in a Windows server environment, shmop functions will only work if PHP is running as a web server module, such those provided by Apache or IIS. CLI and CGI interfaces to PHP do not support shmop functions under Windows.

It's possible that you may not need to use these classes at all. If your web server can be configured to mount a ramdisk partition such as /dev/shm, using shared memory for session storage may be as simple as:

<?php ini_set('session.save_path', '/dev/shm'); ini_get('session.auto_start') or session_start(); ?>

11.5.4. See Also

Documentation on session_set_save_handler( ) at http://www.php.net/session-set-save-handler; documentation on shmop functions at http://www.php.net/shmop. Information on configuring ramdisks on Linux-based systems is available at http://www.linuxhq.com/kernel/file/Documentation/ramdisk.txt.




PHP Cookbook, 2nd Edition
PHP Cookbook: Solutions and Examples for PHP Programmers
ISBN: 0596101015
EAN: 2147483647
Year: 2006
Pages: 445

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net