[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/includes/ -> functions_user.php (source)

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


Generated: Wed Oct 2 15:03:47 2013 Cross-referenced by PHPXref 0.7.1