Verzeichnisstruktur phpBB-3.0.0


Veröffentlicht
12.12.2007

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

functions_user.php

Zuletzt modifiziert: 09.10.2024, 12:50 - Dateigröße: 83.58 KiB


0001  <?php
0002  /**
0003  *
0004  * @package phpBB3
0005  * @version $Id$
0006  * @copyright (c) 2005 phpBB Group
0007  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
0008  *
0009  */
0010   
0011  /**
0012  * @ignore
0013  */
0014  if (!defined('IN_PHPBB'))
0015  {
0016      exit;
0017  }
0018   
0019  /**
0020  * Obtain user_ids from usernames or vice versa. Returns false on
0021  * success else the error string
0022  *
0023  * @param array &$user_id_ary The user ids to check or empty if usernames used
0024  * @param array &$username_ary The usernames to check or empty if user ids used
0025  * @param mixed $user_type Array of user types to check, false if not restricting by user type
0026  */
0027  function user_get_id_name(&$user_id_ary, &$username_ary, $user_type = false)
0028  {
0029      global $db;
0030   
0031      // Are both arrays already filled? Yep, return else
0032      // are neither array filled?
0033      if ($user_id_ary && $username_ary)
0034      {
0035          return false;
0036      }
0037      else if (!$user_id_ary && !$username_ary)
0038      {
0039          return 'NO_USERS';
0040      }
0041   
0042      $which_ary = ($user_id_ary) ? 'user_id_ary' : 'username_ary';
0043   
0044      if ($$which_ary && !is_array($$which_ary))
0045      {
0046          $$which_ary = array($$which_ary);
0047      }
0048   
0049      $sql_in = ($which_ary == 'user_id_ary') ? array_map('intval', $$which_ary) : array_map('utf8_clean_string', $$which_ary);
0050      unset($$which_ary);
0051   
0052      $user_id_ary = $username_ary = array();
0053   
0054      // Grab the user id/username records
0055      $sql_where = ($which_ary == 'user_id_ary') ? 'user_id' : 'username_clean';
0056      $sql = 'SELECT user_id, username
0057          FROM ' . USERS_TABLE . '
0058          WHERE ' . $db->sql_in_set($sql_where, $sql_in);
0059   
0060      if ($user_type !== false && !empty($user_type))
0061      {
0062          $sql .= ' AND ' . $db->sql_in_set('user_type', $user_type);
0063      }
0064   
0065      $result = $db->sql_query($sql);
0066   
0067      if (!($row = $db->sql_fetchrow($result)))
0068      {
0069          $db->sql_freeresult($result);
0070          return 'NO_USERS';
0071      }
0072   
0073      do
0074      {
0075          $username_ary[$row['user_id']] = $row['username'];
0076          $user_id_ary[] = $row['user_id'];
0077      }
0078      while ($row = $db->sql_fetchrow($result));
0079      $db->sql_freeresult($result);
0080   
0081      return false;
0082  }
0083   
0084  /**
0085  * Get latest registered username and update database to reflect it
0086  */
0087  function update_last_username()
0088  {
0089      global $db;
0090   
0091      // Get latest username
0092      $sql = 'SELECT user_id, username, user_colour
0093          FROM ' . USERS_TABLE . '
0094          WHERE user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')
0095          ORDER BY user_id DESC';
0096      $result = $db->sql_query_limit($sql, 1);
0097      $row = $db->sql_fetchrow($result);
0098      $db->sql_freeresult($result);
0099   
0100      if ($row)
0101      {
0102          set_config('newest_user_id', $row['user_id'], true);
0103          set_config('newest_username', $row['username'], true);
0104          set_config('newest_user_colour', $row['user_colour'], true);
0105      }
0106  }
0107   
0108  /**
0109  * Updates a username across all relevant tables/fields
0110  *
0111  * @param string $old_name the old/current username
0112  * @param string $new_name the new username
0113  */
0114  function user_update_name($old_name, $new_name)
0115  {
0116      global $config, $db, $cache;
0117   
0118      $update_ary = array(
0119          FORUMS_TABLE            => array('forum_last_poster_name'),
0120          MODERATOR_CACHE_TABLE    => array('username'),
0121          POSTS_TABLE                => array('post_username'),
0122          TOPICS_TABLE            => array('topic_first_poster_name', 'topic_last_poster_name'),
0123      );
0124   
0125      foreach ($update_ary as $table => $field_ary)
0126      {
0127          foreach ($field_ary as $field)
0128          {
0129              $sql = "UPDATE $table
0130                  SET $field = '" . $db->sql_escape($new_name) . "'
0131                  WHERE $field = '" . $db->sql_escape($old_name) . "'";
0132              $db->sql_query($sql);
0133          }
0134      }
0135   
0136      if ($config['newest_username'] == $old_name)
0137      {
0138          set_config('newest_username', $new_name, true);
0139      }
0140  }
0141   
0142  /**
0143  * Add User
0144  */
0145  function user_add($user_row, $cp_data = false)
0146  {
0147      global $db, $user, $auth, $config, $phpbb_root_path, $phpEx;
0148   
0149      if (empty($user_row['username']) || !isset($user_row['group_id']) || !isset($user_row['user_email']) || !isset($user_row['user_type']))
0150      {
0151          return false;
0152      }
0153   
0154      $username_clean = utf8_clean_string($user_row['username']);
0155   
0156      if (empty($username_clean))
0157      {
0158          return false;
0159      }
0160   
0161      $sql_ary = array(
0162          'username'            => $user_row['username'],
0163          'username_clean'    => $username_clean,
0164          'user_password'        => (isset($user_row['user_password'])) ? $user_row['user_password'] : '',
0165          'user_pass_convert'    => 0,
0166          'user_email'        => strtolower($user_row['user_email']),
0167          'user_email_hash'    => crc32(strtolower($user_row['user_email'])) . strlen($user_row['user_email']),
0168          'group_id'            => $user_row['group_id'],
0169          'user_type'            => $user_row['user_type'],
0170      );
0171   
0172      // These are the additional vars able to be specified
0173      $additional_vars = array(
0174          'user_permissions'    => '',
0175          'user_timezone'        => $config['board_timezone'],
0176          'user_dateformat'    => $config['default_dateformat'],
0177          'user_lang'            => $config['default_lang'],
0178          'user_style'        => $config['default_style'],
0179          'user_allow_pm'        => 1,
0180          'user_actkey'        => '',
0181          'user_ip'            => '',
0182          'user_regdate'        => time(),
0183          'user_passchg'        => time(),
0184          'user_options'        => 895,
0185   
0186          'user_inactive_reason'    => 0,
0187          'user_inactive_time'    => 0,
0188          'user_lastmark'            => time(),
0189          'user_lastvisit'        => 0,
0190          'user_lastpost_time'    => 0,
0191          'user_lastpage'            => '',
0192          'user_posts'            => 0,
0193          'user_dst'                => (int) $config['board_dst'],
0194          'user_colour'            => '',
0195          'user_occ'                => '',
0196          'user_interests'        => '',
0197          'user_avatar'            => '',
0198          'user_avatar_type'        => 0,
0199          'user_avatar_width'        => 0,
0200          'user_avatar_height'    => 0,
0201          'user_new_privmsg'        => 0,
0202          'user_unread_privmsg'    => 0,
0203          'user_last_privmsg'        => 0,
0204          'user_message_rules'    => 0,
0205          'user_full_folder'        => PRIVMSGS_NO_BOX,
0206          'user_emailtime'        => 0,
0207   
0208          'user_notify'            => 0,
0209          'user_notify_pm'        => 1,
0210          'user_notify_type'        => NOTIFY_EMAIL,
0211          'user_allow_pm'            => 1,
0212          'user_allow_viewonline'    => 1,
0213          'user_allow_viewemail'    => 1,
0214          'user_allow_massemail'    => 1,
0215   
0216          'user_sig'                    => '',
0217          'user_sig_bbcode_uid'        => '',
0218          'user_sig_bbcode_bitfield'    => '',
0219          
0220          'user_form_salt'            => unique_id(),
0221      );
0222   
0223      // Now fill the sql array with not required variables
0224      foreach ($additional_vars as $key => $default_value)
0225      {
0226          $sql_ary[$key] = (isset($user_row[$key])) ? $user_row[$key] : $default_value;
0227      }
0228   
0229      // Any additional variables in $user_row not covered above?
0230      $remaining_vars = array_diff(array_keys($user_row), array_keys($sql_ary));
0231   
0232      // Now fill our sql array with the remaining vars
0233      if (sizeof($remaining_vars))
0234      {
0235          foreach ($remaining_vars as $key)
0236          {
0237              $sql_ary[$key] = $user_row[$key];
0238          }
0239      }
0240   
0241      $sql = 'INSERT INTO ' . USERS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
0242      $db->sql_query($sql);
0243   
0244      $user_id = $db->sql_nextid();
0245   
0246      // Insert Custom Profile Fields
0247      if ($cp_data !== false && sizeof($cp_data))
0248      {
0249          $cp_data['user_id'] = (int) $user_id;
0250   
0251          if (!class_exists('custom_profile'))
0252          {
0253              include_once($phpbb_root_path . 'includes/functions_profile_fields.' . $phpEx);
0254          }
0255   
0256          $sql = 'INSERT INTO ' . PROFILE_FIELDS_DATA_TABLE . ' ' .
0257              $db->sql_build_array('INSERT', custom_profile::build_insert_sql_array($cp_data));
0258          $db->sql_query($sql);
0259      }
0260   
0261      // Place into appropriate group...
0262      $sql = 'INSERT INTO ' . USER_GROUP_TABLE . ' ' . $db->sql_build_array('INSERT', array(
0263          'user_id'        => (int) $user_id,
0264          'group_id'        => (int) $user_row['group_id'],
0265          'user_pending'    => 0)
0266      );
0267      $db->sql_query($sql);
0268   
0269      // Now make it the users default group...
0270      group_set_user_default($user_row['group_id'], array($user_id), false);
0271   
0272      // set the newest user and adjust the user count if the user is a normal user and no activation mail is sent
0273      if ($user_row['user_type'] == USER_NORMAL)
0274      {
0275          set_config('newest_user_id', $user_id, true);
0276          set_config('newest_username', $user_row['username'], true);
0277          set_config('num_users', $config['num_users'] + 1, true);
0278   
0279          $sql = 'SELECT group_colour
0280              FROM ' . GROUPS_TABLE . '
0281              WHERE group_id = ' . $user_row['group_id'];
0282          $result = $db->sql_query_limit($sql, 1);
0283          $row = $db->sql_fetchrow($result);
0284          $db->sql_freeresult($result);
0285   
0286          set_config('newest_user_colour', $row['group_colour'], true);
0287      }
0288   
0289      return $user_id;
0290  }
0291   
0292  /**
0293  * Remove User
0294  */
0295  function user_delete($mode, $user_id, $post_username = false)
0296  {
0297      global $cache, $config, $db, $user, $auth;
0298      global $phpbb_root_path, $phpEx;
0299   
0300      $sql = 'SELECT *
0301          FROM ' . USERS_TABLE . '
0302          WHERE user_id = ' . $user_id;
0303      $result = $db->sql_query($sql);
0304      $user_row = $db->sql_fetchrow($result);
0305      $db->sql_freeresult($result);
0306   
0307      if (!$user_row)
0308      {
0309          return false;
0310      }
0311   
0312      $db->sql_transaction('begin');
0313   
0314      // Before we begin, we will remove the reports the user issued.
0315      $sql = 'SELECT r.post_id, p.topic_id
0316          FROM ' . REPORTS_TABLE . ' r, ' . POSTS_TABLE . ' p
0317          WHERE r.user_id = ' . $user_id . '
0318              AND p.post_id = r.post_id';
0319      $result = $db->sql_query($sql);
0320   
0321      $report_posts = $report_topics = array();
0322      while ($row = $db->sql_fetchrow($result))
0323      {
0324          $report_posts[] = $row['post_id'];
0325          $report_topics[] = $row['topic_id'];
0326      }
0327      $db->sql_freeresult($result);
0328   
0329      if (sizeof($report_posts))
0330      {
0331          $report_posts = array_unique($report_posts);
0332          $report_topics = array_unique($report_topics);
0333   
0334          // Get a list of topics that still contain reported posts
0335          $sql = 'SELECT DISTINCT topic_id
0336              FROM ' . POSTS_TABLE . '
0337              WHERE ' . $db->sql_in_set('topic_id', $report_topics) . '
0338                  AND post_reported = 1
0339                  AND ' . $db->sql_in_set('post_id', $report_posts, true);
0340          $result = $db->sql_query($sql);
0341   
0342          $keep_report_topics = array();
0343          while ($row = $db->sql_fetchrow($result))
0344          {
0345              $keep_report_topics[] = $row['topic_id'];
0346          }
0347          $db->sql_freeresult($result);
0348   
0349          if (sizeof($keep_report_topics))
0350          {
0351              $report_topics = array_diff($report_topics, $keep_report_topics);
0352          }
0353          unset($keep_report_topics);
0354   
0355          // Now set the flags back
0356          $sql = 'UPDATE ' . POSTS_TABLE . '
0357              SET post_reported = 0
0358              WHERE ' . $db->sql_in_set('post_id', $report_posts);
0359          $db->sql_query($sql);
0360   
0361          if (sizeof($report_topics))
0362          {
0363              $sql = 'UPDATE ' . TOPICS_TABLE . '
0364                  SET topic_reported = 0
0365                  WHERE ' . $db->sql_in_set('topic_id', $report_topics);
0366              $db->sql_query($sql);
0367          }
0368      }
0369   
0370      // Remove reports
0371      $db->sql_query('DELETE FROM ' . REPORTS_TABLE . ' WHERE user_id = ' . $user_id);
0372   
0373      if ($user_row['user_avatar'] && $user_row['user_avatar_type'] == AVATAR_UPLOAD)
0374      {
0375          avatar_delete('user', $user_row);
0376      }
0377      
0378      switch ($mode)
0379      {
0380          case 'retain':
0381   
0382              if ($post_username === false)
0383              {
0384                  $post_username = $user->lang['GUEST'];
0385              }
0386   
0387              // If the user is inactive and newly registered we assume no posts from this user being there...
0388              if ($user_row['user_type'] == USER_INACTIVE && $user_row['user_inactive_reason'] == INACTIVE_REGISTER && !$user_row['user_posts'])
0389              {
0390              }
0391              else
0392              {
0393                  $sql = 'UPDATE ' . FORUMS_TABLE . '
0394                      SET forum_last_poster_id = ' . ANONYMOUS . ", forum_last_poster_name = '" . $db->sql_escape($post_username) . "', forum_last_poster_colour = ''
0395                      WHERE forum_last_poster_id = $user_id";
0396                  $db->sql_query($sql);
0397   
0398                  $sql = 'UPDATE ' . POSTS_TABLE . '
0399                      SET poster_id = ' . ANONYMOUS . ", post_username = '" . $db->sql_escape($post_username) . "'
0400                      WHERE poster_id = $user_id";
0401                  $db->sql_query($sql);
0402   
0403                  $sql = 'UPDATE ' . POSTS_TABLE . '
0404                      SET post_edit_user = ' . ANONYMOUS . "
0405                      WHERE post_edit_user = $user_id";
0406                  $db->sql_query($sql);
0407   
0408                  $sql = 'UPDATE ' . TOPICS_TABLE . '
0409                      SET topic_poster = ' . ANONYMOUS . ", topic_first_poster_name = '" . $db->sql_escape($post_username) . "', topic_first_poster_colour = ''
0410                      WHERE topic_poster = $user_id";
0411                  $db->sql_query($sql);
0412   
0413                  $sql = 'UPDATE ' . TOPICS_TABLE . '
0414                      SET topic_last_poster_id = ' . ANONYMOUS . ", topic_last_poster_name = '" . $db->sql_escape($post_username) . "', topic_last_poster_colour = ''
0415                      WHERE topic_last_poster_id = $user_id";
0416                  $db->sql_query($sql);
0417   
0418                  // Since we change every post by this author, we need to count this amount towards the anonymous user
0419   
0420                  // Update the post count for the anonymous user
0421                  if ($user_row['user_posts'])
0422                  {
0423                      $sql = 'UPDATE ' . USERS_TABLE . '
0424                          SET user_posts = user_posts + ' . $user_row['user_posts'] . '
0425                          WHERE user_id = ' . ANONYMOUS;
0426                      $db->sql_query($sql);
0427                  }
0428              }
0429          break;
0430   
0431          case 'remove':
0432   
0433              if (!function_exists('delete_posts'))
0434              {
0435                  include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
0436              }
0437   
0438              $sql = 'SELECT topic_id, COUNT(post_id) AS total_posts
0439                  FROM ' . POSTS_TABLE . "
0440                  WHERE poster_id = $user_id
0441                  GROUP BY topic_id";
0442              $result = $db->sql_query($sql);
0443   
0444              $topic_id_ary = array();
0445              while ($row = $db->sql_fetchrow($result))
0446              {
0447                  $topic_id_ary[$row['topic_id']] = $row['total_posts'];
0448              }
0449              $db->sql_freeresult($result);
0450   
0451              if (sizeof($topic_id_ary))
0452              {
0453                  $sql = 'SELECT topic_id, topic_replies, topic_replies_real
0454                      FROM ' . TOPICS_TABLE . '
0455                      WHERE ' . $db->sql_in_set('topic_id', array_keys($topic_id_ary));
0456                  $result = $db->sql_query($sql);
0457   
0458                  $del_topic_ary = array();
0459                  while ($row = $db->sql_fetchrow($result))
0460                  {
0461                      if (max($row['topic_replies'], $row['topic_replies_real']) + 1 == $topic_id_ary[$row['topic_id']])
0462                      {
0463                          $del_topic_ary[] = $row['topic_id'];
0464                      }
0465                  }
0466                  $db->sql_freeresult($result);
0467   
0468                  if (sizeof($del_topic_ary))
0469                  {
0470                      $sql = 'DELETE FROM ' . TOPICS_TABLE . '
0471                          WHERE ' . $db->sql_in_set('topic_id', $del_topic_ary);
0472                      $db->sql_query($sql);
0473                  }
0474              }
0475   
0476              // Delete posts, attachments, etc.
0477              delete_posts('poster_id', $user_id);
0478   
0479          break;
0480      }
0481   
0482      $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);
0483   
0484      foreach ($table_ary as $table)
0485      {
0486          $sql = "DELETE FROM $table
0487              WHERE user_id = $user_id";
0488          $db->sql_query($sql);
0489      }
0490   
0491      $cache->destroy('sql', MODERATOR_CACHE_TABLE);
0492   
0493      // Remove any undelivered mails...
0494      $sql = 'SELECT msg_id, user_id
0495          FROM ' . PRIVMSGS_TO_TABLE . '
0496          WHERE author_id = ' . $user_id . '
0497              AND folder_id = ' . PRIVMSGS_NO_BOX;
0498      $result = $db->sql_query($sql);
0499   
0500      $undelivered_msg = $undelivered_user = array();
0501      while ($row = $db->sql_fetchrow($result))
0502      {
0503          $undelivered_msg[] = $row['msg_id'];
0504          $undelivered_user[$row['user_id']][] = true;
0505      }
0506      $db->sql_freeresult($result);
0507   
0508      if (sizeof($undelivered_msg))
0509      {
0510          $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
0511              WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg);
0512          $db->sql_query($sql);
0513      }
0514   
0515      $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . '
0516          WHERE author_id = ' . $user_id . '
0517              AND folder_id = ' . PRIVMSGS_NO_BOX;
0518      $db->sql_query($sql);
0519   
0520      // Delete all to-information
0521      $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . '
0522          WHERE user_id = ' . $user_id;
0523      $db->sql_query($sql);
0524   
0525      // Set the remaining author id to anonymous - this way users are still able to read messages from users being removed
0526      $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
0527          SET author_id = ' . ANONYMOUS . '
0528          WHERE author_id = ' . $user_id;
0529      $db->sql_query($sql);
0530   
0531      $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
0532          SET author_id = ' . ANONYMOUS . '
0533          WHERE author_id = ' . $user_id;
0534      $db->sql_query($sql);
0535   
0536      foreach ($undelivered_user as $_user_id => $ary)
0537      {
0538          if ($_user_id == $user_id)
0539          {
0540              continue;
0541          }
0542   
0543          $sql = 'UPDATE ' . USERS_TABLE . '
0544              SET user_new_privmsg = user_new_privmsg - ' . sizeof($ary) . ',
0545                  user_unread_privmsg = user_unread_privmsg - ' . sizeof($ary) . '
0546              WHERE user_id = ' . $_user_id;
0547          $db->sql_query($sql);
0548      }
0549   
0550      // Reset newest user info if appropriate
0551      if ($config['newest_user_id'] == $user_id)
0552      {
0553          update_last_username();
0554      }
0555   
0556      // Decrement number of users if this user is active
0557      if ($user_row['user_type'] != USER_INACTIVE && $user_row['user_type'] != USER_IGNORE)
0558      {
0559          set_config('num_users', $config['num_users'] - 1, true);
0560      }
0561   
0562      $db->sql_transaction('commit');
0563   
0564      return false;
0565  }
0566   
0567  /**
0568  * Flips user_type from active to inactive and vice versa, handles group membership updates
0569  *
0570  * @param string $mode can be flip for flipping from active/inactive, activate or deactivate
0571  */
0572  function user_active_flip($mode, $user_id_ary, $reason = INACTIVE_MANUAL)
0573  {
0574      global $config, $db, $user, $auth;
0575   
0576      $deactivated = $activated = 0;
0577      $sql_statements = array();
0578   
0579      if (!is_array($user_id_ary))
0580      {
0581          $user_id_ary = array($user_id_ary);
0582      }
0583   
0584      if (!sizeof($user_id_ary))
0585      {
0586          return;
0587      }
0588   
0589      $sql = 'SELECT user_id, group_id, user_type, user_inactive_reason
0590          FROM ' . USERS_TABLE . '
0591          WHERE ' . $db->sql_in_set('user_id', $user_id_ary);
0592      $result = $db->sql_query($sql);
0593   
0594      while ($row = $db->sql_fetchrow($result))
0595      {
0596          $sql_ary = array();
0597   
0598          if ($row['user_type'] == USER_IGNORE || $row['user_type'] == USER_FOUNDER ||
0599              ($mode == 'activate' && $row['user_type'] != USER_INACTIVE) ||
0600              ($mode == 'deactivate' && $row['user_type'] == USER_INACTIVE))
0601          {
0602              continue;
0603          }
0604   
0605          if ($row['user_type'] == USER_INACTIVE)
0606          {
0607              $activated++;
0608          }
0609          else
0610          {
0611              $deactivated++;
0612   
0613              // Remove the users session key...
0614              $user->reset_login_keys($row['user_id']);
0615          }
0616   
0617          $sql_ary += array(
0618              'user_type'                => ($row['user_type'] == USER_NORMAL) ? USER_INACTIVE : USER_NORMAL,
0619              'user_inactive_time'    => ($row['user_type'] == USER_NORMAL) ? time() : 0,
0620              'user_inactive_reason'    => ($row['user_type'] == USER_NORMAL) ? $reason : 0,
0621          );
0622   
0623          $sql_statements[$row['user_id']] = $sql_ary;
0624      }
0625      $db->sql_freeresult($result);
0626   
0627      if (sizeof($sql_statements))
0628      {
0629          foreach ($sql_statements as $user_id => $sql_ary)
0630          {
0631              $sql = 'UPDATE ' . USERS_TABLE . '
0632                  SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
0633                  WHERE user_id = ' . $user_id;
0634              $db->sql_query($sql);
0635          }
0636   
0637          $auth->acl_clear_prefetch(array_keys($sql_statements));
0638      }
0639   
0640      if ($deactivated)
0641      {
0642          set_config('num_users', $config['num_users'] - $deactivated, true);
0643      }
0644   
0645      if ($activated)
0646      {
0647          set_config('num_users', $config['num_users'] + $activated, true);
0648      }
0649   
0650      // Update latest username
0651      update_last_username();
0652  }
0653   
0654  /**
0655  * Add a ban or ban exclusion to the banlist. Bans either a user, an IP or an email address
0656  *
0657  * @param string $mode Type of ban. One of the following: user, ip, email
0658  * @param mixed $ban Banned entity. Either string or array with usernames, ips or email addresses
0659  * @param int $ban_len Ban length in minutes
0660  * @param string $ban_len_other Ban length as a date (YYYY-MM-DD)
0661  * @param boolean $ban_exclude Exclude these entities from banning?
0662  * @param string $ban_reason String describing the reason for this ban
0663  * @return boolean
0664  */
0665  function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reason, $ban_give_reason = '')
0666  {
0667      global $db, $user, $auth, $cache;
0668   
0669      // Delete stale bans
0670      $sql = 'DELETE FROM ' . BANLIST_TABLE . '
0671          WHERE ban_end < ' . time() . '
0672              AND ban_end <> 0';
0673      $db->sql_query($sql);
0674   
0675      $ban_list = (!is_array($ban)) ? array_unique(explode("\n", $ban)) : $ban;
0676      $ban_list_log = implode(', ', $ban_list);
0677   
0678      $current_time = time();
0679   
0680      // Set $ban_end to the unix time when the ban should end. 0 is a permanent ban.
0681      if ($ban_len)
0682      {
0683          if ($ban_len != -1 || !$ban_len_other)
0684          {
0685              $ban_end = max($current_time, $current_time + ($ban_len) * 60);
0686          }
0687          else
0688          {
0689              $ban_other = explode('-', $ban_len_other);
0690              if (sizeof($ban_other) == 3 && ((int)$ban_other[0] < 9999) &&
0691                  (strlen($ban_other[0]) == 4) && (strlen($ban_other[1]) == 2) && (strlen($ban_other[2]) == 2))
0692              {
0693                  $ban_end = max($current_time, gmmktime(0, 0, 0, (int)$ban_other[1], (int)$ban_other[2], (int)$ban_other[0]));
0694              }
0695              else
0696              {
0697                  trigger_error('LENGTH_BAN_INVALID');
0698              }
0699          }
0700      }
0701      else
0702      {
0703          $ban_end = 0;
0704      }
0705   
0706      $founder = $founder_names = array();
0707   
0708      if (!$ban_exclude)
0709      {
0710          // Create a list of founder...
0711          $sql = 'SELECT user_id, user_email, username_clean
0712              FROM ' . USERS_TABLE . '
0713              WHERE user_type = ' . USER_FOUNDER;
0714          $result = $db->sql_query($sql);
0715   
0716          while ($row = $db->sql_fetchrow($result))
0717          {
0718              $founder[$row['user_id']] = $row['user_email'];
0719              $founder_names[$row['user_id']] = $row['username_clean'];
0720          }
0721          $db->sql_freeresult($result);
0722      }
0723   
0724      $banlist_ary = array();
0725   
0726      switch ($mode)
0727      {
0728          case 'user':
0729              $type = 'ban_userid';
0730   
0731              if (in_array('*', $ban_list))
0732              {
0733                  // Ban all users (it's a good thing that you can exclude people)
0734                  $banlist_ary[] = '*';
0735              }
0736              else
0737              {
0738                  // Select the relevant user_ids.
0739                  $sql_usernames = array();
0740   
0741                  foreach ($ban_list as $username)
0742                  {
0743                      $username = trim($username);
0744                      if ($username != '')
0745                      {
0746                          $clean_name = utf8_clean_string($username);
0747                          if ($clean_name == $user->data['username_clean'])
0748                          {
0749                              trigger_error('CANNOT_BAN_YOURSELF', E_USER_WARNING);
0750                          }
0751                          if (in_array($clean_name, $founder_names))
0752                          {
0753                              trigger_error('CANNOT_BAN_FOUNDER', E_USER_WARNING);
0754                          }
0755                          $sql_usernames[] = $clean_name;
0756                      }
0757                  }
0758   
0759                  // Make sure we have been given someone to ban
0760                  if (!sizeof($sql_usernames))
0761                  {
0762                      trigger_error('NO_USER_SPECIFIED');
0763                  }
0764   
0765                  $sql = 'SELECT user_id
0766                      FROM ' . USERS_TABLE . '
0767                      WHERE ' . $db->sql_in_set('username_clean', $sql_usernames);
0768   
0769                  // Do not allow banning yourself
0770                  if (sizeof($founder))
0771                  {
0772                      $sql .= ' AND ' . $db->sql_in_set('user_id', array_merge(array_keys($founder), array($user->data['user_id'])), true);
0773                  }
0774                  else
0775                  {
0776                      $sql .= ' AND user_id <> ' . $user->data['user_id'];
0777                  }
0778   
0779                  $result = $db->sql_query($sql);
0780   
0781                  if ($row = $db->sql_fetchrow($result))
0782                  {
0783                      do
0784                      {
0785                          $banlist_ary[] = (int) $row['user_id'];
0786                      }
0787                      while ($row = $db->sql_fetchrow($result));
0788                  }
0789                  else
0790                  {
0791                      trigger_error('NO_USERS');
0792                  }
0793                  $db->sql_freeresult($result);
0794              }
0795          break;
0796   
0797          case 'ip':
0798              $type = 'ban_ip';
0799   
0800              foreach ($ban_list as $ban_item)
0801              {
0802                  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))
0803                  {
0804                      // This is an IP range
0805                      // Don't ask about all this, just don't ask ... !
0806                      $ip_1_counter = $ip_range_explode[1];
0807                      $ip_1_end = $ip_range_explode[5];
0808   
0809                      while ($ip_1_counter <= $ip_1_end)
0810                      {
0811                          $ip_2_counter = ($ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[2] : 0;
0812                          $ip_2_end = ($ip_1_counter < $ip_1_end) ? 254 : $ip_range_explode[6];
0813   
0814                          if ($ip_2_counter == 0 && $ip_2_end == 254)
0815                          {
0816                              $ip_2_counter = 256;
0817                              $ip_2_fragment = 256;
0818   
0819                              $banlist_ary[] = "$ip_1_counter.*";
0820                          }
0821   
0822                          while ($ip_2_counter <= $ip_2_end)
0823                          {
0824                              $ip_3_counter = ($ip_2_counter == $ip_range_explode[2] && $ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[3] : 0;
0825                              $ip_3_end = ($ip_2_counter < $ip_2_end || $ip_1_counter < $ip_1_end) ? 254 : $ip_range_explode[7];
0826   
0827                              if ($ip_3_counter == 0 && $ip_3_end == 254)
0828                              {
0829                                  $ip_3_counter = 256;
0830                                  $ip_3_fragment = 256;
0831   
0832                                  $banlist_ary[] = "$ip_1_counter.$ip_2_counter.*";
0833                              }
0834   
0835                              while ($ip_3_counter <= $ip_3_end)
0836                              {
0837                                  $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;
0838                                  $ip_4_end = ($ip_3_counter < $ip_3_end || $ip_2_counter < $ip_2_end) ? 254 : $ip_range_explode[8];
0839   
0840                                  if ($ip_4_counter == 0 && $ip_4_end == 254)
0841                                  {
0842                                      $ip_4_counter = 256;
0843                                      $ip_4_fragment = 256;
0844   
0845                                      $banlist_ary[] = "$ip_1_counter.$ip_2_counter.$ip_3_counter.*";
0846                                  }
0847   
0848                                  while ($ip_4_counter <= $ip_4_end)
0849                                  {
0850                                      $banlist_ary[] = "$ip_1_counter.$ip_2_counter.$ip_3_counter.$ip_4_counter";
0851                                      $ip_4_counter++;
0852                                  }
0853                                  $ip_3_counter++;
0854                              }
0855                              $ip_2_counter++;
0856                          }
0857                          $ip_1_counter++;
0858                      }
0859                  }
0860                  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)))
0861                  {
0862                      // Normal IP address
0863                      $banlist_ary[] = trim($ban_item);
0864                  }
0865                  else if (preg_match('#^\*$#', trim($ban_item)))
0866                  {
0867                      // Ban all IPs
0868                      $banlist_ary[] = '*';
0869                  }
0870                  else if (preg_match('#^([\w\-_]\.?){2,}$#is', trim($ban_item)))
0871                  {
0872                      // hostname
0873                      $ip_ary = gethostbynamel(trim($ban_item));
0874   
0875                      if (!empty($ip_ary))
0876                      {
0877                          foreach ($ip_ary as $ip)
0878                          {
0879                              if ($ip)
0880                              {
0881                                  if (strlen($ip) > 40)
0882                                  {
0883                                      continue;
0884                                  }
0885   
0886                                  $banlist_ary[] = $ip;
0887                              }
0888                          }
0889                      }
0890                  }
0891                  else
0892                  {
0893                      trigger_error('NO_IPS_DEFINED');
0894                  }
0895              }
0896          break;
0897   
0898          case 'email':
0899              $type = 'ban_email';
0900   
0901              foreach ($ban_list as $ban_item)
0902              {
0903                  $ban_item = trim($ban_item);
0904   
0905                  if (preg_match('#^.*?@*|(([a-z0-9\-]+\.)+([a-z]{2,3}))$#i', $ban_item))
0906                  {
0907                      if (strlen($ban_item) > 100)
0908                      {
0909                          continue;
0910                      }
0911   
0912                      if (!sizeof($founder) || !in_array($ban_item, $founder))
0913                      {
0914                          $banlist_ary[] = $ban_item;
0915                      }
0916                  }
0917              }
0918   
0919              if (sizeof($ban_list) == 0)
0920              {
0921                  trigger_error('NO_EMAILS_DEFINED');
0922              }
0923          break;
0924   
0925          default:
0926              trigger_error('NO_MODE');
0927          break;
0928      }
0929   
0930      // Fetch currently set bans of the specified type and exclude state. Prevent duplicate bans.
0931      $sql_where = ($type == 'ban_userid') ? 'ban_userid <> 0' : "$type <> ''";
0932   
0933      $sql = "SELECT $type
0934          FROM " . BANLIST_TABLE . "
0935          WHERE $sql_where
0936              AND ban_exclude = $ban_exclude";
0937      $result = $db->sql_query($sql);
0938   
0939      // Reset $sql_where, because we use it later...
0940      $sql_where = '';
0941   
0942      if ($row = $db->sql_fetchrow($result))
0943      {
0944          $banlist_ary_tmp = array();
0945          do
0946          {
0947              switch ($mode)
0948              {
0949                  case 'user':
0950                      $banlist_ary_tmp[] = $row['ban_userid'];
0951                  break;
0952   
0953                  case 'ip':
0954                      $banlist_ary_tmp[] = $row['ban_ip'];
0955                  break;
0956   
0957                  case 'email':
0958                      $banlist_ary_tmp[] = $row['ban_email'];
0959                  break;
0960              }
0961          }
0962          while ($row = $db->sql_fetchrow($result));
0963   
0964          $banlist_ary = array_unique(array_diff($banlist_ary, $banlist_ary_tmp));
0965          unset($banlist_ary_tmp);
0966      }
0967      $db->sql_freeresult($result);
0968   
0969      // We have some entities to ban
0970      if (sizeof($banlist_ary))
0971      {
0972          $sql_ary = array();
0973   
0974          foreach ($banlist_ary as $ban_entry)
0975          {
0976              $sql_ary[] = array(
0977                  $type                => $ban_entry,
0978                  'ban_start'            => (int) $current_time,
0979                  'ban_end'            => (int) $ban_end,
0980                  'ban_exclude'        => (int) $ban_exclude,
0981                  'ban_reason'        => (string) $ban_reason,
0982                  'ban_give_reason'    => (string) $ban_give_reason,
0983              );
0984          }
0985          
0986          $db->sql_multi_insert(BANLIST_TABLE, $sql_ary);
0987   
0988          // If we are banning we want to logout anyone matching the ban
0989          if (!$ban_exclude)
0990          {
0991              switch ($mode)
0992              {
0993                  case 'user':
0994                      $sql_where = (in_array('*', $banlist_ary)) ? '' : 'WHERE ' . $db->sql_in_set('session_user_id', $banlist_ary);
0995                  break;
0996   
0997                  case 'ip':
0998                      $sql_where = 'WHERE ' . $db->sql_in_set('session_ip', $banlist_ary);
0999                  break;
1000   
1001                  case 'email':
1002                      $banlist_ary_sql = array();
1003   
1004                      foreach ($banlist_ary as $ban_entry)
1005                      {
1006                          $banlist_ary_sql[] = (string) str_replace('*', '%', $ban_entry);
1007                      }
1008   
1009                      $sql = 'SELECT user_id
1010                          FROM ' . USERS_TABLE . '
1011                          WHERE ' . $db->sql_in_set('user_email', $banlist_ary_sql);
1012                      $result = $db->sql_query($sql);
1013   
1014                      $sql_in = array();
1015   
1016                      if ($row = $db->sql_fetchrow($result))
1017                      {
1018                          do
1019                          {
1020                              $sql_in[] = $row['user_id'];
1021                          }
1022                          while ($row = $db->sql_fetchrow($result));
1023   
1024                          $sql_where = 'WHERE ' . $db->sql_in_set('session_user_id', $sql_in);
1025                      }
1026                      $db->sql_freeresult($result);
1027                  break;
1028              }
1029   
1030              if (isset($sql_where) && $sql_where)
1031              {
1032                  $sql = 'DELETE FROM ' . SESSIONS_TABLE . "
1033                      $sql_where";
1034                  $db->sql_query($sql);
1035   
1036                  if ($mode == 'user')
1037                  {
1038                      $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' ' . ((in_array('*', $banlist_ary)) ? '' : 'WHERE ' . $db->sql_in_set('user_id', $banlist_ary));
1039                      $db->sql_query($sql);
1040                  }
1041              }
1042          }
1043   
1044          // Update log
1045          $log_entry = ($ban_exclude) ? 'LOG_BAN_EXCLUDE_' : 'LOG_BAN_';
1046   
1047          // Add to moderator and admin log
1048          add_log('admin', $log_entry . strtoupper($mode), $ban_reason, $ban_list_log);
1049          add_log('mod', 0, 0, $log_entry . strtoupper($mode), $ban_reason, $ban_list_log);
1050   
1051          $cache->destroy('sql', BANLIST_TABLE);
1052   
1053          return true;
1054      }
1055   
1056      // There was nothing to ban/exclude. But destroying the cache because of the removal of stale bans.
1057      $cache->destroy('sql', BANLIST_TABLE);
1058   
1059      return false;
1060  }
1061   
1062  /**
1063  * Unban User
1064  */
1065  function user_unban($mode, $ban)
1066  {
1067      global $db, $user, $auth, $cache;
1068   
1069      // Delete stale bans
1070      $sql = 'DELETE FROM ' . BANLIST_TABLE . '
1071          WHERE ban_end < ' . time() . '
1072              AND ban_end <> 0';
1073      $db->sql_query($sql);
1074   
1075      if (!is_array($ban))
1076      {
1077          $ban = array($ban);
1078      }
1079   
1080      $unban_sql = array_map('intval', $ban);
1081   
1082      if (sizeof($unban_sql))
1083      {
1084          // Grab details of bans for logging information later
1085          switch ($mode)
1086          {
1087              case 'user':
1088                  $sql = 'SELECT u.username AS unban_info
1089                      FROM ' . USERS_TABLE . ' u, ' . BANLIST_TABLE . ' b
1090                      WHERE ' . $db->sql_in_set('b.ban_id', $unban_sql) . '
1091                          AND u.user_id = b.ban_userid';
1092              break;
1093   
1094              case 'email':
1095                  $sql = 'SELECT ban_email AS unban_info
1096                      FROM ' . BANLIST_TABLE . '
1097                      WHERE ' . $db->sql_in_set('ban_id', $unban_sql);
1098              break;
1099   
1100              case 'ip':
1101                  $sql = 'SELECT ban_ip AS unban_info
1102                      FROM ' . BANLIST_TABLE . '
1103                      WHERE ' . $db->sql_in_set('ban_id', $unban_sql);
1104              break;
1105          }
1106          $result = $db->sql_query($sql);
1107   
1108          $l_unban_list = '';
1109          while ($row = $db->sql_fetchrow($result))
1110          {
1111              $l_unban_list .= (($l_unban_list != '') ? ', ' : '') . $row['unban_info'];
1112          }
1113          $db->sql_freeresult($result);
1114   
1115          $sql = 'DELETE FROM ' . BANLIST_TABLE . '
1116              WHERE ' . $db->sql_in_set('ban_id', $unban_sql);
1117          $db->sql_query($sql);
1118   
1119          // Add to moderator and admin log
1120          add_log('admin', 'LOG_UNBAN_' . strtoupper($mode), $l_unban_list);
1121          add_log('mod', 0, 0, 'LOG_UNBAN_' . strtoupper($mode), $l_unban_list);
1122      }
1123   
1124      $cache->destroy('sql', BANLIST_TABLE);
1125   
1126      return false;
1127  }
1128   
1129  /**
1130  * Whois facility
1131  */
1132  function user_ipwhois($ip)
1133  {
1134      $ipwhois = '';
1135   
1136      // Check IP
1137      // Only supporting IPv4 at the moment...
1138      if (empty($ip) || !preg_match(get_preg_expression('ipv4'), $ip))
1139      {
1140          return '';
1141      }
1142   
1143      $match = array(
1144          '#RIPE\.NET#is'                => 'whois.ripe.net',
1145          '#whois\.apnic\.net#is'        => 'whois.apnic.net',
1146          '#nic\.ad\.jp#is'            => 'whois.nic.ad.jp',
1147          '#whois\.registro\.br#is'    => 'whois.registro.br'
1148      );
1149   
1150      if (($fsk = @fsockopen('whois.arin.net', 43)))
1151      {
1152          fputs($fsk, "$ip\n");
1153          while (!feof($fsk))
1154          {
1155              $ipwhois .= fgets($fsk, 1024);
1156          }
1157          @fclose($fsk);
1158      }
1159   
1160      foreach (array_keys($match) as $server)
1161      {
1162          if (preg_match($server, $ipwhois))
1163          {
1164              $ipwhois = '';
1165              if (($fsk = @fsockopen($match[$server], 43)))
1166              {
1167                  fputs($fsk, "$ip\n");
1168                  while (!feof($fsk))
1169                  {
1170                      $ipwhois .= fgets($fsk, 1024);
1171                  }
1172                  @fclose($fsk);
1173              }
1174              break;
1175          }
1176      }
1177   
1178      $ipwhois = htmlspecialchars($ipwhois);
1179   
1180      // Magic URL ;)
1181      return trim(make_clickable($ipwhois, false, ''));
1182  }
1183   
1184  /**
1185  * Data validation ... used primarily but not exclusively by ucp modules
1186  *
1187  * "Master" function for validating a range of data types
1188  */
1189  function validate_data($data, $val_ary)
1190  {
1191      $error = array();
1192   
1193      foreach ($val_ary as $var => $val_seq)
1194      {
1195          if (!is_array($val_seq[0]))
1196          {
1197              $val_seq = array($val_seq);
1198          }
1199   
1200          foreach ($val_seq as $validate)
1201          {
1202              $function = array_shift($validate);
1203              array_unshift($validate, $data[$var]);
1204   
1205              if ($result = call_user_func_array('validate_' . $function, $validate))
1206              {
1207                  $error[] = $result . '_' . strtoupper($var);
1208              }
1209          }
1210      }
1211   
1212      return $error;
1213  }
1214   
1215  /**
1216  * Validate String
1217  *
1218  * @return    boolean|string    Either false if validation succeeded or a string which will be used as the error message (with the variable name appended)
1219  */
1220  function validate_string($string, $optional = false, $min = 0, $max = 0)
1221  {
1222      if (empty($string) && $optional)
1223      {
1224          return false;
1225      }
1226   
1227      if ($min && utf8_strlen(htmlspecialchars_decode($string)) < $min)
1228      {
1229          return 'TOO_SHORT';
1230      }
1231      else if ($max && utf8_strlen(htmlspecialchars_decode($string)) > $max)
1232      {
1233          return 'TOO_LONG';
1234      }
1235   
1236      return false;
1237  }
1238   
1239  /**
1240  * Validate Number
1241  *
1242  * @return    boolean|string    Either false if validation succeeded or a string which will be used as the error message (with the variable name appended)
1243  */
1244  function validate_num($num, $optional = false, $min = 0, $max = 1E99)
1245  {
1246      if (empty($num) && $optional)
1247      {
1248          return false;
1249      }
1250   
1251      if ($num < $min)
1252      {
1253          return 'TOO_SMALL';
1254      }
1255      else if ($num > $max)
1256      {
1257          return 'TOO_LARGE';
1258      }
1259   
1260      return false;
1261  }
1262   
1263  /**
1264  * Validate Match
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_match($string, $optional = false, $match = '')
1269  {
1270      if (empty($string) && $optional)
1271      {
1272          return false;
1273      }
1274   
1275      if (empty($match))
1276      {
1277          return false;
1278      }
1279   
1280      if (!preg_match($match, $string))
1281      {
1282          return 'WRONG_DATA';
1283      }
1284   
1285      return false;
1286  }
1287   
1288  /**
1289  * Check to see if the username has been taken, or if it is disallowed.
1290  * Also checks if it includes the " character, which we don't allow in usernames.
1291  * Used for registering, changing names, and posting anonymously with a username
1292  *
1293  * @param string $username The username to check
1294  * @param string $allowed_username An allowed username, default being $user->data['username']
1295  *
1296  * @return    mixed    Either false if validation succeeded or a string which will be used as the error message (with the variable name appended)
1297  */
1298  function validate_username($username, $allowed_username = false)
1299  {
1300      global $config, $db, $user, $cache;
1301   
1302      $clean_username = utf8_clean_string($username);
1303      $allowed_username = ($allowed_username === false) ? $user->data['username_clean'] : utf8_clean_string($allowed_username);
1304   
1305      if ($allowed_username == $clean_username)
1306      {
1307          return false;
1308      }
1309   
1310      // ... fast checks first.
1311      if (strpos($username, '&quot;') !== false || strpos($username, '"') !== false || empty($clean_username))
1312      {
1313          return 'INVALID_CHARS';
1314      }
1315   
1316      $mbstring = $pcre = false;
1317   
1318      // generic UTF-8 character types supported?
1319      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)
1320      {
1321          $pcre = true;
1322      }
1323      else if (function_exists('mb_ereg_match'))
1324      {
1325          mb_regex_encoding('UTF-8');
1326          $mbstring = true;
1327      }
1328   
1329      switch ($config['allow_name_chars'])
1330      {
1331          case 'USERNAME_CHARS_ANY':
1332              $pcre = true;
1333              $regex = '.+';
1334          break;
1335   
1336          case 'USERNAME_ALPHA_ONLY':
1337              $pcre = true;
1338              $regex = '[A-Za-z0-9]+';
1339          break;
1340   
1341          case 'USERNAME_ALPHA_SPACERS':
1342              $pcre = true;
1343              $regex = '[A-Za-z0-9-[\]_+ ]+';
1344          break;
1345   
1346          case 'USERNAME_LETTER_NUM':
1347              if ($pcre)
1348              {
1349                  $regex = '[\p{Lu}\p{Ll}\p{N}]+';
1350              }
1351              else if ($mbstring)
1352              {
1353                  $regex = '[[:upper:][:lower:][:digit:]]+';
1354              }
1355              else
1356              {
1357                  $pcre = true;
1358                  $regex = '[a-zA-Z0-9]+';
1359              }
1360          break;
1361   
1362          case 'USERNAME_LETTER_NUM_SPACERS':
1363              if ($pcre)
1364              {
1365                  $regex = '[-\]_+ [\p{Lu}\p{Ll}\p{N}]+';
1366              }
1367              else if ($mbstring)
1368              {
1369                  $regex = '[-\]_+ [[:upper:][:lower:][:digit:]]+';
1370              }
1371              else
1372              {
1373                  $pcre = true;
1374                  $regex = '[-\]_+ [a-zA-Z0-9]+';
1375              }
1376          break;
1377   
1378          case 'USERNAME_ASCII':
1379          default:
1380              $pcre = true;
1381              $regex = '[\x01-\x7F]+';
1382          break;
1383      }
1384   
1385      if ($pcre)
1386      {
1387          if (!preg_match('#^' . $regex . '$#u', $username))
1388          {
1389              return 'INVALID_CHARS';
1390          }
1391      }
1392      else if ($mbstring)
1393      {
1394          $matches = array();
1395          mb_ereg_search_init('^' . $username . '$', $regex, $matches);
1396          if (!mb_ereg_search())
1397          {
1398              return 'INVALID_CHARS';
1399          }
1400      }
1401   
1402      $sql = 'SELECT username
1403          FROM ' . USERS_TABLE . "
1404          WHERE username_clean = '" . $db->sql_escape($clean_username) . "'";
1405      $result = $db->sql_query($sql);
1406      $row = $db->sql_fetchrow($result);
1407      $db->sql_freeresult($result);
1408   
1409      if ($row)
1410      {
1411          return 'USERNAME_TAKEN';
1412      }
1413   
1414      $sql = 'SELECT group_name
1415          FROM ' . GROUPS_TABLE . "
1416          WHERE LOWER(group_name) = '" . $db->sql_escape(utf8_strtolower($username)) . "'";
1417      $result = $db->sql_query($sql);
1418      $row = $db->sql_fetchrow($result);
1419      $db->sql_freeresult($result);
1420   
1421      if ($row)
1422      {
1423          return 'USERNAME_TAKEN';
1424      }
1425   
1426      $bad_usernames = $cache->obtain_disallowed_usernames();
1427   
1428      foreach ($bad_usernames as $bad_username)
1429      {
1430          if (preg_match('#^' . $bad_username . '$#', $clean_username))
1431          {
1432              return 'USERNAME_DISALLOWED';
1433          }
1434      }
1435   
1436      $sql = 'SELECT word
1437          FROM ' . WORDS_TABLE;
1438      $result = $db->sql_query($sql);
1439   
1440      while ($row = $db->sql_fetchrow($result))
1441      {
1442          if (preg_match('#(' . str_replace('\*', '.*?', preg_quote($row['word'], '#')) . ')#i', $username))
1443          {
1444              $db->sql_freeresult($result);
1445              return 'USERNAME_DISALLOWED';
1446          }
1447      }
1448      $db->sql_freeresult($result);
1449   
1450      return false;
1451  }
1452   
1453  /**
1454  * Check to see if the password meets the complexity settings
1455  *
1456  * @return    boolean|string    Either false if validation succeeded or a string which will be used as the error message (with the variable name appended)
1457  */
1458  function validate_password($password)
1459  {
1460      global $config, $db, $user;
1461   
1462      if (!$password)
1463      {
1464          return false;
1465      }
1466   
1467      $pcre = $mbstring = false;
1468   
1469      // generic UTF-8 character types supported?
1470      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)
1471      {
1472          $upp = '\p{Lu}';
1473          $low = '\p{Ll}';
1474          $let = '\p{L}';
1475          $num = '\p{N}';
1476          $sym = '[^\p{Lu}\p{Ll}\p{N}]';
1477          $pcre = true;
1478      }
1479      else if (function_exists('mb_ereg_match'))
1480      {
1481          mb_regex_encoding('UTF-8');
1482          $upp = '[[:upper:]]';
1483          $low = '[[:lower:]]';
1484          $let = '[[:lower:][:upper:]]';
1485          $num = '[[:digit:]]';
1486          $sym = '[^[:upper:][:lower:][:digit:]]';
1487          $mbstring = true;
1488      }
1489      else
1490      {
1491          $upp = '[A-Z]';
1492          $low = '[a-z]';
1493          $let = '[a-zA-Z]';
1494          $num = '[0-9]';
1495          $sym = '[^A-Za-z0-9]';
1496          $pcre = true;
1497      }
1498   
1499      $chars = array();
1500   
1501      switch ($config['pass_complex'])
1502      {
1503          case 'PASS_TYPE_CASE':
1504              $chars[] = $low;
1505              $chars[] = $upp;
1506          break;
1507   
1508          case 'PASS_TYPE_ALPHA':
1509              $chars[] = $let;
1510              $chars[] = $num;
1511          break;
1512   
1513          case 'PASS_TYPE_SYMBOL':
1514              $chars[] = $low;
1515              $chars[] = $upp;
1516              $chars[] = $num;
1517              $chars[] = $sym;
1518          break;
1519      }
1520   
1521      if ($pcre)
1522      {
1523          foreach ($chars as $char)
1524          {
1525              if (!preg_match('#' . $char . '#u', $password))
1526              {
1527                  return 'INVALID_CHARS';
1528              }
1529          }
1530      }
1531      else if ($mbstring)
1532      {
1533          foreach ($chars as $char)
1534          {
1535              if (mb_ereg($char, $password) === false)
1536              {
1537                  return 'INVALID_CHARS';
1538              }
1539          }
1540      }
1541   
1542      return false;
1543  }
1544   
1545  /**
1546  * Check to see if email address is banned or already present in the DB
1547  *
1548  * @param string $email The email to check
1549  * @param string $allowed_email An allowed email, default being $user->data['user_email']
1550  *
1551  * @return mixed Either false if validation succeeded or a string which will be used as the error message (with the variable name appended)
1552  */
1553  function validate_email($email, $allowed_email = false)
1554  {
1555      global $config, $db, $user;
1556   
1557      $email = strtolower($email);
1558      $allowed_email = ($allowed_email === false) ? strtolower($user->data['user_email']) : strtolower($allowed_email);
1559   
1560      if ($allowed_email == $email)
1561      {
1562          return false;
1563      }
1564   
1565      if (!preg_match('/^' . get_preg_expression('email') . '$/i', $email))
1566      {
1567          return 'EMAIL_INVALID';
1568      }
1569   
1570      // Check MX record.
1571      // The idea for this is from reading the UseBB blog/announcement. :)
1572      if ($config['email_check_mx'])
1573      {
1574          list(, $domain) = explode('@', $email);
1575   
1576          if (phpbb_checkdnsrr($domain, 'A') === false && phpbb_checkdnsrr($domain, 'MX') === false)
1577          {
1578              return 'DOMAIN_NO_MX_RECORD';
1579          }
1580      }
1581   
1582      if ($user->check_ban(false, false, $email, true) == true)
1583      {
1584          return 'EMAIL_BANNED';
1585      }
1586   
1587      if (!$config['allow_emailreuse'])
1588      {
1589          $sql = 'SELECT user_email_hash
1590              FROM ' . USERS_TABLE . "
1591              WHERE user_email_hash = " . (crc32($email) . strlen($email));
1592          $result = $db->sql_query($sql);
1593          $row = $db->sql_fetchrow($result);
1594          $db->sql_freeresult($result);
1595   
1596          if ($row)
1597          {
1598              return 'EMAIL_TAKEN';
1599          }
1600      }
1601   
1602      return false;
1603  }
1604   
1605  /**
1606  * Validate jabber address
1607  * Taken from the jabber class within flyspray (see author notes)
1608  *
1609  * @author flyspray.org
1610  */
1611  function validate_jabber($jid)
1612  {
1613      if (!$jid)
1614      {
1615          return false;
1616      }
1617   
1618      $seperator_pos = strpos($jid, '@');
1619   
1620      if ($seperator_pos === false)
1621      {
1622          return 'WRONG_DATA';
1623      }
1624   
1625      $username = substr($jid, 0, $seperator_pos);
1626      $realm = substr($jid, $seperator_pos + 1);
1627   
1628      if (strlen($username) == 0 || strlen($realm) < 3)
1629      {
1630          return 'WRONG_DATA';
1631      }
1632   
1633      $arr = explode('.', $realm);
1634   
1635      if (sizeof($arr) == 0)
1636      {
1637          return 'WRONG_DATA';
1638      }
1639   
1640      foreach ($arr as $part)
1641      {
1642          if (substr($part, 0, 1) == '-' || substr($part, -1, 1) == '-')
1643          {
1644              return 'WRONG_DATA';
1645          }
1646   
1647          if (!preg_match("@^[a-zA-Z0-9-.]+$@", $part))
1648          {
1649              return 'WRONG_DATA';
1650          }
1651      }
1652   
1653      $boundary = array(array(0, 127), array(192, 223), array(224, 239), array(240, 247), array(248, 251), array(252, 253));
1654   
1655      // Prohibited Characters RFC3454 + RFC3920
1656      $prohibited = array(
1657          // Table C.1.1
1658          array(0x0020, 0x0020),        // SPACE
1659          // Table C.1.2
1660          array(0x00A0, 0x00A0),        // NO-BREAK SPACE
1661          array(0x1680, 0x1680),        // OGHAM SPACE MARK
1662          array(0x2000, 0x2001),        // EN QUAD
1663          array(0x2001, 0x2001),        // EM QUAD
1664          array(0x2002, 0x2002),        // EN SPACE
1665          array(0x2003, 0x2003),        // EM SPACE
1666          array(0x2004, 0x2004),        // THREE-PER-EM SPACE
1667          array(0x2005, 0x2005),        // FOUR-PER-EM SPACE
1668          array(0x2006, 0x2006),        // SIX-PER-EM SPACE
1669          array(0x2007, 0x2007),        // FIGURE SPACE
1670          array(0x2008, 0x2008),        // PUNCTUATION SPACE
1671          array(0x2009, 0x2009),        // THIN SPACE
1672          array(0x200A, 0x200A),        // HAIR SPACE
1673          array(0x200B, 0x200B),        // ZERO WIDTH SPACE
1674          array(0x202F, 0x202F),        // NARROW NO-BREAK SPACE
1675          array(0x205F, 0x205F),        // MEDIUM MATHEMATICAL SPACE
1676          array(0x3000, 0x3000),        // IDEOGRAPHIC SPACE
1677          // Table C.2.1
1678          array(0x0000, 0x001F),        // [CONTROL CHARACTERS]
1679          array(0x007F, 0x007F),        // DELETE
1680          // Table C.2.2
1681          array(0x0080, 0x009F),        // [CONTROL CHARACTERS]
1682          array(0x06DD, 0x06DD),        // ARABIC END OF AYAH
1683          array(0x070F, 0x070F),        // SYRIAC ABBREVIATION MARK
1684          array(0x180E, 0x180E),        // MONGOLIAN VOWEL SEPARATOR
1685          array(0x200C, 0x200C),         // ZERO WIDTH NON-JOINER
1686          array(0x200D, 0x200D),        // ZERO WIDTH JOINER
1687          array(0x2028, 0x2028),        // LINE SEPARATOR
1688          array(0x2029, 0x2029),        // PARAGRAPH SEPARATOR
1689          array(0x2060, 0x2060),        // WORD JOINER
1690          array(0x2061, 0x2061),        // FUNCTION APPLICATION
1691          array(0x2062, 0x2062),        // INVISIBLE TIMES
1692          array(0x2063, 0x2063),        // INVISIBLE SEPARATOR
1693          array(0x206A, 0x206F),        // [CONTROL CHARACTERS]
1694          array(0xFEFF, 0xFEFF),        // ZERO WIDTH NO-BREAK SPACE
1695          array(0xFFF9, 0xFFFC),        // [CONTROL CHARACTERS]
1696          array(0x1D173, 0x1D17A),    // [MUSICAL CONTROL CHARACTERS]
1697          // Table C.3
1698          array(0xE000, 0xF8FF),        // [PRIVATE USE, PLANE 0]
1699          array(0xF0000, 0xFFFFD),    // [PRIVATE USE, PLANE 15]
1700          array(0x100000, 0x10FFFD),    // [PRIVATE USE, PLANE 16]
1701          // Table C.4
1702          array(0xFDD0, 0xFDEF),        // [NONCHARACTER CODE POINTS]
1703          array(0xFFFE, 0xFFFF),        // [NONCHARACTER CODE POINTS]
1704          array(0x1FFFE, 0x1FFFF),    // [NONCHARACTER CODE POINTS]
1705          array(0x2FFFE, 0x2FFFF),    // [NONCHARACTER CODE POINTS]
1706          array(0x3FFFE, 0x3FFFF),    // [NONCHARACTER CODE POINTS]
1707          array(0x4FFFE, 0x4FFFF),    // [NONCHARACTER CODE POINTS]
1708          array(0x5FFFE, 0x5FFFF),    // [NONCHARACTER CODE POINTS]
1709          array(0x6FFFE, 0x6FFFF),    // [NONCHARACTER CODE POINTS]
1710          array(0x7FFFE, 0x7FFFF),    // [NONCHARACTER CODE POINTS]
1711          array(0x8FFFE, 0x8FFFF),    // [NONCHARACTER CODE POINTS]
1712          array(0x9FFFE, 0x9FFFF),    // [NONCHARACTER CODE POINTS]
1713          array(0xAFFFE, 0xAFFFF),    // [NONCHARACTER CODE POINTS]
1714          array(0xBFFFE, 0xBFFFF),    // [NONCHARACTER CODE POINTS]
1715          array(0xCFFFE, 0xCFFFF),    // [NONCHARACTER CODE POINTS]
1716          array(0xDFFFE, 0xDFFFF),    // [NONCHARACTER CODE POINTS]
1717          array(0xEFFFE, 0xEFFFF),    // [NONCHARACTER CODE POINTS]
1718          array(0xFFFFE, 0xFFFFF),    // [NONCHARACTER CODE POINTS]
1719          array(0x10FFFE, 0x10FFFF),    // [NONCHARACTER CODE POINTS]
1720          // Table C.5
1721          array(0xD800, 0xDFFF),        // [SURROGATE CODES]
1722          // Table C.6
1723          array(0xFFF9, 0xFFF9),        // INTERLINEAR ANNOTATION ANCHOR
1724          array(0xFFFA, 0xFFFA),        // INTERLINEAR ANNOTATION SEPARATOR
1725          array(0xFFFB, 0xFFFB),        // INTERLINEAR ANNOTATION TERMINATOR
1726          array(0xFFFC, 0xFFFC),        // OBJECT REPLACEMENT CHARACTER
1727          array(0xFFFD, 0xFFFD),        // REPLACEMENT CHARACTER
1728          // Table C.7
1729          array(0x2FF0, 0x2FFB),        // [IDEOGRAPHIC DESCRIPTION CHARACTERS]
1730          // Table C.8
1731          array(0x0340, 0x0340),        // COMBINING GRAVE TONE MARK
1732          array(0x0341, 0x0341),        // COMBINING ACUTE TONE MARK
1733          array(0x200E, 0x200E),        // LEFT-TO-RIGHT MARK
1734          array(0x200F, 0x200F),        // RIGHT-TO-LEFT MARK
1735          array(0x202A, 0x202A),        // LEFT-TO-RIGHT EMBEDDING
1736          array(0x202B, 0x202B),        // RIGHT-TO-LEFT EMBEDDING
1737          array(0x202C, 0x202C),        // POP DIRECTIONAL FORMATTING
1738          array(0x202D, 0x202D),        // LEFT-TO-RIGHT OVERRIDE
1739          array(0x202E, 0x202E),        // RIGHT-TO-LEFT OVERRIDE
1740          array(0x206A, 0x206A),        // INHIBIT SYMMETRIC SWAPPING
1741          array(0x206B, 0x206B),        // ACTIVATE SYMMETRIC SWAPPING
1742          array(0x206C, 0x206C),        // INHIBIT ARABIC FORM SHAPING
1743          array(0x206D, 0x206D),        // ACTIVATE ARABIC FORM SHAPING
1744          array(0x206E, 0x206E),        // NATIONAL DIGIT SHAPES
1745          array(0x206F, 0x206F),        // NOMINAL DIGIT SHAPES
1746          // Table C.9
1747          array(0xE0001, 0xE0001),    // LANGUAGE TAG
1748          array(0xE0020, 0xE007F),    // [TAGGING CHARACTERS]
1749          // RFC3920
1750          array(0x22, 0x22),            // "
1751          array(0x26, 0x26),            // &
1752          array(0x27, 0x27),            // '
1753          array(0x2F, 0x2F),            // /
1754          array(0x3A, 0x3A),            // :
1755          array(0x3C, 0x3C),            // <
1756          array(0x3E, 0x3E),            // >
1757          array(0x40, 0x40)            // @
1758      );
1759   
1760      $pos = 0;
1761      $result = true;
1762   
1763      while ($pos < strlen($username))
1764      {
1765          $len = $uni = 0;
1766          for ($i = 0; $i <= 5; $i++)
1767          {
1768              if (ord($username[$pos]) >= $boundary[$i][0] && ord($username[$pos]) <= $boundary[$i][1])
1769              {
1770                  $len = $i + 1;
1771                  $uni = (ord($username[$pos]) - $boundary[$i][0]) * pow(2, $i * 6);
1772   
1773                  for ($k = 1; $k < $len; $k++)
1774                  {
1775                      $uni += (ord($username[$pos + $k]) - 128) * pow(2, ($i - $k) * 6);
1776                  }
1777   
1778                  break;
1779              }
1780          }
1781   
1782          if ($len == 0)
1783          {
1784              return 'WRONG_DATA';
1785          }
1786   
1787          foreach ($prohibited as $pval)
1788          {
1789              if ($uni >= $pval[0] && $uni <= $pval[1])
1790              {
1791                  $result = false;
1792                  break 2;
1793              }
1794          }
1795   
1796          $pos = $pos + $len;
1797      }
1798   
1799      if (!$result)
1800      {
1801          return 'WRONG_DATA';
1802      }
1803   
1804      return false;
1805  }
1806   
1807  /**
1808  * Remove avatar
1809  */
1810  function avatar_delete($mode, $row, $clean_db = false)
1811  {
1812      global $phpbb_root_path, $config, $db, $user;
1813   
1814      // Check if the users avatar is actually *not* a group avatar
1815      if ($mode == 'user')
1816      {
1817          if (strpos($row['user_avatar'], 'g') === 0 || (((int)$row['user_avatar'] !== 0) && ((int)$row['user_avatar'] !== (int)$row['user_id'])))
1818          {
1819              return false;
1820          }
1821      }
1822      
1823      if ($clean_db)
1824      {
1825          avatar_remove_db($row[$mode . '_avatar']);
1826      }
1827      $filename = get_avatar_filename($row[$mode . '_avatar']);
1828      if (file_exists($phpbb_root_path . $config['avatar_path'] . '/' . $filename))
1829      {
1830          @unlink($phpbb_root_path . $config['avatar_path'] . '/' . $filename);
1831          return true;
1832      }
1833   
1834      return false;
1835  }
1836   
1837  /**
1838  * Remote avatar linkage
1839  */
1840  function avatar_remote($data, &$error)
1841  {
1842      global $config, $db, $user, $phpbb_root_path, $phpEx;
1843   
1844      if (!preg_match('#^(http|https|ftp)://#i', $data['remotelink']))
1845      {
1846          $data['remotelink'] = 'http://' . $data['remotelink'];
1847      }
1848      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']))
1849      {
1850          $error[] = $user->lang['AVATAR_URL_INVALID'];
1851          return false;
1852      }
1853   
1854      // Make sure getimagesize works...
1855      if (($image_data = @getimagesize($data['remotelink'])) === false && (empty($data['width']) || empty($data['height'])))
1856      {
1857          $error[] = $user->lang['UNABLE_GET_IMAGE_SIZE'];
1858          return false;
1859      }
1860   
1861      if (!empty($image_data) && ($image_data[0] < 2 || $image_data[1] < 2))
1862      {
1863          $error[] = $user->lang['AVATAR_NO_SIZE'];
1864          return false;
1865      }
1866   
1867      $width = ($data['width'] && $data['height']) ? $data['width'] : $image_data[0];
1868      $height = ($data['width'] && $data['height']) ? $data['height'] : $image_data[1];
1869   
1870      if ($width < 2 || $height < 2)
1871      {
1872          $error[] = $user->lang['AVATAR_NO_SIZE'];
1873          return false;
1874      }
1875   
1876      // Check image type
1877      include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx);
1878      $types = fileupload::image_types();
1879      $extension = strtolower(filespec::get_extension($data['remotelink']));
1880   
1881      if (!empty($image_data) && (!isset($types[$image_data[2]]) || !in_array($extension, $types[$image_data[2]])))
1882      {
1883          if (!isset($types[$image_data[2]]))
1884          {
1885              $error[] = $user->lang['UNABLE_GET_IMAGE_SIZE'];
1886          }
1887          else
1888          {
1889              $error[] = sprintf($user->lang['IMAGE_FILETYPE_MISMATCH'], $types[$image_data[2]][0], $extension);
1890          }
1891          return false;
1892      }
1893   
1894      if ($config['avatar_max_width'] || $config['avatar_max_height'])
1895      {
1896          if ($width > $config['avatar_max_width'] || $height > $config['avatar_max_height'])
1897          {
1898              $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);
1899              return false;
1900          }
1901      }
1902   
1903      if ($config['avatar_min_width'] || $config['avatar_min_height'])
1904      {
1905          if ($width < $config['avatar_min_width'] || $height < $config['avatar_min_height'])
1906          {
1907              $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);
1908              return false;
1909          }
1910      }
1911   
1912      return array(AVATAR_REMOTE, $data['remotelink'], $width, $height);
1913  }
1914   
1915  /**
1916  * Avatar upload using the upload class
1917  */
1918  function avatar_upload($data, &$error)
1919  {
1920      global $phpbb_root_path, $config, $db, $user, $phpEx;
1921   
1922      // Init upload class
1923      include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx);
1924      $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']);
1925   
1926      if (!empty($_FILES['uploadfile']['name']))
1927      {
1928          $file = $upload->form_upload('uploadfile');
1929      }
1930      else
1931      {
1932          $file = $upload->remote_upload($data['uploadurl']);
1933      }
1934      
1935      $prefix = $config['avatar_salt'] . '_';
1936      $file->clean_filename('avatar', $prefix, $data['user_id']);
1937   
1938      $destination = $config['avatar_path'];
1939   
1940      // Adjust destination path (no trailing slash)
1941      if (substr($destination, -1, 1) == '/' || substr($destination, -1, 1) == '\\')
1942      {
1943          $destination = substr($destination, 0, -1);
1944      }
1945   
1946      $destination = str_replace(array('../', '..\\', './', '.\\'), '', $destination);
1947      if ($destination && ($destination[0] == '/' || $destination[0] == "\\"))
1948      {
1949          $destination = '';
1950      }
1951   
1952      // Move file and overwrite any existing image
1953      $file->move_file($destination, true);
1954   
1955      if (sizeof($file->error))
1956      {
1957          $file->remove();
1958          $error = array_merge($error, $file->error);
1959      }
1960   
1961      return array(AVATAR_UPLOAD, $data['user_id'] . '_' . time() . '.' . $file->get('extension'), $file->get('width'), $file->get('height'));
1962  }
1963   
1964  /**
1965  * Generates avatar filename from the database entry
1966  */
1967  function get_avatar_filename($avatar_entry)
1968  {
1969      global $config;
1970   
1971      
1972      if ($avatar_entry[0] === 'g')
1973      {
1974          $avatar_group = true;
1975          $avatar_entry = substr($avatar_entry, 1);
1976      }
1977      else
1978      {
1979          $avatar_group = false;
1980      }
1981      $ext             = substr(strrchr($avatar_entry, '.'), 1);
1982      $avatar_entry    = intval($avatar_entry);
1983      return $config['avatar_salt'] . '_' . (($avatar_group) ? 'g' : '') . $avatar_entry . '.' . $ext;
1984  }
1985   
1986  /**
1987  * Avatar Gallery
1988  */
1989  function avatar_gallery($category, $avatar_select, $items_per_column, $block_var = 'avatar_row')
1990  {
1991      global $user, $cache, $template;
1992      global $config, $phpbb_root_path;
1993   
1994      $avatar_list = array();
1995   
1996      $path = $phpbb_root_path . $config['avatar_gallery_path'];
1997   
1998      if (!file_exists($path) || !is_dir($path))
1999      {
2000          $avatar_list = array($user->lang['NO_AVATAR_CATEGORY'] => array());
2001      }
2002      else
2003      {
2004          // Collect images
2005          $dp = @opendir($path);
2006   
2007          if (!$dp)
2008          {
2009              return array($user->lang['NO_AVATAR_CATEGORY'] => array());
2010          }
2011   
2012          while (($file = readdir($dp)) !== false)
2013          {
2014              if ($file[0] != '.' && preg_match('#^[^&"\'<>]+$#i', $file) && is_dir("$path/$file"))
2015              {
2016                  $avatar_row_count = $avatar_col_count = 0;
2017      
2018                  if ($dp2 = @opendir("$path/$file"))
2019                  {
2020                      while (($sub_file = readdir($dp2)) !== false)
2021                      {
2022                          if (preg_match('#^[^&\'"<>]+\.(?:gif|png|jpe?g)$#i', $sub_file))
2023                          {
2024                              $avatar_list[$file][$avatar_row_count][$avatar_col_count] = array(
2025                                  'file'        => "$file/$sub_file",
2026                                  'filename'    => $sub_file,
2027                                  'name'        => ucfirst(str_replace('_', ' ', preg_replace('#^(.*)\..*$#', '\1', $sub_file))),
2028                              );
2029                              $avatar_col_count++;
2030                              if ($avatar_col_count == $items_per_column)
2031                              {
2032                                  $avatar_row_count++;
2033                                  $avatar_col_count = 0;
2034                              }
2035                          }
2036                      }
2037                      closedir($dp2);
2038                  }
2039              }
2040          }
2041          closedir($dp);
2042      }
2043   
2044      if (!sizeof($avatar_list))
2045      {
2046          $avatar_list = array($user->lang['NO_AVATAR_CATEGORY'] => array());
2047      }
2048   
2049      @ksort($avatar_list);
2050   
2051      $category = (!$category) ? key($avatar_list) : $category;
2052      $avatar_categories = array_keys($avatar_list);
2053   
2054      $s_category_options = '';
2055      foreach ($avatar_categories as $cat)
2056      {
2057          $s_category_options .= '<option value="' . $cat . '"' . (($cat == $category) ? ' selected="selected"' : '') . '>' . $cat . '</option>';
2058      }
2059   
2060      $template->assign_vars(array(
2061          'S_AVATARS_ENABLED'        => true,
2062          'S_IN_AVATAR_GALLERY'    => true,
2063          'S_CAT_OPTIONS'            => $s_category_options)
2064      );
2065   
2066      $avatar_list = (isset($avatar_list[$category])) ? $avatar_list[$category] : array();
2067   
2068      foreach ($avatar_list as $avatar_row_ary)
2069      {
2070          $template->assign_block_vars($block_var, array());
2071   
2072          foreach ($avatar_row_ary as $avatar_col_ary)
2073          {
2074              $template->assign_block_vars($block_var . '.avatar_column', array(
2075                  'AVATAR_IMAGE'    => $phpbb_root_path . $config['avatar_gallery_path'] . '/' . $avatar_col_ary['file'],
2076                  'AVATAR_NAME'    => $avatar_col_ary['name'],
2077                  'AVATAR_FILE'    => $avatar_col_ary['filename'])
2078              );
2079   
2080              $template->assign_block_vars($block_var . '.avatar_option_column', array(
2081                  'AVATAR_IMAGE'    => $phpbb_root_path . $config['avatar_gallery_path'] . '/' . $avatar_col_ary['file'],
2082                  'S_OPTIONS_AVATAR'    => $avatar_col_ary['filename'])
2083              );
2084          }
2085      }
2086   
2087      return $avatar_list;
2088  }
2089   
2090   
2091  /**
2092  * Tries to (re-)establish avatar dimensions
2093  */
2094  function avatar_get_dimensions($avatar, $avatar_type, &$error, $current_x = 0, $current_y = 0)
2095  {
2096      global $config, $phpbb_root_path, $user;
2097      
2098      switch ($avatar_type)
2099      {
2100          case AVATAR_REMOTE :
2101              break;
2102   
2103          case AVATAR_UPLOAD :
2104              $avatar = $phpbb_root_path . $config['avatar_path'] . '/' . get_avatar_filename($avatar);
2105              break;
2106          
2107          case AVATAR_GALLERY :
2108              $avatar = $phpbb_root_path . $config['avatar_gallery_path'] . '/' . $avatar ;
2109              break;
2110      }
2111   
2112      // Make sure getimagesize works...
2113      if (($image_data = @getimagesize($avatar)) === false)
2114      {
2115          $error[] = $user->lang['UNABLE_GET_IMAGE_SIZE'];
2116          return false;
2117      }
2118   
2119      if ($image_data[0] < 2 || $image_data[1] < 2)
2120      {
2121          $error[] = $user->lang['AVATAR_NO_SIZE'];
2122          return false;
2123      }
2124      
2125      // try to maintain ratio
2126      if (!(empty($current_x) && empty($current_y)))
2127      {
2128          if ($current_x != 0)
2129          {
2130              $image_data[1] = (int) floor(($current_x / $image_data[0]) * $image_data[1]);
2131              $image_data[1] = min($config['avatar_max_height'], $image_data[1]);
2132              $image_data[1] = max($config['avatar_min_height'], $image_data[1]);
2133          }
2134          if ($current_y != 0)
2135          {
2136              $image_data[0] = (int) floor(($current_y / $image_data[1]) * $image_data[0]);
2137              $image_data[0] = min($config['avatar_max_width'], $image_data[1]);
2138              $image_data[0] = max($config['avatar_min_width'], $image_data[1]);
2139          }
2140      }
2141      return array($image_data[0], $image_data[1]);
2142  }
2143   
2144  /**
2145  * Uploading/Changing user avatar
2146  */
2147  function avatar_process_user(&$error, $custom_userdata = false)
2148  {
2149      global $config, $phpbb_root_path, $auth, $user, $db;
2150   
2151      $data = array(
2152          'uploadurl'        => request_var('uploadurl', ''),
2153          'remotelink'    => request_var('remotelink', ''),
2154          'width'            => request_var('width', 0),
2155          'height'        => request_var('height', 0),
2156      );
2157   
2158      $error = validate_data($data, array(
2159          'uploadurl'        => array('string', true, 5, 255),
2160          'remotelink'    => array('string', true, 5, 255),
2161          'width'            => array('string', true, 1, 3),
2162          'height'        => array('string', true, 1, 3),
2163      ));
2164   
2165      if (sizeof($error))
2166      {
2167          return false;
2168      }
2169   
2170      $sql_ary = array();
2171   
2172      if ($custom_userdata === false)
2173      {
2174          $userdata = &$user->data;
2175      }
2176      else
2177      {
2178          $userdata = &$custom_userdata;
2179      }
2180   
2181      $data['user_id'] = $userdata['user_id'];
2182      $change_avatar = ($custom_userdata === false) ? $auth->acl_get('u_chgavatar') : true;
2183      $avatar_select = basename(request_var('avatar_select', ''));
2184   
2185      // Can we upload?
2186      $can_upload = ($config['allow_avatar_upload'] && file_exists($phpbb_root_path . $config['avatar_path']) && @is_writable($phpbb_root_path . $config['avatar_path']) && $change_avatar && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on')) ? true : false;
2187   
2188      if ((!empty($_FILES['uploadfile']['name']) || $data['uploadurl']) && $can_upload)
2189      {
2190          list($sql_ary['user_avatar_type'], $sql_ary['user_avatar'], $sql_ary['user_avatar_width'], $sql_ary['user_avatar_height']) = avatar_upload($data, $error);
2191      }
2192      else if ($data['remotelink'] && $change_avatar && $config['allow_avatar_remote'])
2193      {
2194          list($sql_ary['user_avatar_type'], $sql_ary['user_avatar'], $sql_ary['user_avatar_width'], $sql_ary['user_avatar_height']) = avatar_remote($data, $error);
2195      }
2196      else if ($avatar_select && $change_avatar && $config['allow_avatar_local'])
2197      {
2198          $category = basename(request_var('category', ''));
2199   
2200          $sql_ary['user_avatar_type'] = AVATAR_GALLERY;
2201          $sql_ary['user_avatar'] = $avatar_select;
2202   
2203          // check avatar gallery
2204          if (!is_dir($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category))
2205          {
2206              $sql_ary['user_avatar'] = '';
2207              $sql_ary['user_avatar_type'] = $sql_ary['user_avatar_width'] = $sql_ary['user_avatar_height'] = 0;
2208          }
2209          else
2210          {
2211              list($sql_ary['user_avatar_width'], $sql_ary['user_avatar_height']) = getimagesize($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category . '/' . $sql_ary['user_avatar']);
2212              $sql_ary['user_avatar'] = $category . '/' . $sql_ary['user_avatar'];
2213          }
2214      }
2215      else if (isset($_POST['delete']) && $change_avatar)
2216      {
2217          $sql_ary['user_avatar'] = '';
2218          $sql_ary['user_avatar_type'] = $sql_ary['user_avatar_width'] = $sql_ary['user_avatar_height'] = 0;
2219      }
2220      else if (!empty($userdata['user_avatar']))
2221      {
2222          // Only update the dimensions
2223          
2224          if (empty($data['width']) || empty($data['height']))
2225          {
2226              if ($dims = avatar_get_dimensions($userdata['user_avatar'], $userdata['user_avatar_type'], $error, $data['width'], $data['height']))
2227              {
2228                  list($guessed_x, $guessed_y) = $dims;
2229                  if (empty($data['width']))
2230                  {
2231                      $data['width'] = $guessed_x;
2232                  }
2233                  if (empty($data['height']))
2234                  {
2235                      $data['height'] = $guessed_y;
2236                  }
2237              }
2238          }
2239          if (($config['avatar_max_width'] || $config['avatar_max_height']) &&
2240              (($data['width'] != $userdata['user_avatar_width']) || $data['height'] != $userdata['user_avatar_height']))
2241          {
2242              if ($data['width'] > $config['avatar_max_width'] || $data['height'] > $config['avatar_max_height'])
2243              {
2244                  $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']);
2245              }
2246          }
2247   
2248          if (!sizeof($error))
2249          {
2250              if ($config['avatar_min_width'] || $config['avatar_min_height'])
2251              {
2252                  if ($data['width'] < $config['avatar_min_width'] || $data['height'] < $config['avatar_min_height'])
2253                  {
2254                      $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']);
2255                  }
2256              }
2257          }
2258   
2259          if (!sizeof($error))
2260          {
2261              $sql_ary['user_avatar_width'] = $data['width'];
2262              $sql_ary['user_avatar_height'] = $data['height'];
2263          }
2264      }
2265   
2266      if (!sizeof($error))
2267      {
2268          // Do we actually have any data to update?
2269          if (sizeof($sql_ary))
2270          {
2271              $sql = 'UPDATE ' . USERS_TABLE . '
2272                  SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
2273                  WHERE user_id = ' . (($custom_userdata === false) ? $user->data['user_id'] : $custom_userdata['user_id']);
2274              $db->sql_query($sql);
2275   
2276              if (isset($sql_ary['user_avatar']))
2277              {
2278                  $userdata = ($custom_userdata === false) ? $user->data : $custom_userdata;
2279   
2280                  // Delete old avatar if present
2281                  if ((!empty($userdata['user_avatar']) && empty($sql_ary['user_avatar']) && $userdata['user_avatar_type'] == AVATAR_UPLOAD)
2282                     || ( !empty($userdata['user_avatar']) && !empty($sql_ary['user_avatar']) && $userdata['user_avatar_type'] == AVATAR_UPLOAD && $sql_ary['user_avatar_type'] != AVATAR_UPLOAD))
2283                  {
2284                      avatar_delete('user', $userdata);
2285                  }
2286              }
2287          }
2288      }
2289   
2290      return (sizeof($error)) ? false : true;
2291  }
2292   
2293  //
2294  // Usergroup functions
2295  //
2296   
2297  /**
2298  * Add or edit a group. If we're editing a group we only update user
2299  * parameters such as rank, etc. if they are changed
2300  */
2301  function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow_desc_bbcode = false, $allow_desc_urls = false, $allow_desc_smilies = false)
2302  {
2303      global $phpbb_root_path, $config, $db, $user, $file_upload;
2304   
2305      $error = array();
2306      $attribute_ary = array(
2307          'group_colour'            => 'string',
2308          'group_rank'            => 'int',
2309          'group_avatar'            => 'string',
2310          'group_avatar_type'        => 'int',
2311          'group_avatar_width'    => 'int',
2312          'group_avatar_height'    => 'int',
2313   
2314          'group_receive_pm'        => 'int',
2315          'group_legend'            => 'int',
2316          'group_message_limit'    => 'int',
2317   
2318          'group_founder_manage'    => 'int',
2319      );
2320   
2321      // Those are group-only attributes
2322      $group_only_ary = array('group_receive_pm', 'group_legend', 'group_message_limit', 'group_founder_manage');
2323   
2324      // Check data. Limit group name length.
2325      if (!utf8_strlen($name) || utf8_strlen($name) > 60)
2326      {
2327          $error[] = (!utf8_strlen($name)) ? $user->lang['GROUP_ERR_USERNAME'] : $user->lang['GROUP_ERR_USER_LONG'];
2328      }
2329      
2330      $err = group_validate_groupname($group_id, $name);
2331      if (!empty($err))
2332      {
2333          $error[] = $user->lang[$err];
2334      }
2335      
2336      if (!in_array($type, array(GROUP_OPEN, GROUP_CLOSED, GROUP_HIDDEN, GROUP_SPECIAL, GROUP_FREE)))
2337      {
2338          $error[] = $user->lang['GROUP_ERR_TYPE'];
2339      }
2340   
2341      if (!sizeof($error))
2342      {
2343          $user_ary = array();
2344          $sql_ary = array(
2345              'group_name'            => (string) $name,
2346              'group_desc'            => (string) $desc,
2347              'group_desc_uid'        => '',
2348              'group_desc_bitfield'    => '',
2349              'group_type'            => (int) $type,
2350          );
2351   
2352          // Parse description
2353          if ($desc)
2354          {
2355              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);
2356          }
2357   
2358          if (sizeof($group_attributes))
2359          {
2360              foreach ($attribute_ary as $attribute => $_type)
2361              {
2362                  if (isset($group_attributes[$attribute]))
2363                  {
2364                      settype($group_attributes[$attribute], $_type);
2365                      $sql_ary[$attribute] = $group_attributes[$attribute];
2366                  }
2367              }
2368          }
2369   
2370          // Setting the log message before we set the group id (if group gets added)
2371          $log = ($group_id) ? 'LOG_GROUP_UPDATED' : 'LOG_GROUP_CREATED';
2372   
2373          $query = '';
2374   
2375          if ($group_id)
2376          {
2377              $sql = 'SELECT user_id
2378                  FROM ' . USERS_TABLE . '
2379                  WHERE group_id = ' . $group_id;
2380              $result = $db->sql_query($sql);
2381   
2382              while ($row = $db->sql_fetchrow($result))
2383              {
2384                  $user_ary[] = $row['user_id'];
2385              }
2386              $db->sql_freeresult($result);
2387   
2388              if (isset($sql_ary['group_avatar']) && !$sql_ary['group_avatar'])
2389              {
2390                  remove_default_avatar($group_id, $user_ary);
2391              }
2392              if (isset($sql_ary['group_rank']) && !$sql_ary['group_rank'])
2393              {
2394                  remove_default_rank($group_id, $user_ary);
2395              }
2396   
2397              $sql = 'UPDATE ' . GROUPS_TABLE . '
2398                  SET ' . $db->sql_build_array('UPDATE', $sql_ary) . "
2399                  WHERE group_id = $group_id";
2400              $db->sql_query($sql);
2401   
2402              // Since we may update the name too, we need to do this on other tables too...
2403              $sql = 'UPDATE ' . MODERATOR_CACHE_TABLE . "
2404                  SET group_name = '" . $db->sql_escape($sql_ary['group_name']) . "'
2405                  WHERE group_id = $group_id";
2406              $db->sql_query($sql);
2407          }
2408          else
2409          {
2410              $sql = 'INSERT INTO ' . GROUPS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
2411              $db->sql_query($sql);
2412          }
2413   
2414          if (!$group_id)
2415          {
2416              $group_id = $db->sql_nextid();
2417              if (isset($sql_ary['group_avatar_type']) && $sql_ary['group_avatar_type'] == AVATAR_UPLOAD)
2418              {
2419                  group_correct_avatar($group_id, $sql_ary['group_avatar']);
2420              }
2421          }
2422   
2423          // Set user attributes
2424          $sql_ary = array();
2425          if (sizeof($group_attributes))
2426          {
2427              foreach ($attribute_ary as $attribute => $_type)
2428              {
2429                  if (isset($group_attributes[$attribute]) && !in_array($attribute, $group_only_ary))
2430                  {
2431                      // If we are about to set an avatar, we will not overwrite user avatars if no group avatar is set...
2432                      if (strpos($attribute, 'group_avatar') === 0 && !$group_attributes[$attribute])
2433                      {
2434                          continue;
2435                      }
2436   
2437                      $sql_ary[$attribute] = $group_attributes[$attribute];
2438                  }
2439              }
2440          }
2441   
2442          if (sizeof($sql_ary) && sizeof($user_ary))
2443          {
2444              group_set_user_default($group_id, $user_ary, $sql_ary);
2445          }
2446   
2447          $name = ($type == GROUP_SPECIAL) ? $user->lang['G_' . $name] : $name;
2448          add_log('admin', $log, $name);
2449   
2450          group_update_listings($group_id);
2451      }
2452   
2453      return (sizeof($error)) ? $error : false;
2454  }
2455   
2456   
2457  /**
2458  * Changes a group avatar's filename to conform to the naming scheme
2459  */
2460  function group_correct_avatar($group_id, $old_entry)
2461  {
2462      global $config, $db, $phpbb_root_path;
2463   
2464      $group_id        = (int)$group_id;
2465      $ext             = substr(strrchr($old_entry, '.'), 1);
2466      $old_filename     = get_avatar_filename($old_entry);
2467      $new_filename     = $config['avatar_salt'] . "_g$group_id.$ext";
2468      $new_entry         = 'g' . $group_id . '_' . substr(time(), -5) . ".$ext";
2469      
2470      $avatar_path = $phpbb_root_path . $config['avatar_path'];
2471      if (@rename($avatar_path . '/'. $old_filename, $avatar_path . '/' . $new_filename))
2472      {
2473          $sql = 'UPDATE ' . GROUPS_TABLE . '
2474              SET group_avatar = \'' . $db->sql_escape($new_entry) . "'
2475              WHERE group_id = $group_id";
2476          $db->sql_query($sql);
2477      }
2478  }
2479   
2480   
2481  /**
2482  * Remove avatar also for users not having the group as default
2483  */
2484  function avatar_remove_db($avatar_name)
2485  {
2486      global $config, $db;
2487      
2488      $sql = 'UPDATE ' . USERS_TABLE . "
2489          SET user_avatar = '',
2490          user_avatar_type = 0
2491          WHERE user_avatar = '" . $db->sql_escape($avatar_name) . '\'';
2492      $db->sql_query($sql);
2493  }
2494   
2495   
2496  /**
2497  * Group Delete
2498  */
2499  function group_delete($group_id, $group_name = false)
2500  {
2501      global $db, $phpbb_root_path, $phpEx;
2502   
2503      if (!$group_name)
2504      {
2505          $group_name = get_group_name($group_id);
2506      }
2507   
2508      $start = 0;
2509   
2510      do
2511      {
2512          $user_id_ary = $username_ary = array();
2513   
2514          // Batch query for group members, call group_user_del
2515          $sql = 'SELECT u.user_id, u.username
2516              FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . " u
2517              WHERE ug.group_id = $group_id
2518                  AND u.user_id = ug.user_id";
2519          $result = $db->sql_query_limit($sql, 200, $start);
2520   
2521          if ($row = $db->sql_fetchrow($result))
2522          {
2523              do
2524              {
2525                  $user_id_ary[] = $row['user_id'];
2526                  $username_ary[] = $row['username'];
2527   
2528                  $start++;
2529              }
2530              while ($row = $db->sql_fetchrow($result));
2531   
2532              group_user_del($group_id, $user_id_ary, $username_ary, $group_name);
2533          }
2534          else
2535          {
2536              $start = 0;
2537          }
2538          $db->sql_freeresult($result);
2539      }
2540      while ($start);
2541   
2542      // Delete group
2543      $sql = 'DELETE FROM ' . GROUPS_TABLE . "
2544          WHERE group_id = $group_id";
2545      $db->sql_query($sql);
2546   
2547      // Delete auth entries from the groups table
2548      $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . "
2549          WHERE group_id = $group_id";
2550      $db->sql_query($sql);
2551   
2552      // Re-cache moderators
2553      if (!function_exists('cache_moderators'))
2554      {
2555          include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
2556      }
2557   
2558      cache_moderators();
2559   
2560      add_log('admin', 'LOG_GROUP_DELETE', $group_name);
2561   
2562      // Return false - no error
2563      return false;
2564  }
2565   
2566  /**
2567  * Add user(s) to group
2568  *
2569  * @return mixed false if no errors occurred, else the user lang string for the relevant error, for example 'NO_USER'
2570  */
2571  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)
2572  {
2573      global $db, $auth;
2574   
2575      // We need both username and user_id info
2576      $result = user_get_id_name($user_id_ary, $username_ary);
2577   
2578      if (!sizeof($user_id_ary) || $result !== false)
2579      {
2580          return 'NO_USER';
2581      }
2582   
2583      // Remove users who are already members of this group
2584      $sql = 'SELECT user_id, group_leader
2585          FROM ' . USER_GROUP_TABLE . '
2586          WHERE ' . $db->sql_in_set('user_id', $user_id_ary) . "
2587              AND group_id = $group_id";
2588      $result = $db->sql_query($sql);
2589   
2590      $add_id_ary = $update_id_ary = array();
2591      while ($row = $db->sql_fetchrow($result))
2592      {
2593          $add_id_ary[] = (int) $row['user_id'];
2594   
2595          if ($leader && !$row['group_leader'])
2596          {
2597              $update_id_ary[] = (int) $row['user_id'];
2598          }
2599      }
2600      $db->sql_freeresult($result);
2601   
2602      // Do all the users exist in this group?
2603      $add_id_ary = array_diff($user_id_ary, $add_id_ary);
2604   
2605      // If we have no users
2606      if (!sizeof($add_id_ary) && !sizeof($update_id_ary))
2607      {
2608          return 'GROUP_USERS_EXIST';
2609      }
2610   
2611      $db->sql_transaction('begin');
2612   
2613      // Insert the new users
2614      if (sizeof($add_id_ary))
2615      {
2616          $sql_ary = array();
2617   
2618          foreach ($add_id_ary as $user_id)
2619          {
2620              $sql_ary[] = array(
2621                  'user_id'        => (int) $user_id,
2622                  'group_id'        => (int) $group_id,
2623                  'group_leader'    => (int) $leader,
2624                  'user_pending'    => (int) $pending,
2625              );
2626          }
2627   
2628          $db->sql_multi_insert(USER_GROUP_TABLE, $sql_ary);
2629      }
2630   
2631      if (sizeof($update_id_ary))
2632      {
2633          $sql = 'UPDATE ' . USER_GROUP_TABLE . '
2634              SET group_leader = 1
2635              WHERE ' . $db->sql_in_set('user_id', $update_id_ary) . "
2636                  AND group_id = $group_id";
2637          $db->sql_query($sql);
2638      }
2639   
2640      if ($default)
2641      {
2642          group_set_user_default($group_id, $user_id_ary, $group_attributes);
2643      }
2644   
2645      $db->sql_transaction('commit');
2646   
2647      // Clear permissions cache of relevant users
2648      $auth->acl_clear_prefetch($user_id_ary);
2649   
2650      if (!$group_name)
2651      {
2652          $group_name = get_group_name($group_id);
2653      }
2654   
2655      $log = ($leader) ? 'LOG_MODS_ADDED' : 'LOG_USERS_ADDED';
2656   
2657      add_log('admin', $log, $group_name, implode(', ', $username_ary));
2658   
2659      group_update_listings($group_id);
2660   
2661      // Return false - no error
2662      return false;
2663  }
2664   
2665  /**
2666  * Remove a user/s from a given group. When we remove users we update their
2667  * default group_id. We do this by examining which "special" groups they belong
2668  * to. The selection is made based on a reasonable priority system
2669  *
2670  * @return false if no errors occurred, else the user lang string for the relevant error, for example 'NO_USER'
2671  */
2672  function group_user_del($group_id, $user_id_ary = false, $username_ary = false, $group_name = false)
2673  {
2674      global $db, $auth;
2675   
2676      $group_order = array('ADMINISTRATORS', 'GLOBAL_MODERATORS', 'REGISTERED_COPPA', 'REGISTERED', 'BOTS', 'GUESTS');
2677   
2678      // We need both username and user_id info
2679      $result = user_get_id_name($user_id_ary, $username_ary);
2680   
2681      if (!sizeof($user_id_ary) || $result !== false)
2682      {
2683          return 'NO_USER';
2684      }
2685   
2686      $sql = 'SELECT *
2687          FROM ' . GROUPS_TABLE . '
2688          WHERE ' . $db->sql_in_set('group_name', $group_order);
2689      $result = $db->sql_query($sql);
2690   
2691      $group_order_id = $special_group_data = array();
2692      while ($row = $db->sql_fetchrow($result))
2693      {
2694          $group_order_id[$row['group_name']] = $row['group_id'];
2695   
2696          $special_group_data[$row['group_id']] = array(
2697              'group_colour'            => $row['group_colour'],
2698              'group_rank'                => $row['group_rank'],
2699          );
2700   
2701          // Only set the group avatar if one is defined...
2702          if ($row['group_avatar'])
2703          {
2704              $special_group_data[$row['group_id']] = array_merge($special_group_data[$row['group_id']], array(
2705                  'group_avatar'            => $row['group_avatar'],
2706                  'group_avatar_type'        => $row['group_avatar_type'],
2707                  'group_avatar_width'        => $row['group_avatar_width'],
2708                  'group_avatar_height'    => $row['group_avatar_height'])
2709              );
2710          }
2711      }
2712      $db->sql_freeresult($result);
2713   
2714      // 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
2715      $sql = 'SELECT user_id, group_id
2716          FROM ' . USERS_TABLE . '
2717          WHERE ' . $db->sql_in_set('user_id', $user_id_ary);
2718      $result = $db->sql_query($sql);
2719   
2720      $default_groups = array();
2721      while ($row = $db->sql_fetchrow($result))
2722      {
2723          $default_groups[$row['user_id']] = $row['group_id'];
2724      }
2725      $db->sql_freeresult($result);
2726   
2727      // What special group memberships exist for these users?
2728      $sql = 'SELECT g.group_id, g.group_name, ug.user_id
2729          FROM ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g
2730          WHERE ' . $db->sql_in_set('ug.user_id', $user_id_ary) . "
2731              AND g.group_id = ug.group_id
2732              AND g.group_id <> $group_id
2733              AND g.group_type = " . GROUP_SPECIAL . '
2734          ORDER BY ug.user_id, g.group_id';
2735      $result = $db->sql_query($sql);
2736   
2737      $temp_ary = array();
2738      while ($row = $db->sql_fetchrow($result))
2739      {
2740          if ($default_groups[$row['user_id']] == $group_id && (!isset($temp_ary[$row['user_id']]) || array_search($row['group_name'], $group_order) < $temp_ary[$row['user_id']]))
2741          {
2742              $temp_ary[$row['user_id']] = $row['group_id'];
2743          }
2744      }
2745      $db->sql_freeresult($result);
2746   
2747      $sql_where_ary = array();
2748      foreach ($temp_ary as $uid => $gid)
2749      {
2750          $sql_where_ary[$gid][] = $uid;
2751      }
2752      unset($temp_ary);
2753   
2754      foreach ($special_group_data as $gid => $default_data_ary)
2755      {
2756          if (isset($sql_where_ary[$gid]) && sizeof($sql_where_ary[$gid]))
2757          {
2758              remove_default_rank($group_id, $sql_where_ary[$gid]);
2759              remove_default_avatar($group_id, $sql_where_ary[$gid]);
2760              group_set_user_default($gid, $sql_where_ary[$gid], $default_data_ary);
2761          }
2762      }
2763      unset($special_group_data);
2764   
2765      $sql = 'DELETE FROM ' . USER_GROUP_TABLE . "
2766          WHERE group_id = $group_id
2767              AND " . $db->sql_in_set('user_id', $user_id_ary);
2768      $db->sql_query($sql);
2769   
2770      // Clear permissions cache of relevant users
2771      $auth->acl_clear_prefetch($user_id_ary);
2772   
2773      if (!$group_name)
2774      {
2775          $group_name = get_group_name($group_id);
2776      }
2777   
2778      $log = 'LOG_GROUP_REMOVE';
2779   
2780      add_log('admin', $log, $group_name, implode(', ', $username_ary));
2781   
2782      group_update_listings($group_id);
2783   
2784      // Return false - no error
2785      return false;
2786  }
2787   
2788   
2789  /**
2790  * Removes the group avatar of the default group from the users in user_ids who have that group as default.
2791  */
2792  function remove_default_avatar($group_id, $user_ids)
2793  {
2794      global $db;
2795   
2796      if (!is_array($user_ids))
2797      {
2798          $user_ids = array($user_ids);
2799      }
2800      if (empty($user_ids))
2801      {
2802          return false;
2803      }
2804   
2805      $user_ids = array_map('intval', $user_ids);
2806   
2807      $sql = 'SELECT *
2808          FROM ' . GROUPS_TABLE . '
2809          WHERE group_id = ' . (int)$group_id;
2810      $result = $db->sql_query($sql);
2811      if (!$row = $db->sql_fetchrow($result))
2812      {
2813          $db->sql_freeresult($result);
2814          return false;
2815      }
2816      $db->sql_freeresult($result);
2817      
2818      $sql = 'UPDATE ' . USERS_TABLE . "
2819          SET user_avatar = '',
2820              user_avatar_type = 0,
2821              user_avatar_width = 0,
2822              user_avatar_height = 0
2823          WHERE group_id = " . (int) $group_id . "
2824          AND user_avatar = '" . $db->sql_escape($row['group_avatar']) . "'
2825          AND " . $db->sql_in_set('user_id', $user_ids);
2826      
2827      $db->sql_query($sql);
2828  }
2829   
2830  /**
2831  * Removes the group rank of the default group from the users in user_ids who have that group as default.
2832  */
2833  function remove_default_rank($group_id, $user_ids)
2834  {
2835      global $db;
2836   
2837      if (!is_array($user_ids))
2838      {
2839          $user_ids = array($user_ids);
2840      }
2841      if (empty($user_ids))
2842      {
2843          return false;
2844      }
2845   
2846      $user_ids = array_map('intval', $user_ids);
2847   
2848      $sql = 'SELECT *
2849          FROM ' . GROUPS_TABLE . '
2850          WHERE group_id = ' . (int)$group_id;
2851      $result = $db->sql_query($sql);
2852      if (!$row = $db->sql_fetchrow($result))
2853      {
2854          $db->sql_freeresult($result);
2855          return false;
2856      }
2857      $db->sql_freeresult($result);
2858   
2859      $sql = 'UPDATE ' . USERS_TABLE . '
2860          SET user_rank = 0
2861          WHERE group_id = ' . (int)$group_id . '
2862          AND user_rank <> 0
2863          AND user_rank = ' . (int)$row['group_rank'] . '
2864          AND ' . $db->sql_in_set('user_id', $user_ids);
2865      $db->sql_query($sql);
2866  }
2867   
2868  /**
2869  * This is used to promote (to leader), demote or set as default a member/s
2870  */
2871  function group_user_attributes($action, $group_id, $user_id_ary = false, $username_ary = false, $group_name = false, $group_attributes = false)
2872  {
2873      global $db, $auth, $phpbb_root_path, $phpEx, $config;
2874   
2875      // We need both username and user_id info
2876      $result = user_get_id_name($user_id_ary, $username_ary);
2877   
2878      if (!sizeof($user_id_ary) || $result !== false)
2879      {
2880          return false;
2881      }
2882   
2883      if (!$group_name)
2884      {
2885          $group_name = get_group_name($group_id);
2886      }
2887   
2888      switch ($action)
2889      {
2890          case 'demote':
2891          case 'promote':
2892              $sql = 'UPDATE ' . USER_GROUP_TABLE . '
2893                  SET group_leader = ' . (($action == 'promote') ? 1 : 0) . "
2894                  WHERE group_id = $group_id
2895                      AND " . $db->sql_in_set('user_id', $user_id_ary);
2896              $db->sql_query($sql);
2897   
2898              $log = ($action == 'promote') ? 'LOG_GROUP_PROMOTED' : 'LOG_GROUP_DEMOTED';
2899          break;
2900   
2901          case 'approve':
2902              // Make sure we only approve those which are pending ;)
2903              $sql = 'SELECT u.user_id, u.user_email, u.username, u.username_clean, u.user_notify_type, u.user_jabber, u.user_lang
2904                  FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . ' ug
2905                  WHERE ug.group_id = ' . $group_id . '
2906                      AND ug.user_pending = 1
2907                      AND ug.user_id = u.user_id
2908                      AND ' . $db->sql_in_set('ug.user_id', $user_id_ary);
2909              $result = $db->sql_query($sql);
2910   
2911              $user_id_ary = $email_users = array();
2912              while ($row = $db->sql_fetchrow($result))
2913              {
2914                  $user_id_ary[] = $row['user_id'];
2915                  $email_users[] = $row;
2916              }
2917              $db->sql_freeresult($result);
2918   
2919              if (!sizeof($user_id_ary))
2920              {
2921                  return false;
2922              }
2923   
2924              $sql = 'UPDATE ' . USER_GROUP_TABLE . "
2925                  SET user_pending = 0
2926                  WHERE group_id = $group_id
2927                      AND " . $db->sql_in_set('user_id', $user_id_ary);
2928              $db->sql_query($sql);
2929   
2930              // Send approved email to users...
2931              include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
2932              $messenger = new messenger();
2933   
2934              foreach ($email_users as $row)
2935              {
2936                  $messenger->template('group_approved', $row['user_lang']);
2937   
2938                  $messenger->to($row['user_email'], $row['username']);
2939                  $messenger->im($row['user_jabber'], $row['username']);
2940   
2941                  $messenger->assign_vars(array(
2942                      'USERNAME'        => htmlspecialchars_decode($row['username']),
2943                      'GROUP_NAME'    => htmlspecialchars_decode($group_name),
2944                      'U_GROUP'        => generate_board_url() . "/ucp.$phpEx?i=groups&mode=membership")
2945                  );
2946   
2947                  $messenger->send($row['user_notify_type']);
2948              }
2949   
2950              $messenger->save_queue();
2951   
2952              $log = 'LOG_USERS_APPROVED';
2953          break;
2954   
2955          case 'default':
2956              $sql = 'SELECT user_id, group_id FROM ' . USERS_TABLE . '
2957                  WHERE ' . $db->sql_in_set('user_id', $user_id_ary, false, true);
2958              $result = $db->sql_query($sql);
2959   
2960              $groups = array();
2961              while ($row = $db->sql_fetchrow($result))
2962              {
2963                  if (!isset($groups[$row['group_id']]))
2964                  {
2965                      $groups[$row['group_id']] = array();
2966                  }
2967                  $groups[$row['group_id']][] = $row['user_id'];
2968              }
2969              $db->sql_freeresult($result);
2970   
2971              foreach ($groups as $gid => $uids)
2972              {
2973                  remove_default_rank($gid, $uids);
2974                  remove_default_avatar($gid, $uids);
2975              }
2976              group_set_user_default($group_id, $user_id_ary, $group_attributes);
2977              $log = 'LOG_GROUP_DEFAULTS';
2978          break;
2979      }
2980   
2981      // Clear permissions cache of relevant users
2982      $auth->acl_clear_prefetch($user_id_ary);
2983   
2984      add_log('admin', $log, $group_name, implode(', ', $username_ary));
2985   
2986      group_update_listings($group_id);
2987   
2988      return true;
2989  }
2990   
2991  /**
2992  * A small version of validate_username to check for a group name's existence. To be called directly.
2993  */
2994  function group_validate_groupname($group_id, $group_name)
2995  {
2996      global $config, $db;
2997   
2998      $group_name =  utf8_clean_string($group_name);
2999   
3000      if (!empty($group_id))
3001      {
3002          $sql = 'SELECT group_name
3003              FROM ' . GROUPS_TABLE . '
3004              WHERE group_id = ' . (int) $group_id;
3005          $result = $db->sql_query($sql);
3006          $row = $db->sql_fetchrow($result);
3007          $db->sql_freeresult($result);
3008   
3009          if (!$row)
3010          {
3011              return false;
3012          }
3013   
3014          $allowed_groupname = utf8_clean_string($row['group_name']);
3015   
3016          if ($allowed_groupname == $group_name)
3017          {
3018              return false;
3019          }
3020      }
3021   
3022      $sql = 'SELECT group_name
3023          FROM ' . GROUPS_TABLE . "
3024          WHERE LOWER(group_name) = '" . $db->sql_escape(utf8_strtolower($group_name)) . "'";
3025      $result = $db->sql_query($sql);
3026      $row = $db->sql_fetchrow($result);
3027      $db->sql_freeresult($result);
3028      
3029      if ($row)
3030      {
3031          return 'GROUP_NAME_TAKEN';
3032      }
3033   
3034      return false;
3035  }
3036   
3037  /**
3038  * Set users default group
3039  *
3040  * @private
3041  */
3042  function group_set_user_default($group_id, $user_id_ary, $group_attributes = false, $update_listing = false)
3043  {
3044      global $db;
3045   
3046      if (empty($user_id_ary))
3047      {
3048          return;
3049      }
3050   
3051      $attribute_ary = array(
3052          'group_colour'            => 'string',
3053          'group_rank'            => 'int',
3054          'group_avatar'            => 'string',
3055          'group_avatar_type'        => 'int',
3056          'group_avatar_width'    => 'int',
3057          'group_avatar_height'    => 'int',
3058      );
3059   
3060      $sql_ary = array(
3061          'group_id'        => $group_id
3062      );
3063   
3064      // Were group attributes passed to the function? If not we need to obtain them
3065      if ($group_attributes === false)
3066      {
3067          $sql = 'SELECT ' . implode(', ', array_keys($attribute_ary)) . '
3068              FROM ' . GROUPS_TABLE . "
3069              WHERE group_id = $group_id";
3070          $result = $db->sql_query($sql);
3071          $group_attributes = $db->sql_fetchrow($result);
3072          $db->sql_freeresult($result);
3073      }
3074   
3075      foreach ($attribute_ary as $attribute => $type)
3076      {
3077          if (isset($group_attributes[$attribute]))
3078          {
3079              // 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
3080              if ((strpos($attribute, 'group_avatar') === 0 || strpos($attribute, 'group_rank') === 0) && !$group_attributes[$attribute])
3081              {
3082                  continue;
3083              }
3084   
3085              settype($group_attributes[$attribute], $type);
3086              $sql_ary[str_replace('group_', 'user_', $attribute)] = $group_attributes[$attribute];
3087          }
3088      }
3089   
3090      // Before we update the user attributes, we will make a list of those having now the group avatar assigned
3091      if (in_array('user_avatar', array_keys($sql_ary)))
3092      {
3093          // Ok, get the original avatar data from users having an uploaded one (we need to remove these from the filesystem)
3094          $sql = 'SELECT user_id, group_id, user_avatar
3095              FROM ' . USERS_TABLE . '
3096              WHERE ' . $db->sql_in_set('user_id', $user_id_ary) . '
3097                  AND user_avatar_type = ' . AVATAR_UPLOAD;
3098          $result = $db->sql_query($sql);
3099   
3100          while ($row = $db->sql_fetchrow($result))
3101          {
3102              avatar_delete('user', $row);
3103          }
3104          $db->sql_freeresult($result);
3105      }
3106      else
3107      {
3108          unset($sql_ary['user_avatar_type']);
3109          unset($sql_ary['user_avatar_height']);
3110          unset($sql_ary['user_avatar_width']);
3111      }
3112   
3113      $sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
3114          WHERE ' . $db->sql_in_set('user_id', $user_id_ary);
3115      $db->sql_query($sql);
3116   
3117      if (in_array('user_colour', array_keys($sql_ary)))
3118      {
3119          // Update any cached colour information for these users
3120          $sql = 'UPDATE ' . FORUMS_TABLE . " SET forum_last_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "'
3121              WHERE " . $db->sql_in_set('forum_last_poster_id', $user_id_ary);
3122          $db->sql_query($sql);
3123   
3124          $sql = 'UPDATE ' . TOPICS_TABLE . " SET topic_first_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "'
3125              WHERE " . $db->sql_in_set('topic_poster', $user_id_ary);
3126          $db->sql_query($sql);
3127   
3128          $sql = 'UPDATE ' . TOPICS_TABLE . " SET topic_last_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "'
3129              WHERE " . $db->sql_in_set('topic_last_poster_id', $user_id_ary);
3130          $db->sql_query($sql);
3131   
3132          global $config;
3133   
3134          if (in_array($config['newest_user_id'], $user_id_ary))
3135          {
3136              set_config('newest_user_colour', $sql_ary['user_colour'], true);
3137          }
3138      }
3139   
3140      if ($update_listing)
3141      {
3142          group_update_listings($group_id);
3143      }
3144  }
3145   
3146  /**
3147  * Get group name
3148  */
3149  function get_group_name($group_id)
3150  {
3151      global $db, $user;
3152   
3153      $sql = 'SELECT group_name, group_type
3154          FROM ' . GROUPS_TABLE . '
3155          WHERE group_id = ' . (int) $group_id;
3156      $result = $db->sql_query($sql);
3157      $row = $db->sql_fetchrow($result);
3158      $db->sql_freeresult($result);
3159   
3160      if (!$row)
3161      {
3162          return '';
3163      }
3164   
3165      return ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
3166  }
3167   
3168  /**
3169  * Obtain either the members of a specified group, the groups the specified user is subscribed to
3170  * or checking if a specified user is in a specified group. This function does not return pending memberships.
3171  *
3172  * Note: Never use this more than once... first group your users/groups
3173  */
3174  function group_memberships($group_id_ary = false, $user_id_ary = false, $return_bool = false)
3175  {
3176      global $db;
3177   
3178      if (!$group_id_ary && !$user_id_ary)
3179      {
3180          return true;
3181      }
3182   
3183      if ($user_id_ary)
3184      {
3185          $user_id_ary = (!is_array($user_id_ary)) ? array($user_id_ary) : $user_id_ary;
3186      }
3187   
3188      if ($group_id_ary)
3189      {
3190          $group_id_ary = (!is_array($group_id_ary)) ? array($group_id_ary) : $group_id_ary;
3191      }
3192   
3193      $sql = 'SELECT ug.*, u.username, u.username_clean, u.user_email
3194          FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . ' u
3195          WHERE ug.user_id = u.user_id
3196              AND ug.user_pending = 0 AND ';
3197   
3198      if ($group_id_ary)
3199      {
3200          $sql .= ' ' . $db->sql_in_set('ug.group_id', $group_id_ary);
3201      }
3202   
3203      if ($user_id_ary)
3204      {
3205          $sql .= ($group_id_ary) ? ' AND ' : ' ';
3206          $sql .= $db->sql_in_set('ug.user_id', $user_id_ary);
3207      }
3208   
3209      $result = ($return_bool) ? $db->sql_query_limit($sql, 1) : $db->sql_query($sql);
3210   
3211      $row = $db->sql_fetchrow($result);
3212   
3213      if ($return_bool)
3214      {
3215          $db->sql_freeresult($result);
3216          return ($row) ? true : false;
3217      }
3218   
3219      if (!$row)
3220      {
3221          return false;
3222      }
3223   
3224      $return = array();
3225   
3226      do
3227      {
3228          $return[] = $row;
3229      }
3230      while ($row = $db->sql_fetchrow($result));
3231   
3232      $db->sql_freeresult($result);
3233   
3234      return $return;
3235  }
3236   
3237  /**
3238  * Re-cache moderators and foes if group has a_ or m_ permissions
3239  */
3240  function group_update_listings($group_id)
3241  {
3242      global $auth;
3243   
3244      $hold_ary = $auth->acl_group_raw_data($group_id, array('a_', 'm_'));
3245   
3246      if (!sizeof($hold_ary))
3247      {
3248          return;
3249      }
3250   
3251      $mod_permissions = $admin_permissions = false;
3252   
3253      foreach ($hold_ary as $g_id => $forum_ary)
3254      {
3255          foreach ($forum_ary as $forum_id => $auth_ary)
3256          {
3257              foreach ($auth_ary as $auth_option => $setting)
3258              {
3259                  if ($mod_permissions && $admin_permissions)
3260                  {
3261                      break 3;
3262                  }
3263   
3264                  if ($setting != ACL_YES)
3265                  {
3266                      continue;
3267                  }
3268   
3269                  if ($auth_option == 'm_')
3270                  {
3271                      $mod_permissions = true;
3272                  }
3273   
3274                  if ($auth_option == 'a_')
3275                  {
3276                      $admin_permissions = true;
3277                  }
3278              }
3279          }
3280      }
3281   
3282      if ($mod_permissions)
3283      {
3284          if (!function_exists('cache_moderators'))
3285          {
3286              global $phpbb_root_path, $phpEx;
3287              include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
3288          }
3289          cache_moderators();
3290      }
3291   
3292      if ($mod_permissions || $admin_permissions)
3293      {
3294          if (!function_exists('update_foes'))
3295          {
3296              global $phpbb_root_path, $phpEx;
3297              include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
3298          }
3299          update_foes(array($group_id));
3300      }
3301  }
3302   
3303  ?>