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