3 # Copyright (C) 2006 Jason Woofenden
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 # The functions in this file assume that you have this database table:
20 # drop table if exists wfpl_sessions;
21 # create table wfpl_sessions (
22 # id int unique auto_increment,
23 # session_key varchar(16),
30 # You'll want to use these:
33 # session_new('timeout', 'max_len')
34 # session_set('key', 'value')
35 # session_sets(['key': 'value', 'key2': 'val2'])
37 # session_clear() # removes all set() values
38 # session_clear('key')
41 # All session data is cached in globals, so:
42 # 1. don't set large amonuts of data
43 # 2. session_get() is very fast (no db access)
46 # generate a new random 16-character string
47 function session_generate_key() {
48 $character_set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
51 # PHP 4.2.0 and up seed the random number generator for you.
52 # Lets hope that it seeds with something harder to guess than the clock.
53 for($i = 0; $i < 16; ++$i) {
54 $id{$i} = $character_set{mt_rand(0, 61)};
60 # start a new session, tracked by a browser "session cookie".
63 # $idle_timeout (seconds) session ends after this much inactivity (or up to 10% less)
64 # $max_length (seconds) session ends after this long, regardless of activity
65 function session_new($idle_timeout = 129600 /* 36 hours */, $max_length = 604800 /* 1 week */) {
68 $session_key = session_generate_key();
72 'session_key' => $session_key,
73 'idle_timeout' => $idle_timeout,
74 'expires' => $now + $idle_timeout,
75 'expires_max' => $now + $max_length,
79 db_insert_assoc('wfpl_sessions', $row);
80 $session_id = db_auto_id();
81 $GLOBALS['wfpl_session'] = array(
84 'key' => $session_key,
85 'idle_timeout' => $idle_timeout,
86 'expires' => $now + $idle_timeout,
87 'expires_max' => $now + $max_length,
94 function session_set_cookie() {
95 if (session_exists()) {
96 if (!isset($GLOBALS['wfpl_session']['cookie_set'])) {
97 $GLOBALS['wfpl_session']['cookie_set'] = true;
98 header('Set-Cookie: session_key=' . $GLOBALS['wfpl_session']['key'] . '; Path=/');
103 # this is a helper function. See session_new()
104 function session_touch() {
105 if(!session_exists()) {
108 # is the session extendable?
109 if ($GLOBALS['wfpl_session']['expires'] < $GLOBALS['wfpl_session']['expires_max']) {
110 # would this extend the session by at least 10%?
112 $last_activity = $GLOBALS['wfpl_session']['expires'] - $GLOBALS['wfpl_session']['idle_timeout'];
113 # don't db_update if only a tiny fraction of the idle timeout has passed
114 $db_threshold = ceil(0.1 * $GLOBALS['wfpl_session']['idle_timeout']);
115 if ($now > $last_activity + $db_threshold) {
117 $GLOBALS['wfpl_session']['expires_max'],
118 $now + $GLOBALS['wfpl_session']['idle_timeout']
120 db_update('wfpl_sessions', 'expires', $expires, 'where id=%i', $GLOBALS['wfpl_session']['id']);
121 $GLOBALS['wfpl_session']['expires'] = $expires;
126 # delete the current session
127 function kill_session() {
128 if(!session_exists()) {
131 db_delete('wfpl_sessions', 'where id=%i', $GLOBALS['wfpl_session']['id']);
132 $GLOBALS['wfpl_session'] = array('exists' => false);
135 # delete expired sessions from database
136 function session_purge_old() {
137 db_delete('wfpl_sessions', 'where expires < %i', time());
140 # return true if a session exists
141 function session_exists() {
142 if (isset($GLOBALS['wfpl_session'])) {
143 return $GLOBALS['wfpl_session']['exists'];
146 $GLOBALS['wfpl_session'] = array('exists' => false);
148 if(!isset($_COOKIE['session_key'])) {
152 $session_key = ereg_replace('[^a-zA-Z0-9]', '', $_COOKIE['session_key']);
154 if(!strlen($session_key) == 16) {
158 $row = db_get_assoc('wfpl_sessions', 'id,idle_timeout,expires,expires_max,value', 'where session_key=%"', $session_key);
163 if ($now >= (int) $row['expires']) {
168 $GLOBALS['wfpl_session']['exists'] = true;
169 $GLOBALS['wfpl_session']['id'] = $row['id'];
170 $GLOBALS['wfpl_session']['idle_timeout'] = (int) $row['idle_timeout'];
171 $GLOBALS['wfpl_session']['expires'] = (int) $row['expires'];
172 $GLOBALS['wfpl_session']['expires_max'] = (int) $row['expires_max'];
173 $GLOBALS['wfpl_session']['key'] = $session_key;
175 if (strlen($row['value']) && is_array($parsed = json_decode($row['value'], true))) {
176 $GLOBALS['wfpl_session']['value'] = $parsed;
178 $GLOBALS['wfpl_session']['value'] = array();
181 # mark session as not idle
188 # generate a random password using only letters and numbers that look
189 # particularly unique
190 function new_readable_password($length = 8) {
191 $character_set = "ABCDEFHJKLMNPQRTUWXY34789";
194 # PHP 4.2.0 and up seed the random number generator for you.
195 # Lets hope that it seeds with something harder to guess than the clock.
197 $code .= $character_set{mt_rand(0, 24)}; # inclusive
204 # return username if a session exists and is authenticated
205 function logged_in() {
206 if(!session_exists()) {
210 return session_get('auth_username');
215 function session_exists_and_authed() {
221 # return true if a session exists and is authenticated
222 function logged_in_as_admin() {
223 if(!session_exists()) {
227 if(session_get('auth_admin')) {
234 # find existing session, or make one (name "session_init" was taken)
235 function init_session() {
236 if(!session_exists()) {
241 # internal use only (write session cache to db)
242 function _sync_session() {
243 if (count($GLOBALS['wfpl_session']['value']) > 0) {
244 $value = json_encode($GLOBALS['wfpl_session']['value']);
248 db_update('wfpl_sessions', 'value', $value, 'where id=%i', $GLOBALS['wfpl_session']['id']);
251 # save data into the session
252 # $value can be anything json_encode()able
253 function session_set($name, $value) {
255 if (isset($GLOBALS['wfpl_session']['value'][$name])) {
256 if ($GLOBALS['wfpl_session']['value'][$name] === $value) {
260 $GLOBALS['wfpl_session']['value'][$name] = $value;
264 # save data into the session
265 # values can be anything json_encode()able
266 function session_sets($assoc) {
269 foreach ($assoc as $name => &$value) {
270 if (isset($GLOBALS['wfpl_session']['value'][$name])) {
271 if ($GLOBALS['wfpl_session']['value'][$name] === $value) {
275 $GLOBALS['wfpl_session']['value'][$name] = $value;
283 # remove variable from the session
284 # with no args: clear all
285 function session_clear($name = -1) {
286 if(!session_exists()) {
290 if (count($GLOBALS['wfpl_session']['value']) > 0) {
291 $GLOBALS['wfpl_session']['value'] = array();
294 } elseif (isset($GLOBALS['wfpl_session']['value'][$name])) {
295 unset($GLOBALS['wfpl_session']['value'][$name]);
300 # get a variable into the session
301 function session_get($name) {
302 if(!session_exists()) {
305 if (isset($GLOBALS['wfpl_session']['value'][$name])) {
306 return $GLOBALS['wfpl_session']['value'][$name];