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