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  ?>