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