Tout d'abord bonjour à tous, mon problème viens d'une classe de gestion de sessions. J'utilise session_set_save_handler pour paramétrer le comportement de mes sessions et utiliser les fonctionnalités classiques de sessions php.

Pour tenter de prévenir les fixations de sessions, je change l'id de session à chaque appel d'une nouvelle page. Ma classe n'est pas totalement finie mais la partie principale me pose un problème.

J'ai l'impression que lorsque je fais appel à session_regenerate_id(), mon appel en base de données est fait deux fois. En effet, le nouvel identifiant de session est inséré à la place de l'ancien et le nouveau est inconnu au bataillon.

Y aurait-il des problèmes connus entre l'implémentation de session_set_save_handler et session_regenerate_id ?

Plus précisément j'aimerais savoir ce que fais réellement session_regenerate_id ? Est-ce que ça me rappelle un read() ou un write() ?

Pour vous simplifier, le problème vient de mon constructeur car la classe se comporte comme prévu si je comment la ligne session_regenerate_id();

Voici mon code :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
<?php
 
/**
 * @package   Libraries
 * @lastmodif  2009.08.24:03.16PM
 * @version    1.0
 */
 
if( ! class_exists( 'Lib_Session' ) )
{
    /**
     * This class handle the whole session process. It will creates a new
     * session within db or get an existing one using the classic php session
     * functionnalities. Moreover, it attempts to prevent session fixation
     * by changing the session id twice at every page call.
     */
    class Lib_Session
    implements Vsf_Singleton_Interface
    {
        protected static $o_Instance; // Unique instance of the singleton
        protected static $o_Model;    // The database model instance
 
        const i_LastIdTimeOut = 30;   // The last session id validity
 
        // The current session data fields (corresponding to the db fields)
        protected static $s_SessionId, $s_LastSessionId, $i_SessionStart,
                         $i_LastActivity, $s_Userdata;
 
        /**
         * The protected constructor for the singleton instance
         */
        protected function __construct() 
        {
            session_set_save_handler(
                array( & $this, 'open' ),
                array( & $this, 'close' ),
                array( & $this, 'read' ),
                array( & $this, 'write' ),
                array( & $this, 'destroy' ),
                array( & $this, 'gc' )
            );
 
            // We set the values for some configuration options
            ini_set( 'session.name', 'sid' );
            ini_set( 'session.gc_probability', 10 );
            ini_set( 'session.gc_divisor', 100 );
            ini_set( 'session.gc_maxlifetime', 3600 );
 
            session_start();
            session_regenerate_id(); // Attempt to prevent session fixation
        }
 
        /**
         * Return and build if necessary the singleton instance of this class
         *
         * @return Lib_Session
         */
        public static function GetInstance()
        {
            // If there is no instance of the Lib_Session ...
            if( ! self::$o_Instance instanceof self )
                self::$o_Instance = new self; // ... we create one.
            // We return the Lib_Session instance
            return self::$o_Instance;
        }
 
        /**
         * Open function, this works like a constructor and is executed when the
         * session is being opened. The open function expects two parameters, 
         * where the first is the save path and the second is the session name.
         *
         * @param  string $s_Path The session path
         * @param  string $s_Name The session name
         * @return bool (always true)
         */
        public static function Open( $s_Path, $s_Name )
        {
            self::$o_Model = new Model_Session;
            return true;
        }
 
        /**
         * Close function, this works like a destructor and is executed when the
         * session operation is done.
         *
         * @return bool (always true)
         */
        public static function Close()
        {
            @mysql_close();
            return true;
        }
 
        /**
         * Read function must return string value always to make save handler
         * work as expected. Return empty string if there is no data to read. 
         * Return values from other handlers are converted to boolean 
         * expression. TRUE for success, FALSE for failure.
         *
         * @param  string $s_SessionId The unique session id
         * @return string The userdata to store with the $_SESSION superglobal
         */
        public static function Read( $s_SessionId )
        {
            // Try to get the session data informations from database
            $h_Where = array( 'session_id' => $s_SessionId );
            $a_Model = self::$o_Model->Select( NULL, $h_Where, NULL, 0, 1 );
 
            // There is a corresponding session id into db
            if( count( $a_Model ) )
            {
                // We get the content of $a_Model[0]
                $h_Model = array_shift( $a_Model );
 
                // The we set the session corresponding properties ...
                self::$s_SessionId = $h_Model['session_id'];
                self::$s_LastSessionId = $h_Model['last_session_id'];
                self::$i_SessionStart = $h_Model['session_start'];
                self::$i_LastActivity = $h_Model['last_activity'];
                self::$s_Userdata = $h_Model['userdata'];
 
                // ... and return the corresponding userdata
                return self::$s_Userdata;
            }
            else // There is no corresponding session id into db
            {
                // Check if there is an old session id into db
                $h_Where = array( 'last_session_id' => $s_SessionId );
                $a_Model = self::$o_Model->Select( NULL, $h_Where, NULL, 0, 1 );
 
                // There is a corresponding old session id into db
                if( count( $a_Model ) )
                {
                    // We get the content of $a_Model[0]
                    $h_Model = array_shift( $a_Model );
 
                    // We must check whether the last session id is still valid
                    $i_LastValidTime = $h_Model['last_activity'] + self::i_LastIdTimeOut;
                    if( $i_LastValidTime > time() )
                    {
                        // The we set the session corresponding properties ...
                        self::$s_SessionId = $h_Model['session_id'];
                        self::$s_LastSessionId = $h_Model['last_session_id'];
                        self::$i_SessionStart = $h_Model['session_start'];
                        self::$i_LastActivity = $h_Model['last_activity'];
                        self::$s_Userdata = $h_Model['userdata'];
 
                        // ... and return the corresponding userdata
                        return self::$s_Userdata;
                    }
                }           
            }
 
            return '';
        }
 
        /**
         * The "write" handler is not executed until after the output stream is 
         * closed. Thus, output from debugging statements in the "write" handler
         * will never be seen in the browser. If debugging output is necessary,
         * it is suggested that the debug output be written to a file instead. 
         *
         * @param  string $s_SessionId The unique session id
         * @param  string $h_SessionData The corresponding session data
         * @return bool Whether the write request succeeded or not
         */
        public function Write( $s_SessionId, $h_SessionData )
        {
            // Is a session model registered in database ?
            if( ! isset( self::$s_SessionId ) )
            {
                // NO: We creates new session data
                $h_Model = array( 'session_id' => $s_SessionId,
                                  'last_session_id' => self::$s_SessionId,
                                  'session_start' => time(),
                                  'last_activity' => time(),
                                  'userdata' => $h_SessionData );
 
                return self::$o_Model->Insert( $h_Model );
            }
            else
            {
                // YES: We creates a new session id ...
                $h_Model = array( 'session_id' => $s_SessionId,
                                  'last_session_id' => self::$s_SessionId,
                                  'session_start' => self::$i_SessionStart,
                                  'last_activity' => time(),
                                  'userdata' => $h_SessionData );
 
                // ... and update the session data !
                $h_Where = array( 'session_id' => self::$s_SessionId );
                return self::$o_Model->Update( $h_Model, $h_Where );
            }
 
        }
 
        /**
         * The destroy handler, this is executed when a session is destroyed
         * with session_destroy() and takes the session id as its only parameter 
         *
         * @param  string $s_SessionId The unique session id
         * @return bool Whether the delete request succeeded or not
         */
        public function Destroy( $s_SessionId )
        {
            // Check whether session is registered in db ?
            if( isset( self::$s_SessionId ) )
            {
                // Where session_start < actual time - session maxlifetime
                $h_Where = array( 'field' => 'session_id',
                                  'operator' => '=',
                                  'value' => $s_SessionId
                                );
 
                // Delete the expired sessions
                self::$o_Model->Delete( array( 0 => $h_Where ) );
            }
 
            return true;
        }
 
        /**
         * The garbage collector, this is executed when the session garbage 
         * collector is executed and takes the max session lifetime as its 
         * only parameter. 
         *
         * @param  string $i_MaxLifeTime The maximum lifetime for a session
         * @return bool (always true)
         */
        public function Gc( $i_MaxLifeTime )
        {
            // Where session_start < actual time - session maxlifetime
            $h_Where = array( 'field' => 'session_start',
                              'operator' => '<',
                              'value' => time() - $i_MaxLifeTime
                            );
 
            // Delete the expired sessions
            self::$o_Model->Delete( array( 0 => $h_Where ) );
 
            return true;
        }
    }
}