Merge branch 'master' of git://github.com/openemr/openemr
[openemr.git] / library / adodb / session / adodb-session.php
blobc10ddf2a68f9b6f052e063425228b38288305d9e
1 <?php
3 // $CVSHeader$
5 /*
6 V4.01 23 Oct 2003 (c) 2000-2004 John Lim (jlim@natsoft.com.my). All rights reserved.
7 Contributed by Ross Smith (adodb@netebb.com).
8 Released under both BSD license and Lesser GPL library license.
9 Whenever there is any discrepancy between the two licenses,
10 the BSD license will take precedence.
11 Set tabs to 4 for best viewing.
15 You may want to rename the 'data' field to 'session_data' as
16 'data' appears to be a reserved word for one or more of the following:
17 ANSI SQL
18 IBM DB2
19 MS SQL Server
20 Postgres
21 SAP
23 If you do, then execute:
25 ADODB_Session::dataFieldName('session_data');
29 if (!defined('_ADODB_LAYER')) {
30 require_once realpath(dirname(__FILE__) . '/../adodb.inc.php');
33 if (defined('ADODB_SESSION')) return 1;
35 define('ADODB_SESSION', dirname(__FILE__));
37 /*!
38 \static
40 class ADODB_Session {
41 /////////////////////
42 // getter/setter methods
43 /////////////////////
45 /*!
47 function driver($driver = null) {
48 static $_driver = 'mysql';
49 static $set = false;
51 if (!is_null($driver)) {
52 $_driver = trim($driver);
53 $set = true;
54 } elseif (!$set) {
55 // backwards compatibility
56 if (isset($GLOBALS['ADODB_SESSION_DRIVER'])) {
57 return $GLOBALS['ADODB_SESSION_DRIVER'];
61 return $_driver;
64 /*!
66 function host($host = null) {
67 static $_host = 'localhost';
68 static $set = false;
70 if (!is_null($host)) {
71 $_host = trim($host);
72 $set = true;
73 } elseif (!$set) {
74 // backwards compatibility
75 if (isset($GLOBALS['ADODB_SESSION_CONNECT'])) {
76 return $GLOBALS['ADODB_SESSION_CONNECT'];
80 return $_host;
83 /*!
85 function user($user = null) {
86 static $_user = 'root';
87 static $set = false;
89 if (!is_null($user)) {
90 $_user = trim($user);
91 $set = true;
92 } elseif (!$set) {
93 // backwards compatibility
94 if (isset($GLOBALS['ADODB_SESSION_USER'])) {
95 return $GLOBALS['ADODB_SESSION_USER'];
99 return $_user;
104 function password($password = null) {
105 static $_password = '';
106 static $set = false;
108 if (!is_null($password)) {
109 $_password = $password;
110 $set = true;
111 } elseif (!$set) {
112 // backwards compatibility
113 if (isset($GLOBALS['ADODB_SESSION_PWD'])) {
114 return $GLOBALS['ADODB_SESSION_PWD'];
118 return $_password;
123 function database($database = null) {
124 static $_database = 'xphplens_2';
125 static $set = false;
127 if (!is_null($database)) {
128 $_database = trim($database);
129 $set = true;
130 } elseif (!$set) {
131 // backwards compatibility
132 if (isset($GLOBALS['ADODB_SESSION_DB'])) {
133 return $GLOBALS['ADODB_SESSION_DB'];
137 return $_database;
142 function persist($persist = null) {
143 static $_persist = true;
145 if (!is_null($persist)) {
146 $_persist = trim($persist);
149 return $_persist;
154 function lifetime($lifetime = null) {
155 static $_lifetime;
156 static $set = false;
158 if (!is_null($lifetime)) {
159 $_lifetime = (int) $lifetime;
160 $set = true;
161 } elseif (!$set) {
162 // backwards compatibility
163 if (isset($GLOBALS['ADODB_SESS_LIFE'])) {
164 return $GLOBALS['ADODB_SESS_LIFE'];
167 if (!$_lifetime) {
168 $_lifetime = ini_get('session.gc_maxlifetime');
169 if ($_lifetime <= 1) {
170 // bug in PHP 4.0.3 pl 1 -- how about other versions?
171 //print "<h3>Session Error: PHP.INI setting <i>session.gc_maxlifetime</i>not set: $lifetime</h3>";
172 $_lifetime = 1440;
176 return $_lifetime;
181 function debug($debug = null) {
182 static $_debug = false;
183 static $set = false;
185 if (!is_null($debug)) {
186 $_debug = (bool) $debug;
188 $conn = ADODB_Session::_conn();
189 if ($conn) {
190 $conn->debug = $_debug;
192 $set = true;
193 } elseif (!$set) {
194 // backwards compatibility
195 if (isset($GLOBALS['ADODB_SESS_DEBUG'])) {
196 return $GLOBALS['ADODB_SESS_DEBUG'];
200 return $_debug;
205 function expireNotify($expire_notify = null) {
206 static $_expire_notify;
207 static $set = false;
209 if (!is_null($expire_notify)) {
210 $_expire_notify = $expire_notify;
211 $set = true;
212 } elseif (!$set) {
213 // backwards compatibility
214 if (isset($GLOBALS['ADODB_SESSION_EXPIRE_NOTIFY'])) {
215 return $GLOBALS['ADODB_SESSION_EXPIRE_NOTIFY'];
219 return $_expire_notify;
224 function table($table = null) {
225 static $_table = 'sessions';
226 static $set = false;
228 if (!is_null($table)) {
229 $_table = trim($table);
230 $set = true;
231 } elseif (!$set) {
232 // backwards compatibility
233 if (isset($GLOBALS['ADODB_SESSION_TBL'])) {
234 return $GLOBALS['ADODB_SESSION_TBL'];
238 return $_table;
243 function optimize($optimize = null) {
244 static $_optimize = false;
245 static $set = false;
247 if (!is_null($optimize)) {
248 $_optimize = (bool) $optimize;
249 $set = true;
250 } elseif (!$set) {
251 // backwards compatibility
252 if (defined('ADODB_SESSION_OPTIMIZE')) {
253 return true;
257 return $_optimize;
262 function syncSeconds($sync_seconds = null) {
263 static $_sync_seconds = 60;
264 static $set = false;
266 if (!is_null($sync_seconds)) {
267 $_sync_seconds = (int) $sync_seconds;
268 $set = true;
269 } elseif (!$set) {
270 // backwards compatibility
271 if (defined('ADODB_SESSION_SYNCH_SECS')) {
272 return ADODB_SESSION_SYNCH_SECS;
276 return $_sync_seconds;
281 function clob($clob = null) {
282 static $_clob = false;
283 static $set = false;
285 if (!is_null($clob)) {
286 $_clob = strtolower(trim($clob));
287 $set = true;
288 } elseif (!$set) {
289 // backwards compatibility
290 if (isset($GLOBALS['ADODB_SESSION_USE_LOBS'])) {
291 return $GLOBALS['ADODB_SESSION_USE_LOBS'];
295 return $_clob;
300 function dataFieldName($data_field_name = null) {
301 static $_data_field_name = 'data';
303 if (!is_null($data_field_name)) {
304 $_data_field_name = trim($data_field_name);
307 return $_data_field_name;
312 function filter($filter = null) {
313 static $_filter = array();
315 if (!is_null($filter)) {
316 if (!is_array($filter)) {
317 $filter = array($filter);
319 $_filter = $filter;
322 return $_filter;
327 function encryptionKey($encryption_key = null) {
328 static $_encryption_key = 'CRYPTED ADODB SESSIONS ROCK!';
330 if (!is_null($encryption_key)) {
331 $_encryption_key = $encryption_key;
334 return $_encryption_key;
337 /////////////////////
338 // private methods
339 /////////////////////
343 function &_conn($conn=null) {
344 return $GLOBALS['ADODB_SESS_CONN'];
349 function _crc($crc = null) {
350 static $_crc = false;
352 if (!is_null($crc)) {
353 $_crc = $crc;
356 return $_crc;
361 function _init() {
362 session_module_name('user');
363 session_set_save_handler(
364 array('ADODB_Session', 'open'),
365 array('ADODB_Session', 'close'),
366 array('ADODB_Session', 'read'),
367 array('ADODB_Session', 'write'),
368 array('ADODB_Session', 'destroy'),
369 array('ADODB_Session', 'gc')
376 function _sessionKey() {
377 // use this function to create the encryption key for crypted sessions
378 // crypt the used key, ADODB_Session::encryptionKey() as key and session_id() as salt
379 return crypt(ADODB_Session::encryptionKey(), session_id());
384 function _dumprs($rs) {
385 $conn =& ADODB_Session::_conn();
386 $debug = ADODB_Session::debug();
388 if (!$conn) {
389 return;
392 if (!$debug) {
393 return;
396 if (!$rs) {
397 echo "<br />\$rs is null or false<br />\n";
398 return;
401 //echo "<br />\nAffected_Rows=",$conn->Affected_Rows(),"<br />\n";
403 if (!is_object($rs)) {
404 return;
407 require_once ADODB_SESSION.'/../tohtml.inc.php';
408 rs2html($rs);
411 /////////////////////
412 // public methods
413 /////////////////////
416 Create the connection to the database.
418 If $conn already exists, reuse that connection
420 function open($save_path, $session_name, $persist = null) {
421 $conn =& ADODB_Session::_conn();
423 if ($conn) {
424 return true;
427 $database = ADODB_Session::database();
428 $debug = ADODB_Session::debug();
429 $driver = ADODB_Session::driver();
430 $host = ADODB_Session::host();
431 $password = ADODB_Session::password();
432 $user = ADODB_Session::user();
434 if (!is_null($persist)) {
435 $persist = (bool) $persist;
436 ADODB_Session::persist($persist);
437 } else {
438 $persist = ADODB_Session::persist();
441 # these can all be defaulted to in php.ini
442 # assert('$database');
443 # assert('$driver');
444 # assert('$host');
446 // cannot use =& below - do not know why...
447 $conn = ADONewConnection($driver);
449 if ($debug) {
450 $conn->debug = true;
451 // ADOConnection::outp( " driver=$driver user=$user pwd=$password db=$database ");
454 if ($persist) {
455 $ok = $conn->PConnect($host, $user, $password, $database);
456 } else {
457 $ok = $conn->Connect($host, $user, $password, $database);
460 if ($ok) $GLOBALS['ADODB_SESS_CONN'] =& $conn;
461 else
462 ADOConnection::outp('<p>Session: connection failed</p>', false);
465 return $ok;
469 Close the connection
471 function close() {
472 $conn =& ADODB_Session::_conn();
474 if ($conn) {
475 $conn->Close();
478 return true;
482 Slurp in the session variables and return the serialized string
484 function read($key) {
485 $conn =& ADODB_Session::_conn();
486 $data = ADODB_Session::dataFieldName();
487 $filter = ADODB_Session::filter();
488 $table = ADODB_Session::table();
490 if (!$conn) {
491 return '';
494 assert('$table');
496 $qkey = $conn->quote($key);
497 $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
499 $sql = "SELECT $data FROM $table WHERE $binary sesskey = $qkey AND expiry >= " . time();
500 $rs =& $conn->Execute($sql);
501 //ADODB_Session::_dumprs($rs);
502 if ($rs) {
503 if ($rs->EOF) {
504 $v = '';
505 } else {
506 $v = reset($rs->fields);
507 $filter = array_reverse($filter);
508 foreach ($filter as $f) {
509 if (is_object($f)) {
510 $v = $f->read($v, ADODB_Session::_sessionKey());
513 $v = rawurldecode($v);
516 $rs->Close();
518 ADODB_Session::_crc(strlen($v) . crc32($v));
519 return $v;
522 return '';
526 Write the serialized data to a database.
528 If the data has not been modified since the last read(), we do not write.
530 function write($key, $val) {
531 $clob = ADODB_Session::clob();
532 $conn =& ADODB_Session::_conn();
533 $crc = ADODB_Session::_crc();
534 $data = ADODB_Session::dataFieldName();
535 $debug = ADODB_Session::debug();
536 $driver = ADODB_Session::driver();
537 $expire_notify = ADODB_Session::expireNotify();
538 $filter = ADODB_Session::filter();
539 $lifetime = ADODB_Session::lifetime();
540 $table = ADODB_Session::table();
542 if (!$conn) {
543 return false;
546 assert('$table');
548 $expiry = time() + $lifetime;
550 $qkey = $conn->quote($key);
551 $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
553 // crc32 optimization since adodb 2.1
554 // now we only update expiry date, thx to sebastian thom in adodb 2.32
555 if ($crc !== false && $crc == (strlen($val) . crc32($val))) {
556 if ($debug) {
557 echo '<p>Session: Only updating date - crc32 not changed</p>';
559 $sql = "UPDATE $table SET expiry = $expiry WHERE $binary sesskey = $qkey AND expiry >= " . time();
560 $rs =& $conn->Execute($sql);
561 ADODB_Session::_dumprs($rs);
562 if ($rs) {
563 $rs->Close();
565 return true;
567 $val = rawurlencode($val);
568 foreach ($filter as $f) {
569 if (is_object($f)) {
570 $val = $f->write($val, ADODB_Session::_sessionKey());
574 $arr = array('sesskey' => $key, 'expiry' => $expiry, $data => $val, 'expireref' => '');
575 if ($expire_notify) {
576 $var = reset($expire_notify);
577 global $$var;
578 if (isset($$var)) {
579 $arr['expireref'] = $$var;
583 if (!$clob) { // no lobs, simply use replace()
584 $rs = $conn->Replace($table, $arr, 'sesskey', $autoQuote = true);
585 ADODB_Session::_dumprs($rs);
586 } else {
587 // what value shall we insert/update for lob row?
588 switch ($driver) {
589 // empty_clob or empty_lob for oracle dbs
590 case 'oracle':
591 case 'oci8':
592 case 'oci8po':
593 case 'oci805':
594 $lob_value = sprintf('empty_%s()', strtolower($clob));
595 break;
597 // null for all other
598 default:
599 $lob_value = 'null';
600 break;
603 // do we insert or update? => as for sesskey
604 $rs =& $conn->Execute("SELECT COUNT(*) AS cnt FROM $table WHERE $binary sesskey = $qkey");
605 ADODB_Session::_dumprs($rs);
606 if ($rs && reset($rs->fields) > 0) {
607 $sql = "UPDATE $table SET expiry = $expiry, $data = $lob_value WHERE sesskey = $qkey";
608 } else {
609 $sql = "INSERT INTO $table (expiry, $data, sesskey) VALUES ($expiry, $lob_value, $qkey)";
611 if ($rs) {
612 $rs->Close();
615 $err = '';
616 $rs1 =& $conn->Execute($sql);
617 ADODB_Session::_dumprs($rs1);
618 if (!$rs1) {
619 $err = $conn->ErrorMsg()."\n";
621 $rs2 =& $conn->UpdateBlob($table, $data, $val, " sesskey=$qkey", strtoupper($clob));
622 ADODB_Session::_dumprs($rs2);
623 if (!$rs2) {
624 $err .= $conn->ErrorMsg()."\n";
626 $rs = ($rs && $rs2) ? true : false;
627 if ($rs1) {
628 $rs1->Close();
630 if (is_object($rs2)) {
631 $rs2->Close();
635 if (!$rs) {
636 ADOConnection::outp('<p>Session Replace: ' . $conn->ErrorMsg() . '</p>', false);
637 return false;
638 } else {
639 // bug in access driver (could be odbc?) means that info is not committed
640 // properly unless select statement executed in Win2000
641 if ($conn->databaseType == 'access') {
642 $sql = "SELECT sesskey FROM $table WHERE $binary sesskey = $qkey";
643 $rs =& $conn->Execute($sql);
644 ADODB_Session::_dumprs($rs);
645 if ($rs) {
646 $rs->Close();
650 return $rs ? true : false;
655 function destroy($key) {
656 $conn =& ADODB_Session::_conn();
657 $table = ADODB_Session::table();
658 $expire_notify = ADODB_Session::expireNotify();
660 if (!$conn) {
661 return false;
664 assert('$table');
666 $qkey = $conn->quote($key);
667 $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
669 if ($expire_notify) {
670 reset($expire_notify);
671 $fn = next($expire_notify);
672 $savem = $conn->SetFetchMode(ADODB_FETCH_NUM);
673 $sql = "SELECT expireref, sesskey FROM $table WHERE $binary sesskey = $qkey";
674 $rs =& $conn->Execute($sql);
675 ADODB_Session::_dumprs($rs);
676 $conn->SetFetchMode($savem);
677 if (!$rs) {
678 return false;
680 if (!$rs->EOF) {
681 $ref = $rs->fields[0];
682 $key = $rs->fields[1];
683 assert('$ref');
684 assert('$key');
685 $fn($ref, $key);
687 $rs->Close();
690 $sql = "DELETE FROM $table WHERE $binary sesskey = $qkey";
691 $rs =& $conn->Execute($sql);
692 ADODB_Session::_dumprs($rs);
693 if ($rs) {
694 $rs->Close();
697 return $rs ? true : false;
702 function gc($maxlifetime) {
703 $conn =& ADODB_Session::_conn();
704 $debug = ADODB_Session::debug();
705 $expire_notify = ADODB_Session::expireNotify();
706 $optimize = ADODB_Session::optimize();
707 $sync_seconds = ADODB_Session::syncSeconds();
708 $table = ADODB_Session::table();
710 if (!$conn) {
711 return false;
714 assert('$table');
716 $time = time();
718 $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
720 if ($expire_notify) {
721 reset($expire_notify);
722 $fn = next($expire_notify);
723 $savem = $conn->SetFetchMode(ADODB_FETCH_NUM);
724 $sql = "SELECT expireref, sesskey FROM $table WHERE expiry < $time";
725 $rs =& $conn->Execute($sql);
726 ADODB_Session::_dumprs($rs);
727 $conn->SetFetchMode($savem);
728 if ($rs) {
729 $conn->BeginTrans();
730 $keys = array();
731 while (!$rs->EOF) {
732 $ref = $rs->fields[0];
733 $key = $rs->fields[1];
734 $fn($ref, $key);
735 $del = $conn->Execute("DELETE FROM $table WHERE sesskey='$key'");
736 $rs->MoveNext();
738 $rs->Close();
740 $conn->CommitTrans();
742 } else {
743 $sql = "DELETE FROM $table WHERE expiry < $time";
744 $rs =& $conn->Execute($sql);
745 ADODB_Session::_dumprs($rs);
746 if ($rs) {
747 $rs->Close();
749 if ($debug) {
750 ADOConnection::outp("<p><b>Garbage Collection</b>: $sql</p>");
754 // suggested by Cameron, "GaM3R" <gamr@outworld.cx>
755 if ($optimize) {
756 $driver = ADODB_Session::driver();
758 if (preg_match('/mysql/i', $driver)) {
759 $sql = "OPTIMIZE TABLE $table";
761 if (preg_match('/postgres/i', $driver)) {
762 $sql = "VACUUM $table";
764 if (!empty($sql)) {
765 $conn->Execute($sql);
769 if ($sync_seconds) {
770 $sql = 'SELECT ';
771 if ($conn->dataProvider === 'oci8') {
772 $sql .= "TO_CHAR({$conn->sysTimeStamp}, 'RRRR-MM-DD HH24:MI:SS')";
773 } else {
774 $sql .= $conn->sysTimeStamp;
776 $sql .= " FROM $table";
778 $rs =& $conn->SelectLimit($sql, 1);
779 if ($rs && !$rs->EOF) {
780 $dbts = reset($rs->fields);
781 $rs->Close();
782 $dbt = $conn->UnixTimeStamp($dbts);
783 $t = time();
785 if (abs($dbt - $t) >= $sync_seconds) {
786 global $HTTP_SERVER_VARS;
787 $msg = __FILE__ .
788 ": Server time for webserver {$HTTP_SERVER_VARS['HTTP_HOST']} not in synch with database: " .
789 " database=$dbt ($dbts), webserver=$t (diff=". (abs($dbt - $t) / 3600) . ' hours)';
790 error_log($msg);
791 if ($debug) {
792 ADOConnection::outp("<p>$msg</p>");
798 return true;
803 ADODB_Session::_init();
806 // for backwards compatability only
807 function adodb_sess_open($save_path, $session_name, $persist = true) {
808 return ADODB_Session::open($save_path, $session_name, $persist);
811 // for backwards compatability only
812 function adodb_sess_gc($t)
814 return ADODB_Session::gc($t);