3 * Copyright 2005 $ThePhpWikiProgrammingTeam
5 * This file is part of PhpWiki.
7 * PhpWiki is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * PhpWiki is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 * ADODB db sessions, based on pear DB Sessions.
25 * @author: Reini Urban
30 public $_backend_type = "ADODB";
32 function __construct($dbh, $table)
35 $this->_table = $table;
37 ini_set('session.save_handler', 'user');
38 session_module_name('user'); // new style
39 session_set_save_handler(array(&$this, 'open'),
40 array(&$this, 'close'),
41 array(&$this, 'read'),
42 array(&$this, 'write'),
43 array(&$this, 'destroy'),
50 static $parsed = false;
52 if (!$dbh or !is_resource($dbh->_connectionID)) {
53 if (!$parsed) $parsed = parseDSN($request->_dbi->getParam('dsn'));
54 $this->_dbh =& ADONewConnection($parsed['phptype']); // Probably only MySql works just now
55 $this->_dbh->Connect($parsed['hostspec'], $parsed['username'],
56 $parsed['password'], $parsed['database']);
64 return $this->_dbh->Execute($sql);
67 function quote($string)
69 return $this->_dbh->qstr($string);
72 function _disconnect()
74 if (0 and $this->_dbh)
81 * Actually this function is a fake for session_set_save_handle.
82 * @param string $save_path a path to stored files
83 * @param string $session_name a name of the concrete file
84 * @return boolean true just a variable to notify PHP that everything
87 public function open($save_path, $session_name)
89 //$this->log("_open($save_path, $session_name)");
96 * This function is called just after <i>write</i> call.
98 * @return boolean true just a variable to notify PHP that everything
101 public function close()
103 //$this->log("_close()");
108 * Reads the session data from DB.
110 * @param string $id an id of current session
113 public function read($id)
115 //$this->log("_read($id)");
116 $dbh = $this->_connect();
117 $table = $this->_table;
118 $qid = $dbh->qstr($id);
120 $row = $dbh->GetRow("SELECT sess_data FROM $table WHERE sess_id=$qid");
123 $this->_disconnect();
124 if (!empty($res) and preg_match('|^[a-zA-Z0-9/+=]+$|', $res))
125 $res = base64_decode($res);
126 if (strlen($res) > 4000) {
127 trigger_error("Overlarge session data! " . strlen($res) .
128 " gt. 4000", E_USER_WARNING);
129 $res = preg_replace('/s:6:"_cache";O:12:"WikiDB_cache".+}$/', "", $res);
130 $res = preg_replace('/s:12:"_cached_html";s:.+",s:4:"hits"/', 's:4:"hits"', $res);
131 if (strlen($res) > 4000) $res = '';
137 * Saves the session data into DB.
139 * Just a comment: The "write" handler is not
140 * executed until after the output stream is closed. Thus,
141 * output from debugging statements in the "write" handler
142 * will never be seen in the browser. If debugging output
143 * is necessary, it is suggested that the debug output be
144 * written to a file instead.
147 * @param string $sess_data
148 * @return boolean true if data saved successfully and false
151 public function write($id, $sess_data)
153 if (defined("WIKI_XMLRPC") or defined("WIKI_SOAP")) return false;
155 $dbh = $this->_connect();
156 $table = $this->_table;
157 $qid = $dbh->qstr($id);
158 $qip = $dbh->qstr($GLOBALS['request']->get('REMOTE_ADDR'));
159 $time = $dbh->qstr(time());
161 // postgres can't handle binary data in a TEXT field.
162 if (isa($dbh, 'ADODB_postgres64'))
163 $sess_data = base64_encode($sess_data);
164 $qdata = $dbh->qstr($sess_data);
166 /* AffectedRows with sessions seems to be instable on certain platforms.
167 * Enable the safe and slow USE_SAFE_DBSESSION then.
169 if (USE_SAFE_DBSESSION) {
170 $dbh->Execute("DELETE FROM $table"
171 . " WHERE sess_id=$qid");
172 $rs = $dbh->Execute("INSERT INTO $table"
173 . " (sess_id, sess_data, sess_date, sess_ip)"
174 . " VALUES ($qid, $qdata, $time, $qip)");
176 $rs = $dbh->Execute("UPDATE $table"
177 . " SET sess_data=$qdata, sess_date=$time, sess_ip=$qip"
178 . " WHERE sess_id=$qid");
179 $result = $dbh->Affected_Rows();
180 if ($result === false or $result < 1) { // false or int > 0
181 $rs = $dbh->Execute("INSERT INTO $table"
182 . " (sess_id, sess_data, sess_date, sess_ip)"
183 . " VALUES ($qid, $qdata, $time, $qip)");
187 if ($result) $rs->free();
188 $this->_disconnect();
193 * Destroys a session.
195 * Removes a session from the table.
198 * @return boolean true
200 public function destroy($id)
202 $dbh = $this->_connect();
203 $table = $this->_table;
204 $qid = $dbh->qstr($id);
206 $dbh->Execute("DELETE FROM $table WHERE sess_id=$qid");
208 $this->_disconnect();
213 * Cleans out all expired sessions.
215 * @param int $maxlifetime session's time to live.
216 * @return boolean true
218 public function gc($maxlifetime)
220 $dbh = $this->_connect();
221 $table = $this->_table;
222 $threshold = time() - $maxlifetime;
224 $dbh->Execute("DELETE FROM $table WHERE sess_date < $threshold");
226 $this->_disconnect();
230 // WhoIsOnline support.
231 // TODO: ip-accesstime dynamic blocking API
232 function currentSessions()
235 $dbh = $this->_connect();
236 $table = $this->_table;
237 $rs = $dbh->Execute("SELECT sess_data,sess_date,sess_ip FROM $table ORDER BY sess_date DESC");
243 $row = $rs->fetchRow();
247 if (preg_match('|^[a-zA-Z0-9/+=]+$|', $data))
248 $data = base64_decode($data);
249 if ($date < 908437560 or $date > 1588437560)
251 // session_data contains the <variable name> + "|" + <packed string>
252 // we need just the wiki_user object (might be array as well)
253 $user = strstr($data, "wiki_user|");
254 $sessions[] = array('wiki_user' => substr($user, 10), // from "O:" onwards
260 $this->_disconnect();
269 // c-hanging-comment-ender-p: nil
270 // indent-tabs-mode: nil