]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/DbSession/SQL.php
fix ref warnings, analog to ADODB
[SourceForge/phpwiki.git] / lib / DbSession / SQL.php
1 <?php rcs_id('$Id: SQL.php,v 1.2 2005-11-21 20:57:58 rurban Exp $');
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     var $_backend_type = "SQL";
17
18     function DbSession_SQL (&$dbh, $table) {
19
20         $this->_dbh = $dbh;
21         $this->_table = $table;
22
23         ini_set('session.save_handler','user');
24         session_module_name('user'); // new style
25         session_set_save_handler(array(&$this, 'open'),
26                                  array(&$this, 'close'),
27                                  array(&$this, 'read'),
28                                  array(&$this, 'write'),
29                                  array(&$this, 'destroy'),
30                                  array(&$this, 'gc'));
31         return $this;
32     }
33
34     function & _connect() {
35         $dbh = &$this->_dbh;
36         $this->_connected = is_resource($dbh->connection);
37         if (!$this->_connected) {
38             $res = $dbh->connect($dbh->dsn);
39             if (DB::isError($res)) {
40                 error_log("PhpWiki::DbSession::_connect: " . $res->getMessage());
41             }
42         }
43         return $dbh;
44     }
45     
46     function query($sql) {
47         return $this->_dbh->query($sql);
48     }
49     // adds surrounding quotes
50     function quote($string) {
51         return $this->_dbh->quote($string);
52     }
53
54     function _disconnect() {
55         if (0 and $this->_connected)
56             $this->_dbh->disconnect();
57     }
58
59     /**
60      * Opens a session.
61      *
62      * Actually this function is a fake for session_set_save_handle.
63      * @param  string $save_path a path to stored files
64      * @param  string $session_name a name of the concrete file
65      * @return boolean true just a variable to notify PHP that everything 
66      * is good.
67      * @access private
68      */
69     function open ($save_path, $session_name) {
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         //$this->log("_close()");
85         return true;
86     }
87
88     /**
89      * Reads the session data from DB.
90      *
91      * @param  string $id an id of current session
92      * @return string
93      * @access private
94      */
95     function read ($id) {
96         //$this->log("_read($id)");
97         $dbh = $this->_connect();
98         $table = $this->_table;
99         $qid = $dbh->quote($id);
100     
101         $res = $dbh->getOne("SELECT sess_data FROM $table WHERE sess_id=$qid");
102
103         $this->_disconnect();
104         if (DB::isError($res) || empty($res))
105             return '';
106         if (isa($dbh, 'DB_pgsql'))
107             //if (preg_match('|^[a-zA-Z0-9/+=]+$|', $res))
108             $res = base64_decode($res);
109         if (strlen($res) > 4000) {
110             trigger_error("Overlarge session data! ".strlen($res).
111                         " gt. 4000", E_USER_WARNING);
112             $res = preg_replace('/s:6:"_cache";O:12:"WikiDB_cache".+}$/',"",$res);
113             $res = preg_replace('/s:12:"_cached_html";s:.+",s:4:"hits"/','s:4:"hits"',$res);
114             if (strlen($res) > 4000) $res = '';
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      * @access private
134      */
135     function write ($id, $sess_data) {
136         
137         $dbh = $this->_connect();
138         //$dbh->unlock(false,1);
139         $table = $this->_table;
140         $qid = $dbh->quote($id);
141         $qip = $dbh->quote($GLOBALS['request']->get('REMOTE_ADDR'));
142         $time = $dbh->quote(time());
143         if (DEBUG and $sess_data == 'wiki_user|N;') {
144             trigger_error("delete empty session $qid", E_USER_WARNING);
145         }
146         // postgres can't handle binary data in a TEXT field.
147         if (isa($dbh, 'DB_pgsql'))
148             $sess_data = base64_encode($sess_data);
149         $qdata = $dbh->quote($sess_data);
150
151         /* AffectedRows with sessions seems to be instable on certain platforms.
152          * Enable the safe and slow USE_SAFE_DBSESSION then.
153          */
154         if (USE_SAFE_DBSESSION) {
155             $dbh->query("DELETE FROM $table"
156                         . " WHERE sess_id=$qid");
157             $res = $dbh->query("INSERT INTO $table"
158                                . " (sess_id, sess_data, sess_date, sess_ip)"
159                                . " VALUES ($qid, $qdata, $time, $qip)");
160         } else {
161             $res = $dbh->query("UPDATE $table"
162                                . " SET sess_data=$qdata, sess_date=$time, sess_ip=$qip"
163                                . " WHERE sess_id=$qid");
164             $result = $dbh->AffectedRows();
165             if ( $result === false or $result < 1 ) { // 0 cannot happen: time, -1 (failure) on mysql
166                 $res = $dbh->query("INSERT INTO $table"
167                                    . " (sess_id, sess_data, sess_date, sess_ip)"
168                                    . " VALUES ($qid, $qdata, $time, $qip)");
169             }
170         }
171         $this->_disconnect();
172         return ! DB::isError($res);
173     }
174
175     /**
176      * Destroys a session.
177      *
178      * Removes a session from the table.
179      *
180      * @param  string $id
181      * @return boolean true 
182      * @access private
183      */
184     function destroy ($id) {
185         $dbh = $this->_connect();
186         $table = $this->_table;
187         $qid = $dbh->quote($id);
188
189         $dbh->query("DELETE FROM $table WHERE sess_id=$qid");
190
191         $this->_disconnect();
192         return true;     
193     }
194
195     /**
196      * Cleans out all expired sessions.
197      *
198      * @param  int $maxlifetime session's time to live.
199      * @return boolean true
200      * @access private
201      */
202     function gc ($maxlifetime) {
203         $dbh = $this->_connect();
204         $table = $this->_table;
205         $threshold = time() - $maxlifetime;
206
207         $dbh->query("DELETE FROM $table WHERE sess_date < $threshold");
208
209         $this->_disconnect();
210         return true;
211     }
212
213     // WhoIsOnline support
214     // TODO: ip-accesstime dynamic blocking API
215     function currentSessions() {
216         $sessions = array();
217         $dbh = $this->_connect();
218         $table = $this->_table;
219         $res = $dbh->query("SELECT sess_data,sess_date,sess_ip FROM $table ORDER BY sess_date DESC");
220         if (DB::isError($res) || empty($res))
221             return $sessions;
222         while ($row = $res->fetchRow()) {
223             $data = $row['sess_data'];
224             $date = $row['sess_date'];
225             $ip   = $row['sess_ip'];
226             if (preg_match('|^[a-zA-Z0-9/+=]+$|', $data))
227                 $data = base64_decode($data);
228             if ($date < 908437560 or $date > 1588437560)
229                 $date = 0;
230             // session_data contains the <variable name> + "|" + <packed string>
231             // we need just the wiki_user object (might be array as well)
232             $user = strstr($data,"wiki_user|");
233             $sessions[] = array('wiki_user' => substr($user,10), // from "O:" onwards
234                                 'date' => $date,
235                                 'ip'   => $ip);
236         }
237         $this->_disconnect();
238         return $sessions;
239     }
240 }
241
242
243 // $Log: not supported by cvs2svn $
244 // Revision 1.1  2005/02/11 14:41:40  rurban
245 // seperate DbSession classes: less memory, a bit slower
246 //
247
248 // Local Variables:
249 // mode: php
250 // tab-width: 8
251 // c-basic-offset: 4
252 // c-hanging-comment-ender-p: nil
253 // indent-tabs-mode: nil
254 // End:
255 ?>