root/trunk/framework/Web/THttpSession.php

Revision 2482, 19.0 kB (checked in by knut, 4 months ago)

updated copyright

  • Property svn:keywords set to Id
Line 
1<?php
2/**
3 * THttpSession class
4 *
5 * @author Qiang Xue <qiang.xue@gmail.com>
6 * @link http://www.pradosoft.com/
7 * @copyright Copyright &copy; 2005-2008 PradoSoft
8 * @license http://www.pradosoft.com/license/
9 * @version $Id$
10 * @package System.Web
11 */
12
13/**
14 * THttpSession class
15 *
16 * THttpSession provides session-level data management and the related configurations.
17 * To start the session, call {@open}; to complete and send out session data, call {@close};
18 * to destroy the session, call {@destroy}. If AutoStart is true, then the session
19 * will be started once the session module is loaded and initialized.
20 *
21 * To access data stored in session, use THttpSession like an associative array. For example,
22 * <code>
23 *   $session=new THttpSession;
24 *   $session->open();
25 *   $value1=$session['name1'];  // get session variable 'name1'
26 *   $value2=$session['name2'];  // get session variable 'name2'
27 *   foreach($session as $name=>$value) // traverse all session variables
28 *   $session['name3']=$value3;  // set session variable 'name3'
29 * </code>
30 *
31 * The following configurations are available for session:
32 * {@link setAutoStart AutoStart}, {@link setCookie Cookie},
33 * {@link setCacheLimiter, {@link setSavePath SavePath},
34 * {@link setUseCustomStorage UseCustomStorage}, {@link setGCProbability GCProbability},
35 * {@link setCookieUsage CookieUsage}, {@link setTimeout Timeout}.
36 * See the corresponding setter and getter documentation for more information.
37 * Note, these properties must be set before the session is started.
38 *
39 * THttpSession can be inherited with customized session storage method.
40 * Override {@link _open}, {@link _close}, {@link _read}, {@link _write}, {@link _destroy} and {@link _gc}
41 * and set {@link setUseCustomStorage UseCustomStorage} to true.
42 * Then, the session data will be stored using the above methods.
43 *
44 * By default, THttpSession is registered with {@link TApplication} as the
45 * request module. It can be accessed via {@link TApplication::getSession()}.
46 *
47 * THttpSession may be configured in application configuration file as follows,
48 * <code>
49 * <module id="session" class="THttpSession" SessionName="SSID" SavePath="/tmp"
50 *         CookieMode="Allow" UseCustomStorage="false" AutoStart="true" GCProbability="1"
51 *         UseTransparentSessionID="true" TimeOut="3600" />
52 * </code>
53 * where {@link getSessionName SessionName}, {@link getSavePath SavePath},
54 * {@link getCookieMode CookieMode}, {@link getUseCustomStorage
55 * UseCustomStorage}, {@link getAutoStart AutoStart}, {@link getGCProbability
56 * GCProbability}, {@link getUseTransparentSessionID UseTransparentSessionID}
57 * and {@link getTimeOut TimeOut} are configurable properties of THttpSession.
58 *
59 * @author Qiang Xue <qiang.xue@gmail.com>
60 * @version $Id$
61 * @package System.Web
62 * @since 3.0
63 */
64class THttpSession extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
65{
66    /**
67     * @var boolean whether this module has been initialized
68     */
69    private $_initialized=false;
70    /**
71     * @var boolean whether the session has started
72     */
73    private $_started=false;
74    /**
75     * @var boolean whether the session should be started when the module is initialized
76     */
77    private $_autoStart=false;
78    /**
79     * @var THttpCookie cookie to be used to store session ID and other data
80     */
81    private $_cookie=null;
82    /**
83     * @var string module id
84     */
85    private $_id;
86    /**
87     * @var boolean
88     */
89    private $_customStorage=false;
90
91    /**
92     * @return string id of this module
93     */
94    public function getID()
95    {
96        return $this->_id;
97    }
98
99    /**
100     * @param string id of this module
101     */
102    public function setID($value)
103    {
104        $this->_id=$value;
105    }
106
107    /**
108     * Initializes the module.
109     * This method is required by IModule.
110     * If AutoStart is true, the session will be started.
111     * @param TXmlElement module configuration
112     */
113    public function init($config)
114    {
115        if($this->_autoStart)
116            $this->open();
117        $this->_initialized=true;
118        $this->getApplication()->setSession($this);
119        register_shutdown_function(array($this, "close"));
120    }
121
122    /**
123     * Starts the session if it has not started yet.
124     */
125    public function open()
126    {
127        if(!$this->_started)
128        {
129            if($this->_customStorage)
130                session_set_save_handler(array($this,'_open'),array($this,'_close'),array($this,'_read'),array($this,'_write'),array($this,'_destroy'),array($this,'_gc'));
131            if($this->_cookie!==null)
132                session_set_cookie_params($this->_cookie->getExpire(),$this->_cookie->getPath(),$this->_cookie->getDomain(),$this->_cookie->getSecure());
133            if(ini_get('session.auto_start')!=='1')
134                session_start();
135            $this->_started=true;
136        }
137    }
138
139    /**
140     * Ends the current session and store session data.
141     */
142    public function close()
143    {
144        if($this->_started)
145        {
146            session_write_close();
147            $this->_started=false;
148        }
149    }
150
151    /**
152     * Destroys all data registered to a session.
153     */
154    public function destroy()
155    {
156        if($this->_started)
157        {
158            session_destroy();
159            $this->_started=false;
160        }
161    }
162
163    /**
164     * @return boolean whether the session has started
165     */
166    public function getIsStarted()
167    {
168        return $this->_started;
169    }
170
171    /**
172     * @return string the current session ID
173     */
174    public function getSessionID()
175    {
176        return session_id();
177    }
178
179    /**
180     * @param string the session ID for the current session
181     * @throws TInvalidOperationException if session is started already
182     */
183    public function setSessionID($value)
184    {
185        if($this->_started)
186            throw new TInvalidOperationException('httpsession_sessionid_unchangeable');
187        else
188            session_id($value);
189    }
190
191    /**
192     * @return string the current session name
193     */
194    public function getSessionName()
195    {
196        return session_name();
197    }
198
199    /**
200     * @param string the session name for the current session, must be an alphanumeric string, defaults to PHPSESSID
201     * @throws TInvalidOperationException if session is started already
202     */
203    public function setSessionName($value)
204    {
205        if($this->_started)
206            throw new TInvalidOperationException('httpsession_sessionname_unchangeable');
207        else if(ctype_alnum($value))
208            session_name($value);
209        else
210            throw new TInvalidDataValueException('httpsession_sessionname_invalid',$value);
211    }
212
213    /**
214     * @return string the current session save path, defaults to '/tmp'.
215     */
216    public function getSavePath()
217    {
218        return session_save_path();
219    }
220
221    /**
222     * @param string the current session save path
223     * @throws TInvalidOperationException if session is started already
224     */
225    public function setSavePath($value)
226    {
227        if($this->_started)
228            throw new TInvalidOperationException('httpsession_savepath_unchangeable');
229        else if(is_dir($value))
230            session_save_path($value);
231        else
232            throw new TInvalidDataValueException('httpsession_savepath_invalid',$value);
233    }
234
235    /**
236     * @return boolean whether to use user-specified handlers to store session data. Defaults to false.
237     */
238    public function getUseCustomStorage()
239    {
240        return $this->_customStorage;
241    }
242
243    /**
244     * @param boolean whether to use user-specified handlers to store session data.
245     * If true, make sure the methods {@link _open}, {@link _close}, {@link _read},
246     * {@link _write}, {@link _destroy}, and {@link _gc} are overridden in child
247     * class, because they will be used as the callback handlers.
248     */
249    public function setUseCustomStorage($value)
250    {
251        $this->_customStorage=TPropertyValue::ensureBoolean($value);
252    }
253
254    /**
255     * @return THttpCookie cookie that will be used to store session ID
256     */
257    public function getCookie()
258    {
259        if($this->_cookie===null)
260            $this->_cookie=new THttpCookie($this->getSessionName(),$this->getSessionID());
261        return $this->_cookie;
262    }
263
264    /**
265     * @return THttpSessionCookieMode how to use cookie to store session ID. Defaults to THttpSessionCookieMode::Allow.
266     */
267    public function getCookieMode()
268    {
269        if(ini_get('session.use_cookies')==='0')
270            return THttpSessionCookieMode::None;
271        else if(ini_get('session.use_only_cookies')==='0')
272            return THttpSessionCookieMode::Allow;
273        else
274            return THttpSessionCookieMode::Only;
275    }
276
277    /**
278     * @param THttpSessionCookieMode how to use cookie to store session ID
279     * @throws TInvalidOperationException if session is started already
280     */
281    public function setCookieMode($value)
282    {
283        if($this->_started)
284            throw new TInvalidOperationException('httpsession_cookiemode_unchangeable');
285        else
286        {
287            $value=TPropertyValue::ensureEnum($value,'THttpSessionCookieMode');
288            if($value===THttpSessionCookieMode::None)
289                ini_set('session.use_cookies','0');
290            else if($value===THttpSessionCookieMode::Allow)
291            {
292                ini_set('session.use_cookies','1');
293                ini_set('session.use_only_cookies','0');
294            }
295            else
296            {
297                ini_set('session.use_cookies','1');
298                ini_set('session.use_only_cookies','1');
299            }
300        }
301    }
302
303    /**
304     * @return boolean whether the session should be automatically started when the session module is initialized, defaults to false.
305     */
306    public function getAutoStart()
307    {
308        return $this->_autoStart;
309    }
310
311    /**
312     * @param boolean whether the session should be automatically started when the session module is initialized, defaults to false.
313     * @throws TInvalidOperationException if session is started already
314     */
315    public function setAutoStart($value)
316    {
317        if($this->_initialized)
318            throw new TInvalidOperationException('httpsession_autostart_unchangeable');
319        else
320            $this->_autoStart=TPropertyValue::ensureBoolean($value);
321    }
322
323    /**
324     * @return integer the probability (percentage) that the gc (garbage collection) process is started on every session initialization, defaults to 1 meaning 1% chance.
325     */
326    public function getGCProbability()
327    {
328        return TPropertyValue::ensureInteger(ini_get('session.gc_probability'));
329    }
330
331    /**
332     * @param integer the probability (percentage) that the gc (garbage collection) process is started on every session initialization.
333     * @throws TInvalidOperationException if session is started already
334     * @throws TInvalidDataValueException if the value is beyond [0,100].
335     */
336    public function setGCProbability($value)
337    {
338        if($this->_started)
339            throw new TInvalidOperationException('httpsession_gcprobability_unchangeable');
340        else
341        {
342            $value=TPropertyValue::ensureInteger($value);
343            if($value>=0 && $value<=100)
344            {
345                ini_set('session.gc_probability',$value);
346                ini_set('session.gc_divisor','100');
347            }
348            else
349                throw new TInvalidDataValueException('httpsession_gcprobability_invalid',$value);
350        }
351    }
352
353    /**
354     * @return boolean whether transparent sid support is enabled or not, defaults to false.
355     */
356    public function getUseTransparentSessionID()
357    {
358        return ini_get('session.use_trans_sid')==='1';
359    }
360
361    /**
362     * @param boolean whether transparent sid support is enabled or not.
363     */
364    public function setUseTransparentSessionID($value)
365    {
366        if($this->_started)
367            throw new TInvalidOperationException('httpsession_transid_unchangeable');
368        else
369            ini_set('session.use_trans_sid',TPropertyValue::ensureBoolean($value)?'1':'0');
370    }
371
372    /**
373     * @return integer the number of seconds after which data will be seen as 'garbage' and cleaned up, defaults to 1440 seconds.
374     */
375    public function getTimeout()
376    {
377        return TPropertyValue::ensureInteger(ini_get('session.gc_maxlifetime'));
378    }
379
380    /**
381     * @param integer the number of seconds after which data will be seen as 'garbage' and cleaned up
382     * @throws TInvalidOperationException if session is started already
383     */
384    public function setTimeout($value)
385    {
386        if($this->_started)
387            throw new TInvalidOperationException('httpsession_maxlifetime_unchangeable');
388        else
389            ini_set('session.gc_maxlifetime',$value);
390    }
391
392    /**
393     * Session open handler.
394     * This method should be overridden if {@link setUseCustomStorage UseCustomStorage} is set true.
395     * @param string session save path
396     * @param string session name
397     * @return boolean whether session is opened successfully
398     */
399    public function _open($savePath,$sessionName)
400    {
401        return true;
402    }
403
404    /**
405     * Session close handler.
406     * This method should be overridden if {@link setUseCustomStorage UseCustomStorage} is set true.
407     * @return boolean whether session is closed successfully
408     */
409    public function _close()
410    {
411        return true;
412    }
413
414    /**
415     * Session read handler.
416     * This method should be overridden if {@link setUseCustomStorage UseCustomStorage} is set true.
417     * @param string session ID
418     * @return string the session data
419     */
420    public function _read($id)
421    {
422        return '';
423    }
424
425    /**
426     * Session write handler.
427     * This method should be overridden if {@link setUseCustomStorage UseCustomStorage} is set true.
428     * @param string session ID
429     * @param string session data
430     * @return boolean whether session write is successful
431     */
432    public function _write($id,$data)
433    {
434        return true;
435    }
436
437    /**
438     * Session destroy handler.
439     * This method should be overridden if {@link setUseCustomStorage UseCustomStorage} is set true.
440     * @param string session ID
441     * @return boolean whether session is destroyed successfully
442     */
443    public function _destroy($id)
444    {
445        return true;
446    }
447
448    /**
449     * Session GC (garbage collection) handler.
450     * This method should be overridden if {@link setUseCustomStorage UseCustomStorage} is set true.
451     * @param integer the number of seconds after which data will be seen as 'garbage' and cleaned up.
452     * @return boolean whether session is GCed successfully
453     */
454    public function _gc($maxLifetime)
455    {
456        return true;
457    }
458
459    //------ The following methods enable THttpSession to be TMap-like -----
460
461    /**
462     * Returns an iterator for traversing the session variables.
463     * This method is required by the interface IteratorAggregate.
464     * @return TSessionIterator an iterator for traversing the session variables.
465     */
466    public function getIterator()
467    {
468        return new TSessionIterator;
469    }
470
471    /**
472     * @return integer the number of session variables
473     */
474    public function getCount()
475    {
476        return count($_SESSION);
477    }
478
479    /**
480     * Returns the number of items in the session.
481     * This method is required by Countable interface.
482     * @return integer number of items in the session.
483     */
484    public function count()
485    {
486        return $this->getCount();
487    }
488
489    /**
490     * @return array the list of session variable names
491     */
492    public function getKeys()
493    {
494        return array_keys($_SESSION);
495    }
496
497    /**
498     * Returns the session variable value with the session variable name.
499     * This method is exactly the same as {@link offsetGet}.
500     * @param mixed the session variable name
501     * @return mixed the session variable value, null if no such variable exists
502     */
503    public function itemAt($key)
504    {
505        return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
506    }
507
508    /**
509     * Adds a session variable.
510     * Note, if the specified name already exists, the old value will be removed first.
511     * @param mixed session variable name
512     * @param mixed session variable value
513     */
514    public function add($key,$value)
515    {
516        $_SESSION[$key]=$value;
517    }
518
519    /**
520     * Removes a session variable.
521     * @param mixed the name of the session variable to be removed
522     * @return mixed the removed value, null if no such session variable.
523     */
524    public function remove($key)
525    {
526        if(isset($_SESSION[$key]))
527        {
528            $value=$_SESSION[$key];
529            unset($_SESSION[$key]);
530            return $value;
531        }
532        else
533            return null;
534    }
535
536    /**
537     * Removes all session variables
538     */
539    public function clear()
540    {
541        foreach(array_keys($_SESSION) as $key)
542            unset($_SESSION[$key]);
543    }
544
545    /**
546     * @param mixed session variable name
547     * @return boolean whether there is the named session variable
548     */
549    public function contains($key)
550    {
551        return isset($_SESSION[$key]);
552    }
553
554    /**
555     * @return array the list of all session variables in array
556     */
557    public function toArray()
558    {
559        return $_SESSION;
560    }
561
562    /**
563     * This method is required by the interface ArrayAccess.
564     * @param mixed the offset to check on
565     * @return boolean
566     */
567    public function offsetExists($offset)
568    {
569        return isset($_SESSION[$offset]);
570    }
571
572    /**
573     * This method is required by the interface ArrayAccess.
574     * @param integer the offset to retrieve element.
575     * @return mixed the element at the offset, null if no element is found at the offset
576     */
577    public function offsetGet($offset)
578    {
579        return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
580    }
581
582    /**
583     * This method is required by the interface ArrayAccess.
584     * @param integer the offset to set element
585     * @param mixed the element value
586     */
587    public function offsetSet($offset,$item)
588    {
589        $_SESSION[$offset]=$item;
590    }
591
592    /**
593     * This method is required by the interface ArrayAccess.
594     * @param mixed the offset to unset element
595     */
596    public function offsetUnset($offset)
597    {
598        unset($_SESSION[$offset]);
599    }
600}
601
602/**
603 * TSessionIterator class
604 *
605 * TSessionIterator implements Iterator interface.
606 *
607 * TSessionIterator is used by THttpSession. It allows THttpSession to return a new iterator
608 * for traversing the session variables.
609 *
610 * @author Qiang Xue <qiang.xue@gmail.com>
611 * @version $Id$
612 * @package System.Web
613 * @since 3.0
614 */
615class TSessionIterator implements Iterator
616{
617    /**
618     * @var array list of keys in the map
619     */
620    private $_keys;
621    /**
622     * @var mixed current key
623     */
624    private $_key;
625
626    /**
627     * Constructor.
628     * @param array the data to be iterated through
629     */
630    public function __construct()
631    {
632        $this->_keys=array_keys($_SESSION);
633    }
634
635    /**
636     * Rewinds internal array pointer.
637     * This method is required by the interface Iterator.
638     */
639    public function rewind()
640    {
641        $this->_key=reset($this->_keys);
642    }
643
644    /**
645     * Returns the key of the current array element.
646     * This method is required by the interface Iterator.
647     * @return mixed the key of the current array element
648     */
649    public function key()
650    {
651        return $this->_key;
652    }
653
654    /**
655     * Returns the current array element.
656     * This method is required by the interface Iterator.
657     * @return mixed the current array element
658     */
659    public function current()
660    {
661        return isset($_SESSION[$this->_key])?$_SESSION[$this->_key]:null;
662    }
663
664    /**
665     * Moves the internal pointer to the next array element.
666     * This method is required by the interface Iterator.
667     */
668    public function next()
669    {
670        do
671        {
672            $this->_key=next($this->_keys);
673        }
674        while(!isset($_SESSION[$this->_key]) && $this->_key!==false);
675    }
676
677    /**
678     * Returns whether there is an element at current position.
679     * This method is required by the interface Iterator.
680     * @return boolean
681     */
682    public function valid()
683    {
684        return $this->_key!==false;
685    }
686}
687
688
689/**
690 * THttpSessionCookieMode class.
691 * THttpSessionCookieMode defines the enumerable type for the possible methods of
692 * using cookies to store session ID.
693 *
694 * The following enumerable values are defined:
695 * - None: not using cookie.
696 * - Allow: using cookie.
697 * - Only: using cookie only.
698 *
699 * @author Qiang Xue <qiang.xue@gmail.com>
700 * @version $Id$
701 * @package System.Web
702 * @since 3.0.4
703 */
704class THttpSessionCookieMode extends TEnumerable
705{
706    const None='None';
707    const Allow='Allow';
708    const Only='Only';
709}
710
711?>
Note: See TracBrowser for help on using the browser.