]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/DbSession/PDO.php
Use __construct
[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 __construct($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     }
27
28     function & _connect()
29     {
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;
38     }
39
40     function query($sql)
41     {
42         return $this->_backend->query($sql);
43     }
44
45     function quote($string)
46     {
47         return $this->_backend->quote($string);
48     }
49
50     function _disconnect()
51     {
52         if (0 and $this->_dbh)
53             unset($this->_dbh);
54     }
55
56     /**
57      * Opens a session.
58      *
59      * Actually this function is a fake for session_set_save_handle.
60      * @param  string  $save_path    a path to stored files
61      * @param  string  $session_name a name of the concrete file
62      * @return boolean true just a variable to notify PHP that everything
63      * is good.
64      */
65     public function open($save_path, $session_name)
66     {
67         //$this->log("_open($save_path, $session_name)");
68         return true;
69     }
70
71     /**
72      * Closes a session.
73      *
74      * This function is called just after <i>write</i> call.
75      *
76      * @return boolean true just a variable to notify PHP that everything
77      * is good.
78      */
79     public function close()
80     {
81         //$this->log("_close()");
82         return true;
83     }
84
85     /**
86      * Reads the session data from DB.
87      *
88      * @param  string $id an id of current session
89      * @return string
90      */
91     public function read($id)
92     {
93         //$this->log("_read($id)");
94         $dbh = $this->_connect();
95         $table = $this->_table;
96         $sth = $dbh->prepare("SELECT sess_data FROM $table WHERE sess_id=?");
97         $sth->bindParam(1, $id, PDO::PARAM_STR, 32);
98         if ($sth->execute()) {
99             $res = $sth->fetchColumn();
100         } else {
101             $res = '';
102         }
103         $this->_disconnect();
104         if (!empty($res) and isa($dbh, 'ADODB_postgres64')) {
105             $res = base64_decode($res);
106         }
107         if (strlen($res) > 4000) {
108             trigger_error("Overlarge session data! " . strlen($res) .
109                 " gt. 4000", E_USER_WARNING);
110             $res = preg_replace('/s:6:"_cache";O:12:"WikiDB_cache".+}$/', "", $res);
111             $res = preg_replace('/s:12:"_cached_html";s:.+",s:4:"hits"/', 's:4:"hits"', $res);
112             if (strlen($res) > 4000) {
113                 $res = '';
114             }
115         }
116         return $res;
117     }
118
119     /**
120      * Saves the session data into DB.
121      *
122      * Just  a  comment:       The  "write"  handler  is  not
123      * executed until after the output stream is closed. Thus,
124      * output from debugging statements in the "write" handler
125      * will  never be seen in the browser. If debugging output
126      * is  necessary, it is suggested that the debug output be
127      * written to a file instead.
128      *
129      * @param  string  $id
130      * @param  string  $sess_data
131      * @return boolean true if data saved successfully  and false
132      * otherwise.
133      */
134     public function write($id, $sess_data)
135     {
136         if (defined("WIKI_XMLRPC") or defined("WIKI_SOAP")) return false;
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 unstable 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=$id");
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      */
197     public function destroy($id)
198     {
199         $table = $this->_table;
200         $dbh = $this->_connect();
201         $sth = $dbh->prepare("DELETE FROM $table WHERE sess_id=?");
202         $sth->bindParam(1, $id, PDO::PARAM_STR, 32);
203         $sth->execute();
204         $this->_disconnect();
205         return true;
206     }
207
208     /**
209      * Cleans out all expired sessions.
210      *
211      * @param  int     $maxlifetime session's time to live.
212      * @return boolean true
213      */
214     public function gc($maxlifetime)
215     {
216         $table = $this->_table;
217         $threshold = time() - $maxlifetime;
218         $dbh = $this->_connect();
219         $sth = $dbh->prepare("DELETE FROM $table WHERE sess_date < ?");
220         $sth->bindParam(1, $threshold, PDO::PARAM_INT);
221         $sth->execute();
222         $this->_disconnect();
223         return true;
224     }
225
226     // WhoIsOnline support.
227     // TODO: ip-accesstime dynamic blocking API
228     function currentSessions()
229     {
230         $sessions = array();
231         $table = $this->_table;
232         $dbh = $this->_connect();
233         $sth = $dbh->prepare("SELECT sess_data,sess_date,sess_ip FROM $table ORDER BY sess_date DESC");
234         if (!$sth->execute()) {
235             return $sessions;
236         }
237         while ($row = $sth->fetch(PDO::FETCH_NUM)) {
238             $data = $row[0];
239             $date = $row[1];
240             $ip = $row[2];
241             if (preg_match('|^[a-zA-Z0-9/+=]+$|', $data))
242                 $data = base64_decode($data);
243             if ($date < 908437560 or $date > 1588437560)
244                 $date = 0;
245             // session_data contains the <variable name> + "|" + <packed string>
246             // we need just the wiki_user object (might be array as well)
247             $user = strstr($data, "wiki_user|");
248             $sessions[] = array('wiki_user' => substr($user, 10), // from "O:" onwards
249                 'date' => $date,
250                 'ip' => $ip);
251         }
252         $this->_disconnect();
253         return $sessions;
254     }
255 }
256
257 // Local Variables:
258 // mode: php
259 // tab-width: 8
260 // c-basic-offset: 4
261 // c-hanging-comment-ender-p: nil
262 // indent-tabs-mode: nil
263 // End: