Development

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

You must first sign up to be able to contribute.

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

Revision 29519, 8.1 kB (checked in by fabien, 4 years ago)

[1.3, 1.4] marked response as private when using the sfCacheSessionStorage class (closes #8535)

  • 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     parent::initialize(array_merge(array('session_name' => 'sfproject',
44                                          'session_cookie_lifetime' => '+30 days',
45                                          'session_cookie_path' => '/',
46                                          'session_cookie_domain' => null,
47                                          'session_cookie_secure' => false,
48                                          'session_cookie_http_only' => true,
49                                          'session_cookie_secret' => 'sf$ecret'), $options));
50
51     // create cache instance
52     if (isset($this->options['cache']) && $this->options['cache']['class'])
53     {
54       $this->cache = new $this->options['cache']['class'](is_array($this->options['cache']['param']) ? $this->options['cache']['param'] : array());
55     }
56     else
57     {
58       throw new InvalidArgumentException('sfCacheSessionStorage requires cache option.');
59     }
60
61     $this->context     = sfContext::getInstance();
62
63     $this->dispatcher  = $this->context->getEventDispatcher();
64     $this->request     = $this->context->getRequest();
65     $this->response    = $this->context->getResponse();
66
67     $cookie = $this->request->getCookie($this->options['session_name']);
68
69     if(strpos($cookie, ':') !== false)
70     {
71       // split cookie data id:signature(id+secret)
72       list($id, $signature) = explode(':', $cookie, 2);
73
74       if($signature == sha1($id.':'.$this->options['session_cookie_secret']))
75       {
76         // cookie is valid
77         $this->id = $id;
78       }
79       else
80       {
81         // cookie signature broken
82         $this->id = null;
83       }
84     }
85     else
86     {
87       // cookie format wrong
88       $this->id = null;
89     }
90
91     if(empty($this->id))
92     {
93        $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'localhost';
94        $ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'ua';
95
96        // generate new id based on random # / ip / user agent / secret
97        $this->id = md5(rand(0, 999999).$ip.$ua.$this->options['session_cookie_secret']);
98
99        if(sfConfig::get('sf_logging_enabled'))
100        {
101          $this->dispatcher->notify(new sfEvent($this, 'application.log', array('New session created')));
102        }
103
104        // only send cookie when id is issued
105        $this->response->setCookie($this->options['session_name'],
106                                   $this->id.':'.sha1($this->id.':'.$this->options['session_cookie_secret']),
107                                   $this->options['session_cookie_lifetime'],
108                                   $this->options['session_cookie_path'],
109                                   $this->options['session_cookie_domain'],
110                                   $this->options['session_cookie_secure'],
111                                   $this->options['session_cookie_http_only']);
112
113        $this->data = array();
114     }
115     else
116     {
117       // load data from cache
118       $this->data = $this->cache->get($this->id, array());
119
120       if(sfConfig::get('sf_logging_enabled'))
121       {
122         $this->dispatcher->notify(new sfEvent($this, 'application.log', array('Restored previous session')));
123       }
124     }
125     session_id($this->id);
126     $this->response->addCacheControlHttpHeader('private');
127
128     return true;
129   }
130
131   /**
132    * Write data to this storage.
133    *
134    * The preferred format for a key is directory style so naming conflicts can be avoided.
135    *
136    * @param string $key  A unique key identifying your data.
137    * @param mixed  $data Data associated with your key.
138    *
139    * @return void
140    */
141   public function write($key, $data)
142   {
143     $this->dataChanged = true;
144
145     $this->data[$key] =& $data;
146   }
147
148   /**
149    * Read data from this storage.
150    *
151    * The preferred format for a key is directory style so naming conflicts can be avoided.
152    *
153    * @param string $key A unique key identifying your data.
154    *
155    * @return mixed Data associated with the key.
156    */
157   public function read($key)
158   {
159     $retval = null;
160
161     if (isset($this->data[$key]))
162     {
163       $retval =& $this->data[$key];
164     }
165
166     return $retval;
167   }
168
169   /**
170    * Remove data from this storage.
171    *
172    * The preferred format for a key is directory style so naming conflicts can be avoided.
173    *
174    * @param string $key A unique key identifying your data.
175    *
176    * @return mixed Data associated with the key.
177    */
178   public function remove($key)
179   {
180     $retval = null;
181
182     if (isset($this->data[$key]))
183     {
184       $this->dataChanged = true;
185
186       $retval =& $this->data[$key];
187       unset($this->data[$key]);
188     }
189
190     return $retval;
191   }
192
193   /**
194    * Regenerates id that represents this storage.
195    *
196    * @param boolean $destroy Destroy session when regenerating?
197    *
198    * @return boolean True if session regenerated, false if error
199    *
200    * @throws <b>sfStorageException</b> If an error occurs while regenerating this storage
201    */
202   public function regenerate($destroy = false)
203   {
204     if($destroy)
205     {
206       $this->data = array();
207       $this->cache->remove($this->id);
208     }
209
210     // generate session id
211     $this->id = md5(rand(0, 999999).$_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGENT'].$this->options['session_cookie_secret']);
212
213     // save data to cache
214     $this->cache->set($this->id, $this->data);
215
216     // update session id in signed cookie
217     $this->response->setCookie($this->options['session_name'],
218                                $this->id.':'.sha1($this->id.':'.$this->options['session_cookie_secret']),
219                                $this->options['session_cookie_lifetime'],
220                                $this->options['session_cookie_path'],
221                                $this->options['session_cookie_domain'],
222                                $this->options['session_cookie_secure'],
223                                $this->options['session_cookie_http_only']);
224     session_id($this->id);
225     return true;
226   }
227
228   /**
229    * Expires the session storage instance.
230    */
231   public function expire()
232   {
233     // destroy data and regenerate id
234     $this->regenerate(true);
235
236     if(sfConfig::get('sf_logging_enabled'))
237     {
238       $this->dispatcher->notify(new sfEvent($this, 'application.log', array('new session created due to expiraton')));
239     }
240   }
241
242   /**
243    * Executes the shutdown procedure.
244    *
245    * @throws <b>sfStorageException</b> If an error occurs while shutting down this storage
246    */
247   public function shutdown()
248   {
249     // only update cache if session has changed
250     if($this->dataChanged === true)
251     {
252       $this->cache->set($this->id, $this->data);
253       if(sfConfig::get('sf_logging_enabled'))
254       {
255         $this->dispatcher->notify(new sfEvent($this, 'application.log', array('Storing session to cache')));
256         // $this->dispatcher->notify(new sfEvent($this, 'application.log', array(var_export($this->data, true))));
257       }
258     }
259   }
260 }
261
Note: See TracBrowser for help on using the browser.