3 # This program is in the public domain within the United States. Additionally,
4 # we waive copyright and related rights in the work worldwide through the CC0
5 # 1.0 Universal public domain dedication, which can be found at
6 # http://creativecommons.org/publicdomain/zero/1.0/
9 # The functions in this file assume that you have this database table:
10 # drop table if exists wfpl_sessions;
11 # create table wfpl_sessions (
12 # id int unique auto_increment,
13 # session_key varchar(16),
20 # You'll want to use these:
23 # session_new('timeout', 'max_len')
24 # session_set('key', 'value')
25 # session_sets(['key': 'value', 'key2': 'val2'])
27 # session_clear() # removes all set() values
28 # session_clear('key')
31 # All session data is cached in globals, so:
32 # 1. don't set large amonuts of data
33 # 2. session_get() is very fast (no db access)
36 # generate a new random 16-character string
37 function session_generate_key() {
38 $character_set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
41 # PHP 4.2.0 and up seed the random number generator for you.
42 # Lets hope that it seeds with something harder to guess than the clock.
43 for($i = 0; $i < 16; ++$i) {
44 $id{$i} = $character_set{mt_rand(0, 61)};
50 # start a new session, tracked by a browser "session cookie".
53 # $idle_timeout (seconds) session ends after this much inactivity (or up to 10% less)
54 # $max_length (seconds) session ends after this long, regardless of activity
55 function session_new($idle_timeout = 129600 /* 36 hours */, $max_length = 604800 /* 1 week */) {
58 $session_key = session_generate_key();
62 'session_key' => $session_key,
63 'idle_timeout' => $idle_timeout,
64 'expires' => $now + $idle_timeout,
65 'expires_max' => $now + $max_length,
69 db_insert_assoc('wfpl_sessions', $row);
70 $session_id = db_auto_id();
71 $GLOBALS['wfpl_session'] = array(
74 'key' => $session_key,
75 'idle_timeout' => $idle_timeout,
76 'expires' => $now + $idle_timeout,
77 'expires_max' => $now + $max_length,
84 function session_set_cookie() {
85 if (session_exists()) {
86 if (!isset($GLOBALS['wfpl_session']['cookie_set'])) {
87 $GLOBALS['wfpl_session']['cookie_set'] = true;
88 header('Set-Cookie: session_key=' . $GLOBALS['wfpl_session']['key'] . '; Path=/');
93 # this is a helper function. See session_new()
94 function session_touch() {
95 if(!session_exists()) {
98 # is the session extendable?
99 if ($GLOBALS['wfpl_session']['expires'] < $GLOBALS['wfpl_session']['expires_max']) {
100 # would this extend the session by at least 10%?
102 $last_activity = $GLOBALS['wfpl_session']['expires'] - $GLOBALS['wfpl_session']['idle_timeout'];
103 # don't db_update if only a tiny fraction of the idle timeout has passed
104 $db_threshold = ceil(0.1 * $GLOBALS['wfpl_session']['idle_timeout']);
105 if ($now > $last_activity + $db_threshold) {
107 $GLOBALS['wfpl_session']['expires_max'],
108 $now + $GLOBALS['wfpl_session']['idle_timeout']
110 db_update('wfpl_sessions', 'expires', $expires, 'where id=%i', $GLOBALS['wfpl_session']['id']);
111 $GLOBALS['wfpl_session']['expires'] = $expires;
116 # delete the current session
117 function kill_session() {
118 if(!session_exists()) {
121 db_delete('wfpl_sessions', 'where id=%i', $GLOBALS['wfpl_session']['id']);
122 $GLOBALS['wfpl_session'] = array('exists' => false);
125 # delete expired sessions from database
126 function session_purge_old() {
127 db_delete('wfpl_sessions', 'where expires < %i', time());
130 # return true if a session exists
131 function session_exists() {
132 if (isset($GLOBALS['wfpl_session'])) {
133 return $GLOBALS['wfpl_session']['exists'];
136 $GLOBALS['wfpl_session'] = array('exists' => false);
138 if(!isset($_COOKIE['session_key'])) {
142 $session_key = preg_replace('|[^a-z0-9]|i', '', $_COOKIE['session_key']);
144 if(!strlen($session_key) == 16) {
148 $row = db_get_assoc('wfpl_sessions', 'id,idle_timeout,expires,expires_max,value', 'where session_key=%"', $session_key);
153 if ($now >= (int) $row['expires']) {
158 $GLOBALS['wfpl_session']['exists'] = true;
159 $GLOBALS['wfpl_session']['id'] = $row['id'];
160 $GLOBALS['wfpl_session']['idle_timeout'] = (int) $row['idle_timeout'];
161 $GLOBALS['wfpl_session']['expires'] = (int) $row['expires'];
162 $GLOBALS['wfpl_session']['expires_max'] = (int) $row['expires_max'];
163 $GLOBALS['wfpl_session']['key'] = $session_key;
165 if (strlen($row['value']) && is_array($parsed = json_decode($row['value'], true))) {
166 $GLOBALS['wfpl_session']['value'] = $parsed;
168 $GLOBALS['wfpl_session']['value'] = array();
171 # mark session as not idle
178 # generate a random password using only letters and numbers that look
179 # particularly unique
180 function new_readable_password($length = 8) {
181 $character_set = "ABCDEFHJKLMNPQRTUWXY34789";
184 # PHP 4.2.0 and up seed the random number generator for you.
185 # Lets hope that it seeds with something harder to guess than the clock.
187 $code .= $character_set{mt_rand(0, 24)}; # inclusive
194 # return username if a session exists and is authenticated
195 function logged_in() {
196 if(!session_exists()) {
200 return session_get('auth_username');
205 function session_exists_and_authed() {
211 # return true if a session exists and is authenticated
212 function logged_in_as_admin() {
213 if(!session_exists()) {
217 if(session_get('auth_admin')) {
224 # find existing session, or make one (name "session_init" was taken)
225 function init_session() {
226 if(!session_exists()) {
231 # internal use only (write session cache to db)
232 function _sync_session() {
233 if (count($GLOBALS['wfpl_session']['value']) > 0) {
234 $value = json_encode($GLOBALS['wfpl_session']['value']);
238 db_update('wfpl_sessions', 'value', $value, 'where id=%i', $GLOBALS['wfpl_session']['id']);
241 # save data into the session
242 # $value can be anything json_encode()able
243 function session_set($name, $value) {
245 if (isset($GLOBALS['wfpl_session']['value'][$name])) {
246 if ($GLOBALS['wfpl_session']['value'][$name] === $value) {
250 $GLOBALS['wfpl_session']['value'][$name] = $value;
254 # save data into the session
255 # values can be anything json_encode()able
256 function session_sets($assoc) {
259 foreach ($assoc as $name => &$value) {
260 if (isset($GLOBALS['wfpl_session']['value'][$name])) {
261 if ($GLOBALS['wfpl_session']['value'][$name] === $value) {
265 $GLOBALS['wfpl_session']['value'][$name] = $value;
273 # remove variable from the session
274 # with no args: clear all
275 function session_clear($name = -1) {
276 if(!session_exists()) {
280 if (count($GLOBALS['wfpl_session']['value']) > 0) {
281 $GLOBALS['wfpl_session']['value'] = array();
284 } elseif (isset($GLOBALS['wfpl_session']['value'][$name])) {
285 unset($GLOBALS['wfpl_session']['value'][$name]);
290 # get a variable into the session
291 function session_get($name) {
292 if(!session_exists()) {
295 if (isset($GLOBALS['wfpl_session']['value'][$name])) {
296 return $GLOBALS['wfpl_session']['value'][$name];