1+ <?php
2+ /**
3+ * User: jg
4+ * Date: 14/02/17
5+ * Time: 12:52
6+ */
7+
8+ namespace ByJG \Session ;
9+
10+ use ByJG \Util \JwtWrapper ;
11+ use SessionHandlerInterface ;
12+
13+ class JwtSession implements SessionHandlerInterface
14+ {
15+ const COOKIE_PREFIX = "AUTH_BEARER_ " ;
16+
17+ protected $ serverName ;
18+
19+ protected $ secretKey ;
20+
21+ protected $ timeOutMinutes ;
22+
23+ protected $ suffix = "default " ;
24+
25+ /**
26+ * JwtSession constructor.
27+ *
28+ * @param $serverName
29+ * @param $secretKey
30+ * @param int $timeOutMinutes
31+ */
32+ public function __construct ($ serverName , $ secretKey , $ timeOutMinutes = 20 , $ sessionContext = 'default ' )
33+ {
34+ $ this ->serverName = $ serverName ;
35+ $ this ->secretKey = $ secretKey ;
36+ $ this ->timeOutMinutes = $ timeOutMinutes ;
37+ $ this ->suffix = $ sessionContext ;
38+ }
39+
40+ public function replaceSessionHandler ($ startSession = true )
41+ {
42+ if (session_status () != PHP_SESSION_NONE ) {
43+ throw new \Exception ('Session already started! ' );
44+ }
45+
46+ session_set_save_handler ($ this , true );
47+
48+ if ($ startSession ) {
49+ ob_start ();
50+ session_start ();
51+ }
52+ }
53+
54+ /**
55+ * Close the session
56+ *
57+ * @link http://php.net/manual/en/sessionhandlerinterface.close.php
58+ * @return bool <p>
59+ * The return value (usually TRUE on success, FALSE on failure).
60+ * Note this value is returned internally to PHP for processing.
61+ * </p>
62+ * @since 5.4.0
63+ */
64+ public function close ()
65+ {
66+ return true ;
67+ }
68+
69+ /**
70+ * Destroy a session
71+ *
72+ * @link http://php.net/manual/en/sessionhandlerinterface.destroy.php
73+ * @param string $session_id The session ID being destroyed.
74+ * @return bool <p>
75+ * The return value (usually TRUE on success, FALSE on failure).
76+ * Note this value is returned internally to PHP for processing.
77+ * </p>
78+ * @since 5.4.0
79+ */
80+ public function destroy ($ session_id )
81+ {
82+ setcookie (self ::COOKIE_PREFIX . $ this ->suffix , null );
83+ return true ;
84+ }
85+
86+ /**
87+ * Cleanup old sessions
88+ *
89+ * @link http://php.net/manual/en/sessionhandlerinterface.gc.php
90+ * @param int $maxlifetime <p>
91+ * Sessions that have not updated for
92+ * the last maxlifetime seconds will be removed.
93+ * </p>
94+ * @return bool <p>
95+ * The return value (usually TRUE on success, FALSE on failure).
96+ * Note this value is returned internally to PHP for processing.
97+ * </p>
98+ * @since 5.4.0
99+ */
100+ public function gc ($ maxlifetime )
101+ {
102+ return true ;
103+ }
104+
105+ /**
106+ * Initialize session
107+ *
108+ * @link http://php.net/manual/en/sessionhandlerinterface.open.php
109+ * @param string $save_path The path where to store/retrieve the session.
110+ * @param string $name The session name.
111+ * @return bool <p>
112+ * The return value (usually TRUE on success, FALSE on failure).
113+ * Note this value is returned internally to PHP for processing.
114+ * </p>
115+ * @since 5.4.0
116+ */
117+ public function open ($ save_path , $ name )
118+ {
119+ return true ;
120+ }
121+
122+ /**
123+ * Read session data
124+ *
125+ * @link http://php.net/manual/en/sessionhandlerinterface.read.php
126+ * @param string $session_id The session id to read data for.
127+ * @return string <p>
128+ * Returns an encoded string of the read data.
129+ * If nothing was read, it must return an empty string.
130+ * Note this value is returned internally to PHP for processing.
131+ * </p>
132+ * @since 5.4.0
133+ */
134+ public function read ($ session_id )
135+ {
136+ try {
137+ if (isset ($ _COOKIE [self ::COOKIE_PREFIX . $ this ->suffix ])) {
138+ $ jwt = new JwtWrapper ($ this ->serverName , $ this ->secretKey );
139+ $ data = $ jwt ->extractData ($ _COOKIE [self ::COOKIE_PREFIX . $ this ->suffix ]);
140+
141+ return $ this ->serializeSessionData ($ data ->data );
142+ }
143+ return '' ;
144+ } catch (\Exception $ ex ) {
145+ return '' ;
146+ }
147+ }
148+
149+ /**
150+ * Write session data
151+ *
152+ * @link http://php.net/manual/en/sessionhandlerinterface.write.php
153+ * @param string $session_id The session id.
154+ * @param string $session_data <p>
155+ * The encoded session data. This data is the
156+ * result of the PHP internally encoding
157+ * the $_SESSION superglobal to a serialized
158+ * string and passing it as this parameter.
159+ * Please note sessions use an alternative serialization method.
160+ * </p>
161+ * @return bool <p>
162+ * The return value (usually TRUE on success, FALSE on failure).
163+ * Note this value is returned internally to PHP for processing.
164+ * </p>
165+ * @since 5.4.0
166+ */
167+ public function write ($ session_id , $ session_data )
168+ {
169+ $ jwt = new JwtWrapper ($ this ->serverName , $ this ->secretKey );
170+ $ data = $ jwt ->createJwtData ($ this ->unSerializeSessionData ($ session_data ), $ this ->timeOutMinutes * 60 );
171+ $ token = $ jwt ->generateToken ($ data );
172+
173+ setcookie (self ::COOKIE_PREFIX . $ this ->suffix , $ token );
174+
175+ return true ;
176+ }
177+
178+ public function serializeSessionData ($ array )
179+ {
180+ $ result = '' ;
181+ foreach ($ array as $ key => $ value ) {
182+ $ result .= $ key . "| " . serialize ($ value );
183+ }
184+
185+ return $ result ;
186+ }
187+
188+ public function unSerializeSessionData ($ session_data )
189+ {
190+ $ return_data = array ();
191+ $ offset = 0 ;
192+ while ($ offset < strlen ($ session_data )) {
193+ if (!strstr (substr ($ session_data , $ offset ), "| " )) {
194+ throw new \Exception ("invalid data, remaining: " . substr ($ session_data , $ offset ));
195+ }
196+ $ pos = strpos ($ session_data , "| " , $ offset );
197+ $ num = $ pos - $ offset ;
198+ $ varname = substr ($ session_data , $ offset , $ num );
199+ $ offset += $ num + 1 ;
200+ $ data = unserialize (substr ($ session_data , $ offset ));
201+ $ return_data [$ varname ] = $ data ;
202+ $ offset += strlen (serialize ($ data ));
203+ }
204+
205+ return $ return_data ;
206+ }
207+ }
0 commit comments