]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/DbSession/PDO.php
Remove history
[SourceForge/phpwiki.git] / lib / DbSession / PDO.php
1 <?php rcs_id('$Id$');
2
3 /** 
4  * Db sessions for PDO, based on pear DB Sessions.
5  *
6  * @author: Reini Urban
7  */
8 class DbSession_PDO
9 extends DbSession
10 {
11     var $_backend_type = "PDO";
12
13     function DbSession_PDO ($dbh, $table) {
14
15         $this->_dbh = $dbh;
16         $this->_table = $table;
17
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'),
25                                  array(&$this, 'gc'));
26         return $this;
27     }
28
29     function & _connect() {
30         $dbh =& $this->_dbh;
31         if (!$dbh or !is_object($dbh)) {
32             global $DBParams;
33             $db = new WikiDB_backend_PDO($DBParams);
34             $this->_dbh =& $db->_dbh;
35             $this->_backend =& $db;
36         }
37         return $dbh->_dbh;
38     }
39     
40     function query($sql) {
41         return $this->_backend->query($sql);
42     }
43
44     function quote($string) {
45         return $this->_backend->quote($sql);
46     }
47
48     function _disconnect() {
49         if (0 and $this->_dbh)
50             unset($this->_dbh);
51     }
52
53     /**
54      * Opens a session.
55      *
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 
60      * is good.
61      * @access private
62      */
63     function open ($save_path, $session_name) {
64         //$this->log("_open($save_path, $session_name)");
65         return true;
66     }
67
68     /**
69      * Closes a session.
70      *
71      * This function is called just after <i>write</i> call.
72      *
73      * @return boolean true just a variable to notify PHP that everything 
74      * is good.
75      * @access private
76      */
77     function close() {
78         //$this->log("_close()");
79         return true;
80     }
81
82     /**
83      * Reads the session data from DB.
84      *
85      * @param  string $id an id of current session
86      * @return string
87      * @access private
88      */
89     function read ($id) {
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();
96         else $res = '';
97         $this->_disconnect();
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 = '';
106         }
107         return $res;
108     }
109   
110     /**
111      * Saves the session data into DB.
112      *
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.
119      *
120      * @param  string $id
121      * @param  string $sess_data
122      * @return boolean true if data saved successfully  and false
123      * otherwise.
124      * @access private
125      */
126     function write ($id, $sess_data) {
127         if (defined("WIKI_XMLRPC") or defined("WIKI_SOAP")) return;     
128         
129         $dbh = $this->_connect();
130         $table = $this->_table;
131         $time = time();
132
133         // postgres can't handle binary data in a TEXT field.
134         if (isa($dbh, 'ADODB_postgres64'))
135             $sess_data = base64_encode($sess_data);
136
137         /* AffectedRows with sessions seems to be instable on certain platforms.
138          * Enable the safe and slow USE_SAFE_DBSESSION then.
139          */
140         if (USE_SAFE_DBSESSION) {
141             $this->_backend->beginTransaction();
142             $rs = $this->query("DELETE FROM $table"
143                                . " WHERE sess_id=$qid");
144             $sth = $dbh->prepare("INSERT INTO $table"
145                                 . " (sess_id, sess_data, sess_date, sess_ip)"
146                                  . " VALUES (?, ?, ?, ?)");
147             $sth->bindParam(1, $id, PDO_PARAM_STR, 32);
148             $sth->bindParam(2, $sess_data, PDO_PARAM_LOB);
149             $sth->bindParam(3, $time, PDO_PARAM_INT);
150             $sth->bindParam(4, $GLOBALS['request']->get('REMOTE_ADDR'), PDO_PARAM_STR, 15);
151             if ($result = $sth->execute()) {
152                 $this->_backend->commit();
153             } else {
154                 $this->_backend->rollBack();
155             }
156         } else {
157             $sth = $dbh->prepare("UPDATE $table"
158                                 . " SET sess_data=?, sess_date=?, sess_ip=?"
159                                 . " WHERE sess_id=?");
160             $sth->bindParam(1, $sess_data, PDO_PARAM_LOB);
161             $sth->bindParam(2, $time, PDO_PARAM_INT);
162             $sth->bindParam(3, $GLOBALS['request']->get('REMOTE_ADDR'), PDO_PARAM_STR, 15);
163             $sth->bindParam(4, $id, PDO_PARAM_STR, 32);
164             $result = $sth->execute(); // implicit affected rows
165             if ( $result === false or $result < 1 ) { // false or int > 0
166                 $sth = $dbh->prepare("INSERT INTO $table"
167                                      . " (sess_id, sess_data, sess_date, sess_ip)"
168                                      . " VALUES (?, ?, ?, ?)");
169                 $sth->bindParam(1, $id, PDO_PARAM_STR, 32);
170                 $sth->bindParam(2, $sess_data, PDO_PARAM_LOB);
171                 $sth->bindParam(3, $time, PDO_PARAM_INT);
172                 $sth->bindParam(4, $GLOBALS['request']->get('REMOTE_ADDR'), PDO_PARAM_STR, 15);
173                 $result = $sth->execute();
174             }
175         }
176         $this->_disconnect();
177         return $result;
178     }
179
180     /**
181      * Destroys a session.
182      *
183      * Removes a session from the table.
184      *
185      * @param  string $id
186      * @return boolean true 
187      * @access private
188      */
189     function destroy ($id) {
190         $table = $this->_table;
191         $dbh = $this->_connect();
192         $sth = $dbh->prepare("DELETE FROM $table WHERE sess_id=?");
193         $sth->bindParam(1, $id, PDO_PARAM_STR, 32);
194         $sth->execute();
195         $this->_disconnect();
196         return true;     
197     }
198
199     /**
200      * Cleans out all expired sessions.
201      *
202      * @param  int $maxlifetime session's time to live.
203      * @return boolean true
204      * @access private
205      */
206     function gc ($maxlifetime) {
207         $table = $this->_table;
208         $threshold = time() - $maxlifetime;
209         $dbh = $this->_connect();
210         $sth = $dbh->prepare("DELETE FROM $table WHERE sess_date < ?");
211         $sth->bindParam(1, $threshold, PDO_PARAM_INT);
212         $sth->execute();
213         $this->_disconnect();
214         return true;
215     }
216
217     // WhoIsOnline support. 
218     // TODO: ip-accesstime dynamic blocking API
219     function currentSessions() {
220         $sessions = array();
221         $table = $this->_table;
222         $dbh = $this->_connect();
223         $sth = $dbh->prepare("SELECT sess_data,sess_date,sess_ip FROM $table ORDER BY sess_date DESC");
224         if (!$sth->execute()) {
225             return $sessions;
226         }
227         while ($row = $sth->fetch(PDO_FETCH_NUM)) {
228             $data = $row[0];
229             $date = $row[1];
230             $ip   = $row[2];
231             if (preg_match('|^[a-zA-Z0-9/+=]+$|', $data))
232                 $data = base64_decode($data);
233             if ($date < 908437560 or $date > 1588437560)
234                 $date = 0;
235             // session_data contains the <variable name> + "|" + <packed string>
236             // we need just the wiki_user object (might be array as well)
237             $user = strstr($data, "wiki_user|");
238             $sessions[] = array('wiki_user' => substr($user,10), // from "O:" onwards
239                                 'date' => $date,
240                                 'ip' => $ip);
241         }
242         $this->_disconnect();
243         return $sessions;
244     }
245 }
246
247 // Local Variables:
248 // mode: php
249 // tab-width: 8
250 // c-basic-offset: 4
251 // c-hanging-comment-ender-p: nil
252 // indent-tabs-mode: nil
253 // End:
254 ?>