Guest User

function_user.php

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