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

Benjamin Mako Hill || Want to submit a patch?