Development

/branches/1.4/lib/storage/sfCacheSessionStorage.class.php

You must first sign up to be able to contribute.

root/branches/1.4/lib/storage/sfCacheSessionStorage.class.php

Revision 33027, 8.8 kB (checked in by fabien, 3 years ago)

[1.4] removed old comment

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1 <?php
2
3 /**
4  * sfCacheSessionStorage manages session storage via a signed cookie and cache backend.
5  *
6  * This class stores the session data in via sfCache instance and with an id issued in a
7  * signed cookie. Useful when you don't want to store the session.
8  *
9  * @package    symfony
10  * @subpackage storage
11  * @author     Dustin Whittle <dustin.whittle@symfony-project.com>
12  */
13 class sfCacheSessionStorage extends sfStorage
14 {
15   protected
16     $id          = null,
17     $context     = null,
18     $dispatcher  = null,
19     $request     = null,
20     $response    = null,
21     $cache       = null,
22     $data        = array(),
23     $dataChanged = false;
24
25   /**
26    * Initialize this Storage.
27    *
28    * @param array $options  An associative array of initialization parameters.
29    *                        session_name [required] name of session to use
30    *                        session_cookie_path [required] cookie path
31    *                        session_cookie_domain [required] cookie domain
32    *                        session_cookie_lifetime [required] liftime of cookie
33    *                        session_cookie_secure [required] send only if secure connection
34    *                        session_cookie_http_only [required] accessible only via http protocol
35    *
36    * @return bool true, when initialization completes successfully.
37    *
38    * @throws <b>sfInitializationException</b> If an error occurs while initializing this Storage.
39    */
40   public function initialize($options = array())
41   {
42     // initialize parent
43     
44     // bc with a slightly different name formerly used here, let's be
45     // compatible with the base class name for it from here on out
46     if (isset($options['session_cookie_http_only']))
47     {
48       $options['session_cookie_httponly'] = $options['session_cookie_http_only'];
49     }
50     
51     parent::initialize(array_merge(array('session_name' => 'sfproject',
52                                          'session_cookie_lifetime' => '+30 days',
53                                          'session_cookie_path' => '/',
54                                          'session_cookie_domain' => null,
55                                          'session_cookie_secure' => false,
56                                          'session_cookie_httponly' => true,
57                                          'session_cookie_secret' => 'sf$ecret'), $options));
58
59     // create cache instance
60     if (isset($this->options['cache']) && $this->options['cache']['class'])
61     {
62       $this->cache = new $this->options['cache']['class'](is_array($this->options['cache']['param']) ? $this->options['cache']['param'] : array());
63     }
64     else
65     {
66       throw new InvalidArgumentException('sfCacheSessionStorage requires cache option.');
67     }
68
69     $this->context     = sfContext::getInstance();
70
71     $this->dispatcher  = $this->context->getEventDispatcher();
72     $this->request     = $this->context->getRequest();
73     $this->response    = $this->context->getResponse();
74
75     $cookie = $this->request->getCookie($this->options['session_name']);
76
77     if(strpos($cookie, ':') !== false)
78     {
79       // split cookie data id:signature(id+secret)
80       list($id, $signature) = explode(':', $cookie, 2);
81
82       if($signature == sha1($id.':'.$this->options['session_cookie_secret']))
83       {
84         // cookie is valid
85         $this->id = $id;
86       }
87       else
88       {
89         // cookie signature broken
90         $this->id = null;
91       }
92     }
93     else
94     {
95       // cookie format wrong
96       $this->id = null;
97     }
98
99     if(empty($this->id))
100     {
101        $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'localhost';
102        $ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'ua';
103
104        // generate new id based on random # / ip / user agent / secret
105        $this->id = md5(rand(0, 999999).$ip.$ua.$this->options['session_cookie_secret']);
106
107        if(sfConfig::get('sf_logging_enabled'))
108        {
109          $this->dispatcher->notify(new sfEvent($this, 'application.log', array('New session created')));
110        }
111
112        // only send cookie when id is issued
113        $this->response->setCookie($this->options['session_name'],
114                                   $this->id.':'.sha1($this->id.':'.$this->options['session_cookie_secret']),
115                                   $this->options['session_cookie_lifetime'],
116                                   $this->options['session_cookie_path'],
117                                   $this->options['session_cookie_domain'],
118                                   $this->options['session_cookie_secure'],
119                                   $this->options['session_cookie_httponly']);
120
121        $this->data = array();
122     }
123     else
124     {
125       // load data from cache. Watch out for the default case. We could
126       // serialize(array()) as the default to the call but that would be a performance hit
127       $raw = $this->cache->get($this->id, null);
128       if (is_null($raw))
129       {
130         $this->data = array();
131       }
132       elseif (is_array($raw))
133       {
134         // probably an old cached value (BC)
135         $this->data = $raw;
136       }
137       else
138       {
139         $this->data = unserialize($raw);
140       }
141
142       if(sfConfig::get('sf_logging_enabled'))
143       {
144         $this->dispatcher->notify(new sfEvent($this, 'application.log', array('Restored previous session')));
145       }
146     }
147     session_id($this->id);
148     $this->response->addCacheControlHttpHeader('private');
149
150     return true;
151   }
152
153   /**
154    * Write data to this storage.
155    *
156    * The preferred format for a key is directory style so naming conflicts can be avoided.
157    *
158    * @param string $key  A unique key identifying your data.
159    * @param mixed  $data Data associated with your key.
160    *
161    * @return void
162    */
163   public function write($key, $data)
164   {
165     $this->dataChanged = true;
166
167     $this->data[$key] =& $data;
168   }
169
170   /**
171    * Read data from this storage.
172    *
173    * The preferred format for a key is directory style so naming conflicts can be avoided.
174    *
175    * @param string $key A unique key identifying your data.
176    *
177    * @return mixed Data associated with the key.
178    */
179   public function read($key)
180   {
181     $retval = null;
182
183     if (isset($this->data[$key]))
184     {
185       $retval =& $this->data[$key];
186     }
187
188     return $retval;
189   }
190
191   /**
192    * Remove data from this storage.
193    *
194    * The preferred format for a key is directory style so naming conflicts can be avoided.
195    *
196    * @param string $key A unique key identifying your data.
197    *
198    * @return mixed Data associated with the key.
199    */
200   public function remove($key)
201   {
202     $retval = null;
203
204     if (isset($this->data[$key]))
205     {
206       $this->dataChanged = true;
207
208       $retval =& $this->data[$key];
209       unset($this->data[$key]);
210     }
211
212     return $retval;
213   }
214
215   /**
216    * Regenerates id that represents this storage.
217    *
218    * @param boolean $destroy Destroy session when regenerating?
219    *
220    * @return boolean True if session regenerated, false if error
221    *
222    * @throws <b>sfStorageException</b> If an error occurs while regenerating this storage
223    */
224   public function regenerate($destroy = false)
225   {
226     if($destroy)
227     {
228       $this->data = array();
229       $this->cache->remove($this->id);
230     }
231
232     // generate session id
233     $ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'ua';
234     
235     $this->id = md5(rand(0, 999999).$_SERVER['REMOTE_ADDR'].$ua.$this->options['session_cookie_secret']);
236
237     // save data to cache
238     $this->cache->set($this->id, serialize($this->data));
239
240     // update session id in signed cookie
241     $this->response->setCookie($this->options['session_name'],
242                                $this->id.':'.sha1($this->id.':'.$this->options['session_cookie_secret']),
243                                $this->options['session_cookie_lifetime'],
244                                $this->options['session_cookie_path'],
245                                $this->options['session_cookie_domain'],
246                                $this->options['session_cookie_secure'],
247                                $this->options['session_cookie_httponly']);
248     session_id($this->id);
249     return true;
250   }
251
252   /**
253    * Expires the session storage instance.
254    */
255   public function expire()
256   {
257     // destroy data and regenerate id
258     $this->regenerate(true);
259
260     if(sfConfig::get('sf_logging_enabled'))
261     {
262       $this->dispatcher->notify(new sfEvent($this, 'application.log', array('new session created due to expiraton')));
263     }
264   }
265
266   /**
267    * Executes the shutdown procedure.
268    *
269    * @throws <b>sfStorageException</b> If an error occurs while shutting down this storage
270    */
271   public function shutdown()
272   {
273     // only update cache if session has changed
274     if($this->dataChanged === true)
275     {
276       $this->cache->set($this->id, serialize($this->data));
277       if(sfConfig::get('sf_logging_enabled'))
278       {
279         $this->dispatcher->notify(new sfEvent($this, 'application.log', array('Storing session to cache')));
280       }
281     }
282   }
283 }
284
Note: See TracBrowser for help on using the browser.