00001 <?php 00002 00003 /* 00004 * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 00005 * Copyright (C) 2002-2007 The Nucleus Group 00006 * 00007 * This program is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU General Public License 00009 * as published by the Free Software Foundation; either version 2 00010 * of the License, or (at your option) any later version. 00011 * (see nucleus/documentation/index.html#license for more info) 00012 */ 00021 class MEMBER { 00022 00023 // 1 when authenticated, 0 when not 00024 var $loggedin = 0; 00025 var $password; // not the actual password, but rather a MD5 hash 00026 00027 var $cookiekey; // value that should also be in the client cookie to allow authentication 00028 00029 // member info 00030 var $id = -1; 00031 var $realname; 00032 var $displayname; 00033 var $email; 00034 var $url; 00035 var $language = ''; // name of the language file to use (e.g. 'english' -> english.php) 00036 var $admin = 0; // (either 0 or 1) 00037 var $canlogin = 0; // (either 0 or 1) 00038 var $notes; 00039 00040 // (private) 00041 function MEMBER() { 00042 00043 } 00044 00045 // (static) 00046 function &createFromName($displayname) { 00047 $mem =& new MEMBER(); 00048 $mem->readFromName($displayname); 00049 return $mem; 00050 } 00051 00052 // (static) 00053 function &createFromID($id) { 00054 $mem =& new MEMBER(); 00055 $mem->readFromID($id); 00056 return $mem; 00057 } 00058 00059 function readFromName($displayname) { 00060 return $this->read("mname='".addslashes($displayname)."'"); 00061 } 00062 00063 function readFromID($id) { 00064 return $this->read("mnumber=" . intval($id)); 00065 } 00066 00071 function login($login, $password) { 00072 $this->loggedin = 0; 00073 if (!$this->readFromName($login)) 00074 return 0; 00075 if (!$this->checkPassword($password)) 00076 return 0; 00077 $this->loggedin = 1; 00078 return $this->isLoggedIn(); 00079 } 00080 00081 // login using cookie key 00082 function cookielogin($login, $cookiekey) { 00083 $this->loggedin = 0; 00084 if (!$this->readFromName($login)) 00085 return 0; 00086 if (!$this->checkCookieKey($cookiekey)) 00087 return 0; 00088 $this->loggedin = 1; 00089 return $this->isLoggedIn(); 00090 } 00091 00092 function logout() { 00093 $this->loggedin=0; 00094 } 00095 00096 function isLoggedIn() { 00097 return $this->loggedin; 00098 } 00099 00100 function read($where) { 00101 // read info 00102 $query = 'SELECT * FROM '.sql_table('member') . ' WHERE ' . $where; 00103 00104 $res = sql_query($query); 00105 $obj = mysql_fetch_object($res); 00106 00107 $this->setRealName($obj->mrealname); 00108 $this->setEmail($obj->memail); 00109 $this->password = $obj->mpassword; 00110 $this->setCookieKey($obj->mcookiekey); 00111 $this->setURL($obj->murl); 00112 $this->setDisplayName($obj->mname); 00113 $this->setAdmin($obj->madmin); 00114 $this->id = $obj->mnumber; 00115 $this->setCanLogin($obj->mcanlogin); 00116 $this->setNotes($obj->mnotes); 00117 $this->setLanguage($obj->deflang); 00118 00119 return mysql_num_rows($res); 00120 } 00121 00122 00127 function isBlogAdmin($blogid) { 00128 $query = 'SELECT tadmin FROM '.sql_table('team').' WHERE' 00129 . ' tblog=' . intval($blogid) 00130 . ' and tmember='. $this->getID(); 00131 $res = sql_query($query); 00132 if (mysql_num_rows($res) == 0) 00133 return 0; 00134 else 00135 return (mysql_result($res,0,0) == 1) ; 00136 } 00137 00138 function blogAdminRights($blogid) { 00139 return ($this->isAdmin() || $this->isBlogAdmin($blogid)); 00140 } 00141 00142 00143 function teamRights($blogid) { 00144 return ($this->isAdmin() || $this->isTeamMember($blogid)); 00145 } 00146 00150 function isTeamMember($blogid) { 00151 $query = 'SELECT * FROM '.sql_table('team').' WHERE' 00152 . ' tblog=' . intval($blogid) 00153 . ' and tmember='. $this->getID(); 00154 $res = sql_query($query); 00155 return (mysql_num_rows($res) != 0); 00156 } 00157 00166 function canAlterComment($commentid) { 00167 if ($this->isAdmin()) return 1; 00168 00169 $query = 'SELECT citem as itemid, iblog as blogid, cmember as cauthor, iauthor' 00170 . ' FROM '.sql_table('comment') .', '.sql_table('item').', '.sql_table('blog') 00171 . ' WHERE citem=inumber and iblog=bnumber and cnumber=' . intval($commentid); 00172 $res = sql_query($query); 00173 $obj = mysql_fetch_object($res); 00174 00175 return ($obj->cauthor == $this->getID()) or $this->isBlogAdmin($obj->blogid) or ($obj->iauthor == $this->getID()); 00176 } 00177 00184 function canAlterItem($itemid) { 00185 if ($this->isAdmin()) return 1; 00186 00187 $query = 'SELECT iblog, iauthor FROM '.sql_table('item').' WHERE inumber=' . intval($itemid); 00188 $res = sql_query($query); 00189 $obj = mysql_fetch_object($res); 00190 return ($obj->iauthor == $this->getID()) or $this->isBlogAdmin($obj->iblog); 00191 } 00192 00200 function canUpdateItem($itemid, $newcat) { 00201 global $manager; 00202 00203 // item does not exists -> NOK 00204 if (!$manager->existsItem($itemid,1,1)) return 0; 00205 00206 // cannot alter item -> NOK 00207 if (!$this->canAlterItem($itemid)) return 0; 00208 00209 // if this is a 'newcat' style newcat 00210 // no blog admin of destination blog -> NOK 00211 // blog admin of destination blog -> OK 00212 if (strstr($newcat,'newcat')) { 00213 // get blogid 00214 list($blogid) = sscanf($newcat,'newcat-%d'); 00215 return $this->blogAdminRights($blogid); 00216 } 00217 00218 // category does not exist -> NOK 00219 if (!$manager->existsCategory($newcat)) return 0; 00220 00221 00222 // get item 00223 $item =& $manager->getItem($itemid,1,1); 00224 00225 // old catid = new catid -> OK 00226 if ($item['catid'] == $newcat) return 1; 00227 00228 // not a valid category -> NOK 00229 $validCat = quickQuery('SELECT COUNT(*) AS result FROM '.sql_table('category').' WHERE catid='.intval($newcat)); 00230 if (!$validCat) return 0; 00231 00232 // get destination blog 00233 $source_blogid = getBlogIDFromItemID($itemid); 00234 $dest_blogid = getBlogIDFromCatID($newcat); 00235 00236 // not a team member of destination blog -> NOK 00237 if (!$this->teamRights($dest_blogid)) return 0; 00238 00239 // if member is author of item -> OK 00240 if ($item['authorid'] == $this->getID()) return 1; 00241 00242 // if member has admin rights on both blogs: OK 00243 if (($this->blogAdminRights($dest_blogid)) && ($this->blogAdminRights($source_blogid))) return 1; 00244 00245 // all other cases: NOK 00246 return 0; 00247 00248 } 00249 00250 function canAddItem($catid) { 00251 global $manager; 00252 00253 // if this is a 'newcat' style newcat 00254 // no blog admin of destination blog -> NOK 00255 // blog admin of destination blog -> OK 00256 if (strstr($catid,'newcat')) { 00257 // get blogid 00258 list($blogid) = sscanf($catid,"newcat-%d"); 00259 return $this->blogAdminRights($blogid); 00260 } 00261 00262 // category does not exist -> NOK 00263 if (!$manager->existsCategory($catid)) return 0; 00264 00265 $blogid = getBlogIDFromCatID($catid); 00266 00267 // no team rights for blog -> NOK 00268 if (!$this->teamRights($blogid)) return 0; 00269 00270 // all other cases: OK 00271 return 1; 00272 } 00273 00278 function canBeDeleted() { 00279 $res = sql_query('SELECT * FROM '.sql_table('item').' WHERE iauthor=' . $this->getID()); 00280 return (mysql_num_rows($res) == 0); 00281 } 00282 00290 function setCookies($shared = 0) { 00291 global $CONF; 00292 00293 if ($CONF['SessionCookie'] || $shared) 00294 $lifetime = 0; 00295 else 00296 $lifetime = (time()+2592000); 00297 00298 setcookie($CONF['CookiePrefix'] .'user',$this->getDisplayName(),$lifetime,$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']); 00299 setcookie($CONF['CookiePrefix'] .'loginkey', $this->getCookieKey(),$lifetime,$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']); 00300 00301 // make sure cookies on shared pcs don't get renewed 00302 if ($shared) 00303 setcookie($CONF['CookiePrefix'] .'sharedpc', '1',$lifetime,$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']); 00304 } 00305 00306 function sendActivationLink($type, $extra='') 00307 { 00308 global $CONF; 00309 00310 // generate key and URL 00311 $key = $this->generateActivationEntry($type, $extra); 00312 $url = $CONF['AdminURL'] . 'index.php?action=activate&key=' . $key; 00313 00314 // choose text to use in mail 00315 switch ($type) 00316 { 00317 case 'register': 00318 $message = _ACTIVATE_REGISTER_MAIL; 00319 $title = _ACTIVATE_REGISTER_MAILTITLE; 00320 break; 00321 case 'forgot': 00322 $message = _ACTIVATE_FORGOT_MAIL; 00323 $title = _ACTIVATE_FORGOT_MAILTITLE; 00324 break; 00325 case 'addresschange': 00326 $message = _ACTIVATE_CHANGE_MAIL; 00327 $title = _ACTIVATE_CHANGE_MAILTITLE; 00328 break; 00329 default; 00330 } 00331 00332 // fill out variables in text 00333 00334 $aVars = array( 00335 'siteName' => $CONF['SiteName'], 00336 'siteUrl' => $CONF['IndexURL'], 00337 'memberName' => $this->getDisplayName(), 00338 'activationUrl' => $url 00339 ); 00340 00341 $message = TEMPLATE::fill($message, $aVars); 00342 $title = TEMPLATE::fill($title, $aVars); 00343 00344 // send mail 00345 00346 mb_language('ja'); 00347 mb_internal_encoding(_CHARSET); 00348 @mb_send_mail($this->getEmail(), $title ,$message,'From: ' . $CONF['AdminEmail']); 00349 00350 ACTIONLOG::add(INFO, _ACTIONLOG_ACTIVATIONLINK . ' (' . $this->getDisplayName() . ' / type: ' . $type . ')'); 00351 00352 00353 } 00354 00358 function getAdminBlogs() { 00359 $blogs = array(); 00360 00361 if ($this->isAdmin()) 00362 $query = 'SELECT bnumber as blogid from '.sql_table('blog'); 00363 else 00364 $query = 'SELECT tblog as blogid from '.sql_table('team').' where tadmin=1 and tmember=' . $this->getID(); 00365 00366 $res = sql_query($query); 00367 if (mysql_num_rows($res) > 0) { 00368 while ($obj = mysql_fetch_object($res)) { 00369 array_push($blogs, $obj->blogid); 00370 } 00371 } 00372 00373 return $blogs; 00374 } 00375 00380 function getNotifyFromMailAddress($suggest = "") { 00381 global $CONF; 00382 if ($this->isLoggedIn()) { 00383 return $this->getDisplayName() . " <" . $this->getEmail() . ">"; 00384 } else if (isValidMailAddress($suggest)) { 00385 return $suggest; 00386 } else { 00387 return $CONF['AdminEmail']; 00388 } 00389 } 00390 00394 function write() { 00395 00396 $query = 'UPDATE '.sql_table('member') 00397 . " SET mname='" . addslashes($this->getDisplayName()) . "'," 00398 . " mrealname='". addslashes($this->getRealName()) . "'," 00399 . " mpassword='". addslashes($this->getPassword()) . "'," 00400 . " mcookiekey='". addslashes($this->getCookieKey()) . "'," 00401 . " murl='" . addslashes($this->getURL()) . "'," 00402 . " memail='" . addslashes($this->getEmail()) . "'," 00403 . " madmin=" . $this->isAdmin() . "," 00404 . " mnotes='" . addslashes($this->getNotes()) . "'," 00405 . " mcanlogin=" . $this->canLogin() . "," 00406 . " deflang='" . addslashes($this->getLanguage()) . "'" 00407 . " WHERE mnumber=" . $this->getID(); 00408 sql_query($query); 00409 } 00410 00411 function checkPassword($pw) { 00412 return (md5($pw) == $this->getPassword()); 00413 } 00414 00415 function checkCookieKey($key) { 00416 return (($key != '') && ($key == $this->getCookieKey())); 00417 } 00418 00419 function getRealName() { 00420 return $this->realname; 00421 } 00422 00423 function setRealName($name) { 00424 $this->realname = $name; 00425 } 00426 00427 function getEmail() { 00428 return $this->email; 00429 } 00430 00431 function setEmail($email) { 00432 $this->email = $email; 00433 } 00434 00435 function getPassword() { 00436 return $this->password; 00437 } 00438 00439 function setPassword($pwd) { 00440 $this->password = md5($pwd); 00441 } 00442 00443 function getCookieKey() { 00444 return $this->cookiekey; 00445 } 00446 00450 function newCookieKey() { 00451 mt_srand( (double) microtime() * 1000000); 00452 $this->cookiekey = md5(uniqid(mt_rand())); 00453 $this->write(); 00454 return $this->cookiekey; 00455 } 00456 00457 function setCookieKey($val) { 00458 $this->cookiekey = $val; 00459 } 00460 00461 function getURL() { 00462 return $this->url; 00463 } 00464 00465 function setURL($site) { 00466 $this->url = $site; 00467 } 00468 00469 function getLanguage() { 00470 return $this->language; 00471 } 00472 00473 function setLanguage($lang) { 00474 $this->language = $lang; 00475 } 00476 00477 function setDisplayName($nick) { 00478 $this->displayname = $nick; 00479 } 00480 00481 function getDisplayName() { 00482 return $this->displayname; 00483 } 00484 00485 function isAdmin() { 00486 return $this->admin; 00487 } 00488 00489 function setAdmin($val) { 00490 $this->admin = $val; 00491 } 00492 00493 function canLogin() { 00494 return $this->canlogin; 00495 } 00496 00497 function setCanLogin($val) { 00498 $this->canlogin = $val; 00499 } 00500 00501 function getNotes() { 00502 return $this->notes; 00503 } 00504 00505 function setNotes($val) { 00506 $this->notes = $val; 00507 } 00508 00509 function getID() { 00510 return $this->id; 00511 } 00512 00513 // returns true if there is a member with the given login name (static) 00514 function exists($name) { 00515 $r = sql_query('select * FROM '.sql_table('member')." WHERE mname='".addslashes($name)."'"); 00516 return (mysql_num_rows($r) != 0); 00517 } 00518 00519 // returns true if there is a member with the given ID (static) 00520 function existsID($id) { 00521 $r = sql_query('select * FROM '.sql_table('member')." WHERE mnumber='".intval($id)."'"); 00522 return (mysql_num_rows($r) != 0); 00523 } 00524 00525 // checks if a username is protected. If so, it can not be used on anonymous comments 00526 function isNameProtected($name) { 00527 00528 // extract name 00529 $name = strip_tags($name); 00530 $name = trim($name); 00531 00532 return MEMBER::exists($name); 00533 } 00534 00535 // adds a new member (static) 00536 function create($name, $realname, $password, $email, $url, $admin, $canlogin, $notes) { 00537 if (!isValidMailAddress($email)) 00538 return _ERROR_BADMAILADDRESS; 00539 00540 if (!isValidDisplayName($name)) 00541 return _ERROR_BADNAME; 00542 00543 if (MEMBER::exists($name)) 00544 return _ERROR_NICKNAMEINUSE; 00545 00546 if (!$realname) 00547 return _ERROR_REALNAMEMISSING; 00548 00549 if (!$password) 00550 return _ERROR_PASSWORDMISSING; 00551 00552 // Sometimes user didn't prefix the URL with http://, this cause a malformed URL. Let's fix it. 00553 if (!eregi("^https?://", $url)) 00554 $url = "http://".$url; 00555 00556 $name = addslashes($name); 00557 $realname = addslashes($realname); 00558 $password = addslashes(md5($password)); 00559 $email = addslashes($email); 00560 $url = addslashes($url); 00561 $admin = intval($admin); 00562 $canlogin = intval($canlogin); 00563 $notes = addslashes($notes); 00564 00565 $query = 'INSERT INTO '.sql_table('member')." (MNAME,MREALNAME,MPASSWORD,MEMAIL,MURL, MADMIN, MCANLOGIN, MNOTES) " 00566 . "VALUES ('$name','$realname','$password','$email','$url',$admin, $canlogin, '$notes')"; 00567 sql_query($query); 00568 00569 ACTIONLOG::add(INFO, _ACTIONLOG_NEWMEMBER . ' ' . $name); 00570 00571 return 1; 00572 } 00573 00580 function getActivationInfo($key) 00581 { 00582 $query = 'SELECT * FROM ' . sql_table('activation') . ' WHERE vkey=\'' . addslashes($key). '\''; 00583 $res = sql_query($query); 00584 00585 if (!$res || (mysql_num_rows($res) == 0)) 00586 return 0; 00587 else 00588 return mysql_fetch_object($res); 00589 } 00590 00602 function generateActivationEntry($type, $extra = '') 00603 { 00604 // clean up old entries 00605 $this->cleanupActivationTable(); 00606 00607 // kill any existing entries for the current member (delete is ok) 00608 // (only one outstanding activation key can be present for a member) 00609 sql_query('DELETE FROM ' . sql_table('activation') . ' WHERE vmember=' . intval($this->getID())); 00610 00611 $canLoginWhileActive = false; // indicates if the member can log in while the link is active 00612 switch ($type) 00613 { 00614 case 'forgot': 00615 $canLoginWhileActive = true; 00616 break; 00617 case 'register': 00618 break; 00619 case 'addresschange': 00620 $extra = $extra . '/' . ($this->canLogin() ? '1' : '0'); 00621 break; 00622 } 00623 00624 $ok = false; 00625 while (!$ok) 00626 { 00627 // generate a random key 00628 srand((double)microtime()*1000000); 00629 $key = md5(uniqid(rand(), true)); 00630 00631 // attempt to add entry in database 00632 // add in database as non-active 00633 $query = 'INSERT INTO ' . sql_table('activation'). ' (vkey, vtime, vmember, vtype, vextra) '; 00634 $query .= 'VALUES (\'' . addslashes($key). '\', \'' . date('Y-m-d H:i:s',time()) . '\', \'' . intval($this->getID()). '\', \'' . addslashes($type). '\', \'' . addslashes($extra). '\')'; 00635 if (sql_query($query)) 00636 $ok = true; 00637 } 00638 00639 // mark member as not allowed to log in 00640 if (!$canLoginWhileActive) 00641 { 00642 $this->setCanLogin(0); 00643 $this->write(); 00644 } 00645 00646 // return the key 00647 return $key; 00648 } 00649 00655 function activate($key) 00656 { 00657 // get activate info 00658 $info = MEMBER::getActivationInfo($key); 00659 00660 // no active key 00661 if (!$info) 00662 return false; 00663 00664 switch ($info->vtype) 00665 { 00666 case 'forgot': 00667 // nothing to do 00668 break; 00669 case 'register': 00670 // set canlogin value 00671 global $CONF; 00672 sql_query('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($CONF['NewMemberCanLogon']). ' WHERE mnumber=' . intval($info->vmember)); 00673 break; 00674 case 'addresschange': 00675 // reset old 'canlogin' value 00676 list($oldEmail, $oldCanLogin) = explode('/', $info->vextra); 00677 sql_query('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($oldCanLogin). ' WHERE mnumber=' . intval($info->vmember)); 00678 break; 00679 } 00680 00681 // delete from activation table 00682 sql_query('DELETE FROM ' . sql_table('activation') . ' WHERE vkey=\'' . addslashes($key) . '\''); 00683 00684 // success! 00685 return true; 00686 } 00687 00694 function cleanupActivationTable() 00695 { 00696 $boundary = time() - (60 * 60 * 24 * 2); 00697 00698 // 1. walk over all entries, and see if special actions need to be performed 00699 $res = sql_query('SELECT * FROM ' . sql_table('activation') . ' WHERE vtime < \'' . date('Y-m-d H:i:s',$boundary) . '\''); 00700 00701 while ($o = mysql_fetch_object($res)) 00702 { 00703 switch ($o->vtype) 00704 { 00705 case 'register': 00706 // delete all information about this site member. registration is undone because there was 00707 // no timely activation 00708 include_once($DIR_LIBS . 'ADMIN.php'); 00709 ADMIN::deleteOneMember(intval($o->vmember)); 00710 break; 00711 case 'addresschange': 00712 // revert the e-mail address of the member back to old address 00713 list($oldEmail, $oldCanLogin) = explode('/', $o->vextra); 00714 sql_query('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($oldCanLogin). ', memail=\'' . addslashes($oldEmail). '\' WHERE mnumber=' . intval($o->vmember)); 00715 break; 00716 case 'forgot': 00717 // delete the activation link and ignore. member can request a new password using the 00718 // forgot password link 00719 break; 00720 } 00721 } 00722 00723 // 2. delete activation entries for real 00724 sql_query('DELETE FROM ' . sql_table('activation') . ' WHERE vtime < \'' . date('Y-m-d H:i:s',$boundary) . '\''); 00725 } 00726 00727 } 00728 00729 ?>