This week only. Pastebin PRO Accounts Christmas Special! Don't miss out!Want more features on Pastebin? Sign Up, it's FREE!
Guest

RMcGirr83

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