<<<<<<< HEAD readFromName($displayname); return $mem; } /** * Member::createFromID() * Create a member object for a given ID * * @static * @param Integer $id id for member */ public static function &createFromID($id) { $mem = new Member(); $mem->readFromID($id); return $mem; } /** * Member::readFromName() * Read member table in database * * @param String $displayname login name * @return Object SQL resource * */ public function readFromName($displayname) { return $this->read('mname='.DB::quoteValue($displayname)); } /** * Member::readFromID() * Read member table in database * * @param Integer $id id for member * @return Object SQL resource * */ public function readFromID($id) { return $this->read("mnumber=" . intval($id)); } /** * Member::hash() * hash the target string * * @param String $string target string * @return Void hashed string */ public function hash($string) { switch ( $this->algorism ) { case 'md5': default: $string = md5($string); } return $string; } /** * Member::set_cookie_salt() * * @param integer $key secureCookieKey value * @return void * */ private function set_cookie_salt($key = 0) { if ( !$key ) { $key = 24; } switch( $key ) { case 8: $this->cookie_salt = preg_replace('/\.[0-9]+\.[0-9]+\.[0-9]+$/', '', serverVar('REMOTE_ADDR')); break; case 16: $this->cookie_salt = preg_replace('/\.[0-9]+\.[0-9]+$/', '', serverVar('REMOTE_ADDR')); break; case 24: $this->cookie_salt = preg_replace('/\.[0-9]+$/', '', serverVar('REMOTE_ADDR')); break; case 32: $this->cookie_salt = serverVar('REMOTE_ADDR'); break; default: $this->cookie_salt = 'none'; } return; } /** * Member::login() * Tries to login as a given user. * Returns true when succeeded, returns false when failed * 3.40 adds CustomLogin event * * @param String $login login name for member * @param String $password password for member * @param Integer $shared whether the user agent is shared or not * */ public function login($login, $password, $shared=1) { global $CONF, $errormessage, $manager; /* TODO: validation for $login, $password, $shared */ if ( $login == '' || $password == '' ) { return 0; } /* limiting the length of password to avoid hash collision */ $password=i18n::substr($password, 0, 40); /* * generate cookie salt from secure cookie key settings * (either 'none', 0, 8, 16, 24, or 32) */ if ( !$this->cookie_salt ) { $salt = 0; if ( array_key_exists('secureCookieKey', $CONF) ) { $salt = $CONF['secureCookieKey']; } $this->set_cookie_salt($salt); } $success = 0; $allowlocal = 1; $manager->notify('CustomLogin', array('login' => &$login, 'password'=>&$password, 'success'=>&$success, 'allowlocal'=>&$allowlocal)); $this->loggedin = 0; if ( $success ) { $this->loggedin = ( $this->readFromName($login) ); } elseif ( $allowlocal ) { $this->loggedin = ( $this->readFromName($login) && $this->checkPassword($password) ); } /* login failed */ if ( !$this->loggedin ) { $trimlogin = trim($login); if ( empty($trimlogin) ) { $errormessage = "Please enter a username."; } else { $errormessage = 'Login failed for ' . $login; } $manager->notify('LoginFailed', array('username' => $login) ); ActionLog::add(INFO, $errormessage); } /* login success */ else { /* For lower compatibility */ if ( strlen($this->password) === 32 ) { $this->password = $this->hash($password); } $this->newCookieKey(); $this->setCookies($shared); if ( $this->cookie_salt !== 'none' ) { /* secure cookie key */ $this->setCookieKey($this->hash($this->getCookieKey() . $this->cookie_salt)); $this->write(); } $errormessage = ''; $manager->notify('LoginSuccess', array('member' => &$member, 'username' => $login) ); ActionLog::add(INFO, "Login successful for $login (sharedpc=$shared)"); } return $this->loggedin; } /** * Member::cookielogin() * Login using cookie key * * @param String $login not used * @param String $cookiekey not used * @return Boolean login or not */ public function cookielogin($login='', $cookiekey='') { global $CONF, $manager; if ( !headers_sent() && cookieVar("{$CONF['CookiePrefix']}user") ) { /* Cookie Authentication */ $ck = cookieVar("{$CONF['CookiePrefix']}loginkey"); /* TODO: validation for each cookie values */ /* limiting the length of password to avoid hash collision */ $ck = i18n::substr($ck,0,32); /* * generate cookie salt from secure cookie key settings * (either 'none', 0, 8, 16, 24, or 32) */ if ( !$this->cookie_salt ) { $salt = 0; if ( array_key_exists('secureCookieKey', $CONF) ) { $salt = $CONF['secureCookieKey']; } $this->set_cookie_salt($salt); } if ( $this->cookie_salt !== 'none' ) { $ck = $this->hash($ck . $this->cookie_salt); } $this->loggedin = ( $this->readFromName(cookieVar("{$CONF['CookiePrefix']}user")) && $this->checkCookieKey($ck) ); unset($ck); /* renew cookies when not on a shared computer */ if ( $this->loggedin && (cookieVar($CONF['CookiePrefix'] . 'sharedpc') != 1) ) { $this->setCookieKey(cookieVar("{$CONF['CookiePrefix']}loginkey")); $this->setCookies(); } } return $this->loggedin; } /** * Member::logout() * logout and expire cookie * * @param Void * @return Void */ public function logout() { global $CONF, $manager; if ( !headers_sent() && cookieVar("{$CONF['CookiePrefix']}user") ) { /* remove cookies on logout */ setcookie("{$CONF['CookiePrefix']}user", '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']); setcookie("{$CONF['CookiePrefix']}loginkey", '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']); $manager->notify('Logout', array('username' => cookieVar("{$CONF['CookiePrefix']}user") ) ); } $this->loggedin = 0; return; } /** * Member::isLoggedIn() * return member is loggedin or not * * @param Void * @return Void */ public function isLoggedIn() { return $this->loggedin; } /** * MEMBER:read() * Read member information from the database * * @param String $where where statement * @return Resource SQL resource * */ public function read($where) { // read info $query = 'SELECT * FROM '.sql_table('member') . ' WHERE ' . $where; $row = DB::getRow($query); $this->setRealName($row['mrealname']); $this->setEmail($row['memail']); $this->password = $row['mpassword']; $this->setCookieKey($row['mcookiekey']); $this->setURL($row['murl']); $this->setDisplayName($row['mname']); $this->setAdmin($row['madmin']); $this->id = $row['mnumber']; $this->setCanLogin($row['mcanlogin']); $this->setNotes($row['mnotes']); $this->setLocale($row['mlocale']); $this->setAutosave($row['mautosave']); return $row ? TRUE : FALSE; } /** * Member::isBlogAdmin() * Returns true if member is an admin for the given blog * (returns false if not a team member) * * @param Integer $blogid weblog id * @return Integer weblog admin or not * */ public function isBlogAdmin($blogid) { $query = 'SELECT tadmin FROM '.sql_table('team').' WHERE' . ' tblog=' . intval($blogid) . ' and tmember='. $this->getID(); $res = DB::getValue($query); if ( $res ) return ($res == 1); else return 0; } /** * Member::blogAdminRights() * * @param integer $blogid ID of target weblog * @return boolean whether to have admin rights to the weblog or not * */ public function blogAdminRights($blogid) { return ($this->isAdmin() || $this->isBlogAdmin($blogid)); } /** * Member::teamRights() * * @param integer $blogid ID of target weblog * @return boolean whether to have admin right to the weblog or not * */ public function teamRights($blogid) { return ($this->isAdmin() || $this->isTeamMember($blogid)); } /** * Member::isTeamMember() * Returns true if this member is a team member of the given blog * * @param integer $blogid ID of target weblog * @return boolean whether to join the weblog or not * */ public function isTeamMember($blogid) { $query = 'SELECT * FROM '.sql_table('team').' WHERE' . ' tblog=' . intval($blogid) . ' and tmember='. $this->getID(); $res = DB::getResult($query); return ($res->rowCount() != 0); } /** * Member::canAddItem() * * @param integer $catid ID of target category * @return boolean whether to be able to add items to the category or not * */ public function canAddItem($catid) { global $manager; // if this is a 'newcat' style newcat // no blog admin of destination blog -> NOK // blog admin of destination blog -> OK if ( i18n::strpos($catid,'newcat') === 0 ) { // get blogid list($blogid) = sscanf($catid,"newcat-%d"); return $this->blogAdminRights($blogid); } // category does not exist -> NOK if ( !$manager->existsCategory($catid) ) { return 0; } $blogid = getBlogIDFromCatID($catid); // no team rights for blog -> NOK if (!$this->teamRights($blogid)) { return 0; } // all other cases: OK return 1; } /** * Member::canAlterComment() * Returns true if this member can edit/delete a commentitem. This can be in the * following cases: * - member is a super-admin * - member is the author of the comment * - member is admin of the blog associated with the comment * - member is author of the item associated with the comment * * @param integer $commentid ID of target comment * @return boolean delete/edit the comment or not * */ public function canAlterComment($commentid) { if ( $this->isAdmin() ) { return 1; } $query = 'SELECT citem as itemid, iblog as blogid, cmember as cauthor, iauthor' . ' FROM '.sql_table('comment') .', '.sql_table('item').', '.sql_table('blog') . ' WHERE citem=inumber and iblog=bnumber and cnumber=' . intval($commentid); $res = DB::getRow($query); return ($res['cauthor'] == $this->getID()) or $this->isBlogAdmin($res['blogid']) or ($res['iauthor'] == $this->getID()); } /** * Member::canAlterItem() * Returns true if this member can edit/delete an item. This is true in the following * cases: - member is a super-admin * - member is the author of the item * - member is admin of the the associated blog * * @param integer $itemid ID of target item * @return boolean delete/edit the item or not * */ public function canAlterItem($itemid) { if ($this->isAdmin()) return 1; $query = 'SELECT iblog, iauthor FROM '.sql_table('item').' WHERE inumber=' . intval($itemid); $res = DB::getRow($query); return ($res['iauthor'] == $this->getID()) or $this->isBlogAdmin($res['iblog']); } /** * Member::canBeDeleted() * Return true if member can be deleted. This means that there are no items posted by the member left * * @param void * @return boolean whether there is no items or exists * */ public function canBeDeleted() { $res = DB::getResult('SELECT * FROM '.sql_table('item').' WHERE iauthor=' . $this->getID()); return ( $res->rowCount() == 0 ); } /** * Member::canUpdateItem() * returns true if this member can move/update an item to a given category, * false if not (see comments fot the tests that are executed) * * @param integer $itemid * @param string $newcat (can also be of form 'newcat-x' with x=blogid) * @return boolean whether being able to update the item or not * */ public function canUpdateItem($itemid, $newcat) { global $manager; // item does not exists -> NOK if ( !$manager->existsItem($itemid,1,1) ) { return 0; } // cannot alter item -> NOK if (!$this->canAlterItem($itemid)) { return 0; } // if this is a 'newcat' style newcat // no blog admin of destination blog -> NOK // blog admin of destination blog -> OK if ( i18n::strpos($newcat, 'newcat') === 0 ) { // get blogid list($blogid) = sscanf($newcat, 'newcat-%d'); return $this->blogAdminRights($blogid); } // category does not exist -> NOK if (!$manager->existsCategory($newcat)) { return 0; } // get item $item =& $manager->getItem($itemid,1,1); // old catid = new catid -> OK if ($item['catid'] == $newcat) { return 1; } // not a valid category -> NOK $validCat = DB::getValue('SELECT COUNT(*) AS result FROM '.sql_table('category').' WHERE catid='.intval($newcat)); if ( !$validCat ) { return 0; } // get destination blog $source_blogid = getBlogIDFromItemID($itemid); $dest_blogid = getBlogIDFromCatID($newcat); // not a team member of destination blog -> NOK if ( !$this->teamRights($dest_blogid) ) { return 0; } // if member is author of item -> OK if ( $item['authorid'] == $this->getID() ) { return 1; } // if member has admin rights on both blogs: OK if ( ($this->blogAdminRights($dest_blogid)) && ($this->blogAdminRights($source_blogid)) ) { return 1; } // all other cases: NOK return 0; } /** * Member::setCookies() * Sets the cookies for the member * * @param boolean $shared set this to 1 when using a shared computer. Cookies will expire * at the end of the session in this case. * @return void * */ public function setCookies($shared = 0) { global $CONF; if ( $CONF['SessionCookie'] || $shared ) { $lifetime = 0; } else { $lifetime = time()+2592000; } setcookie($CONF['CookiePrefix'] . 'user', $this->getDisplayName(), $lifetime, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']); setcookie($CONF['CookiePrefix'] . 'loginkey', $this->getCookieKey(), $lifetime, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']); // make sure cookies on shared pcs don't get renewed if ( $shared ) { setcookie($CONF['CookiePrefix'] .'sharedpc', '1',$lifetime,$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']); } return; } /** * Member::sendActivationLink() * Send activation mail * * @param string $type activation type * @param string $extra extra info * @return void */ public function sendActivationLink($type, $extra='') { global $CONF; if ( !isset($CONF['ActivationDays']) ) { $CONF['ActivationDays'] = 2; } // generate key and URL $key = $this->generateActivationEntry($type, $extra); $url = $CONF['AdminURL'] . 'index.php?action=activate&key=' . $key; // choose text to use in mail switch ( $type ) { case 'register': $message = _ACTIVATE_REGISTER_MAIL; $subject = _ACTIVATE_REGISTER_MAILTITLE; break; case 'forgot': $message = _ACTIVATE_FORGOT_MAIL; $subject = _ACTIVATE_FORGOT_MAILTITLE; break; case 'addresschange': $message = _ACTIVATE_CHANGE_MAIL; $subject = _ACTIVATE_CHANGE_MAILTITLE; break; default; } // fill out variables in text $aVars = array( 'siteName' => $CONF['SiteName'], 'siteUrl' => $CONF['IndexURL'], 'memberName' => $this->getDisplayName(), 'activationUrl' => $url, 'activationDays' => $CONF['ActivationDays'] ); $message = Template::fill($message, $aVars); $subject = Template::fill($subject, $aVars); // send mail NOTIFICATION::mail($this->getEmail(), $subject ,$message, $CONF['AdminEmail'], i18n::get_current_charset()); ActionLog::add(INFO, _ACTIONLOG_ACTIVATIONLINK . ' (' . $this->getDisplayName() . ' / type: ' . $type . ')'); return; } /** * Member::getAdminBlogs() * Returns an array of all blogids for which member has admin rights * * @param void * @return array weblog IDs in which this member has admin rights * */ public function getAdminBlogs() { $blogs = array(); if ($this->isAdmin()) { $query = 'SELECT bnumber as blogid from '.sql_table('blog'); } else { $query = 'SELECT tblog as blogid from '.sql_table('team').' where tadmin=1 and tmember=' . $this->getID(); } $res = DB::getResult($query); if ( $res->rowCount() > 0 ) { foreach ( $res as $row ) { array_push($blogs, $row['blogid']); } } return $blogs; } /** * Member::getTeamBlogs() * Returns an array of all blogids for which member has team rights * * @param boolean $incAdmin whether checking weblog admin rights or not * @return array weblog IDs in which this member join * */ public function getTeamBlogs($incAdmin = 1) { $incAdmin = intval($incAdmin); $blogs = array(); if ( $this->isAdmin() && $incAdmin ) { $query = 'SELECT bnumber as blogid from '.sql_table('blog'); } else { $query = 'SELECT tblog as blogid from '.sql_table('team').' where tmember=' . $this->getID(); } $res = DB::getResult($query); if ( $res->rowCount() > 0 ) { foreach ( $res as $row ) { array_push($blogs, $row['blogid']); } } return $blogs; } /** * Member::getNotifyFromMailAddress() * * Returns an email address from which notification of commenting/karma voting can * be sent. A suggestion can be given for when the member is not logged in * * @param String $suggest * @return String mail address or suggestion */ public function getNotifyFromMailAddress($suggest = "") { global $CONF; if ( $this->isLoggedIn() ) { return $this->getDisplayName() . " <" . $this->getEmail() . ">"; } else if ( NOTIFICATION::address_validation($suggest) ) { return $suggest; } return $CONF['AdminEmail']; } /** * Member::write() * Write data to database * * @param void * @return void * */ public function write() { $query = 'UPDATE '.sql_table('member') . ' SET mname=' . DB::quoteValue($this->displayname) . ', ' . 'mrealname='. DB::quoteValue($this->realname) . ', ' . 'mpassword='. DB::quoteValue($this->password) . ', ' . 'mcookiekey='. DB::quoteValue($this->cookiekey) . ', ' . 'murl=' . DB::quoteValue($this->url) . ', ' . 'memail=' . DB::quoteValue($this->email) . ', ' . 'madmin=' . intval($this->admin) . ', ' . 'mnotes=' . DB::quoteValue($this->notes) . ', ' . 'mcanlogin=' . intval($this->canlogin) . ', ' . 'mlocale=' . DB::quoteValue($this->locale) . ', ' . 'mautosave=' . intval($this->autosave) . ' ' . 'WHERE mnumber=' . intval($this->id); DB::execute($query); return; } public function checkCookieKey($key) { return ( ($key != '') && ( $key == $this->getCookieKey() ) ); } public function checkPassword($pw) { /* for lower compatibility (md5) */ if ( strlen($this->password) === 32 ) { return (md5($pw) == $this->password); } return ($this->hash($pw) == $this->password); } public function getRealName() { return $this->realname; } public function setRealName($name) { $this->realname = $name; } public function getEmail() { return $this->email; } public function setEmail($email) { $this->email = $email; } public function getPassword() { return $this->password; } public function setPassword($pwd) { $this->password = $this->hash($pwd); } public function getCookieKey() { return $this->cookiekey; } /** * Member::newCookieKey() * Generate new cookiekey, save it, and return it * * @param void * @return void * */ public function newCookieKey() { mt_srand( (double) microtime() * 1000000); $this->cookiekey = $this->hash(uniqid(mt_rand())); $this->write(); return $this->cookiekey; } public function setCookieKey($val) { $this->cookiekey = $val; } public function getURL() { return $this->url; } public function setURL($site) { $this->url = $site; } public function getLocale() { return $this->locale; } public function setLocale($locale) { if ( !preg_match('#^(.+)_(.+)_(.+)$#', $locale) && ($locale = i18n::convert_old_language_file_name_to_locale($locale)) === FALSE ) { $locale = ''; } $this->locale = $locale; return; } public function setDisplayName($nick) { $this->displayname = $nick; } public function getDisplayName() { return $this->displayname; } public function isAdmin() { return $this->admin; } public function setAdmin($val) { $this->admin = $val; } public function canLogin() { return $this->canlogin; } public function setCanLogin($val) { $this->canlogin = $val; } public function getNotes() { return $this->notes; } public function setNotes($val) { $this->notes = $val; } public function getAutosave() { return $this->autosave; } public function setAutosave($val) { $this->autosave = $val; return; } /** * Member::getID() * * @param void * @return integer id of this member object * */ public function getID() { return $this->id; } /** * Member::exists() * Returns true if there is a member with the given login name * * @static * @param string $name target name * @return boolean whether target name exists or not */ public static function exists($name) { $r = DB::getResult('SELECT * FROM ' . sql_table('member') . ' WHERE mname=' . DB::quoteValue($name)); return ( $r->rowCount() != 0 ); } /** * Member::existsID() * Returns true if there is a member with the given ID * * @static * @param integer $id target id * @return boolean whether target id exists or not * */ public static function existsID($id) { $r = DB::getResult('SELECT * FROM ' . sql_table('member') . ' WHERE mnumber=' . intval($id)); return ( $r->rowCount() != 0 ); } /** * Member::isNameProtected() * Checks if a username is protected. * If so, it can not be used on anonymous comments * * @param string $name target name * @return boolean whether the name exists or not * */ public function isNameProtected($name) { // extract name $name = strip_tags($name); $name = trim($name); return self::exists($name); } /** * Member::create() * Adds a new member * * @static * @param String $name * @param String $realname * @param String $password * @param String $email * @param String $url * @param String $admin * @param String $canlogin * @param String $notes * @return String 1 if success, others if fail */ static public function create($name, $realname, $password, $email, $url, $admin, $canlogin, $notes) { if ( !NOTIFICATION::address_validation($email) ) { return _ERROR_BADMAILADDRESS; } /* TODO: this method should be in MEMBER class, not globalfunctions */ if ( !isValidDisplayName($name) ) { return _ERROR_BADNAME; } if ( self::exists($name) ) { return _ERROR_NICKNAMEINUSE; } if ( !$realname ) { return _ERROR_REALNAMEMISSING; } /* TODO: check the number of characters */ if ( !$password ) { return _ERROR_PASSWORDMISSING; } /* * begin if: sometimes user didn't prefix the URL with http:// or https://, * this cause a malformed URL. Let's fix it. */ if ( !preg_match('#^https?://#', $url) ) { $url = 'http://' . $url; } $name = DB::quoteValue($name); $realname = DB::quoteValue($realname); /* NOTE: hashed password is automatically updated if the length is 32 bytes when logging in */ $password = DB::quoteValue(md5($password)); $email = DB::quoteValue($email); $url = DB::quoteValue($url); $admin = (integer) $admin; $canlogin = (integer) $canlogin; $notes = DB::quoteValue($notes); $query = "INSERT INTO %s" . " (MNAME,MREALNAME,MPASSWORD,MEMAIL,MURL, MADMIN, MCANLOGIN, MNOTES)" . " VALUES (%s, %s, %s, %s, %s, %d, %d, %s)"; $query = sprintf($query, sql_table('member'), $name, $realname, $password, $email, $url, $admin, $canlogin, $notes); DB::execute($query); ActionLog::add(INFO, _ACTIONLOG_NEWMEMBER . ' ' . $name); return 1; } /** * Member::getActivationInfo() * Returns activation info for a certain key (an object with properties vkey, vmember, ...) * * @static * @param string $key activation key * @return mixed return 0 if failed, else return activation table object * */ public static function getActivationInfo($key) { $query = 'SELECT * FROM ' . sql_table('activation') . ' WHERE vkey=' . DB::quoteValue($key); $res = DB::getResult($query); if ( !$res || ($res->rowCount() == 0) ) { return 0; } return $res->fetch(); } /** * Member::generateActivationEntry() * Creates an account activation key * addresschange -> old email address * * @param string $type one of the following values (determines what to do when activation expires) * 'register' (new member registration) * 'forgot' (forgotton password) * 'addresschange' (member address has changed) * @param string $extra extra info (needed when validation link expires) * @return string activation key */ public function generateActivationEntry($type, $extra = '') { // clean up old entries $this->cleanupActivationTable(); // kill any existing entries for the current member (delete is ok) // (only one outstanding activation key can be present for a member) DB::execute('DELETE FROM ' . sql_table('activation') . ' WHERE vmember=' . intval($this->getID())); // indicates if the member can log in while the link is active $canLoginWhileActive = false; switch ( $type ) { case 'forgot': $canLoginWhileActive = true; break; case 'register': break; case 'addresschange': $extra = $extra . '/' . ( $this->canLogin() ? '1' : '0' ); break; } $ok = false; while ( !$ok ) { // generate a random key srand((double)microtime()*1000000); $key = $this->hash(uniqid(rand(), true)); // attempt to add entry in database // add in database as non-active $query = 'INSERT INTO %s (vkey, vtime, vmember, vtype, vextra) VALUES (%s, %s, %d, %s, %s)'; $query = sprintf($query , sql_table('activation') , DB::quoteValue($key) , DB::formatDateTime() , intval($this->getID()) , DB::quoteValue($type) , DB::quoteValue($extra) ); if ( DB::execute($query) !== FALSE ) $ok = true; } // mark member as not allowed to log in if ( !$canLoginWhileActive ) { $this->setCanLogin(0); $this->write(); } // return the key return $key; } /** * Member::activate() * Inidicates that an activation link has been clicked and any forms displayed * there have been successfully filled out. * * @param string $key activation key * @return boolean * */ public function activate($key) { // get activate info $info = self::getActivationInfo($key); // no active key if ( !$info ) { return false; } switch ( $info['vtype'] ) { case 'forgot': // nothing to do break; case 'register': // set canlogin value global $CONF; DB::execute('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($CONF['NewMemberCanLogon']). ' WHERE mnumber=' . intval($info['vmember'])); break; case 'addresschange': // reset old 'canlogin' value list($oldEmail, $oldCanLogin) = preg_split('#/#', $info['vextra']); DB::execute('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($oldCanLogin). ' WHERE mnumber=' . intval($info['vmember'])); break; } // delete from activation table DB::execute('DELETE FROM ' . sql_table('activation') . ' WHERE vkey=' . DB::quoteValue($key)); // success! return true; } /** * Member::cleanupActivationTable() * Cleans up entries in the activation table. All entries older than 2 days are removed. * (static) * * @param void * @return void */ public function cleanupActivationTable() { $actdays = 2; if ( isset($CONF['ActivationDays']) && intval($CONF['ActivationDays']) > 0 ) { $actdays = intval($CONF['ActivationDays']); } else { $CONF['ActivationDays'] = 2; } $boundary = time() - (60 * 60 * 24 * $actdays); // 1. walk over all entries, and see if special actions need to be performed $query = sprintf('SELECT * FROM %s WHERE vtime < %s', sql_table('activation'), DB::formatDateTime($boundary)); $res = DB::getResult($query); foreach ( $res as $row ) { switch ( $row['vtype'] ) { case 'register': // delete all information about this site member. registration is undone because there was // no timely activation include_once($DIR_LIBS . 'ADMIN.php'); Admin::deleteOneMember(intval($row['vmember'])); break; case 'addresschange': // revert the e-mail address of the member back to old address list($oldEmail, $oldCanLogin) = preg_split('#/#', $row['vextra']); DB::execute('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($oldCanLogin). ', memail=' . DB::quoteValue($oldEmail). ' WHERE mnumber=' . intval($row['vmember'])); break; case 'forgot': // delete the activation link and ignore. member can request a new password using the // forgot password link break; } } // 2. delete activation entries for real $query = sprintf('DELETE FROM %s WHERE vtime < %s', sql_table('activation'), DB::formatDateTime($boundary)); DB::execute($query); return; } /** * Member::$language * * @obsolete * @param void * @return void * */ public $language = ''; /** * Member::getLanguage() * * @obsolete * @param void * @return void * */ public function getLanguage() { if ( ($language = i18n::convert_locale_to_old_language_file_name($this->locale)) === FALSE ) { $language = ''; } return $language; } } ======= readFromName($displayname); return $mem; } /** * Member::createFromID() * Create a member object for a given ID * * @static * @param Integer $id id for member */ public static function &createFromID($id) { $mem = new Member(); $mem->readFromID($id); return $mem; } /** * Member::readFromName() * Read member table in database * * @param String $displayname login name * @return Object SQL resource * */ public function readFromName($displayname) { return $this->read('mname='.DB::quoteValue($displayname)); } /** * Member::readFromID() * Read member table in database * * @param Integer $id id for member * @return Object SQL resource * */ public function readFromID($id) { return $this->read("mnumber=" . intval($id)); } /** * Member::hash() * hash the target string * * @param String $string target string * @return Void hashed string */ public function hash($string) { switch ( $this->algorism ) { case 'md5': default: $string = md5($string); } return $string; } /** * Member::set_cookie_salt() * * @param integer $key secureCookieKey value * @return void * */ private function set_cookie_salt($key = 0) { if ( !$key ) { $key = 24; } switch( $key ) { case 8: $this->cookie_salt = preg_replace('/\.[0-9]+\.[0-9]+\.[0-9]+$/', '', serverVar('REMOTE_ADDR')); break; case 16: $this->cookie_salt = preg_replace('/\.[0-9]+\.[0-9]+$/', '', serverVar('REMOTE_ADDR')); break; case 24: $this->cookie_salt = preg_replace('/\.[0-9]+$/', '', serverVar('REMOTE_ADDR')); break; case 32: $this->cookie_salt = serverVar('REMOTE_ADDR'); break; default: $this->cookie_salt = 'none'; } return; } /** * Member::login() * Tries to login as a given user. * Returns true when succeeded, returns false when failed * 3.40 adds CustomLogin event * * @param String $login login name for member * @param String $password password for member * @param Integer $shared whether the user agent is shared or not * */ public function login($login, $password, $shared=1) { global $CONF, $errormessage, $manager; /* TODO: validation for $login, $password, $shared */ if ( $login == '' || $password == '' ) { return 0; } /* limiting the length of password to avoid hash collision */ $password=i18n::substr($password, 0, 40); /* * generate cookie salt from secure cookie key settings * (either 'none', 0, 8, 16, 24, or 32) */ if ( !$this->cookie_salt ) { $salt = 0; if ( array_key_exists('secureCookieKey', $CONF) ) { $salt = $CONF['secureCookieKey']; } $this->set_cookie_salt($salt); } $success = 0; $allowlocal = 1; $data = array('login' => &$login, 'password'=>&$password, 'success'=>&$success, 'allowlocal'=>&$allowlocal); $manager->notify('CustomLogin', $data); $this->loggedin = 0; if ( $success ) { $this->loggedin = ( $this->readFromName($login) ); } elseif ( $allowlocal ) { $this->loggedin = ( $this->readFromName($login) && $this->checkPassword($password) ); } /* login failed */ if ( !$this->loggedin ) { $trimlogin = trim($login); if ( empty($trimlogin) ) { $errormessage = "Please enter a username."; } else { $errormessage = 'Login failed for ' . $login; } $data = array('username' => $login); $manager->notify('LoginFailed', $data); ActionLog::add(INFO, $errormessage); } /* login success */ else { /* For lower compatibility */ if ( strlen($this->password) === 32 ) { $this->password = $this->hash($password); } $this->newCookieKey(); $this->setCookies($shared); if ( $this->cookie_salt !== 'none' ) { /* secure cookie key */ $this->setCookieKey($this->hash($this->getCookieKey() . $this->cookie_salt)); $this->write(); } $errormessage = ''; $data = array('member' => &$this, 'username' => $login); $manager->notify('LoginSuccess', $data); ActionLog::add(INFO, "Login successful for $login (sharedpc=$shared)"); } return $this->loggedin; } /** * Member::cookielogin() * Login using cookie key * * @param String $login not used * @param String $cookiekey not used * @return Boolean login or not */ public function cookielogin($login='', $cookiekey='') { global $CONF, $manager; if ( !headers_sent() && cookieVar("{$CONF['CookiePrefix']}user") ) { /* Cookie Authentication */ $ck = cookieVar("{$CONF['CookiePrefix']}loginkey"); /* TODO: validation for each cookie values */ /* limiting the length of password to avoid hash collision */ $ck = i18n::substr($ck,0,32); /* * generate cookie salt from secure cookie key settings * (either 'none', 0, 8, 16, 24, or 32) */ if ( !$this->cookie_salt ) { $salt = 0; if ( array_key_exists('secureCookieKey', $CONF) ) { $salt = $CONF['secureCookieKey']; } $this->set_cookie_salt($salt); } if ( $this->cookie_salt !== 'none' ) { $ck = $this->hash($ck . $this->cookie_salt); } $this->loggedin = ( $this->readFromName(cookieVar("{$CONF['CookiePrefix']}user")) && $this->checkCookieKey($ck) ); unset($ck); /* renew cookies when not on a shared computer */ if ( $this->loggedin && (cookieVar($CONF['CookiePrefix'] . 'sharedpc') != 1) ) { $this->setCookieKey(cookieVar("{$CONF['CookiePrefix']}loginkey")); $this->setCookies(); } } return $this->loggedin; } /** * Member::logout() * logout and expire cookie * * @param Void * @return Void */ public function logout() { global $CONF, $manager; if ( !headers_sent() && cookieVar("{$CONF['CookiePrefix']}user") ) { /* remove cookies on logout */ setcookie("{$CONF['CookiePrefix']}user", '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']); setcookie("{$CONF['CookiePrefix']}loginkey", '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']); $data = array('username' => cookieVar("{$CONF['CookiePrefix']}user")); $manager->notify('Logout', $data); } $this->loggedin = 0; return; } /** * Member::isLoggedIn() * return member is loggedin or not * * @param Void * @return Void */ public function isLoggedIn() { return $this->loggedin; } /** * MEMBER:read() * Read member information from the database * * @param String $where where statement * @return Resource SQL resource * */ public function read($where) { // read info $query = 'SELECT * FROM '.sql_table('member') . ' WHERE ' . $where; $row = DB::getRow($query); $this->setRealName($row['mrealname']); $this->setEmail($row['memail']); $this->password = $row['mpassword']; $this->setCookieKey($row['mcookiekey']); $this->setURL($row['murl']); $this->setDisplayName($row['mname']); $this->setAdmin($row['madmin']); $this->id = $row['mnumber']; $this->setCanLogin($row['mcanlogin']); $this->setNotes($row['mnotes']); $this->setLocale($row['mlocale']); $this->setAutosave($row['mautosave']); $this->setAdminSkin($row['madminskin']); $this->setBookmarklet($row['mbkmklt']); return $row ? TRUE : FALSE; } /** * Member::isBlogAdmin() * Returns true if member is an admin for the given blog * (returns false if not a team member) * * @param Integer $blogid weblog id * @return Integer weblog admin or not * */ public function isBlogAdmin($blogid) { $query = 'SELECT tadmin FROM '.sql_table('team').' WHERE' . ' tblog=' . intval($blogid) . ' and tmember='. $this->getID(); $res = DB::getValue($query); if ( $res ) return ($res == 1); else return 0; } /** * Member::blogAdminRights() * * @param integer $blogid ID of target weblog * @return boolean whether to have admin rights to the weblog or not * */ public function blogAdminRights($blogid) { return ($this->isAdmin() || $this->isBlogAdmin($blogid)); } /** * Member::teamRights() * * @param integer $blogid ID of target weblog * @return boolean whether to have admin right to the weblog or not * */ public function teamRights($blogid) { return ($this->isAdmin() || $this->isTeamMember($blogid)); } /** * Member::isTeamMember() * Returns true if this member is a team member of the given blog * * @param integer $blogid ID of target weblog * @return boolean whether to join the weblog or not * */ public function isTeamMember($blogid) { $query = 'SELECT * FROM '.sql_table('team').' WHERE' . ' tblog=' . intval($blogid) . ' and tmember='. $this->getID(); $res = DB::getResult($query); return ($res->rowCount() != 0); } /** * Member::canAddItem() * * @param integer $catid ID of target category * @return boolean whether to be able to add items to the category or not * */ public function canAddItem($catid) { global $manager; // if this is a 'newcat' style newcat // no blog admin of destination blog -> NOK // blog admin of destination blog -> OK if ( i18n::strpos($catid,'newcat') === 0 ) { // get blogid list($blogid) = sscanf($catid,"newcat-%d"); return $this->blogAdminRights($blogid); } // category does not exist -> NOK if ( !$manager->existsCategory($catid) ) { return 0; } $blogid = getBlogIDFromCatID($catid); // no team rights for blog -> NOK if (!$this->teamRights($blogid)) { return 0; } // all other cases: OK return 1; } /** * Member::canAlterComment() * Returns true if this member can edit/delete a commentitem. This can be in the * following cases: * - member is a super-admin * - member is the author of the comment * - member is admin of the blog associated with the comment * - member is author of the item associated with the comment * * @param integer $commentid ID of target comment * @return boolean delete/edit the comment or not * */ public function canAlterComment($commentid) { if ( $this->isAdmin() ) { return 1; } $query = 'SELECT citem as itemid, iblog as blogid, cmember as cauthor, iauthor' . ' FROM '.sql_table('comment') .', '.sql_table('item').', '.sql_table('blog') . ' WHERE citem=inumber and iblog=bnumber and cnumber=' . intval($commentid); $res = DB::getRow($query); return ($res['cauthor'] == $this->getID()) or $this->isBlogAdmin($res['blogid']) or ($res['iauthor'] == $this->getID()); } /** * Member::canAlterItem() * Returns true if this member can edit/delete an item. This is true in the following * cases: - member is a super-admin * - member is the author of the item * - member is admin of the the associated blog * * @param integer $itemid ID of target item * @return boolean delete/edit the item or not * */ public function canAlterItem($itemid) { if ($this->isAdmin()) return 1; $query = 'SELECT iblog, iauthor FROM '.sql_table('item').' WHERE inumber=' . intval($itemid); $res = DB::getRow($query); return ($res['iauthor'] == $this->getID()) or $this->isBlogAdmin($res['iblog']); } /** * Member::canBeDeleted() * Return true if member can be deleted. This means that there are no items posted by the member left * * @param void * @return boolean whether there is no items or exists * */ public function canBeDeleted() { $res = DB::getResult('SELECT * FROM '.sql_table('item').' WHERE iauthor=' . $this->getID()); return ( $res->rowCount() == 0 ); } /** * Member::canUpdateItem() * returns true if this member can move/update an item to a given category, * false if not (see comments fot the tests that are executed) * * @param integer $itemid * @param string $newcat (can also be of form 'newcat-x' with x=blogid) * @return boolean whether being able to update the item or not * */ public function canUpdateItem($itemid, $newcat) { global $manager; // item does not exists -> NOK if ( !$manager->existsItem($itemid,1,1) ) { return 0; } // cannot alter item -> NOK if (!$this->canAlterItem($itemid)) { return 0; } // if this is a 'newcat' style newcat // no blog admin of destination blog -> NOK // blog admin of destination blog -> OK if ( i18n::strpos($newcat, 'newcat') === 0 ) { // get blogid list($blogid) = sscanf($newcat, 'newcat-%d'); return $this->blogAdminRights($blogid); } // category does not exist -> NOK if (!$manager->existsCategory($newcat)) { return 0; } // get item $item =& $manager->getItem($itemid,1,1); // old catid = new catid -> OK if ($item['catid'] == $newcat) { return 1; } // not a valid category -> NOK $validCat = DB::getValue('SELECT COUNT(*) AS result FROM '.sql_table('category').' WHERE catid='.intval($newcat)); if ( !$validCat ) { return 0; } // get destination blog $item =& $manager->getItem($itemid, 1, 1); $source_blogid = $item['blogid']; $dest_blogid = getBlogIDFromCatID($newcat); // not a team member of destination blog -> NOK if ( !$this->teamRights($dest_blogid) ) { return 0; } // if member is author of item -> OK if ( $item['authorid'] == $this->getID() ) { return 1; } // if member has admin rights on both blogs: OK if ( ($this->blogAdminRights($dest_blogid)) && ($this->blogAdminRights($source_blogid)) ) { return 1; } // all other cases: NOK return 0; } /** * Member::setCookies() * Sets the cookies for the member * * @param boolean $shared set this to 1 when using a shared computer. Cookies will expire * at the end of the session in this case. * @return void * */ public function setCookies($shared = 0) { global $CONF; if ( $CONF['SessionCookie'] || $shared ) { $lifetime = 0; } else { $lifetime = time()+2592000; } setcookie($CONF['CookiePrefix'] . 'user', $this->getDisplayName(), $lifetime, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']); setcookie($CONF['CookiePrefix'] . 'loginkey', $this->getCookieKey(), $lifetime, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']); // make sure cookies on shared pcs don't get renewed if ( $shared ) { setcookie($CONF['CookiePrefix'] .'sharedpc', '1',$lifetime,$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']); } return; } /** * Member::sendActivationLink() * Send activation mail * * @param string $type activation type * @param string $extra extra info * @return void */ public function sendActivationLink($type, $extra='') { global $CONF; if ( !isset($CONF['ActivationDays']) ) { $CONF['ActivationDays'] = 2; } // generate key and URL $key = $this->generateActivationEntry($type, $extra); $url = $CONF['AdminURL'] . 'index.php?action=activate&key=' . $key; // choose text to use in mail switch ( $type ) { case 'register': $message = _ACTIVATE_REGISTER_MAIL; $subject = _ACTIVATE_REGISTER_MAILTITLE; break; case 'forgot': $message = _ACTIVATE_FORGOT_MAIL; $subject = _ACTIVATE_FORGOT_MAILTITLE; break; case 'addresschange': $message = _ACTIVATE_CHANGE_MAIL; $subject = _ACTIVATE_CHANGE_MAILTITLE; break; default; } // fill out variables in text $aVars = array( 'siteName' => $CONF['SiteName'], 'siteUrl' => $CONF['IndexURL'], 'memberName' => $this->getDisplayName(), 'activationUrl' => $url, 'activationDays' => $CONF['ActivationDays'] ); $message = Template::fill($message, $aVars); $subject = Template::fill($subject, $aVars); // send mail NOTIFICATION::mail($this->getEmail(), $subject ,$message, $CONF['AdminEmail'], i18n::get_current_charset()); ActionLog::add(INFO, _ACTIONLOG_ACTIVATIONLINK . ' (' . $this->getDisplayName() . ' / type: ' . $type . ')'); return; } /** * Member::getAdminBlogs() * Returns an array of all blogids for which member has admin rights * * @param void * @return array weblog IDs in which this member has admin rights * */ public function getAdminBlogs() { $blogs = array(); if ($this->isAdmin()) { $query = 'SELECT bnumber as blogid from '.sql_table('blog'); } else { $query = 'SELECT tblog as blogid from '.sql_table('team').' where tadmin=1 and tmember=' . $this->getID(); } $res = DB::getResult($query); if ( $res->rowCount() > 0 ) { foreach ( $res as $row ) { array_push($blogs, $row['blogid']); } } return $blogs; } /** * Member::getTeamBlogs() * Returns an array of all blogids for which member has team rights * * @param boolean $incAdmin whether checking weblog admin rights or not * @return array weblog IDs in which this member join * */ public function getTeamBlogs($incAdmin = 1) { $incAdmin = intval($incAdmin); $blogs = array(); if ( $this->isAdmin() && $incAdmin ) { $query = 'SELECT bnumber as blogid from '.sql_table('blog'); } else { $query = 'SELECT tblog as blogid from '.sql_table('team').' where tmember=' . $this->getID(); } $res = DB::getResult($query); if ( $res->rowCount() > 0 ) { foreach ( $res as $row ) { array_push($blogs, $row['blogid']); } } return $blogs; } /** * Member::getNotifyFromMailAddress() * * Returns an email address from which notification of commenting/karma voting can * be sent. A suggestion can be given for when the member is not logged in * * @param String $suggest * @return String mail address or suggestion */ public function getNotifyFromMailAddress($suggest = "") { global $CONF; if ( $this->isLoggedIn() ) { return $this->getDisplayName() . " <" . $this->getEmail() . ">"; } else if ( NOTIFICATION::address_validation($suggest) ) { return $suggest; } return $CONF['AdminEmail']; } /** * Member::write() * Write data to database * * @param void * @return void * */ public function write() { $query = 'UPDATE '.sql_table('member') . ' SET mname=' . DB::quoteValue($this->displayname) . ', ' . 'mrealname='. DB::quoteValue($this->realname) . ', ' . 'mpassword='. DB::quoteValue($this->password) . ', ' . 'mcookiekey='. DB::quoteValue($this->cookiekey) . ', ' . 'murl=' . DB::quoteValue($this->url) . ', ' . 'memail=' . DB::quoteValue($this->email) . ', ' . 'madmin=' . intval($this->admin) . ', ' . 'mnotes=' . DB::quoteValue($this->notes) . ', ' . 'mcanlogin=' . intval($this->canlogin) . ', ' . 'mlocale=' . DB::quoteValue($this->locale) . ', ' . 'madminskin=' . DB::quoteValue($this->adminskin) . ', ' . 'mbkmklt=' . DB::quoteValue($this->bookmarklet) . ', ' . 'mautosave=' . intval($this->autosave) . ' ' . 'WHERE mnumber=' . intval($this->id); DB::execute($query); return; } public function checkCookieKey($key) { return ( ($key != '') && ( $key == $this->getCookieKey() ) ); } public function checkPassword($pw) { /* for lower compatibility (md5) */ if ( strlen($this->password) === 32 ) { return (md5($pw) == $this->password); } return ($this->hash($pw) == $this->password); } public function getRealName() { return $this->realname; } public function setRealName($name) { $this->realname = $name; } public function getEmail() { return $this->email; } public function setEmail($email) { $this->email = $email; } public function getPassword() { return $this->password; } public function setPassword($pwd) { $this->password = $this->hash($pwd); } public function getCookieKey() { return $this->cookiekey; } /** * Member::newCookieKey() * Generate new cookiekey, save it, and return it * * @param void * @return void * */ public function newCookieKey() { mt_srand( (double) microtime() * 1000000); $this->cookiekey = $this->hash(uniqid(mt_rand())); $this->write(); return $this->cookiekey; } public function setCookieKey($val) { $this->cookiekey = $val; } public function getURL() { return $this->url; } public function setURL($site) { $this->url = $site; } public function setAdminSkin($skin) { $this->adminskin = $skin; } public function setBookmarklet($skin) { $this->bookmarklet = $skin; } public function getAdminSkin() { return $this->adminskin; } public function getBookmarklet() { return $this->bookmarklet; } public function getLocale() { return $this->locale; } public function setLocale($locale) { if ( !preg_match('#^(.+)_(.+)_(.+)$#', $locale) && ($locale = i18n::convert_old_language_file_name_to_locale($locale)) === FALSE ) { $locale = ''; } $this->locale = $locale; return; } public function setDisplayName($nick) { $this->displayname = $nick; } public function getDisplayName() { return $this->displayname; } public function isAdmin() { return $this->admin; } public function setAdmin($val) { $this->admin = $val; } public function canLogin() { return $this->canlogin; } public function setCanLogin($val) { $this->canlogin = $val; } public function getNotes() { return $this->notes; } public function setNotes($val) { $this->notes = $val; } public function getAutosave() { return $this->autosave; } public function setAutosave($val) { $this->autosave = $val; return; } /** * Member::getID() * * @param void * @return integer id of this member object * */ public function getID() { return $this->id; } /** * Member::exists() * Returns true if there is a member with the given login name * * @static * @param string $name target name * @return boolean whether target name exists or not */ public static function exists($name) { $r = DB::getResult('SELECT * FROM ' . sql_table('member') . ' WHERE mname=' . DB::quoteValue($name)); return ( $r->rowCount() != 0 ); } /** * Member::existsID() * Returns true if there is a member with the given ID * * @static * @param integer $id target id * @return boolean whether target id exists or not * */ public static function existsID($id) { $r = DB::getResult('SELECT * FROM ' . sql_table('member') . ' WHERE mnumber=' . intval($id)); return ( $r->rowCount() != 0 ); } /** * Member::isNameProtected() * Checks if a username is protected. * If so, it can not be used on anonymous comments * * @param string $name target name * @return boolean whether the name exists or not * */ public function isNameProtected($name) { // extract name $name = strip_tags($name); $name = trim($name); return self::exists($name); } /** * Member::create() * Adds a new member * * @static * @param String $name * @param String $realname * @param String $password * @param String $email * @param String $url * @param String $admin * @param String $canlogin * @param String $notes * @return String 1 if success, others if fail */ static public function create($name, $realname, $password, $email, $url, $admin, $canlogin, $notes) { if ( !NOTIFICATION::address_validation($email) ) { return _ERROR_BADMAILADDRESS; } /* TODO: this method should be in MEMBER class, not globalfunctions */ if ( !isValidDisplayName($name) ) { return _ERROR_BADNAME; } if ( self::exists($name) ) { return _ERROR_NICKNAMEINUSE; } if ( !$realname ) { return _ERROR_REALNAMEMISSING; } /* TODO: check the number of characters */ if ( !$password ) { return _ERROR_PASSWORDMISSING; } /* * begin if: sometimes user didn't prefix the URL with http:// or https://, * this cause a malformed URL. Let's fix it. */ if ( !preg_match('#^https?://#', $url) ) { $url = 'http://' . $url; } $name = DB::quoteValue($name); $realname = DB::quoteValue($realname); /* NOTE: hashed password is automatically updated if the length is 32 bytes when logging in */ $password = DB::quoteValue(md5($password)); $email = DB::quoteValue($email); $url = DB::quoteValue($url); $admin = (integer) $admin; $canlogin = (integer) $canlogin; $notes = DB::quoteValue($notes); $query = "INSERT INTO %s" . " (MNAME,MREALNAME,MPASSWORD,MEMAIL,MURL, MADMIN, MCANLOGIN, MNOTES)" . " VALUES (%s, %s, %s, %s, %s, %d, %d, %s)"; $query = sprintf($query, sql_table('member'), $name, $realname, $password, $email, $url, $admin, $canlogin, $notes); DB::execute($query); ActionLog::add(INFO, _ACTIONLOG_NEWMEMBER . ' ' . $name); return 1; } /** * Member::getActivationInfo() * Returns activation info for a certain key (an object with properties vkey, vmember, ...) * * @static * @param string $key activation key * @return mixed return 0 if failed, else return activation table object * */ public static function getActivationInfo($key) { $query = 'SELECT * FROM ' . sql_table('activation') . ' WHERE vkey=' . DB::quoteValue($key); $res = DB::getResult($query); if ( !$res || ($res->rowCount() == 0) ) { return 0; } return $res->fetch(); } /** * Member::generateActivationEntry() * Creates an account activation key * addresschange -> old email address * * @param string $type one of the following values (determines what to do when activation expires) * 'register' (new member registration) * 'forgot' (forgotton password) * 'addresschange' (member address has changed) * @param string $extra extra info (needed when validation link expires) * @return string activation key */ public function generateActivationEntry($type, $extra = '') { // clean up old entries $this->cleanupActivationTable(); // kill any existing entries for the current member (delete is ok) // (only one outstanding activation key can be present for a member) DB::execute('DELETE FROM ' . sql_table('activation') . ' WHERE vmember=' . intval($this->getID())); // indicates if the member can log in while the link is active $canLoginWhileActive = false; switch ( $type ) { case 'forgot': $canLoginWhileActive = true; break; case 'register': break; case 'addresschange': $extra = $extra . '/' . ( $this->canLogin() ? '1' : '0' ); break; } $ok = false; while ( !$ok ) { // generate a random key srand((double)microtime()*1000000); $key = $this->hash(uniqid(rand(), true)); // attempt to add entry in database // add in database as non-active $query = 'INSERT INTO %s (vkey, vtime, vmember, vtype, vextra) VALUES (%s, %s, %d, %s, %s)'; $query = sprintf($query , sql_table('activation') , DB::quoteValue($key) , DB::formatDateTime() , intval($this->getID()) , DB::quoteValue($type) , DB::quoteValue($extra) ); if ( DB::execute($query) !== FALSE ) $ok = true; } // mark member as not allowed to log in if ( !$canLoginWhileActive ) { $this->setCanLogin(0); $this->write(); } // return the key return $key; } /** * Member::activate() * Inidicates that an activation link has been clicked and any forms displayed * there have been successfully filled out. * * @param string $key activation key * @return boolean * */ public function activate($key) { // get activate info $info = self::getActivationInfo($key); // no active key if ( !$info ) { return false; } switch ( $info['vtype'] ) { case 'forgot': // nothing to do break; case 'register': // set canlogin value global $CONF; DB::execute('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($CONF['NewMemberCanLogon']). ' WHERE mnumber=' . intval($info['vmember'])); break; case 'addresschange': // reset old 'canlogin' value list($oldEmail, $oldCanLogin) = preg_split('#/#', $info['vextra']); DB::execute('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($oldCanLogin). ' WHERE mnumber=' . intval($info['vmember'])); break; } // delete from activation table DB::execute('DELETE FROM ' . sql_table('activation') . ' WHERE vkey=' . DB::quoteValue($key)); // success! return true; } /** * Member::cleanupActivationTable() * Cleans up entries in the activation table. All entries older than 2 days are removed. * (static) * * @param void * @return void */ public function cleanupActivationTable() { $actdays = 2; if ( isset($CONF['ActivationDays']) && intval($CONF['ActivationDays']) > 0 ) { $actdays = intval($CONF['ActivationDays']); } else { $CONF['ActivationDays'] = 2; } $boundary = time() - (60 * 60 * 24 * $actdays); // 1. walk over all entries, and see if special actions need to be performed $query = sprintf('SELECT * FROM %s WHERE vtime < %s', sql_table('activation'), DB::formatDateTime($boundary)); $res = DB::getResult($query); foreach ( $res as $row ) { switch ( $row['vtype'] ) { case 'register': // delete all information about this site member. registration is undone because there was // no timely activation include_once($DIR_LIBS . 'ADMIN.php'); Admin::deleteOneMember(intval($row['vmember'])); break; case 'addresschange': // revert the e-mail address of the member back to old address list($oldEmail, $oldCanLogin) = preg_split('#/#', $row['vextra']); DB::execute('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($oldCanLogin). ', memail=' . DB::quoteValue($oldEmail). ' WHERE mnumber=' . intval($row['vmember'])); break; case 'forgot': // delete the activation link and ignore. member can request a new password using the // forgot password link break; } } // 2. delete activation entries for real $query = sprintf('DELETE FROM %s WHERE vtime < %s', sql_table('activation'), DB::formatDateTime($boundary)); DB::execute($query); return; } /** * Member::$language * * @obsolete * @param void * @return void * */ public $language = ''; /** * Member::getLanguage() * * @obsolete * @param void * @return void * */ public function getLanguage() { if ( ($language = i18n::convert_locale_to_old_language_file_name($this->locale)) === FALSE ) { $language = ''; } return $language; } } >>>>>>> skinnable-master