4 * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
\r
5 * Copyright (C) 2002-2009 The Nucleus Group
\r
7 * This program is free software; you can redistribute it and/or
\r
8 * modify it under the terms of the GNU General Public License
\r
9 * as published by the Free Software Foundation; either version 2
\r
10 * of the License, or (at your option) any later version.
\r
11 * (see nucleus/documentation/index.html#license for more info)
\r
14 * A class representing site members
\r
16 * @license http://nucleuscms.org/license.txt GNU General Public License
\r
17 * @copyright Copyright (C) 2002-2009 The Nucleus Group
\r
18 * @version $Id: MEMBER.php 1616 2012-01-08 09:48:15Z sakamocchi $
\r
22 // 1 when authenticated, 0 when not
\r
23 public $loggedin = 0;
\r
24 public $password; // not the actual password, but rather a MD5 hash
\r
25 private $algorism = 'md5';
\r
27 public $cookiekey; // value that should also be in the client cookie to allow authentication
\r
28 private $cookie_salt = FALSE;
\r
33 public $displayname;
\r
36 public $admin = 0; // (either 0 or 1)
\r
37 public $canlogin = 0; // (either 0 or 1)
\r
39 public $autosave = 1; // if the member use the autosave draft function
\r
40 private $locale = '';
\r
43 * Member::__construct()
\r
44 * Constructor for a member object
\r
50 public function __construct()
\r
56 * Member::createFromName()
\r
57 * Create a member object for a given displayname
\r
60 * @param String $displayname login name
\r
61 * @return Object member object
\r
64 public static function &createFromName($displayname)
\r
66 $mem = new Member();
\r
67 $mem->readFromName($displayname);
\r
72 * Member::createFromID()
\r
73 * Create a member object for a given ID
\r
76 * @param Integer $id id for member
\r
78 public static function &createFromID($id)
\r
80 $mem = new Member();
\r
81 $mem->readFromID($id);
\r
86 * Member::readFromName()
\r
87 * Read member table in database
\r
89 * @param String $displayname login name
\r
90 * @return Object SQL resource
\r
93 public function readFromName($displayname)
\r
95 return $this->read("mname='".sql_real_escape_string($displayname)."'");
\r
99 * Member::readFromID()
\r
100 * Read member table in database
\r
102 * @param Integer $id id for member
\r
103 * @return Object SQL resource
\r
106 public function readFromID($id)
\r
108 return $this->read("mnumber=" . intval($id));
\r
113 * hash the target string
\r
115 * @param String $string target string
\r
116 * @return Void hashed string
\r
118 public function hash($string)
\r
120 switch ( $this->algorism )
\r
124 $string = md5($string);
\r
130 * Member::set_cookie_salt()
\r
132 * @param integer $key secureCookieKey value
\r
136 private function set_cookie_salt($key = 0)
\r
146 $this->cookie_salt = preg_replace('/\.[0-9]+\.[0-9]+\.[0-9]+$/', '', serverVar('REMOTE_ADDR'));
\r
149 $this->cookie_salt = preg_replace('/\.[0-9]+\.[0-9]+$/', '', serverVar('REMOTE_ADDR'));
\r
152 $this->cookie_salt = preg_replace('/\.[0-9]+$/', '', serverVar('REMOTE_ADDR'));
\r
155 $this->cookie_salt = serverVar('REMOTE_ADDR');
\r
158 $this->cookie_salt = 'none';
\r
165 * Tries to login as a given user.
\r
166 * Returns true when succeeded, returns false when failed
\r
167 * 3.40 adds CustomLogin event
\r
169 * @param String $login login name for member
\r
170 * @param String $password password for member
\r
171 * @param Integer $shared whether the user agent is shared or not
\r
174 public function login($login, $password, $shared=1)
\r
176 global $CONF, $errormessage, $manager;
\r
178 /* TODO: validation for $login, $password, $shared */
\r
179 if ( $login == '' || $password == '' )
\r
183 /* limiting the length of password to avoid hash collision */
\r
184 $password=i18n::substr($password, 0, 40);
\r
187 * generate cookie salt from secure cookie key settings
\r
188 * (either 'none', 0, 8, 16, 24, or 32)
\r
190 if ( !$this->cookie_salt )
\r
193 if ( array_key_exists('secureCookieKey', $CONF) )
\r
195 $salt = $CONF['secureCookieKey'];
\r
197 $this->set_cookie_salt($salt);
\r
202 $manager->notify('CustomLogin', array('login' => &$login, 'password'=>&$password, 'success'=>&$success, 'allowlocal'=>&$allowlocal));
\r
204 $this->loggedin = 0;
\r
207 $this->loggedin = ( $this->readFromName($login) );
\r
209 elseif ( $allowlocal )
\r
211 $this->loggedin = ( $this->readFromName($login) && $this->checkPassword($password) );
\r
215 if ( !$this->loggedin )
\r
217 $trimlogin = trim($login);
\r
218 if ( empty($trimlogin) )
\r
220 $errormessage = "Please enter a username.";
\r
224 $errormessage = 'Login failed for ' . $login;
\r
226 $manager->notify('LoginFailed', array('username' => $login) );
\r
227 ActionLog::add(INFO, $errormessage);
\r
229 /* login success */
\r
232 /* For lower compatibility */
\r
233 if ( strlen($this->password) === 32 )
\r
235 $this->password = $this->hash($password);
\r
238 $this->newCookieKey();
\r
239 $this->setCookies($shared);
\r
241 if ( $this->cookie_salt !== 'none' )
\r
243 /* secure cookie key */
\r
244 $this->setCookieKey($this->hash($this->getCookieKey() . $this->cookie_salt));
\r
248 $errormessage = '';
\r
249 $manager->notify('LoginSuccess', array('member' => &$member, 'username' => $login) );
\r
250 ActionLog::add(INFO, "Login successful for $login (sharedpc=$shared)");
\r
253 return $this->loggedin;
\r
257 * Member::cookielogin()
\r
258 * Login using cookie key
\r
260 * @param String $login not used
\r
261 * @param String $cookiekey not used
\r
262 * @return Boolean login or not
\r
264 public function cookielogin($login='', $cookiekey='')
\r
266 global $CONF, $manager;
\r
268 if ( !headers_sent() && cookieVar("{$CONF['CookiePrefix']}user") )
\r
270 /* Cookie Authentication */
\r
271 $ck = cookieVar("{$CONF['CookiePrefix']}loginkey");
\r
273 /* TODO: validation for each cookie values */
\r
275 /* limiting the length of password to avoid hash collision */
\r
276 $ck = i18n::substr($ck,0,32);
\r
279 * generate cookie salt from secure cookie key settings
\r
280 * (either 'none', 0, 8, 16, 24, or 32)
\r
282 if ( !$this->cookie_salt )
\r
285 if ( array_key_exists('secureCookieKey', $CONF) )
\r
287 $salt = $CONF['secureCookieKey'];
\r
289 $this->set_cookie_salt($salt);
\r
292 if ( $this->cookie_salt !== 'none' )
\r
294 $ck = $this->hash($ck . $this->cookie_salt);
\r
296 $this->loggedin = ( $this->readFromName(cookieVar("{$CONF['CookiePrefix']}user")) && $this->checkCookieKey($ck) );
\r
299 /* renew cookies when not on a shared computer */
\r
300 if ( $this->loggedin && (cookieVar($CONF['CookiePrefix'] . 'sharedpc') != 1) )
\r
302 $this->setCookieKey(cookieVar("{$CONF['CookiePrefix']}loginkey"));
\r
303 $this->setCookies();
\r
306 return $this->loggedin;
\r
311 * logout and expire cookie
\r
316 public function logout()
\r
318 global $CONF, $manager;
\r
320 if ( !headers_sent() && cookieVar("{$CONF['CookiePrefix']}user") )
\r
322 /* remove cookies on logout */
\r
323 setcookie("{$CONF['CookiePrefix']}user", '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
\r
324 setcookie("{$CONF['CookiePrefix']}loginkey", '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
\r
325 $manager->notify('Logout', array('username' => cookieVar("{$CONF['CookiePrefix']}user") ) );
\r
328 $this->loggedin = 0;
\r
333 * Member::isLoggedIn()
\r
334 * return member is loggedin or not
\r
339 public function isLoggedIn()
\r
341 return $this->loggedin;
\r
346 * Read member information from the database
\r
348 * @param String $where where statement
\r
349 * @return Resource SQL resource
\r
352 public function read($where)
\r
355 $query = 'SELECT * FROM '.sql_table('member') . ' WHERE ' . $where;
\r
357 $res = sql_query($query);
\r
358 $obj = sql_fetch_object($res);
\r
360 $this->setRealName($obj->mrealname);
\r
361 $this->setEmail($obj->memail);
\r
362 $this->password = $obj->mpassword;
\r
363 $this->setCookieKey($obj->mcookiekey);
\r
364 $this->setURL($obj->murl);
\r
365 $this->setDisplayName($obj->mname);
\r
366 $this->setAdmin($obj->madmin);
\r
367 $this->id = $obj->mnumber;
\r
368 $this->setCanLogin($obj->mcanlogin);
\r
369 $this->setNotes($obj->mnotes);
\r
370 $this->setLocale($obj->mlocale);
\r
371 $this->setAutosave($obj->mautosave);
\r
373 return sql_num_rows($res);
\r
377 * Member::isBlogAdmin()
\r
378 * Returns true if member is an admin for the given blog
\r
379 * (returns false if not a team member)
\r
381 * @param Integer $blogid weblog id
\r
382 * @return Integer weblog admin or not
\r
385 public function isBlogAdmin($blogid)
\r
387 $query = 'SELECT tadmin FROM '.sql_table('team').' WHERE'
\r
388 . ' tblog=' . intval($blogid)
\r
389 . ' and tmember='. $this->getID();
\r
390 $res = sql_query($query);
\r
391 if ( sql_num_rows($res) == 0 )
\r
394 return ( sql_result($res,0,0) == 1 );
\r
398 * Member::blogAdminRights()
\r
400 * @param integer $blogid ID of target weblog
\r
401 * @return boolean whether to have admin rights to the weblog or not
\r
404 public function blogAdminRights($blogid)
\r
406 return ($this->isAdmin() || $this->isBlogAdmin($blogid));
\r
410 * Member::teamRights()
\r
412 * @param integer $blogid ID of target weblog
\r
413 * @return boolean whether to have admin right to the weblog or not
\r
416 public function teamRights($blogid)
\r
418 return ($this->isAdmin() || $this->isTeamMember($blogid));
\r
422 * Member::isTeamMember()
\r
423 * Returns true if this member is a team member of the given blog
\r
425 * @param integer $blogid ID of target weblog
\r
426 * @return boolean whether to join the weblog or not
\r
429 public function isTeamMember($blogid)
\r
431 $query = 'SELECT * FROM '.sql_table('team').' WHERE'
\r
432 . ' tblog=' . intval($blogid)
\r
433 . ' and tmember='. $this->getID();
\r
434 $res = sql_query($query);
\r
435 return (sql_num_rows($res) != 0);
\r
439 * Member::canAddItem()
\r
441 * @param integer $catid ID of target category
\r
442 * @return boolean whether to be able to add items to the category or not
\r
445 public function canAddItem($catid)
\r
449 // if this is a 'newcat' style newcat
\r
450 // no blog admin of destination blog -> NOK
\r
451 // blog admin of destination blog -> OK
\r
452 if ( i18n::strpos($catid,'newcat') === 0 )
\r
455 list($blogid) = sscanf($catid,"newcat-%d");
\r
456 return $this->blogAdminRights($blogid);
\r
459 // category does not exist -> NOK
\r
460 if ( !$manager->existsCategory($catid) )
\r
465 $blogid = getBlogIDFromCatID($catid);
\r
467 // no team rights for blog -> NOK
\r
468 if (!$this->teamRights($blogid))
\r
473 // all other cases: OK
\r
478 * Member::canAlterComment()
\r
479 * Returns true if this member can edit/delete a commentitem. This can be in the
\r
481 * - member is a super-admin
\r
482 * - member is the author of the comment
\r
483 * - member is admin of the blog associated with the comment
\r
484 * - member is author of the item associated with the comment
\r
486 * @param integer $commentid ID of target comment
\r
487 * @return boolean delete/edit the comment or not
\r
490 public function canAlterComment($commentid)
\r
492 if ( $this->isAdmin() )
\r
497 $query = 'SELECT citem as itemid, iblog as blogid, cmember as cauthor, iauthor'
\r
498 . ' FROM '.sql_table('comment') .', '.sql_table('item').', '.sql_table('blog')
\r
499 . ' WHERE citem=inumber and iblog=bnumber and cnumber=' . intval($commentid);
\r
500 $res = sql_query($query);
\r
501 $obj = sql_fetch_object($res);
\r
503 return ($obj->cauthor == $this->getID()) or $this->isBlogAdmin($obj->blogid) or ($obj->iauthor == $this->getID());
\r
507 * Member::canAlterItem()
\r
508 * Returns true if this member can edit/delete an item. This is true in the following
\r
509 * cases: - member is a super-admin
\r
510 * - member is the author of the item
\r
511 * - member is admin of the the associated blog
\r
513 * @param integer $itemid ID of target item
\r
514 * @return boolean delete/edit the item or not
\r
517 public function canAlterItem($itemid)
\r
519 if ($this->isAdmin()) return 1;
\r
521 $query = 'SELECT iblog, iauthor FROM '.sql_table('item').' WHERE inumber=' . intval($itemid);
\r
522 $res = sql_query($query);
\r
523 $obj = sql_fetch_object($res);
\r
524 return ($obj->iauthor == $this->getID()) or $this->isBlogAdmin($obj->iblog);
\r
528 * Member::canBeDeleted()
\r
529 * Return true if member can be deleted. This means that there are no items posted by the member left
\r
532 * @return boolean whether there is no items or exists
\r
535 public function canBeDeleted()
\r
537 $res = sql_query('SELECT * FROM '.sql_table('item').' WHERE iauthor=' . $this->getID());
\r
538 return ( sql_num_rows($res) == 0 );
\r
542 * Member::canUpdateItem()
\r
543 * returns true if this member can move/update an item to a given category,
\r
544 * false if not (see comments fot the tests that are executed)
\r
546 * @param integer $itemid
\r
547 * @param string $newcat (can also be of form 'newcat-x' with x=blogid)
\r
548 * @return boolean whether being able to update the item or not
\r
551 public function canUpdateItem($itemid, $newcat)
\r
555 // item does not exists -> NOK
\r
556 if ( !$manager->existsItem($itemid,1,1) )
\r
561 // cannot alter item -> NOK
\r
562 if (!$this->canAlterItem($itemid))
\r
567 // if this is a 'newcat' style newcat
\r
568 // no blog admin of destination blog -> NOK
\r
569 // blog admin of destination blog -> OK
\r
570 if ( i18n::strpos($newcat, 'newcat') === 0 )
\r
573 list($blogid) = sscanf($newcat,'newcat-%d');
\r
574 return $this->blogAdminRights($blogid);
\r
577 // category does not exist -> NOK
\r
578 if (!$manager->existsCategory($newcat))
\r
584 $item =& $manager->getItem($itemid,1,1);
\r
586 // old catid = new catid -> OK
\r
587 if ($item['catid'] == $newcat)
\r
592 // not a valid category -> NOK
\r
593 $validCat = quickQuery('SELECT COUNT(*) AS result FROM '.sql_table('category').' WHERE catid='.intval($newcat));
\r
599 // get destination blog
\r
600 $source_blogid = getBlogIDFromItemID($itemid);
\r
601 $dest_blogid = getBlogIDFromCatID($newcat);
\r
603 // not a team member of destination blog -> NOK
\r
604 if ( !$this->teamRights($dest_blogid) )
\r
609 // if member is author of item -> OK
\r
610 if ( $item['authorid'] == $this->getID() )
\r
615 // if member has admin rights on both blogs: OK
\r
616 if ( ($this->blogAdminRights($dest_blogid)) && ($this->blogAdminRights($source_blogid)) )
\r
621 // all other cases: NOK
\r
626 * Member::setCookies()
\r
627 * Sets the cookies for the member
\r
629 * @param boolean $shared set this to 1 when using a shared computer. Cookies will expire
\r
630 * at the end of the session in this case.
\r
634 public function setCookies($shared = 0)
\r
638 if ( $CONF['SessionCookie'] || $shared )
\r
644 $lifetime = time()+2592000;
\r
647 setcookie($CONF['CookiePrefix'] . 'user', $this->getDisplayName(), $lifetime, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
\r
648 setcookie($CONF['CookiePrefix'] . 'loginkey', $this->getCookieKey(), $lifetime, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
\r
650 // make sure cookies on shared pcs don't get renewed
\r
653 setcookie($CONF['CookiePrefix'] .'sharedpc', '1',$lifetime,$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);
\r
659 * Member::sendActivationLink()
\r
660 * Send activation mail
\r
662 * @param string $type activation type
\r
663 * @param string $extra extra info
\r
666 public function sendActivationLink($type, $extra='')
\r
670 if ( !isset($CONF['ActivationDays']) )
\r
672 $CONF['ActivationDays'] = 2;
\r
675 // generate key and URL
\r
676 $key = $this->generateActivationEntry($type, $extra);
\r
677 $url = $CONF['AdminURL'] . 'index.php?action=activate&key=' . $key;
\r
679 // choose text to use in mail
\r
683 $message = _ACTIVATE_REGISTER_MAIL;
\r
684 $subject = _ACTIVATE_REGISTER_MAILTITLE;
\r
687 $message = _ACTIVATE_FORGOT_MAIL;
\r
688 $subject = _ACTIVATE_FORGOT_MAILTITLE;
\r
690 case 'addresschange':
\r
691 $message = _ACTIVATE_CHANGE_MAIL;
\r
692 $subject = _ACTIVATE_CHANGE_MAILTITLE;
\r
697 // fill out variables in text
\r
699 'siteName' => $CONF['SiteName'],
\r
700 'siteUrl' => $CONF['IndexURL'],
\r
701 'memberName' => $this->getDisplayName(),
\r
702 'activationUrl' => $url,
\r
703 'activationDays' => $CONF['ActivationDays']
\r
706 $message = Template::fill($message, $aVars);
\r
707 $subject = Template::fill($subject, $aVars);
\r
710 NOTIFICATION::mail($this->getEmail(), $subject ,$message, $CONF['AdminEmail'], i18n::get_current_charset());
\r
712 ActionLog::add(INFO, _ACTIONLOG_ACTIVATIONLINK . ' (' . $this->getDisplayName() . ' / type: ' . $type . ')');
\r
717 * Member::getAdminBlogs()
\r
718 * Returns an array of all blogids for which member has admin rights
\r
721 * @return array weblog IDs in which this member has admin rights
\r
724 public function getAdminBlogs()
\r
728 if ($this->isAdmin())
\r
730 $query = 'SELECT bnumber as blogid from '.sql_table('blog');
\r
734 $query = 'SELECT tblog as blogid from '.sql_table('team').' where tadmin=1 and tmember=' . $this->getID();
\r
737 $res = sql_query($query);
\r
738 if ( sql_num_rows($res) > 0 )
\r
740 while ( $obj = sql_fetch_object($res) )
\r
742 array_push($blogs, $obj->blogid);
\r
749 * Member::getTeamBlogs()
\r
750 * Returns an array of all blogids for which member has team rights
\r
752 * @param boolean $incAdmin whether checking weblog admin rights or not
\r
753 * @return array weblog IDs in which this member join
\r
756 public function getTeamBlogs($incAdmin = 1)
\r
758 $incAdmin = intval($incAdmin);
\r
761 if ( $this->isAdmin() && $incAdmin )
\r
763 $query = 'SELECT bnumber as blogid from '.sql_table('blog');
\r
767 $query = 'SELECT tblog as blogid from '.sql_table('team').' where tmember=' . $this->getID();
\r
770 $res = sql_query($query);
\r
771 if ( sql_num_rows($res) > 0 )
\r
773 while ( $obj = sql_fetch_object($res) )
\r
775 array_push($blogs, $obj->blogid);
\r
782 * Member::getNotifyFromMailAddress()
\r
784 * Returns an email address from which notification of commenting/karma voting can
\r
785 * be sent. A suggestion can be given for when the member is not logged in
\r
787 * @param String $suggest
\r
788 * @return String mail address or suggestion
\r
790 public function getNotifyFromMailAddress($suggest = "")
\r
793 if ( $this->isLoggedIn() )
\r
795 return $this->getDisplayName() . " <" . $this->getEmail() . ">";
\r
797 else if ( NOTIFICATION::address_validation($suggest) )
\r
801 return $CONF['AdminEmail'];
\r
806 * Write data to database
\r
812 public function write()
\r
814 $query = 'UPDATE '.sql_table('member')
\r
815 . " SET mname='" . sql_real_escape_string($this->displayname) . "', "
\r
816 . "mrealname='". sql_real_escape_string($this->realname) . "', "
\r
817 . "mpassword='". sql_real_escape_string($this->password) . "', "
\r
818 . "mcookiekey='". sql_real_escape_string($this->cookiekey) . "', "
\r
819 . "murl='" . sql_real_escape_string($this->url) . "', "
\r
820 . "memail='" . sql_real_escape_string($this->email) . "', "
\r
821 . "madmin=" . intval($this->admin) . ", "
\r
822 . "mnotes='" . sql_real_escape_string($this->notes) . "', "
\r
823 . "mcanlogin=" . intval($this->canlogin) . ", "
\r
824 . "mlocale='" . sql_real_escape_string($this->locale) . "', "
\r
825 . "mautosave=" . intval($this->autosave) . " "
\r
826 . "WHERE mnumber=" . intval($this->id);
\r
831 public function checkCookieKey($key)
\r
833 return ( ($key != '') && ( $key == $this->getCookieKey() ) );
\r
836 public function checkPassword($pw)
\r
838 /* for lower compatibility (md5) */
\r
839 if ( strlen($this->password) === 32 )
\r
841 return (md5($pw) == $this->password);
\r
843 return ($this->hash($pw) == $this->password);
\r
846 public function getRealName()
\r
848 return $this->realname;
\r
851 public function setRealName($name)
\r
853 $this->realname = $name;
\r
856 public function getEmail()
\r
858 return $this->email;
\r
861 public function setEmail($email)
\r
863 $this->email = $email;
\r
866 public function getPassword()
\r
868 return $this->password;
\r
871 public function setPassword($pwd)
\r
873 $this->password = $this->hash($pwd);
\r
876 public function getCookieKey()
\r
878 return $this->cookiekey;
\r
882 * Member::newCookieKey()
\r
883 * Generate new cookiekey, save it, and return it
\r
889 public function newCookieKey()
\r
891 mt_srand( (double) microtime() * 1000000);
\r
892 $this->cookiekey = $this->hash(uniqid(mt_rand()));
\r
894 return $this->cookiekey;
\r
897 public function setCookieKey($val)
\r
899 $this->cookiekey = $val;
\r
902 public function getURL()
\r
907 public function setURL($site)
\r
909 $this->url = $site;
\r
912 public function getLocale()
\r
914 return $this->locale;
\r
917 public function setLocale($locale)
\r
919 if ( !preg_match('#^(.+)_(.+)_(.+)$#', $locale)
\r
920 && ($locale = i18n::convert_old_language_file_name_to_locale($locale)) === FALSE )
\r
924 $this->locale = $locale;
\r
928 public function setDisplayName($nick)
\r
930 $this->displayname = $nick;
\r
933 public function getDisplayName()
\r
935 return $this->displayname;
\r
938 public function isAdmin()
\r
940 return $this->admin;
\r
943 public function setAdmin($val)
\r
945 $this->admin = $val;
\r
948 public function canLogin()
\r
950 return $this->canlogin;
\r
953 public function setCanLogin($val)
\r
955 $this->canlogin = $val;
\r
958 public function getNotes()
\r
960 return $this->notes;
\r
963 public function setNotes($val)
\r
965 $this->notes = $val;
\r
968 public function getAutosave()
\r
970 return $this->autosave;
\r
973 public function setAutosave($val)
\r
975 $this->autosave = $val;
\r
983 * @return integer id of this member object
\r
986 public function getID()
\r
993 * Returns true if there is a member with the given login name
\r
996 * @param string $name target name
\r
997 * @return boolean whether target name exists or not
\r
999 public static function exists($name)
\r
1001 $r = sql_query('select * FROM '.sql_table('member')." WHERE mname='".sql_real_escape_string($name)."'");
\r
1002 return ( sql_num_rows($r) != 0 );
\r
1006 * Member::existsID()
\r
1007 * Returns true if there is a member with the given ID
\r
1010 * @param integer $id target id
\r
1011 * @return boolean whether target id exists or not
\r
1014 public static function existsID($id)
\r
1016 $r = sql_query('select * FROM '.sql_table('member')." WHERE mnumber='".intval($id)."'");
\r
1017 return (sql_num_rows($r) != 0);
\r
1021 * Member::isNameProtected()
\r
1022 * Checks if a username is protected.
\r
1023 * If so, it can not be used on anonymous comments
\r
1025 * @param string $name target name
\r
1026 * @return boolean whether the name exists or not
\r
1029 public function isNameProtected($name)
\r
1032 $name = strip_tags($name);
\r
1033 $name = trim($name);
\r
1034 return self::exists($name);
\r
1038 * Member::create()
\r
1039 * Adds a new member
\r
1042 * @param String $name
\r
1043 * @param String $realname
\r
1044 * @param String $password
\r
1045 * @param String $email
\r
1046 * @param String $url
\r
1047 * @param String $admin
\r
1048 * @param String $canlogin
\r
1049 * @param String $notes
\r
1050 * @return String 1 if success, others if fail
\r
1052 static public function create($name, $realname, $password, $email, $url, $admin, $canlogin, $notes)
\r
1054 if ( !NOTIFICATION::address_validation($email) )
\r
1056 return _ERROR_BADMAILADDRESS;
\r
1059 /* TODO: this method should be in MEMBER class, not globalfunctions */
\r
1060 if ( !isValidDisplayName($name) )
\r
1062 return _ERROR_BADNAME;
\r
1065 if ( self::exists($name) )
\r
1067 return _ERROR_NICKNAMEINUSE;
\r
1072 return _ERROR_REALNAMEMISSING;
\r
1075 /* TODO: check the number of characters */
\r
1078 return _ERROR_PASSWORDMISSING;
\r
1082 * begin if: sometimes user didn't prefix the URL with http:// or https://,
\r
1083 * this cause a malformed URL. Let's fix it.
\r
1086 if ( !preg_match('#^https?://#', $url) )
\r
1088 $url = 'http://' . $url;
\r
1091 $name = sql_real_escape_string($name);
\r
1092 $realname = sql_real_escape_string($realname);
\r
1093 /* NOTE: hashed password is automatically updated if the length is 32 bytes when logging in */
\r
1094 $password = sql_real_escape_string(md5($password));
\r
1095 $email = sql_real_escape_string($email);
\r
1096 $url = sql_real_escape_string($url);
\r
1097 $admin = (integer) $admin;
\r
1098 $canlogin = (integer) $canlogin;
\r
1099 $notes = sql_real_escape_string($notes);
\r
1101 $query = "INSERT INTO %s"
\r
1102 . " (MNAME,MREALNAME,MPASSWORD,MEMAIL,MURL, MADMIN, MCANLOGIN, MNOTES)"
\r
1103 . " VALUES ('%s','%s','%s','%s','%s',%d, %d, '%s')";
\r
1104 $query = sprintf($query, sql_table('member'), $name, $realname, $password, $email, $url, $admin, $canlogin, $notes);
\r
1105 sql_query($query);
\r
1107 ActionLog::add(INFO, _ACTIONLOG_NEWMEMBER . ' ' . $name);
\r
1113 * Member::getActivationInfo()
\r
1114 * Returns activation info for a certain key (an object with properties vkey, vmember, ...)
\r
1117 * @param string $key activation key
\r
1118 * @return mixed return 0 if failed, else return activation table object
\r
1121 public static function getActivationInfo($key)
\r
1123 $query = 'SELECT * FROM ' . sql_table('activation') . ' WHERE vkey=\'' . sql_real_escape_string($key). '\'';
\r
1124 $res = sql_query($query);
\r
1126 if ( !$res || (sql_num_rows($res) == 0) )
\r
1130 return sql_fetch_object($res);
\r
1134 * Member::generateActivationEntry()
\r
1135 * Creates an account activation key
\r
1136 * addresschange -> old email address
\r
1138 * @param string $type one of the following values (determines what to do when activation expires)
\r
1139 * 'register' (new member registration)
\r
1140 * 'forgot' (forgotton password)
\r
1141 * 'addresschange' (member address has changed)
\r
1142 * @param string $extra extra info (needed when validation link expires)
\r
1143 * @return string activation key
\r
1145 public function generateActivationEntry($type, $extra = '')
\r
1147 // clean up old entries
\r
1148 $this->cleanupActivationTable();
\r
1150 // kill any existing entries for the current member (delete is ok)
\r
1151 // (only one outstanding activation key can be present for a member)
\r
1152 sql_query('DELETE FROM ' . sql_table('activation') . ' WHERE vmember=' . intval($this->getID()));
\r
1154 // indicates if the member can log in while the link is active
\r
1155 $canLoginWhileActive = false;
\r
1159 $canLoginWhileActive = true;
\r
1163 case 'addresschange':
\r
1164 $extra = $extra . '/' . ( $this->canLogin() ? '1' : '0' );
\r
1171 // generate a random key
\r
1172 srand((double)microtime()*1000000);
\r
1173 $key = $this->hash(uniqid(rand(), true));
\r
1175 // attempt to add entry in database
\r
1176 // add in database as non-active
\r
1177 $query = 'INSERT INTO ' . sql_table('activation'). ' (vkey, vtime, vmember, vtype, vextra) ';
\r
1178 $query .= 'VALUES (\'' . sql_real_escape_string($key). '\', \'' . date('Y-m-d H:i:s',time()) . '\', \'' . intval($this->getID()). '\', \'' . sql_real_escape_string($type). '\', \'' . sql_real_escape_string($extra). '\')';
\r
1179 if ( sql_query($query) )
\r
1183 // mark member as not allowed to log in
\r
1184 if ( !$canLoginWhileActive )
\r
1186 $this->setCanLogin(0);
\r
1195 * Member::activate()
\r
1196 * Inidicates that an activation link has been clicked and any forms displayed
\r
1197 * there have been successfully filled out.
\r
1199 * @param string $key activation key
\r
1203 public function activate($key)
\r
1205 // get activate info
\r
1206 $info = self::getActivationInfo($key);
\r
1214 switch ( $info->vtype )
\r
1220 // set canlogin value
\r
1222 sql_query('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($CONF['NewMemberCanLogon']). ' WHERE mnumber=' . intval($info->vmember));
\r
1224 case 'addresschange':
\r
1225 // reset old 'canlogin' value
\r
1226 list($oldEmail, $oldCanLogin) = preg_split('#/#', $info->vextra);
\r
1227 sql_query('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($oldCanLogin). ' WHERE mnumber=' . intval($info->vmember));
\r
1231 // delete from activation table
\r
1232 sql_query('DELETE FROM ' . sql_table('activation') . ' WHERE vkey=\'' . sql_real_escape_string($key) . '\'');
\r
1239 * Member::cleanupActivationTable()
\r
1240 * Cleans up entries in the activation table. All entries older than 2 days are removed.
\r
1246 public function cleanupActivationTable()
\r
1249 if ( isset($CONF['ActivationDays']) && intval($CONF['ActivationDays']) > 0 )
\r
1251 $actdays = intval($CONF['ActivationDays']);
\r
1255 $CONF['ActivationDays'] = 2;
\r
1257 $boundary = time() - (60 * 60 * 24 * $actdays);
\r
1259 // 1. walk over all entries, and see if special actions need to be performed
\r
1260 $res = sql_query('SELECT * FROM ' . sql_table('activation') . ' WHERE vtime < \'' . date('Y-m-d H:i:s',$boundary) . '\'');
\r
1262 while ( $o = sql_fetch_object($res) )
\r
1264 switch ( $o->vtype )
\r
1267 // delete all information about this site member. registration is undone because there was
\r
1268 // no timely activation
\r
1269 include_once($DIR_LIBS . 'ADMIN.php');
\r
1270 Admin::deleteOneMember(intval($o->vmember));
\r
1272 case 'addresschange':
\r
1273 // revert the e-mail address of the member back to old address
\r
1274 list($oldEmail, $oldCanLogin) = preg_split('#/#', $o->vextra);
\r
1275 sql_query('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($oldCanLogin). ', memail=\'' . sql_real_escape_string($oldEmail). '\' WHERE mnumber=' . intval($o->vmember));
\r
1278 // delete the activation link and ignore. member can request a new password using the
\r
1279 // forgot password link
\r
1284 // 2. delete activation entries for real
\r
1285 sql_query('DELETE FROM ' . sql_table('activation') . ' WHERE vtime < \'' . date('Y-m-d H:i:s',$boundary) . '\'');
\r
1290 * Member::$language
\r
1297 public $language = '';
\r
1299 * Member::getLanguage()
\r
1306 public function getLanguage()
\r
1308 if ( ($language = i18n::convert_locale_to_old_language_file_name($this->locale)) === FALSE )
\r