OSDN Git Service

本家Nucleus CMSの開発を補助するためにコミット
[nucleus-jp/nucleus-next.git] / nucleus / libs / MEMBER.php
1 <?php
2
3 /*
4  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
5  * Copyright (C) 2002-2009 The Nucleus Group
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  * (see nucleus/documentation/index.html#license for more info)
12  */
13 /**
14  * A class representing site members
15  *
16  * @license http://nucleuscms.org/license.txt GNU General Public License
17  * @copyright Copyright (C) 2002-2009 The Nucleus Group
18  * @version $Id: MEMBER.php 1616 2012-01-08 09:48:15Z sakamocchi $
19  */
20 class MEMBER {
21         
22         // 1 when authenticated, 0 when not
23         public $loggedin = 0;
24         public $password;               // not the actual password, but rather a MD5 hash
25         
26         public $cookiekey;              // value that should also be in the client cookie to allow authentication
27         
28         // member info
29         public $id = -1;
30         public $realname;
31         public $displayname;
32         public $email;
33         public $url;
34         public $admin = 0;                      // (either 0 or 1)
35         public $canlogin = 0;           // (either 0 or 1)
36         public $notes;
37         public $autosave = 1;           // if the member use the autosave draft function
38         
39         /*
40          * NOTE: $locale value obsoleted $language value since version 4.0
41          */
42         public $language = '';
43         public $locale = '';
44         
45         /**
46          * Constructor for a member object
47          */             
48         public function MEMBER()
49         {
50                 // do nothing
51                 return;
52         }
53
54         /**
55          * Create a member object for a given displayname
56          *
57          * @static               
58          */             
59         public static function &createFromName($displayname)
60         {
61                 $mem = new MEMBER();
62                 $mem->readFromName($displayname);
63                 return $mem;
64         }
65
66         /**
67          * Create a member object for a given ID
68          *
69          * @static      
70          */
71         public static function &createFromID($id)
72         {
73                 $mem = new MEMBER();
74                 $mem->readFromID($id);
75                 return $mem;
76         }
77         
78         public function readFromName($displayname)
79         {
80                 return $this->read("mname='".sql_real_escape_string($displayname)."'");
81         }
82         
83         public function readFromID($id)
84         {
85                 return $this->read("mnumber=" . intval($id));
86         }
87         
88         /*
89          * Tries to login as a given user.
90          * Returns true when succeeded, returns false when failed
91          * 3.40 adds CustomLogin event
92          */
93         public function login($login, $password)
94         {
95                 global $manager;
96                 
97                 $success = 0;
98                 $allowlocal = 1;
99                 $manager->notify('CustomLogin', array('login' => &$login, 'password'=>&$password, 'success'=>&$success, 'allowlocal'=>&$allowlocal));
100                 
101                 $this->loggedin = 0;
102                 if ( $success )
103                 {
104                         $this->loggedin = ( $this->readFromName($login) );
105                 }
106                 elseif ( $allowlocal )
107                 {
108                         $this->loggedin = ( $this->readFromName($login) && $this->checkPassword($password) );
109                 }
110                 return $this->loggedin;
111         }
112         
113         /*
114          * Login using cookie key
115          */
116         public function cookielogin($login, $cookiekey)
117         {
118                 $this->loggedin = ( $this->readFromName($login) && $this->checkCookieKey($cookiekey) );
119                 return $this->loggedin;
120         }
121         
122         public function logout()
123         {
124                 $this->loggedin = 0;
125                 return;
126         }
127         
128         public function isLoggedIn()
129         {
130                 return $this->loggedin;
131         }
132         
133         /*
134          * Read member information from the database 
135          */
136         public function read($where) {
137                 // read info
138                 $query =  'SELECT * FROM '.sql_table('member') . ' WHERE ' . $where;
139                 
140                 $res = sql_query($query);
141                 $obj = sql_fetch_object($res);
142                 
143                 $this->setRealName($obj->mrealname);
144                 $this->setEmail($obj->memail);
145                 $this->password = $obj->mpassword;
146                 $this->setCookieKey($obj->mcookiekey);
147                 $this->setURL($obj->murl);
148                 $this->setDisplayName($obj->mname);
149                 $this->setAdmin($obj->madmin);
150                 $this->id = $obj->mnumber;
151                 $this->setCanLogin($obj->mcanlogin);
152                 $this->setNotes($obj->mnotes);
153                 /*
154                  * FIXME: the name of this field should be 'mlocale', not deflang.
155                  */
156                 $this->setLocale($obj->deflang);
157                 $this->setAutosave($obj->mautosave);
158                 
159                 return sql_num_rows($res);
160         }
161         
162         /*
163          * Returns true if member is an admin for the given blog
164          * (returns false if not a team member)
165          */
166         public function isBlogAdmin($blogid)
167         {
168                 $query = 'SELECT tadmin FROM '.sql_table('team').' WHERE'
169                            . ' tblog=' . intval($blogid)
170                            . ' and tmember='. $this->getID();
171                 $res = sql_query($query);
172                 if ( sql_num_rows($res) == 0 )
173                         return 0;
174                 else
175                         return ( sql_result($res,0,0) == 1 );
176         }
177         
178         public function blogAdminRights($blogid)
179         {
180                 return ($this->isAdmin() || $this->isBlogAdmin($blogid));
181         }
182         
183         public function teamRights($blogid)
184         {
185                 return ($this->isAdmin() || $this->isTeamMember($blogid));
186         }
187
188         /*
189          * Returns true if this member is a team member of the given blog
190          */
191         function isTeamMember($blogid)
192         {
193                 $query = 'SELECT * FROM '.sql_table('team').' WHERE'
194                            . ' tblog=' . intval($blogid)
195                            . ' and tmember='. $this->getID();
196                 $res = sql_query($query);
197                 return (sql_num_rows($res) != 0);
198         }
199
200         function canAddItem($catid)
201         {
202                 global $manager;
203                 
204                 // if this is a 'newcat' style newcat
205                 // no blog admin of destination blog -> NOK
206                 // blog admin of destination blog -> OK
207                 if ( strstr($catid,'newcat') )
208                 {
209                         // get blogid
210                         list($blogid) = sscanf($catid,"newcat-%d");
211                         return $this->blogAdminRights($blogid);
212                 }
213                 
214                 // category does not exist -> NOK
215                 if ( !$manager->existsCategory($catid) )
216                 {
217                         return 0;
218                 }
219                 
220                 $blogid = getBlogIDFromCatID($catid);
221                 
222                 // no team rights for blog -> NOK
223                 if (!$this->teamRights($blogid))
224                 {
225                         return 0;
226                 }
227                 
228                 // all other cases: OK
229                 return 1;
230         }
231         
232         /*
233          * Returns true if this member can edit/delete a commentitem. This can be in the
234          * following cases:
235          *        - member is a super-admin
236          *   - member is the author of the comment
237          *   - member is admin of the blog associated with the comment
238          *   - member is author of the item associated with the comment
239          */
240         public function canAlterComment($commentid)
241         {
242                 if ( $this->isAdmin() )
243                 {
244                         return 1;
245                 }
246         
247                 $query =  'SELECT citem as itemid, iblog as blogid, cmember as cauthor, iauthor'
248                            . ' FROM '.sql_table('comment') .', '.sql_table('item').', '.sql_table('blog')
249                            . ' WHERE citem=inumber and iblog=bnumber and cnumber=' . intval($commentid);
250                 $res = sql_query($query);
251                 $obj = sql_fetch_object($res);
252         
253                 return ($obj->cauthor == $this->getID()) or $this->isBlogAdmin($obj->blogid) or ($obj->iauthor == $this->getID());
254         }
255         
256         /*
257          * Returns true if this member can edit/delete an item. This is true in the following
258          * cases: - member is a super-admin
259          *             - member is the author of the item
260          *        - member is admin of the the associated blog
261          */
262         public function canAlterItem($itemid)
263         {
264                 if ($this->isAdmin()) return 1;
265
266                 $query =  'SELECT iblog, iauthor FROM '.sql_table('item').' WHERE inumber=' . intval($itemid);
267                 $res = sql_query($query);
268                 $obj = sql_fetch_object($res);
269                 return ($obj->iauthor == $this->getID()) or $this->isBlogAdmin($obj->iblog);
270         }
271
272         /*
273          * Return true if member can be deleted. This means that there are no items
274          * posted by the member left
275          */
276         public function canBeDeleted()
277         {
278                 $res = sql_query('SELECT * FROM '.sql_table('item').' WHERE iauthor=' . $this->getID());
279                 return (sql_num_rows($res) == 0);
280         }
281
282         /*
283          * returns true if this member can move/update an item to a given category,
284          * false if not (see comments fot the tests that are executed)
285          *
286          * @param itemid
287          * @param newcat (can also be of form 'newcat-x' with x=blogid)
288          */
289         public function canUpdateItem($itemid, $newcat)
290         {
291                 global $manager;
292
293                 // item does not exists -> NOK
294                 if ( !$manager->existsItem($itemid,1,1) )
295                 {
296                         return 0;
297                 }
298                 
299                 // cannot alter item -> NOK
300                 if (!$this->canAlterItem($itemid))
301                 {
302                         return 0;
303                 }
304                 
305                 // if this is a 'newcat' style newcat
306                 // no blog admin of destination blog -> NOK
307                 // blog admin of destination blog -> OK
308                 if (strstr($newcat,'newcat'))
309                 {
310                         // get blogid
311                         list($blogid) = sscanf($newcat,'newcat-%d');
312                         return $this->blogAdminRights($blogid);
313                 }
314                 
315                 // category does not exist -> NOK
316                 if (!$manager->existsCategory($newcat))
317                 {
318                         return 0;
319                 }
320                 
321                 // get item
322                 $item =& $manager->getItem($itemid,1,1);
323                 
324                 // old catid = new catid -> OK
325                 if ($item['catid'] == $newcat)
326                 {
327                         return 1;
328                 }
329                 
330                 // not a valid category -> NOK
331                 $validCat = quickQuery('SELECT COUNT(*) AS result FROM '.sql_table('category').' WHERE catid='.intval($newcat));
332                 if ( !$validCat )
333                 {
334                         return 0;
335                 }
336                 
337                 // get destination blog
338                 $source_blogid = getBlogIDFromItemID($itemid);
339                 $dest_blogid = getBlogIDFromCatID($newcat);
340                 
341                 // not a team member of destination blog -> NOK
342                 if ( !$this->teamRights($dest_blogid) )
343                 {
344                         return 0;
345                 }
346                 
347                 // if member is author of item -> OK
348                 if ( $item['authorid'] == $this->getID() )
349                 {
350                         return 1;
351                 }
352                 
353                 // if member has admin rights on both blogs: OK
354                 if ( ($this->blogAdminRights($dest_blogid)) && ($this->blogAdminRights($source_blogid)) )
355                 {
356                         return 1;
357                 }
358                 
359                 // all other cases: NOK
360                 return 0;
361         }
362
363         /**
364           * Sets the cookies for the member
365           *
366           * @param shared
367           *             set this to 1 when using a shared computer. Cookies will expire
368           *             at the end of the session in this case.
369           */
370         public function setCookies($shared = 0)
371         {
372                 global $CONF;
373                 
374                 if ( $CONF['SessionCookie'] || $shared )
375                 {
376                         $lifetime = 0;
377                 }
378                 else
379                 {
380                         $lifetime = time()+2592000;
381                 }
382                 
383                 setcookie($CONF['CookiePrefix'] .'user',$this->getDisplayName(),$lifetime,$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);
384                 setcookie($CONF['CookiePrefix'] .'loginkey', $this->getCookieKey(),$lifetime,$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);
385                 
386                 // make sure cookies on shared pcs don't get renewed
387                 if ( $shared )
388                 {
389                         setcookie($CONF['CookiePrefix'] .'sharedpc', '1',$lifetime,$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);
390                 }
391                 return;
392         }
393         
394         public function sendActivationLink($type, $extra='')
395         {
396                 global $CONF;
397                 
398                 if (!isset($CONF['ActivationDays']))
399                 {
400                         $CONF['ActivationDays'] = 2;
401                 }
402                 
403                 // generate key and URL
404                 $key = $this->generateActivationEntry($type, $extra);
405                 $url = $CONF['AdminURL'] . 'index.php?action=activate&key=' . $key;
406                 
407                 // choose text to use in mail
408                 switch ( $type )
409                 {
410                         case 'register':
411                                 $message = _ACTIVATE_REGISTER_MAIL;
412                                 $title = _ACTIVATE_REGISTER_MAILTITLE;
413                                 break;
414                         case 'forgot':
415                                 $message = _ACTIVATE_FORGOT_MAIL;
416                                 $title = _ACTIVATE_FORGOT_MAILTITLE;
417                                 break;
418                         case 'addresschange':
419                                 $message = _ACTIVATE_CHANGE_MAIL;
420                                 $title = _ACTIVATE_CHANGE_MAILTITLE;
421                                 break;
422                         default;
423                 }
424                 
425                 // fill out variables in text
426                 $aVars = array(
427                         'siteName' => $CONF['SiteName'],
428                         'siteUrl' => $CONF['IndexURL'],
429                         'memberName' => $this->getDisplayName(),
430                         'activationUrl' => $url,
431                         'activationDays' => $CONF['ActivationDays']
432                 );
433                 
434                 $message = TEMPLATE::fill($message, $aVars);
435                 $title = TEMPLATE::fill($title, $aVars);
436                 
437                 // send mail
438                 i18n::mail($this->getEmail(), $title ,$message, $CONF['AdminEmail']);
439                 
440                 ACTIONLOG::add(INFO, _ACTIONLOG_ACTIVATIONLINK . ' (' . $this->getDisplayName() . ' / type: ' . $type . ')');
441                 return;
442         }
443         
444         /*
445          * Returns an array of all blogids for which member has admin rights
446          */
447         public function getAdminBlogs()
448         {
449                 $blogs = array();
450                 
451                 if ($this->isAdmin())
452                 {
453                         $query = 'SELECT bnumber as blogid from '.sql_table('blog');
454                 }
455                 else
456                 {
457                         $query = 'SELECT tblog as blogid from '.sql_table('team').' where tadmin=1 and tmember=' . $this->getID();
458                 }
459                 
460                 $res = sql_query($query);
461                 if ( sql_num_rows($res) > 0 )
462                 {
463                         while ( $obj = sql_fetch_object($res) )
464                         {
465                                 array_push($blogs, $obj->blogid);
466                         }
467                 }
468                 return $blogs;
469         }
470         
471         /*
472          * Returns an array of all blogids for which member has team rights
473          */
474         public function getTeamBlogs($incAdmin = 1)
475         {
476                 $incAdmin = intval($incAdmin);
477                 $blogs = array();
478                 
479                 if ( $this->isAdmin() && $incAdmin )
480                 {
481                         $query = 'SELECT bnumber as blogid from '.sql_table('blog');
482                 }
483                 else
484                 {
485                         $query = 'SELECT tblog as blogid from '.sql_table('team').' where tmember=' . $this->getID();
486                 }
487                 
488                 $res = sql_query($query);
489                 if ( sql_num_rows($res) > 0 )
490                 {
491                         while ( $obj = sql_fetch_object($res) )
492                         {
493                                 array_push($blogs, $obj->blogid);
494                         }
495                 }
496                 return $blogs;
497         }
498         
499         /*
500          * Returns an email address from which notification of commenting/karma voting can
501          * be sent. A suggestion can be given for when the member is not logged in
502          */
503         public function getNotifyFromMailAddress($suggest = "")
504         {
505                 global $CONF;
506                 if ( $this->isLoggedIn() )
507                 {
508                         return $this->getDisplayName() . " <" . $this->getEmail() . ">";
509                 }
510                 else if ( isValidMailAddress($suggest) )
511                 {
512                         return $suggest;
513                 }
514                 else
515                 {
516                         return $CONF['AdminEmail'];
517                 }
518         }
519         
520         /*
521          * Write data to database
522          */
523         function write()
524         {
525                 $query =  'UPDATE '.sql_table('member')
526                            . " SET mname='" . sql_real_escape_string($this->getDisplayName()) . "',"
527                            . "     mrealname='". sql_real_escape_string($this->getRealName()) . "',"
528                            . "     mpassword='". sql_real_escape_string($this->getPassword()) . "',"
529                            . "     mcookiekey='". sql_real_escape_string($this->getCookieKey()) . "',"
530                            . "     murl='" . sql_real_escape_string($this->getURL()) . "',"
531                            . "     memail='" . sql_real_escape_string($this->getEmail()) . "',"
532                            . "     madmin=" . $this->isAdmin() . ","
533                            . "     mnotes='" . sql_real_escape_string($this->getNotes()) . "',"
534                            . "     mcanlogin=" . $this->canLogin() . ","
535                            . "      deflang='" . sql_real_escape_string($this->getLocale()) . "',"
536                            . "      mautosave=" . intval($this->getAutosave()) . ""                        
537                            . " WHERE mnumber=" . $this->getID();
538                 sql_query($query);
539                 return;
540         }
541         
542         public function checkCookieKey($key)
543         {
544                 return ( ($key != '') && ( $key == $this->getCookieKey() ) );
545         }
546         
547         public function checkPassword($pw)
548         {
549                 return (md5($pw) == $this->getPassword());
550         }
551         
552         public function getRealName()
553         {
554                 return $this->realname;
555         }
556
557         public function setRealName($name)
558         {
559                 $this->realname = $name;
560         }
561
562         public function getEmail()
563         {
564                 return $this->email;
565         }
566
567         public function setEmail($email)
568         {
569                 $this->email = $email;
570         }
571
572         public function getPassword()
573         {
574                 return $this->password;
575         }
576
577         public function setPassword($pwd)
578         {
579                 $this->password = md5($pwd);
580         }
581
582         public function getCookieKey()
583         {
584                 return $this->cookiekey;
585         }
586         
587         /*
588          * Generate new cookiekey, save it, and return it
589          */
590         public function newCookieKey()
591         {
592                 mt_srand( (double) microtime() * 1000000);
593                 $this->cookiekey = md5(uniqid(mt_rand()));
594                 $this->write();
595                 return $this->cookiekey;
596         }
597         
598         public function setCookieKey($val)
599         {
600                 $this->cookiekey = $val;
601         }
602         
603         public function getURL()
604         {
605                 return $this->url;
606         }
607         
608         public function setURL($site)
609         {
610                 $this->url = $site;
611         }
612         
613         /*
614          * FIXME: $this->locale is always correct or not?
615          * NOTE: Deprecated, this will be obsoleted soon.
616          */
617         public function getLanguage()
618         {
619                 if ( ($language = i18n::convert_locale_to_old_language_file_name($this->locale)) === FALSE )
620                 {
621                         $language = '';
622                 }
623                 return $language;
624         }
625         
626         public function getLocale()
627         {
628                 return $this->locale;
629         }
630         
631         /*
632          * FIXME: $locale value should obsolete $language value near future
633          */
634         public function setLocale($locale)
635         {
636                 if ( !!preg_match('#^(.+)_(.+)_(.+)$#', $locale)
637                  && ($locale = i18n::convert_old_language_file_name_to_locale($locale)) === FALSE )
638                 {
639                         $locale = '';
640                 }
641                 $this->locale = $locale;
642                 return;
643         }
644         
645         public function setDisplayName($nick)
646         {
647                 $this->displayname = $nick;
648         }
649         
650         public function getDisplayName()
651         {
652                 return $this->displayname;
653         }
654         
655         public function isAdmin()
656         {
657                 return $this->admin;
658         }
659         
660         public function setAdmin($val)
661         {
662                 $this->admin = $val;
663         }
664         
665         public function canLogin()
666         {
667                 return $this->canlogin;
668         }
669         
670         public function setCanLogin($val)
671         {
672                 $this->canlogin = $val;
673         }
674         
675         public function getNotes()
676         {
677                 return $this->notes;
678         }
679         
680         public function setNotes($val)
681         {
682                 $this->notes = $val;
683         }
684         
685         public function getAutosave()
686         {
687                 return $this->autosave;
688         }
689         
690         public function setAutosave($val)
691         {
692                 $this->autosave = $val;
693         }
694         
695         public function getID()
696         {
697                 return $this->id;
698         }
699         
700         /*
701          * Returns true if there is a member with the given login name
702          * 
703          * @static
704          */
705         public static function exists($name)
706         {
707                 $r = sql_query('select * FROM '.sql_table('member')." WHERE mname='".sql_real_escape_string($name)."'");
708                 return ( sql_num_rows($r) != 0 );
709         }
710         
711         /*
712          * Returns true if there is a member with the given ID
713          *
714          * @static
715          */
716         public static function existsID($id)
717         {
718                 $r = sql_query('select * FROM '.sql_table('member')." WHERE mnumber='".intval($id)."'");
719                 return (sql_num_rows($r) != 0);
720         }
721         
722         /*
723          *  Checks if a username is protected. 
724          *  If so, it can not be used on anonymous comments
725          */
726         function isNameProtected($name)
727         {
728                 // extract name
729                 $name = strip_tags($name);
730                 $name = trim($name);
731                 return MEMBER::exists($name);
732         }
733         
734         /*
735          * Adds a new member
736          * 
737          * @static
738          */
739         public static function create($name, $realname, $password, $email, $url, $admin, $canlogin, $notes)
740         {
741                 if ( !isValidMailAddress($email) )
742                 {
743                         return _ERROR_BADMAILADDRESS;
744                 }
745                 
746                 if ( !isValidDisplayName($name) )
747                 {
748                         return _ERROR_BADNAME;
749                 }
750                 
751                 if ( MEMBER::exists($name) )
752                 {
753                         return _ERROR_NICKNAMEINUSE;
754                 }
755                 
756                 if ( !$realname )
757                 {
758                         return _ERROR_REALNAMEMISSING;
759                 }
760                 
761                 if ( !$password )
762                 {
763                         return _ERROR_PASSWORDMISSING;
764                 }
765                 
766                 // begin if: sometimes user didn't prefix the URL with http:// or https://, this cause a malformed URL. Let's fix it.
767                 if (!preg_match('#^https?://#', $url) )
768                 {
769                         $url = 'http://' . $url;
770                 } // end if
771                 
772                 $name = sql_real_escape_string($name);
773                 $realname = sql_real_escape_string($realname);
774                 $password = sql_real_escape_string(md5($password));
775                 $email = sql_real_escape_string($email);
776                 $url = sql_real_escape_string($url);
777                 $admin = intval($admin);
778                 $canlogin = intval($canlogin);
779                 $notes = sql_real_escape_string($notes);
780                 
781                 $query = 'INSERT INTO '.sql_table('member')." (MNAME,MREALNAME,MPASSWORD,MEMAIL,MURL, MADMIN, MCANLOGIN, MNOTES) "
782                            . "VALUES ('$name','$realname','$password','$email','$url',$admin, $canlogin, '$notes')";
783                 sql_query($query);
784                 
785                 ACTIONLOG::add(INFO, _ACTIONLOG_NEWMEMBER . ' ' . $name);
786                 
787                 return 1;
788         }
789         
790         /*
791          * Returns activation info for a certain key (an object with properties vkey, vmember, ...)
792          * (static)
793          *
794          * @author karma
795          */
796         public static function getActivationInfo($key)
797         {
798                 $query = 'SELECT * FROM ' . sql_table('activation') . ' WHERE vkey=\'' . sql_real_escape_string($key). '\'';
799                 $res = sql_query($query);
800                 
801                 if ( !$res || (sql_num_rows($res) == 0) )
802                 {
803                         return 0;
804                 }
805                 else
806                 {
807                         return sql_fetch_object($res);
808                 }
809         }
810         
811         /*
812          * Creates an account activation key
813          *
814          * @param $type one of the following values (determines what to do when activation expires)
815          *                'register' (new member registration)
816          *                'forgot' (forgotton password)
817          *                'addresschange' (member address has changed)
818          * @param $extra extra info (needed when validation link expires)
819          *                                addresschange -> old email address
820          * @author dekarma
821          */
822         public function generateActivationEntry($type, $extra = '')
823         {
824                 // clean up old entries
825                 $this->cleanupActivationTable();
826                 
827                 // kill any existing entries for the current member (delete is ok)
828                 // (only one outstanding activation key can be present for a member)
829                 sql_query('DELETE FROM ' . sql_table('activation') . ' WHERE vmember=' . intval($this->getID()));
830                 
831                 // indicates if the member can log in while the link is active
832                 $canLoginWhileActive = false;
833                 switch ( $type )
834                 {
835                         case 'forgot':
836                                 $canLoginWhileActive = true;
837                                 break;
838                         case 'register':
839                                 break;
840                         case 'addresschange':
841                                 $extra = $extra . '/' . ( $this->canLogin() ? '1' : '0' );
842                                 break;
843                 }
844                 
845                 $ok = false;
846                 while ( !$ok )
847                 {
848                         // generate a random key
849                         srand((double)microtime()*1000000);
850                         $key = md5(uniqid(rand(), true));
851                         
852                         // attempt to add entry in database
853                         // add in database as non-active
854                         $query = 'INSERT INTO ' . sql_table('activation'). ' (vkey, vtime, vmember, vtype, vextra) ';
855                         $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). '\')';
856                         if ( sql_query($query) )
857                                 $ok = true;
858                 }
859                 
860                 // mark member as not allowed to log in
861                 if ( !$canLoginWhileActive )
862                 {
863                         $this->setCanLogin(0);
864                         $this->write();
865                 }
866                 
867                 // return the key
868                 return $key;
869         }
870         
871         /*
872          * Inidicates that an activation link has been clicked and any forms displayed
873          * there have been successfully filled out.
874          * @author dekarma
875          */
876         function activate($key)
877         {
878                 // get activate info
879                 $info = MEMBER::getActivationInfo($key);
880                 
881                 // no active key
882                 if ( !$info )
883                 {
884                         return false;
885                 }
886                 
887                 switch ( $info->vtype )
888                 {
889                         case 'forgot':
890                                 // nothing to do
891                                 break;
892                         case 'register':
893                                 // set canlogin value
894                                 global $CONF;
895                                 sql_query('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($CONF['NewMemberCanLogon']). ' WHERE mnumber=' . intval($info->vmember));
896                                 break;
897                         case 'addresschange':
898                                 // reset old 'canlogin' value
899                                 list($oldEmail, $oldCanLogin) = i18n::explode('/', $info->vextra);
900                                 sql_query('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($oldCanLogin). ' WHERE mnumber=' . intval($info->vmember));
901                                 break;
902                 }
903                 
904                 // delete from activation table
905                 sql_query('DELETE FROM ' . sql_table('activation') . ' WHERE vkey=\'' . sql_real_escape_string($key) . '\'');
906                 
907                 // success!
908                 return true;
909         }
910         
911         /**
912          * Cleans up entries in the activation table. All entries older than 2 days are removed.
913          * (static)
914          *
915          * @author dekarma
916          */
917         public function cleanupActivationTable()
918         {
919                 $actdays = 2;
920                 if ( isset($CONF['ActivationDays']) && intval($CONF['ActivationDays']) > 0 )
921                 {
922                         $actdays = intval($CONF['ActivationDays']);
923                 }
924                 else
925                 {
926                         $CONF['ActivationDays'] = 2;
927                 }
928                 $boundary = time() - (60 * 60 * 24 * $actdays);
929                 
930                 // 1. walk over all entries, and see if special actions need to be performed
931                 $res = sql_query('SELECT * FROM ' . sql_table('activation') . ' WHERE vtime < \'' . date('Y-m-d H:i:s',$boundary) . '\'');
932                 
933                 while ( $o = sql_fetch_object($res) )
934                 {
935                         switch ( $o->vtype )
936                         {
937                                 case 'register':
938                                         // delete all information about this site member. registration is undone because there was
939                                         // no timely activation
940                                         include_once($DIR_LIBS . 'ADMIN.php');
941                                         ADMIN::deleteOneMember(intval($o->vmember));
942                                         break;
943                                 case 'addresschange':
944                                         // revert the e-mail address of the member back to old address
945                                         list($oldEmail, $oldCanLogin) = i18n::explode('/', $o->vextra);
946                                         sql_query('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($oldCanLogin). ', memail=\'' . sql_real_escape_string($oldEmail). '\' WHERE mnumber=' . intval($o->vmember));
947                                         break;
948                                 case 'forgot':
949                                         // delete the activation link and ignore. member can request a new password using the
950                                         // forgot password link
951                                         break;
952                         }
953                 }
954                 
955                 // 2. delete activation entries for real
956                 sql_query('DELETE FROM ' . sql_table('activation') . ' WHERE vtime < \'' . date('Y-m-d H:i:s',$boundary) . '\'');
957         }
958 }