query_select('f_custom_fields', array('id', 'cf_type', 'cf_name'), null, 'ORDER BY cf_order,' . $GLOBALS['FORUM_DB']->translate_field_ref('cf_name')));
// Headings
$headings = member_get_csv_headings();
foreach ($cpfs as $i => $c) { // CPFs take precedence over normal fields of the same name
$cpfs[$i]['_cf_name'] = get_translated_text($c['cf_name'], $GLOBALS['FORUM_DB']);
$headings[$cpfs[$i]['_cf_name']] = strval($i); // We specially recognise numeric names as a map back to a CPF ID
}
// Subscription types
$subscription_types = array();
if (addon_installed('ecommerce')) {
require_lang('ecommerce');
$usergroup_subscription_rows = $GLOBALS['FORUM_DB']->query_select('f_usergroup_subs', array('id', 's_title'));
foreach ($usergroup_subscription_rows as $usergroup_subscription_row) {
$item_name = get_translated_text($usergroup_subscription_row['s_title'], $GLOBALS['FORUM_DB']);
$heading_lang_strings = array(
'SUBSCRIPTION_START_TIME',
'SUBSCRIPTION_TERM_START_TIME',
'SUBSCRIPTION_TERM_END_TIME',
'SUBSCRIPTION_EXPIRY_TIME',
'PAYMENT_GATEWAY',
'STATUS',
);
foreach ($heading_lang_strings as $heading_lang_string) {
$headings[$item_name . ' (' . do_lang($heading_lang_string) . ')'] = ':' . str_replace('/', '\\', $item_name . ' (' . do_lang($heading_lang_string) . ')'); // Forward slashes are assumed as delimiters
}
$subscription_types['USERGROUP' . strval($usergroup_subscription_row['id'])] = $item_name;
}
}
return array($headings, $cpfs, $subscription_types);
}
/**
* Get field mapping data for CSV import/export.
*
* @return array A map of heading information (human name to field name/encoding details)
*/
function member_get_csv_headings()
{
$headings = array(
'ID' => 'id',
'Username' => 'm_username',
'E-mail address' => 'm_email_address',
'Password' => 'm_pass_hash_salted/m_pass_salt/m_password_compat_scheme'
);
if (addon_installed('cns_member_avatars')) {
$headings += array(
'Avatar' => '#m_avatar_url',
);
}
if (addon_installed('cns_member_photos')) {
$headings += array(
'Photo' => '#m_photo_url',
);
}
$headings += array(
'Signature' => '*m_signature',
'Validated' => '!m_validated',
'Join time' => '&m_join_time',
'Last visit' => '&m_last_visit_time',
'Number of posts' => 'm_cache_num_posts',
'Usergroup' => '@m_primary_group',
'Banned' => '!m_is_perm_banned',
'Date of birth' => 'm_dob_year/m_dob_month/m_dob_day',
'Reveal age' => '!m_reveal_age',
'Language' => 'm_language',
'Accept member e-mails' => '!m_allow_emails',
'Opt-in' => '!m_allow_emails_from_staff',
'Auto mark read' => 'm_auto_mark_read',
);
return $headings;
}
/**
* Get a list of timezones.
*
* @param ?string $timezone Current timezone to select (null: server default)
* @return Tempcode List of timezones
*/
function create_selection_list_timezone_list($timezone = null)
{
if (is_null($timezone)) {
$timezone = get_site_timezone();
}
$timezone_list = '';//new Tempcode();
$time_now = time();
foreach (get_timezone_list() as $_timezone => $timezone_nice) {
$timezone_list .= ''; // XHTMLXHTML
//$timezone_list->attach(do_template('CNS_AUTO_TIME_ZONE_ENTRY', array('_GUID' => '2aed8a9fcccb52e5d52b5a307a906b3a', 'HOUR' => date('H', tz_time($time_now, $_timezone)), 'DW' => date('w', tz_time(time(), $_timezone)), 'NAME' => $_timezone, 'SELECTED' => ($timezone == $_timezone), 'CLASS' => '', 'TEXT' => $timezone_nice)));
}
return make_string_tempcode($timezone_list);
}
/**
* Validate an IP address, indirectly by passing through a confirmation code.
*/
function approve_ip_script()
{
require_code('site');
attach_to_screen_header(''); // XHTMLXHTML
$keep = keep_symbol(array('1'));
$code = either_param_string('code', '');
if ($code == '') {
$title = get_screen_title('CONFIRM');
require_code('form_templates');
$fields = new Tempcode();
$fields->attach(form_input_codename(do_lang_tempcode('CODE'), '', 'code', '', true));
$submit_name = do_lang_tempcode('PROCEED');
$url = find_script('approve_ip') . $keep;
$middle = do_template('FORM_SCREEN', array('_GUID' => 'd92ce4ec82dc709f920a4ce6760778de', 'TITLE' => $title, 'SKIP_WEBSTANDARDS' => true, 'HIDDEN' => '', 'URL' => $url, 'FIELDS' => $fields, 'TEXT' => do_lang_tempcode('MISSING_CONFIRM_CODE'), 'SUBMIT_ICON' => 'buttons__proceed', 'SUBMIT_NAME' => $submit_name));
$echo = globalise($middle, null, '', true, true);
$echo->evaluate_echo();
exit();
}
// If we're still here, we're ok to go
require_lang('cns');
$test = $GLOBALS['FORUM_DB']->query_select_value_if_there('f_member_known_login_ips', 'i_val_code', array('i_val_code' => $code));
if (is_null($test)) {
warn_exit(do_lang_tempcode('ALREADY_VALIDATED'));
}
$GLOBALS['FORUM_DB']->query_update('f_member_known_login_ips', array('i_val_code' => ''), array('i_val_code' => $code), '', 1);
$title = get_screen_title('CONFIRM');
$middle = redirect_screen($title, get_base_url() . $keep, do_lang_tempcode('SUCCESS'));
$echo = globalise($middle, null, '', true, true);
$echo->evaluate_echo();
exit();
}
/**
* If we are using human names for usernames, a conflict is likely. Store a suffixed variety. Maybe later Composr will strip these suffixes out in some contexts.
*
* @param SHORT_TEXT $username The desired human name for the member profile.
* @return SHORT_TEXT A unique username.
*/
function get_username_from_human_name($username)
{
$username = preg_replace('# \(\d+\)$#', '', $username);
$_username = $username;
$i = 1;
do {
$test = $GLOBALS['FORUM_DB']->query_select_value_if_there('f_members', 'id', array('m_username' => $_username));
if (!is_null($test)) {
$i++;
$_username = $username . ' (' . strval($i) . ')';
}
} while (!is_null($test));
$username = $_username;
return $username;
}
/**
* Get a form for finishing off a member profile (such as for LDAP or httpauth, where a partial profile is automatically made, but needs completion).
*
* @param SHORT_TEXT $username The username for the member profile.
* @param ID_TEXT $type The type of member profile we are finishing off.
* @param string $email_address Auto-detected e-mail address (blank: none)
* @param ?integer $dob_day Auto-detected DOB day (null: unknown)
* @param ?integer $dob_month Auto-detected DOB month (null: unknown)
* @param ?integer $dob_year Auto-detected DOB year (null: unknown)
* @param ?ID_TEXT $timezone Auto-detected Timezone (null: unknown)
* @param ?ID_TEXT $language Auto-detected Language (null: unknown)
* @return Tempcode The form.
*/
function cns_member_external_linker_ask($username, $type, $email_address = '', $dob_day = null, $dob_month = null, $dob_year = null, $timezone = null, $language = null)
{
require_lang('cns');
// If somehow, we're not fully started up, or in a messy state
require_code('urls');
cms_ob_end_clean(); // Emergency output, potentially, so kill off any active buffer
$title = get_screen_title('FINISH_PROFILE');
if ($username != '') {
$username = get_username_from_human_name($username);
}
list($fields, $hidden) = cns_get_member_fields(true, null, null, $email_address, 1, $dob_day, $dob_month, $dob_year, $timezone, null, null, 1, 0, null, $language, 1, 1, 1, null, $username, 0, $type);
$hidden->attach(build_keep_post_fields());
$hidden->attach(form_input_hidden('finishing_profile', '1'));
$text = do_lang_tempcode('ENTER_PROFILE_DETAILS_FINISH');
$submit_name = do_lang_tempcode('PROCEED');
$url = get_self_url();
return do_template('FORM_SCREEN', array('_GUID' => 'f3fa74f4842f3660f0831f8d708d256d', 'HIDDEN' => $hidden, 'TITLE' => $title, 'FIELDS' => $fields, 'TEXT' => $text, 'SUBMIT_ICON' => 'menu__site_meta__user_actions__join', 'SUBMIT_NAME' => $submit_name, 'URL' => $url));
}
/**
* Finishing off of a member profile (such as for LDAP or httpauth, where a partial profile is automatically made, but needs completion).
*
* @param SHORT_TEXT $username The username for the member profile.
* @param SHORT_TEXT $password The password for the member profile.
* @param ID_TEXT $type The type of member profile we are finishing off.
* @param boolean $email_check Whether to check for duplicated email addresses.
* @param string $email_address Auto-detected e-mail address (blank: none)
* @param ?integer $dob_day Auto-detected DOB day (null: unknown)
* @param ?integer $dob_month Auto-detected DOB month (null: unknown)
* @param ?integer $dob_year Auto-detected DOB year (null: unknown)
* @param ?ID_TEXT $timezone Auto-detected Timezone (null: unknown)
* @param ?ID_TEXT $language Auto-detected Language (null: unknown)
* @param ?URLPATH $avatar_url The URL to the member's avatar (blank: none) (null: choose one automatically).
* @param URLPATH $photo_url The URL to the member's photo (blank: none).
* @param URLPATH $photo_thumb_url The URL to the member's photo thumbnail (blank: none).
* @return MEMBER The member ID for the finished off profile.
*/
function cns_member_external_linker($username, $password, $type, $email_check = true, $email_address = '', $dob_day = null, $dob_month = null, $dob_year = null, $timezone = null, $language = null, $avatar_url = null, $photo_url = '', $photo_thumb_url = '')
{
// Read in data
$email_address = trim(post_param_string('email_address', $email_address));
require_code('temporal2');
list($dob_year, $dob_month, $dob_day) = post_param_date_components('dob', $dob_year, $dob_month, $dob_day);
$reveal_age = post_param_integer('reveal_age', 0); // For default privacy, default off
require_code('temporal');
if (is_null($timezone)) {
$timezone = get_site_timezone();
}
$timezone = post_param_string('timezone', $timezone);
if (is_null($language)) {
$language = get_site_default_lang();
}
$language = post_param_string('language', $language);
$allow_emails = post_param_integer('allow_emails', 0); // For default privacy, default off
$allow_emails_from_staff = post_param_integer('allow_emails_from_staff', 0); // For default privacy, default off
require_code('cns_groups');
$custom_fields = cns_get_all_custom_fields_match(
cns_get_all_default_groups(true), // groups
null, // public view
null, // owner view
null, // owner set
null, // required
null, // show in posts
null, // show in post previews
null, // special start
true // show on join form
);
$actual_custom_fields = cns_read_in_custom_fields($custom_fields);
foreach ($actual_custom_fields as $key => $val) {
if ($val == STRING_MAGIC_NULL) {
$actual_custom_fields[$key] = '';
}
}
$groups = cns_get_all_default_groups(true); // $groups will contain the built in default primary group too (it is not $secondary_groups)
$primary_group = post_param_integer('primary_group', null);
if (($primary_group !== null) && (!in_array($primary_group, $groups)/*= not built in default, which is automatically ok to join without extra security*/)) {
// Check security
$test = $GLOBALS['FORUM_DB']->query_select_value('f_groups', 'g_is_presented_at_install', array('id' => $primary_group));
if ($test == 1) {
$groups = cns_get_all_default_groups(false); // Get it so it does not include the built in default primary group
$groups[] = $primary_group; // And add in the *chosen* primary group
} else {
$primary_group = null;
}
} else {
$primary_group = null;
}
if ($primary_group === null) { // Security error, or built in default (which will already be in $groups)
$primary_group = get_first_default_group();
}
// Check that the given address isn't already used (if one_per_email_address on)
if ((get_option('one_per_email_address') != '0') && ($email_address != '') && ($email_check)) {
$test = $GLOBALS['FORUM_DB']->query_select_value_if_there('f_members', 'm_username', array('m_email_address' => $email_address));
if (!is_null($test)) {
global $MEMBER_CACHED;
$MEMBER_CACHED = db_get_first_id();
$reset_url = build_url(array('page' => 'lost_password', 'email_address' => $email_address), get_module_zone('lost_password'));
warn_exit(do_lang_tempcode('EMAIL_ADDRESS_IN_USE', escape_html(get_site_name()), escape_html($reset_url->evaluate())));
}
}
$require_new_member_validation = get_option('require_new_member_validation') == '1';
$validated = $require_new_member_validation ? 0 : 1;
if ($require_new_member_validation) {
require_code('site');
attach_message(do_lang_tempcode('AWAITING_MEMBER_VALIDATION'), 'notice');
}
// Add member
require_code('cns_members_action');
$ret = cns_make_member($username, $password, $email_address, $groups, $dob_day, $dob_month, $dob_year, $actual_custom_fields, $timezone, null, $validated, time(), time(), '', $avatar_url, '', 0, 1, $reveal_age, '', $photo_url, $photo_thumb_url, 1, 1, $language, $allow_emails, $allow_emails_from_staff, get_ip_address(), '', false, $type, '');
return $ret;
}
/**
* Read in the custom profile field POST data.
*
* @param array $custom_fields The CPF field rows that we'll be reading in the member's values for.
* @param ?MEMBER $member_id Member involved (null: new member)
* @return array The CPF data.
*/
function cns_read_in_custom_fields($custom_fields, $member_id = null)
{
require_code('fields');
require_code('cns_members_action');
$actual_custom_fields = array();
foreach ($custom_fields as $custom_field) {
$ob = get_fields_hook($custom_field['cf_type']);
$old_value = is_null($member_id) ? null : $GLOBALS['FORUM_DB']->query_select_value_if_there('f_member_custom_fields', 'field_' . strval($custom_field['id']), array('mf_member_id' => $member_id));
// Field not required if not yet filled in but member already registered, if PRIVILEGE ON for that. Prevents annoyance for new required CPFs added later.
if (!member_field_is_required($member_id, 'required_cpfs', $old_value)) {
$custom_field['cf_required'] = 0;
}
$value = $ob->inputted_to_field_value($member_id !== null, $custom_field, 'uploads/cns_cpf_upload', ($old_value === null) ? null : array('cv_value' => $old_value));
// Required field validation (a standard for all field hooks)
if (($custom_field['cf_required'] == 1) && (($value == '') || (($value == STRING_MAGIC_NULL) && !fractional_edit()))) {
warn_exit(do_lang_tempcode('_REQUIRED_NOT_FILLED_IN', $custom_field['cf_name']));
}
if ((fractional_edit()) && ($value != STRING_MAGIC_NULL)) {
$rendered = $ob->render_field_value($custom_field, $value, 0, null, 'f_member_custom_fields', $member_id, 'ce_id', 'cf_id', 'field_' . strval($custom_field['id']), $member_id);
$_POST['field_' . strval($custom_field['id']) . '__altered_rendered_output'] = is_object($rendered) ? $rendered->evaluate() : $rendered;
}
$actual_custom_fields[$custom_field['id']] = $value;
}
return $actual_custom_fields;
}
/**
* Get form fields for adding/editing/finishing a member profile.
*
* @param boolean $mini_mode Whether we are only handling the essential details of a profile.
* @param ?MEMBER $member_id The ID of the member we are handling (null: new member).
* @param ?array $groups A list of usergroups (null: default/current usergroups).
* @param SHORT_TEXT $email_address The e-mail address.
* @param BINARY $preview_posts Whether posts are previewed before they are made.
* @param ?integer $dob_day Day of date of birth (null: not known).
* @param ?integer $dob_month Month of date of birth (null: not known).
* @param ?integer $dob_year Year of date of birth (null: not known).
* @param ?ID_TEXT $timezone The member timezone (null: site default).
* @param ?array $custom_fields A map of custom fields values (field-id=>value) (null: not known).
* @param ?ID_TEXT $theme The members default theme (null: not known).
* @param BINARY $reveal_age Whether the members age may be shown.
* @param BINARY $views_signatures Whether the member sees signatures in posts.
* @param ?BINARY $auto_monitor_contrib_content Whether the member automatically is enabled for notifications for content they contribute to (null: get default from config).
* @param ?LANGUAGE_NAME $language The members language (null: auto detect).
* @param BINARY $allow_emails Whether the member allows e-mails via the site.
* @param BINARY $allow_emails_from_staff Whether the member allows e-mails from staff via the site.
* @param BINARY $validated Whether the profile has been validated.
* @param ?GROUP $primary_group The members primary (null: not known).
* @param SHORT_TEXT $username The username.
* @param BINARY $is_perm_banned Whether the member is permanently banned.
* @param ID_TEXT $special_type The special type of profile this is (blank: not a special type).
* @param BINARY $highlighted_name Whether the member username will be highlighted.
* @param SHORT_TEXT $pt_allow Usergroups that may PT the member.
* @param LONG_TEXT $pt_rules_text Rules that other members must agree to before they may start a PT with the member.
* @param ?TIME $on_probation_until When the member is on probation until (null: just finished probation / or effectively was never on it)
* @return array A pair: The form fields, Hidden fields (both Tempcode).
*/
function cns_get_member_fields($mini_mode = true, $member_id = null, $groups = null, $email_address = '', $preview_posts = 0, $dob_day = null, $dob_month = null, $dob_year = null, $timezone = null, $custom_fields = null, $theme = null, $reveal_age = 1, $views_signatures = 1, $auto_monitor_contrib_content = null, $language = null, $allow_emails = 1, $allow_emails_from_staff = 1, $validated = 1, $primary_group = null, $username = '', $is_perm_banned = 0, $special_type = '', $highlighted_name = 0, $pt_allow = '*', $pt_rules_text = '', $on_probation_until = null)
{
$fields = new Tempcode();
$hidden = new Tempcode();
list($_fields, $_hidden) = cns_get_member_fields_settings($mini_mode, $member_id, $groups, $email_address, $preview_posts, $dob_day, $dob_month, $dob_year, $timezone, $theme, $reveal_age, $views_signatures, $auto_monitor_contrib_content, $language, $allow_emails, $allow_emails_from_staff, $validated, $primary_group, $username, $is_perm_banned, $special_type, $highlighted_name, $pt_allow, $pt_rules_text, $on_probation_until);
$fields->attach($_fields);
$hidden->attach($_hidden);
if (!$mini_mode) {
$fields->attach(do_template('FORM_SCREEN_FIELD_SPACER', array(
'_GUID' => '14205f6bf83c469a1404d24967d7b6f6',
'TITLE' => do_lang_tempcode('PROFILE'),
'SECTION_HIDDEN' => (get_page_name() == 'admin_cns_members'),
)));
}
list($_fields, $_hidden) = cns_get_member_fields_profile($mini_mode, $member_id, $groups, $custom_fields);
$fields->attach($_fields);
$hidden->attach($_hidden);
return array($fields, $hidden);
}
/**
* Get form fields for adding/editing/finishing a member profile.
*
* @param boolean $mini_mode Whether we are only handling the essential details of a profile.
* @param ?MEMBER $member_id The ID of the member we are handling (null: new member).
* @param ?array $groups A list of usergroups (null: default/current usergroups).
* @param SHORT_TEXT $email_address The e-mail address.
* @param ?BINARY $preview_posts Whether posts are previewed before they are made (null: calculate statistically).
* @param ?integer $dob_day Day of date of birth (null: not known).
* @param ?integer $dob_month Month of date of birth (null: not known).
* @param ?integer $dob_year Year of date of birth (null: not known).
* @param ?ID_TEXT $timezone The member timezone (null: site default).
* @param ?ID_TEXT $theme The members default theme (null: not known).
* @param BINARY $reveal_age Whether the members age may be shown.
* @param BINARY $views_signatures Whether the member sees signatures in posts.
* @param ?BINARY $auto_monitor_contrib_content Whether the member automatically is enabled for notifications for content they contribute to (null: get default from config).
* @param ?LANGUAGE_NAME $language The members language (null: auto detect).
* @param BINARY $allow_emails Whether the member allows e-mails via the site.
* @param BINARY $allow_emails_from_staff Whether the member allows e-mails from staff via the site.
* @param BINARY $validated Whether the profile has been validated.
* @param ?GROUP $primary_group The members primary (null: not known).
* @param SHORT_TEXT $username The username.
* @param BINARY $is_perm_banned Whether the member is permanently banned.
* @param ID_TEXT $special_type The special type of profile this is (blank: not a special type).
* @param BINARY $highlighted_name Whether the member username will be highlighted.
* @param SHORT_TEXT $pt_allow Usergroups that may PT the member.
* @param LONG_TEXT $pt_rules_text Rules that other members must agree to before they may start a PT with the member.
* @param ?TIME $on_probation_until When the member is on probation until (null: just finished probation / or effectively was never on it)
* @return array A pair: The form fields, Hidden fields (both Tempcode).
*/
function cns_get_member_fields_settings($mini_mode = true, $member_id = null, $groups = null, $email_address = '', $preview_posts = null, $dob_day = null, $dob_month = null, $dob_year = null, $timezone = null, $theme = null, $reveal_age = 1, $views_signatures = 1, $auto_monitor_contrib_content = null, $language = null, $allow_emails = 1, $allow_emails_from_staff = 1, $validated = 1, $primary_group = null, $username = '', $is_perm_banned = 0, $special_type = '', $highlighted_name = 0, $pt_allow = '*', $pt_rules_text = '', $on_probation_until = null)
{
require_code('form_templates');
require_code('cns_members_action');
$preview_posts = take_param_int_modeavg($preview_posts, 'm_preview_posts', 'f_members', 0);
require_code('cns_field_editability');
if (is_null($auto_monitor_contrib_content)) {
$auto_monitor_contrib_content = (get_option('allow_auto_notifications') == '0') ? 0 : 1;
}
$hidden = new Tempcode();
if ($member_id === $GLOBALS['CNS_DRIVER']->get_guest_id()) {
fatal_exit(do_lang_tempcode('INTERNAL_ERROR'));
}
require_code('form_templates');
require_code('encryption');
if (($special_type == '') && ($member_id !== null)) {
$special_type = get_member_special_type($member_id);
}
if (is_null($groups)) {
$groups = is_null($member_id) ? cns_get_all_default_groups(true) : $GLOBALS['CNS_DRIVER']->get_members_groups($member_id);
}
$fields = new Tempcode();
// Username
if (cns_field_editable('username', $special_type)) {
if ((is_null($member_id)) || (has_actual_page_access(get_member(), 'admin_cns_members')) || (has_privilege($member_id, 'rename_self'))) {
$prohibit_username_whitespace = get_option('prohibit_username_whitespace');
if ($prohibit_username_whitespace == '1') {
$pattern = '[^\s]*';
$pattern_error = do_lang('USERNAME_PASSWORD_WHITESPACE');
} else {
$pattern = null;
$pattern_error = null;
}
$fields->attach(form_input_line(do_lang_tempcode('USERNAME'), do_lang_tempcode('DESCRIPTION_USERNAME'), ($member_id === null) ? 'username' : 'edit_username', $username, true, null, null, 'text', null, $pattern, $pattern_error));
}
}
// Password
if (cns_field_editable('password', $special_type)) {
if ((is_null($member_id)) || ($member_id == get_member()) || (has_privilege(get_member(), 'assume_any_member'))) {
$temporary_password = (!is_null($member_id)) && ($member_id == get_member() && ($GLOBALS['FORUM_DRIVER']->get_member_row_field($member_id, 'm_password_compat_scheme') == 'temporary'));
if ($temporary_password) {
$password_field_description = do_lang_tempcode('DESCRIPTION_PASSWORD_TEMPORARY');
} else {
$password_field_description = do_lang_tempcode('DESCRIPTION_PASSWORD' . (!is_null($member_id) ? '_EDIT' : ''));
}
$fields->attach(form_input_password(do_lang_tempcode(is_null($member_id) ? 'PASSWORD' : 'NEW_PASSWORD'), $password_field_description, is_null($member_id) ? 'password' : 'edit_password', $mini_mode || $temporary_password));
$fields->attach(form_input_password(do_lang_tempcode('CONFIRM_PASSWORD'), '', 'password_confirm', $mini_mode || $temporary_password));
}
}
// Work out what options we need to present
$doing_international = (get_option('allow_international') == '1');
$_langs = find_all_langs();
$doing_langs = multi_lang();
$doing_email_option = (get_option('allow_email_disable') == '1') && (addon_installed('cns_contact_member'));
$doing_email_from_staff_option = (get_option('allow_email_from_staff_disable') == '1');
$unspecced_theme_zone_exists = $GLOBALS['SITE_DB']->query_value_if_there('SELECT COUNT(*) FROM ' . get_table_prefix() . 'zones WHERE ' . db_string_equal_to('zone_theme', '') . ' OR ' . db_string_equal_to('zone_theme', '-1'));
$doing_theme_option = ($unspecced_theme_zone_exists != 0) && (!$mini_mode);
$doing_local_forum_options = (addon_installed('cns_forum')) && (!$mini_mode);
// E-mail address
if (cns_field_editable('email', $special_type)) {
if ($email_address == '') {
$email_address = trim(get_param_string('email_address', ''));
}
$email_description = new Tempcode();
if ((get_option('valid_email_domains') != '') && ($mini_mode)) { // domain restriction only applies on public join form ($mini_mode)
$email_description = do_lang_tempcode('MUST_BE_EMAIL_DOMAIN', '*.' . preg_replace('#\s*,\s*#', ', *.', escape_html(get_option('valid_email_domains'))) . '', escape_html(get_option('valid_email_domains')));
} else {
if (get_option('email_confirm_join') == '1') {
$email_description = do_lang_tempcode('MUST_BE_REAL_ADDRESS');
}
}
$email_address_required = member_field_is_required($member_id, 'email_address');
$fields->attach(form_input_email(do_lang_tempcode('EMAIL_ADDRESS'), $email_description, 'email_address', $email_address, $email_address_required));
if ((is_null($member_id)) && ($email_address == '') && (get_option('email_confirm_join') == '1')) {
$fields->attach(form_input_email(do_lang_tempcode('CONFIRM_EMAIL_ADDRESS'), '', 'email_address_confirm', '', $email_address_required));
}
}
// E-mail privacy
if ($doing_email_option) {
$field_title = do_lang_tempcode('ALLOW_EMAILS');
if (cns_field_editable('email', $special_type)) {
$field_title = do_lang_tempcode('RELATED_FIELD', $field_title);
}
$fields->attach(form_input_tick($field_title, do_lang_tempcode('DESCRIPTION_ALLOW_EMAILS'), 'allow_emails', $allow_emails == 1));
}
if ($doing_email_from_staff_option) {
$field_title = do_lang_tempcode('ALLOW_EMAILS_FROM_STAFF');
if (cns_field_editable('email', $special_type)) {
$field_title = do_lang_tempcode('RELATED_FIELD', $field_title);
}
$fields->attach(form_input_tick($field_title, do_lang_tempcode('DESCRIPTION_ALLOW_EMAILS_FROM_STAFF'), 'allow_emails_from_staff', $allow_emails_from_staff == 1));
}
// DOB
if (cns_field_editable('dob', $special_type)) {
$default_time = is_null($dob_month) ? null : usertime_to_utctime(mktime(0, 0, 0, $dob_month, $dob_day, $dob_year));
if (get_option('dobs') == '1') {
$dob_required = member_field_is_required($member_id, 'dob');
$fields->attach(form_input_date(do_lang_tempcode($dob_required ? 'DATE_OF_BIRTH' : 'ENTER_YOUR_BIRTHDAY'), '', 'dob', $dob_required, false, false, $default_time, -130));
if (addon_installed('cns_forum')) {
$fields->attach(form_input_tick(do_lang_tempcode('RELATED_FIELD', do_lang_tempcode('REVEAL_AGE')), do_lang_tempcode('DESCRIPTION_REVEAL_AGE'), 'reveal_age', $reveal_age == 1));
}
}
}
/*
if (!$mini_mode) {
if (($doing_international) || ($doing_langs) || ($doing_email_option) || ($doing_wide_option) || ($doing_theme_option) || ($doing_local_forum_options)) {
$fields->attach(do_template('FORM_SCREEN_FIELD_SPACER', array('_GUID' => '3cd79bbea084ec1fe148edddad7d52b4', 'FORCE_OPEN' => is_null($member_id) ? true : null, 'TITLE' => do_lang_tempcode('SETTINGS'))));
}
}
*/
require_lang('config');
// Timezones, if enabled
if ($doing_international) {
$timezone_list = create_selection_list_timezone_list($timezone);
$fields->attach(form_input_list(do_lang_tempcode('TIMEZONE'), do_lang_tempcode('DESCRIPTION_TIMEZONE_MEMBER'), 'timezone', $timezone_list));
}
// Language choice, if we have multiple languages on site
if ($doing_langs) {
$lang_list = new Tempcode();
$no_lang_set = (is_null($language)) || ($language == '');
$allow_no_lang_set = (get_value('allow_no_lang_selection') === '1');
if ($allow_no_lang_set) {
$lang_list->attach(form_input_list_entry('', $no_lang_set, do_lang_tempcode('UNSET')));
} else {
if ($no_lang_set) {
$language = user_lang();
}
}
$lang_list->attach(create_selection_list_langs($language));
$fields->attach(form_input_list(do_lang_tempcode('LANGUAGE'), '', 'language', $lang_list, null, false, !$allow_no_lang_set));
}
if (!$mini_mode) {
// Theme, if we have any zones giving a choice
require_code('themes2');
$entries = create_selection_list_themes($theme, false, false, 'RELY_SITE_DEFAULT');
require_lang('themes');
if ($doing_theme_option) {
$fields->attach(form_input_list(do_lang_tempcode('THEME'), do_lang_tempcode('DESCRIPTION_THEME'), 'theme', $entries));
}
// Various forum options
if (addon_installed('cns_forum')) {
if (get_option('forced_preview_option') == '1') {
$fields->attach(form_input_tick(do_lang_tempcode('PREVIEW_POSTS'), do_lang_tempcode('DESCRIPTION_PREVIEW_POSTS'), 'preview_posts', $preview_posts == 1));
}
if (addon_installed('cns_signatures')) {
if (get_option('enable_views_sigs_option', true) === '1') {
$fields->attach(form_input_tick(do_lang_tempcode('VIEWS_SIGNATURES'), do_lang_tempcode('DESCRIPTION_VIEWS_SIGNATURES'), 'views_signatures', $views_signatures == 1));
} else {
$hidden->attach(form_input_hidden('views_signatures', '1'));
}
}
//$fields->attach(form_input_tick(do_lang_tempcode('AUTO_NOTIFICATION_CONTRIB_CONTENT'), do_lang_tempcode('DESCRIPTION_AUTO_NOTIFICATION_CONTRIB_CONTENT'), 'auto_monitor_contrib_content', $auto_monitor_contrib_content == 1)); Now on notifications tab, even though it is technically an account setting
$usergroup_list = new Tempcode();
$lgroups = $GLOBALS['CNS_DRIVER']->get_usergroup_list(true, true, false, null, null, true);
foreach ($lgroups as $key => $val) {
if ($key != db_get_first_id()) {
$usergroup_list->attach(form_input_list_entry(strval($key), ($pt_allow == '*') || count(array_intersect(array(strval($key)), explode(',', $pt_allow))) != 0, $val));
}
}
if (get_option('enable_pt_restrict') == '1') {
$fields->attach(do_template('FORM_SCREEN_FIELD_SPACER', array('_GUID' => '7e5deb351a7a5214fbff10049839e258', 'TITLE' => do_lang_tempcode('PRIVATE_TOPICS'), 'SECTION_HIDDEN' => ($pt_allow == '*') && ($pt_rules_text == ''))));
$fields->attach(form_input_multi_list(do_lang_tempcode('PT_ALLOW'), addon_installed('chat') ? do_lang_tempcode('PT_ALLOW_DESCRIPTION_CHAT') : do_lang_tempcode('PT_ALLOW_DESCRIPTION'), 'pt_allow', $usergroup_list));
$fields->attach(form_input_text_comcode(do_lang_tempcode('PT_RULES_TEXT'), do_lang_tempcode('PT_RULES_TEXT_DESCRIPTION'), 'pt_rules_text', $pt_rules_text, false));
}
if (get_option('is_on_automatic_mark_topic_read') == '0') {
require_code('users');
$auto_mark_read = $GLOBALS['FORUM_DRIVER']->get_member_row_field($member_id, 'm_auto_mark_read');
$fields->attach(form_input_tick(do_lang_tempcode('ENABLE_AUTO_MARK_READ'), do_lang_tempcode('DESCRIPTION_ENABLE_AUTO_MARK_READ'), 'auto_mark_read', $auto_mark_read == 1));
} else {
$hidden->attach(form_input_hidden('auto_mark_read', '1'));
}
}
// Prepare list of usergroups, if maybe we are gonna let (a) usergroup-change field(s)
$group_count = $GLOBALS['FORUM_DB']->query_select_value('f_groups', 'COUNT(*)');
$rows = $GLOBALS['FORUM_DB']->query_select('f_groups', array('id', 'g_name', 'g_hidden', 'g_open_membership'), ($group_count > 200) ? array('g_is_private_club' => 0) : null, 'ORDER BY g_order,' . $GLOBALS['FORUM_DB']->translate_field_ref('g_name'));
$_groups = new Tempcode();
$default_primary_group = get_first_default_group();
$current_primary_group = null;
foreach ($rows as $group) {
if ($group['id'] != db_get_first_id()) {
$selected = ($group['id'] == $primary_group) || (is_null($primary_group) && ($group['id'] == $default_primary_group));
if ($selected) {
$current_primary_group = $group['id'];
}
$_groups->attach(form_input_list_entry(strval($group['id']), $selected, get_translated_text($group['g_name'], $GLOBALS['FORUM_DB'])));
}
}
// Some admin options...
if (has_privilege(get_member(), 'member_maintenance')) {
$fields->attach(do_template('FORM_SCREEN_FIELD_SPACER', array('_GUID' => '04422238c372edd0b11c11a05feb6267', 'TITLE' => do_lang_tempcode('MEMBER_ACCESS'))));
// Probation
if (has_privilege(get_member(), 'probate_members')) {
if ((!is_null($member_id)) && ($member_id != get_member())) { // Can't put someone new on probation, and can't put yourself on probation
$fields->attach(form_input_date(do_lang_tempcode('ON_PROBATION_UNTIL'), do_lang_tempcode('DESCRIPTION_ON_PROBATION_UNTIL'), 'on_probation_until', false, is_null($on_probation_until) || $on_probation_until <= time(), true, $on_probation_until, 2));
}
}
// Primary usergroup
if (cns_field_editable('primary_group', $special_type)) {
if (has_privilege(get_member(), 'assume_any_member')) {
if ((is_null($member_id)) || (!$GLOBALS['FORUM_DRIVER']->is_super_admin($member_id)) || (count($GLOBALS['FORUM_DRIVER']->member_group_query($GLOBALS['FORUM_DRIVER']->get_super_admin_groups(), 2)) > 1)) {
$fields->attach(form_input_list(do_lang_tempcode('PRIMARY_GROUP'), do_lang_tempcode('DESCRIPTION_PRIMARY_GROUP'), 'primary_group', $_groups));
}
}
}
}
// Secondary usergroups
if (cns_field_editable('secondary_groups', $special_type)) {
$_groups2 = new Tempcode();
$members_groups = is_null($member_id) ? array() : cns_get_members_groups($member_id, false, false, false);
foreach ($rows as $group) {
if (($group['g_hidden'] == 1) && (!array_key_exists($group['id'], $members_groups)) && (!has_privilege(get_member(), 'see_hidden_groups'))) {
continue;
}
if (($group['id'] != db_get_first_id()) && ((array_key_exists($group['id'], $members_groups)) || (has_privilege(get_member(), 'assume_any_member')) || ($group['g_open_membership'] == 1))) {
$selected = array_key_exists($group['id'], $members_groups) && ($group['id'] != $current_primary_group);
$_groups2->attach(form_input_list_entry(strval($group['id']), $selected, get_translated_text($group['g_name'], $GLOBALS['FORUM_DB'])));
}
}
$sec_url = build_url(array('page' => 'groups', 'type' => 'browse'), get_module_zone('groups'));
if (!$_groups2->is_empty()) {
$fields->attach(form_input_multi_list(do_lang_tempcode('SECONDARY_GROUP_MEMBERSHIP'), do_lang_tempcode('DESCRIPTION_SECONDARY_GROUP', escape_html($sec_url->evaluate())), 'secondary_groups', $_groups2));
}
}
// Special admin options
if (has_privilege(get_member(), 'member_maintenance')) {
if ($validated == 0) {
$validated = get_param_integer('validated', 0);
if (($validated == 1) && (addon_installed('unvalidated'))) {
attach_message(do_lang_tempcode('WILL_BE_VALIDATED_WHEN_SAVING'));
}
}
if (addon_installed('unvalidated')) {
$fields->attach(form_input_tick(do_lang_tempcode('VALIDATED'), do_lang_tempcode('DESCRIPTION_MEMBER_VALIDATED'), 'validated', $validated == 1));
}
if (get_option('enable_highlight_name') == '1') {
$fields->attach(form_input_tick(do_lang_tempcode('HIGHLIGHTED_NAME'), do_lang_tempcode(addon_installed('pointstore') ? 'DESCRIPTION_HIGHLIGHTED_NAME_P' : 'DESCRIPTION_HIGHLIGHTED_NAME'), 'highlighted_name', $highlighted_name == 1));
}
if ((!is_null($member_id)) && ($member_id != get_member())) {// Can't ban someone new, and can't ban yourself
$fields->attach(form_input_tick(do_lang_tempcode('BANNED'), do_lang_tempcode('DESCRIPTION_MEMBER_BANNED'), 'is_perm_banned', $is_perm_banned == 1));
}
}
if (addon_installed('content_reviews')) {
require_code('content_reviews2');
$fields->attach(content_review_get_fields('member', is_null($member_id) ? null : strval($member_id)));
}
}
return array($fields, $hidden);
}
/**
* Get form fields for adding/editing/finishing a member profile.
*
* @param boolean $mini_mode Whether we are only handling the essential details of a profile.
* @param ?MEMBER $member_id The ID of the member we are handling (null: new member).
* @param ?array $groups A list of usergroups (null: default/current usergroups).
* @param ?array $custom_fields A map of custom fields values (field-id=>value) (null: not known).
* @return array A pair: The form fields, Hidden fields (both Tempcode).
*/
function cns_get_member_fields_profile($mini_mode = true, $member_id = null, $groups = null, $custom_fields = null)
{
require_code('cns_members_action');
$fields = new Tempcode();
$hidden = new Tempcode();
if (is_null($groups)) {
$groups = is_null($member_id) ? cns_get_all_default_groups(true) : $GLOBALS['CNS_DRIVER']->get_members_groups($member_id);
}
$_custom_fields = cns_get_all_custom_fields_match(
$groups, // groups
($mini_mode || (is_null($member_id)) || ($member_id == get_member()) || (has_privilege(get_member(), 'view_any_profile_field'))) ? null : 1, // public view
null, // owner view
($mini_mode || (is_null($member_id)) || ($member_id != get_member()) || (has_privilege(get_member(), 'view_any_profile_field'))) ? null : 1, // owner set
null, // required
null, // show in posts
null, // show in post previews
null, // special start
$mini_mode ? true : null // show on join form
);
$GLOBALS['NO_DEV_MODE_FULLSTOP_CHECK'] = true;
$field_groups = array();
require_code('fields');
require_code('encryption');
foreach ($_custom_fields as $custom_field) {
$ob = get_fields_hook($custom_field['cf_type']);
list(, , $storage_type) = $ob->get_field_value_row_bits($custom_field);
$existing_field = (!is_null($custom_fields)) && (array_key_exists($custom_field['trans_name'], $custom_fields));
if ($existing_field) {
$value = $custom_fields[$custom_field['trans_name']]['RAW'];
if (($custom_field['cf_encrypted'] == 1) && (is_encryption_enabled())) {
$value = remove_magic_encryption_marker($value);
}
if (!member_field_is_required($member_id, 'required_cpfs', $value) && $custom_field['cf_type'] != 'tick'/*HACKHACK*/) {
$custom_field['cf_required'] = 0;
}
} else {
$value = $custom_field['cf_default'];
if (!member_field_is_required($member_id, 'required_cpfs', '')) {
$custom_field['cf_required'] = 0;
}
}
$result = mixed();
$_description = escape_html(get_translated_text($custom_field['cf_description'], $GLOBALS['FORUM_DB']));
$field_cat = '';
$matches = array();
if (strpos($custom_field['trans_name'], ': ') !== false) {
$field_cat = substr($custom_field['trans_name'], 0, strpos($custom_field['trans_name'], ': '));
if ($field_cat . ': ' == $custom_field['trans_name']) {
$custom_field['trans_name'] = $field_cat; // Just been pulled out as heading, nothing after ": "
} else {
$custom_field['trans_name'] = substr($custom_field['trans_name'], strpos($custom_field['trans_name'], ': ') + 2);
}
} elseif (preg_match('#(^\([A-Z][^\)]*\) )|( \([A-Z][^\)]*\)$)#', $custom_field['trans_name'], $matches) != 0) {
$field_cat = trim($matches[0], '() ');
$custom_field['trans_name'] = str_replace($matches[0], '', $custom_field['trans_name']);
}
$result = $ob->get_field_inputter($custom_field['trans_name'], $_description, $custom_field, $value, !$existing_field);
if (!array_key_exists($field_cat, $field_groups)) {
$field_groups[$field_cat] = new Tempcode();
}
if (is_array($result)) {
$field_groups[$field_cat]->attach($result[0]);
$hidden->attach($result[1]);
} else {
$field_groups[$field_cat]->attach($result);
}
}
if (array_key_exists('', $field_groups)) { // Blank prefix must go first
$field_groups_blank = $field_groups[''];
unset($field_groups['']);
$field_groups = array_merge(array($field_groups_blank), $field_groups);
}
foreach ($field_groups as $field_group_title => $extra_fields) {
if (is_integer($field_group_title)) {
$field_group_title = ($field_group_title == 0) ? '' : strval($field_group_title);
}
if ($field_group_title != '') {
$fields->attach(do_template('FORM_SCREEN_FIELD_SPACER', array(
'_GUID' => 'af91e3c040a0a18a4d9cc1143c0d2007',
'TITLE' => $field_group_title,
'SECTION_HIDDEN' => (get_page_name() == 'admin_cns_members'),
)));
}
$fields->attach($extra_fields);
}
$GLOBALS['NO_DEV_MODE_FULLSTOP_CHECK'] = false;
return array($fields, $hidden);
}
/**
* Edit a member.
*
* @param AUTO_LINK $member_id The ID of the member.
* @param ?SHORT_TEXT $email_address The e-mail address. (null: don't change)
* @param ?BINARY $preview_posts Whether posts are previewed before they are made. (null: don't change)
* @param ?integer $dob_day Day of date of birth. (null: don't change) (-1: deset)
* @param ?integer $dob_month Month of date of birth. (null: don't change) (-1: deset)
* @param ?integer $dob_year Year of date of birth. (null: don't change) (-1: deset)
* @param ?ID_TEXT $timezone The member timezone. (null: don't change)
* @param ?GROUP $primary_group The members primary (null: don't change).
* @param array $custom_fields A map of custom fields values (field-id=>value).
* @param ?ID_TEXT $theme The members default theme. (null: don't change)
* @param ?BINARY $reveal_age Whether the members age may be shown. (null: don't change)
* @param ?BINARY $views_signatures Whether the member sees signatures in posts. (null: don't change)
* @param ?BINARY $auto_monitor_contrib_content Whether the member automatically is enabled for notifications for content they contribute to. (null: don't change)
* @param ?LANGUAGE_NAME $language The members language. (null: don't change)
* @param ?BINARY $allow_emails Whether the member allows e-mails via the site. (null: don't change)
* @param ?BINARY $allow_emails_from_staff Whether the member allows e-mails from staff via the site. (null: don't change)
* @param ?BINARY $validated Whether the profile has been validated (null: do not change this). (null: don't change)
* @param ?string $username The username. (null: don't change)
* @param ?string $password The password. (null: don't change)
* @param ?BINARY $highlighted_name Whether the member username will be highlighted. (null: don't change)
* @param ?SHORT_TEXT $pt_allow Usergroups that may PT the member. (null: don't change)
* @param ?LONG_TEXT $pt_rules_text Rules that other members must agree to before they may start a PT with the member. (null: don't change)
* @param ?TIME $on_probation_until When the member is on probation until (null: don't change)
* @param ?BINARY $auto_mark_read Mark topics as read automatically (null: don't change)
* @param ?TIME $join_time When the member joined (null: don't change)
* @param ?URLPATH $avatar_url Avatar (null: don't change)
* @param ?LONG_TEXT $signature Signature (null: don't change)
* @param ?BINARY $is_perm_banned Banned status (null: don't change)
* @param ?URLPATH $photo_url Photo URL (null: don't change)
* @param ?URLPATH $photo_thumb_url URL of thumbnail of photo (null: don't change)
* @param ?SHORT_TEXT $salt Password salt (null: don't change)
* @param ?ID_TEXT $password_compatibility_scheme Password compatibility scheme (null: don't change)
* @param boolean $skip_checks Whether to skip security checks and most of the change-triggered emails
*/
function cns_edit_member($member_id, $email_address, $preview_posts, $dob_day, $dob_month, $dob_year, $timezone, $primary_group, $custom_fields, $theme, $reveal_age, $views_signatures, $auto_monitor_contrib_content, $language, $allow_emails, $allow_emails_from_staff, $validated = null, $username = null, $password = null, $highlighted_name = null, $pt_allow = '*', $pt_rules_text = '', $on_probation_until = null, $auto_mark_read = null, $join_time = null, $avatar_url = null, $signature = null, $is_perm_banned = null, $photo_url = null, $photo_thumb_url = null, $salt = null, $password_compatibility_scheme = null, $skip_checks = false)
{
require_code('type_sanitisation');
require_code('cns_members_action');
$update = array();
if (!$skip_checks) {
$old_email_address = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_email_address');
$email_address_required = member_field_is_required($member_id, 'email_address');
if ((!is_null($email_address)) && ($email_address != '') && ($email_address != STRING_MAGIC_NULL) && (!is_email_address($email_address))) {
warn_exit(do_lang_tempcode('_INVALID_EMAIL_ADDRESS', escape_html($email_address)));
}
if ((get_option('one_per_email_address') != '0') && ($email_address != '') && ($email_address != $old_email_address) && ($email_address != STRING_MAGIC_NULL)) {
$test = $GLOBALS['FORUM_DB']->query_select_value_if_there('f_members', 'id', array('m_email_address' => $email_address));
if ((!is_null($test)) && ($test != $member_id)) {
warn_exit(do_lang_tempcode('_EMAIL_ADDRESS_IN_USE'));
}
}
}
if (!is_null($username)) {
if (!$skip_checks) {
cns_check_name_valid($username, $member_id, $password);
require_code('urls2');
suggest_new_idmoniker_for('members', 'view', strval($member_id), '', $username);
}
}
if (!is_null($password)) { // Password change
if ((is_null($password_compatibility_scheme)) && (get_value('no_password_hashing') === '1')) {
$password_compatibility_scheme = 'plain';
$update['m_password_change_code'] = '';
$salt = '';
}
if ((!is_null($salt)) || (!is_null($password_compatibility_scheme))) {
if (!is_null($salt)) {
$update['m_pass_salt'] = $salt;
}
if (!is_null($password_compatibility_scheme)) {
$update['m_password_compat_scheme'] = $password_compatibility_scheme;
}
$update['m_pass_hash_salted'] = $password;
} else {
require_code('crypt');
$update['m_password_change_code'] = '';
$salt = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_pass_salt');
$update['m_pass_hash_salted'] = ratchet_hash($password, $salt);
$update['m_password_compat_scheme'] = '';
}
$password_change_days = get_option('password_change_days');
if (intval($password_change_days) > 0) {
if ($password_compatibility_scheme == '') {
require_code('password_rules');
bump_password_change_date($member_id, $password, $update['m_pass_hash_salted'], $salt, $skip_checks);
$update['m_last_visit_time'] = time(); // Needed when an admin changing another password (but okay always): So that the password isn't assumed auto-expired, forcing them to reset it again
}
}
}
// Supplement custom field values given with defaults, and check constraints
$all_fields = cns_get_all_custom_fields_match($GLOBALS['CNS_DRIVER']->get_members_groups($member_id));
foreach ($all_fields as $field) {
$field_id = $field['id'];
if (array_key_exists($field_id, $custom_fields)) {
if (!$skip_checks) {
if (($field['cf_owner_set'] == 0) && ($member_id == get_member()) && (!has_privilege(get_member(), 'view_any_profile_field'))) {
access_denied('I_ERROR');
}
}
}
}
// Set custom profile field values
$all_fields_types = collapse_2d_complexity('id', 'cf_type', $all_fields);
$changes = array();
foreach ($custom_fields as $field_id => $value) {
if (!array_key_exists($field_id, $all_fields_types)) {
continue; // Trying to set a field we're not allowed to (doesn't apply to our group)
}
$change = cns_set_custom_field($member_id, $field_id, $value, $all_fields_types[$field_id], true);
if (!is_null($change)) {
$changes = array_merge($changes, $change);
}
}
if (count($changes) != 0) {
$GLOBALS['FORUM_DB']->query_update('f_member_custom_fields', $changes, array('mf_member_id' => $member_id), '', 1);
}
$old_primary_group = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_primary_group');
$_pt_rules_text = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_pt_rules_text');
$_signature = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_signature');
if (!is_null($theme)) {
$update['m_theme'] = $theme;
}
if (!is_null($preview_posts)) {
$update['m_preview_posts'] = $preview_posts;
}
if (!is_null($dob_day)) {
$update['m_dob_day'] = ($dob_day == -1) ? null : $dob_day;
}
if (!is_null($dob_month)) {
$update['m_dob_month'] = ($dob_month == -1) ? null : $dob_month;
}
if (!is_null($dob_year)) {
$update['m_dob_year'] = ($dob_year == -1) ? null : $dob_year;
}
if (!is_null($timezone)) {
$update['m_timezone_offset'] = $timezone;
}
if (!is_null($reveal_age)) {
$update['m_reveal_age'] = $reveal_age;
}
if (!is_null($email_address)) {
$update['m_email_address'] = $email_address;
}
if (!is_null($views_signatures)) {
$update['m_views_signatures'] = $views_signatures;
}
if (!is_null($auto_monitor_contrib_content)) {
$update['m_auto_monitor_contrib_content'] = $auto_monitor_contrib_content;
}
if (!is_null($language)) {
$update['m_language'] = $language;
}
$doing_email_option = (get_option('allow_email_disable') == '1') && (addon_installed('cns_contact_member'));
if ((!is_null($allow_emails)) && ($doing_email_option)) {
$update['m_allow_emails'] = $allow_emails;
}
$doing_email_from_staff_option = (get_option('allow_email_from_staff_disable') == '1');
if ((!is_null($allow_emails_from_staff)) && ($doing_email_from_staff_option)) {
$update['m_allow_emails_from_staff'] = $allow_emails_from_staff;
}
if (!is_null($pt_allow)) {
$update['m_pt_allow'] = $pt_allow;
}
if (!is_null($pt_rules_text)) {
$update += lang_remap_comcode('m_pt_rules_text', $_pt_rules_text, $pt_rules_text, $GLOBALS['FORUM_DB']);
}
if (($skip_checks) || (has_privilege(get_member(), 'probate_members'))) {
$update['m_on_probation_until'] = $on_probation_until;
}
if (!is_null($auto_mark_read)) {
$update['m_auto_mark_read'] = $auto_mark_read;
}
if (!is_null($join_time)) {
$update['m_join_time'] = $join_time;
}
if (!is_null($avatar_url)) {
$update['m_avatar_url'] = $avatar_url;
}
if (!is_null($signature)) {
$update += lang_remap_comcode('m_signature', $_signature, $signature, $GLOBALS['FORUM_DB']);
}
if (!is_null($is_perm_banned)) {
$update['m_is_perm_banned'] = $is_perm_banned;
}
if (!is_null($photo_url)) {
$update['m_photo_url'] = $photo_url;
}
if (!is_null($photo_thumb_url)) {
$update['m_photo_thumb_url'] = $photo_thumb_url;
}
$old_username = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_username');
if ((!is_null($username)) && (!is_null($old_username)) && ($username != $old_username) && (($skip_checks) || (has_actual_page_access(get_member(), 'admin_cns_members')) || (has_privilege($member_id, 'rename_self')))) { // Username change
$update['m_username'] = $username;
// Reassign personal galleries
if (addon_installed('galleries')) {
require_lang('galleries');
$personal_galleries = $GLOBALS['SITE_DB']->query('SELECT name,fullname,parent_id FROM ' . get_table_prefix() . 'galleries WHERE name LIKE \'member\_' . strval($member_id) . '\_%\'');
foreach ($personal_galleries as $gallery) {
$parent_title = get_translated_text($GLOBALS['SITE_DB']->query_select_value('galleries', 'fullname', array('name' => $gallery['parent_id'])));
if (get_translated_text($gallery['fullname']) == do_lang('PERSONAL_GALLERY_OF', $old_username, $parent_title)) {
$new_fullname = do_lang('PERSONAL_GALLERY_OF', $username, $parent_title);
$GLOBALS['SITE_DB']->query_update('galleries', lang_remap_comcode('fullname', $gallery['fullname'], $new_fullname), array('name' => $gallery['name']), '', 1);
}
}
}
require_code('notifications');
$subject = do_lang('USERNAME_CHANGED_MAIL_SUBJECT', $username, $old_username, null, get_lang($member_id));
$mail = do_notification_lang('USERNAME_CHANGED_MAIL', comcode_escape(get_site_name()), comcode_escape($username), comcode_escape($old_username), get_lang($member_id));
dispatch_notification('cns_username_changed', null, $subject, $mail, array($member_id));
$subject = do_lang('STAFF_USERNAME_CHANGED_MAIL_SUBJECT', $username, $old_username, null, get_site_default_lang());
$mail = do_notification_lang('STAFF_USERNAME_CHANGED_MAIL', comcode_escape(get_site_name()), comcode_escape($username), comcode_escape($old_username), get_site_default_lang());
dispatch_notification('cns_username_changed_staff', null, $subject, $mail, null, get_member(), 3, false, false, null, null, '', '', '', '', null, true);
if (addon_installed('news')) {
$GLOBALS['SITE_DB']->query_update('news', array('author' => $username), array('author' => $old_username));
}
update_member_username_caching($member_id, $username);
}
if (!is_null($password)) { // Password change
// Security, clear out sessions from other people on this user - just in case the reset is due to suspicious activity
$GLOBALS['SITE_DB']->query('DELETE FROM ' . get_table_prefix() . 'sessions WHERE member_id=' . strval($member_id) . ' AND ' . db_string_not_equal_to('the_session', get_session_id()));
if (!$skip_checks) {
if (($member_id == get_member()) || (get_value('disable_password_change_notifications_for_staff') !== '1')) {
if (get_page_name() != 'admin_cns_members') {
require_code('notifications');
$part_b = '';
if (!has_actual_page_access(get_member(), 'admin_cns_members')) {
$part_b = do_lang('PASSWORD_CHANGED_MAIL_BODY_2', get_ip_address());
}
$mail = do_notification_lang('PASSWORD_CHANGED_MAIL_BODY', get_site_name(), $part_b, null, get_lang($member_id));
dispatch_notification('cns_password_changed', null, do_lang('PASSWORD_CHANGED_MAIL_SUBJECT', null, null, null, get_lang($member_id)), $mail, array($member_id), null, 2);
}
}
}
}
if (!is_null($validated)) {
$update['m_validated_email_confirm_code'] = '';
if (addon_installed('unvalidated')) {
$update['m_validated'] = $validated;
if (($validated == 1) && ($GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_validated') == 0)) {
$update['m_join_time'] = time(); // So welcome mails go out correctly
}
}
}
if (!is_null($highlighted_name)) {
$update['m_highlighted_name'] = $highlighted_name;
}
if (!is_null($primary_group)) {
$update['m_primary_group'] = $primary_group;
if ($primary_group != $old_primary_group) {
$GLOBALS['FORUM_DB']->query_insert('f_group_join_log', array(
'member_id' => $member_id,
'usergroup_id' => $primary_group,
'join_time' => time()
));
log_it('MEMBER_PRIMARY_GROUP_CHANGED', strval($member_id), strval($primary_group));
}
}
$join_time = $GLOBALS['FORUM_DRIVER']->get_member_row_field($member_id, 'm_join_time');
$GLOBALS['FORUM_DB']->query_update('f_members', $update, array('id' => $member_id), '', 1);
if (get_member() != $member_id) {
log_it('EDIT_MEMBER_PROFILE', strval($member_id), $username);
}
$old_validated = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_validated');
if (($old_validated == 0) && ($validated == 1)) {
require_code('mail');
$_login_url = build_url(array('page' => 'login'), get_module_zone('login'), null, false, false, true);
$login_url = $_login_url->evaluate();
$_username = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_username');
// NB: Same mail also sent in settings.php (quick-validate feature)
$vm_subject = do_lang('VALIDATED_MEMBER_SUBJECT', get_site_name(), null, get_lang($member_id));
$vm_body = do_lang('MEMBER_VALIDATED', get_site_name(), $_username, $login_url, get_lang($member_id));
mail_wrap($vm_subject, $vm_body, array($email_address), $_username, '', '', 3, null, false, null, false, false, false, 'MAIL', false, null, null, $join_time);
}
$old_email_address = $GLOBALS['FORUM_DRIVER']->get_member_row_field($member_id, 'm_email_address');
if ($old_email_address != $email_address) {
$GLOBALS['FORUM_DB']->query_update('f_invites', array('i_email_address' => $old_email_address), array('i_email_address' => $email_address));
}
delete_value('cns_newest_member_id');
delete_value('cns_newest_member_username');
// Decache from run-time cache
unset($GLOBALS['FORUM_DRIVER']->MEMBER_ROWS_CACHED[$member_id]);
unset($GLOBALS['MEMBER_CACHE_FIELD_MAPPINGS'][$member_id]);
unset($GLOBALS['TIMEZONE_MEMBER_CACHE'][$member_id]);
unset($GLOBALS['USER_NAME_CACHE'][$member_id]);
if ((addon_installed('commandr')) && (!running_script('install')) && (!get_mass_import_mode())) {
require_code('resource_fs');
generate_resource_fs_moniker('member', strval($member_id));
}
decache('main_members');
if (($GLOBALS['FORUM_DRIVER']->is_super_admin($member_id)) && ($old_email_address == '')) {
decache('main_staff_checklist'); // As it tracks whether admin have e-mail address set
}
require_code('sitemap_xml');
notify_sitemap_node_edit('_SEARCH:members:view:' . strval($member_id), true);
}
/**
* Delete a member.
*
* @param AUTO_LINK $member_id The ID of the member.
*/
function cns_delete_member($member_id)
{
$username = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_username');
$signature = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_signature');
require_code('attachments2');
require_code('attachments3');
delete_lang_comcode_attachments($signature, 'signature', strval($member_id), $GLOBALS['FORUM_DB']);
$GLOBALS['FORUM_DB']->query_delete('f_members', array('id' => $member_id), '', 1);
$GLOBALS['FORUM_DB']->query_delete('f_group_members', array('gm_member_id' => $member_id));
$GLOBALS['FORUM_DB']->query_update('f_groups', array('g_group_leader' => get_member()), array('g_group_leader' => $member_id));
$GLOBALS['SITE_DB']->query_delete('sessions', array('member_id' => $member_id));
require_code('fields');
// Delete custom profile fields
$cpfs = $GLOBALS['FORUM_DB']->query_select('f_custom_fields');
$fields_row = $GLOBALS['FORUM_DB']->query_select('f_member_custom_fields', array('*'), array('mf_member_id' => $member_id), '', 1);
if (array_key_exists(0, $fields_row)) {
foreach ($cpfs as $field) {
$l = $fields_row[0]['field_' . strval($field['id'])];
$object = get_fields_hook($field['cf_type']);
list(, , $storage_type) = $object->get_field_value_row_bits($field);
if (method_exists($object, 'cleanup')) {
$object->cleanup(array('cv_value' => $l));
}
if ((strpos($storage_type, '_trans') !== false) && (!is_null($l))) {
if (true) { // Always do this just in case it is for attachments
require_code('attachments2');
require_code('attachments3');
delete_lang_comcode_attachments($l, 'null', strval($member_id), $GLOBALS['FORUM_DB']);
} else {
delete_lang($l, $GLOBALS['FORUM_DB']);
}
}
}
}
$GLOBALS['FORUM_DB']->query_delete('f_member_custom_fields', array('mf_member_id' => $member_id), '', 1);
// Cleanup images
$old = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_avatar_url');
if ((url_is_local($old)) && ((substr($old, 0, 20) == 'uploads/cns_avatars/') || (substr($old, 0, 16) == 'uploads/avatars/'))) {
@unlink(get_custom_file_base() . '/' . rawurldecode($old));
sync_file(rawurldecode($old));
}
$old = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_photo_url');
if ((url_is_local($old)) && ((substr($old, 0, 19) == 'uploads/cns_photos/') || (substr($old, 0, 15) == 'uploads/photos/'))) {
@unlink(get_custom_file_base() . '/' . rawurldecode($old));
sync_file(rawurldecode($old));
}
if (addon_installed('catalogues')) {
update_catalogue_content_ref('member', strval($member_id), '');
}
delete_value('cns_newest_member_id');
delete_value('cns_newest_member_username');
log_it('DELETE_MEMBER', strval($member_id), $username);
if ((addon_installed('commandr')) && (!running_script('install')) && (!get_mass_import_mode())) {
require_code('resource_fs');
expunge_resource_fs_moniker('member', strval($member_id));
}
decache('main_members');
require_code('sitemap_xml');
notify_sitemap_node_delete('_SEARCH:members:view:' . strval($member_id));
}
/**
* Ban a member.
*
* @param AUTO_LINK $member_id The ID of the member.
*/
function cns_ban_member($member_id)
{
if ($GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_is_perm_banned') == 1) {
return;
}
require_code('mail');
$username = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_username');
$email_address = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_email_address');
$join_time = $GLOBALS['FORUM_DRIVER']->get_member_row_field($member_id, 'm_join_time');
$GLOBALS['FORUM_DB']->query_update('f_members', array('m_is_perm_banned' => 1), array('id' => $member_id), '', 1);
log_it('BAN_MEMBER', strval($member_id), $username);
require_lang('cns');
$mail = do_lang('BAN_MEMBER_MAIL', $username, get_site_name(), array(), get_lang($member_id));
mail_wrap(do_lang('BAN_MEMBER_MAIL_SUBJECT', null, null, null, get_lang($member_id)), $mail, array($email_address), $username, '', '', 2, null, false, null, false, false, false, 'MAIL', false, null, null, $join_time);
decache('main_members');
unset($GLOBALS['FORUM_DRIVER']->MEMBER_ROWS_CACHED[$member_id]);
}
/**
* Unban a member.
*
* @param AUTO_LINK $member_id The ID of the member.
*/
function cns_unban_member($member_id)
{
if ($GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_is_perm_banned') == 0) {
return;
}
$username = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_username');
$email_address = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_email_address');
$join_time = $GLOBALS['FORUM_DRIVER']->get_member_row_field($member_id, 'm_join_time');
$GLOBALS['FORUM_DB']->query_update('f_members', array('m_is_perm_banned' => 0), array('id' => $member_id), '', 1);
log_it('UNBAN_MEMBER', strval($member_id), $username);
require_lang('cns');
$mail = do_lang('UNBAN_MEMBER_MAIL', $username, get_site_name(), array(), get_lang($member_id));
mail_wrap(do_lang('UNBAN_MEMBER_MAIL_SUBJECT', null, null, null, get_lang($member_id)), $mail, array($email_address), $username, '', '', 2, null, false, null, false, false, false, 'MAIL', false, null, null, $join_time);
decache('main_members');
unset($GLOBALS['FORUM_DRIVER']->MEMBER_ROWS_CACHED[$member_id]);
}
/**
* Edit a custom profile field.
*
* @param AUTO_LINK $id The ID of the custom profile field.
* @param SHORT_TEXT $name Name of the field.
* @param SHORT_TEXT $description Description of the field.
* @param LONG_TEXT $default The default value for the field.
* @param BINARY $public_view Whether the field is publicly viewable.
* @param BINARY $owner_view Whether the field is viewable by the owner.
* @param BINARY $owner_set Whether the field may be set by the owner.
* @param BINARY $encrypted Whether the field should be encrypted.
* @param BINARY $required Whether the field is to be shown on the join form
* @param BINARY $show_in_posts Whether this field is shown in posts and places where member details are highlighted (such as an image in a member gallery).
* @param BINARY $show_in_post_previews Whether this field is shown in preview places, such as in the forum member tooltip.
* @param ?integer $order The order of this field relative to other fields. (null: keep the current order)
* @param LONG_TEXT $only_group The usergroups that this field is confined to (comma-separated list).
* @param ID_TEXT $type The type of the field.
* @set short_text long_text short_trans long_trans integer upload picture url list tick float
* @param BINARY $show_on_join_form Whether it is required that every member have this field filled in.
* @param SHORT_TEXT $options Field options
*/
function cns_edit_custom_field($id, $name, $description, $default, $public_view, $owner_view, $owner_set, $encrypted, $required, $show_in_posts, $show_in_post_previews, $order, $only_group, $type, $show_on_join_form, $options)
{
$dbs_back = $GLOBALS['NO_DB_SCOPE_CHECK'];
$GLOBALS['NO_DB_SCOPE_CHECK'] = true;
if ($only_group == '-1') {
$only_group = '';
}
$info = $GLOBALS['FORUM_DB']->query_select('f_custom_fields', array('cf_name', 'cf_description'), array('id' => $id), '', 1);
$_name = $info[0]['cf_name'];
$_description = $info[0]['cf_description'];
$map = array(
'cf_default' => $default,
'cf_public_view' => $public_view,
'cf_owner_view' => $owner_view,
'cf_owner_set' => $owner_set,
'cf_required' => $required,
'cf_show_in_posts' => $show_in_posts,
'cf_show_in_post_previews' => $show_in_post_previews,
'cf_only_group' => $only_group,
'cf_type' => $type,
'cf_show_on_join_form' => $show_on_join_form,
'cf_options' => $options,
);
$map += lang_remap('cf_name', $_name, $name, $GLOBALS['FORUM_DB']);
$map += lang_remap('cf_description', $_description, $description, $GLOBALS['FORUM_DB']);
if ($order !== null) {
$map['cf_order'] = $order;
}
$GLOBALS['FORUM_DB']->query_update('f_custom_fields', $map, array('id' => $id), '', 1);
require_code('cns_members_action');
list($_type, $index) = get_cpf_storage_for($type);
require_code('database_action');
if (substr(get_db_type(), 0, 5) == 'mysql') {
$GLOBALS['SITE_DB']->query('SET sql_mode=\'\'', null, null, true); // Turn off strict mode
}
$GLOBALS['FORUM_DB']->alter_table_field('f_member_custom_fields', 'field_' . strval($id), $_type); // LEGACY: Field type should not have changed, but bugs can happen, especially between CMS versions, so we allow a CPF edit as a "fixup" op
build_cpf_indices($id, $index, $type, $_type);
log_it('EDIT_CUSTOM_PROFILE_FIELD', strval($id), $name);
if ((addon_installed('commandr')) && (!running_script('install')) && (!get_mass_import_mode())) {
require_code('resource_fs');
generate_resource_fs_moniker('cpf', strval($id));
}
$GLOBALS['NO_DB_SCOPE_CHECK'] = $dbs_back;
if (function_exists('persistent_cache_delete')) {
persistent_cache_delete('CUSTOM_FIELD_CACHE');
persistent_cache_delete('LIST_CPFS');
}
decache('main_members');
}
/**
* Delete a custom profile field.
*
* @param AUTO_LINK $id The ID of the custom profile field.
*/
function cns_delete_custom_field($id)
{
$dbs_back = $GLOBALS['NO_DB_SCOPE_CHECK'];
$GLOBALS['NO_DB_SCOPE_CHECK'] = true;
$info = $GLOBALS['FORUM_DB']->query_select('f_custom_fields', array('cf_name', 'cf_description'), array('id' => $id), '', 1);
if (!array_key_exists(0, $info)) {
warn_exit(do_lang_tempcode('MISSING_RESOURCE', 'cpf'));
}
$_name = $info[0]['cf_name'];
$_description = $info[0]['cf_description'];
require_code('database_action');
delete_lang($_name, $GLOBALS['FORUM_DB']);
delete_lang($_description, $GLOBALS['FORUM_DB']);
$GLOBALS['FORUM_DB']->delete_index_if_exists('f_member_custom_fields', 'mcf' . strval($id));
$GLOBALS['FORUM_DB']->delete_index_if_exists('f_member_custom_fields', '#mcf_ft_' . strval($id));
$GLOBALS['FORUM_DB']->delete_table_field('f_member_custom_fields', 'field_' . strval($id));
$GLOBALS['FORUM_DB']->query_delete('f_custom_fields', array('id' => $id), '', 1);
$GLOBALS['NO_DB_SCOPE_CHECK'] = $dbs_back;
global $TABLE_LANG_FIELDS_CACHE;
unset($TABLE_LANG_FIELDS_CACHE['f_member_custom_fields']);
log_it('DELETE_CUSTOM_PROFILE_FIELD', strval($id), get_translated_text($_name, $GLOBALS['FORUM_DB']));
if ((addon_installed('commandr')) && (!running_script('install')) && (!get_mass_import_mode())) {
require_code('resource_fs');
expunge_resource_fs_moniker('cpf', strval($id));
}
if (function_exists('persistent_cache_delete')) {
persistent_cache_delete('CUSTOM_FIELD_CACHE');
persistent_cache_delete('LIST_CPFS');
}
if (function_exists('decache')) {
decache('main_members');
}
}
/**
* Set a custom profile field for a member.
*
* @param MEMBER $member_id The member.
* @param AUTO_LINK $field_id The field being set.
* @param mixed $value The value of the field. For a trans-type field, this can be either a lang-ID to be copied (from forum DB), or an actual string.
* @param ?ID_TEXT $type The field type (null: look it up).
* @param boolean $defer Whether to defer the change, by returning a result change rather than doing it right away.
* @return ?array Mapping change (null: none / can't defer).
*/
function cns_set_custom_field($member_id, $field_id, $value, $type = null, $defer = false)
{
if ($value === STRING_MAGIC_NULL) {
return null;
}
if (is_null($type)) {
$type = $GLOBALS['FORUM_DB']->query_select_value('f_custom_fields', 'cf_type', array('id' => $field_id));
}
cns_get_custom_field_mappings($member_id); // This will do an auto-repair if CPF storage row is missing
$db_fieldname = 'field_' . strval($field_id);
global $ANY_FIELD_ENCRYPTED;
if ($ANY_FIELD_ENCRYPTED === null) {
$ANY_FIELD_ENCRYPTED = !is_null($GLOBALS['FORUM_DB']->query_select_value_if_there('f_custom_fields', 'cf_encrypted', array('cf_encrypted' => 1)));
}
if ($ANY_FIELD_ENCRYPTED) {
$encrypted = $GLOBALS['FORUM_DB']->query_select_value('f_custom_fields', 'cf_encrypted', array('id' => $field_id));
if ($encrypted) {
require_code('encryption');
$current = $GLOBALS['FORUM_DB']->query_select_value_if_there('f_member_custom_fields', $db_fieldname, array('mf_member_id' => $member_id));
if ($current === null) {
return null;
}
if ((remove_magic_encryption_marker($value) == remove_magic_encryption_marker($current)) && (is_data_encrypted($current))) {
return null;
}
$value = encrypt_data($value);
}
} else {
$encrypted = false;
}
require_code('fields');
$ob = get_fields_hook($type);
list(, , $storage_type) = $ob->get_field_value_row_bits(array('id' => $field_id, 'cf_default' => '', 'cf_type' => $type));
static $done_one_posting_field = false;
$ret = null;
if (strpos($storage_type, '_trans') !== false) {
if (is_integer($value)) {
$value = get_translated_text($value, $GLOBALS['FORUM_DB']);
}
$map = array();
$current = $GLOBALS['FORUM_DB']->query_select_value_if_there('f_member_custom_fields', $db_fieldname, array('mf_member_id' => $member_id));
if (is_null($current)) {
if (($type == 'posting_field') && (!$done_one_posting_field)) {
$done_one_posting_field = true;
require_code('attachments2');
$map += insert_lang_comcode_attachments($db_fieldname, 3, $value, 'null', strval($member_id), $GLOBALS['FORUM_DB']);
} else {
$map += insert_lang_comcode($db_fieldname, $value, 3, $GLOBALS['FORUM_DB']);
}
$GLOBALS['FORUM_DB']->query_update('f_member_custom_fields', $map, array('mf_member_id' => $member_id), '', 1);
} else {
if (($type == 'posting_field') && (!$done_one_posting_field)) {
$done_one_posting_field = true;
require_code('attachments2');
require_code('attachments3');
$map += update_lang_comcode_attachments($db_fieldname, $current, $value, 'null', strval($member_id), $GLOBALS['FORUM_DB'], $member_id);
} else {
$map += lang_remap_comcode($db_fieldname, $current, $value, $GLOBALS['FORUM_DB']);
}
$GLOBALS['FORUM_DB']->query_update('f_member_custom_fields', $map, array('mf_member_id' => $member_id), '', 1);
}
} else {
$change = array();
if (is_string($value)) {
switch ($storage_type) {
case 'short_trans':
case 'long_trans':
$change += insert_lang($db_fieldname, $value, 3, $GLOBALS['FORUM_DB']);
break;
case 'integer':
$change[$db_fieldname] = ($value == '') ? null : intval($value);
break;
case 'float':
$change[$db_fieldname] = ($value == '') ? null : floatval($value);
break;
default:
$change[$db_fieldname] = $value;
break;
}
} elseif ($value === null) {
switch ($storage_type) {
case 'integer':
case 'float':
$change[$db_fieldname] = $value;
break;
}
} else {
$change[$db_fieldname] = $value;
}
if (!$defer) {
$GLOBALS['FORUM_DB']->query_update('f_member_custom_fields', $change, array('mf_member_id' => $member_id), '', 1);
}
$ret = $change;
}
if (function_exists('decache')) {
decache('main_members');
}
global $MEMBER_CACHE_FIELD_MAPPINGS;
if ((isset($MEMBER_CACHE_FIELD_MAPPINGS)) && (isset($MEMBER_CACHE_FIELD_MAPPINGS[$member_id]))) {
unset($MEMBER_CACHE_FIELD_MAPPINGS[$member_id]);
}
return $ret;
}
/**
* Check a username is valid for adding, and possibly also the password.
*
* @param ?SHORT_TEXT $username The username (may get altered) (null: nothing to check).
* @param ?MEMBER $member_id The member (null: member not actually added yet; this ID is only given for the duplication check, to make sure it doesn't think we are duplicating with ourself).
* @param ?SHORT_TEXT $password The password (null: nothing to check).
* @param boolean $return_errors Whether to return errors instead of dieing on them.
* @return ?Tempcode Error (null: none).
*/
function cns_check_name_valid(&$username, $member_id = null, $password = null, $return_errors = false)
{
// Check it doesn't already exist
if (!is_null($username)) {
$test = is_null($member_id) ? null : $GLOBALS['FORUM_DB']->query_select_value_if_there('f_members', 'id', array('m_username' => $username, 'id' => $member_id)); // Precedence on an ID match in case there are duplicate usernames and user is trying to fix that
if (is_null($test)) {
$test = $GLOBALS['FORUM_DB']->query_select_value_if_there('f_members', 'id', array('m_username' => $username));
}
if ((!is_null($test)) && ($test !== $member_id)) {
$error = do_lang_tempcode('USERNAME_ALREADY_EXISTS');
if ($return_errors) {
return $error;
}
warn_exit($error);
}
$username_changed = is_null($test);
} else {
$username_changed = false;
}
if (!is_null($username)) {
// Check for disallowed symbols in username
$disallowed_characters = array(/*'<','>','&','"',"'",'$',','*/); // Actually we can tolerate this stuff
foreach ($disallowed_characters as $disallowed_character) {
if ((strpos($username, $disallowed_character) !== false) && ($username_changed)) {
$error = do_lang_tempcode('USERNAME_BAD_SYMBOLS', escape_html($disallowed_character));
if ($return_errors) {
return $error;
}
warn_exit($error);
}
}
if ((strpos($username, '@') !== false) && (strpos($username, '.') !== false) && ($username_changed)) {
$error = do_lang_tempcode('USERNAME_BAD_SYMBOLS', escape_html('@ / .'));
if ($return_errors) {
return $error;
}
warn_exit($error);
}
}
// Check lengths
if (get_page_name() != 'admin_cns_members') {
if (!is_null($username)) {
$_maximum_username_length = get_option('maximum_username_length');
$maximum_username_length = intval($_maximum_username_length);
if ((cms_mb_strlen($username) > $maximum_username_length) && ($username_changed)) {
$error = do_lang_tempcode('USERNAME_TOO_LONG', escape_html(integer_format($maximum_username_length)));
if ($return_errors) {
return $error;
}
warn_exit($error);
}
$_minimum_username_length = get_option('minimum_username_length');
$minimum_username_length = intval($_minimum_username_length);
if ((cms_mb_strlen($username) < $minimum_username_length) && ($username_changed)) {
$error = do_lang_tempcode('USERNAME_TOO_SHORT', escape_html(integer_format($minimum_username_length)));
if ($return_errors) {
return $error;
}
warn_exit($error);
}
}
if (!is_null($password)) {
require_code('password_rules');
$test = check_password_complexity($username, $password, $return_errors);
if (!is_null($test)) {
return $test;
}
}
}
// Check for whitespace
if (!is_null($username)) {
$prohibit_username_whitespace = get_option('prohibit_username_whitespace');
if (($prohibit_username_whitespace === '1') && (cms_preg_match_safe('#\s#', $username) != 0) && ($username_changed)) {
$error = do_lang_tempcode('USERNAME_PASSWORD_WHITESPACE');
if ($return_errors) {
return $error;
}
warn_exit($error);
}
}
if (!is_null($password)) {
$prohibit_password_whitespace = get_option('prohibit_password_whitespace');
if (($prohibit_password_whitespace === '1') && (cms_preg_match_safe('#\s#', $password) != 0) && ($username_changed)) {
$error = do_lang_tempcode('USERNAME_PASSWORD_WHITESPACE');
if ($return_errors) {
return $error;
}
warn_exit($error);
}
}
// Check against restricted usernames
if ((get_page_name() != 'admin_cns_members') && ($username_changed)) {
$restricted_usernames = explode(',', get_option('restricted_usernames'));
$restricted_usernames[] = do_lang('GUEST');
$restricted_usernames[] = do_lang('UNKNOWN');
$restricted_usernames[] = do_lang('SYSTEM');
foreach ($restricted_usernames as $_restricted_username) {
$restricted_username = trim($_restricted_username);
if ($restricted_username == '') {
continue;
}
if (strpos($username, $restricted_username) !== false) {
$error = do_lang_tempcode('USERNAME_BAD_SUBSTRING', escape_html($restricted_username));
if ($return_errors) {
return $error;
}
warn_exit($error);
}
}
}
// Check it is not numeric
if (is_numeric($username)) {
$error = do_lang_tempcode('USERNAME_NUMERIC');
if ($return_errors) {
return $error;
}
warn_exit($error);
}
return null;
}
/**
* Edit a member's personal title, and check validity.
*
* @param SHORT_TEXT $new_title The new title.
* @param ?MEMBER $member_id The member (null: the current member).
*/
function cns_member_choose_title($new_title, $member_id = null)
{
if (is_null($member_id)) {
$member_id = get_member();
}
$old_title = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_title');
if ($old_title == $new_title) {
return;
}
if (cms_mb_strlen($new_title) > intval(get_option('max_member_title_length'))) {
warn_exit(do_lang_tempcode('MEMBER_TITLE_TOO_BIG'));
}
$GLOBALS['FORUM_DB']->query_update('f_members', array('m_title' => $new_title), array('id' => $member_id), '', 1);
// Decache from run-time cache
unset($GLOBALS['FORUM_DRIVER']->MEMBER_ROWS_CACHED[$member_id]);
unset($GLOBALS['MEMBER_CACHE_FIELD_MAPPINGS'][$member_id]);
decache('main_members');
}
/**
* Edit a member's signature, and check validity.
*
* @param LONG_TEXT $new_signature The new signature.
* @param ?MEMBER $member_id The member (null: the current member).
*/
function cns_member_choose_signature($new_signature, $member_id = null)
{
if (is_null($member_id)) {
$member_id = get_member();
}
$max_sig_length = cns_get_member_best_group_property($member_id, 'max_sig_length_comcode');
if (cms_mb_strlen($new_signature) > $max_sig_length) {
warn_exit(make_string_tempcode(escape_html(do_lang('SIGNATURE_TOO_BIG'))));
}
$_signature = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_signature');
if (get_translated_text($_signature, $GLOBALS['FORUM_DB']) == $new_signature) {
return;
}
require_code('attachments2');
require_code('attachments3');
$map = array();
$map += update_lang_comcode_attachments('m_signature', $_signature, $new_signature, 'cns_signature', strval($member_id), $GLOBALS['FORUM_DB'], $member_id);
$GLOBALS['FORUM_DB']->query_update('f_members', $map, array('id' => $member_id), '', 1);
require_code('notifications');
$subject = do_lang('CHOOSE_SIGNATURE_SUBJECT', $GLOBALS['FORUM_DRIVER']->get_username($member_id, true), $GLOBALS['FORUM_DRIVER']->get_username($member_id), null, get_lang($member_id));
$body = do_notification_lang('CHOOSE_SIGNATURE_BODY', $new_signature, $GLOBALS['FORUM_DRIVER']->get_username($member_id), $GLOBALS['FORUM_DRIVER']->get_username($member_id, true), get_lang($member_id));
dispatch_notification('cns_choose_signature', null, $subject, $body, null, get_member(), 3, false, false, null, null, '', '', '', '', null, true);
// Decache from run-time cache
unset($GLOBALS['FORUM_DRIVER']->MEMBER_ROWS_CACHED[$member_id]);
unset($GLOBALS['MEMBER_CACHE_FIELD_MAPPINGS'][$member_id]);
}
/**
* Edit a member's avatar, and check validity.
*
* @param URLPATH $avatar_url The new avatar URL.
* @param ?MEMBER $member_id The member (null: the current member).
*/
function cns_member_choose_avatar($avatar_url, $member_id = null)
{
if (is_null($member_id)) {
$member_id = get_member();
}
$old = $GLOBALS['FORUM_DB']->query_select_value('f_members', 'm_avatar_url', array('id' => $member_id));
if ($old == $avatar_url) {
return;
}
// Check it has valid dimensions
if ($avatar_url != '') {
require_code('images');
if (!is_image($avatar_url, true)) {
$ext = get_file_extension($avatar_url);
warn_exit(do_lang_tempcode('UNKNOWN_FORMAT', escape_html($ext)));
}
$stub = url_is_local($avatar_url) ? (get_complex_base_url($avatar_url) . '/') : '';
if (function_exists('imagetypes')) {
$file_path_stub = convert_url_to_path($stub . $avatar_url);
if (!is_null($file_path_stub)) {
$from_file = @file_get_contents($file_path_stub);
} else {
$from_file = http_download_file($stub . $avatar_url, 1024 * 1024 * 4/*reasonable limit*/, false);
}
if (is_null($from_file)) {
warn_exit(do_lang_tempcode('MISSING_RESOURCE', do_lang_tempcode('URL')));
}
$test = cms_getimagesizefromstring($from_file, get_file_extension($avatar_url));
if (!$test) {
warn_exit(do_lang_tempcode('CORRUPT_FILE', escape_html($avatar_url)));
}
list($sx, $sy) = $test;
require_code('cns_groups');
$width = cns_get_member_best_group_property($member_id, 'max_avatar_width');
$height = cns_get_member_best_group_property($member_id, 'max_avatar_height');
if (($sx > $width) || ($sy > $height)) {
require_code('images');
$file_path = get_custom_file_base() . '/' . rawurldecode($avatar_url);
if ((!is_saveable_image($file_path)) || (!url_is_local($avatar_url))) {
if ((url_is_local($avatar_url)) && (substr($avatar_url, 0, 20) == 'uploads/cns_avatars/')) {
unlink($file_path);
sync_file(rawurldecode($avatar_url));
}
warn_exit(do_lang_tempcode('IMAGE_BAD_DIMENSIONS', strval($width) . 'x' . strval($height), strval($sx) . 'x' . strval($sy)));
}
convert_image($file_path, $file_path, $width, $height, -1, false, get_file_extension($file_path), true, true);
}
}
if ((substr($avatar_url, 0, 7) != 'themes/') && (addon_installed('cns_avatars'))) {
require_code('notifications');
$subject = do_lang('CHOOSE_AVATAR_SUBJECT', $GLOBALS['FORUM_DRIVER']->get_username($member_id, true), $GLOBALS['FORUM_DRIVER']->get_username($member_id), null, get_lang($member_id));
$body = do_notification_lang('CHOOSE_AVATAR_BODY', $stub . $avatar_url, $GLOBALS['FORUM_DRIVER']->get_username($member_id), $GLOBALS['FORUM_DRIVER']->get_username($member_id, true), get_lang($member_id));
dispatch_notification('cns_choose_avatar', null, $subject, $body, null, get_member(), 3, false, false, null, null, '', '', '', '', null, true);
}
}
// Cleanup old avatar
if ((url_is_local($old)) && ((substr($old, 0, 20) == 'uploads/cns_avatars/') || (substr($old, 0, 16) == 'uploads/avatars/')) && ($old != $avatar_url)) {
@unlink(get_custom_file_base() . '/' . rawurldecode($old));
sync_file(rawurldecode($old));
}
$GLOBALS['FORUM_DB']->query_update('f_members', array('m_avatar_url' => $avatar_url), array('id' => $member_id), '', 1);
// Decache from run-time cache
unset($GLOBALS['FORUM_DRIVER']->MEMBER_ROWS_CACHED[$member_id]);
unset($GLOBALS['MEMBER_CACHE_FIELD_MAPPINGS'][$member_id]);
decache('main_friends_list');
decache('main_members');
}
/**
* Edit a member's photo, and check validity.
*
* @param ID_TEXT $param_name The identifier for the name of the posted URL field.
* @param ID_TEXT $upload_name The identifier for the name of the posted upload.
* @param ?MEMBER $member_id The member (null: the current member).
*/
function cns_member_choose_photo($param_name, $upload_name, $member_id = null)
{
if (is_null($member_id)) {
$member_id = get_member();
}
require_code('uploads');
if (((!array_key_exists($upload_name, $_FILES)) || (!is_plupload()) && (!is_uploaded_file($_FILES[$upload_name]['tmp_name'])))) {
$old = $GLOBALS['FORUM_DB']->query_select_value('f_members', 'm_photo_url', array('id' => $member_id));
$x = post_param_string($param_name, '');
if (($x != '') && (url_is_local($x))) {
if (!$GLOBALS['FORUM_DRIVER']->is_super_admin(get_member())) {
if ($old != $x) {
access_denied('ASSOCIATE_EXISTING_FILE');
}
}
}
if ($old == $x) {
return; // Not changed, bomb out as we don't want to generate a thumbnail
}
}
// Find photo URL
set_images_cleanup_pipeline_settings(IMG_RECOMPRESS_LOSSLESS, null, null, true); // Code to strip GPS
$urls = get_url($param_name, $upload_name, file_exists(get_custom_file_base() . '/uploads/photos') ? 'uploads/photos' : 'uploads/cns_photos', 0, CMS_UPLOAD_IMAGE, true, 'thumb_' . $param_name, $upload_name . '2', false, true);
reset_images_cleanup_pipeline_settings();
if (!(strlen($urls[0]) > 1)) {
$urls[1] = '';
}
if (((get_base_url() != get_forum_base_url()) || ((!empty($GLOBALS['SITE_INFO']['on_msn'])) && ($GLOBALS['SITE_INFO']['on_msn'] == '1'))) && ($urls[0] != '') && (url_is_local($urls[0]))) {
$urls[0] = get_base_url() . '/' . $urls[0];
}
if (((get_base_url() != get_forum_base_url()) || ((!empty($GLOBALS['SITE_INFO']['on_msn'])) && ($GLOBALS['SITE_INFO']['on_msn'] == '1'))) && ($urls[1] != '') && (url_is_local($urls[1]))) {
$urls[1] = get_base_url() . '/' . $urls[1];
}
// At this point in the code, we know a photo was uploaded or changed to blank.
// If we don't have GD, we need them to have uploaded a thumbnail too.
if (!function_exists('imagetypes')) {
if (((!array_key_exists($upload_name . '2', $_FILES)) || (!is_plupload()) && (!is_uploaded_file($_FILES[$upload_name . '2']['tmp_name'])))) {
$field = post_param_string('thumb_' . $param_name, '');
if (($field == '') && ($urls[0] != '')) {
warn_exit(do_lang_tempcode('IMPROPERLY_FILLED_IN_UPLOAD'));
}
if (($field != '') && (url_is_local($field)) && (!$GLOBALS['FORUM_DRIVER']->is_super_admin(get_member()))) {
$old = $GLOBALS['FORUM_DB']->query_select_value('f_members', 'm_photo_thumb_url', array('id' => $member_id));
if ($old != $field) {
access_denied('ASSOCIATE_EXISTING_FILE');
}
}
}
}
cns_member_choose_photo_concrete($urls[0], $urls[1], $member_id);
decache('main_members');
}
/**
* Edit a member's photo.
*
* @param URLPATH $url URL to photo.
* @param URLPATH $thumb_url URL to thumbnail photo.
* @param ?MEMBER $member_id The member (null: the current member).
*/
function cns_member_choose_photo_concrete($url, $thumb_url, $member_id = null)
{
if (is_null($member_id)) {
$member_id = get_member();
}
// Cleanup old photo
$old = $GLOBALS['FORUM_DB']->query_select_value('f_members', 'm_photo_url', array('id' => $member_id));
if ($old == $url) {
return;
}
if ((url_is_local($old)) && ((substr($old, 0, 19) == 'uploads/cns_photos/') || (substr($old, 0, 15) == 'uploads/photos/'))) {
sync_file(rawurldecode($old));
@unlink(get_custom_file_base() . '/' . rawurldecode($old));
}
$GLOBALS['FORUM_DB']->query_update('f_members', array('m_photo_url' => $url, 'm_photo_thumb_url' => $thumb_url), array('id' => $member_id), '', 1);
require_code('notifications');
$subject = do_lang('CHOOSE_PHOTO_SUBJECT', $GLOBALS['FORUM_DRIVER']->get_username($member_id, true), $GLOBALS['FORUM_DRIVER']->get_username($member_id), null, get_lang($member_id));
$body = do_notification_lang('CHOOSE_PHOTO_BODY', $url, $thumb_url, array($GLOBALS['FORUM_DRIVER']->get_username($member_id), $GLOBALS['FORUM_DRIVER']->get_username($member_id, true)), get_lang($member_id));
dispatch_notification('cns_choose_photo', null, $subject, $body, null, get_member(), 3, false, false, null, null, '', '', '', '', null, true);
// If Avatars addon not installed, use photo for it
if (!addon_installed('cns_avatars')) {
$avatar_url = $url;
if (function_exists('imagetypes')) {
$stub = url_is_local($avatar_url) ? (get_complex_base_url($avatar_url) . '/') : '';
$file_path = convert_url_to_path($stub . $avatar_url);
if (!is_null($file_path)) {
$new_file_path = str_replace('/cns_photos/', '/cns_avatars/', $file_path);
if (!file_exists($new_file_path)) {
copy($file_path, $new_file_path);
fix_permissions($new_file_path);
sync_file($new_file_path);
}
$avatar_url = str_replace('/cns_photos/', '/cns_avatars/', $avatar_url);
}
}
cns_member_choose_avatar($avatar_url, $member_id);
}
// Decache from run-time cache
unset($GLOBALS['FORUM_DRIVER']->MEMBER_ROWS_CACHED[$member_id]);
unset($GLOBALS['MEMBER_CACHE_FIELD_MAPPINGS'][$member_id]);
decache('main_friends_list');
decache('main_members');
}
/**
* Update caching against a member's username. This doesn't change the username in the actual member record -- it is assumed that this will be done elsewhere.
*
* @param MEMBER $member_id The member ID.
* @param ID_TEXT $username The new username that is being set for them.
*/
function update_member_username_caching($member_id, $username)
{
// Fix caching for usernames
$to_fix = array(
'f_forums/f_cache_last_username/f_cache_last_member_id',
'f_posts/p_poster_name_if_guest/p_poster',
'f_topics/t_cache_first_username/t_cache_first_member_id',
'f_topics/t_cache_last_username/t_cache_last_member_id',
'sessions/cache_username/member_id',
);
foreach ($to_fix as $fix) {
list($table, $field, $updating_field) = explode('/', $fix, 3);
$con = $GLOBALS[(substr($table, 0, 2) == 'f_') ? 'FORUM_DB' : 'SITE_DB'];
$con->query_update($table, array($field => $username), array($updating_field => $member_id));
}
}
/**
* Delete a custom profile field from one of the predefined templates (this is often used by importers).
*
* @param ID_TEXT $field The identifier of the boiler custom profile field.
*/
function cns_delete_boiler_custom_field($field)
{
require_lang('cns_special_cpf');
$test = $GLOBALS['FORUM_DB']->query_select_value_if_there('f_custom_fields', 'id', array($GLOBALS['SITE_DB']->translate_field_ref('cf_name') => do_lang('DEFAULT_CPF_' . $field . '_NAME')));
if (!is_null($test)) {
require_code('cns_members_action');
cns_delete_custom_field($test);
}
}
/**
* Rebuild custom profile field indices.
*
* @param boolean $leave_existing Whether to leave existing indexes alone (may be useful as deleting then recreating indexes can be very slow).
*/
function rebuild_all_cpf_indices($leave_existing = false)
{
$GLOBALS['NO_QUERY_LIMIT'] = true; // TODO: Change in v11
$fields = $GLOBALS['FORUM_DB']->query_select('f_custom_fields', array('id', 'cf_type'), array(), 'ORDER BY cf_required+cf_show_on_join_form DESC,cf_public_view+cf_owner_set DESC,cf_order DESC'); // TODO: Respect searchable setting in v11
if (!$leave_existing) {
// Delete existing indexes
foreach ($fields as $field) {
$id = $field['id'];
$GLOBALS['FORUM_DB']->delete_index_if_exists('f_member_custom_fields', 'field_' . strval($id)); // LEGACY
$GLOBALS['FORUM_DB']->delete_index_if_exists('f_member_custom_fields', 'mcf' . strval($id));
$GLOBALS['FORUM_DB']->delete_index_if_exists('f_member_custom_fields', '#mcf_ft_' . strval($id));
}
// Delete any stragglers (already deleted fields or inconsistent naming)
$GLOBALS['FORUM_DB']->query_delete('db_meta_indices', array('i_table' => 'f_member_custom_fields'));
if (strpos(get_db_type(), 'mysql') !== false) {
$indexes = $GLOBALS['FORUM_DB']->query('SHOW INDEXES FROM ' . $GLOBALS['FORUM_DB']->get_table_prefix() . 'f_member_custom_fields WHERE Column_name<>\'mf_member_id\'');
foreach ($indexes as $index) {
$GLOBALS['FORUM_DB']->query('DROP INDEX ' . $index['Key_name'] . ' ON ' . $GLOBALS['FORUM_DB']->get_table_prefix() . 'f_member_custom_fields');
}
}
}
// Rebuild indexes
require_code('cns_members_action');
foreach ($fields as $field) {
$id = $field['id'];
$type = $field['cf_type'];
list($_type, $index) = get_cpf_storage_for($type);
$okay = build_cpf_indices($id, $index, $type, $_type);
if (!$okay) { // Limit was hit
break;
}
}
}