1<?php
2
3DEFINE("SESSION_FILE_PREFIX" ,"session_test_");
4
5/*
6 * == General Return Value Rule ==
7 *
8 * Returning FALSE indicates FATAL error.
9 * Exceptions are: gc(), validate_sid()
10 *
11 * == Session Data Lock ==
12 *
13 * Session data lock is mandatory. Lock must be exclusive. i.e. Block read also.
14 *
15 * == Collision Detection ==
16 *
17 * Collision detection is mandatory to reject attacker initialized session ID.
18 * Coolision detection is absolute requirement for secure session.
19 */
20
21
22/* Open session data database */
23function open($save_path, $session_name) {
24    // string $save_path - Directory path, connection strings, etc. Default: session.save_path
25    // string $session_name - Session ID cookie name. Default: session.name
26
27    global $session_save_path, $name;
28    $session_save_path = $save_path;
29    $name = $session_name;
30    echo "Open [{$session_save_path},{$session_name}]\n";
31
32    // MUST return bool. Return TRUE for success.
33    return true;
34}
35
36/* Close session data database */
37function close() {
38    // void parameter
39    // NOTE: This function should unlock session data, if write() does not unlock it.
40
41    global $session_save_path, $name;
42    echo "Close [{$session_save_path},{$name}]\n";
43
44    // MUST return bool. Return TRUE for success.
45    return true;
46}
47
48/* Read session data */
49function read($id) {
50    // string $id - Session ID string
51    // NOTE: All production session save handler MUST implement "exclusive" lock.
52    //       e.g. Use "serializable transaction isolation level" with RDBMS.
53    //       read() would be the best place for locking for most save handlers.
54
55    global $session_save_path, $name, $session_id;
56    $session_id = $id;
57    echo "Read [{$session_save_path},{$id}]\n";
58    $session_file = "$session_save_path/".SESSION_FILE_PREFIX.$id;
59    // read MUST create file. Otherwise, strict mode will not work
60    touch($session_file);
61
62    // MUST return STRING for successful read().
63    // Return FALSE only when there is error. i.e. Do not return FALSE
64    // for non-existing session data for the $id.
65    return (string) @file_get_contents($session_file);
66}
67
68/* Write session data */
69function write($id, $session_data) {
70    // string $id - Session ID string
71    // string $session_data - Session data string serialized by session serializer.
72    // NOTE: This function may unlock session data locked by read(). If write() is
73    //       is not suitable place your handler to unlock. Unlock data at close().
74
75    global $session_save_path, $name, $session_id;
76    $session_id = $id;
77    echo "Write [{$session_save_path},{$id},{$session_data}]\n";
78    $session_file = "$session_save_path/".SESSION_FILE_PREFIX.$id;
79    if ($fp = fopen($session_file, "w")) {
80        $return = fwrite($fp, $session_data);
81        fclose($fp);
82        return $return === FALSE ? FALSE : TRUE;
83    }
84
85    // MUST return bool. Return TRUE for success.
86    return false;
87}
88
89/* Remove specified session */
90function destroy($id) {
91    // string $id - Session ID string
92
93    global $session_save_path, $name;
94    echo "Destroy [{$session_save_path},{$id}]\n";
95    $session_file = "$session_save_path/".SESSION_FILE_PREFIX.$id;
96    unlink($session_file);
97
98    // MUST return bool. Return TRUE for success.
99    // Return FALSE only when there is error. i.e. Do not return FALSE
100    // for non-existing session data for the $id.
101    return true;
102}
103
104/* Perform garbage collection */
105function gc($maxlifetime) {
106    // long $maxlifetime - GC TTL in seconds. Default: session.gc_maxlifetime
107
108    global $session_save_path, $name;
109    $gc_cnt = 0;
110    $directory = opendir($session_save_path."/");
111    $length = strlen(SESSION_FILE_PREFIX);
112    while (($file = readdir($directory)) !== FALSE) {
113        $qualified = ($session_save_path."/".$file);
114        if (is_file($qualified) === TRUE) {
115            if (substr($file, 0, $length) === SESSION_FILE_PREFIX && (filemtime($qualified) + $maxlifetime <= time() )) {
116                unlink($qualified);
117                $gc_cnt++;
118            }
119        }
120    }
121    closedir($directory);
122
123    // SHOULD return long (number of deleted sessions).
124    // Returning TRUE works also, but it will not report correct number of deleted sessions.
125    // Return negative value for error. FALSE does not work because it's the same as 0.
126    return $gc_cnt;
127}
128
129/* Create new secure session ID */
130function create_sid() {
131    // void parameter
132    // NOTE: Defining create_sid() is mandatory because validate_sid() is mandatory for
133    //       security reasons for production save handler.
134    //       PHP 7.1 has session_create_id() for secure session ID generation. Older PHPs
135    //       must generate secure session ID by yourself.
136    //       e.g. hash('sha2', random_bytes(64)) or use /dev/urandom
137
138    $id = ('PHPT-'.time());
139    echo "CreateID [{$id}]\n";
140
141    // MUST return session ID string.
142    // Return FALSE for error.
143    return $id;
144}
145
146/* Check session ID collision */
147function validate_sid($id) {
148    // string $id - Session ID string
149
150    global $session_save_path, $name;
151    echo "ValidateID [{$session_save_path},{$id}]\n";
152    $session_file = "$session_save_path/".SESSION_FILE_PREFIX.$id;
153    $ret = file_exists($session_file);
154
155    // MUST return bool. Return TRUE for collision.
156    // NOTE: This handler is mandatory for session security.
157    //       All save handlers MUST implement this handler.
158    //       Check session ID collision, return TRUE when it collides.
159    //       Otherwise, return FALSE.
160    return $ret;
161}
162
163/* Update session data access time stamp WITHOUT writing $session_data */
164function update($id, $session_data) {
165    // string $id - Session ID string
166    // string $session_data - Session data serialized by session serializer
167    // NOTE: This handler is optional. If your session database cannot
168    //       support time stamp updating, you must not define this.
169
170    global $session_save_path, $name;
171    echo "Update [{$session_save_path},{$id}]\n";
172    $session_file = "$session_save_path/".SESSION_FILE_PREFIX.$id;
173    $ret = touch($session_file);
174
175    // MUST return bool. Return TRUE for success.
176    return $ret;
177}
178
179
180function feature() {
181    /* NOT IMPLEMENTED YET */
182    /* TYPES: gc, create_sid, use_strict_mode, minimzie_lock, lazy_write
183    /* VALUES: 0=unknown, 1=supported, 2=partially supported, 3=unsupported */
184    return array('gc'=>0,
185                 'create_sid'=>1,
186                 'use_strict_mode'=>2,
187                 'minimize_lock'=>3,
188                 'lazy_write'=>4,
189                 'invalid'=>5,
190                 'another invalid'=>6
191                 );
192}
193
194?>
195