Tagged 0.7.5
[scuttle] / services / userservice.php
1 <?php
2 class UserService {
3   var $db;
4
5   function &getInstance(&$db) {
6     static $instance;
7     if (!isset($instance)) {
8       $instance = new UserService($db);
9     }
10     return $instance;
11   }
12
13   var $fields = array(
14     'primary'   => 'uId',
15     'username'  => 'username',
16     'password'  => 'password'
17   );
18   var $profileurl;
19   var $tablename;
20   var $sessionkey;
21   var $cookiekey;
22   var $cookietime = 1209600; // 2 weeks
23
24     function UserService(&$db) {
25         $this->db =& $db;
26         $this->tablename = $GLOBALS['tableprefix'] .'users';
27         $this->sessionkey = $GLOBALS['cookieprefix'] .'-currentuserid';
28         $this->cookiekey = $GLOBALS['cookieprefix'] .'-login';
29         $this->profileurl = createURL('profile', '%2$s');
30     }
31
32     function _checkdns($host) {
33         if (function_exists('checkdnsrr')) {
34             return checkdnsrr($host);
35         } else {
36             return $this->_checkdnsrr($host);
37         }
38     }
39
40     function _checkdnsrr($host, $type = "MX") {
41         if(!empty($host)) {
42             @exec("nslookup -type=$type $host", $output);
43             while(list($k, $line) = each($output)) {
44                 if(eregi("^$host", $line)) {
45                     return true;
46                 }
47             }
48             return false;
49         }
50     }
51
52     function _getuser($fieldname, $value) {
53         $query = 'SELECT * FROM '. $this->getTableName() .' WHERE '. $fieldname .' = "'. $this->db->sql_escape($value) .'"';
54
55         if (! ($dbresult =& $this->db->sql_query($query)) ) {
56             message_die(GENERAL_ERROR, 'Could not get user', '', __LINE__, __FILE__, $query, $this->db);
57             return false;
58         }
59
60         if ($row =& $this->db->sql_fetchrow($dbresult))
61             return $row;
62         else
63             return false;
64     }
65
66     function _randompassword() {
67         $password = mt_rand(1, 99999999);
68         $password = substr(md5($password), mt_rand(0, 19), mt_rand(6, 12));
69         return $password;
70     }
71
72     function _updateuser($uId, $fieldname, $value) {
73         $updates = array ($fieldname => $value);
74         $sql = 'UPDATE '. $this->getTableName() .' SET '. $this->db->sql_build_array('UPDATE', $updates) .' WHERE '. $this->getFieldName('primary') .'='. intval($uId);
75
76         // Execute the statement.
77         $this->db->sql_transaction('begin');
78         if (!($dbresult = & $this->db->sql_query($sql))) {
79             $this->db->sql_transaction('rollback');
80             message_die(GENERAL_ERROR, 'Could not update user', '', __LINE__, __FILE__, $sql, $this->db);
81             return false;
82         }
83         $this->db->sql_transaction('commit');
84
85         // Everything worked out, so return true.
86         return true;
87     }
88
89     function getProfileUrl($id, $username) {
90         return sprintf($this->profileurl, urlencode($id), urlencode($username));
91     }
92
93     function getUserByUsername($username) {
94         return $this->_getuser($this->getFieldName('username'), $username);
95     }
96
97     function getUser($id) {
98         return $this->_getuser($this->getFieldName('primary'), $id);
99     }
100
101     function isLoggedOn() {
102         return ($this->getCurrentUserId() !== false);
103     }
104
105     function &getCurrentUser($refresh = FALSE, $newval = NULL) {
106         static $currentuser;
107         if (!is_null($newval)) //internal use only: reset currentuser
108             $currentuser = $newval;
109         else if ($refresh || !isset($currentuser)) {
110             if ($id = $this->getCurrentUserId())
111                 $currentuser = $this->getUser($id);
112             else
113                 return;
114         }
115         return $currentuser;
116     }
117
118     function isAdmin($userid) {
119         return false; //not implemented yet
120     }
121
122     function getCurrentUserId() {
123         if (isset($_SESSION[$this->getSessionKey()])) {
124             return $_SESSION[$this->getSessionKey()];
125         } else if (isset($_COOKIE[$this->getCookieKey()])) {
126             $cook = split(':', $_COOKIE[$this->getCookieKey()]);
127             //cookie looks like this: 'id:md5(username+password)'
128             $query = 'SELECT * FROM '. $this->getTableName() .
129                      ' WHERE MD5(CONCAT('.$this->getFieldName('username') .
130                                      ', '.$this->getFieldName('password') .
131                      ')) = \''.$this->db->sql_escape($cook[1]).'\' AND '.
132                      $this->getFieldName('primary'). ' = '. $this->db->sql_escape($cook[0]);
133
134             if (! ($dbresult =& $this->db->sql_query($query)) ) {
135                 message_die(GENERAL_ERROR, 'Could not get user', '', __LINE__, __FILE__, $query, $this->db);
136                 return false;
137             }
138
139             if ($row = $this->db->sql_fetchrow($dbresult)) {
140                 $_SESSION[$this->getSessionKey()] = $row[$this->getFieldName('primary')];
141                 return $_SESSION[$this->getSessionKey()];
142             }
143         }
144         return false;
145     }
146
147     function login($username, $password, $remember = FALSE, $path = '/') {
148         $password = $this->sanitisePassword($password);
149         $query = 'SELECT '. $this->getFieldName('primary') .' FROM '. $this->getTableName() .' WHERE '. $this->getFieldName('username') .' = "'. $this->db->sql_escape($username) .'" AND '. $this->getFieldName('password') .' = "'. $this->db->sql_escape($password) .'"';
150
151         if (! ($dbresult =& $this->db->sql_query($query)) ) {
152             message_die(GENERAL_ERROR, 'Could not get user', '', __LINE__, __FILE__, $query, $this->db);
153             return false;
154         }
155
156         if ($row =& $this->db->sql_fetchrow($dbresult)) {
157             $id = $_SESSION[$this->getSessionKey()] = $row[$this->getFieldName('primary')];
158             if ($remember) {
159                 $cookie = $id .':'. md5($username.$password);
160                 setcookie($this->cookiekey, $cookie, time() + $this->cookietime, $path);
161             }
162             return true;
163         } else {
164             return false;
165         }
166     }
167
168     function logout($path = '/') {
169         @setcookie($this->cookiekey, NULL, time() - 1, $path);
170         unset($_COOKIE[$this->cookiekey]);
171         session_unset();
172         $this->getCurrentUser(TRUE, false);
173     }
174
175     function getWatchlist($uId) {
176         // Gets the list of user IDs being watched by the given user.
177         $query = 'SELECT watched FROM '. $GLOBALS['tableprefix'] .'watched WHERE uId = '. intval($uId);
178
179         if (! ($dbresult =& $this->db->sql_query($query)) ) {
180             message_die(GENERAL_ERROR, 'Could not get watchlist', '', __LINE__, __FILE__, $query, $this->db);
181             return false;
182         }
183
184         $arrWatch = array();
185         if ($this->db->sql_numrows($dbresult) == 0)
186             return $arrWatch;
187         while ($row =& $this->db->sql_fetchrow($dbresult))
188             $arrWatch[] = $row['watched'];
189         return $arrWatch;
190     }
191
192     function getWatchNames($uId, $watchedby = false) {
193         // Gets the list of user names being watched by the given user.
194         // - If $watchedby is false get the list of users that $uId watches
195         // - If $watchedby is true get the list of users that watch $uId
196         if ($watchedby) {
197             $table1 = 'b';
198             $table2 = 'a';
199         } else {
200             $table1 = 'a';
201             $table2 = 'b';
202         }
203         $query = 'SELECT '. $table1 .'.'. $this->getFieldName('username') .' FROM '. $GLOBALS['tableprefix'] .'watched AS W, '. $this->getTableName() .' AS a, '. $this->getTableName() .' AS b WHERE W.watched = a.'. $this->getFieldName('primary') .' AND W.uId = b.'. $this->getFieldName('primary') .' AND '. $table2 .'.'. $this->getFieldName('primary') .' = '. intval($uId) .' ORDER BY '. $table1 .'.'. $this->getFieldName('username');
204
205         if (!($dbresult =& $this->db->sql_query($query))) {
206             message_die(GENERAL_ERROR, 'Could not get watchlist', '', __LINE__, __FILE__, $query, $this->db);
207             return false;
208         }
209
210         $arrWatch = array();
211         if ($this->db->sql_numrows($dbresult) == 0) {
212             return $arrWatch;
213         }
214         while ($row =& $this->db->sql_fetchrow($dbresult)) {
215             $arrWatch[] = $row[$this->getFieldName('username')];
216         }
217         return $arrWatch;
218     }
219
220     function getWatchStatus($watcheduser, $currentuser) {
221         // Returns true if the current user is watching the given user, and false otherwise.
222         $query = 'SELECT watched FROM '. $GLOBALS['tableprefix'] .'watched AS W INNER JOIN '. $this->getTableName() .' AS U ON U.'. $this->getFieldName('primary') .' = W.watched WHERE U.'. $this->getFieldName('primary') .' = '. intval($watcheduser) .' AND W.uId = '. intval($currentuser);
223         
224         if (! ($dbresult =& $this->db->sql_query($query)) ) {
225             message_die(GENERAL_ERROR, 'Could not get watchstatus', '', __LINE__, __FILE__, $query, $this->db);
226             return false;
227         }
228
229         $arrWatch = array();
230         if ($this->db->sql_numrows($dbresult) == 0)
231             return false;
232         else 
233             return true;
234     }
235
236     function setWatchStatus($subjectUserID) {
237         if (!is_numeric($subjectUserID))
238             return false;
239
240         $currentUserID = $this->getCurrentUserId();
241         $watched = $this->getWatchStatus($subjectUserID, $currentUserID);
242
243         if ($watched) {
244             $sql = 'DELETE FROM '. $GLOBALS['tableprefix'] .'watched WHERE uId = '. intval($currentUserID) .' AND watched = '. intval($subjectUserID);
245             if (!($dbresult =& $this->db->sql_query($sql))) {
246                 $this->db->sql_transaction('rollback');
247                 message_die(GENERAL_ERROR, 'Could not add user to watch list', '', __LINE__, __FILE__, $sql, $this->db);
248                 return false;
249             }
250         } else {
251             $values = array(
252                 'uId' => intval($currentUserID),
253                 'watched' => intval($subjectUserID)
254             ); 
255             $sql = 'INSERT INTO '. $GLOBALS['tableprefix'] .'watched '. $this->db->sql_build_array('INSERT', $values);
256             if (!($dbresult =& $this->db->sql_query($sql))) {
257                 $this->db->sql_transaction('rollback');
258                 message_die(GENERAL_ERROR, 'Could not add user to watch list', '', __LINE__, __FILE__, $sql, $this->db);
259                 return false;
260             }
261         }
262
263         $this->db->sql_transaction('commit');
264         return true;
265     }
266
267     function addUser($username, $password, $email) {
268         // Set up the SQL UPDATE statement.
269         $datetime = gmdate('Y-m-d H:i:s', time());
270         $password = $this->sanitisePassword($password);
271         $values = array('username' => $username, 'password' => $password, 'email' => $email, 'uDatetime' => $datetime, 'uModified' => $datetime);
272         $sql = 'INSERT INTO '. $this->getTableName() .' '. $this->db->sql_build_array('INSERT', $values);
273
274         // Execute the statement.
275         $this->db->sql_transaction('begin');
276         if (!($dbresult = & $this->db->sql_query($sql))) {
277             $this->db->sql_transaction('rollback');
278             message_die(GENERAL_ERROR, 'Could not insert user', '', __LINE__, __FILE__, $sql, $this->db);
279             return false;
280         }
281         $this->db->sql_transaction('commit');
282
283         // Everything worked out, so return true.
284         return true;
285     }
286
287     function updateUser($uId, $password, $name, $email, $homepage, $uContent) {
288         if (!is_numeric($uId))
289             return false;
290
291         // Set up the SQL UPDATE statement.
292         $moddatetime = gmdate('Y-m-d H:i:s', time());
293         if ($password == '')
294             $updates = array ('uModified' => $moddatetime, 'name' => $name, 'email' => $email, 'homepage' => $homepage, 'uContent' => $uContent);
295         else
296             $updates = array ('uModified' => $moddatetime, 'password' => $this->sanitisePassword($password), 'name' => $name, 'email' => $email, 'homepage' => $homepage, 'uContent' => $uContent);
297         $sql = 'UPDATE '. $this->getTableName() .' SET '. $this->db->sql_build_array('UPDATE', $updates) .' WHERE '. $this->getFieldName('primary') .'='. intval($uId);
298
299         // Execute the statement.
300         $this->db->sql_transaction('begin');
301         if (!($dbresult = & $this->db->sql_query($sql))) {
302             $this->db->sql_transaction('rollback');
303             message_die(GENERAL_ERROR, 'Could not update user', '', __LINE__, __FILE__, $sql, $this->db);
304             return false;
305         }
306         $this->db->sql_transaction('commit');
307
308         // Everything worked out, so return true.
309         return true;
310     }
311
312     function sanitisePassword($password) {
313         return sha1(trim($password));
314     }
315
316     function generatePassword($uId) {
317         if (!is_numeric($uId))
318             return false;
319
320         $password = $this->_randompassword();
321
322         if ($this->_updateuser($uId, $this->getFieldName('password'), $this->sanitisePassword($password)))
323             return $password;
324         else
325             return false;
326     }
327
328     function isReserved($username) {
329         if (in_array($username, $GLOBALS['reservedusers'])) {
330             return true;
331         } else {
332             return false;
333         }
334     }
335
336     function isValidEmail($email) {
337         if (preg_match("/^((?:(?:(?:\w[\.\-\+_]?)*)\w)+)\@((?:(?:(?:\w[\.\-_]?){0,62})\w)+)\.(\w{2,6})$/i", $email) > 0) {
338             list($emailUser, $emailDomain) = explode("@", $email);
339
340             // Check if the email domain has a DNS record
341             if ($this->_checkdns($emailDomain)) {
342                 return true;
343             }
344         }
345         return false;
346     }
347
348     // Properties
349     function getTableName()       { return $this->tablename; }
350     function setTableName($value) { $this->tablename = $value; }
351
352     function getFieldName($field)         { return $this->fields[$field]; }
353     function setFieldName($field, $value) { $this->fields[$field] = $value; }
354
355     function getSessionKey()       { return $this->sessionkey; }
356     function setSessionKey($value) { $this->sessionkey = $value; }
357
358     function getCookieKey()       { return $this->cookiekey; }
359     function setCookieKey($value) { $this->cookiekey = $value; }
360 }

Benjamin Mako Hill || Want to submit a patch?