[ Index ] |
|
Code source de b2evolution 2.1.0-beta |
1 <?php 2 /** 3 * This file implements the User class. 4 * 5 * This file is part of the evoCore framework - {@link http://evocore.net/} 6 * See also {@link http://sourceforge.net/projects/evocms/}. 7 * 8 * @copyright (c)2003-2007 by Francois PLANQUE - {@link http://fplanque.net/} 9 * Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}. 10 * 11 * {@internal License choice 12 * - If you have received this file as part of a package, please find the license.txt file in 13 * the same folder or the closest folder above for complete license terms. 14 * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/) 15 * then you must choose one of the following licenses before using the file: 16 * - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php 17 * - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php 18 * }} 19 * 20 * {@internal Open Source relicensing agreement: 21 * Daniel HAHLER grants Francois PLANQUE the right to license 22 * Daniel HAHLER's contributions to this file and the b2evolution project 23 * under any OSI approved OSS license (http://www.opensource.org/licenses/). 24 * }} 25 * 26 * @package evocore 27 * 28 * {@internal Below is a list of authors who have contributed to design/coding of this file: }} 29 * @author fplanque: Francois PLANQUE 30 * @author blueyed: Daniel HAHLER 31 * 32 * @version $Id: _user.class.php,v 1.2 2007/08/26 17:05:58 blueyed Exp $ 33 */ 34 if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' ); 35 36 load_class('_core/model/dataobjects/_dataobject.class.php'); 37 38 /** 39 * User Class 40 * 41 * @package evocore 42 */ 43 class User extends DataObject 44 { 45 var $login; 46 var $pass; 47 var $firstname; 48 var $lastname; 49 var $nickname; 50 var $idmode; 51 var $locale; 52 var $email; 53 var $url; 54 var $icq; 55 var $aim; 56 var $msn; 57 var $yim; 58 var $ip; 59 var $domain; 60 var $browser; 61 var $datecreated; 62 var $level; 63 64 /** 65 * Does the user accept emails through a message form? 66 * @var boolean 67 */ 68 var $allow_msgform; 69 var $notify; 70 var $showonline; 71 72 /** 73 * Has the user been validated (by email)? 74 * @var boolean 75 */ 76 var $validated; 77 78 /** 79 * Number of posts by this user. Use get_num_posts() to access this (lazy filled). 80 * @var integer 81 * @access protected 82 */ 83 var $_num_posts; 84 85 /** 86 * The ID of the (primary, currently only) group of the user. 87 * @var integer 88 */ 89 var $group_ID; 90 91 /** 92 * Reference to group 93 * @see User::get_Group() 94 * @var Group 95 * @access protected 96 */ 97 var $Group; 98 99 /** 100 * Blog posts statuses permissions 101 */ 102 var $blog_post_statuses = array(); 103 104 /** 105 * Cache for perms. 106 * @access protected 107 * @var array 108 */ 109 var $cache_perms = array(); 110 111 112 /** 113 * Constructor 114 * 115 * @param object DB row 116 */ 117 function User( $db_row = NULL ) 118 { 119 global $default_locale, $Settings, $localtimenow; 120 121 // Call parent constructor: 122 parent::DataObject( 'T_users', 'user_', 'user_ID' ); 123 124 // blueyed> TODO: this will never get translated for the current User if he has another locale/lang set than default, because it gets adjusted AFTER instantiating him/her.. 125 // Use a callback (get_delete_restrictions/get_delete_cascades) instead? Should be also better for performance! 126 // fp> These settings should probably be merged with the global database description used by the installer/upgrader. However I'm not sure about how compelx plugins would be able to integrate then... 127 $this->delete_restrictions = array( 128 array( 'table'=>'T_blogs', 'fk'=>'blog_owner_user_ID', 'msg'=>T_('%d blogs owned by this user') ), 129 array( 'table'=>'T_items__item', 'fk'=>'post_lastedit_user_ID', 'msg'=>T_('%d posts last edited by this user') ), 130 array( 'table'=>'T_items__item', 'fk'=>'post_assigned_user_ID', 'msg'=>T_('%d posts assigned to this user') ), 131 array( 'table'=>'T_links', 'fk'=>'link_creator_user_ID', 'msg'=>T_('%d links created by this user') ), 132 array( 'table'=>'T_links', 'fk'=>'link_lastedit_user_ID', 'msg'=>T_('%d links last edited by this user') ), 133 ); 134 135 $this->delete_cascades = array( 136 array( 'table'=>'T_usersettings', 'fk'=>'uset_user_ID', 'msg'=>T_('%d user settings on collections') ), 137 array( 'table'=>'T_sessions', 'fk'=>'sess_user_ID', 'msg'=>T_('%d sessions opened by this user') ), 138 array( 'table'=>'T_coll_user_perms', 'fk'=>'bloguser_user_ID', 'msg'=>T_('%d user permissions on blogs') ), 139 array( 'table'=>'T_subscriptions', 'fk'=>'sub_user_ID', 'msg'=>T_('%d subscriptions') ), 140 array( 'table'=>'T_items__item', 'fk'=>'post_creator_user_ID', 'msg'=>T_('%d posts created by this user') ), 141 ); 142 143 if( $db_row == NULL ) 144 { // Setting those object properties, which are not "NULL" in DB (MySQL strict mode): 145 146 // echo 'Creating blank user'; 147 $this->set( 'login', 'login' ); 148 $this->set( 'pass', md5('pass') ); 149 $this->set( 'locale', 150 isset( $Settings ) 151 ? $Settings->get('default_locale') // TODO: (settings) use "new users template setting" 152 : $default_locale ); 153 $this->set( 'email', '' ); // fp> TODO: this is an invalid value. Saving the object without a valid email should fail! (actually: it should be fixed by providing a valid email) 154 $this->set( 'level', isset( $Settings ) ? $Settings->get('newusers_level') : 0 ); 155 if( isset($localtimenow) ) 156 { 157 $this->set_datecreated( $localtimenow ); 158 } 159 else 160 { // We don't know local time here! 161 $this->set_datecreated( time() ); 162 } 163 164 if( isset($Settings) ) 165 { // Group for this user: 166 $this->group_ID = $Settings->get('newusers_grp_ID'); 167 } 168 169 $this->set( 'allow_msgform', 1 ); 170 $this->set( 'notify', 1 ); 171 $this->set( 'showonline', 1 ); 172 } 173 else 174 { 175 // echo 'Instanciating existing user'; 176 $this->ID = $db_row->user_ID; 177 $this->login = $db_row->user_login; 178 $this->pass = $db_row->user_pass; 179 $this->firstname = $db_row->user_firstname; 180 $this->lastname = $db_row->user_lastname; 181 $this->nickname = $db_row->user_nickname; 182 $this->idmode = $db_row->user_idmode; 183 $this->locale = $db_row->user_locale; 184 $this->email = $db_row->user_email; 185 $this->url = $db_row->user_url; 186 $this->icq = $db_row->user_icq; 187 $this->aim = $db_row->user_aim; 188 $this->msn = $db_row->user_msn; 189 $this->yim = $db_row->user_yim; 190 $this->ip = $db_row->user_ip; 191 $this->domain = $db_row->user_domain; 192 $this->browser = $db_row->user_browser; 193 $this->datecreated = $db_row->dateYMDhour; 194 $this->level = $db_row->user_level; 195 $this->allow_msgform = $db_row->user_allow_msgform; 196 $this->validated = $db_row->user_validated; 197 $this->notify = $db_row->user_notify; 198 $this->showonline = $db_row->user_showonline; 199 200 // Group for this user: 201 $this->group_ID = $db_row->user_grp_ID; 202 } 203 } 204 205 206 /** 207 * Get a param 208 * 209 * @param string the parameter 210 */ 211 function get( $parname ) 212 { 213 switch( $parname ) 214 { 215 case 'fullname': 216 return $this->firstname.' '.$this->lastname; 217 218 case 'preferredname': 219 return $this->get_preferred_name(); 220 221 case 'num_posts': 222 return $this->get_num_posts(); 223 224 default: 225 // All other params: 226 return parent::get( $parname ); 227 } 228 } 229 230 231 /** 232 * Get preferred name of the user, according to {@link User::$idmode}. 233 * 234 * @return string 235 */ 236 function get_preferred_name() 237 { 238 switch( $this->idmode ) 239 { 240 case 'namefl': 241 return parent::get('firstname').' '.parent::get('lastname'); 242 243 case 'namelf': 244 return parent::get('lastname').' '.parent::get('firstname'); 245 246 default: 247 return parent::get($this->idmode); 248 } 249 } 250 251 252 /** 253 * Get the number of posts for the user. 254 * 255 * @return integer 256 */ 257 function get_num_posts() 258 { 259 global $DB; 260 261 if( is_null( $this->_num_posts ) ) 262 { 263 $this->_num_posts = $DB->get_var( 'SELECT count(*) 264 FROM T_items__item 265 WHERE post_creator_user_ID = '.$this->ID ); 266 } 267 268 return $this->_num_posts; 269 } 270 271 272 /** 273 * Get the path to the media directory. If it does not exist, it will be created. 274 * 275 * If we're {@link is_admin_page() on an admin page}, it adds status messages. 276 * @todo These status messages should rather go to a "syslog" and not be displayed to a normal user 277 * 278 * @param boolean Create the directory, if it does not exist yet? 279 * @return mixed the path as string on success, false if the dir could not be created 280 */ 281 function get_media_dir( $create = true ) 282 { 283 global $basepath, $media_subdir, $Messages, $Settings, $Debuglog; 284 285 if( ! $Settings->get( 'fm_enable_roots_user' ) ) 286 { // User directories are disabled: 287 $Debuglog->add( 'Attempt to access user media dir, but this feature is disabled', 'files' ); 288 return false; 289 } 290 291 $userdir = get_canonical_path( $basepath.$media_subdir.'users/'.$this->login.'/' ); 292 293 if( $create && ! is_dir( $userdir ) ) 294 { 295 if( ! is_writable( dirname($userdir) ) ) 296 { // add error 297 if( is_admin_page() ) 298 { 299 $Messages->add( sprintf( T_("The user's media directory «%s» could not be created, because the parent directory is not writable or does not exist."), rel_path_to_base($userdir) ), 'error' ); 300 } 301 return false; 302 } 303 elseif( !@mkdir( $userdir ) ) 304 { // add error 305 if( is_admin_page() ) 306 { 307 $Messages->add( sprintf( T_("The user's media directory «%s» could not be created."), rel_path_to_base($userdir) ), 'error' ); 308 } 309 return false; 310 } 311 else 312 { // chmod and add note: 313 $chmod = $Settings->get('fm_default_chmod_dir'); 314 if( !empty($chmod) ) 315 { 316 @chmod( $userdir, octdec($chmod) ); 317 } 318 if( is_admin_page() ) 319 { 320 $Messages->add( sprintf( T_("The user's directory «%s» has been created with permissions %s."), rel_path_to_base($userdir), substr( sprintf('%o', fileperms($userdir)), -3 ) ), 'success' ); 321 } 322 } 323 } 324 return $userdir; 325 } 326 327 328 /** 329 * Get the URL to the media folder 330 * 331 * @return string the URL 332 */ 333 function get_media_url() 334 { 335 global $media_url, $Settings, $Debuglog; 336 337 if( ! $Settings->get( 'fm_enable_roots_user' ) ) 338 { // User directories are disabled: 339 $Debuglog->add( 'Attempt to access user media URL, but this feature is disabled', 'files' ); 340 return false; 341 } 342 343 return $media_url.'users/'.$this->login.'/'; 344 } 345 346 347 /** 348 * Set param value 349 * 350 * @param string parameter name 351 * @param mixed parameter value 352 * @return boolean true, if a value has been set; false if it has not changed 353 */ 354 function set( $parname, $parvalue ) 355 { 356 switch( $parname ) 357 { 358 case 'icq': 359 return parent::set_param( $parname, 'number', $parvalue, true ); 360 361 case 'level': 362 case 'notify': 363 case 'showonline': 364 return parent::set_param( $parname, 'number', $parvalue ); 365 366 case 'validated': 367 return parent::set_param( $parname, 'number', $parvalue ? 1 : 0 ); // convert boolean 368 369 default: 370 return parent::set_param( $parname, 'string', $parvalue ); 371 } 372 } 373 374 375 /** 376 * Set date created. 377 * 378 * @param integer seconds since Unix Epoch. 379 */ 380 function set_datecreated( $datecreated, $isYMDhour = false ) 381 { 382 if( !$isYMDhour ) 383 { 384 $datecreated = date('Y-m-d H:i:s', $datecreated ); 385 } 386 // Set value: 387 $this->datecreated = $datecreated; 388 // Remmeber change for later db update: 389 $this->dbchange( 'dateYMDhour', 'string', 'datecreated' ); 390 } 391 392 393 /** 394 * Set email address of the user. 395 * 396 * If the email address has changed and we're configured to invalidate the user in this case, 397 * the user's account gets invalidated here. 398 * 399 * @param string email address to set for the User 400 * @return boolean true, if set; false if not changed 401 */ 402 function set_email( $email ) 403 { 404 global $Settings; 405 406 $r = parent::set_param( 'email', 'string', $email ); 407 408 // Change "validated" status to false (if email has changed and Settings are available, which they are not during install): 409 if( $r && isset($Settings) && $Settings->get('newusers_revalidate_emailchg') ) 410 { // In-validate account, because (changed) email has not been verified yet: 411 parent::set_param( 'validated', 'number', 0 ); 412 } 413 414 return $r; 415 } 416 417 418 /** 419 * Set new Group. 420 * 421 * @param Group the Group object to put the user into 422 * @return boolean true if set, false if not changed 423 */ 424 function set_Group( & $Group ) 425 { 426 if( $Group !== $this->Group ) 427 { 428 $this->Group = & $Group; 429 430 $this->dbchange( 'user_grp_ID', 'number', 'Group->get(\'ID\')' ); 431 432 return true; 433 } 434 435 return false; 436 } 437 438 /** 439 * @deprecated by {@link User::set_Group()} since 1.9 440 */ 441 function setGroup( & $Group ) 442 { 443 global $Debuglog; 444 $Debuglog->add( 'Call to deprecated method User::setGroup(), use set_Group() instead.', 'deprecated' ); 445 return $this->set_Group( $Group ); 446 } 447 448 449 /** 450 * Get the {@link Group} of the user. 451 * 452 * @return Group (by reference) 453 */ 454 function & get_Group() 455 { 456 if( ! isset($this->Group) ) 457 { 458 $GroupCache = & get_Cache( 'GroupCache' ); 459 $this->Group = & $GroupCache->get_by_ID($this->group_ID); 460 } 461 return $this->Group; 462 } 463 464 465 /** 466 * Check permission for this user 467 * 468 * @param string Permission name, can be one of: 469 * - 'upload' 470 * - 'edit_timestamp' 471 * - 'cats_post_statuses', see {@link User::check_perm_catsusers()} 472 * - either group permission names, see {@link Group::check_perm()} 473 * - either blogusers permission names, see {@link User::check_perm_blogusers()} 474 * @param string Permission level 475 * @param boolean Execution will halt if this is !0 and permission is denied 476 * @param mixed Permission target (blog ID, array of cat IDs, Item...) 477 * @return boolean 0 if permission denied 478 */ 479 function check_perm( $permname, $permlevel = 'any', $assert = false, $perm_target = NULL ) 480 { 481 global $Debuglog; 482 483 if( is_object($perm_target) && isset($perm_target->ID) ) 484 { 485 $perm_target_ID = $perm_target->ID; 486 } 487 elseif( !is_array($perm_target) ) 488 { 489 $perm_target_ID = $perm_target; 490 } 491 492 if( isset($perm_target_ID) // if it makes sense to check the cache 493 && isset($this->cache_perms[$permname][$permlevel][$perm_target_ID]) ) 494 { // Permission in available in Cache: 495 $Debuglog->add( "Got perm [$permname][$permlevel][$perm_target_ID] from cache", 'perms' ); 496 return $this->cache_perms[$permname][$permlevel][$perm_target_ID]; 497 } 498 499 $perm = false; 500 501 switch( $permname ) 502 { // What permission do we want to check? 503 case 'cats_post_statuses': 504 case 'cats_post!published': 505 case 'cats_post!protected': 506 case 'cats_post!private': 507 case 'cats_post!draft': 508 case 'cats_post!deprecated': 509 case 'cats_post!redirected': 510 // Category permissions... 511 $perm = $this->check_perm_catsusers( $permname, $permlevel, $perm_target ); 512 if( ! $perm ) 513 { // Check groups category permissions... 514 $this->get_Group(); 515 $perm = $this->Group->check_perm_catsgroups( $permname, $permlevel, $perm_target ); 516 } 517 break; 518 519 case 'blog_ismember': 520 case 'blog_post_statuses': 521 case 'blog_post!published': 522 case 'blog_post!protected': 523 case 'blog_post!private': 524 case 'blog_post!draft': 525 case 'blog_post!deprecated': 526 case 'blog_post!redirected': 527 case 'blog_del_post': 528 case 'blog_comments': 529 case 'blog_properties': 530 case 'blog_cats': 531 case 'blog_genstatic': 532 // Blog permission to edit its properties... 533 534 if( $this->check_perm_blogowner( $perm_target_ID ) ) 535 { // Owner can do *almost* anything: 536 $perm = true; 537 break; 538 } 539 540 /* continue */ 541 542 case 'blog_admin': // This is what the owner does not have access to! 543 544 // Group may grant VIEW access, FULL access: 545 $this->get_Group(); 546 if( $this->Group->check_perm( 'blogs', $permlevel ) ) 547 { // If group grants a global permission: 548 $perm = true; 549 break; 550 } 551 552 if( $perm_target > 0 ) 553 { // Check user perm for this blog: 554 $perm = $this->check_perm_blogusers( $permname, $permlevel, $perm_target_ID ); 555 if( $perm == false ) 556 { // Check groups for permissions to this specific blog: 557 $perm = $this->Group->check_perm_bloggroups( $permname, $permlevel, $perm_target_ID ); 558 } 559 } 560 break; 561 562 case 'item_post!published': 563 case 'item_post!protected': 564 case 'item_post!private': 565 case 'item_post!draft': 566 case 'item_post!deprecated': 567 case 'item_post!redirected': 568 // Get the Blog ID 569 /** 570 * @var Item 571 */ 572 $Item = & $perm_target; 573 $Item->get_Blog(); 574 $blog_ID = $Item->Blog->ID; 575 576 if( $this->check_perm_blogowner( $blog_ID ) ) 577 { // Owner can do *almost* anything: 578 $perm = true; 579 break; 580 } 581 582 // Group may grant VIEW access, FULL access: 583 $this->get_Group(); 584 if( $this->Group->check_perm( 'blogs', $permlevel ) ) 585 { // If group grants a global permission: 586 $perm = true; 587 break; 588 } 589 590 // Check permissions at the blog level: 591 $blog_permname = 'blog_'.substr( $permname, 5 ); 592 $perm = $this->check_perm_blogusers( $blog_permname, $permlevel, $blog_ID, $Item ); 593 if( $perm == false ) 594 { // Check groups for permissions to this specific blog: 595 $perm = $this->Group->check_perm_bloggroups( $blog_permname, $permlevel, $blog_ID, $Item, $this ); 596 } 597 break; 598 599 case 'stats': 600 // Blog permission to edit its properties... 601 $this->get_Group(); 602 603 // Group may grant VIEW acces, FULL access: 604 if( $this->Group->check_perm( $permname, $permlevel ) ) 605 { // If group grants a global permission: 606 $perm = true; 607 break; 608 } 609 610 if( $perm_target > 0 ) 611 { // Check user perm for this blog: 612 $perm = $this->check_perm_blogusers( $permname, $permlevel, $perm_target ); 613 if ( $perm == false ) 614 { // Check groups for permissions to this specific blog: 615 $perm = $this->Group->check_perm_bloggroups( $permname, $permlevel, $perm_target ); 616 } 617 } 618 break; 619 620 case 'edit_timestamp': 621 // Global permission to edit timestamps... 622 // fp> TODO: merge below 623 $perm = ($this->level >= 5); 624 break; 625 626 case 'item': 627 // This is a high level perm... 628 if( !is_a( $perm_target, 'Item' ) ) 629 { 630 debug_die( 'No item provided to permission item:'.$permlevel ); 631 } 632 633 switch( $permlevel ) 634 { 635 case 'edit': 636 $post_status = $perm_target->get( 'status' ); 637 $blog = $perm_target->blog_ID; 638 // Call lower level: 639 $perm = $this->check_perm( 'blog_post_statuses', $post_status, false, $blog ); 640 break; 641 642 default: 643 debug_die( 'Unhandled permission item:'.$permlevel ); 644 } 645 break; 646 647 648 default: 649 // Other global permissions (see if the group can handle them), includes: 650 // files 651 // Forward request to group: 652 $this->get_Group(); 653 $perm = $this->Group->check_perm( $permname, $permlevel, $perm_target ); 654 } 655 656 // echo "<br>Checking user perm $permname:$permlevel:$perm_target"; 657 $Debuglog->add( "User perm $permname:$permlevel:" 658 .( is_object($perm_target) ? get_class($perm_target).'('.$perm_target_ID.')' : $perm_target ) // prevent catchable E_FATAL with PHP 5.2 (because there's no __tostring for e.g. Item) 659 .' => '.($perm?'granted':'DENIED'), 'perms' ); 660 661 if( ! $perm && $assert ) 662 { // We can't let this go on! 663 global $app_name; 664 debug_die( sprintf( /* %s is the application name, usually "b2evolution" */ T_('Group/user permission denied by %s!'), $app_name )." ($permname:$permlevel:$perm_target)" ); 665 } 666 667 if( isset($perm_target_ID) ) 668 { 669 // echo "cache_perms[$permname][$permlevel][$perm_target] = $perm;"; 670 $this->cache_perms[$permname][$permlevel][$perm_target_ID] = $perm; 671 } 672 673 return $perm; 674 } 675 676 677 /** 678 * Check if the user is the owner of the designated blog (whoch gives him a lot of permissions) 679 * 680 * @param integer 681 * @return boolean 682 */ 683 function check_perm_blogowner( $blog_ID ) 684 { 685 if( empty($blog_ID) ) 686 { 687 return false; 688 } 689 690 $BlogCache = & get_Cache('BlogCache'); 691 /** 692 * @var Blog 693 */ 694 $Blog = & $BlogCache->get_by_ID( $blog_ID ); 695 696 return ( $Blog->owner_user_ID == $this->ID ); 697 } 698 699 700 /** 701 * Check permission for this user on a set of specified categories 702 * 703 * This is not for direct use, please call {@link User::check_perm()} instead 704 * 705 * @see User::check_perm() 706 * @param string Permission name, can be one of the following: 707 * - cat_post_statuses 708 * - more to come later... 709 * @param string Permission level 710 * @param array Array of target cat IDs 711 * @return boolean 0 if permission denied 712 */ 713 function check_perm_catsusers( $permname, $permlevel, & $perm_target_cats ) 714 { 715 // Check if permission is granted: 716 switch( $permname ) 717 { 718 case 'cats_post_statuses': 719 case 'cats_post!published': 720 case 'cats_post!protected': 721 case 'cats_post!private': 722 case 'cats_post!draft': 723 case 'cats_post!deprecated': 724 case 'cats_post!redirected': 725 // We'll actually pass this on to blog permissions 726 727 // First we need to create an array of blogs, not cats 728 $perm_target_blogs = array(); 729 foreach( $perm_target_cats as $loop_cat_ID ) 730 { 731 $loop_cat_blog_ID = get_catblog( $loop_cat_ID ); 732 // echo "cat $loop_cat_ID -> blog $loop_cat_blog_ID <br />"; 733 if( ! in_array( $loop_cat_blog_ID, $perm_target_blogs ) ) 734 { // not already in list: add it: 735 $perm_target_blogs[] = $loop_cat_blog_ID; 736 } 737 } 738 739 // Now we'll check permissions for each blog: 740 foreach( $perm_target_blogs as $loop_blog_ID ) 741 { 742 if( ! $this->check_perm( 'blog_'.substr($permname,5), $permlevel, false, $loop_blog_ID ) ) 743 { // If at least one blog is denied: 744 return false; // permission denied 745 } 746 } 747 return true; // Permission granted 748 } 749 750 return false; // permission denied 751 } 752 753 754 /** 755 * Check permission for this user on a specified blog 756 * 757 * This is not for direct use, please call {@link User::check_perm()} instead 758 * 759 * @see User::check_perm() 760 * @param string Permission name, can be one of the following: 761 * - blog_ismember 762 * - blog_post_statuses 763 * - blog_del_post 764 * - blog_comments 765 * - blog_cats 766 * - blog_properties 767 * - blog_genstatic 768 * @param string Permission level 769 * @param integer Permission target blog ID 770 * @param Item Item that we want to edit 771 * @return boolean 0 if permission denied 772 */ 773 function check_perm_blogusers( $permname, $permlevel, $perm_target_blog, $Item = NULL ) 774 { 775 global $DB; 776 // echo "checkin for $permname >= $permlevel on blog $perm_target_blog<br />"; 777 778 $BlogCache = & get_Cache('BlogCache'); 779 /** 780 * @var Blog 781 */ 782 $Blog = & $BlogCache->get_by_ID( $perm_target_blog ); 783 if( ! $Blog->advanced_perms ) 784 { // We do not abide to advanced perms 785 return false; 786 } 787 788 if( ! isset( $this->blog_post_statuses[$perm_target_blog] ) ) 789 { // Allowed blog post statuses have not been loaded yet: 790 if( $this->ID == 0 ) 791 { // User not in DB, nothing to load!: 792 return false; // Permission denied 793 } 794 795 // Load now: 796 // echo 'loading allowed statuses'; 797 $query = " 798 SELECT * 799 FROM T_coll_user_perms 800 WHERE bloguser_blog_ID = $perm_target_blog 801 AND bloguser_user_ID = $this->ID"; 802 $row = $DB->get_row( $query, ARRAY_A ); 803 804 if( empty($row) ) 805 { // No rights set for this Blog/User: remember this (in order not to have the same query next time) 806 $this->blog_post_statuses[$perm_target_blog] = array( 807 'blog_ismember' => '0', 808 'blog_post_statuses' => array(), 809 'blog_edit' => 'no', 810 'blog_del_post' => '0', 811 'blog_comments' => '0', 812 'blog_cats' => '0', 813 'blog_properties' => '0', 814 'blog_admin' => '0', 815 ); 816 } 817 else 818 { // OK, rights found: 819 $this->blog_post_statuses[$perm_target_blog] = array(); 820 821 $this->blog_post_statuses[$perm_target_blog]['blog_ismember'] = $row['bloguser_ismember']; 822 823 $bloguser_perm_post = $row['bloguser_perm_poststatuses']; 824 if( empty($bloguser_perm_post ) ) 825 $this->blog_post_statuses[$perm_target_blog]['blog_post_statuses'] = array(); 826 else 827 $this->blog_post_statuses[$perm_target_blog]['blog_post_statuses'] = explode( ',', $bloguser_perm_post ); 828 829 $this->blog_post_statuses[$perm_target_blog]['blog_edit'] = $row['bloguser_perm_edit']; 830 $this->blog_post_statuses[$perm_target_blog]['blog_del_post'] = $row['bloguser_perm_delpost']; 831 $this->blog_post_statuses[$perm_target_blog]['blog_comments'] = $row['bloguser_perm_comments']; 832 $this->blog_post_statuses[$perm_target_blog]['blog_cats'] = $row['bloguser_perm_cats']; 833 $this->blog_post_statuses[$perm_target_blog]['blog_properties'] = $row['bloguser_perm_properties']; 834 $this->blog_post_statuses[$perm_target_blog]['blog_admin'] = $row['bloguser_perm_admin']; 835 } 836 } 837 838 // Check if permission is granted: 839 switch( $permname ) 840 { 841 case 'stats': 842 // Wiewing stats is the same perm as being authorized to edit properties: (TODO...) 843 if( $permlevel == 'view' ) 844 { 845 return $this->blog_post_statuses[$perm_target_blog]['blog_properties']; 846 } 847 // No other perm can be granted here (TODO...) 848 return false; 849 850 case 'blog_genstatic': 851 case 'blog_post_statuses': 852 // echo count($this->blog_post_statuses); 853 return ( count($this->blog_post_statuses[$perm_target_blog]['blog_post_statuses']) > 0 ); 854 855 case 'blog_post!published': 856 case 'blog_post!protected': 857 case 'blog_post!private': 858 case 'blog_post!draft': 859 case 'blog_post!deprecated': 860 case 'blog_post!redirected': 861 // We want a specific permission: 862 $subperm = substr( $permname, 10 ); 863 // echo "checking : $subperm - ", implode( ',', $this->blog_post_statuses[$perm_target_blog]['blog_post_statuses'] ), '<br />'; 864 $perm = in_array( $subperm, $this->blog_post_statuses[$perm_target_blog]['blog_post_statuses'] ); 865 866 // TODO: the following probably should be handled by the Item class! 867 if( $perm && $permlevel == 'edit' && !empty($Item) ) 868 { // Can we edit this specific Item? 869 switch( $this->blog_post_statuses[$perm_target_blog]['blog_edit'] ) 870 { 871 case 'own': 872 // Own posts only: 873 return ($Item->creator_user_ID == $this->ID); 874 875 case 'lt': 876 // Own + Lower level posts only: 877 if( $Item->creator_user_ID == $this->ID ) 878 { 879 return true; 880 } 881 $item_creator_User = & $Item->get_creator_User(); 882 return ( $item_creator_User->level < $this->level ); 883 884 case 'le': 885 // Own + Lower or equal level posts only: 886 if( $Item->creator_user_ID == $this->ID ) 887 { 888 return true; 889 } 890 $item_creator_User = & $Item->get_creator_User(); 891 return ( $item_creator_User->level <= $this->level ); 892 893 case 'all': 894 return true; 895 896 case 'no': 897 default: 898 return false; 899 } 900 } 901 902 return $perm; 903 904 default: 905 // echo $permname, '=', $this->blog_post_statuses[$perm_target_blog][$permname], ' '; 906 return $this->blog_post_statuses[$perm_target_blog][$permname]; 907 } 908 } 909 910 911 /** 912 * Insert object into DB based on previously recorded changes 913 * 914 * Triggers the plugin event AfterUserInsert. 915 * 916 * @return boolean true on success 917 */ 918 function dbinsert() 919 { 920 global $Plugins; 921 922 if( $result = parent::dbinsert() ) 923 { // We could insert the user object.. 924 925 // Notify plugins: 926 // A user could be created also in another DB (to synchronize it with b2evo) 927 $Plugins->trigger_event( 'AfterUserInsert', $params = array( 'User' => & $this ) ); 928 } 929 930 return $result; 931 } 932 933 934 /** 935 * Update the DB based on previously recorded changes. 936 * 937 * Triggers the plugin event AfterUserUpdate. 938 * 939 * @return boolean true on success 940 */ 941 function dbupdate() 942 { 943 global $DB, $Plugins; 944 945 if( $result = parent::dbupdate() ) 946 { // We could update the user object.. 947 948 // Notify plugins: 949 // Example: A authentication plugin could synchronize/update the password of the user. 950 $Plugins->trigger_event( 'AfterUserUpdate', $params = array( 'User' => & $this ) ); 951 } 952 953 return $result; 954 } 955 956 957 /** 958 * Delete user and dependencies from database 959 * 960 * Includes WAY TOO MANY requests because we try to be compatible with MySQL 3.23, bleh! 961 * 962 * @param Log Log object where output gets added (by reference). 963 */ 964 function dbdelete( & $Log ) 965 { 966 global $DB, $Plugins; 967 968 if( $this->ID == 0 ) debug_die( 'Non persistant object cannot be deleted!' ); 969 970 $DB->begin(); 971 972 // Transform registered user comments to unregistered: 973 $ret = $DB->query( 'UPDATE T_comments 974 SET comment_author_ID = NULL, 975 comment_author = '.$DB->quote( $this->get('preferredname') ).', 976 comment_author_email = '.$DB->quote( $this->get('email') ).', 977 comment_author_url = '.$DB->quote( $this->get('url') ).' 978 WHERE comment_author_ID = '.$this->ID ); 979 if( is_a( $Log, 'log' ) ) 980 { 981 $Log->add( 'Transforming user\'s comments to unregistered comments... '.sprintf( '(%d rows)', $ret ), 'note' ); 982 } 983 984 // Get list of posts that are going to be deleted (3.23) 985 $post_list = implode( ',', $DB->get_col( ' 986 SELECT post_ID 987 FROM T_items__item 988 WHERE post_creator_user_ID = '.$this->ID ) ); 989 990 if( !empty( $post_list ) ) 991 { 992 // Delete comments 993 $ret = $DB->query( "DELETE FROM T_comments 994 WHERE comment_post_ID IN ($post_list)" ); 995 if( is_a( $Log, 'log' ) ) 996 { 997 $Log->add( sprintf( 'Deleted %d comments on user\'s posts.', $ret ), 'note' ); 998 } 999 1000 // Delete post extracats 1001 $ret = $DB->query( "DELETE FROM T_postcats 1002 WHERE postcat_post_ID IN ($post_list)" ); 1003 if( is_a( $Log, 'log' ) ) 1004 { 1005 $Log->add( sprintf( 'Deleted %d extracats of user\'s posts\'.', $ret ) ); // TODO: geeky wording. 1006 } 1007 1008 // Posts will we auto-deleted by parent method 1009 } 1010 else 1011 { // no posts 1012 if( is_a( $Log, 'log' ) ) 1013 { 1014 $Log->add( 'No posts to delete.', 'note' ); 1015 } 1016 } 1017 1018 // remember ID, because parent method resets it to 0 1019 $old_ID = $this->ID; 1020 1021 // Delete main object: 1022 if( ! parent::dbdelete() ) 1023 { 1024 $DB->rollback(); 1025 1026 $Log->add( 'User has not been deleted.', 'error' ); 1027 return false; 1028 } 1029 1030 $DB->commit(); 1031 1032 if( is_a( $Log, 'log' ) ) 1033 { 1034 $Log->add( 'Deleted User.', 'note' ); 1035 } 1036 1037 // Notify plugins: 1038 $this->ID = $old_ID; 1039 $Plugins->trigger_event( 'AfterUserDelete', $params = array( 'User' => & $this ) ); 1040 $this->ID = 0; 1041 1042 return true; 1043 } 1044 1045 1046 function callback_optionsForIdMode( $value ) 1047 { 1048 $field_options = ''; 1049 $idmode = $this->get( 'idmode' ); 1050 1051 foreach( array( 'nickname' => array( T_('Nickname') ), 1052 'login' => array( T_('Login') ), 1053 'firstname' => array( T_('First name') ), 1054 'lastname' => array( T_('Last name') ), 1055 'namefl' => array( T_('First name').' '.T_('Last name'), 1056 implode( ' ', array( $this->get('firstname'), $this->get('lastname') ) ) ), 1057 'namelf' => array( T_('Last name').' '.T_('First name'), 1058 implode( ' ', array( $this->get('lastname'), $this->get('firstname') ) ) ), 1059 ) 1060 as $lIdMode => $lInfo ) 1061 { 1062 $disp = isset( $lInfo[1] ) ? $lInfo[1] : $this->get($lIdMode); 1063 1064 $field_options .= '<option value="'.$lIdMode.'"'; 1065 if( $value == $lIdMode ) 1066 { 1067 $field_options .= ' selected="selected"'; 1068 } 1069 $field_options .= '>'.( !empty( $disp ) ? $disp.' ' : ' - ' ) 1070 .'«'.$lInfo[0].'»' 1071 .'</option>'; 1072 } 1073 1074 return $field_options; 1075 } 1076 1077 1078 /** 1079 * Send an email to the user with a link to validate/confirm his email address. 1080 * 1081 * If the email could get sent, it saves the used "request_id" into the user's Session. 1082 * 1083 * @param string URL, where to redirect the user after he clicked the validation link (gets saved in Session). 1084 * @return boolean True, if the email could get sent; false if not 1085 */ 1086 function send_validate_email( $redirect_to_after = NULL ) 1087 { 1088 global $app_name, $htsrv_url_sensitive, $Session; 1089 1090 $request_id = generate_random_key(22); 1091 1092 $message = T_('You need to validate your email address by clicking on the following link.') 1093 ."\n\n" 1094 .T_('Login:')." $this->login\n" 1095 .sprintf( /* TRANS: %s gets replaced by $app_name (normally "b2evolution") */ T_('Link to validate your %s account:'), $app_name ) 1096 ."\n" 1097 .$htsrv_url_sensitive.'login.php?action=validatemail' 1098 .'&reqID='.$request_id 1099 .'&sessID='.$Session->ID // used to detect cookie problems 1100 ."\n\n" 1101 .T_('Please note:') 1102 .' '.T_('For security reasons the link is only valid for your current session (by means of your session cookie).'); 1103 1104 $r = send_mail( $this->email, sprintf( T_('Validate your email address for "%s"'), $this->login ), $message ); 1105 1106 if( $r ) 1107 { // save request_id into Session 1108 $request_ids = $Session->get( 'core.validatemail.request_ids' ); 1109 if( ! is_array($request_ids) ) 1110 { 1111 $request_ids = array(); 1112 } 1113 $request_ids[] = $request_id; 1114 $Session->set( 'core.validatemail.request_ids', $request_ids, 86400 * 2 ); // expires in two days (or when clicked) 1115 if( isset($redirect_to_after) ) 1116 { 1117 $Session->set( 'core.validatemail.redirect_to', $redirect_to_after ); 1118 } 1119 $Session->dbsave(); // save immediately 1120 } 1121 1122 return $r; 1123 } 1124 1125 1126 // Template functions {{{ 1127 1128 /** 1129 * Template function: display user's level 1130 */ 1131 function level() 1132 { 1133 $this->disp( 'level', 'raw' ); 1134 } 1135 1136 1137 /** 1138 * Template function: display user's login 1139 * 1140 * @param string Output format, see {@link format_to_output()} 1141 */ 1142 function login( $format = 'htmlbody' ) 1143 { 1144 $this->disp( 'login', $format ); 1145 } 1146 1147 1148 /** 1149 * Template helper function: Get a link to a message form for this user. 1150 * 1151 * @param string url of the message form 1152 * @param string to display before link 1153 * @param string to display after link 1154 * @param string link text 1155 * @param string link title 1156 * @param string class name 1157 */ 1158 function get_msgform_link( $form_url = NULL, $before = ' ', $after = ' ', $text = '#', $title = '#', $class = '' ) 1159 { 1160 if( empty($this->email) ) 1161 { // We have no email for this User :( 1162 return false; 1163 } 1164 if( empty($this->allow_msgform) ) 1165 { 1166 return false; 1167 } 1168 1169 if( is_null($form_url) ) 1170 { 1171 global $Blog; 1172 $form_url = isset($Blog) ? $Blog->get('msgformurl') : ''; 1173 } 1174 1175 $form_url = url_add_param( $form_url, 'recipient_id='.$this->ID.'&redirect_to='.rawurlencode(url_rel_to_same_host(regenerate_url('','','','&'), $form_url)) ); 1176 1177 if( $title == '#' ) $title = T_('Send email to user'); 1178 if( $text == '#' ) $text = get_icon( 'email', 'imgtag', array( 'class' => 'middle', 'title' => $title ) ); 1179 1180 $r = ''; 1181 $r .= $before; 1182 $r .= '<a href="'.$form_url.'" title="'.$title.'"'; 1183 if( !empty( $class ) ) 1184 { 1185 $r .= ' class="'.$class.'"'; 1186 } 1187 $r .= '>'.$text.'</a>'; 1188 $r .= $after; 1189 1190 return $r; 1191 } 1192 1193 1194 /** 1195 * Template function: display a link to a message form for this user 1196 * 1197 * @param string url of the message form 1198 * @param string to display before link 1199 * @param string to display after link 1200 * @param string link text 1201 * @param string link title 1202 * @param string class name 1203 */ 1204 function msgform_link( $form_url = NULL, $before = ' ', $after = ' ', $text = '#', $title = '#', $class = '' ) 1205 { 1206 echo $this->get_msgform_link( $form_url, $before, $after, $text, $title, $class ); 1207 } 1208 1209 1210 /** 1211 * Template function: display user's preferred name 1212 * 1213 * @param string Output format, see {@link format_to_output()} 1214 */ 1215 function preferred_name( $format = 'htmlbody' ) 1216 { 1217 echo format_to_output( $this->get_preferred_name(), $format ); 1218 } 1219 1220 1221 /** 1222 * Template function: display user's URL 1223 * 1224 * @param string string to display before the date (if changed) 1225 * @param string string to display after the date (if changed) 1226 * @param string Output format, see {@link format_to_output()} 1227 */ 1228 function url( $before = '', $after = '', $format = 'htmlbody' ) 1229 { 1230 if( !empty( $this->url ) ) 1231 { 1232 echo $before; 1233 $this->disp( 'url', $format ); 1234 echo $after; 1235 } 1236 } 1237 1238 1239 /** 1240 * Template function: display number of user's posts 1241 */ 1242 function num_posts( $format = 'htmlbody' ) 1243 { 1244 echo format_to_output( $this->get_num_posts(), $format ); 1245 } 1246 1247 1248 /** 1249 * Template function: display first name of the user 1250 */ 1251 function first_name( $format = 'htmlbody' ) 1252 { 1253 $this->disp( 'firstname', $format ); 1254 } 1255 1256 1257 /** 1258 * Template function: display last name of the user 1259 */ 1260 function last_name( $format = 'htmlbody' ) 1261 { 1262 $this->disp( 'lastname', $format ); 1263 } 1264 1265 1266 /** 1267 * Template function: display nickname of the user 1268 */ 1269 function nick_name( $format = 'htmlbody' ) 1270 { 1271 $this->disp( 'nickname', $format ); 1272 } 1273 1274 1275 /** 1276 * Template function: display email of the user 1277 */ 1278 function email( $format = 'htmlbody' ) 1279 { 1280 $this->disp( 'email', $format ); 1281 } 1282 1283 1284 /** 1285 * Template function: display ICQ of the user 1286 */ 1287 function icq( $format = 'htmlbody' ) 1288 { 1289 $this->disp( 'icq', $format ); 1290 } 1291 1292 1293 /** 1294 * Template function: display AIM of the user. 1295 * 1296 * NOTE: Replaces spaces with '+' ?!? 1297 */ 1298 function aim( $format = 'htmlbody' ) 1299 { 1300 echo format_to_output( str_replace(' ', '+', $this->get('aim') ), $format ); 1301 } 1302 1303 1304 /** 1305 * Template function: display Yahoo IM of the user 1306 */ 1307 function yim( $format = 'htmlbody' ) 1308 { 1309 $this->disp( 'yim', $format ); 1310 } 1311 1312 1313 /** 1314 * Template function: display MSN of the user 1315 */ 1316 function msn( $format = 'htmlbody' ) 1317 { 1318 $this->disp( 'msn', $format ); 1319 } 1320 1321 // }}} 1322 1323 } 1324 1325 /* 1326 * $Log: _user.class.php,v $ 1327 * Revision 1.2 2007/08/26 17:05:58 blueyed 1328 * MFB: Use $media_url in get_media_url 1329 * 1330 * Revision 1.1 2007/06/25 11:01:45 fplanque 1331 * MODULES (refactored MVC) 1332 * 1333 * Revision 1.77 2007/06/19 23:15:08 blueyed 1334 * doc fixes 1335 * 1336 * Revision 1.76 2007/06/18 21:14:57 fplanque 1337 * :/ 1338 * 1339 * Revision 1.74 2007/06/11 01:55:57 fplanque 1340 * level based user permissions 1341 * 1342 * Revision 1.73 2007/05/31 03:02:23 fplanque 1343 * Advanced perms now disabled by default (simpler interface). 1344 * Except when upgrading. 1345 * Enable advanced perms in blog settings -> features 1346 * 1347 * Revision 1.72 2007/05/30 01:18:56 fplanque 1348 * blog owner gets all permissions except advanced/admin settings 1349 * 1350 * Revision 1.71 2007/05/29 01:17:20 fplanque 1351 * advanced admin blog settings are now restricted by a special permission 1352 * 1353 * Revision 1.70 2007/05/28 01:33:22 fplanque 1354 * permissions/fixes 1355 * 1356 * Revision 1.69 2007/05/14 02:43:05 fplanque 1357 * Started renaming tables. There probably won't be a better time than 2.0. 1358 * 1359 * Revision 1.68 2007/04/26 00:11:11 fplanque 1360 * (c) 2007 1361 * 1362 * Revision 1.67 2007/03/26 21:03:45 blueyed 1363 * Normalized/Whitespace 1364 * 1365 * Revision 1.66 2007/03/20 09:53:26 fplanque 1366 * Letting boggers view their own stats. 1367 * + Letthing admins view the aggregate by default. 1368 * 1369 * Revision 1.65 2007/03/07 02:34:29 fplanque 1370 * Fixed very sneaky bug 1371 * 1372 * Revision 1.64 2007/03/02 00:44:43 fplanque 1373 * various small fixes 1374 * 1375 * Revision 1.63 2007/01/23 21:45:25 fplanque 1376 * "enforce" foreign keys 1377 * 1378 * Revision 1.62 2007/01/23 05:00:25 fplanque 1379 * better user defaults 1380 * 1381 * Revision 1.61 2007/01/14 22:08:48 fplanque 1382 * Broadened global group blog view/edit provileges. 1383 * I hoipe I didn't screw up here :/ 1384 * 1385 * Revision 1.60 2006/12/22 00:50:33 fplanque 1386 * improved path cleaning 1387 * 1388 * Revision 1.59 2006/12/13 19:16:31 blueyed 1389 * Fixed E_FATAL with PHP 5.2 1390 * 1391 * Revision 1.58 2006/12/12 19:39:07 fplanque 1392 * enhanced file links / permissions 1393 * 1394 * Revision 1.57 2006/12/07 23:13:11 fplanque 1395 * @var needs to have only one argument: the variable type 1396 * Otherwise, I can't code! 1397 * 1398 * Revision 1.56 2006/12/06 22:30:07 fplanque 1399 * Fixed this use case: 1400 * Users cannot register themselves. 1401 * Admin creates users that are validated by default. (they don't have to validate) 1402 * Admin can invalidate a user. (his email, address actually) 1403 * 1404 * Revision 1.55 2006/12/03 00:22:16 fplanque 1405 * doc 1406 * 1407 * Revision 1.54 2006/11/28 01:10:28 blueyed 1408 * doc/discussion 1409 * 1410 * Revision 1.53 2006/11/28 00:33:01 blueyed 1411 * Removed DB::compString() (never used) and DB::get_list() (just a macro and better to have in the 4 used places directly; Cleanup/normalization; no extended regexp, when not needed! 1412 * 1413 * Revision 1.52 2006/11/27 21:10:23 fplanque 1414 * doc 1415 * 1416 * Revision 1.51 2006/11/26 02:30:39 fplanque 1417 * doc / todo 1418 * 1419 * Revision 1.50 2006/11/24 18:27:25 blueyed 1420 * Fixed link to b2evo CVS browsing interface in file docblocks 1421 * 1422 * Revision 1.49 2006/11/02 20:34:40 blueyed 1423 * MFB (the changed member order is by design, according to db_schema.inc.php) 1424 * 1425 * Revision 1.48 2006/10/23 22:19:02 blueyed 1426 * Fixed/unified encoding of redirect_to param. Use just rawurlencode() and no funky & replacements 1427 * 1428 * Revision 1.47 2006/10/22 21:38:00 blueyed 1429 * getGroup() was never in 1.8, so no need to keep it for BC 1430 * 1431 * Revision 1.46 2006/10/22 21:28:41 blueyed 1432 * Fixes and cleanup for empty User instantiation. 1433 * 1434 * Revision 1.45 2006/10/18 00:03:51 blueyed 1435 * Some forgotten url_rel_to_same_host() additions 1436 */ 1437 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Thu Nov 29 23:58:50 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |