1 <?php rcs_id('$Id: PDO.php,v 1.2 2006-02-22 20:56:24 rurban Exp $');
4 * Db sessions for PDO, based on pear DB Sessions.
11 var $_backend_type = "PDO";
13 function DbSession_PDO ($dbh, $table) {
16 $this->_table = $table;
18 ini_set('session.save_handler','user');
19 session_module_name('user'); // new style
20 session_set_save_handler(array(&$this, 'open'),
21 array(&$this, 'close'),
22 array(&$this, 'read'),
23 array(&$this, 'write'),
24 array(&$this, 'destroy'),
29 function & _connect() {
31 if (!$dbh or !is_object($dbh)) {
33 $db = new WikiDB_backend_PDO($DBParams);
34 $this->_dbh =& $db->_dbh;
35 $this->_backend =& $db;
40 function query($sql) {
41 return $this->_backend->query($sql);
44 function quote($string) {
45 return $this->_backend->quote($sql);
48 function _disconnect() {
49 if (0 and $this->_dbh)
56 * Actually this function is a fake for session_set_save_handle.
57 * @param string $save_path a path to stored files
58 * @param string $session_name a name of the concrete file
59 * @return boolean true just a variable to notify PHP that everything
63 function open ($save_path, $session_name) {
64 //$this->log("_open($save_path, $session_name)");
71 * This function is called just after <i>write</i> call.
73 * @return boolean true just a variable to notify PHP that everything
78 //$this->log("_close()");
83 * Reads the session data from DB.
85 * @param string $id an id of current session
90 //$this->log("_read($id)");
91 $dbh = $this->_connect();
92 $table = $this->_table;
93 $sth = $dbh->prepare("SELECT sess_data FROM $table WHERE sess_id=?");
94 $sth->bindParam(1, $id, PDO_PARAM_STR, 32);
95 if ($sth->execute()) $res = $sth->fetchSingle();
98 if (!empty($res) and isa($dbh, 'ADODB_postgres64'))
99 $res = base64_decode($res);
100 if (strlen($res) > 4000) {
101 trigger_error("Overlarge session data! ".strlen($res).
102 " gt. 4000", E_USER_WARNING);
103 $res = preg_replace('/s:6:"_cache";O:12:"WikiDB_cache".+}$/',"",$res);
104 $res = preg_replace('/s:12:"_cached_html";s:.+",s:4:"hits"/','s:4:"hits"',$res);
105 if (strlen($res) > 4000) $res = '';
111 * Saves the session data into DB.
113 * Just a comment: The "write" handler is not
114 * executed until after the output stream is closed. Thus,
115 * output from debugging statements in the "write" handler
116 * will never be seen in the browser. If debugging output
117 * is necessary, it is suggested that the debug output be
118 * written to a file instead.
121 * @param string $sess_data
122 * @return boolean true if data saved successfully and false
126 function write ($id, $sess_data) {
128 $dbh = $this->_connect();
129 $table = $this->_table;
132 // postgres can't handle binary data in a TEXT field.
133 if (isa($dbh, 'ADODB_postgres64'))
134 $sess_data = base64_encode($sess_data);
136 /* AffectedRows with sessions seems to be instable on certain platforms.
137 * Enable the safe and slow USE_SAFE_DBSESSION then.
139 if (USE_SAFE_DBSESSION) {
140 $this->_backend->beginTransaction();
141 $rs = $this->query("DELETE FROM $table"
142 . " WHERE sess_id=$qid");
143 $sth = $dbh->prepare("INSERT INTO $table"
144 . " (sess_id, sess_data, sess_date, sess_ip)"
145 . " VALUES (?, ?, ?, ?)");
146 $sth->bindParam(1, $id, PDO_PARAM_STR, 32);
147 $sth->bindParam(2, $sess_data, PDO_PARAM_LOB);
148 $sth->bindParam(3, $time, PDO_PARAM_INT);
149 $sth->bindParam(4, $GLOBALS['request']->get('REMOTE_ADDR'), PDO_PARAM_STR, 15);
150 if ($result = $sth->execute()) {
151 $this->_backend->commit();
153 $this->_backend->rollBack();
156 $sth = $dbh->prepare("UPDATE $table"
157 . " SET sess_data=?, sess_date=?, sess_ip=?"
158 . " WHERE sess_id=?");
159 $sth->bindParam(1, $sess_data, PDO_PARAM_LOB);
160 $sth->bindParam(2, $time, PDO_PARAM_INT);
161 $sth->bindParam(3, $GLOBALS['request']->get('REMOTE_ADDR'), PDO_PARAM_STR, 15);
162 $sth->bindParam(4, $id, PDO_PARAM_STR, 32);
163 $result = $sth->execute(); // implicit affected rows
164 if ( $result === false or $result < 1 ) { // false or int > 0
165 $sth = $dbh->prepare("INSERT INTO $table"
166 . " (sess_id, sess_data, sess_date, sess_ip)"
167 . " VALUES (?, ?, ?, ?)");
168 $sth->bindParam(1, $id, PDO_PARAM_STR, 32);
169 $sth->bindParam(2, $sess_data, PDO_PARAM_LOB);
170 $sth->bindParam(3, $time, PDO_PARAM_INT);
171 $sth->bindParam(4, $GLOBALS['request']->get('REMOTE_ADDR'), PDO_PARAM_STR, 15);
172 $result = $sth->execute();
175 $this->_disconnect();
180 * Destroys a session.
182 * Removes a session from the table.
185 * @return boolean true
188 function destroy ($id) {
189 $table = $this->_table;
190 $dbh = $this->_connect();
191 $sth = $dbh->prepare("DELETE FROM $table WHERE sess_id=?");
192 $sth->bindParam(1, $id, PDO_PARAM_STR, 32);
194 $this->_disconnect();
199 * Cleans out all expired sessions.
201 * @param int $maxlifetime session's time to live.
202 * @return boolean true
205 function gc ($maxlifetime) {
206 $table = $this->_table;
207 $threshold = time() - $maxlifetime;
208 $dbh = $this->_connect();
209 $sth = $dbh->prepare("DELETE FROM $table WHERE sess_date < ?");
210 $sth->bindParam(1, $threshold, PDO_PARAM_INT);
212 $this->_disconnect();
216 // WhoIsOnline support.
217 // TODO: ip-accesstime dynamic blocking API
218 function currentSessions() {
220 $table = $this->_table;
221 $dbh = $this->_connect();
222 $sth = $dbh->prepare("SELECT sess_data,sess_date,sess_ip FROM $table ORDER BY sess_date DESC");
223 if (!$sth->execute()) {
226 while ($row = $sth->fetch(PDO_FETCH_NUM)) {
230 if (preg_match('|^[a-zA-Z0-9/+=]+$|', $data))
231 $data = base64_decode($data);
232 if ($date < 908437560 or $date > 1588437560)
234 // session_data contains the <variable name> + "|" + <packed string>
235 // we need just the wiki_user object (might be array as well)
236 $user = strstr($data, "wiki_user|");
237 $sessions[] = array('wiki_user' => substr($user,10), // from "O:" onwards
241 $this->_disconnect();
246 // $Log: not supported by cvs2svn $
247 // Revision 1.1 2005/02/11 14:41:40 rurban
248 // seperate DbSession classes: less memory, a bit slower
255 // c-hanging-comment-ender-p: nil
256 // indent-tabs-mode: nil