示例#1
0
/**
 * Allow the change or view of profiles...
 *
 * @param array $post_errors = array()
 */
function ModifyProfile($post_errors = array())
{
    global $txt, $scripturl, $user_info, $context, $sourcedir, $user_profile, $cur_profile;
    global $modSettings, $memberContext, $profile_vars, $smcFunc, $post_errors, $options, $user_settings;
    // Don't reload this as we may have processed error strings.
    if (empty($post_errors)) {
        loadLanguage('Profile+Drafts');
    }
    loadTemplate('Profile');
    require_once $sourcedir . '/Subs-Menu.php';
    // Did we get the user by name...
    if (isset($_REQUEST['user'])) {
        $memberResult = loadMemberData($_REQUEST['user'], true, 'profile');
    } elseif (!empty($_REQUEST['u'])) {
        $memberResult = loadMemberData((int) $_REQUEST['u'], false, 'profile');
    } else {
        $memberResult = loadMemberData($user_info['id'], false, 'profile');
    }
    // Check if loadMemberData() has returned a valid result.
    if (!is_array($memberResult)) {
        fatal_lang_error('not_a_user', false);
    }
    // If all went well, we have a valid member ID!
    list($memID) = $memberResult;
    $context['id_member'] = $memID;
    $cur_profile = $user_profile[$memID];
    // Let's have some information about this member ready, too.
    loadMemberContext($memID);
    $context['member'] = $memberContext[$memID];
    // Is this the profile of the user himself or herself?
    $context['user']['is_owner'] = $memID == $user_info['id'];
    /* Define all the sections within the profile area!
    		We start by defining the permission required - then SMF takes this and turns it into the relevant context ;)
    		Possible fields:
    			For Section:
    				string $title:		Section title.
    				array $areas:		Array of areas within this section.
    
    			For Areas:
    				string $label:		Text string that will be used to show the area in the menu.
    				string $file:		Optional text string that may contain a file name that's needed for inclusion in order to display the area properly.
    				string $custom_url:	Optional href for area.
    				string $function:	Function to execute for this section.
    				bool $enabled:		Should area be shown?
    				string $sc:		Session check validation to do on save - note without this save will get unset - if set.
    				bool $hidden:		Does this not actually appear on the menu?
    				bool $password:		Whether to require the user's password in order to save the data in the area.
    				array $subsections:	Array of subsections, in order of appearance.
    				array $permission:	Array of permissions to determine who can access this area. Should contain arrays $own and $any.
    	*/
    $profile_areas = array('info' => array('title' => $txt['profileInfo'], 'areas' => array('summary' => array('label' => $txt['summary'], 'file' => 'Profile-View.php', 'function' => 'summary', 'permission' => array('own' => 'profile_view_own', 'any' => 'profile_view_any')), 'statistics' => array('label' => $txt['statPanel'], 'file' => 'Profile-View.php', 'function' => 'statPanel', 'permission' => array('own' => 'profile_view_own', 'any' => 'profile_view_any')), 'showposts' => array('label' => $txt['showPosts'], 'file' => 'Profile-View.php', 'function' => 'showPosts', 'subsections' => array('messages' => array($txt['showMessages'], array('profile_view_own', 'profile_view_any')), 'topics' => array($txt['showTopics'], array('profile_view_own', 'profile_view_any')), 'attach' => array($txt['showAttachments'], array('profile_view_own', 'profile_view_any'))), 'permission' => array('own' => 'profile_view_own', 'any' => 'profile_view_any')), 'showdrafts' => array('label' => $txt['drafts_show'], 'file' => 'Drafts.php', 'function' => 'showProfileDrafts', 'enabled' => !empty($modSettings['drafts_enabled']) && $context['user']['is_owner'], 'permission' => array('own' => 'profile_view_own', 'any' => array())), 'permissions' => array('label' => $txt['showPermissions'], 'file' => 'Profile-View.php', 'function' => 'showPermissions', 'permission' => array('own' => 'manage_permissions', 'any' => 'manage_permissions')), 'tracking' => array('label' => $txt['trackUser'], 'file' => 'Profile-View.php', 'function' => 'tracking', 'subsections' => array('activity' => array($txt['trackActivity'], 'moderate_forum'), 'ip' => array($txt['trackIP'], 'moderate_forum'), 'edits' => array($txt['trackEdits'], 'moderate_forum'), 'logins' => array($txt['trackLogins'], array('profile_view_own', 'moderate_forum'))), 'permission' => array('own' => 'moderate_forum', 'any' => 'moderate_forum')), 'viewwarning' => array('label' => $txt['profile_view_warnings'], 'enabled' => in_array('w', $context['admin_features']) && $modSettings['warning_settings'][0] == 1 && $cur_profile['warning'] && (!empty($modSettings['warning_show']) && ($context['user']['is_owner'] || $modSettings['warning_show'] == 2)), 'file' => 'Profile-View.php', 'function' => 'viewWarning', 'permission' => array('own' => 'profile_view_own', 'any' => 'issue_warning')))), 'edit_profile' => array('title' => $txt['profileEdit'], 'areas' => array('account' => array('label' => $txt['account'], 'file' => 'Profile-Modify.php', 'function' => 'account', 'enabled' => $context['user']['is_admin'] || $cur_profile['id_group'] != 1 && !in_array(1, explode(',', $cur_profile['additional_groups'])), 'sc' => 'post', 'token' => 'profile-ac%u', 'password' => true, 'permission' => array('own' => array('profile_identity_any', 'profile_identity_own', 'manage_membergroups'), 'any' => array('profile_identity_any', 'manage_membergroups'))), 'forumprofile' => array('label' => $txt['forumprofile'], 'file' => 'Profile-Modify.php', 'function' => 'forumProfile', 'sc' => 'post', 'token' => 'profile-fp%u', 'permission' => array('own' => array('profile_extra_any', 'profile_extra_own', 'profile_title_own', 'profile_title_any'), 'any' => array('profile_extra_any', 'profile_title_any'))), 'theme' => array('label' => $txt['theme'], 'file' => 'Profile-Modify.php', 'function' => 'theme', 'sc' => 'post', 'token' => 'profile-th%u', 'permission' => array('own' => array('profile_extra_any', 'profile_extra_own'), 'any' => array('profile_extra_any'))), 'authentication' => array('label' => $txt['authentication'], 'file' => 'Profile-Modify.php', 'function' => 'authentication', 'enabled' => !empty($modSettings['enableOpenID']) || !empty($cur_profile['openid_uri']), 'sc' => 'post', 'token' => 'profile-au%u', 'hidden' => empty($modSettings['enableOpenID']) && empty($cur_profile['openid_uri']), 'password' => true, 'permission' => array('own' => array('profile_identity_any', 'profile_identity_own'), 'any' => array('profile_identity_any'))), 'notification' => array('label' => $txt['notification'], 'file' => 'Profile-Modify.php', 'function' => 'notification', 'sc' => 'post', 'token' => 'profile-nt%u', 'permission' => array('own' => array('profile_extra_any', 'profile_extra_own'), 'any' => array('profile_extra_any'))), 'pmprefs' => array('label' => $txt['pmprefs'], 'file' => 'Profile-Modify.php', 'function' => 'pmprefs', 'enabled' => allowedTo(array('profile_extra_own', 'profile_extra_any')), 'sc' => 'post', 'token' => 'profile-pm%u', 'permission' => array('own' => array('pm_read'), 'any' => array('profile_extra_any'))), 'ignoreboards' => array('label' => $txt['ignoreboards'], 'file' => 'Profile-Modify.php', 'function' => 'ignoreboards', 'enabled' => !empty($modSettings['allow_ignore_boards']), 'sc' => 'post', 'token' => 'profile-ib%u', 'permission' => array('own' => array('profile_extra_any', 'profile_extra_own'), 'any' => array('profile_extra_any'))), 'lists' => array('label' => $txt['editBuddyIgnoreLists'], 'file' => 'Profile-Modify.php', 'function' => 'editBuddyIgnoreLists', 'enabled' => !empty($modSettings['enable_buddylist']) && $context['user']['is_owner'], 'sc' => 'post', 'token' => 'profile-bl%u', 'subsections' => array('buddies' => array($txt['editBuddies']), 'ignore' => array($txt['editIgnoreList'])), 'permission' => array('own' => array('profile_extra_any', 'profile_extra_own'), 'any' => array())), 'groupmembership' => array('label' => $txt['groupmembership'], 'file' => 'Profile-Modify.php', 'function' => 'groupMembership', 'enabled' => !empty($modSettings['show_group_membership']) && $context['user']['is_owner'], 'sc' => 'request', 'token' => 'profile-gm%u', 'token_type' => 'request', 'permission' => array('own' => array('profile_view_own'), 'any' => array('manage_membergroups'))))), 'profile_action' => array('title' => $txt['profileAction'], 'areas' => array('sendpm' => array('label' => $txt['profileSendIm'], 'custom_url' => $scripturl . '?action=pm;sa=send', 'permission' => array('own' => array(), 'any' => array('pm_send'))), 'issuewarning' => array('label' => $txt['profile_issue_warning'], 'enabled' => in_array('w', $context['admin_features']) && $modSettings['warning_settings'][0] == 1 && (!$context['user']['is_owner'] || $context['user']['is_admin']), 'file' => 'Profile-Actions.php', 'function' => 'issueWarning', 'token' => 'profile-iw%u', 'enabled' => !$context['user']['is_owner'], 'permission' => array('own' => array('issue_warning'), 'any' => array('issue_warning'))), 'banuser' => array('label' => $txt['profileBanUser'], 'custom_url' => $scripturl . '?action=admin;area=ban;sa=add', 'enabled' => $cur_profile['id_group'] != 1 && !in_array(1, explode(',', $cur_profile['additional_groups'])), 'permission' => array('own' => array(), 'any' => array('manage_bans'))), 'subscriptions' => array('label' => $txt['subscriptions'], 'file' => 'Profile-Actions.php', 'function' => 'subscriptions', 'enabled' => !empty($modSettings['paid_enabled']), 'permission' => array('own' => array('profile_view_own'), 'any' => array('moderate_forum'))), 'deleteaccount' => array('label' => $txt['deleteAccount'], 'file' => 'Profile-Actions.php', 'function' => 'deleteAccount', 'sc' => 'post', 'token' => 'profile-da%u', 'password' => true, 'permission' => array('own' => array('profile_remove_any', 'profile_remove_own'), 'any' => array('profile_remove_any'))), 'activateaccount' => array('file' => 'Profile-Actions.php', 'function' => 'activateAccount', 'sc' => 'get', 'token' => 'profile-aa%u', 'select' => 'summary', 'permission' => array('own' => array(), 'any' => array('moderate_forum'))))));
    // Let them modify profile areas easily.
    call_integration_hook('integrate_profile_areas', array(&$profile_areas));
    // Do some cleaning ready for the menu function.
    $context['password_areas'] = array();
    $current_area = isset($_REQUEST['area']) ? $_REQUEST['area'] : '';
    foreach ($profile_areas as $section_id => $section) {
        // Do a bit of spring cleaning so to speak.
        foreach ($section['areas'] as $area_id => $area) {
            // If it said no permissions that meant it wasn't valid!
            if (empty($area['permission'][$context['user']['is_owner'] ? 'own' : 'any'])) {
                $profile_areas[$section_id]['areas'][$area_id]['enabled'] = false;
            } else {
                $profile_areas[$section_id]['areas'][$area_id]['permission'] = $area['permission'][$context['user']['is_owner'] ? 'own' : 'any'];
            }
            // Password required - only if not on OpenID.
            if (!empty($area['password'])) {
                $context['password_areas'][] = $area_id;
            }
        }
    }
    // Is there an updated message to show?
    if (isset($_GET['updated'])) {
        $context['profile_updated'] = $txt['profile_updated_own'];
    }
    // Set a few options for the menu.
    $menuOptions = array('disable_url_session_check' => true, 'current_area' => $current_area, 'extra_url_parameters' => array('u' => $context['id_member']));
    // Actually create the menu!
    $profile_include_data = createMenu($profile_areas, $menuOptions);
    // No menu means no access.
    if (!$profile_include_data && (!$user_info['is_guest'] || validateSession())) {
        fatal_lang_error('no_access', false);
    }
    // Make a note of the Unique ID for this menu.
    $context['profile_menu_id'] = $context['max_menu_id'];
    $context['profile_menu_name'] = 'menu_data_' . $context['profile_menu_id'];
    // Set the selected item - now it's been validated.
    $current_area = $profile_include_data['current_area'];
    $context['menu_item_selected'] = $current_area;
    // Before we go any further, let's work on the area we've said is valid. Note this is done here just in case we ever compromise the menu function in error!
    $context['completed_save'] = false;
    $context['do_preview'] = isset($_REQUEST['preview_signature']);
    $security_checks = array();
    $found_area = false;
    foreach ($profile_areas as $section_id => $section) {
        // Do a bit of spring cleaning so to speak.
        foreach ($section['areas'] as $area_id => $area) {
            // Is this our area?
            if ($current_area == $area_id) {
                // This can't happen - but is a security check.
                if (isset($section['enabled']) && $section['enabled'] == false || isset($area['enabled']) && $area['enabled'] == false) {
                    fatal_lang_error('no_access', false);
                }
                // Are we saving data in a valid area?
                if (isset($area['sc']) && (isset($_REQUEST['save']) || $context['do_preview'])) {
                    $security_checks['session'] = $area['sc'];
                    $context['completed_save'] = true;
                }
                // Do we need to perform a token check?
                if (!empty($area['token'])) {
                    $security_checks[isset($_REQUEST['save']) ? 'validateToken' : 'needsToken'] = $area['token'];
                    $token_name = $area['token'] !== true ? str_replace('%u', $context['id_member'], $area['token']) : 'profile-u' . $context['id_member'];
                    $token_type = isset($area['token_type']) && in_array($area['token_type'], array('request', 'post', 'get')) ? $area['token_type'] : 'post';
                }
                // Does this require session validating?
                if (!empty($area['validate']) || isset($_REQUEST['save']) && !$context['user']['is_owner']) {
                    $security_checks['validate'] = true;
                }
                // Permissions for good measure.
                if (!empty($profile_include_data['permission'])) {
                    $security_checks['permission'] = $profile_include_data['permission'];
                }
                // Either way got something.
                $found_area = true;
            }
        }
    }
    // Oh dear, some serious security lapse is going on here... we'll put a stop to that!
    if (!$found_area) {
        fatal_lang_error('no_access', false);
    }
    // Release this now.
    unset($profile_areas);
    // Now the context is setup have we got any security checks to carry out additional to that above?
    if (isset($security_checks['validateToken'])) {
        validateToken($token_name, $token_type);
    }
    if (isset($security_checks['session'])) {
        checkSession($security_checks['session']);
    }
    if (isset($security_checks['validate'])) {
        validateSession();
    }
    if (isset($security_checks['permission'])) {
        isAllowedTo($security_checks['permission']);
    }
    // Create a token if needed.
    if (isset($security_checks['needsToken']) || isset($security_checks['validateToken'])) {
        createToken($token_name, $token_type);
        $context['token_check'] = $token_name;
    }
    // File to include?
    if (isset($profile_include_data['file'])) {
        require_once $sourcedir . '/' . $profile_include_data['file'];
    }
    // Make sure that the area function does exist!
    if (!isset($profile_include_data['function']) || !function_exists($profile_include_data['function'])) {
        destroyMenu();
        fatal_lang_error('no_access', false);
    }
    // Build the link tree.
    $context['linktree'][] = array('url' => $scripturl . '?action=profile' . ($memID != $user_info['id'] ? ';u=' . $memID : ''), 'name' => sprintf($txt['profile_of_username'], $context['member']['name']));
    if (!empty($profile_include_data['label'])) {
        $context['linktree'][] = array('url' => $scripturl . '?action=profile' . ($memID != $user_info['id'] ? ';u=' . $memID : '') . ';area=' . $profile_include_data['current_area'], 'name' => $profile_include_data['label']);
    }
    if (!empty($profile_include_data['current_subsection']) && $profile_include_data['subsections'][$profile_include_data['current_subsection']][0] != $profile_include_data['label']) {
        $context['linktree'][] = array('url' => $scripturl . '?action=profile' . ($memID != $user_info['id'] ? ';u=' . $memID : '') . ';area=' . $profile_include_data['current_area'] . ';sa=' . $profile_include_data['current_subsection'], 'name' => $profile_include_data['subsections'][$profile_include_data['current_subsection']][0]);
    }
    // Set the template for this area and add the profile layer.
    $context['sub_template'] = $profile_include_data['function'];
    $context['template_layers'][] = 'profile';
    // All the subactions that require a user password in order to validate.
    $check_password = $context['user']['is_owner'] && in_array($profile_include_data['current_area'], $context['password_areas']);
    $context['require_password'] = $check_password && empty($user_settings['openid_uri']);
    // If we're in wireless then we have a cut down template...
    if (WIRELESS && $context['sub_template'] == 'summary' && WIRELESS_PROTOCOL != 'wap') {
        $context['sub_template'] = WIRELESS_PROTOCOL . '_profile';
    }
    // These will get populated soon!
    $post_errors = array();
    $profile_vars = array();
    // Right - are we saving - if so let's save the old data first.
    if ($context['completed_save']) {
        // Clean up the POST variables.
        $_POST = htmltrim__recursive($_POST);
        $_POST = htmlspecialchars__recursive($_POST);
        if ($check_password) {
            // If we're using OpenID try to revalidate.
            if (!empty($user_settings['openid_uri'])) {
                require_once $sourcedir . '/Subs-OpenID.php';
                smf_openID_revalidate();
            } else {
                // You didn't even enter a password!
                if (trim($_POST['oldpasswrd']) == '') {
                    $post_errors[] = 'no_password';
                }
                // Since the password got modified due to all the $_POST cleaning, lets undo it so we can get the correct password
                $_POST['oldpasswrd'] = un_htmlspecialchars($_POST['oldpasswrd']);
                // Does the integration want to check passwords?
                $good_password = in_array(true, call_integration_hook('integrate_verify_password', array($cur_profile['member_name'], $_POST['oldpasswrd'], false)), true);
                // Bad password!!!
                if (!$good_password && $user_info['passwd'] != sha1(strtolower($user_profile[$memID]['member_name']) . un_htmlspecialchars(stripslashes($_POST['oldpasswrd'])))) {
                    $post_errors[] = 'bad_password';
                }
                // Warn other elements not to jump the gun and do custom changes!
                if (in_array('bad_password', $post_errors)) {
                    $context['password_auth_failed'] = true;
                }
            }
        }
        // Change the IP address in the database.
        if ($context['user']['is_owner']) {
            $profile_vars['member_ip'] = $user_info['ip'];
        }
        // Now call the sub-action function...
        if ($current_area == 'activateaccount') {
            if (empty($post_errors)) {
                activateAccount($memID);
            }
        } elseif ($current_area == 'deleteaccount') {
            if (empty($post_errors)) {
                deleteAccount2($memID);
                redirectexit();
            }
        } elseif ($current_area == 'groupmembership' && empty($post_errors)) {
            $msg = groupMembership2($profile_vars, $post_errors, $memID);
            // Whatever we've done, we have nothing else to do here...
            redirectexit('action=profile' . ($context['user']['is_owner'] ? '' : ';u=' . $memID) . ';area=groupmembership' . (!empty($msg) ? ';msg=' . $msg : ''));
        } elseif ($current_area == 'authentication') {
            authentication($memID, true);
        } elseif (in_array($current_area, array('account', 'forumprofile', 'theme', 'pmprefs'))) {
            saveProfileFields();
        } else {
            $force_redirect = true;
            // Ensure we include this.
            require_once $sourcedir . '/Profile-Modify.php';
            saveProfileChanges($profile_vars, $post_errors, $memID);
        }
        call_integration_hook('integrate_profile_save', array($profile_vars, $post_errors, $memID));
        // There was a problem, let them try to re-enter.
        if (!empty($post_errors)) {
            // Load the language file so we can give a nice explanation of the errors.
            loadLanguage('Errors');
            $context['post_errors'] = $post_errors;
        } elseif (!empty($profile_vars)) {
            // If we've changed the password, notify any integration that may be listening in.
            if (isset($profile_vars['passwd'])) {
                call_integration_hook('integrate_reset_pass', array($cur_profile['member_name'], $cur_profile['member_name'], $_POST['passwrd2']));
            }
            updateMemberData($memID, $profile_vars);
            // What if this is the newest member?
            if ($modSettings['latestMember'] == $memID) {
                updateStats('member');
            } elseif (isset($profile_vars['real_name'])) {
                updateSettings(array('memberlist_updated' => time()));
            }
            // If the member changed his/her birthdate, update calendar statistics.
            if (isset($profile_vars['birthdate']) || isset($profile_vars['real_name'])) {
                updateSettings(array('calendar_updated' => time()));
            }
            // Anything worth logging?
            if (!empty($context['log_changes']) && !empty($modSettings['modlog_enabled'])) {
                $log_changes = array();
                require_once $sourcedir . '/Logging.php';
                foreach ($context['log_changes'] as $k => $v) {
                    $log_changes[] = array('action' => $k, 'log_type' => 'user', 'extra' => array_merge($v, array('applicator' => $user_info['id'], 'member_affected' => $memID)));
                }
                logActions($log_changes);
            }
            // Have we got any post save functions to execute?
            if (!empty($context['profile_execute_on_save'])) {
                foreach ($context['profile_execute_on_save'] as $saveFunc) {
                    $saveFunc();
                }
            }
            // Let them know it worked!
            $context['profile_updated'] = $context['user']['is_owner'] ? $txt['profile_updated_own'] : sprintf($txt['profile_updated_else'], $cur_profile['member_name']);
            // Invalidate any cached data.
            cache_put_data('member_data-profile-' . $memID, null, 0);
        }
    }
    // Have some errors for some reason?
    if (!empty($post_errors)) {
        // Set all the errors so the template knows what went wrong.
        foreach ($post_errors as $error_type) {
            $context['modify_error'][$error_type] = true;
        }
    } elseif (!empty($profile_vars) && $context['user']['is_owner'] && !$context['do_preview']) {
        redirectexit('action=profile;area=' . $current_area . ';updated');
    } elseif (!empty($force_redirect)) {
        redirectexit('action=profile' . ($context['user']['is_owner'] ? '' : ';u=' . $memID) . ';area=' . $current_area);
    }
    // Call the appropriate subaction function.
    $profile_include_data['function']($memID);
    // Set the page title if it's not already set...
    if (!isset($context['page_title'])) {
        $context['page_title'] = $txt['profile'] . (isset($txt[$current_area]) ? ' - ' . $txt[$current_area] : '');
    }
}
示例#2
0
/**
 * Save any changes to the custom profile fields
 *
 * @param int $memID
 * @param string $area
 * @param bool $sanitize = true
 */
function makeCustomFieldChanges($memID, $area, $sanitize = true)
{
    global $context, $user_profile, $user_info, $modSettings;
    $db = database();
    if ($sanitize && isset($_POST['customfield'])) {
        $_POST['customfield'] = htmlspecialchars__recursive($_POST['customfield']);
    }
    $where = $area == 'register' ? 'show_reg != 0' : 'show_profile = {string:area}';
    // Load the fields we are saving too - make sure we save valid data (etc).
    $request = $db->query('', '
		SELECT col_name, field_name, field_desc, field_type, field_length, field_options, default_value, show_reg, mask, private
		FROM {db_prefix}custom_fields
		WHERE ' . $where . '
			AND active = {int:is_active}', array('is_active' => 1, 'area' => $area));
    $changes = array();
    $log_changes = array();
    while ($row = $db->fetch_assoc($request)) {
        /* This means don't save if:
        			- The user is NOT an admin.
        			- The data is not freely viewable and editable by users.
        			- The data is not invisible to users but editable by the owner (or if it is the user is not the owner)
        			- The area isn't registration, and if it is that the field is not suppossed to be shown there.
        		*/
        if ($row['private'] != 0 && !allowedTo('admin_forum') && ($memID != $user_info['id'] || $row['private'] != 2) && ($area != 'register' || $row['show_reg'] == 0)) {
            continue;
        }
        // Validate the user data.
        if ($row['field_type'] == 'check') {
            $value = isset($_POST['customfield'][$row['col_name']]) ? 1 : 0;
        } elseif ($row['field_type'] == 'select' || $row['field_type'] == 'radio') {
            $value = $row['default_value'];
            foreach (explode(',', $row['field_options']) as $k => $v) {
                if (isset($_POST['customfield'][$row['col_name']]) && $_POST['customfield'][$row['col_name']] == $k) {
                    $value = $v;
                }
            }
        } else {
            $value = isset($_POST['customfield'][$row['col_name']]) ? $_POST['customfield'][$row['col_name']] : '';
            if ($row['field_length']) {
                $value = Util::substr($value, 0, $row['field_length']);
            }
            // Any masks?
            if ($row['field_type'] == 'text' && !empty($row['mask']) && $row['mask'] != 'none') {
                // @todo We never error on this - just ignore it at the moment...
                if ($row['mask'] == 'email' && (preg_match('~^[0-9A-Za-z=_+\\-/][0-9A-Za-z=_\'+\\-/\\.]*@[\\w\\-]+(\\.[\\w\\-]+)*(\\.[\\w]{2,6})$~', $value) === 0 || strlen($value) > 255)) {
                    $value = '';
                } elseif ($row['mask'] == 'number') {
                    $value = (int) $value;
                } elseif (substr($row['mask'], 0, 5) == 'regex' && trim($value) != '' && preg_match(substr($row['mask'], 5), $value) === 0) {
                    $value = '';
                }
            }
        }
        // Did it change?
        if (!isset($user_profile[$memID]['options'][$row['col_name']]) || $user_profile[$memID]['options'][$row['col_name']] !== $value) {
            $log_changes[] = array('action' => 'customfield_' . $row['col_name'], 'log_type' => 'user', 'extra' => array('previous' => !empty($user_profile[$memID]['options'][$row['col_name']]) ? $user_profile[$memID]['options'][$row['col_name']] : '', 'new' => $value, 'applicator' => $user_info['id'], 'member_affected' => $memID));
            $changes[] = array($row['col_name'], $value, $memID);
            $user_profile[$memID]['options'][$row['col_name']] = $value;
        }
    }
    $db->free_result($request);
    call_integration_hook('integrate_save_custom_profile_fields', array(&$changes, &$log_changes, $memID, $area, $sanitize));
    // Make those changes!
    if (!empty($changes) && empty($context['password_auth_failed'])) {
        $db->insert('replace', '{db_prefix}custom_fields_data', array('variable' => 'string-255', 'value' => 'string-65534', 'id_member' => 'int'), $changes, array('variable', 'id_member'));
        if (!empty($log_changes) && !empty($modSettings['modlog_enabled'])) {
            logActions($log_changes);
        }
    }
}
示例#3
0
/**
 * This function logs a single action in the respective log. (database log)
 *
 * - You should use {@link logActions()} instead if you have multiple entries to add
 * @example logAction('remove', array('starter' => $id_member_started));
 *
 * @param string $action
 * @param string[] $extra = array()
 * @param string $log_type options: 'moderate', 'admin', ...etc.
 */
function logAction($action, $extra = array(), $log_type = 'moderate')
{
    // Set up the array and pass through to logActions
    return logActions(array(array('action' => $action, 'log_type' => $log_type, 'extra' => $extra)));
}
示例#4
0
 /**
  * Allow the change or view of profiles.
  * Loads the profile menu.
  *
  * @see Action_Controller::action_index()
  */
 public function action_index()
 {
     global $txt, $scripturl, $user_info, $context, $user_profile, $cur_profile;
     global $modSettings, $memberContext, $profile_vars, $post_errors, $user_settings;
     // Don't reload this as we may have processed error strings.
     if (empty($post_errors)) {
         loadLanguage('Profile+Drafts');
     }
     loadTemplate('Profile');
     require_once SUBSDIR . '/Menu.subs.php';
     require_once SUBSDIR . '/Profile.subs.php';
     $memID = currentMemberID();
     $context['id_member'] = $memID;
     $cur_profile = $user_profile[$memID];
     // Let's have some information about this member ready, too.
     loadMemberContext($memID);
     $context['member'] = $memberContext[$memID];
     // Is this the profile of the user himself or herself?
     $context['user']['is_owner'] = $memID == $user_info['id'];
     /**
      * Define all the sections within the profile area!
      * We start by defining the permission required - then we take this and turn
      * it into the relevant context ;)
      *
      * Possible fields:
      *   For Section:
      *    - string $title: Section title.
      *    - array $areas:  Array of areas within this section.
      *
      *   For Areas:
      *    - string $label:      Text string that will be used to show the area in the menu.
      *    - string $file:       Optional text string that may contain a file name that's needed for inclusion in order to display the area properly.
      *    - string $custom_url: Optional href for area.
      *    - string $function:   Function to execute for this section.
      *    - bool $enabled:      Should area be shown?
      *    - string $sc:         Session check validation to do on save - note without this save will get unset - if set.
      *    - bool $hidden:       Does this not actually appear on the menu?
      *    - bool $password:     Whether to require the user's password in order to save the data in the area.
      *    - array $subsections: Array of subsections, in order of appearance.
      *    - array $permission:  Array of permissions to determine who can access this area. Should contain arrays $own and $any.
      */
     $profile_areas = array('info' => array('title' => $txt['profileInfo'], 'areas' => array('summary' => array('label' => $txt['summary'], 'file' => 'ProfileInfo.controller.php', 'controller' => 'ProfileInfo_Controller', 'function' => 'action_summary', 'token' => 'profile-aa%u', 'token_type' => 'get', 'permission' => array('own' => 'profile_view_own', 'any' => 'profile_view_any')), 'statistics' => array('label' => $txt['statPanel'], 'file' => 'ProfileInfo.controller.php', 'controller' => 'ProfileInfo_Controller', 'function' => 'action_statPanel', 'permission' => array('own' => 'profile_view_own', 'any' => 'profile_view_any')), 'showposts' => array('label' => $txt['showPosts'], 'file' => 'ProfileInfo.controller.php', 'controller' => 'ProfileInfo_Controller', 'function' => 'action_showPosts', 'subsections' => array('messages' => array($txt['showMessages'], array('profile_view_own', 'profile_view_any')), 'topics' => array($txt['showTopics'], array('profile_view_own', 'profile_view_any')), 'unwatchedtopics' => array($txt['showUnwatched'], array('profile_view_own', 'profile_view_any'), 'enabled' => $modSettings['enable_unwatch'] && $context['user']['is_owner']), 'attach' => array($txt['showAttachments'], array('profile_view_own', 'profile_view_any'))), 'permission' => array('own' => 'profile_view_own', 'any' => 'profile_view_any')), 'showdrafts' => array('label' => $txt['drafts_show'], 'file' => 'Draft.controller.php', 'controller' => 'Draft_Controller', 'function' => 'action_showProfileDrafts', 'enabled' => !empty($modSettings['drafts_enabled']) && $context['user']['is_owner'], 'permission' => array('own' => 'profile_view_own', 'any' => array())), 'showlikes' => array('label' => $txt['likes_show'], 'file' => 'Likes.controller.php', 'controller' => 'Likes_Controller', 'function' => 'action_showProfileLikes', 'enabled' => !empty($modSettings['likes_enabled']) && $context['user']['is_owner'], 'subsections' => array('given' => array($txt['likes_given'], array('profile_view_own')), 'received' => array($txt['likes_received'], array('profile_view_own'))), 'permission' => array('own' => 'profile_view_own', 'any' => array())), 'permissions' => array('label' => $txt['showPermissions'], 'file' => 'ProfileInfo.controller.php', 'controller' => 'ProfileInfo_Controller', 'function' => 'action_showPermissions', 'permission' => array('own' => 'manage_permissions', 'any' => 'manage_permissions')), 'history' => array('label' => $txt['history'], 'file' => 'ProfileHistory.controller.php', 'controller' => 'ProfileHistory_Controller', 'function' => 'action_index', 'subsections' => array('activity' => array($txt['trackActivity'], 'moderate_forum'), 'ip' => array($txt['trackIP'], 'moderate_forum'), 'edits' => array($txt['trackEdits'], 'moderate_forum'), 'logins' => array($txt['trackLogins'], array('profile_view_own', 'moderate_forum'))), 'permission' => array('own' => 'moderate_forum', 'any' => 'moderate_forum')), 'viewwarning' => array('label' => $txt['profile_view_warnings'], 'enabled' => in_array('w', $context['admin_features']) && !empty($modSettings['warning_enable']) && $cur_profile['warning'] && (!empty($modSettings['warning_show']) && ($context['user']['is_owner'] || $modSettings['warning_show'] == 2)), 'file' => 'ProfileInfo.controller.php', 'controller' => 'ProfileInfo_Controller', 'function' => 'action_viewWarning', 'permission' => array('own' => 'profile_view_own', 'any' => 'issue_warning')))), 'edit_profile' => array('title' => $txt['profileEdit'], 'areas' => array('account' => array('label' => $txt['account'], 'file' => 'ProfileOptions.controller.php', 'controller' => 'ProfileOptions_Controller', 'function' => 'action_account', 'enabled' => $context['user']['is_admin'] || $cur_profile['id_group'] != 1 && !in_array(1, explode(',', $cur_profile['additional_groups'])), 'sc' => 'post', 'token' => 'profile-ac%u', 'password' => true, 'permission' => array('own' => array('profile_identity_any', 'profile_identity_own', 'manage_membergroups'), 'any' => array('profile_identity_any', 'manage_membergroups'))), 'forumprofile' => array('label' => $txt['forumprofile'], 'file' => 'ProfileOptions.controller.php', 'controller' => 'ProfileOptions_Controller', 'function' => 'action_forumProfile', 'sc' => 'post', 'token' => 'profile-fp%u', 'permission' => array('own' => array('profile_extra_any', 'profile_extra_own', 'profile_title_own', 'profile_title_any'), 'any' => array('profile_extra_any', 'profile_title_any'))), 'theme' => array('label' => $txt['theme'], 'file' => 'ProfileOptions.controller.php', 'controller' => 'ProfileOptions_Controller', 'function' => 'action_themepick', 'sc' => 'post', 'token' => 'profile-th%u', 'permission' => array('own' => array('profile_extra_any', 'profile_extra_own'), 'any' => array('profile_extra_any'))), 'authentication' => array('label' => $txt['authentication'], 'file' => 'ProfileOptions.controller.php', 'controller' => 'ProfileOptions_Controller', 'function' => 'action_authentication', 'enabled' => !empty($modSettings['enableOpenID']) || !empty($cur_profile['openid_uri']), 'sc' => 'post', 'token' => 'profile-au%u', 'hidden' => empty($modSettings['enableOpenID']) && empty($cur_profile['openid_uri']), 'password' => true, 'permission' => array('own' => array('profile_identity_any', 'profile_identity_own'), 'any' => array('profile_identity_any'))), 'notification' => array('label' => $txt['notifications'], 'file' => 'ProfileOptions.controller.php', 'controller' => 'ProfileOptions_Controller', 'function' => 'action_notification', 'sc' => 'post', 'token' => 'profile-nt%u', 'permission' => array('own' => array('profile_extra_any', 'profile_extra_own'), 'any' => array('profile_extra_any'))), 'contactprefs' => array('label' => $txt['contactprefs'], 'file' => 'ProfileOptions.controller.php', 'controller' => 'ProfileOptions_Controller', 'function' => 'action_pmprefs', 'enabled' => allowedTo(array('profile_extra_own', 'profile_extra_any')), 'sc' => 'post', 'token' => 'profile-pm%u', 'permission' => array('own' => array('pm_read'), 'any' => array('profile_extra_any'))), 'ignoreboards' => array('label' => $txt['ignoreboards'], 'file' => 'ProfileOptions.controller.php', 'controller' => 'ProfileOptions_Controller', 'function' => 'action_ignoreboards', 'enabled' => !empty($modSettings['allow_ignore_boards']), 'sc' => 'post', 'token' => 'profile-ib%u', 'permission' => array('own' => array('profile_extra_any', 'profile_extra_own'), 'any' => array('profile_extra_any'))), 'lists' => array('label' => $txt['editBuddyIgnoreLists'], 'file' => 'ProfileOptions.controller.php', 'controller' => 'ProfileOptions_Controller', 'function' => 'action_editBuddyIgnoreLists', 'enabled' => !empty($modSettings['enable_buddylist']) && $context['user']['is_owner'], 'sc' => 'post', 'token' => 'profile-bl%u', 'subsections' => array('buddies' => array($txt['editBuddies']), 'ignore' => array($txt['editIgnoreList'])), 'permission' => array('own' => array('profile_extra_any', 'profile_extra_own'), 'any' => array())), 'groupmembership' => array('label' => $txt['groupmembership'], 'file' => 'ProfileOptions.controller.php', 'controller' => 'ProfileOptions_Controller', 'function' => 'action_groupMembership', 'enabled' => !empty($modSettings['show_group_membership']) && $context['user']['is_owner'], 'sc' => 'request', 'token' => 'profile-gm%u', 'token_type' => 'request', 'permission' => array('own' => array('profile_view_own'), 'any' => array('manage_membergroups'))))), 'profile_action' => array('title' => $txt['profileAction'], 'areas' => array('sendpm' => array('label' => $txt['profileSendIm'], 'custom_url' => $scripturl . '?action=pm;sa=send', 'permission' => array('own' => array(), 'any' => array('pm_send'))), 'issuewarning' => array('label' => $txt['profile_issue_warning'], 'enabled' => in_array('w', $context['admin_features']) && !empty($modSettings['warning_enable']) && (!$context['user']['is_owner'] || $context['user']['is_admin']), 'file' => 'ProfileAccount.controller.php', 'controller' => 'ProfileAccount_Controller', 'function' => 'action_issuewarning', 'token' => 'profile-iw%u', 'permission' => array('own' => array(), 'any' => array('issue_warning'))), 'banuser' => array('label' => $txt['profileBanUser'], 'custom_url' => $scripturl . '?action=admin;area=ban;sa=add', 'enabled' => $cur_profile['id_group'] != 1 && !in_array(1, explode(',', $cur_profile['additional_groups'])), 'permission' => array('own' => array(), 'any' => array('manage_bans'))), 'subscriptions' => array('label' => $txt['subscriptions'], 'file' => 'ProfileSubscriptions.controller.php', 'controller' => 'ProfileSubscriptions_Controller', 'function' => 'action_subscriptions', 'enabled' => !empty($modSettings['paid_enabled']), 'permission' => array('own' => array('profile_view_own'), 'any' => array('moderate_forum'))), 'deleteaccount' => array('label' => $txt['deleteAccount'], 'file' => 'ProfileAccount.controller.php', 'controller' => 'ProfileAccount_Controller', 'function' => 'action_deleteaccount', 'sc' => 'post', 'token' => 'profile-da%u', 'password' => true, 'permission' => array('own' => array('profile_remove_any', 'profile_remove_own'), 'any' => array('profile_remove_any'))), 'activateaccount' => array('file' => 'ProfileAccount.controller.php', 'controller' => 'ProfileAccount_Controller', 'function' => 'action_activateaccount', 'sc' => 'get', 'token' => 'profile-aa%u', 'permission' => array('own' => array(), 'any' => array('moderate_forum'))))));
     // Is there an updated message to show?
     if (isset($_GET['updated'])) {
         $context['profile_updated'] = $txt['profile_updated_own'];
     }
     // Set a few options for the menu.
     $menuOptions = array('disable_url_session_check' => true, 'hook' => 'profile', 'extra_url_parameters' => array('u' => $context['id_member']), 'default_include_dir' => CONTROLLERDIR);
     // Actually create the menu!
     $profile_include_data = createMenu($profile_areas, $menuOptions);
     unset($profile_areas);
     // If it said no permissions that meant it wasn't valid!
     if ($profile_include_data && empty($profile_include_data['permission'])) {
         $profile_include_data['enabled'] = false;
     }
     // No menu and guest? A warm welcome to register
     if (!$profile_include_data && $user_info['is_guest']) {
         is_not_guest();
     }
     // No menu means no access.
     if (!$profile_include_data || isset($profile_include_data['enabled']) && $profile_include_data['enabled'] === false) {
         fatal_lang_error('no_access', false);
     }
     // Make a note of the Unique ID for this menu.
     $context['profile_menu_id'] = $context['max_menu_id'];
     $context['profile_menu_name'] = 'menu_data_' . $context['profile_menu_id'];
     // Set the selected item - now it's been validated.
     $current_area = $profile_include_data['current_area'];
     $context['menu_item_selected'] = $current_area;
     // Before we go any further, let's work on the area we've said is valid.
     // Note this is done here just in case we ever compromise the menu function in error!
     $this->_completed_save = false;
     $context['do_preview'] = isset($_REQUEST['preview_signature']);
     // Are we saving data in a valid area?
     if (isset($profile_include_data['sc']) && (isset($_REQUEST['save']) || $context['do_preview'])) {
         checkSession($profile_include_data['sc']);
         $this->_completed_save = true;
     }
     // Does this require session validating?
     if (!empty($area['validate']) || isset($_REQUEST['save']) && !$context['user']['is_owner']) {
         validateSession();
     }
     // Do we need to perform a token check?
     if (!empty($profile_include_data['token'])) {
         if ($profile_include_data['token'] !== true) {
             $token_name = str_replace('%u', $context['id_member'], $profile_include_data['token']);
         } else {
             $token_name = 'profile-u' . $context['id_member'];
         }
         if (isset($profile_include_data['token_type']) && in_array($profile_include_data['token_type'], array('request', 'post', 'get'))) {
             $token_type = $profile_include_data['token_type'];
         } else {
             $token_type = 'post';
         }
         if (isset($_REQUEST['save'])) {
             validateToken($token_name, $token_type);
         }
     }
     // Permissions for good measure.
     if (!empty($profile_include_data['permission'])) {
         isAllowedTo($profile_include_data['permission'][$context['user']['is_owner'] ? 'own' : 'any']);
     }
     // Create a token if needed.
     if (!empty($profile_include_data['token'])) {
         createToken($token_name, $token_type);
         $context['token_check'] = $token_name;
     }
     // Build the link tree.
     $context['linktree'][] = array('url' => $scripturl . '?action=profile' . ($memID != $user_info['id'] ? ';u=' . $memID : ''), 'name' => sprintf($txt['profile_of_username'], $context['member']['name']));
     if (!empty($profile_include_data['label'])) {
         $context['linktree'][] = array('url' => $scripturl . '?action=profile' . ($memID != $user_info['id'] ? ';u=' . $memID : '') . ';area=' . $profile_include_data['current_area'], 'name' => $profile_include_data['label']);
     }
     if (!empty($profile_include_data['current_subsection']) && $profile_include_data['subsections'][$profile_include_data['current_subsection']][0] != $profile_include_data['label']) {
         $context['linktree'][] = array('url' => $scripturl . '?action=profile' . ($memID != $user_info['id'] ? ';u=' . $memID : '') . ';area=' . $profile_include_data['current_area'] . ';sa=' . $profile_include_data['current_subsection'], 'name' => $profile_include_data['subsections'][$profile_include_data['current_subsection']][0]);
     }
     // Set the template for this area... if you still can :P
     // and add the profile layer.
     $context['sub_template'] = $profile_include_data['function'];
     Template_Layers::getInstance()->add('profile');
     loadJavascriptFile('profile.js');
     // All the subactions that require a user password in order to validate.
     $check_password = $context['user']['is_owner'] && !empty($profile_include_data['password']);
     $context['require_password'] = $check_password && empty($user_settings['openid_uri']);
     // These will get populated soon!
     $post_errors = array();
     $profile_vars = array();
     // Right - are we saving - if so let's save the old data first.
     if ($this->_completed_save) {
         // Clean up the POST variables.
         $_POST = htmltrim__recursive($_POST);
         $_POST = htmlspecialchars__recursive($_POST);
         if ($check_password) {
             // If we're using OpenID try to revalidate.
             if (!empty($user_settings['openid_uri'])) {
                 require_once SUBSDIR . '/OpenID.subs.php';
                 $openID = new OpenID();
                 $openID->revalidate();
             } else {
                 // You didn't even enter a password!
                 if (trim($_POST['oldpasswrd']) == '') {
                     $post_errors[] = 'no_password';
                 }
                 // Since the password got modified due to all the $_POST cleaning, lets undo it so we can get the correct password
                 $_POST['oldpasswrd'] = un_htmlspecialchars($_POST['oldpasswrd']);
                 // Does the integration want to check passwords?
                 $good_password = in_array(true, call_integration_hook('integrate_verify_password', array($cur_profile['member_name'], $_POST['oldpasswrd'], false)), true);
                 // Start up the password checker, we have work to do
                 require_once SUBSDIR . '/Auth.subs.php';
                 // Bad password!!!
                 if (!$good_password && !validateLoginPassword($_POST['oldpasswrd'], $user_info['passwd'], $user_profile[$memID]['member_name'])) {
                     $post_errors[] = 'bad_password';
                 }
                 // Warn other elements not to jump the gun and do custom changes!
                 if (in_array('bad_password', $post_errors)) {
                     $context['password_auth_failed'] = true;
                 }
             }
         }
         // Change the IP address in the database.
         if ($context['user']['is_owner']) {
             $profile_vars['member_ip'] = $user_info['ip'];
         }
         // Now call the sub-action function...
         if ($current_area == 'activateaccount') {
             if (empty($post_errors)) {
                 require_once CONTROLLERDIR . '/ProfileAccount.controller.php';
                 $controller = new ProfileAccount_Controller();
                 $controller->action_activateaccount();
             }
         } elseif ($current_area == 'deleteaccount') {
             if (empty($post_errors)) {
                 require_once CONTROLLERDIR . '/ProfileAccount.controller.php';
                 $controller = new ProfileAccount_Controller();
                 $controller->action_deleteaccount2();
                 redirectexit();
             }
         } elseif ($current_area == 'groupmembership' && empty($post_errors)) {
             require_once CONTROLLERDIR . '/ProfileOptions.controller.php';
             $controller = new Profileoptions_Controller();
             $msg = $controller->action_groupMembership2();
             // Whatever we've done, we have nothing else to do here...
             redirectexit('action=profile' . ($context['user']['is_owner'] ? '' : ';u=' . $memID) . ';area=groupmembership' . (!empty($msg) ? ';msg=' . $msg : ''));
         } elseif ($current_area == 'authentication') {
             require_once CONTROLLERDIR . '/ProfileOptions.controller.php';
             $controller = new ProfileOptions_Controller();
             $controller->action_authentication(true);
         } elseif (in_array($current_area, array('account', 'forumprofile', 'theme', 'contactprefs'))) {
             saveProfileFields();
         } else {
             $force_redirect = true;
             saveProfileChanges($profile_vars, $memID);
         }
         call_integration_hook('integrate_profile_save', array(&$profile_vars, &$post_errors, $memID));
         // There was a problem, let them try to re-enter.
         if (!empty($post_errors)) {
             // Load the language file so we can give a nice explanation of the errors.
             loadLanguage('Errors');
             $context['post_errors'] = $post_errors;
         } elseif (!empty($profile_vars)) {
             // If we've changed the password, notify any integration that may be listening in.
             if (isset($profile_vars['passwd'])) {
                 call_integration_hook('integrate_reset_pass', array($cur_profile['member_name'], $cur_profile['member_name'], $_POST['passwrd2']));
             }
             updateMemberData($memID, $profile_vars);
             // What if this is the newest member?
             if ($modSettings['latestMember'] == $memID) {
                 updateStats('member');
             } elseif (isset($profile_vars['real_name'])) {
                 updateSettings(array('memberlist_updated' => time()));
             }
             // If the member changed his/her birthdate, update calendar statistics.
             if (isset($profile_vars['birthdate']) || isset($profile_vars['real_name'])) {
                 updateSettings(array('calendar_updated' => time()));
             }
             // Anything worth logging?
             if (!empty($context['log_changes']) && !empty($modSettings['modlog_enabled'])) {
                 $log_changes = array();
                 foreach ($context['log_changes'] as $k => $v) {
                     $log_changes[] = array('action' => $k, 'log_type' => 'user', 'extra' => array_merge($v, array('applicator' => $user_info['id'], 'member_affected' => $memID)));
                 }
                 logActions($log_changes);
             }
             // Have we got any post save functions to execute?
             if (!empty($context['profile_execute_on_save'])) {
                 foreach ($context['profile_execute_on_save'] as $saveFunc) {
                     $saveFunc();
                 }
             }
             // Let them know it worked!
             $context['profile_updated'] = $context['user']['is_owner'] ? $txt['profile_updated_own'] : sprintf($txt['profile_updated_else'], $cur_profile['member_name']);
             // Invalidate any cached data.
             cache_put_data('member_data-profile-' . $memID, null, 0);
         }
     }
     // Have some errors for some reason?
     if (!empty($post_errors)) {
         // Set all the errors so the template knows what went wrong.
         foreach ($post_errors as $error_type) {
             $context['modify_error'][$error_type] = true;
         }
     } elseif (!empty($profile_vars) && $context['user']['is_owner'] && !$context['do_preview']) {
         redirectexit('action=profile;area=' . $current_area . ';updated');
     } elseif (!empty($force_redirect)) {
         redirectexit('action=profile' . ($context['user']['is_owner'] ? '' : ';u=' . $memID) . ';area=' . $current_area);
     }
     // Let go to the right place
     if (isset($profile_include_data['file'])) {
         require_once $profile_include_data['file'];
     }
     callMenu($profile_include_data);
     // Set the page title if it's not already set...
     if (!isset($context['page_title'])) {
         $context['page_title'] = $txt['profile'] . (isset($txt[$current_area]) ? ' - ' . $txt[$current_area] : '');
     }
 }
示例#5
0
/**
 * Delete one or more members.
 *
 * What it does:
 * - Requires profile_remove_own or profile_remove_any permission for
 * respectively removing your own account or any account.
 * - Non-admins cannot delete admins.
 *
 * The function:
 * - changes author of messages, topics and polls to guest authors.
 * - removes all log entries concerning the deleted members, except the
 * error logs, ban logs and moderation logs.
 * - removes these members' personal messages (only the inbox)
 * - rmoves avatars, ban entries, theme settings, moderator positions, poll votes,
 * drafts, likes, mentions, notifications
 * - removes custom field data associated with them
 * - updates member statistics afterwards.
 *
 * @package Members
 * @param int[]|int $users
 * @param bool $check_not_admin = false
 */
function deleteMembers($users, $check_not_admin = false)
{
    global $modSettings, $user_info;
    $db = database();
    // Try give us a while to sort this out...
    @set_time_limit(600);
    // Try to get some more memory.
    setMemoryLimit('128M');
    // If it's not an array, make it so!
    if (!is_array($users)) {
        $users = array($users);
    } else {
        $users = array_unique($users);
    }
    // Make sure there's no void user in here.
    $users = array_diff($users, array(0));
    // How many are they deleting?
    if (empty($users)) {
        return;
    } elseif (count($users) == 1) {
        list($user) = $users;
        if ($user == $user_info['id']) {
            isAllowedTo('profile_remove_own');
        } else {
            isAllowedTo('profile_remove_any');
        }
    } else {
        foreach ($users as $k => $v) {
            $users[$k] = (int) $v;
        }
        // Deleting more than one?  You can't have more than one account...
        isAllowedTo('profile_remove_any');
    }
    // Get their names for logging purposes.
    $request = $db->query('', '
		SELECT id_member, member_name, email_address, CASE WHEN id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0 THEN 1 ELSE 0 END AS is_admin
		FROM {db_prefix}members
		WHERE id_member IN ({array_int:user_list})
		LIMIT ' . count($users), array('user_list' => $users, 'admin_group' => 1));
    $admins = array();
    $emails = array();
    $user_log_details = array();
    while ($row = $db->fetch_assoc($request)) {
        if ($row['is_admin']) {
            $admins[] = $row['id_member'];
        }
        $user_log_details[$row['id_member']] = array($row['id_member'], $row['member_name']);
        $emails[] = $row['email_address'];
    }
    $db->free_result($request);
    if (empty($user_log_details)) {
        return;
    }
    // Make sure they aren't trying to delete administrators if they aren't one.  But don't bother checking if it's just themself.
    if (!empty($admins) && ($check_not_admin || !allowedTo('admin_forum') && (count($users) != 1 || $users[0] != $user_info['id']))) {
        $users = array_diff($users, $admins);
        foreach ($admins as $id) {
            unset($user_log_details[$id]);
        }
    }
    // No one left?
    if (empty($users)) {
        return;
    }
    // Log the action - regardless of who is deleting it.
    $log_changes = array();
    foreach ($user_log_details as $user) {
        $log_changes[] = array('action' => 'delete_member', 'log_type' => 'admin', 'extra' => array('member' => $user[0], 'name' => $user[1], 'member_acted' => $user_info['name']));
        // Remove any cached data if enabled.
        if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2) {
            cache_put_data('user_settings-' . $user[0], null, 60);
        }
    }
    // Make these peoples' posts guest posts.
    $db->query('', '
		UPDATE {db_prefix}messages
		SET id_member = {int:guest_id}' . (!empty($modSettings['deleteMembersRemovesEmail']) ? ',
		poster_email = {string:blank_email}' : '') . '
		WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'blank_email' => '', 'users' => $users));
    $db->query('', '
		UPDATE {db_prefix}polls
		SET id_member = {int:guest_id}
		WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users));
    // Make these peoples' posts guest first posts and last posts.
    $db->query('', '
		UPDATE {db_prefix}topics
		SET id_member_started = {int:guest_id}
		WHERE id_member_started IN ({array_int:users})', array('guest_id' => 0, 'users' => $users));
    $db->query('', '
		UPDATE {db_prefix}topics
		SET id_member_updated = {int:guest_id}
		WHERE id_member_updated IN ({array_int:users})', array('guest_id' => 0, 'users' => $users));
    $db->query('', '
		UPDATE {db_prefix}log_actions
		SET id_member = {int:guest_id}
		WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users));
    $db->query('', '
		UPDATE {db_prefix}log_banned
		SET id_member = {int:guest_id}
		WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users));
    $db->query('', '
		UPDATE {db_prefix}log_errors
		SET id_member = {int:guest_id}
		WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users));
    // Delete the member.
    $db->query('', '
		DELETE FROM {db_prefix}members
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    // Delete any drafts...
    $db->query('', '
		DELETE FROM {db_prefix}user_drafts
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    // Delete any likes...
    $db->query('', '
		DELETE FROM {db_prefix}message_likes
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    // Delete any custom field data...
    $db->query('', '
		DELETE FROM {db_prefix}custom_fields_data
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    // Delete any post by email keys...
    $db->query('', '
		DELETE FROM {db_prefix}postby_emails
		WHERE email_to IN ({array_string:emails})', array('emails' => $emails));
    // Delete the logs...
    $db->query('', '
		DELETE FROM {db_prefix}log_actions
		WHERE id_log = {int:log_type}
			AND id_member IN ({array_int:users})', array('log_type' => 2, 'users' => $users));
    $db->query('', '
		DELETE FROM {db_prefix}log_boards
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    $db->query('', '
		DELETE FROM {db_prefix}log_comments
		WHERE id_recipient IN ({array_int:users})
			AND comment_type = {string:warntpl}', array('users' => $users, 'warntpl' => 'warntpl'));
    $db->query('', '
		DELETE FROM {db_prefix}log_group_requests
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    $db->query('', '
		DELETE FROM {db_prefix}log_karma
		WHERE id_target IN ({array_int:users})
			OR id_executor IN ({array_int:users})', array('users' => $users));
    $db->query('', '
		DELETE FROM {db_prefix}log_mark_read
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    $db->query('', '
		DELETE FROM {db_prefix}log_notify
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    $db->query('', '
		DELETE FROM {db_prefix}log_online
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    $db->query('', '
		DELETE FROM {db_prefix}log_subscribed
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    $db->query('', '
		DELETE FROM {db_prefix}log_topics
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    $db->query('', '
		DELETE FROM {db_prefix}collapsed_categories
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    // Make their votes appear as guest votes - at least it keeps the totals right.
    // @todo Consider adding back in cookie protection.
    $db->query('', '
		UPDATE {db_prefix}log_polls
		SET id_member = {int:guest_id}
		WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users));
    // Remove the mentions
    $db->query('', '
		DELETE FROM {db_prefix}log_mentions
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    // Delete personal messages.
    require_once SUBSDIR . '/PersonalMessage.subs.php';
    deleteMessages(null, null, $users);
    $db->query('', '
		UPDATE {db_prefix}personal_messages
		SET id_member_from = {int:guest_id}
		WHERE id_member_from IN ({array_int:users})', array('guest_id' => 0, 'users' => $users));
    // They no longer exist, so we don't know who it was sent to.
    $db->query('', '
		DELETE FROM {db_prefix}pm_recipients
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    // Delete avatar.
    require_once SUBSDIR . '/ManageAttachments.subs.php';
    removeAttachments(array('id_member' => $users));
    // It's over, no more moderation for you.
    $db->query('', '
		DELETE FROM {db_prefix}moderators
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    $db->query('', '
		DELETE FROM {db_prefix}group_moderators
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    // If you don't exist we can't ban you.
    $db->query('', '
		DELETE FROM {db_prefix}ban_items
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    // Remove individual theme settings.
    $db->query('', '
		DELETE FROM {db_prefix}themes
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    // These users are nobody's buddy nomore.
    $request = $db->query('', '
		SELECT id_member, pm_ignore_list, buddy_list
		FROM {db_prefix}members
		WHERE FIND_IN_SET({raw:pm_ignore_list}, pm_ignore_list) != 0 OR FIND_IN_SET({raw:buddy_list}, buddy_list) != 0', array('pm_ignore_list' => implode(', pm_ignore_list) != 0 OR FIND_IN_SET(', $users), 'buddy_list' => implode(', buddy_list) != 0 OR FIND_IN_SET(', $users)));
    while ($row = $db->fetch_assoc($request)) {
        updateMemberData($row['id_member'], array('pm_ignore_list' => implode(',', array_diff(explode(',', $row['pm_ignore_list']), $users)), 'buddy_list' => implode(',', array_diff(explode(',', $row['buddy_list']), $users))));
    }
    $db->free_result($request);
    // Make sure no member's birthday is still sticking in the calendar...
    updateSettings(array('calendar_updated' => time()));
    // Integration rocks!
    call_integration_hook('integrate_delete_members', array($users));
    updateMemberStats();
    logActions($log_changes);
}
示例#6
0
    /**
     * Modify a user's karma.
     * It redirects back to the referrer afterward, whether by javascript or the passed parameters.
     * Requires the karma_edit permission, and that the user isn't a guest.
     * It depends on the karmaMode, karmaWaitTime, and karmaTimeRestrictAdmins settings.
     * It is accessed via ?action=karma.
     *
     * @return void
     */
    public function init()
    {
        global $modSettings, $txt, $user_info, $topic, $smcFunc, $context, $sourcedir;
        // If the mod is disabled, show an error.
        if (empty($modSettings['karmaMode'])) {
            fatal_lang_error('feature_disabled', true);
        }
        // If you're a guest or can't do this, blow you off...
        is_not_guest();
        isAllowedTo('karma_edit');
        checkSession('get');
        // If you don't have enough posts, tough luck.
        // @todo Should this be dropped in favor of post group permissions?
        // Should this apply to the member you are smiting/applauding?
        if (!$user_info['is_admin'] && $user_info['posts'] < $modSettings['karmaMinPosts']) {
            fatal_lang_error('not_enough_posts_karma', true, array($modSettings['karmaMinPosts']));
        }
        // And you can't modify your own, punk! (use the profile if you need to.)
        if (empty($_REQUEST['uid']) || (int) $_REQUEST['uid'] == $user_info['id']) {
            fatal_lang_error('cant_change_own_karma', false);
        }
        // The user ID _must_ be a number, no matter what.
        $memID = (int) $_REQUEST['uid'];
        // Applauding or smiting?
        $dir = $_REQUEST['sa'] != 'applaud' ? -1 : 1;
        if ($dir == 1 && empty($modSettings['karmaApplaudLabel']) || $dir == -1 && empty($modSettings['karmaSmiteLabel'])) {
            fatal_lang_error('feature_disabled', false);
        }
        // Delete any older items from the log. (karmaWaitTime is by hour.)
        $smcFunc['db_query']('', '
			DELETE FROM {db_prefix}log_karma
			WHERE {int:current_time} - log_time > {int:wait_time}', array('wait_time' => (int) ($modSettings['karmaWaitTime'] * 3600), 'current_time' => time()));
        // Start off with no change in karma.
        $action = 0;
        // Not an administrator... or one who is restricted as well.
        if (!empty($modSettings['karmaTimeRestrictAdmins']) || !allowedTo('moderate_forum')) {
            // Find out if this user has done this recently...
            $request = $smcFunc['db_query']('', '
				SELECT action
				FROM {db_prefix}log_karma
				WHERE id_target = {int:id_target}
					AND id_executor = {int:current_member}
				LIMIT 1', array('current_member' => $user_info['id'], 'id_target' => $memID));
            if ($smcFunc['db_num_rows']($request) > 0) {
                list($action) = $smcFunc['db_fetch_row']($request);
            }
            $smcFunc['db_free_result']($request);
        }
        $karma = loadMemberCustomFields($memID, array('karma_good', 'karma_bad'));
        if (empty($karma[$memID]['karma_good']['value'])) {
            $karma[$memID]['karma_good']['value'] = 0;
        }
        if (empty($karma[$memID]['karma_bad']['value'])) {
            $karma[$memID]['karma_bad']['value'] = 0;
        }
        $changes = array();
        $log_changes = array();
        $col_name = $dir == 1 ? 'karma_good' : 'karma_bad';
        $value = $karma[$memID][$col_name]['value'] + 1;
        // They haven't, not before now, anyhow.
        if (empty($action) || empty($modSettings['karmaWaitTime'])) {
            // Put it in the log.
            $smcFunc['db_insert']('replace', '{db_prefix}log_karma', array('action' => 'int', 'id_target' => 'int', 'id_executor' => 'int', 'log_time' => 'int'), array($dir, $memID, $user_info['id'], time()), array('id_target', 'id_executor'));
            // Change by one.
            $log_changes[] = array('action' => $col_name, 'log_type' => 'user', 'extra' => array('value' => $value, 'applicator' => $user_info['id'], 'member_affected' => $memID));
            $changes[] = array(1, $col_name, $value, $memID);
        } else {
            // If you are gonna try to repeat.... don't allow it.
            if ($action == $dir) {
                fatal_lang_error('karma_wait_time', false, array($modSettings['karmaWaitTime'], $modSettings['karmaWaitTime'] == 1 ? strtolower($txt['hour']) : $txt['hours']));
            }
            // You decided to go back on your previous choice?
            $smcFunc['db_query']('', '
				UPDATE {db_prefix}log_karma
				SET action = {int:action}, log_time = {int:current_time}
				WHERE id_target = {int:id_target}
					AND id_executor = {int:current_member}', array('current_member' => $user_info['id'], 'action' => $dir, 'current_time' => time(), 'id_target' => $memID));
            // It was recently changed the OTHER way... so... reverse it!
            $log_changes[] = array('action' => $col_name, 'log_type' => 'user', 'extra' => array('value' => $value, 'applicator' => $user_info['id'], 'member_affected' => $memID));
            $changes[] = array(1, $col_name, $value, $memID);
            $changes[] = array(1, $dir == 1 ? 'karma_good' : 'karma_bad', $karma[$memID][$dir == 1 ? 'karma_good' : 'karma_bad']['value'] - 1, $memID);
        }
        // Make those changes!
        if (!empty($changes)) {
            $smcFunc['db_insert']('replace', '{db_prefix}themes', array('id_theme' => 'int', 'variable' => 'string-255', 'value' => 'string-65534', 'id_member' => 'int'), $changes, array('id_theme', 'variable', 'id_member'));
            if (!empty($log_changes) && !empty($modSettings['modlog_enabled'])) {
                require_once $sourcedir . '/Logging.php';
                logActions($log_changes);
            }
        }
        if (true) {
            //isset($_REQUEST['f']))
            redirectexit();
        } else {
            echo '<!DOCTYPE html>
	<html', $context['right_to_left'] ? ' dir="rtl"' : '', '>
		<head>
			<title>...</title>
			<script><!-- // --><![CDATA[
				history.go(-1);
			// ]]></script>
		</head>
		<body>&laquo;</body>
	</html>';
            obExit(false);
        }
    }
示例#7
0
/**
 * This function logs an action in the respective log. (database log)
 * You should use {@link logActions()} instead.
 * @example logAction('remove', array('starter' => $id_member_started));
 *
 * @deprecated deprecated since version 2.1
 * @param string $action
 * @param array $extra = array()
 * @param string $log_type, options 'moderate', 'admin', ...etc.
 */
function logAction($action, $extra = array(), $log_type = 'moderate')
{
    return logActions(array(array('action' => $action, 'log_type' => $log_type, 'extra' => $extra)));
}