[ Index ] |
PHP Cross Reference of phpBB-3.1.12-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * This file is part of the phpBB Forum Software package. 5 * 6 * @copyright (c) phpBB Limited <https://www.phpbb.com> 7 * @license GNU General Public License, version 2 (GPL-2.0) 8 * 9 * For full copyright and license information, please see 10 * the docs/CREDITS.txt file. 11 * 12 */ 13 14 /** 15 * @ignore 16 */ 17 if (!defined('IN_PHPBB')) 18 { 19 exit; 20 } 21 22 /** 23 * Obtain user_ids from usernames or vice versa. Returns false on 24 * success else the error string 25 * 26 * @param array &$user_id_ary The user ids to check or empty if usernames used 27 * @param array &$username_ary The usernames to check or empty if user ids used 28 * @param mixed $user_type Array of user types to check, false if not restricting by user type 29 */ 30 function user_get_id_name(&$user_id_ary, &$username_ary, $user_type = false) 31 { 32 global $db; 33 34 // Are both arrays already filled? Yep, return else 35 // are neither array filled? 36 if ($user_id_ary && $username_ary) 37 { 38 return false; 39 } 40 else if (!$user_id_ary && !$username_ary) 41 { 42 return 'NO_USERS'; 43 } 44 45 $which_ary = ($user_id_ary) ? 'user_id_ary' : 'username_ary'; 46 47 if (${$which_ary} && !is_array(${$which_ary})) 48 { 49 ${$which_ary} = array(${$which_ary}); 50 } 51 52 $sql_in = ($which_ary == 'user_id_ary') ? array_map('intval', ${$which_ary}) : array_map('utf8_clean_string', ${$which_ary}); 53 unset(${$which_ary}); 54 55 $user_id_ary = $username_ary = array(); 56 57 // Grab the user id/username records 58 $sql_where = ($which_ary == 'user_id_ary') ? 'user_id' : 'username_clean'; 59 $sql = 'SELECT user_id, username 60 FROM ' . USERS_TABLE . ' 61 WHERE ' . $db->sql_in_set($sql_where, $sql_in); 62 63 if ($user_type !== false && !empty($user_type)) 64 { 65 $sql .= ' AND ' . $db->sql_in_set('user_type', $user_type); 66 } 67 68 $result = $db->sql_query($sql); 69 70 if (!($row = $db->sql_fetchrow($result))) 71 { 72 $db->sql_freeresult($result); 73 return 'NO_USERS'; 74 } 75 76 do 77 { 78 $username_ary[$row['user_id']] = $row['username']; 79 $user_id_ary[] = $row['user_id']; 80 } 81 while ($row = $db->sql_fetchrow($result)); 82 $db->sql_freeresult($result); 83 84 return false; 85 } 86 87 /** 88 * Get latest registered username and update database to reflect it 89 */ 90 function update_last_username() 91 { 92 global $db; 93 94 // Get latest username 95 $sql = 'SELECT user_id, username, user_colour 96 FROM ' . USERS_TABLE . ' 97 WHERE user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ') 98 ORDER BY user_id DESC'; 99 $result = $db->sql_query_limit($sql, 1); 100 $row = $db->sql_fetchrow($result); 101 $db->sql_freeresult($result); 102 103 if ($row) 104 { 105 set_config('newest_user_id', $row['user_id'], true); 106 set_config('newest_username', $row['username'], true); 107 set_config('newest_user_colour', $row['user_colour'], true); 108 } 109 } 110 111 /** 112 * Updates a username across all relevant tables/fields 113 * 114 * @param string $old_name the old/current username 115 * @param string $new_name the new username 116 */ 117 function user_update_name($old_name, $new_name) 118 { 119 global $config, $db, $cache, $phpbb_dispatcher; 120 121 $update_ary = array( 122 FORUMS_TABLE => array( 123 'forum_last_poster_id' => 'forum_last_poster_name', 124 ), 125 MODERATOR_CACHE_TABLE => array( 126 'user_id' => 'username', 127 ), 128 POSTS_TABLE => array( 129 'poster_id' => 'post_username', 130 ), 131 TOPICS_TABLE => array( 132 'topic_poster' => 'topic_first_poster_name', 133 'topic_last_poster_id' => 'topic_last_poster_name', 134 ), 135 ); 136 137 foreach ($update_ary as $table => $field_ary) 138 { 139 foreach ($field_ary as $id_field => $name_field) 140 { 141 $sql = "UPDATE $table 142 SET $name_field = '" . $db->sql_escape($new_name) . "' 143 WHERE $name_field = '" . $db->sql_escape($old_name) . "' 144 AND $id_field <> " . ANONYMOUS; 145 $db->sql_query($sql); 146 } 147 } 148 149 if ($config['newest_username'] == $old_name) 150 { 151 set_config('newest_username', $new_name, true); 152 } 153 154 /** 155 * Update a username when it is changed 156 * 157 * @event core.update_username 158 * @var string old_name The old username that is replaced 159 * @var string new_name The new username 160 * @since 3.1.0-a1 161 */ 162 $vars = array('old_name', 'new_name'); 163 extract($phpbb_dispatcher->trigger_event('core.update_username', compact($vars))); 164 165 // Because some tables/caches use username-specific data we need to purge this here. 166 $cache->destroy('sql', MODERATOR_CACHE_TABLE); 167 } 168 169 /** 170 * Adds an user 171 * 172 * @param mixed $user_row An array containing the following keys (and the appropriate values): username, group_id (the group to place the user in), user_email and the user_type(usually 0). Additional entries not overridden by defaults will be forwarded. 173 * @param string $cp_data custom profile fields, see custom_profile::build_insert_sql_array 174 * @param array $notifications_data The notifications settings for the new user 175 * @return the new user's ID. 176 */ 177 function user_add($user_row, $cp_data = false, $notifications_data = null) 178 { 179 global $db, $user, $auth, $config, $phpbb_root_path, $phpEx; 180 global $phpbb_dispatcher, $phpbb_container; 181 182 if (empty($user_row['username']) || !isset($user_row['group_id']) || !isset($user_row['user_email']) || !isset($user_row['user_type'])) 183 { 184 return false; 185 } 186 187 $username_clean = utf8_clean_string($user_row['username']); 188 189 if (empty($username_clean)) 190 { 191 return false; 192 } 193 194 $sql_ary = array( 195 'username' => $user_row['username'], 196 'username_clean' => $username_clean, 197 'user_password' => (isset($user_row['user_password'])) ? $user_row['user_password'] : '', 198 'user_email' => strtolower($user_row['user_email']), 199 'user_email_hash' => phpbb_email_hash($user_row['user_email']), 200 'group_id' => $user_row['group_id'], 201 'user_type' => $user_row['user_type'], 202 ); 203 204 // These are the additional vars able to be specified 205 $additional_vars = array( 206 'user_permissions' => '', 207 'user_timezone' => $config['board_timezone'], 208 'user_dateformat' => $config['default_dateformat'], 209 'user_lang' => $config['default_lang'], 210 'user_style' => (int) $config['default_style'], 211 'user_actkey' => '', 212 'user_ip' => '', 213 'user_regdate' => time(), 214 'user_passchg' => time(), 215 'user_options' => 230271, 216 // We do not set the new flag here - registration scripts need to specify it 217 'user_new' => 0, 218 219 'user_inactive_reason' => 0, 220 'user_inactive_time' => 0, 221 'user_lastmark' => time(), 222 'user_lastvisit' => 0, 223 'user_lastpost_time' => 0, 224 'user_lastpage' => '', 225 'user_posts' => 0, 226 'user_colour' => '', 227 'user_avatar' => '', 228 'user_avatar_type' => '', 229 'user_avatar_width' => 0, 230 'user_avatar_height' => 0, 231 'user_new_privmsg' => 0, 232 'user_unread_privmsg' => 0, 233 'user_last_privmsg' => 0, 234 'user_message_rules' => 0, 235 'user_full_folder' => PRIVMSGS_NO_BOX, 236 'user_emailtime' => 0, 237 238 'user_notify' => 0, 239 'user_notify_pm' => 1, 240 'user_notify_type' => NOTIFY_EMAIL, 241 'user_allow_pm' => 1, 242 'user_allow_viewonline' => 1, 243 'user_allow_viewemail' => 1, 244 'user_allow_massemail' => 1, 245 246 'user_sig' => '', 247 'user_sig_bbcode_uid' => '', 248 'user_sig_bbcode_bitfield' => '', 249 250 'user_form_salt' => unique_id(), 251 ); 252 253 // Now fill the sql array with not required variables 254 foreach ($additional_vars as $key => $default_value) 255 { 256 $sql_ary[$key] = (isset($user_row[$key])) ? $user_row[$key] : $default_value; 257 } 258 259 // Any additional variables in $user_row not covered above? 260 $remaining_vars = array_diff(array_keys($user_row), array_keys($sql_ary)); 261 262 // Now fill our sql array with the remaining vars 263 if (sizeof($remaining_vars)) 264 { 265 foreach ($remaining_vars as $key) 266 { 267 $sql_ary[$key] = $user_row[$key]; 268 } 269 } 270 271 /** 272 * Use this event to modify the values to be inserted when a user is added 273 * 274 * @event core.user_add_modify_data 275 * @var array user_row Array of user details submited to user_add 276 * @var array cp_data Array of Custom profile fields submited to user_add 277 * @var array sql_ary Array of data to be inserted when a user is added 278 * @var array notifications_data Array of notification data to be inserted when a user is added 279 * @since 3.1.0-a1 280 * @changed 3.1.0-b5 Added user_row and cp_data 281 * @changed 3.1.11-RC1 Added notifications_data 282 */ 283 $vars = array('user_row', 'cp_data', 'sql_ary', 'notifications_data'); 284 extract($phpbb_dispatcher->trigger_event('core.user_add_modify_data', compact($vars))); 285 286 $sql = 'INSERT INTO ' . USERS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); 287 $db->sql_query($sql); 288 289 $user_id = $db->sql_nextid(); 290 291 // Insert Custom Profile Fields 292 if ($cp_data !== false && sizeof($cp_data)) 293 { 294 $cp_data['user_id'] = (int) $user_id; 295 296 $cp = $phpbb_container->get('profilefields.manager'); 297 $sql = 'INSERT INTO ' . PROFILE_FIELDS_DATA_TABLE . ' ' . 298 $db->sql_build_array('INSERT', $cp->build_insert_sql_array($cp_data)); 299 $db->sql_query($sql); 300 } 301 302 // Place into appropriate group... 303 $sql = 'INSERT INTO ' . USER_GROUP_TABLE . ' ' . $db->sql_build_array('INSERT', array( 304 'user_id' => (int) $user_id, 305 'group_id' => (int) $user_row['group_id'], 306 'user_pending' => 0) 307 ); 308 $db->sql_query($sql); 309 310 // Now make it the users default group... 311 group_set_user_default($user_row['group_id'], array($user_id), false); 312 313 // Add to newly registered users group if user_new is 1 314 if ($config['new_member_post_limit'] && $sql_ary['user_new']) 315 { 316 $sql = 'SELECT group_id 317 FROM ' . GROUPS_TABLE . " 318 WHERE group_name = 'NEWLY_REGISTERED' 319 AND group_type = " . GROUP_SPECIAL; 320 $result = $db->sql_query($sql); 321 $add_group_id = (int) $db->sql_fetchfield('group_id'); 322 $db->sql_freeresult($result); 323 324 if ($add_group_id) 325 { 326 global $phpbb_log; 327 328 // Because these actions only fill the log unneccessarily we skip the add_log() entry. 329 $phpbb_log->disable('admin'); 330 331 // Add user to "newly registered users" group and set to default group if admin specified so. 332 if ($config['new_member_group_default']) 333 { 334 group_user_add($add_group_id, $user_id, false, false, true); 335 $user_row['group_id'] = $add_group_id; 336 } 337 else 338 { 339 group_user_add($add_group_id, $user_id); 340 } 341 342 $phpbb_log->enable('admin'); 343 } 344 } 345 346 // set the newest user and adjust the user count if the user is a normal user and no activation mail is sent 347 if ($user_row['user_type'] == USER_NORMAL || $user_row['user_type'] == USER_FOUNDER) 348 { 349 set_config('newest_user_id', $user_id, true); 350 set_config('newest_username', $user_row['username'], true); 351 set_config_count('num_users', 1, true); 352 353 $sql = 'SELECT group_colour 354 FROM ' . GROUPS_TABLE . ' 355 WHERE group_id = ' . (int) $user_row['group_id']; 356 $result = $db->sql_query_limit($sql, 1); 357 $row = $db->sql_fetchrow($result); 358 $db->sql_freeresult($result); 359 360 set_config('newest_user_colour', $row['group_colour'], true); 361 } 362 363 // Use default notifications settings if notifications_data is not set 364 if ($notifications_data === null) 365 { 366 $notifications_data = array( 367 array( 368 'item_type' => 'notification.type.post', 369 'method' => 'notification.method.email', 370 ), 371 array( 372 'item_type' => 'notification.type.topic', 373 'method' => 'notification.method.email', 374 ), 375 ); 376 } 377 378 // Subscribe user to notifications if necessary 379 if (!empty($notifications_data)) 380 { 381 $phpbb_notifications = $phpbb_container->get('notification_manager'); 382 foreach ($notifications_data as $subscription) 383 { 384 $phpbb_notifications->add_subscription($subscription['item_type'], 0, $subscription['method'], $user_id); 385 } 386 } 387 388 /** 389 * Event that returns user id, user detals and user CPF of newly registared user 390 * 391 * @event core.user_add_after 392 * @var int user_id User id of newly registared user 393 * @var array user_row Array of user details submited to user_add 394 * @var array cp_data Array of Custom profile fields submited to user_add 395 * @since 3.1.0-b5 396 */ 397 $vars = array('user_id', 'user_row', 'cp_data'); 398 extract($phpbb_dispatcher->trigger_event('core.user_add_after', compact($vars))); 399 400 return $user_id; 401 } 402 403 /** 404 * Remove User 405 * 406 * @param string $mode Either 'retain' or 'remove' 407 * @param mixed $user_ids Either an array of integers or an integer 408 * @param bool $retain_username 409 * @return bool 410 */ 411 function user_delete($mode, $user_ids, $retain_username = true) 412 { 413 global $cache, $config, $db, $user, $phpbb_dispatcher, $phpbb_container; 414 global $phpbb_root_path, $phpEx; 415 416 $db->sql_transaction('begin'); 417 418 $user_rows = array(); 419 if (!is_array($user_ids)) 420 { 421 $user_ids = array($user_ids); 422 } 423 424 $user_id_sql = $db->sql_in_set('user_id', $user_ids); 425 426 $sql = 'SELECT * 427 FROM ' . USERS_TABLE . ' 428 WHERE ' . $user_id_sql; 429 $result = $db->sql_query($sql); 430 while ($row = $db->sql_fetchrow($result)) 431 { 432 $user_rows[(int) $row['user_id']] = $row; 433 } 434 $db->sql_freeresult($result); 435 436 if (empty($user_rows)) 437 { 438 return false; 439 } 440 441 /** 442 * Event before a user is deleted 443 * 444 * @event core.delete_user_before 445 * @var string mode Mode of deletion (retain/delete posts) 446 * @var array user_ids IDs of the deleted user 447 * @var mixed retain_username True if username should be retained 448 * or false if not 449 * @since 3.1.0-a1 450 */ 451 $vars = array('mode', 'user_ids', 'retain_username'); 452 extract($phpbb_dispatcher->trigger_event('core.delete_user_before', compact($vars))); 453 454 // Before we begin, we will remove the reports the user issued. 455 $sql = 'SELECT r.post_id, p.topic_id 456 FROM ' . REPORTS_TABLE . ' r, ' . POSTS_TABLE . ' p 457 WHERE ' . $db->sql_in_set('r.user_id', $user_ids) . ' 458 AND p.post_id = r.post_id'; 459 $result = $db->sql_query($sql); 460 461 $report_posts = $report_topics = array(); 462 while ($row = $db->sql_fetchrow($result)) 463 { 464 $report_posts[] = $row['post_id']; 465 $report_topics[] = $row['topic_id']; 466 } 467 $db->sql_freeresult($result); 468 469 if (sizeof($report_posts)) 470 { 471 $report_posts = array_unique($report_posts); 472 $report_topics = array_unique($report_topics); 473 474 // Get a list of topics that still contain reported posts 475 $sql = 'SELECT DISTINCT topic_id 476 FROM ' . POSTS_TABLE . ' 477 WHERE ' . $db->sql_in_set('topic_id', $report_topics) . ' 478 AND post_reported = 1 479 AND ' . $db->sql_in_set('post_id', $report_posts, true); 480 $result = $db->sql_query($sql); 481 482 $keep_report_topics = array(); 483 while ($row = $db->sql_fetchrow($result)) 484 { 485 $keep_report_topics[] = $row['topic_id']; 486 } 487 $db->sql_freeresult($result); 488 489 if (sizeof($keep_report_topics)) 490 { 491 $report_topics = array_diff($report_topics, $keep_report_topics); 492 } 493 unset($keep_report_topics); 494 495 // Now set the flags back 496 $sql = 'UPDATE ' . POSTS_TABLE . ' 497 SET post_reported = 0 498 WHERE ' . $db->sql_in_set('post_id', $report_posts); 499 $db->sql_query($sql); 500 501 if (sizeof($report_topics)) 502 { 503 $sql = 'UPDATE ' . TOPICS_TABLE . ' 504 SET topic_reported = 0 505 WHERE ' . $db->sql_in_set('topic_id', $report_topics); 506 $db->sql_query($sql); 507 } 508 } 509 510 // Remove reports 511 $db->sql_query('DELETE FROM ' . REPORTS_TABLE . ' WHERE ' . $user_id_sql); 512 513 $num_users_delta = 0; 514 515 // Get auth provider collection in case accounts might need to be unlinked 516 $provider_collection = $phpbb_container->get('auth.provider_collection'); 517 518 // Some things need to be done in the loop (if the query changes based 519 // on which user is currently being deleted) 520 $added_guest_posts = 0; 521 foreach ($user_rows as $user_id => $user_row) 522 { 523 if ($user_row['user_avatar'] && $user_row['user_avatar_type'] == 'avatar.driver.upload') 524 { 525 avatar_delete('user', $user_row); 526 } 527 528 // Unlink accounts 529 foreach ($provider_collection as $provider_name => $auth_provider) 530 { 531 $provider_data = $auth_provider->get_auth_link_data($user_id); 532 533 if ($provider_data !== null) 534 { 535 $link_data = array( 536 'user_id' => $user_id, 537 'link_method' => 'user_delete', 538 ); 539 540 // BLOCK_VARS might contain hidden fields necessary for unlinking accounts 541 if (isset($provider_data['BLOCK_VARS']) && is_array($provider_data['BLOCK_VARS'])) 542 { 543 foreach ($provider_data['BLOCK_VARS'] as $provider_service) 544 { 545 if (!array_key_exists('HIDDEN_FIELDS', $provider_service)) 546 { 547 $provider_service['HIDDEN_FIELDS'] = array(); 548 } 549 550 $auth_provider->unlink_account(array_merge($link_data, $provider_service['HIDDEN_FIELDS'])); 551 } 552 } 553 else 554 { 555 $auth_provider->unlink_account($link_data); 556 } 557 } 558 } 559 560 // Decrement number of users if this user is active 561 if ($user_row['user_type'] != USER_INACTIVE && $user_row['user_type'] != USER_IGNORE) 562 { 563 --$num_users_delta; 564 } 565 566 switch ($mode) 567 { 568 case 'retain': 569 if ($retain_username === false) 570 { 571 $post_username = $user->lang['GUEST']; 572 } 573 else 574 { 575 $post_username = $user_row['username']; 576 } 577 578 // If the user is inactive and newly registered 579 // we assume no posts from the user, and save 580 // the queries 581 if ($user_row['user_type'] != USER_INACTIVE || $user_row['user_inactive_reason'] != INACTIVE_REGISTER || $user_row['user_posts']) 582 { 583 // When we delete these users and retain the posts, we must assign all the data to the guest user 584 $sql = 'UPDATE ' . FORUMS_TABLE . ' 585 SET forum_last_poster_id = ' . ANONYMOUS . ", forum_last_poster_name = '" . $db->sql_escape($post_username) . "', forum_last_poster_colour = '' 586 WHERE forum_last_poster_id = $user_id"; 587 $db->sql_query($sql); 588 589 $sql = 'UPDATE ' . POSTS_TABLE . ' 590 SET poster_id = ' . ANONYMOUS . ", post_username = '" . $db->sql_escape($post_username) . "' 591 WHERE poster_id = $user_id"; 592 $db->sql_query($sql); 593 594 $sql = 'UPDATE ' . TOPICS_TABLE . ' 595 SET topic_poster = ' . ANONYMOUS . ", topic_first_poster_name = '" . $db->sql_escape($post_username) . "', topic_first_poster_colour = '' 596 WHERE topic_poster = $user_id"; 597 $db->sql_query($sql); 598 599 $sql = 'UPDATE ' . TOPICS_TABLE . ' 600 SET topic_last_poster_id = ' . ANONYMOUS . ", topic_last_poster_name = '" . $db->sql_escape($post_username) . "', topic_last_poster_colour = '' 601 WHERE topic_last_poster_id = $user_id"; 602 $db->sql_query($sql); 603 604 // Since we change every post by this author, we need to count this amount towards the anonymous user 605 606 if ($user_row['user_posts']) 607 { 608 $added_guest_posts += $user_row['user_posts']; 609 } 610 } 611 break; 612 613 case 'remove': 614 // there is nothing variant specific to deleting posts 615 break; 616 } 617 } 618 619 if ($num_users_delta != 0) 620 { 621 set_config_count('num_users', $num_users_delta, true); 622 } 623 624 // Now do the invariant tasks 625 // all queries performed in one call of this function are in a single transaction 626 // so this is kosher 627 if ($mode == 'retain') 628 { 629 // Assign more data to the Anonymous user 630 $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' 631 SET poster_id = ' . ANONYMOUS . ' 632 WHERE ' . $db->sql_in_set('poster_id', $user_ids); 633 $db->sql_query($sql); 634 635 $sql = 'UPDATE ' . USERS_TABLE . ' 636 SET user_posts = user_posts + ' . $added_guest_posts . ' 637 WHERE user_id = ' . ANONYMOUS; 638 $db->sql_query($sql); 639 } 640 else if ($mode == 'remove') 641 { 642 if (!function_exists('delete_posts')) 643 { 644 include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); 645 } 646 647 // Delete posts, attachments, etc. 648 // delete_posts can handle any number of IDs in its second argument 649 delete_posts('poster_id', $user_ids); 650 } 651 652 $table_ary = array(USERS_TABLE, USER_GROUP_TABLE, TOPICS_WATCH_TABLE, FORUMS_WATCH_TABLE, ACL_USERS_TABLE, TOPICS_TRACK_TABLE, TOPICS_POSTED_TABLE, FORUMS_TRACK_TABLE, PROFILE_FIELDS_DATA_TABLE, MODERATOR_CACHE_TABLE, DRAFTS_TABLE, BOOKMARKS_TABLE, SESSIONS_KEYS_TABLE, PRIVMSGS_FOLDER_TABLE, PRIVMSGS_RULES_TABLE); 653 654 // Delete the miscellaneous (non-post) data for the user 655 foreach ($table_ary as $table) 656 { 657 $sql = "DELETE FROM $table 658 WHERE " . $user_id_sql; 659 $db->sql_query($sql); 660 } 661 662 $cache->destroy('sql', MODERATOR_CACHE_TABLE); 663 664 // Change user_id to anonymous for posts edited by this user 665 $sql = 'UPDATE ' . POSTS_TABLE . ' 666 SET post_edit_user = ' . ANONYMOUS . ' 667 WHERE ' . $db->sql_in_set('post_edit_user', $user_ids); 668 $db->sql_query($sql); 669 670 // Change user_id to anonymous for pms edited by this user 671 $sql = 'UPDATE ' . PRIVMSGS_TABLE . ' 672 SET message_edit_user = ' . ANONYMOUS . ' 673 WHERE ' . $db->sql_in_set('message_edit_user', $user_ids); 674 $db->sql_query($sql); 675 676 // Change user_id to anonymous for posts deleted by this user 677 $sql = 'UPDATE ' . POSTS_TABLE . ' 678 SET post_delete_user = ' . ANONYMOUS . ' 679 WHERE ' . $db->sql_in_set('post_delete_user', $user_ids); 680 $db->sql_query($sql); 681 682 // Change user_id to anonymous for topics deleted by this user 683 $sql = 'UPDATE ' . TOPICS_TABLE . ' 684 SET topic_delete_user = ' . ANONYMOUS . ' 685 WHERE ' . $db->sql_in_set('topic_delete_user', $user_ids); 686 $db->sql_query($sql); 687 688 // Delete user log entries about this user 689 $sql = 'DELETE FROM ' . LOG_TABLE . ' 690 WHERE ' . $db->sql_in_set('reportee_id', $user_ids); 691 $db->sql_query($sql); 692 693 // Change user_id to anonymous for this users triggered events 694 $sql = 'UPDATE ' . LOG_TABLE . ' 695 SET user_id = ' . ANONYMOUS . ' 696 WHERE ' . $user_id_sql; 697 $db->sql_query($sql); 698 699 // Delete the user_id from the zebra table 700 $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' 701 WHERE ' . $user_id_sql . ' 702 OR ' . $db->sql_in_set('zebra_id', $user_ids); 703 $db->sql_query($sql); 704 705 // Delete the user_id from the banlist 706 $sql = 'DELETE FROM ' . BANLIST_TABLE . ' 707 WHERE ' . $db->sql_in_set('ban_userid', $user_ids); 708 $db->sql_query($sql); 709 710 // Delete the user_id from the session table 711 $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' 712 WHERE ' . $db->sql_in_set('session_user_id', $user_ids); 713 $db->sql_query($sql); 714 715 // Clean the private messages tables from the user 716 if (!function_exists('phpbb_delete_user_pms')) 717 { 718 include($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx); 719 } 720 phpbb_delete_users_pms($user_ids); 721 722 $phpbb_notifications = $phpbb_container->get('notification_manager'); 723 $phpbb_notifications->delete_notifications('notification.type.admin_activate_user', $user_ids); 724 725 $db->sql_transaction('commit'); 726 727 /** 728 * Event after a user is deleted 729 * 730 * @event core.delete_user_after 731 * @var string mode Mode of deletion (retain/delete posts) 732 * @var array user_ids IDs of the deleted user 733 * @var mixed retain_username True if username should be retained 734 * or false if not 735 * @since 3.1.0-a1 736 */ 737 $vars = array('mode', 'user_ids', 'retain_username'); 738 extract($phpbb_dispatcher->trigger_event('core.delete_user_after', compact($vars))); 739 740 // Reset newest user info if appropriate 741 if (in_array($config['newest_user_id'], $user_ids)) 742 { 743 update_last_username(); 744 } 745 746 return false; 747 } 748 749 /** 750 * Flips user_type from active to inactive and vice versa, handles group membership updates 751 * 752 * @param string $mode can be flip for flipping from active/inactive, activate or deactivate 753 */ 754 function user_active_flip($mode, $user_id_ary, $reason = INACTIVE_MANUAL) 755 { 756 global $config, $db, $user, $auth, $phpbb_dispatcher; 757 758 $deactivated = $activated = 0; 759 $sql_statements = array(); 760 761 if (!is_array($user_id_ary)) 762 { 763 $user_id_ary = array($user_id_ary); 764 } 765 766 if (!sizeof($user_id_ary)) 767 { 768 return; 769 } 770 771 $sql = 'SELECT user_id, group_id, user_type, user_inactive_reason 772 FROM ' . USERS_TABLE . ' 773 WHERE ' . $db->sql_in_set('user_id', $user_id_ary); 774 $result = $db->sql_query($sql); 775 776 while ($row = $db->sql_fetchrow($result)) 777 { 778 $sql_ary = array(); 779 780 if ($row['user_type'] == USER_IGNORE || $row['user_type'] == USER_FOUNDER || 781 ($mode == 'activate' && $row['user_type'] != USER_INACTIVE) || 782 ($mode == 'deactivate' && $row['user_type'] == USER_INACTIVE)) 783 { 784 continue; 785 } 786 787 if ($row['user_type'] == USER_INACTIVE) 788 { 789 $activated++; 790 } 791 else 792 { 793 $deactivated++; 794 795 // Remove the users session key... 796 $user->reset_login_keys($row['user_id']); 797 } 798 799 $sql_ary += array( 800 'user_type' => ($row['user_type'] == USER_NORMAL) ? USER_INACTIVE : USER_NORMAL, 801 'user_inactive_time' => ($row['user_type'] == USER_NORMAL) ? time() : 0, 802 'user_inactive_reason' => ($row['user_type'] == USER_NORMAL) ? $reason : 0, 803 ); 804 805 $sql_statements[$row['user_id']] = $sql_ary; 806 } 807 $db->sql_freeresult($result); 808 809 /** 810 * Check or modify activated/deactivated users data before submitting it to the database 811 * 812 * @event core.user_active_flip_before 813 * @var string mode User type changing mode, can be: flip|activate|deactivate 814 * @var int reason Reason for changing user type, can be: INACTIVE_REGISTER|INACTIVE_PROFILE|INACTIVE_MANUAL|INACTIVE_REMIND 815 * @var int activated The number of users to be activated 816 * @var int deactivated The number of users to be deactivated 817 * @var array user_id_ary Array with user ids to change user type 818 * @var array sql_statements Array with users data to submit to the database, keys: user ids, values: arrays with user data 819 * @since 3.1.4-RC1 820 */ 821 $vars = array('mode', 'reason', 'activated', 'deactivated', 'user_id_ary', 'sql_statements'); 822 extract($phpbb_dispatcher->trigger_event('core.user_active_flip_before', compact($vars))); 823 824 if (sizeof($sql_statements)) 825 { 826 foreach ($sql_statements as $user_id => $sql_ary) 827 { 828 $sql = 'UPDATE ' . USERS_TABLE . ' 829 SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' 830 WHERE user_id = ' . $user_id; 831 $db->sql_query($sql); 832 } 833 834 $auth->acl_clear_prefetch(array_keys($sql_statements)); 835 } 836 837 /** 838 * Perform additional actions after the users have been activated/deactivated 839 * 840 * @event core.user_active_flip_after 841 * @var string mode User type changing mode, can be: flip|activate|deactivate 842 * @var int reason Reason for changing user type, can be: INACTIVE_REGISTER|INACTIVE_PROFILE|INACTIVE_MANUAL|INACTIVE_REMIND 843 * @var int activated The number of users to be activated 844 * @var int deactivated The number of users to be deactivated 845 * @var array user_id_ary Array with user ids to change user type 846 * @var array sql_statements Array with users data to submit to the database, keys: user ids, values: arrays with user data 847 * @since 3.1.4-RC1 848 */ 849 $vars = array('mode', 'reason', 'activated', 'deactivated', 'user_id_ary', 'sql_statements'); 850 extract($phpbb_dispatcher->trigger_event('core.user_active_flip_after', compact($vars))); 851 852 if ($deactivated) 853 { 854 set_config_count('num_users', $deactivated * (-1), true); 855 } 856 857 if ($activated) 858 { 859 set_config_count('num_users', $activated, true); 860 } 861 862 // Update latest username 863 update_last_username(); 864 } 865 866 /** 867 * Add a ban or ban exclusion to the banlist. Bans either a user, an IP or an email address 868 * 869 * @param string $mode Type of ban. One of the following: user, ip, email 870 * @param mixed $ban Banned entity. Either string or array with usernames, ips or email addresses 871 * @param int $ban_len Ban length in minutes 872 * @param string $ban_len_other Ban length as a date (YYYY-MM-DD) 873 * @param boolean $ban_exclude Exclude these entities from banning? 874 * @param string $ban_reason String describing the reason for this ban 875 * @return boolean 876 */ 877 function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reason, $ban_give_reason = '') 878 { 879 global $db, $user, $auth, $cache; 880 881 // Delete stale bans 882 $sql = 'DELETE FROM ' . BANLIST_TABLE . ' 883 WHERE ban_end < ' . time() . ' 884 AND ban_end <> 0'; 885 $db->sql_query($sql); 886 887 $ban_list = (!is_array($ban)) ? array_unique(explode("\n", $ban)) : $ban; 888 $ban_list_log = implode(', ', $ban_list); 889 890 $current_time = time(); 891 892 // Set $ban_end to the unix time when the ban should end. 0 is a permanent ban. 893 if ($ban_len) 894 { 895 if ($ban_len != -1 || !$ban_len_other) 896 { 897 $ban_end = max($current_time, $current_time + ($ban_len) * 60); 898 } 899 else 900 { 901 $ban_other = explode('-', $ban_len_other); 902 if (sizeof($ban_other) == 3 && ((int) $ban_other[0] < 9999) && 903 (strlen($ban_other[0]) == 4) && (strlen($ban_other[1]) == 2) && (strlen($ban_other[2]) == 2)) 904 { 905 $ban_end = max($current_time, $user->create_datetime() 906 ->setDate((int) $ban_other[0], (int) $ban_other[1], (int) $ban_other[2]) 907 ->setTime(0, 0, 0) 908 ->getTimestamp() + $user->timezone->getOffset(new DateTime('UTC'))); 909 } 910 else 911 { 912 trigger_error('LENGTH_BAN_INVALID', E_USER_WARNING); 913 } 914 } 915 } 916 else 917 { 918 $ban_end = 0; 919 } 920 921 $founder = $founder_names = array(); 922 923 if (!$ban_exclude) 924 { 925 // Create a list of founder... 926 $sql = 'SELECT user_id, user_email, username_clean 927 FROM ' . USERS_TABLE . ' 928 WHERE user_type = ' . USER_FOUNDER; 929 $result = $db->sql_query($sql); 930 931 while ($row = $db->sql_fetchrow($result)) 932 { 933 $founder[$row['user_id']] = $row['user_email']; 934 $founder_names[$row['user_id']] = $row['username_clean']; 935 } 936 $db->sql_freeresult($result); 937 } 938 939 $banlist_ary = array(); 940 941 switch ($mode) 942 { 943 case 'user': 944 $type = 'ban_userid'; 945 946 // At the moment we do not support wildcard username banning 947 948 // Select the relevant user_ids. 949 $sql_usernames = array(); 950 951 foreach ($ban_list as $username) 952 { 953 $username = trim($username); 954 if ($username != '') 955 { 956 $clean_name = utf8_clean_string($username); 957 if ($clean_name == $user->data['username_clean']) 958 { 959 trigger_error('CANNOT_BAN_YOURSELF', E_USER_WARNING); 960 } 961 if (in_array($clean_name, $founder_names)) 962 { 963 trigger_error('CANNOT_BAN_FOUNDER', E_USER_WARNING); 964 } 965 $sql_usernames[] = $clean_name; 966 } 967 } 968 969 // Make sure we have been given someone to ban 970 if (!sizeof($sql_usernames)) 971 { 972 trigger_error('NO_USER_SPECIFIED', E_USER_WARNING); 973 } 974 975 $sql = 'SELECT user_id 976 FROM ' . USERS_TABLE . ' 977 WHERE ' . $db->sql_in_set('username_clean', $sql_usernames); 978 979 // Do not allow banning yourself, the guest account, or founders. 980 $non_bannable = array($user->data['user_id'], ANONYMOUS); 981 if (sizeof($founder)) 982 { 983 $sql .= ' AND ' . $db->sql_in_set('user_id', array_merge(array_keys($founder), $non_bannable), true); 984 } 985 else 986 { 987 $sql .= ' AND ' . $db->sql_in_set('user_id', $non_bannable, true); 988 } 989 990 $result = $db->sql_query($sql); 991 992 if ($row = $db->sql_fetchrow($result)) 993 { 994 do 995 { 996 $banlist_ary[] = (int) $row['user_id']; 997 } 998 while ($row = $db->sql_fetchrow($result)); 999 } 1000 else 1001 { 1002 $db->sql_freeresult($result); 1003 trigger_error('NO_USERS', E_USER_WARNING); 1004 } 1005 $db->sql_freeresult($result); 1006 break; 1007 1008 case 'ip': 1009 $type = 'ban_ip'; 1010 1011 foreach ($ban_list as $ban_item) 1012 { 1013 if (preg_match('#^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})[ ]*\-[ ]*([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$#', trim($ban_item), $ip_range_explode)) 1014 { 1015 // This is an IP range 1016 // Don't ask about all this, just don't ask ... ! 1017 $ip_1_counter = $ip_range_explode[1]; 1018 $ip_1_end = $ip_range_explode[5]; 1019 1020 while ($ip_1_counter <= $ip_1_end) 1021 { 1022 $ip_2_counter = ($ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[2] : 0; 1023 $ip_2_end = ($ip_1_counter < $ip_1_end) ? 254 : $ip_range_explode[6]; 1024 1025 if ($ip_2_counter == 0 && $ip_2_end == 254) 1026 { 1027 $ip_2_counter = 256; 1028 $ip_2_fragment = 256; 1029 1030 $banlist_ary[] = "$ip_1_counter.*"; 1031 } 1032 1033 while ($ip_2_counter <= $ip_2_end) 1034 { 1035 $ip_3_counter = ($ip_2_counter == $ip_range_explode[2] && $ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[3] : 0; 1036 $ip_3_end = ($ip_2_counter < $ip_2_end || $ip_1_counter < $ip_1_end) ? 254 : $ip_range_explode[7]; 1037 1038 if ($ip_3_counter == 0 && $ip_3_end == 254) 1039 { 1040 $ip_3_counter = 256; 1041 $ip_3_fragment = 256; 1042 1043 $banlist_ary[] = "$ip_1_counter.$ip_2_counter.*"; 1044 } 1045 1046 while ($ip_3_counter <= $ip_3_end) 1047 { 1048 $ip_4_counter = ($ip_3_counter == $ip_range_explode[3] && $ip_2_counter == $ip_range_explode[2] && $ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[4] : 0; 1049 $ip_4_end = ($ip_3_counter < $ip_3_end || $ip_2_counter < $ip_2_end) ? 254 : $ip_range_explode[8]; 1050 1051 if ($ip_4_counter == 0 && $ip_4_end == 254) 1052 { 1053 $ip_4_counter = 256; 1054 $ip_4_fragment = 256; 1055 1056 $banlist_ary[] = "$ip_1_counter.$ip_2_counter.$ip_3_counter.*"; 1057 } 1058 1059 while ($ip_4_counter <= $ip_4_end) 1060 { 1061 $banlist_ary[] = "$ip_1_counter.$ip_2_counter.$ip_3_counter.$ip_4_counter"; 1062 $ip_4_counter++; 1063 } 1064 $ip_3_counter++; 1065 } 1066 $ip_2_counter++; 1067 } 1068 $ip_1_counter++; 1069 } 1070 } 1071 else if (preg_match('#^([0-9]{1,3})\.([0-9\*]{1,3})\.([0-9\*]{1,3})\.([0-9\*]{1,3})$#', trim($ban_item)) || preg_match('#^[a-f0-9:]+\*?$#i', trim($ban_item))) 1072 { 1073 // Normal IP address 1074 $banlist_ary[] = trim($ban_item); 1075 } 1076 else if (preg_match('#^\*$#', trim($ban_item))) 1077 { 1078 // Ban all IPs 1079 $banlist_ary[] = '*'; 1080 } 1081 else if (preg_match('#^([\w\-_]\.?){2,}$#is', trim($ban_item))) 1082 { 1083 // hostname 1084 $ip_ary = gethostbynamel(trim($ban_item)); 1085 1086 if (!empty($ip_ary)) 1087 { 1088 foreach ($ip_ary as $ip) 1089 { 1090 if ($ip) 1091 { 1092 if (strlen($ip) > 40) 1093 { 1094 continue; 1095 } 1096 1097 $banlist_ary[] = $ip; 1098 } 1099 } 1100 } 1101 } 1102 1103 if (empty($banlist_ary)) 1104 { 1105 trigger_error('NO_IPS_DEFINED', E_USER_WARNING); 1106 } 1107 } 1108 break; 1109 1110 case 'email': 1111 $type = 'ban_email'; 1112 1113 foreach ($ban_list as $ban_item) 1114 { 1115 $ban_item = trim($ban_item); 1116 1117 if (preg_match('#^.*?@*|(([a-z0-9\-]+\.)+([a-z]{2,3}))$#i', $ban_item)) 1118 { 1119 if (strlen($ban_item) > 100) 1120 { 1121 continue; 1122 } 1123 1124 if (!sizeof($founder) || !in_array($ban_item, $founder)) 1125 { 1126 $banlist_ary[] = $ban_item; 1127 } 1128 } 1129 } 1130 1131 if (sizeof($ban_list) == 0) 1132 { 1133 trigger_error('NO_EMAILS_DEFINED', E_USER_WARNING); 1134 } 1135 break; 1136 1137 default: 1138 trigger_error('NO_MODE', E_USER_WARNING); 1139 break; 1140 } 1141 1142 // Fetch currently set bans of the specified type and exclude state. Prevent duplicate bans. 1143 $sql_where = ($type == 'ban_userid') ? 'ban_userid <> 0' : "$type <> ''"; 1144 1145 $sql = "SELECT $type 1146 FROM " . BANLIST_TABLE . " 1147 WHERE $sql_where 1148 AND ban_exclude = " . (int) $ban_exclude; 1149 $result = $db->sql_query($sql); 1150 1151 // Reset $sql_where, because we use it later... 1152 $sql_where = ''; 1153 1154 if ($row = $db->sql_fetchrow($result)) 1155 { 1156 $banlist_ary_tmp = array(); 1157 do 1158 { 1159 switch ($mode) 1160 { 1161 case 'user': 1162 $banlist_ary_tmp[] = $row['ban_userid']; 1163 break; 1164 1165 case 'ip': 1166 $banlist_ary_tmp[] = $row['ban_ip']; 1167 break; 1168 1169 case 'email': 1170 $banlist_ary_tmp[] = $row['ban_email']; 1171 break; 1172 } 1173 } 1174 while ($row = $db->sql_fetchrow($result)); 1175 1176 $banlist_ary_tmp = array_intersect($banlist_ary, $banlist_ary_tmp); 1177 1178 if (sizeof($banlist_ary_tmp)) 1179 { 1180 // One or more entities are already banned/excluded, delete the existing bans, so they can be re-inserted with the given new length 1181 $sql = 'DELETE FROM ' . BANLIST_TABLE . ' 1182 WHERE ' . $db->sql_in_set($type, $banlist_ary_tmp) . ' 1183 AND ban_exclude = ' . (int) $ban_exclude; 1184 $db->sql_query($sql); 1185 } 1186 1187 unset($banlist_ary_tmp); 1188 } 1189 $db->sql_freeresult($result); 1190 1191 // We have some entities to ban 1192 if (sizeof($banlist_ary)) 1193 { 1194 $sql_ary = array(); 1195 1196 foreach ($banlist_ary as $ban_entry) 1197 { 1198 $sql_ary[] = array( 1199 $type => $ban_entry, 1200 'ban_start' => (int) $current_time, 1201 'ban_end' => (int) $ban_end, 1202 'ban_exclude' => (int) $ban_exclude, 1203 'ban_reason' => (string) $ban_reason, 1204 'ban_give_reason' => (string) $ban_give_reason, 1205 ); 1206 } 1207 1208 $db->sql_multi_insert(BANLIST_TABLE, $sql_ary); 1209 1210 // If we are banning we want to logout anyone matching the ban 1211 if (!$ban_exclude) 1212 { 1213 switch ($mode) 1214 { 1215 case 'user': 1216 $sql_where = 'WHERE ' . $db->sql_in_set('session_user_id', $banlist_ary); 1217 break; 1218 1219 case 'ip': 1220 $sql_where = 'WHERE ' . $db->sql_in_set('session_ip', $banlist_ary); 1221 break; 1222 1223 case 'email': 1224 $banlist_ary_sql = array(); 1225 1226 foreach ($banlist_ary as $ban_entry) 1227 { 1228 $banlist_ary_sql[] = (string) str_replace('*', '%', $ban_entry); 1229 } 1230 1231 $sql = 'SELECT user_id 1232 FROM ' . USERS_TABLE . ' 1233 WHERE ' . $db->sql_in_set('user_email', $banlist_ary_sql); 1234 $result = $db->sql_query($sql); 1235 1236 $sql_in = array(); 1237 1238 if ($row = $db->sql_fetchrow($result)) 1239 { 1240 do 1241 { 1242 $sql_in[] = $row['user_id']; 1243 } 1244 while ($row = $db->sql_fetchrow($result)); 1245 1246 $sql_where = 'WHERE ' . $db->sql_in_set('session_user_id', $sql_in); 1247 } 1248 $db->sql_freeresult($result); 1249 break; 1250 } 1251 1252 if (isset($sql_where) && $sql_where) 1253 { 1254 $sql = 'DELETE FROM ' . SESSIONS_TABLE . " 1255 $sql_where"; 1256 $db->sql_query($sql); 1257 1258 if ($mode == 'user') 1259 { 1260 $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' ' . ((in_array('*', $banlist_ary)) ? '' : 'WHERE ' . $db->sql_in_set('user_id', $banlist_ary)); 1261 $db->sql_query($sql); 1262 } 1263 } 1264 } 1265 1266 // Update log 1267 $log_entry = ($ban_exclude) ? 'LOG_BAN_EXCLUDE_' : 'LOG_BAN_'; 1268 1269 // Add to admin log, moderator log and user notes 1270 add_log('admin', $log_entry . strtoupper($mode), $ban_reason, $ban_list_log); 1271 add_log('mod', 0, 0, $log_entry . strtoupper($mode), $ban_reason, $ban_list_log); 1272 if ($mode == 'user') 1273 { 1274 foreach ($banlist_ary as $user_id) 1275 { 1276 add_log('user', $user_id, $log_entry . strtoupper($mode), $ban_reason, $ban_list_log); 1277 } 1278 } 1279 1280 $cache->destroy('sql', BANLIST_TABLE); 1281 1282 return true; 1283 } 1284 1285 // There was nothing to ban/exclude. But destroying the cache because of the removal of stale bans. 1286 $cache->destroy('sql', BANLIST_TABLE); 1287 1288 return false; 1289 } 1290 1291 /** 1292 * Unban User 1293 */ 1294 function user_unban($mode, $ban) 1295 { 1296 global $db, $user, $auth, $cache, $phpbb_dispatcher; 1297 1298 // Delete stale bans 1299 $sql = 'DELETE FROM ' . BANLIST_TABLE . ' 1300 WHERE ban_end < ' . time() . ' 1301 AND ban_end <> 0'; 1302 $db->sql_query($sql); 1303 1304 if (!is_array($ban)) 1305 { 1306 $ban = array($ban); 1307 } 1308 1309 $unban_sql = array_map('intval', $ban); 1310 1311 if (sizeof($unban_sql)) 1312 { 1313 // Grab details of bans for logging information later 1314 switch ($mode) 1315 { 1316 case 'user': 1317 $sql = 'SELECT u.username AS unban_info, u.user_id 1318 FROM ' . USERS_TABLE . ' u, ' . BANLIST_TABLE . ' b 1319 WHERE ' . $db->sql_in_set('b.ban_id', $unban_sql) . ' 1320 AND u.user_id = b.ban_userid'; 1321 break; 1322 1323 case 'email': 1324 $sql = 'SELECT ban_email AS unban_info 1325 FROM ' . BANLIST_TABLE . ' 1326 WHERE ' . $db->sql_in_set('ban_id', $unban_sql); 1327 break; 1328 1329 case 'ip': 1330 $sql = 'SELECT ban_ip AS unban_info 1331 FROM ' . BANLIST_TABLE . ' 1332 WHERE ' . $db->sql_in_set('ban_id', $unban_sql); 1333 break; 1334 } 1335 $result = $db->sql_query($sql); 1336 1337 $l_unban_list = ''; 1338 $user_ids_ary = array(); 1339 while ($row = $db->sql_fetchrow($result)) 1340 { 1341 $l_unban_list .= (($l_unban_list != '') ? ', ' : '') . $row['unban_info']; 1342 if ($mode == 'user') 1343 { 1344 $user_ids_ary[] = $row['user_id']; 1345 } 1346 } 1347 $db->sql_freeresult($result); 1348 1349 $sql = 'DELETE FROM ' . BANLIST_TABLE . ' 1350 WHERE ' . $db->sql_in_set('ban_id', $unban_sql); 1351 $db->sql_query($sql); 1352 1353 // Add to moderator log, admin log and user notes 1354 add_log('admin', 'LOG_UNBAN_' . strtoupper($mode), $l_unban_list); 1355 add_log('mod', 0, 0, 'LOG_UNBAN_' . strtoupper($mode), $l_unban_list); 1356 if ($mode == 'user') 1357 { 1358 foreach ($user_ids_ary as $user_id) 1359 { 1360 add_log('user', $user_id, 'LOG_UNBAN_' . strtoupper($mode), $l_unban_list); 1361 } 1362 } 1363 1364 /** 1365 * Use this event to perform actions after the unban has been performed 1366 * 1367 * @event core.user_unban 1368 * @var string mode One of the following: user, ip, email 1369 * @var array user_ids_ary Array with user_ids 1370 * @since 3.1.11-RC1 1371 */ 1372 $vars = array( 1373 'mode', 1374 'user_ids_ary', 1375 ); 1376 extract($phpbb_dispatcher->trigger_event('core.user_unban', compact($vars))); 1377 } 1378 1379 $cache->destroy('sql', BANLIST_TABLE); 1380 1381 return false; 1382 } 1383 1384 /** 1385 * Internet Protocol Address Whois 1386 * RFC3912: WHOIS Protocol Specification 1387 * 1388 * @param string $ip Ip address, either IPv4 or IPv6. 1389 * 1390 * @return string Empty string if not a valid ip address. 1391 * Otherwise make_clickable()'ed whois result. 1392 */ 1393 function user_ipwhois($ip) 1394 { 1395 if (empty($ip)) 1396 { 1397 return ''; 1398 } 1399 1400 if (preg_match(get_preg_expression('ipv4'), $ip)) 1401 { 1402 // IPv4 address 1403 $whois_host = 'whois.arin.net.'; 1404 } 1405 else if (preg_match(get_preg_expression('ipv6'), $ip)) 1406 { 1407 // IPv6 address 1408 $whois_host = 'whois.sixxs.net.'; 1409 } 1410 else 1411 { 1412 return ''; 1413 } 1414 1415 $ipwhois = ''; 1416 1417 if (($fsk = @fsockopen($whois_host, 43))) 1418 { 1419 // CRLF as per RFC3912 1420 fputs($fsk, "$ip\r\n"); 1421 while (!feof($fsk)) 1422 { 1423 $ipwhois .= fgets($fsk, 1024); 1424 } 1425 @fclose($fsk); 1426 } 1427 1428 $match = array(); 1429 1430 // Test for referrals from $whois_host to other whois databases, roll on rwhois 1431 if (preg_match('#ReferralServer:[\x20]*whois://(.+)#im', $ipwhois, $match)) 1432 { 1433 if (strpos($match[1], ':') !== false) 1434 { 1435 $pos = strrpos($match[1], ':'); 1436 $server = substr($match[1], 0, $pos); 1437 $port = (int) substr($match[1], $pos + 1); 1438 unset($pos); 1439 } 1440 else 1441 { 1442 $server = $match[1]; 1443 $port = 43; 1444 } 1445 1446 $buffer = ''; 1447 1448 if (($fsk = @fsockopen($server, $port))) 1449 { 1450 fputs($fsk, "$ip\r\n"); 1451 while (!feof($fsk)) 1452 { 1453 $buffer .= fgets($fsk, 1024); 1454 } 1455 @fclose($fsk); 1456 } 1457 1458 // Use the result from $whois_host if we don't get any result here 1459 $ipwhois = (empty($buffer)) ? $ipwhois : $buffer; 1460 } 1461 1462 $ipwhois = htmlspecialchars($ipwhois); 1463 1464 // Magic URL ;) 1465 return trim(make_clickable($ipwhois, false, '')); 1466 } 1467 1468 /** 1469 * Data validation ... used primarily but not exclusively by ucp modules 1470 * 1471 * "Master" function for validating a range of data types 1472 */ 1473 function validate_data($data, $val_ary) 1474 { 1475 global $user; 1476 1477 $error = array(); 1478 1479 foreach ($val_ary as $var => $val_seq) 1480 { 1481 if (!is_array($val_seq[0])) 1482 { 1483 $val_seq = array($val_seq); 1484 } 1485 1486 foreach ($val_seq as $validate) 1487 { 1488 $function = array_shift($validate); 1489 array_unshift($validate, $data[$var]); 1490 1491 if (is_array($function)) 1492 { 1493 $result = call_user_func_array(array($function[0], 'validate_' . $function[1]), $validate); 1494 } 1495 else 1496 { 1497 $function_prefix = (function_exists('phpbb_validate_' . $function)) ? 'phpbb_validate_' : 'validate_'; 1498 $result = call_user_func_array($function_prefix . $function, $validate); 1499 } 1500 1501 if ($result) 1502 { 1503 // Since errors are checked later for their language file existence, we need to make sure custom errors are not adjusted. 1504 $error[] = (empty($user->lang[$result . '_' . strtoupper($var)])) ? $result : $result . '_' . strtoupper($var); 1505 } 1506 } 1507 } 1508 1509 return $error; 1510 } 1511 1512 /** 1513 * Validate String 1514 * 1515 * @return boolean|string Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) 1516 */ 1517 function validate_string($string, $optional = false, $min = 0, $max = 0) 1518 { 1519 if (empty($string) && $optional) 1520 { 1521 return false; 1522 } 1523 1524 if ($min && utf8_strlen(htmlspecialchars_decode($string)) < $min) 1525 { 1526 return 'TOO_SHORT'; 1527 } 1528 else if ($max && utf8_strlen(htmlspecialchars_decode($string)) > $max) 1529 { 1530 return 'TOO_LONG'; 1531 } 1532 1533 return false; 1534 } 1535 1536 /** 1537 * Validate Number 1538 * 1539 * @return boolean|string Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) 1540 */ 1541 function validate_num($num, $optional = false, $min = 0, $max = 1E99) 1542 { 1543 if (empty($num) && $optional) 1544 { 1545 return false; 1546 } 1547 1548 if ($num < $min) 1549 { 1550 return 'TOO_SMALL'; 1551 } 1552 else if ($num > $max) 1553 { 1554 return 'TOO_LARGE'; 1555 } 1556 1557 return false; 1558 } 1559 1560 /** 1561 * Validate Date 1562 * @param String $string a date in the dd-mm-yyyy format 1563 * @return boolean 1564 */ 1565 function validate_date($date_string, $optional = false) 1566 { 1567 $date = explode('-', $date_string); 1568 if ((empty($date) || sizeof($date) != 3) && $optional) 1569 { 1570 return false; 1571 } 1572 else if ($optional) 1573 { 1574 for ($field = 0; $field <= 1; $field++) 1575 { 1576 $date[$field] = (int) $date[$field]; 1577 if (empty($date[$field])) 1578 { 1579 $date[$field] = 1; 1580 } 1581 } 1582 $date[2] = (int) $date[2]; 1583 // assume an arbitrary leap year 1584 if (empty($date[2])) 1585 { 1586 $date[2] = 1980; 1587 } 1588 } 1589 1590 if (sizeof($date) != 3 || !checkdate($date[1], $date[0], $date[2])) 1591 { 1592 return 'INVALID'; 1593 } 1594 1595 return false; 1596 } 1597 1598 1599 /** 1600 * Validate Match 1601 * 1602 * @return boolean|string Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) 1603 */ 1604 function validate_match($string, $optional = false, $match = '') 1605 { 1606 if (empty($string) && $optional) 1607 { 1608 return false; 1609 } 1610 1611 if (empty($match)) 1612 { 1613 return false; 1614 } 1615 1616 if (!preg_match($match, $string)) 1617 { 1618 return 'WRONG_DATA'; 1619 } 1620 1621 return false; 1622 } 1623 1624 /** 1625 * Validate Language Pack ISO Name 1626 * 1627 * Tests whether a language name is valid and installed 1628 * 1629 * @param string $lang_iso The language string to test 1630 * 1631 * @return bool|string Either false if validation succeeded or 1632 * a string which will be used as the error message 1633 * (with the variable name appended) 1634 */ 1635 function validate_language_iso_name($lang_iso) 1636 { 1637 global $db; 1638 1639 $sql = 'SELECT lang_id 1640 FROM ' . LANG_TABLE . " 1641 WHERE lang_iso = '" . $db->sql_escape($lang_iso) . "'"; 1642 $result = $db->sql_query($sql); 1643 $lang_id = (int) $db->sql_fetchfield('lang_id'); 1644 $db->sql_freeresult($result); 1645 1646 return ($lang_id) ? false : 'WRONG_DATA'; 1647 } 1648 1649 /** 1650 * Validate Timezone Name 1651 * 1652 * Tests whether a timezone name is valid 1653 * 1654 * @param string $timezone The timezone string to test 1655 * 1656 * @return bool|string Either false if validation succeeded or 1657 * a string which will be used as the error message 1658 * (with the variable name appended) 1659 */ 1660 function phpbb_validate_timezone($timezone) 1661 { 1662 return (in_array($timezone, phpbb_get_timezone_identifiers($timezone))) ? false : 'TIMEZONE_INVALID'; 1663 } 1664 1665 /** 1666 * Check to see if the username has been taken, or if it is disallowed. 1667 * Also checks if it includes the " character, which we don't allow in usernames. 1668 * Used for registering, changing names, and posting anonymously with a username 1669 * 1670 * @param string $username The username to check 1671 * @param string $allowed_username An allowed username, default being $user->data['username'] 1672 * 1673 * @return mixed Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) 1674 */ 1675 function validate_username($username, $allowed_username = false) 1676 { 1677 global $config, $db, $user, $cache; 1678 1679 $clean_username = utf8_clean_string($username); 1680 $allowed_username = ($allowed_username === false) ? $user->data['username_clean'] : utf8_clean_string($allowed_username); 1681 1682 if ($allowed_username == $clean_username) 1683 { 1684 return false; 1685 } 1686 1687 // ... fast checks first. 1688 if (strpos($username, '"') !== false || strpos($username, '"') !== false || empty($clean_username)) 1689 { 1690 return 'INVALID_CHARS'; 1691 } 1692 1693 $mbstring = $pcre = false; 1694 1695 // generic UTF-8 character types supported? 1696 if (phpbb_pcre_utf8_support()) 1697 { 1698 $pcre = true; 1699 } 1700 else if (function_exists('mb_ereg_match')) 1701 { 1702 mb_regex_encoding('UTF-8'); 1703 $mbstring = true; 1704 } 1705 1706 switch ($config['allow_name_chars']) 1707 { 1708 case 'USERNAME_CHARS_ANY': 1709 $pcre = true; 1710 $regex = '.+'; 1711 break; 1712 1713 case 'USERNAME_ALPHA_ONLY': 1714 $pcre = true; 1715 $regex = '[A-Za-z0-9]+'; 1716 break; 1717 1718 case 'USERNAME_ALPHA_SPACERS': 1719 $pcre = true; 1720 $regex = '[A-Za-z0-9-[\]_+ ]+'; 1721 break; 1722 1723 case 'USERNAME_LETTER_NUM': 1724 if ($pcre) 1725 { 1726 $regex = '[\p{Lu}\p{Ll}\p{N}]+'; 1727 } 1728 else if ($mbstring) 1729 { 1730 $regex = '[[:upper:][:lower:][:digit:]]+'; 1731 } 1732 else 1733 { 1734 $pcre = true; 1735 $regex = '[a-zA-Z0-9]+'; 1736 } 1737 break; 1738 1739 case 'USERNAME_LETTER_NUM_SPACERS': 1740 if ($pcre) 1741 { 1742 $regex = '[-\]_+ [\p{Lu}\p{Ll}\p{N}]+'; 1743 } 1744 else if ($mbstring) 1745 { 1746 $regex = '[-\]_+ \[[:upper:][:lower:][:digit:]]+'; 1747 } 1748 else 1749 { 1750 $pcre = true; 1751 $regex = '[-\]_+ [a-zA-Z0-9]+'; 1752 } 1753 break; 1754 1755 case 'USERNAME_ASCII': 1756 default: 1757 $pcre = true; 1758 $regex = '[\x01-\x7F]+'; 1759 break; 1760 } 1761 1762 if ($pcre) 1763 { 1764 if (!preg_match('#^' . $regex . '$#u', $username)) 1765 { 1766 return 'INVALID_CHARS'; 1767 } 1768 } 1769 else if ($mbstring) 1770 { 1771 mb_ereg_search_init($username, '^' . $regex . '$'); 1772 if (!mb_ereg_search()) 1773 { 1774 return 'INVALID_CHARS'; 1775 } 1776 } 1777 1778 $sql = 'SELECT username 1779 FROM ' . USERS_TABLE . " 1780 WHERE username_clean = '" . $db->sql_escape($clean_username) . "'"; 1781 $result = $db->sql_query($sql); 1782 $row = $db->sql_fetchrow($result); 1783 $db->sql_freeresult($result); 1784 1785 if ($row) 1786 { 1787 return 'USERNAME_TAKEN'; 1788 } 1789 1790 $sql = 'SELECT group_name 1791 FROM ' . GROUPS_TABLE . " 1792 WHERE LOWER(group_name) = '" . $db->sql_escape(utf8_strtolower($username)) . "'"; 1793 $result = $db->sql_query($sql); 1794 $row = $db->sql_fetchrow($result); 1795 $db->sql_freeresult($result); 1796 1797 if ($row) 1798 { 1799 return 'USERNAME_TAKEN'; 1800 } 1801 1802 $bad_usernames = $cache->obtain_disallowed_usernames(); 1803 1804 foreach ($bad_usernames as $bad_username) 1805 { 1806 if (preg_match('#^' . $bad_username . '$#', $clean_username)) 1807 { 1808 return 'USERNAME_DISALLOWED'; 1809 } 1810 } 1811 1812 return false; 1813 } 1814 1815 /** 1816 * Check to see if the password meets the complexity settings 1817 * 1818 * @return boolean|string Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) 1819 */ 1820 function validate_password($password) 1821 { 1822 global $config; 1823 1824 if ($password === '' || $config['pass_complex'] === 'PASS_TYPE_ANY') 1825 { 1826 // Password empty or no password complexity required. 1827 return false; 1828 } 1829 1830 $pcre = $mbstring = false; 1831 1832 // generic UTF-8 character types supported? 1833 if (phpbb_pcre_utf8_support()) 1834 { 1835 $upp = '\p{Lu}'; 1836 $low = '\p{Ll}'; 1837 $num = '\p{N}'; 1838 $sym = '[^\p{Lu}\p{Ll}\p{N}]'; 1839 $pcre = true; 1840 } 1841 else if (function_exists('mb_ereg_match')) 1842 { 1843 mb_regex_encoding('UTF-8'); 1844 $upp = '[[:upper:]]'; 1845 $low = '[[:lower:]]'; 1846 $num = '[[:digit:]]'; 1847 $sym = '[^[:upper:][:lower:][:digit:]]'; 1848 $mbstring = true; 1849 } 1850 else 1851 { 1852 $upp = '[A-Z]'; 1853 $low = '[a-z]'; 1854 $num = '[0-9]'; 1855 $sym = '[^A-Za-z0-9]'; 1856 $pcre = true; 1857 } 1858 1859 $chars = array(); 1860 1861 switch ($config['pass_complex']) 1862 { 1863 // No break statements below ... 1864 // We require strong passwords in case pass_complex is not set or is invalid 1865 default: 1866 1867 // Require mixed case letters, numbers and symbols 1868 case 'PASS_TYPE_SYMBOL': 1869 $chars[] = $sym; 1870 1871 // Require mixed case letters and numbers 1872 case 'PASS_TYPE_ALPHA': 1873 $chars[] = $num; 1874 1875 // Require mixed case letters 1876 case 'PASS_TYPE_CASE': 1877 $chars[] = $low; 1878 $chars[] = $upp; 1879 } 1880 1881 if ($pcre) 1882 { 1883 foreach ($chars as $char) 1884 { 1885 if (!preg_match('#' . $char . '#u', $password)) 1886 { 1887 return 'INVALID_CHARS'; 1888 } 1889 } 1890 } 1891 else if ($mbstring) 1892 { 1893 foreach ($chars as $char) 1894 { 1895 if (mb_ereg($char, $password) === false) 1896 { 1897 return 'INVALID_CHARS'; 1898 } 1899 } 1900 } 1901 1902 return false; 1903 } 1904 1905 /** 1906 * Check to see if email address is a valid address and contains a MX record 1907 * 1908 * @param string $email The email to check 1909 * 1910 * @return mixed Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) 1911 */ 1912 function phpbb_validate_email($email, $config = null) 1913 { 1914 if ($config === null) 1915 { 1916 global $config; 1917 } 1918 1919 $email = strtolower($email); 1920 1921 if (!preg_match('/^' . get_preg_expression('email') . '$/i', $email)) 1922 { 1923 return 'EMAIL_INVALID'; 1924 } 1925 1926 // Check MX record. 1927 // The idea for this is from reading the UseBB blog/announcement. :) 1928 if ($config['email_check_mx']) 1929 { 1930 list(, $domain) = explode('@', $email); 1931 1932 if (phpbb_checkdnsrr($domain, 'A') === false && phpbb_checkdnsrr($domain, 'MX') === false) 1933 { 1934 return 'DOMAIN_NO_MX_RECORD'; 1935 } 1936 } 1937 1938 return false; 1939 } 1940 1941 /** 1942 * Check to see if email address is banned or already present in the DB 1943 * 1944 * @param string $email The email to check 1945 * @param string $allowed_email An allowed email, default being $user->data['user_email'] 1946 * 1947 * @return mixed Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) 1948 */ 1949 function validate_user_email($email, $allowed_email = false) 1950 { 1951 global $config, $db, $user; 1952 1953 $email = strtolower($email); 1954 $allowed_email = ($allowed_email === false) ? strtolower($user->data['user_email']) : strtolower($allowed_email); 1955 1956 if ($allowed_email == $email) 1957 { 1958 return false; 1959 } 1960 1961 $validate_email = phpbb_validate_email($email, $config); 1962 if ($validate_email) 1963 { 1964 return $validate_email; 1965 } 1966 1967 if (($ban_reason = $user->check_ban(false, false, $email, true)) !== false) 1968 { 1969 return ($ban_reason === true) ? 'EMAIL_BANNED' : $ban_reason; 1970 } 1971 1972 if (!$config['allow_emailreuse']) 1973 { 1974 $sql = 'SELECT user_email_hash 1975 FROM ' . USERS_TABLE . " 1976 WHERE user_email_hash = " . $db->sql_escape(phpbb_email_hash($email)); 1977 $result = $db->sql_query($sql); 1978 $row = $db->sql_fetchrow($result); 1979 $db->sql_freeresult($result); 1980 1981 if ($row) 1982 { 1983 return 'EMAIL_TAKEN'; 1984 } 1985 } 1986 1987 return false; 1988 } 1989 1990 /** 1991 * Validate jabber address 1992 * Taken from the jabber class within flyspray (see author notes) 1993 * 1994 * @author flyspray.org 1995 */ 1996 function validate_jabber($jid) 1997 { 1998 if (!$jid) 1999 { 2000 return false; 2001 } 2002 2003 $separator_pos = strpos($jid, '@'); 2004 2005 if ($separator_pos === false) 2006 { 2007 return 'WRONG_DATA'; 2008 } 2009 2010 $username = substr($jid, 0, $separator_pos); 2011 $realm = substr($jid, $separator_pos + 1); 2012 2013 if (strlen($username) == 0 || strlen($realm) < 3) 2014 { 2015 return 'WRONG_DATA'; 2016 } 2017 2018 $arr = explode('.', $realm); 2019 2020 if (sizeof($arr) == 0) 2021 { 2022 return 'WRONG_DATA'; 2023 } 2024 2025 foreach ($arr as $part) 2026 { 2027 if (substr($part, 0, 1) == '-' || substr($part, -1, 1) == '-') 2028 { 2029 return 'WRONG_DATA'; 2030 } 2031 2032 if (!preg_match("@^[a-zA-Z0-9-.]+$@", $part)) 2033 { 2034 return 'WRONG_DATA'; 2035 } 2036 } 2037 2038 $boundary = array(array(0, 127), array(192, 223), array(224, 239), array(240, 247), array(248, 251), array(252, 253)); 2039 2040 // Prohibited Characters RFC3454 + RFC3920 2041 $prohibited = array( 2042 // Table C.1.1 2043 array(0x0020, 0x0020), // SPACE 2044 // Table C.1.2 2045 array(0x00A0, 0x00A0), // NO-BREAK SPACE 2046 array(0x1680, 0x1680), // OGHAM SPACE MARK 2047 array(0x2000, 0x2001), // EN QUAD 2048 array(0x2001, 0x2001), // EM QUAD 2049 array(0x2002, 0x2002), // EN SPACE 2050 array(0x2003, 0x2003), // EM SPACE 2051 array(0x2004, 0x2004), // THREE-PER-EM SPACE 2052 array(0x2005, 0x2005), // FOUR-PER-EM SPACE 2053 array(0x2006, 0x2006), // SIX-PER-EM SPACE 2054 array(0x2007, 0x2007), // FIGURE SPACE 2055 array(0x2008, 0x2008), // PUNCTUATION SPACE 2056 array(0x2009, 0x2009), // THIN SPACE 2057 array(0x200A, 0x200A), // HAIR SPACE 2058 array(0x200B, 0x200B), // ZERO WIDTH SPACE 2059 array(0x202F, 0x202F), // NARROW NO-BREAK SPACE 2060 array(0x205F, 0x205F), // MEDIUM MATHEMATICAL SPACE 2061 array(0x3000, 0x3000), // IDEOGRAPHIC SPACE 2062 // Table C.2.1 2063 array(0x0000, 0x001F), // [CONTROL CHARACTERS] 2064 array(0x007F, 0x007F), // DELETE 2065 // Table C.2.2 2066 array(0x0080, 0x009F), // [CONTROL CHARACTERS] 2067 array(0x06DD, 0x06DD), // ARABIC END OF AYAH 2068 array(0x070F, 0x070F), // SYRIAC ABBREVIATION MARK 2069 array(0x180E, 0x180E), // MONGOLIAN VOWEL SEPARATOR 2070 array(0x200C, 0x200C), // ZERO WIDTH NON-JOINER 2071 array(0x200D, 0x200D), // ZERO WIDTH JOINER 2072 array(0x2028, 0x2028), // LINE SEPARATOR 2073 array(0x2029, 0x2029), // PARAGRAPH SEPARATOR 2074 array(0x2060, 0x2060), // WORD JOINER 2075 array(0x2061, 0x2061), // FUNCTION APPLICATION 2076 array(0x2062, 0x2062), // INVISIBLE TIMES 2077 array(0x2063, 0x2063), // INVISIBLE SEPARATOR 2078 array(0x206A, 0x206F), // [CONTROL CHARACTERS] 2079 array(0xFEFF, 0xFEFF), // ZERO WIDTH NO-BREAK SPACE 2080 array(0xFFF9, 0xFFFC), // [CONTROL CHARACTERS] 2081 array(0x1D173, 0x1D17A), // [MUSICAL CONTROL CHARACTERS] 2082 // Table C.3 2083 array(0xE000, 0xF8FF), // [PRIVATE USE, PLANE 0] 2084 array(0xF0000, 0xFFFFD), // [PRIVATE USE, PLANE 15] 2085 array(0x100000, 0x10FFFD), // [PRIVATE USE, PLANE 16] 2086 // Table C.4 2087 array(0xFDD0, 0xFDEF), // [NONCHARACTER CODE POINTS] 2088 array(0xFFFE, 0xFFFF), // [NONCHARACTER CODE POINTS] 2089 array(0x1FFFE, 0x1FFFF), // [NONCHARACTER CODE POINTS] 2090 array(0x2FFFE, 0x2FFFF), // [NONCHARACTER CODE POINTS] 2091 array(0x3FFFE, 0x3FFFF), // [NONCHARACTER CODE POINTS] 2092 array(0x4FFFE, 0x4FFFF), // [NONCHARACTER CODE POINTS] 2093 array(0x5FFFE, 0x5FFFF), // [NONCHARACTER CODE POINTS] 2094 array(0x6FFFE, 0x6FFFF), // [NONCHARACTER CODE POINTS] 2095 array(0x7FFFE, 0x7FFFF), // [NONCHARACTER CODE POINTS] 2096 array(0x8FFFE, 0x8FFFF), // [NONCHARACTER CODE POINTS] 2097 array(0x9FFFE, 0x9FFFF), // [NONCHARACTER CODE POINTS] 2098 array(0xAFFFE, 0xAFFFF), // [NONCHARACTER CODE POINTS] 2099 array(0xBFFFE, 0xBFFFF), // [NONCHARACTER CODE POINTS] 2100 array(0xCFFFE, 0xCFFFF), // [NONCHARACTER CODE POINTS] 2101 array(0xDFFFE, 0xDFFFF), // [NONCHARACTER CODE POINTS] 2102 array(0xEFFFE, 0xEFFFF), // [NONCHARACTER CODE POINTS] 2103 array(0xFFFFE, 0xFFFFF), // [NONCHARACTER CODE POINTS] 2104 array(0x10FFFE, 0x10FFFF), // [NONCHARACTER CODE POINTS] 2105 // Table C.5 2106 array(0xD800, 0xDFFF), // [SURROGATE CODES] 2107 // Table C.6 2108 array(0xFFF9, 0xFFF9), // INTERLINEAR ANNOTATION ANCHOR 2109 array(0xFFFA, 0xFFFA), // INTERLINEAR ANNOTATION SEPARATOR 2110 array(0xFFFB, 0xFFFB), // INTERLINEAR ANNOTATION TERMINATOR 2111 array(0xFFFC, 0xFFFC), // OBJECT REPLACEMENT CHARACTER 2112 array(0xFFFD, 0xFFFD), // REPLACEMENT CHARACTER 2113 // Table C.7 2114 array(0x2FF0, 0x2FFB), // [IDEOGRAPHIC DESCRIPTION CHARACTERS] 2115 // Table C.8 2116 array(0x0340, 0x0340), // COMBINING GRAVE TONE MARK 2117 array(0x0341, 0x0341), // COMBINING ACUTE TONE MARK 2118 array(0x200E, 0x200E), // LEFT-TO-RIGHT MARK 2119 array(0x200F, 0x200F), // RIGHT-TO-LEFT MARK 2120 array(0x202A, 0x202A), // LEFT-TO-RIGHT EMBEDDING 2121 array(0x202B, 0x202B), // RIGHT-TO-LEFT EMBEDDING 2122 array(0x202C, 0x202C), // POP DIRECTIONAL FORMATTING 2123 array(0x202D, 0x202D), // LEFT-TO-RIGHT OVERRIDE 2124 array(0x202E, 0x202E), // RIGHT-TO-LEFT OVERRIDE 2125 array(0x206A, 0x206A), // INHIBIT SYMMETRIC SWAPPING 2126 array(0x206B, 0x206B), // ACTIVATE SYMMETRIC SWAPPING 2127 array(0x206C, 0x206C), // INHIBIT ARABIC FORM SHAPING 2128 array(0x206D, 0x206D), // ACTIVATE ARABIC FORM SHAPING 2129 array(0x206E, 0x206E), // NATIONAL DIGIT SHAPES 2130 array(0x206F, 0x206F), // NOMINAL DIGIT SHAPES 2131 // Table C.9 2132 array(0xE0001, 0xE0001), // LANGUAGE TAG 2133 array(0xE0020, 0xE007F), // [TAGGING CHARACTERS] 2134 // RFC3920 2135 array(0x22, 0x22), // " 2136 array(0x26, 0x26), // & 2137 array(0x27, 0x27), // ' 2138 array(0x2F, 0x2F), // / 2139 array(0x3A, 0x3A), // : 2140 array(0x3C, 0x3C), // < 2141 array(0x3E, 0x3E), // > 2142 array(0x40, 0x40) // @ 2143 ); 2144 2145 $pos = 0; 2146 $result = true; 2147 2148 while ($pos < strlen($username)) 2149 { 2150 $len = $uni = 0; 2151 for ($i = 0; $i <= 5; $i++) 2152 { 2153 if (ord($username[$pos]) >= $boundary[$i][0] && ord($username[$pos]) <= $boundary[$i][1]) 2154 { 2155 $len = $i + 1; 2156 $uni = (ord($username[$pos]) - $boundary[$i][0]) * pow(2, $i * 6); 2157 2158 for ($k = 1; $k < $len; $k++) 2159 { 2160 $uni += (ord($username[$pos + $k]) - 128) * pow(2, ($i - $k) * 6); 2161 } 2162 2163 break; 2164 } 2165 } 2166 2167 if ($len == 0) 2168 { 2169 return 'WRONG_DATA'; 2170 } 2171 2172 foreach ($prohibited as $pval) 2173 { 2174 if ($uni >= $pval[0] && $uni <= $pval[1]) 2175 { 2176 $result = false; 2177 break 2; 2178 } 2179 } 2180 2181 $pos = $pos + $len; 2182 } 2183 2184 if (!$result) 2185 { 2186 return 'WRONG_DATA'; 2187 } 2188 2189 return false; 2190 } 2191 2192 /** 2193 * Validate hex colour value 2194 * 2195 * @param string $colour The hex colour value 2196 * @param bool $optional Whether the colour value is optional. True if an empty 2197 * string will be accepted as correct input, false if not. 2198 * @return bool|string Error message if colour value is incorrect, false if it 2199 * fits the hex colour code 2200 */ 2201 function phpbb_validate_hex_colour($colour, $optional = false) 2202 { 2203 if ($colour === '') 2204 { 2205 return (($optional) ? false : 'WRONG_DATA'); 2206 } 2207 2208 if (!preg_match('/^([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/', $colour)) 2209 { 2210 return 'WRONG_DATA'; 2211 } 2212 2213 return false; 2214 } 2215 2216 /** 2217 * Verifies whether a style ID corresponds to an active style. 2218 * 2219 * @param int $style_id The style_id of a style which should be checked if activated or not. 2220 * @return boolean 2221 */ 2222 function phpbb_style_is_active($style_id) 2223 { 2224 global $db; 2225 2226 $sql = 'SELECT style_active 2227 FROM ' . STYLES_TABLE . ' 2228 WHERE style_id = '. (int) $style_id; 2229 $result = $db->sql_query($sql); 2230 2231 $style_is_active = (bool) $db->sql_fetchfield('style_active'); 2232 $db->sql_freeresult($result); 2233 2234 return $style_is_active; 2235 } 2236 2237 /** 2238 * Remove avatar 2239 */ 2240 function avatar_delete($mode, $row, $clean_db = false) 2241 { 2242 global $phpbb_root_path, $config, $db, $user; 2243 2244 // Check if the users avatar is actually *not* a group avatar 2245 if ($mode == 'user') 2246 { 2247 if (strpos($row['user_avatar'], 'g') === 0 || (((int) $row['user_avatar'] !== 0) && ((int) $row['user_avatar'] !== (int) $row['user_id']))) 2248 { 2249 return false; 2250 } 2251 } 2252 2253 if ($clean_db) 2254 { 2255 avatar_remove_db($row[$mode . '_avatar']); 2256 } 2257 $filename = get_avatar_filename($row[$mode . '_avatar']); 2258 2259 if (file_exists($phpbb_root_path . $config['avatar_path'] . '/' . $filename)) 2260 { 2261 @unlink($phpbb_root_path . $config['avatar_path'] . '/' . $filename); 2262 return true; 2263 } 2264 2265 return false; 2266 } 2267 2268 /** 2269 * Generates avatar filename from the database entry 2270 */ 2271 function get_avatar_filename($avatar_entry) 2272 { 2273 global $config; 2274 2275 if ($avatar_entry[0] === 'g') 2276 { 2277 $avatar_group = true; 2278 $avatar_entry = substr($avatar_entry, 1); 2279 } 2280 else 2281 { 2282 $avatar_group = false; 2283 } 2284 $ext = substr(strrchr($avatar_entry, '.'), 1); 2285 $avatar_entry = intval($avatar_entry); 2286 return $config['avatar_salt'] . '_' . (($avatar_group) ? 'g' : '') . $avatar_entry . '.' . $ext; 2287 } 2288 2289 /** 2290 * Returns an explanation string with maximum avatar settings 2291 * 2292 * @return string 2293 */ 2294 function phpbb_avatar_explanation_string() 2295 { 2296 global $config, $user; 2297 2298 return $user->lang(($config['avatar_filesize'] == 0) ? 'AVATAR_EXPLAIN_NO_FILESIZE' : 'AVATAR_EXPLAIN', 2299 $user->lang('PIXELS', (int) $config['avatar_max_width']), 2300 $user->lang('PIXELS', (int) $config['avatar_max_height']), 2301 round($config['avatar_filesize'] / 1024)); 2302 } 2303 2304 // 2305 // Usergroup functions 2306 // 2307 2308 /** 2309 * Add or edit a group. If we're editing a group we only update user 2310 * parameters such as rank, etc. if they are changed 2311 */ 2312 function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow_desc_bbcode = false, $allow_desc_urls = false, $allow_desc_smilies = false) 2313 { 2314 global $phpbb_root_path, $config, $db, $user, $file_upload, $phpbb_container; 2315 2316 $error = array(); 2317 2318 // Attributes which also affect the users table 2319 $user_attribute_ary = array('group_colour', 'group_rank', 'group_avatar', 'group_avatar_type', 'group_avatar_width', 'group_avatar_height'); 2320 2321 // Check data. Limit group name length. 2322 if (!utf8_strlen($name) || utf8_strlen($name) > 60) 2323 { 2324 $error[] = (!utf8_strlen($name)) ? $user->lang['GROUP_ERR_USERNAME'] : $user->lang['GROUP_ERR_USER_LONG']; 2325 } 2326 2327 $err = group_validate_groupname($group_id, $name); 2328 if (!empty($err)) 2329 { 2330 $error[] = $user->lang[$err]; 2331 } 2332 2333 if (!in_array($type, array(GROUP_OPEN, GROUP_CLOSED, GROUP_HIDDEN, GROUP_SPECIAL, GROUP_FREE))) 2334 { 2335 $error[] = $user->lang['GROUP_ERR_TYPE']; 2336 } 2337 2338 $group_teampage = !empty($group_attributes['group_teampage']); 2339 unset($group_attributes['group_teampage']); 2340 2341 if (!sizeof($error)) 2342 { 2343 $current_legend = \phpbb\groupposition\legend::GROUP_DISABLED; 2344 $current_teampage = \phpbb\groupposition\teampage::GROUP_DISABLED; 2345 2346 $legend = $phpbb_container->get('groupposition.legend'); 2347 $teampage = $phpbb_container->get('groupposition.teampage'); 2348 if ($group_id) 2349 { 2350 try 2351 { 2352 $current_legend = $legend->get_group_value($group_id); 2353 $current_teampage = $teampage->get_group_value($group_id); 2354 } 2355 catch (\phpbb\groupposition\exception $exception) 2356 { 2357 trigger_error($user->lang($exception->getMessage())); 2358 } 2359 } 2360 2361 if (!empty($group_attributes['group_legend'])) 2362 { 2363 if (($group_id && ($current_legend == \phpbb\groupposition\legend::GROUP_DISABLED)) || !$group_id) 2364 { 2365 // Old group currently not in the legend or new group, add at the end. 2366 $group_attributes['group_legend'] = 1 + $legend->get_group_count(); 2367 } 2368 else 2369 { 2370 // Group stayes in the legend 2371 $group_attributes['group_legend'] = $current_legend; 2372 } 2373 } 2374 else if ($group_id && ($current_legend != \phpbb\groupposition\legend::GROUP_DISABLED)) 2375 { 2376 // Group is removed from the legend 2377 try 2378 { 2379 $legend->delete_group($group_id, true); 2380 } 2381 catch (\phpbb\groupposition\exception $exception) 2382 { 2383 trigger_error($user->lang($exception->getMessage())); 2384 } 2385 $group_attributes['group_legend'] = \phpbb\groupposition\legend::GROUP_DISABLED; 2386 } 2387 else 2388 { 2389 $group_attributes['group_legend'] = \phpbb\groupposition\legend::GROUP_DISABLED; 2390 } 2391 2392 // Unset the objects, we don't need them anymore. 2393 unset($legend); 2394 2395 $user_ary = array(); 2396 $sql_ary = array( 2397 'group_name' => (string) $name, 2398 'group_desc' => (string) $desc, 2399 'group_desc_uid' => '', 2400 'group_desc_bitfield' => '', 2401 'group_type' => (int) $type, 2402 ); 2403 2404 // Parse description 2405 if ($desc) 2406 { 2407 generate_text_for_storage($sql_ary['group_desc'], $sql_ary['group_desc_uid'], $sql_ary['group_desc_bitfield'], $sql_ary['group_desc_options'], $allow_desc_bbcode, $allow_desc_urls, $allow_desc_smilies); 2408 } 2409 2410 if (sizeof($group_attributes)) 2411 { 2412 // Merge them with $sql_ary to properly update the group 2413 $sql_ary = array_merge($sql_ary, $group_attributes); 2414 } 2415 2416 // Setting the log message before we set the group id (if group gets added) 2417 $log = ($group_id) ? 'LOG_GROUP_UPDATED' : 'LOG_GROUP_CREATED'; 2418 2419 $query = ''; 2420 2421 if ($group_id) 2422 { 2423 $sql = 'SELECT user_id 2424 FROM ' . USERS_TABLE . ' 2425 WHERE group_id = ' . $group_id; 2426 $result = $db->sql_query($sql); 2427 2428 while ($row = $db->sql_fetchrow($result)) 2429 { 2430 $user_ary[] = $row['user_id']; 2431 } 2432 $db->sql_freeresult($result); 2433 2434 if (isset($sql_ary['group_avatar'])) 2435 { 2436 remove_default_avatar($group_id, $user_ary); 2437 } 2438 2439 if (isset($sql_ary['group_rank'])) 2440 { 2441 remove_default_rank($group_id, $user_ary); 2442 } 2443 2444 $sql = 'UPDATE ' . GROUPS_TABLE . ' 2445 SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " 2446 WHERE group_id = $group_id"; 2447 $db->sql_query($sql); 2448 2449 // Since we may update the name too, we need to do this on other tables too... 2450 $sql = 'UPDATE ' . MODERATOR_CACHE_TABLE . " 2451 SET group_name = '" . $db->sql_escape($sql_ary['group_name']) . "' 2452 WHERE group_id = $group_id"; 2453 $db->sql_query($sql); 2454 2455 // One special case is the group skip auth setting. If this was changed we need to purge permissions for this group 2456 if (isset($group_attributes['group_skip_auth'])) 2457 { 2458 // Get users within this group... 2459 $sql = 'SELECT user_id 2460 FROM ' . USER_GROUP_TABLE . ' 2461 WHERE group_id = ' . $group_id . ' 2462 AND user_pending = 0'; 2463 $result = $db->sql_query($sql); 2464 2465 $user_id_ary = array(); 2466 while ($row = $db->sql_fetchrow($result)) 2467 { 2468 $user_id_ary[] = $row['user_id']; 2469 } 2470 $db->sql_freeresult($result); 2471 2472 if (!empty($user_id_ary)) 2473 { 2474 global $auth; 2475 2476 // Clear permissions cache of relevant users 2477 $auth->acl_clear_prefetch($user_id_ary); 2478 } 2479 } 2480 } 2481 else 2482 { 2483 $sql = 'INSERT INTO ' . GROUPS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); 2484 $db->sql_query($sql); 2485 } 2486 2487 // Remove the group from the teampage, only if unselected and we are editing a group, 2488 // which is currently displayed. 2489 if (!$group_teampage && $group_id && $current_teampage != \phpbb\groupposition\teampage::GROUP_DISABLED) 2490 { 2491 try 2492 { 2493 $teampage->delete_group($group_id); 2494 } 2495 catch (\phpbb\groupposition\exception $exception) 2496 { 2497 trigger_error($user->lang($exception->getMessage())); 2498 } 2499 } 2500 2501 if (!$group_id) 2502 { 2503 $group_id = $db->sql_nextid(); 2504 2505 if (isset($sql_ary['group_avatar_type']) && $sql_ary['group_avatar_type'] == 'avatar.driver.upload') 2506 { 2507 group_correct_avatar($group_id, $sql_ary['group_avatar']); 2508 } 2509 } 2510 2511 try 2512 { 2513 if ($group_teampage && $current_teampage == \phpbb\groupposition\teampage::GROUP_DISABLED) 2514 { 2515 $teampage->add_group($group_id); 2516 } 2517 2518 if ($group_teampage) 2519 { 2520 if ($current_teampage == \phpbb\groupposition\teampage::GROUP_DISABLED) 2521 { 2522 $teampage->add_group($group_id); 2523 } 2524 } 2525 else if ($group_id && ($current_teampage != \phpbb\groupposition\teampage::GROUP_DISABLED)) 2526 { 2527 $teampage->delete_group($group_id); 2528 } 2529 } 2530 catch (\phpbb\groupposition\exception $exception) 2531 { 2532 trigger_error($user->lang($exception->getMessage())); 2533 } 2534 unset($teampage); 2535 2536 // Set user attributes 2537 $sql_ary = array(); 2538 if (sizeof($group_attributes)) 2539 { 2540 // Go through the user attributes array, check if a group attribute matches it and then set it. ;) 2541 foreach ($user_attribute_ary as $attribute) 2542 { 2543 if (!isset($group_attributes[$attribute])) 2544 { 2545 continue; 2546 } 2547 2548 // If we are about to set an avatar, we will not overwrite user avatars if no group avatar is set... 2549 if (strpos($attribute, 'group_avatar') === 0 && !$group_attributes[$attribute]) 2550 { 2551 continue; 2552 } 2553 2554 $sql_ary[$attribute] = $group_attributes[$attribute]; 2555 } 2556 } 2557 2558 if (sizeof($sql_ary) && sizeof($user_ary)) 2559 { 2560 group_set_user_default($group_id, $user_ary, $sql_ary); 2561 } 2562 2563 $name = ($type == GROUP_SPECIAL) ? $user->lang['G_' . $name] : $name; 2564 add_log('admin', $log, $name); 2565 2566 group_update_listings($group_id); 2567 } 2568 2569 return (sizeof($error)) ? $error : false; 2570 } 2571 2572 2573 /** 2574 * Changes a group avatar's filename to conform to the naming scheme 2575 */ 2576 function group_correct_avatar($group_id, $old_entry) 2577 { 2578 global $config, $db, $phpbb_root_path; 2579 2580 $group_id = (int) $group_id; 2581 $ext = substr(strrchr($old_entry, '.'), 1); 2582 $old_filename = get_avatar_filename($old_entry); 2583 $new_filename = $config['avatar_salt'] . "_g$group_id.$ext"; 2584 $new_entry = 'g' . $group_id . '_' . substr(time(), -5) . ".$ext"; 2585 2586 $avatar_path = $phpbb_root_path . $config['avatar_path']; 2587 if (@rename($avatar_path . '/'. $old_filename, $avatar_path . '/' . $new_filename)) 2588 { 2589 $sql = 'UPDATE ' . GROUPS_TABLE . ' 2590 SET group_avatar = \'' . $db->sql_escape($new_entry) . "' 2591 WHERE group_id = $group_id"; 2592 $db->sql_query($sql); 2593 } 2594 } 2595 2596 2597 /** 2598 * Remove avatar also for users not having the group as default 2599 */ 2600 function avatar_remove_db($avatar_name) 2601 { 2602 global $config, $db; 2603 2604 $sql = 'UPDATE ' . USERS_TABLE . " 2605 SET user_avatar = '', 2606 user_avatar_type = '' 2607 WHERE user_avatar = '" . $db->sql_escape($avatar_name) . '\''; 2608 $db->sql_query($sql); 2609 } 2610 2611 2612 /** 2613 * Group Delete 2614 */ 2615 function group_delete($group_id, $group_name = false) 2616 { 2617 global $db, $cache, $auth, $user, $phpbb_root_path, $phpEx, $phpbb_dispatcher, $phpbb_container; 2618 2619 if (!$group_name) 2620 { 2621 $group_name = get_group_name($group_id); 2622 } 2623 2624 $start = 0; 2625 2626 do 2627 { 2628 $user_id_ary = $username_ary = array(); 2629 2630 // Batch query for group members, call group_user_del 2631 $sql = 'SELECT u.user_id, u.username 2632 FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . " u 2633 WHERE ug.group_id = $group_id 2634 AND u.user_id = ug.user_id"; 2635 $result = $db->sql_query_limit($sql, 200, $start); 2636 2637 if ($row = $db->sql_fetchrow($result)) 2638 { 2639 do 2640 { 2641 $user_id_ary[] = $row['user_id']; 2642 $username_ary[] = $row['username']; 2643 2644 $start++; 2645 } 2646 while ($row = $db->sql_fetchrow($result)); 2647 2648 group_user_del($group_id, $user_id_ary, $username_ary, $group_name); 2649 } 2650 else 2651 { 2652 $start = 0; 2653 } 2654 $db->sql_freeresult($result); 2655 } 2656 while ($start); 2657 2658 // Delete group from legend and teampage 2659 try 2660 { 2661 $legend = $phpbb_container->get('groupposition.legend'); 2662 $legend->delete_group($group_id); 2663 unset($legend); 2664 } 2665 catch (\phpbb\groupposition\exception $exception) 2666 { 2667 // The group we want to delete does not exist. 2668 // No reason to worry, we just continue the deleting process. 2669 //trigger_error($user->lang($exception->getMessage())); 2670 } 2671 2672 try 2673 { 2674 $teampage = $phpbb_container->get('groupposition.teampage'); 2675 $teampage->delete_group($group_id); 2676 unset($teampage); 2677 } 2678 catch (\phpbb\groupposition\exception $exception) 2679 { 2680 // The group we want to delete does not exist. 2681 // No reason to worry, we just continue the deleting process. 2682 //trigger_error($user->lang($exception->getMessage())); 2683 } 2684 2685 // Delete group 2686 $sql = 'DELETE FROM ' . GROUPS_TABLE . " 2687 WHERE group_id = $group_id"; 2688 $db->sql_query($sql); 2689 2690 // Delete auth entries from the groups table 2691 $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . " 2692 WHERE group_id = $group_id"; 2693 $db->sql_query($sql); 2694 2695 /** 2696 * Event after a group is deleted 2697 * 2698 * @event core.delete_group_after 2699 * @var int group_id ID of the deleted group 2700 * @var string group_name Name of the deleted group 2701 * @since 3.1.0-a1 2702 */ 2703 $vars = array('group_id', 'group_name'); 2704 extract($phpbb_dispatcher->trigger_event('core.delete_group_after', compact($vars))); 2705 2706 // Re-cache moderators 2707 if (!function_exists('phpbb_cache_moderators')) 2708 { 2709 include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); 2710 } 2711 2712 phpbb_cache_moderators($db, $cache, $auth); 2713 2714 add_log('admin', 'LOG_GROUP_DELETE', $group_name); 2715 2716 // Return false - no error 2717 return false; 2718 } 2719 2720 /** 2721 * Add user(s) to group 2722 * 2723 * @return mixed false if no errors occurred, else the user lang string for the relevant error, for example 'NO_USER' 2724 */ 2725 function group_user_add($group_id, $user_id_ary = false, $username_ary = false, $group_name = false, $default = false, $leader = 0, $pending = 0, $group_attributes = false) 2726 { 2727 global $db, $auth, $phpbb_container, $phpbb_dispatcher; 2728 2729 // We need both username and user_id info 2730 $result = user_get_id_name($user_id_ary, $username_ary); 2731 2732 if (!sizeof($user_id_ary) || $result !== false) 2733 { 2734 return 'NO_USER'; 2735 } 2736 2737 // Remove users who are already members of this group 2738 $sql = 'SELECT user_id, group_leader 2739 FROM ' . USER_GROUP_TABLE . ' 2740 WHERE ' . $db->sql_in_set('user_id', $user_id_ary) . " 2741 AND group_id = $group_id"; 2742 $result = $db->sql_query($sql); 2743 2744 $add_id_ary = $update_id_ary = array(); 2745 while ($row = $db->sql_fetchrow($result)) 2746 { 2747 $add_id_ary[] = (int) $row['user_id']; 2748 2749 if ($leader && !$row['group_leader']) 2750 { 2751 $update_id_ary[] = (int) $row['user_id']; 2752 } 2753 } 2754 $db->sql_freeresult($result); 2755 2756 // Do all the users exist in this group? 2757 $add_id_ary = array_diff($user_id_ary, $add_id_ary); 2758 2759 // If we have no users 2760 if (!sizeof($add_id_ary) && !sizeof($update_id_ary)) 2761 { 2762 return 'GROUP_USERS_EXIST'; 2763 } 2764 2765 $db->sql_transaction('begin'); 2766 2767 // Insert the new users 2768 if (sizeof($add_id_ary)) 2769 { 2770 $sql_ary = array(); 2771 2772 foreach ($add_id_ary as $user_id) 2773 { 2774 $sql_ary[] = array( 2775 'user_id' => (int) $user_id, 2776 'group_id' => (int) $group_id, 2777 'group_leader' => (int) $leader, 2778 'user_pending' => (int) $pending, 2779 ); 2780 } 2781 2782 $db->sql_multi_insert(USER_GROUP_TABLE, $sql_ary); 2783 } 2784 2785 if (sizeof($update_id_ary)) 2786 { 2787 $sql = 'UPDATE ' . USER_GROUP_TABLE . ' 2788 SET group_leader = 1 2789 WHERE ' . $db->sql_in_set('user_id', $update_id_ary) . " 2790 AND group_id = $group_id"; 2791 $db->sql_query($sql); 2792 } 2793 2794 if ($default) 2795 { 2796 group_user_attributes('default', $group_id, $user_id_ary, false, $group_name, $group_attributes); 2797 } 2798 2799 $db->sql_transaction('commit'); 2800 2801 // Clear permissions cache of relevant users 2802 $auth->acl_clear_prefetch($user_id_ary); 2803 2804 /** 2805 * Event after users are added to a group 2806 * 2807 * @event core.group_add_user_after 2808 * @var int group_id ID of the group to which users are added 2809 * @var string group_name Name of the group 2810 * @var array user_id_ary IDs of the users which are added 2811 * @var array username_ary names of the users which are added 2812 * @var int pending Pending setting, 1 if user(s) added are pending 2813 * @since 3.1.7-RC1 2814 */ 2815 $vars = array( 2816 'group_id', 2817 'group_name', 2818 'user_id_ary', 2819 'username_ary', 2820 'pending', 2821 ); 2822 extract($phpbb_dispatcher->trigger_event('core.group_add_user_after', compact($vars))); 2823 2824 if (!$group_name) 2825 { 2826 $group_name = get_group_name($group_id); 2827 } 2828 2829 $log = ($leader) ? 'LOG_MODS_ADDED' : (($pending) ? 'LOG_USERS_PENDING' : 'LOG_USERS_ADDED'); 2830 2831 add_log('admin', $log, $group_name, implode(', ', $username_ary)); 2832 2833 group_update_listings($group_id); 2834 2835 if ($pending) 2836 { 2837 $phpbb_notifications = $phpbb_container->get('notification_manager'); 2838 2839 foreach ($add_id_ary as $user_id) 2840 { 2841 $phpbb_notifications->add_notifications('notification.type.group_request', array( 2842 'group_id' => $group_id, 2843 'user_id' => $user_id, 2844 'group_name' => $group_name, 2845 )); 2846 } 2847 } 2848 2849 // Return false - no error 2850 return false; 2851 } 2852 2853 /** 2854 * Remove a user/s from a given group. When we remove users we update their 2855 * default group_id. We do this by examining which "special" groups they belong 2856 * to. The selection is made based on a reasonable priority system 2857 * 2858 * @return false if no errors occurred, else the user lang string for the relevant error, for example 'NO_USER' 2859 */ 2860 function group_user_del($group_id, $user_id_ary = false, $username_ary = false, $group_name = false, $log_action = true) 2861 { 2862 global $db, $auth, $config, $phpbb_dispatcher, $phpbb_container; 2863 2864 if ($config['coppa_enable']) 2865 { 2866 $group_order = array('ADMINISTRATORS', 'GLOBAL_MODERATORS', 'NEWLY_REGISTERED', 'REGISTERED_COPPA', 'REGISTERED', 'BOTS', 'GUESTS'); 2867 } 2868 else 2869 { 2870 $group_order = array('ADMINISTRATORS', 'GLOBAL_MODERATORS', 'NEWLY_REGISTERED', 'REGISTERED', 'BOTS', 'GUESTS'); 2871 } 2872 2873 // We need both username and user_id info 2874 $result = user_get_id_name($user_id_ary, $username_ary); 2875 2876 if (!sizeof($user_id_ary) || $result !== false) 2877 { 2878 return 'NO_USER'; 2879 } 2880 2881 $sql = 'SELECT * 2882 FROM ' . GROUPS_TABLE . ' 2883 WHERE ' . $db->sql_in_set('group_name', $group_order); 2884 $result = $db->sql_query($sql); 2885 2886 $group_order_id = $special_group_data = array(); 2887 while ($row = $db->sql_fetchrow($result)) 2888 { 2889 $group_order_id[$row['group_name']] = $row['group_id']; 2890 2891 $special_group_data[$row['group_id']] = array( 2892 'group_colour' => $row['group_colour'], 2893 'group_rank' => $row['group_rank'], 2894 ); 2895 2896 // Only set the group avatar if one is defined... 2897 if ($row['group_avatar']) 2898 { 2899 $special_group_data[$row['group_id']] = array_merge($special_group_data[$row['group_id']], array( 2900 'group_avatar' => $row['group_avatar'], 2901 'group_avatar_type' => $row['group_avatar_type'], 2902 'group_avatar_width' => $row['group_avatar_width'], 2903 'group_avatar_height' => $row['group_avatar_height']) 2904 ); 2905 } 2906 } 2907 $db->sql_freeresult($result); 2908 2909 // Get users default groups - we only need to reset default group membership if the group from which the user gets removed is set as default 2910 $sql = 'SELECT user_id, group_id 2911 FROM ' . USERS_TABLE . ' 2912 WHERE ' . $db->sql_in_set('user_id', $user_id_ary); 2913 $result = $db->sql_query($sql); 2914 2915 $default_groups = array(); 2916 while ($row = $db->sql_fetchrow($result)) 2917 { 2918 $default_groups[$row['user_id']] = $row['group_id']; 2919 } 2920 $db->sql_freeresult($result); 2921 2922 // What special group memberships exist for these users? 2923 $sql = 'SELECT g.group_id, g.group_name, ug.user_id 2924 FROM ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g 2925 WHERE ' . $db->sql_in_set('ug.user_id', $user_id_ary) . " 2926 AND g.group_id = ug.group_id 2927 AND g.group_id <> $group_id 2928 AND g.group_type = " . GROUP_SPECIAL . ' 2929 ORDER BY ug.user_id, g.group_id'; 2930 $result = $db->sql_query($sql); 2931 2932 $temp_ary = array(); 2933 while ($row = $db->sql_fetchrow($result)) 2934 { 2935 if ($default_groups[$row['user_id']] == $group_id && (!isset($temp_ary[$row['user_id']]) || $group_order_id[$row['group_name']] < $temp_ary[$row['user_id']])) 2936 { 2937 $temp_ary[$row['user_id']] = $row['group_id']; 2938 } 2939 } 2940 $db->sql_freeresult($result); 2941 2942 // sql_where_ary holds the new default groups and their users 2943 $sql_where_ary = array(); 2944 foreach ($temp_ary as $uid => $gid) 2945 { 2946 $sql_where_ary[$gid][] = $uid; 2947 } 2948 unset($temp_ary); 2949 2950 foreach ($special_group_data as $gid => $default_data_ary) 2951 { 2952 if (isset($sql_where_ary[$gid]) && sizeof($sql_where_ary[$gid])) 2953 { 2954 remove_default_rank($group_id, $sql_where_ary[$gid]); 2955 remove_default_avatar($group_id, $sql_where_ary[$gid]); 2956 group_set_user_default($gid, $sql_where_ary[$gid], $default_data_ary); 2957 } 2958 } 2959 unset($special_group_data); 2960 2961 /** 2962 * Event before users are removed from a group 2963 * 2964 * @event core.group_delete_user_before 2965 * @var int group_id ID of the group from which users are deleted 2966 * @var string group_name Name of the group 2967 * @var array user_id_ary IDs of the users which are removed 2968 * @var array username_ary names of the users which are removed 2969 * @since 3.1.0-a1 2970 */ 2971 $vars = array('group_id', 'group_name', 'user_id_ary', 'username_ary'); 2972 extract($phpbb_dispatcher->trigger_event('core.group_delete_user_before', compact($vars))); 2973 2974 $sql = 'DELETE FROM ' . USER_GROUP_TABLE . " 2975 WHERE group_id = $group_id 2976 AND " . $db->sql_in_set('user_id', $user_id_ary); 2977 $db->sql_query($sql); 2978 2979 // Clear permissions cache of relevant users 2980 $auth->acl_clear_prefetch($user_id_ary); 2981 2982 /** 2983 * Event after users are removed from a group 2984 * 2985 * @event core.group_delete_user_after 2986 * @var int group_id ID of the group from which users are deleted 2987 * @var string group_name Name of the group 2988 * @var array user_id_ary IDs of the users which are removed 2989 * @var array username_ary names of the users which are removed 2990 * @since 3.1.7-RC1 2991 */ 2992 $vars = array('group_id', 'group_name', 'user_id_ary', 'username_ary'); 2993 extract($phpbb_dispatcher->trigger_event('core.group_delete_user_after', compact($vars))); 2994 2995 if ($log_action) 2996 { 2997 if (!$group_name) 2998 { 2999 $group_name = get_group_name($group_id); 3000 } 3001 3002 $log = 'LOG_GROUP_REMOVE'; 3003 3004 if ($group_name) 3005 { 3006 add_log('admin', $log, $group_name, implode(', ', $username_ary)); 3007 } 3008 } 3009 3010 group_update_listings($group_id); 3011 3012 $phpbb_notifications = $phpbb_container->get('notification_manager'); 3013 3014 $phpbb_notifications->delete_notifications('notification.type.group_request', $user_id_ary, $group_id); 3015 3016 // Return false - no error 3017 return false; 3018 } 3019 3020 3021 /** 3022 * Removes the group avatar of the default group from the users in user_ids who have that group as default. 3023 */ 3024 function remove_default_avatar($group_id, $user_ids) 3025 { 3026 global $db; 3027 3028 if (!is_array($user_ids)) 3029 { 3030 $user_ids = array($user_ids); 3031 } 3032 if (empty($user_ids)) 3033 { 3034 return false; 3035 } 3036 3037 $user_ids = array_map('intval', $user_ids); 3038 3039 $sql = 'SELECT * 3040 FROM ' . GROUPS_TABLE . ' 3041 WHERE group_id = ' . (int) $group_id; 3042 $result = $db->sql_query($sql); 3043 if (!$row = $db->sql_fetchrow($result)) 3044 { 3045 $db->sql_freeresult($result); 3046 return false; 3047 } 3048 $db->sql_freeresult($result); 3049 3050 $sql = 'UPDATE ' . USERS_TABLE . " 3051 SET user_avatar = '', 3052 user_avatar_type = '', 3053 user_avatar_width = 0, 3054 user_avatar_height = 0 3055 WHERE group_id = " . (int) $group_id . " 3056 AND user_avatar = '" . $db->sql_escape($row['group_avatar']) . "' 3057 AND " . $db->sql_in_set('user_id', $user_ids); 3058 3059 $db->sql_query($sql); 3060 } 3061 3062 /** 3063 * Removes the group rank of the default group from the users in user_ids who have that group as default. 3064 */ 3065 function remove_default_rank($group_id, $user_ids) 3066 { 3067 global $db; 3068 3069 if (!is_array($user_ids)) 3070 { 3071 $user_ids = array($user_ids); 3072 } 3073 if (empty($user_ids)) 3074 { 3075 return false; 3076 } 3077 3078 $user_ids = array_map('intval', $user_ids); 3079 3080 $sql = 'SELECT * 3081 FROM ' . GROUPS_TABLE . ' 3082 WHERE group_id = ' . (int) $group_id; 3083 $result = $db->sql_query($sql); 3084 if (!$row = $db->sql_fetchrow($result)) 3085 { 3086 $db->sql_freeresult($result); 3087 return false; 3088 } 3089 $db->sql_freeresult($result); 3090 3091 $sql = 'UPDATE ' . USERS_TABLE . ' 3092 SET user_rank = 0 3093 WHERE group_id = ' . (int) $group_id . ' 3094 AND user_rank <> 0 3095 AND user_rank = ' . (int) $row['group_rank'] . ' 3096 AND ' . $db->sql_in_set('user_id', $user_ids); 3097 $db->sql_query($sql); 3098 } 3099 3100 /** 3101 * This is used to promote (to leader), demote or set as default a member/s 3102 */ 3103 function group_user_attributes($action, $group_id, $user_id_ary = false, $username_ary = false, $group_name = false, $group_attributes = false) 3104 { 3105 global $db, $auth, $phpbb_root_path, $phpEx, $config, $phpbb_container, $phpbb_dispatcher; 3106 3107 // We need both username and user_id info 3108 $result = user_get_id_name($user_id_ary, $username_ary); 3109 3110 if (!sizeof($user_id_ary) || $result !== false) 3111 { 3112 return 'NO_USERS'; 3113 } 3114 3115 if (!$group_name) 3116 { 3117 $group_name = get_group_name($group_id); 3118 } 3119 3120 switch ($action) 3121 { 3122 case 'demote': 3123 case 'promote': 3124 3125 $sql = 'SELECT user_id 3126 FROM ' . USER_GROUP_TABLE . " 3127 WHERE group_id = $group_id 3128 AND user_pending = 1 3129 AND " . $db->sql_in_set('user_id', $user_id_ary); 3130 $result = $db->sql_query_limit($sql, 1); 3131 $not_empty = ($db->sql_fetchrow($result)); 3132 $db->sql_freeresult($result); 3133 if ($not_empty) 3134 { 3135 return 'NO_VALID_USERS'; 3136 } 3137 3138 $sql = 'UPDATE ' . USER_GROUP_TABLE . ' 3139 SET group_leader = ' . (($action == 'promote') ? 1 : 0) . " 3140 WHERE group_id = $group_id 3141 AND user_pending = 0 3142 AND " . $db->sql_in_set('user_id', $user_id_ary); 3143 $db->sql_query($sql); 3144 3145 $log = ($action == 'promote') ? 'LOG_GROUP_PROMOTED' : 'LOG_GROUP_DEMOTED'; 3146 break; 3147 3148 case 'approve': 3149 // Make sure we only approve those which are pending ;) 3150 $sql = 'SELECT u.user_id, u.user_email, u.username, u.username_clean, u.user_notify_type, u.user_jabber, u.user_lang 3151 FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . ' ug 3152 WHERE ug.group_id = ' . $group_id . ' 3153 AND ug.user_pending = 1 3154 AND ug.user_id = u.user_id 3155 AND ' . $db->sql_in_set('ug.user_id', $user_id_ary); 3156 $result = $db->sql_query($sql); 3157 3158 $user_id_ary = array(); 3159 while ($row = $db->sql_fetchrow($result)) 3160 { 3161 $user_id_ary[] = $row['user_id']; 3162 } 3163 $db->sql_freeresult($result); 3164 3165 if (!sizeof($user_id_ary)) 3166 { 3167 return false; 3168 } 3169 3170 $sql = 'UPDATE ' . USER_GROUP_TABLE . " 3171 SET user_pending = 0 3172 WHERE group_id = $group_id 3173 AND " . $db->sql_in_set('user_id', $user_id_ary); 3174 $db->sql_query($sql); 3175 3176 $phpbb_notifications = $phpbb_container->get('notification_manager'); 3177 3178 $phpbb_notifications->add_notifications('notification.type.group_request_approved', array( 3179 'user_ids' => $user_id_ary, 3180 'group_id' => $group_id, 3181 'group_name' => $group_name, 3182 )); 3183 $phpbb_notifications->delete_notifications('notification.type.group_request', $user_id_ary, $group_id); 3184 3185 $log = 'LOG_USERS_APPROVED'; 3186 break; 3187 3188 case 'default': 3189 // We only set default group for approved members of the group 3190 $sql = 'SELECT user_id 3191 FROM ' . USER_GROUP_TABLE . " 3192 WHERE group_id = $group_id 3193 AND user_pending = 0 3194 AND " . $db->sql_in_set('user_id', $user_id_ary); 3195 $result = $db->sql_query($sql); 3196 3197 $user_id_ary = $username_ary = array(); 3198 while ($row = $db->sql_fetchrow($result)) 3199 { 3200 $user_id_ary[] = $row['user_id']; 3201 } 3202 $db->sql_freeresult($result); 3203 3204 $result = user_get_id_name($user_id_ary, $username_ary); 3205 if (!sizeof($user_id_ary) || $result !== false) 3206 { 3207 return 'NO_USERS'; 3208 } 3209 3210 $sql = 'SELECT user_id, group_id 3211 FROM ' . USERS_TABLE . ' 3212 WHERE ' . $db->sql_in_set('user_id', $user_id_ary, false, true); 3213 $result = $db->sql_query($sql); 3214 3215 $groups = array(); 3216 while ($row = $db->sql_fetchrow($result)) 3217 { 3218 if (!isset($groups[$row['group_id']])) 3219 { 3220 $groups[$row['group_id']] = array(); 3221 } 3222 $groups[$row['group_id']][] = $row['user_id']; 3223 } 3224 $db->sql_freeresult($result); 3225 3226 foreach ($groups as $gid => $uids) 3227 { 3228 remove_default_rank($gid, $uids); 3229 remove_default_avatar($gid, $uids); 3230 } 3231 group_set_user_default($group_id, $user_id_ary, $group_attributes); 3232 $log = 'LOG_GROUP_DEFAULTS'; 3233 break; 3234 } 3235 3236 /** 3237 * Event to perform additional actions on setting user group attributes 3238 * 3239 * @event core.user_set_group_attributes 3240 * @var int group_id ID of the group 3241 * @var string group_name Name of the group 3242 * @var array user_id_ary IDs of the users to set group attributes 3243 * @var array username_ary Names of the users to set group attributes 3244 * @var array group_attributes Group attributes which were changed 3245 * @var string action Action to perform over the group members 3246 * @since 3.1.10-RC1 3247 */ 3248 $vars = array( 3249 'group_id', 3250 'group_name', 3251 'user_id_ary', 3252 'username_ary', 3253 'group_attributes', 3254 'action', 3255 ); 3256 extract($phpbb_dispatcher->trigger_event('core.user_set_group_attributes', compact($vars))); 3257 3258 // Clear permissions cache of relevant users 3259 $auth->acl_clear_prefetch($user_id_ary); 3260 3261 add_log('admin', $log, $group_name, implode(', ', $username_ary)); 3262 3263 group_update_listings($group_id); 3264 3265 return false; 3266 } 3267 3268 /** 3269 * A small version of validate_username to check for a group name's existence. To be called directly. 3270 */ 3271 function group_validate_groupname($group_id, $group_name) 3272 { 3273 global $config, $db; 3274 3275 $group_name = utf8_clean_string($group_name); 3276 3277 if (!empty($group_id)) 3278 { 3279 $sql = 'SELECT group_name 3280 FROM ' . GROUPS_TABLE . ' 3281 WHERE group_id = ' . (int) $group_id; 3282 $result = $db->sql_query($sql); 3283 $row = $db->sql_fetchrow($result); 3284 $db->sql_freeresult($result); 3285 3286 if (!$row) 3287 { 3288 return false; 3289 } 3290 3291 $allowed_groupname = utf8_clean_string($row['group_name']); 3292 3293 if ($allowed_groupname == $group_name) 3294 { 3295 return false; 3296 } 3297 } 3298 3299 $sql = 'SELECT group_name 3300 FROM ' . GROUPS_TABLE . " 3301 WHERE LOWER(group_name) = '" . $db->sql_escape(utf8_strtolower($group_name)) . "'"; 3302 $result = $db->sql_query($sql); 3303 $row = $db->sql_fetchrow($result); 3304 $db->sql_freeresult($result); 3305 3306 if ($row) 3307 { 3308 return 'GROUP_NAME_TAKEN'; 3309 } 3310 3311 return false; 3312 } 3313 3314 /** 3315 * Set users default group 3316 * 3317 * @access private 3318 */ 3319 function group_set_user_default($group_id, $user_id_ary, $group_attributes = false, $update_listing = false) 3320 { 3321 global $phpbb_container, $db, $phpbb_dispatcher; 3322 3323 if (empty($user_id_ary)) 3324 { 3325 return; 3326 } 3327 3328 $attribute_ary = array( 3329 'group_colour' => 'string', 3330 'group_rank' => 'int', 3331 'group_avatar' => 'string', 3332 'group_avatar_type' => 'string', 3333 'group_avatar_width' => 'int', 3334 'group_avatar_height' => 'int', 3335 ); 3336 3337 $sql_ary = array( 3338 'group_id' => $group_id 3339 ); 3340 3341 // Were group attributes passed to the function? If not we need to obtain them 3342 if ($group_attributes === false) 3343 { 3344 $sql = 'SELECT ' . implode(', ', array_keys($attribute_ary)) . ' 3345 FROM ' . GROUPS_TABLE . " 3346 WHERE group_id = $group_id"; 3347 $result = $db->sql_query($sql); 3348 $group_attributes = $db->sql_fetchrow($result); 3349 $db->sql_freeresult($result); 3350 } 3351 3352 foreach ($attribute_ary as $attribute => $type) 3353 { 3354 if (isset($group_attributes[$attribute])) 3355 { 3356 // If we are about to set an avatar or rank, we will not overwrite with empty, unless we are not actually changing the default group 3357 if ((strpos($attribute, 'group_avatar') === 0 || strpos($attribute, 'group_rank') === 0) && !$group_attributes[$attribute]) 3358 { 3359 continue; 3360 } 3361 3362 settype($group_attributes[$attribute], $type); 3363 $sql_ary[str_replace('group_', 'user_', $attribute)] = $group_attributes[$attribute]; 3364 } 3365 } 3366 3367 $updated_sql_ary = $sql_ary; 3368 3369 // Before we update the user attributes, we will update the rank for users that don't have a custom rank 3370 if (isset($sql_ary['user_rank'])) 3371 { 3372 $sql = 'UPDATE ' . USERS_TABLE . ' 3373 SET ' . $db->sql_build_array('UPDATE', array('user_rank' => $sql_ary['user_rank'])) . ' 3374 WHERE user_rank = 0 3375 AND ' . $db->sql_in_set('user_id', $user_id_ary); 3376 $db->sql_query($sql); 3377 unset($sql_ary['user_rank']); 3378 } 3379 3380 // Before we update the user attributes, we will update the avatar for users that don't have a custom avatar 3381 $avatar_options = array('user_avatar', 'user_avatar_type', 'user_avatar_height', 'user_avatar_width'); 3382 3383 if (isset($sql_ary['user_avatar'])) 3384 { 3385 $avatar_sql_ary = array(); 3386 foreach ($avatar_options as $avatar_option) 3387 { 3388 if (isset($sql_ary[$avatar_option])) 3389 { 3390 $avatar_sql_ary[$avatar_option] = $sql_ary[$avatar_option]; 3391 } 3392 } 3393 3394 $sql = 'UPDATE ' . USERS_TABLE . ' 3395 SET ' . $db->sql_build_array('UPDATE', $avatar_sql_ary) . " 3396 WHERE user_avatar = '' 3397 AND " . $db->sql_in_set('user_id', $user_id_ary); 3398 $db->sql_query($sql); 3399 } 3400 3401 // Remove the avatar options, as we already updated them 3402 foreach ($avatar_options as $avatar_option) 3403 { 3404 unset($sql_ary[$avatar_option]); 3405 } 3406 3407 if (!empty($sql_ary)) 3408 { 3409 $sql = 'UPDATE ' . USERS_TABLE . ' 3410 SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' 3411 WHERE ' . $db->sql_in_set('user_id', $user_id_ary); 3412 $db->sql_query($sql); 3413 } 3414 3415 if (isset($sql_ary['user_colour'])) 3416 { 3417 // Update any cached colour information for these users 3418 $sql = 'UPDATE ' . FORUMS_TABLE . " 3419 SET forum_last_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "' 3420 WHERE " . $db->sql_in_set('forum_last_poster_id', $user_id_ary); 3421 $db->sql_query($sql); 3422 3423 $sql = 'UPDATE ' . TOPICS_TABLE . " 3424 SET topic_first_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "' 3425 WHERE " . $db->sql_in_set('topic_poster', $user_id_ary); 3426 $db->sql_query($sql); 3427 3428 $sql = 'UPDATE ' . TOPICS_TABLE . " 3429 SET topic_last_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "' 3430 WHERE " . $db->sql_in_set('topic_last_poster_id', $user_id_ary); 3431 $db->sql_query($sql); 3432 3433 global $config; 3434 3435 if (in_array($config['newest_user_id'], $user_id_ary)) 3436 { 3437 set_config('newest_user_colour', $sql_ary['user_colour'], true); 3438 } 3439 } 3440 3441 // Make all values available for the event 3442 $sql_ary = $updated_sql_ary; 3443 3444 /** 3445 * Event when the default group is set for an array of users 3446 * 3447 * @event core.user_set_default_group 3448 * @var int group_id ID of the group 3449 * @var array user_id_ary IDs of the users 3450 * @var array group_attributes Group attributes which were changed 3451 * @var array update_listing Update the list of moderators and foes 3452 * @var array sql_ary User attributes which were changed 3453 * @since 3.1.0-a1 3454 */ 3455 $vars = array('group_id', 'user_id_ary', 'group_attributes', 'update_listing', 'sql_ary'); 3456 extract($phpbb_dispatcher->trigger_event('core.user_set_default_group', compact($vars))); 3457 3458 if ($update_listing) 3459 { 3460 group_update_listings($group_id); 3461 } 3462 3463 // Because some tables/caches use usercolour-specific data we need to purge this here. 3464 $phpbb_container->get('cache.driver')->destroy('sql', MODERATOR_CACHE_TABLE); 3465 } 3466 3467 /** 3468 * Get group name 3469 */ 3470 function get_group_name($group_id) 3471 { 3472 global $db, $user; 3473 3474 $sql = 'SELECT group_name, group_type 3475 FROM ' . GROUPS_TABLE . ' 3476 WHERE group_id = ' . (int) $group_id; 3477 $result = $db->sql_query($sql); 3478 $row = $db->sql_fetchrow($result); 3479 $db->sql_freeresult($result); 3480 3481 if (!$row || ($row['group_type'] == GROUP_SPECIAL && empty($user->lang))) 3482 { 3483 return ''; 3484 } 3485 3486 return ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']; 3487 } 3488 3489 /** 3490 * Obtain either the members of a specified group, the groups the specified user is subscribed to 3491 * or checking if a specified user is in a specified group. This function does not return pending memberships. 3492 * 3493 * Note: Never use this more than once... first group your users/groups 3494 */ 3495 function group_memberships($group_id_ary = false, $user_id_ary = false, $return_bool = false) 3496 { 3497 global $db; 3498 3499 if (!$group_id_ary && !$user_id_ary) 3500 { 3501 return true; 3502 } 3503 3504 if ($user_id_ary) 3505 { 3506 $user_id_ary = (!is_array($user_id_ary)) ? array($user_id_ary) : $user_id_ary; 3507 } 3508 3509 if ($group_id_ary) 3510 { 3511 $group_id_ary = (!is_array($group_id_ary)) ? array($group_id_ary) : $group_id_ary; 3512 } 3513 3514 $sql = 'SELECT ug.*, u.username, u.username_clean, u.user_email 3515 FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . ' u 3516 WHERE ug.user_id = u.user_id 3517 AND ug.user_pending = 0 AND '; 3518 3519 if ($group_id_ary) 3520 { 3521 $sql .= ' ' . $db->sql_in_set('ug.group_id', $group_id_ary); 3522 } 3523 3524 if ($user_id_ary) 3525 { 3526 $sql .= ($group_id_ary) ? ' AND ' : ' '; 3527 $sql .= $db->sql_in_set('ug.user_id', $user_id_ary); 3528 } 3529 3530 $result = ($return_bool) ? $db->sql_query_limit($sql, 1) : $db->sql_query($sql); 3531 3532 $row = $db->sql_fetchrow($result); 3533 3534 if ($return_bool) 3535 { 3536 $db->sql_freeresult($result); 3537 return ($row) ? true : false; 3538 } 3539 3540 if (!$row) 3541 { 3542 return false; 3543 } 3544 3545 $return = array(); 3546 3547 do 3548 { 3549 $return[] = $row; 3550 } 3551 while ($row = $db->sql_fetchrow($result)); 3552 3553 $db->sql_freeresult($result); 3554 3555 return $return; 3556 } 3557 3558 /** 3559 * Re-cache moderators and foes if group has a_ or m_ permissions 3560 */ 3561 function group_update_listings($group_id) 3562 { 3563 global $db, $cache, $auth; 3564 3565 $hold_ary = $auth->acl_group_raw_data($group_id, array('a_', 'm_')); 3566 3567 if (!sizeof($hold_ary)) 3568 { 3569 return; 3570 } 3571 3572 $mod_permissions = $admin_permissions = false; 3573 3574 foreach ($hold_ary as $g_id => $forum_ary) 3575 { 3576 foreach ($forum_ary as $forum_id => $auth_ary) 3577 { 3578 foreach ($auth_ary as $auth_option => $setting) 3579 { 3580 if ($mod_permissions && $admin_permissions) 3581 { 3582 break 3; 3583 } 3584 3585 if ($setting != ACL_YES) 3586 { 3587 continue; 3588 } 3589 3590 if ($auth_option == 'm_') 3591 { 3592 $mod_permissions = true; 3593 } 3594 3595 if ($auth_option == 'a_') 3596 { 3597 $admin_permissions = true; 3598 } 3599 } 3600 } 3601 } 3602 3603 if ($mod_permissions) 3604 { 3605 if (!function_exists('phpbb_cache_moderators')) 3606 { 3607 global $phpbb_root_path, $phpEx; 3608 include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); 3609 } 3610 phpbb_cache_moderators($db, $cache, $auth); 3611 } 3612 3613 if ($mod_permissions || $admin_permissions) 3614 { 3615 if (!function_exists('phpbb_update_foes')) 3616 { 3617 global $phpbb_root_path, $phpEx; 3618 include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); 3619 } 3620 phpbb_update_foes($db, $auth, array($group_id)); 3621 } 3622 } 3623 3624 3625 3626 /** 3627 * Funtion to make a user leave the NEWLY_REGISTERED system group. 3628 * @access public 3629 * @param $user_id The id of the user to remove from the group 3630 */ 3631 function remove_newly_registered($user_id, $user_data = false) 3632 { 3633 global $db; 3634 3635 if ($user_data === false) 3636 { 3637 $sql = 'SELECT * 3638 FROM ' . USERS_TABLE . ' 3639 WHERE user_id = ' . $user_id; 3640 $result = $db->sql_query($sql); 3641 $user_row = $db->sql_fetchrow($result); 3642 $db->sql_freeresult($result); 3643 3644 if (!$user_row) 3645 { 3646 return false; 3647 } 3648 else 3649 { 3650 $user_data = $user_row; 3651 } 3652 } 3653 3654 if (empty($user_data['user_new'])) 3655 { 3656 return false; 3657 } 3658 3659 $sql = 'SELECT group_id 3660 FROM ' . GROUPS_TABLE . " 3661 WHERE group_name = 'NEWLY_REGISTERED' 3662 AND group_type = " . GROUP_SPECIAL; 3663 $result = $db->sql_query($sql); 3664 $group_id = (int) $db->sql_fetchfield('group_id'); 3665 $db->sql_freeresult($result); 3666 3667 if (!$group_id) 3668 { 3669 return false; 3670 } 3671 3672 // We need to call group_user_del here, because this function makes sure everything is correctly changed. 3673 // Force function to not log the removal of users from newly registered users group 3674 group_user_del($group_id, $user_id, false, false, false); 3675 3676 // Set user_new to 0 to let this not be triggered again 3677 $sql = 'UPDATE ' . USERS_TABLE . ' 3678 SET user_new = 0 3679 WHERE user_id = ' . $user_id; 3680 $db->sql_query($sql); 3681 3682 // The new users group was the users default group? 3683 if ($user_data['group_id'] == $group_id) 3684 { 3685 // Which group is now the users default one? 3686 $sql = 'SELECT group_id 3687 FROM ' . USERS_TABLE . ' 3688 WHERE user_id = ' . $user_id; 3689 $result = $db->sql_query($sql); 3690 $user_data['group_id'] = $db->sql_fetchfield('group_id'); 3691 $db->sql_freeresult($result); 3692 } 3693 3694 return $user_data['group_id']; 3695 } 3696 3697 /** 3698 * Gets user ids of currently banned registered users. 3699 * 3700 * @param array $user_ids Array of users' ids to check for banning, 3701 * leave empty to get complete list of banned ids 3702 * @param bool|int $ban_end Bool True to get users currently banned 3703 * Bool False to only get permanently banned users 3704 * Int Unix timestamp to get users banned until that time 3705 * @return array Array of banned users' ids if any, empty array otherwise 3706 */ 3707 function phpbb_get_banned_user_ids($user_ids = array(), $ban_end = true) 3708 { 3709 global $db; 3710 3711 $sql_user_ids = (!empty($user_ids)) ? $db->sql_in_set('ban_userid', $user_ids) : 'ban_userid <> 0'; 3712 3713 // Get banned User ID's 3714 // Ignore stale bans which were not wiped yet 3715 $banned_ids_list = array(); 3716 $sql = 'SELECT ban_userid 3717 FROM ' . BANLIST_TABLE . " 3718 WHERE $sql_user_ids 3719 AND ban_exclude <> 1"; 3720 3721 if ($ban_end === true) 3722 { 3723 // Banned currently 3724 $sql .= " AND (ban_end > " . time() . ' 3725 OR ban_end = 0)'; 3726 } 3727 else if ($ban_end === false) 3728 { 3729 // Permanently banned 3730 $sql .= " AND ban_end = 0"; 3731 } 3732 else 3733 { 3734 // Banned until a specified time 3735 $sql .= " AND (ban_end > " . (int) $ban_end . ' 3736 OR ban_end = 0)'; 3737 } 3738 3739 $result = $db->sql_query($sql); 3740 while ($row = $db->sql_fetchrow($result)) 3741 { 3742 $user_id = (int) $row['ban_userid']; 3743 $banned_ids_list[$user_id] = $user_id; 3744 } 3745 $db->sql_freeresult($result); 3746 3747 return $banned_ids_list; 3748 } 3749 3750 /** 3751 * Function for assigning a template var if the zebra module got included 3752 */ 3753 function phpbb_module_zebra($mode, &$module_row) 3754 { 3755 global $template; 3756 3757 $template->assign_var('S_ZEBRA_ENABLED', true); 3758 3759 if ($mode == 'friends') 3760 { 3761 $template->assign_var('S_ZEBRA_FRIENDS_ENABLED', true); 3762 } 3763 3764 if ($mode == 'foes') 3765 { 3766 $template->assign_var('S_ZEBRA_FOES_ENABLED', true); 3767 } 3768 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Jan 11 00:25:41 2018 | Cross-referenced by PHPXref 0.7.1 |