OSDN Git Service

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