Advertisement
Guest User

RMcGirr83

a guest
Jan 22nd, 2010
326
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 97.42 KB | None | 0 0
  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. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement