1 <?php rcs_id('$Id: DbSession.php,v 1.8 2004-04-02 15:06:55 rurban Exp $');
4 * Store sessions data in Pear DB / ADODB ....
8 * Originally by Stanislav Shramko <stanis@movingmail.com>
9 * Minor rewrite by Reini Urban <rurban@x-ray.at> for Phpwiki.
10 * Quasi-major rewrite/decruft/fix by Jeff Dairiki <dairiki@dairiki.org>.
19 * Pear DB handle, or WikiDB object (from which the Pear DB handle will
22 * @param string $table
23 * Name of SQL table containing session data.
25 function DB_Session(&$dbh, $table = 'session') {
26 // Coerce WikiDB to PearDB or ADODB.
27 // Todo: adodb/dba handlers
28 $db_type = $GLOBALS['DBParams']['dbtype'];
29 if (isa($dbh, 'WikiDB')) {
30 $backend = &$dbh->_backend;
31 $db_type = substr(get_class($dbh),7);
32 $class = "DB_Session_".$db_type;
33 if (class_exists($class)) {
34 $this->_backend = new $class(&$backend->_dbh, $table);
35 return $this->_backend;
40 //Fixme: E_USER_WARNING ignored!
41 trigger_error(sprintf(
42 _("Your WikiDB DB backend '%s' cannot be used for DB_Session. Set USE_DB_SESSION to false."),
43 $db_type), E_USER_WARNING);
46 function currentSessions() {
47 return $this->_backend->currentSessions();
49 function query($sql) {
50 return $this->_backend->query($sql);
52 function quote($string) {
53 return $this->_backend->quote($string);
61 var $_backend_type = "SQL";
63 function DB_Session_SQL ($dbh, $table) {
66 $this->_table = $table;
68 ini_set('session.save_handler','user');
69 session_module_name('user'); // new style
70 session_set_save_handler(array(&$this, 'open'),
71 array(&$this, 'close'),
72 array(&$this, 'read'),
73 array(&$this, 'write'),
74 array(&$this, 'destroy'),
81 $this->_connected = (bool)$dbh->connection;
82 if (!$this->_connected) {
83 $res = $dbh->connect($dbh->dsn);
84 if (DB::isError($res)) {
85 error_log("PhpWiki::DB_Session::_connect: " . $res->getMessage());
91 function query($sql) {
92 return $this->_dbh->query($sql);
95 function quote($string) {
96 return $this->_dbh->quote($string);
99 function _disconnect() {
100 if (!$this->_connected)
101 $this->_dbh->disconnect();
107 * Actually this function is a fake for session_set_save_handle.
108 * @param string $save_path a path to stored files
109 * @param string $session_name a name of the concrete file
110 * @return boolean true just a variable to notify PHP that everything
114 function open ($save_path, $session_name) {
115 //$this->log("_open($save_path, $session_name)");
122 * This function is called just after <i>write</i> call.
124 * @return boolean true just a variable to notify PHP that everything
129 //$this->log("_close()");
134 * Reads the session data from DB.
136 * @param string $id an id of current session
140 function read ($id) {
141 //$this->log("_read($id)");
142 $dbh = &$this->_connect();
143 $table = $this->_table;
144 $qid = $dbh->quote($id);
146 $res = $dbh->getOne("SELECT sess_data FROM $table WHERE sess_id=$qid");
148 $this->_disconnect();
149 if (DB::isError($res) || empty($res))
151 if (preg_match('|^[a-zA-Z0-9/+=]+$|', $res))
152 $res = base64_decode($res);
157 * Saves the session data into DB.
159 * Just a comment: The "write" handler is not
160 * executed until after the output stream is closed. Thus,
161 * output from debugging statements in the "write" handler
162 * will never be seen in the browser. If debugging output
163 * is necessary, it is suggested that the debug output be
164 * written to a file instead.
167 * @param string $sess_data
168 * @return boolean true if data saved successfully and false
172 function write ($id, $sess_data) {
174 $dbh = &$this->_connect();
175 $table = $this->_table;
176 $qid = $dbh->quote($id);
179 // postgres can't handle binary data in a TEXT field.
180 if (isa($dbh, 'DB_pgsql'))
181 $sess_data = base64_encode($sess_data);
182 $qdata = $dbh->quote($sess_data);
184 $res = $dbh->query("UPDATE $table"
185 . " SET sess_data=$qdata, sess_date=$time"
186 . " WHERE sess_id=$qid");
188 if ($dbh->affectedRows() == 0)
189 $res = $dbh->query("INSERT INTO $table"
190 . " (sess_id, sess_data, sess_date)"
191 . " VALUES ($qid, $qdata, $time)");
193 $this->_disconnect();
194 return ! DB::isError($res);
198 * Destroys a session.
200 * Removes a session from the table.
203 * @return boolean true
206 function destroy ($id) {
207 $dbh = &$this->_connect();
208 $table = $this->_table;
209 $qid = $dbh->quote($id);
211 $dbh->query("DELETE FROM $table WHERE sess_id=$qid");
213 $this->_disconnect();
218 * Cleans out all expired sessions.
220 * @param int $maxlifetime session's time to live.
221 * @return boolean true
224 function gc ($maxlifetime) {
225 $dbh = &$this->_connect();
226 $table = $this->_table;
227 $threshold = time() - $maxlifetime;
229 $dbh->query("DELETE FROM $table WHERE sess_date < $threshold");
231 $this->_disconnect();
235 // WhoIsOnline support
236 function currentSessions() {
238 $dbh = &$this->_connect();
239 $table = $this->_table;
240 $res = $this->query("SELECT sess_data,sess_date FROM $table ORDER BY sess_date DESC");
241 if (DB::isError($res) || empty($res))
243 while ($row = $res->fetchRow()) {
244 $data = $row['sess_data'];
245 $date = $row['sess_date'];
246 if (preg_match('|^[a-zA-Z0-9/+=]+$|', $data))
247 $data = base64_decode($data);
248 // session_data contains the <variable name> + "|" + <packed string>
249 // we need just the wiki_user object (might be array as well)
250 $user = strstr($data,"wiki_user|");
251 $sessions[] = array('wiki_user' => substr($user,10), // from "O:" onwards
254 $this->_disconnect();
260 // self-written adodb-sessions
261 class DB_Session_ADODB
264 var $_backend_type = "ADODB";
266 function DB_Session_ADODB ($dbh, $table) {
269 $this->_table = $table;
271 ini_set('session.save_handler','user');
272 session_module_name('user'); // new style
273 session_set_save_handler(array(&$this, 'open'),
274 array(&$this, 'close'),
275 array(&$this, 'read'),
276 array(&$this, 'write'),
277 array(&$this, 'destroy'),
278 array(&$this, 'gc'));
282 function _connect() {
284 static $parsed = false;
287 if (!$parsed) $parsed = parseDSN($DBParams['dsn']);
288 $this->_dbh = &ADONewConnection($parsed['phptype']); // Probably only MySql works just now
289 $conn = $this->_dbh->Connect($parsed['hostspec'],$parsed['username'],
290 $parsed['password'], $parsed['database']);
296 function query($sql) {
297 return $this->_dbh->Execute($sql);
300 function quote($string) {
301 return $this->_dbh->qstr($string);
304 function _disconnect() {
306 $this->_dbh->close();
312 * Actually this function is a fake for session_set_save_handle.
313 * @param string $save_path a path to stored files
314 * @param string $session_name a name of the concrete file
315 * @return boolean true just a variable to notify PHP that everything
319 function open ($save_path, $session_name) {
320 //$this->log("_open($save_path, $session_name)");
327 * This function is called just after <i>write</i> call.
329 * @return boolean true just a variable to notify PHP that everything
334 //$this->log("_close()");
339 * Reads the session data from DB.
341 * @param string $id an id of current session
345 function read ($id) {
346 //$this->log("_read($id)");
347 $dbh = &$this->_connect();
348 $table = $this->_table;
349 $qid = $dbh->quote($id);
351 $rs = $dbh->Execute("SELECT sess_data FROM $table WHERE sess_id=$qid");
353 $res = $rs->fields["sess_data"];
355 $this->_disconnect();
356 if (!empty($res) and preg_match('|^[a-zA-Z0-9/+=]+$|', $res))
357 $res = base64_decode($res);
362 * Saves the session data into DB.
364 * Just a comment: The "write" handler is not
365 * executed until after the output stream is closed. Thus,
366 * output from debugging statements in the "write" handler
367 * will never be seen in the browser. If debugging output
368 * is necessary, it is suggested that the debug output be
369 * written to a file instead.
372 * @param string $sess_data
373 * @return boolean true if data saved successfully and false
377 function write ($id, $sess_data) {
379 $dbh = &$this->_connect();
380 $table = $this->_table;
381 $qid = $dbh->quote($id);
384 // postgres can't handle binary data in a TEXT field.
385 if (isa($dbh, 'DB_pgsql'))
386 $sess_data = base64_encode($sess_data);
387 $qdata = $dbh->quote($sess_data);
388 $res = $dbh->query("UPDATE $table"
389 . " SET sess_data=$qdata, sess_date=$time"
390 . " WHERE sess_id=$qid");
391 // Warning: This works only only adodb_mysql!
392 // The parent class adodb needs ->AffectedRows()
393 if (!$dbh->_AffectedRows())
394 $res = $dbh->query("INSERT INTO $table"
395 . " (sess_id, sess_data, sess_date)"
396 . " VALUES ($qid, $qdata, $time)");
397 $this->_disconnect();
402 * Destroys a session.
404 * Removes a session from the table.
407 * @return boolean true
410 function destroy ($id) {
411 $dbh = &$this->_connect();
412 $table = $this->_table;
413 $qid = $dbh->quote($id);
415 $dbh->query("DELETE FROM $table WHERE sess_id=$qid");
417 $this->_disconnect();
422 * Cleans out all expired sessions.
424 * @param int $maxlifetime session's time to live.
425 * @return boolean true
428 function gc ($maxlifetime) {
429 $dbh = &$this->_connect();
430 $table = $this->_table;
431 $threshold = time() - $maxlifetime;
433 $dbh->query("DELETE FROM $table WHERE sess_date < $threshold");
435 $this->_disconnect();
439 // WhoIsOnline support
440 function currentSessions() {
442 $dbh = &$this->_connect();
443 $table = $this->_table;
444 $rs = $this->query("SELECT sess_data,sess_date FROM $table ORDER BY sess_date DESC");
448 while ($row = $rs->fetchRow()) {
449 $data = $row['sess_data'];
450 $date = $row['sess_date'];
451 if (preg_match('|^[a-zA-Z0-9/+=]+$|', $data))
452 $data = base64_decode($data);
453 // session_data contains the <variable name> + "|" + <packed string>
454 // we need just the wiki_user object (might be array as well)
455 $user = strstr($data,"wiki_user|");
456 $sessions[] = array('wiki_user' => substr($user,10), // from "O:" onwards
459 $this->_disconnect();
469 // c-hanging-comment-ender-p: nil
470 // indent-tabs-mode: nil