function testSimpleError()
 {
     $error_context = Error_Context::context();
     // Let's add an error and see
     $error_context->addError('test');
     $this->assertTrue($error_context->hasErrors());
     $this->assertTrue($error_context->hasError('test'));
     $this->assertFalse($error_context->hasError('test2'));
     $this->assertEqual($error_context->getErrorType(), Error_Context::MINOR);
     // Now the error can be removed
     $error_context->removeError('test');
     $this->assertFalse($error_context->hasErrors());
     $this->assertFalse($error_context->hasError('test'));
     $this->assertFalse($error_context->hasError('test2'));
     $this->assertFalse($error_context->getErrors());
 }
/**
 * Create a anti-bot verification control?
 *
 * @param mixed[] $verificationOptions
 * @param bool $do_test = false
 */
function create_control_verification(&$verificationOptions, $do_test = false)
{
    global $context;
    // We need to remember this because when failing the page is realoaded and the
    // code must remain the same (unless it has to change)
    static $all_instances = array();
    // Always have an ID.
    assert(isset($verificationOptions['id']));
    $isNew = !isset($context['controls']['verification'][$verificationOptions['id']]);
    if ($isNew) {
        $context['controls']['verification'][$verificationOptions['id']] = array('id' => $verificationOptions['id'], 'max_errors' => isset($verificationOptions['max_errors']) ? $verificationOptions['max_errors'] : 3, 'render' => false);
    }
    $thisVerification =& $context['controls']['verification'][$verificationOptions['id']];
    if (!isset($_SESSION[$verificationOptions['id'] . '_vv'])) {
        $_SESSION[$verificationOptions['id'] . '_vv'] = array();
    }
    $force_refresh = (!empty($_SESSION[$verificationOptions['id'] . '_vv']['did_pass']) || empty($_SESSION[$verificationOptions['id'] . '_vv']['count']) || $_SESSION[$verificationOptions['id'] . '_vv']['count'] > 3) && empty($verificationOptions['dont_refresh']);
    if (!isset($all_instances[$verificationOptions['id']])) {
        $known_verifications = loadVerificationControls();
        $all_instances[$verificationOptions['id']] = array();
        foreach ($known_verifications as $verification) {
            $class_name = 'Verification_Controls_' . ucfirst($verification);
            $current_instance = new $class_name($verificationOptions);
            // If there is anything to show, otherwise forget it
            if ($current_instance->showVerification($isNew, $force_refresh)) {
                $all_instances[$verificationOptions['id']][$verification] = $current_instance;
            }
        }
    }
    $instances =& $all_instances[$verificationOptions['id']];
    // Is there actually going to be anything?
    if (empty($instances)) {
        return false;
    } elseif (!$isNew && !$do_test) {
        return true;
    }
    $verification_errors = Error_Context::context($verificationOptions['id']);
    $increase_error_count = false;
    // Start with any testing.
    if ($do_test) {
        // This cannot happen!
        if (!isset($_SESSION[$verificationOptions['id'] . '_vv']['count'])) {
            fatal_lang_error('no_access', false);
        }
        foreach ($instances as $instance) {
            $outcome = $instance->doTest();
            if ($outcome !== true) {
                $increase_error_count = true;
                $verification_errors->addError($outcome);
            }
        }
    }
    // Any errors means we refresh potentially.
    if ($increase_error_count) {
        if (empty($_SESSION[$verificationOptions['id'] . '_vv']['errors'])) {
            $_SESSION[$verificationOptions['id'] . '_vv']['errors'] = 0;
        } elseif ($_SESSION[$verificationOptions['id'] . '_vv']['errors'] > $thisVerification['max_errors']) {
            $force_refresh = true;
        }
        // Keep a track of these.
        $_SESSION[$verificationOptions['id'] . '_vv']['errors']++;
    }
    // Are we refreshing then?
    if ($force_refresh) {
        // Assume nothing went before.
        $_SESSION[$verificationOptions['id'] . '_vv']['count'] = 0;
        $_SESSION[$verificationOptions['id'] . '_vv']['errors'] = 0;
        $_SESSION[$verificationOptions['id'] . '_vv']['did_pass'] = false;
    }
    foreach ($instances as $test => $instance) {
        $instance->createTest($force_refresh);
        $thisVerification['test'][$test] = $instance->prepareContext();
        if ($instance->hasVisibleTemplate()) {
            $thisVerification['render'] = true;
        }
    }
    $_SESSION[$verificationOptions['id'] . '_vv']['count'] = empty($_SESSION[$verificationOptions['id'] . '_vv']['count']) ? 1 : $_SESSION[$verificationOptions['id'] . '_vv']['count'] + 1;
    // Return errors if we have them.
    if ($verification_errors->hasErrors()) {
        // @todo temporary until the error class is implemented in register
        $error_codes = array();
        foreach ($verification_errors->getErrors() as $errors) {
            foreach ($errors as $error) {
                $error_codes[] = $error;
            }
        }
        return $error_codes;
    } elseif ($do_test) {
        $_SESSION[$verificationOptions['id'] . '_vv']['did_pass'] = true;
    }
    // Say that everything went well chaps.
    return true;
}
 /**
  * See if a username already exists.
  */
 private function _registerCheckUsername()
 {
     global $context;
     // This is XML!
     loadTemplate('Xml');
     $context['sub_template'] = 'check_username';
     $context['checked_username'] = isset($_GET['username']) ? un_htmlspecialchars($_GET['username']) : '';
     $context['valid_username'] = true;
     // Clean it up like mother would.
     $context['checked_username'] = preg_replace('~[\\t\\n\\r \\x0B\\0\\x{A0}\\x{AD}\\x{2000}-\\x{200F}\\x{201F}\\x{202F}\\x{3000}\\x{FEFF}]+~u', ' ', $context['checked_username']);
     $errors = Error_Context::context('valid_username', 0);
     require_once SUBSDIR . '/Auth.subs.php';
     validateUsername(0, $context['checked_username'], 'valid_username', true, false);
     $context['valid_username'] = !$errors->hasErrors();
 }
Exemple #4
0
/**
 * Creates a new ban group
 *
 * What it does:
 * - If a ban group with the same name already exists or the group s successfully created the ID is returned
 * - On error the error code is returned or false
 *
 * @package Bans
 * @param mixed[] $ban_info
 * @return int the ban group's ID
 */
function insertBanGroup($ban_info = array())
{
    $db = database();
    $ban_errors = Error_Context::context('ban', 1);
    if (empty($ban_info['name'])) {
        $ban_errors->addError('ban_name_empty');
    }
    if (empty($ban_info['cannot']['access']) && empty($ban_info['cannot']['register']) && empty($ban_info['cannot']['post']) && empty($ban_info['cannot']['login'])) {
        $ban_errors->addError('ban_unknown_restriction_type');
    }
    if ($ban_errors->hasErrors()) {
        return false;
    }
    // Check whether a ban with this name already exists.
    $request = $db->query('', '
		SELECT id_ban_group
		FROM {db_prefix}ban_groups
		WHERE name = {string:new_ban_name}' . '
		LIMIT 1', array('new_ban_name' => $ban_info['name']));
    // @todo shouldn't be an error here?
    if ($db->num_rows($request) == 1) {
        list($id_ban) = $db->fetch_row($request);
        $db->free_result($request);
        return $id_ban;
    }
    $db->free_result($request);
    // Yes yes, we're ready to add now.
    $db->insert('', '{db_prefix}ban_groups', array('name' => 'string-20', 'ban_time' => 'int', 'expire_time' => 'raw', 'cannot_access' => 'int', 'cannot_register' => 'int', 'cannot_post' => 'int', 'cannot_login' => 'int', 'reason' => 'string-255', 'notes' => 'string-65534'), array($ban_info['name'], time(), $ban_info['db_expiration'], $ban_info['cannot']['access'], $ban_info['cannot']['register'], $ban_info['cannot']['post'], $ban_info['cannot']['login'], $ban_info['reason'], $ban_info['notes']), array('id_ban_group'));
    $ban_info['id'] = $db->insert_id('{db_prefix}ban_groups', 'id_ban_group');
    if (empty($ban_info['id'])) {
        $ban_errors->addError('impossible_insert_new_bangroup');
    }
    return $ban_info['id'];
}
 /**
  * Send the emails.
  *
  * - Sends off emails to all the moderators.
  * - Sends to administrators and global moderators. (1 and 2)
  * - Called by action_reporttm(), and thus has the same permission and setting requirements as it does.
  * - Accessed through ?action=reporttm when posting.
  */
 public function action_reporttm2()
 {
     global $txt, $scripturl, $topic, $board, $user_info, $modSettings, $language, $context;
     // You must have the proper permissions!
     isAllowedTo('report_any');
     // Make sure they aren't spamming.
     spamProtection('reporttm');
     require_once SUBSDIR . '/Mail.subs.php';
     // No errors, yet.
     $report_errors = Error_Context::context('report', 1);
     // Check their session.
     if (checkSession('post', '', false) != '') {
         $report_errors->addError('session_timeout');
     }
     // Make sure we have a comment and it's clean.
     if (!isset($_POST['comment']) || Util::htmltrim($_POST['comment']) === '') {
         $report_errors->addError('no_comment');
     }
     $poster_comment = strtr(Util::htmlspecialchars($_POST['comment']), array("\r" => '', "\t" => ''));
     if (Util::strlen($poster_comment) > 254) {
         $report_errors->addError('post_too_long');
     }
     // Guests need to provide their address!
     if ($user_info['is_guest']) {
         require_once SUBSDIR . '/DataValidator.class.php';
         if (!Data_Validator::is_valid($_POST, array('email' => 'valid_email'), array('email' => 'trim'))) {
             empty($_POST['email']) ? $report_errors->addError('no_email') : $report_errors->addError('bad_email');
         }
         isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt['guest_title']));
         $user_info['email'] = htmlspecialchars($_POST['email'], ENT_COMPAT, 'UTF-8');
     }
     // Could they get the right verification code?
     if ($user_info['is_guest'] && !empty($modSettings['guests_report_require_captcha'])) {
         require_once SUBSDIR . '/VerificationControls.class.php';
         $verificationOptions = array('id' => 'report');
         $context['require_verification'] = create_control_verification($verificationOptions, true);
         if (is_array($context['require_verification'])) {
             foreach ($context['require_verification'] as $error) {
                 $report_errors->addError($error, 0);
             }
         }
     }
     // Any errors?
     if ($report_errors->hasErrors()) {
         return $this->action_reporttm();
     }
     // Get the basic topic information, and make sure they can see it.
     $msg_id = (int) $_POST['msg'];
     $message = posterDetails($msg_id, $topic);
     if (empty($message)) {
         fatal_lang_error('no_board', false);
     }
     $poster_name = un_htmlspecialchars($message['real_name']) . ($message['real_name'] != $message['poster_name'] ? ' (' . $message['poster_name'] . ')' : '');
     $reporterName = un_htmlspecialchars($user_info['name']) . ($user_info['name'] != $user_info['username'] && $user_info['username'] != '' ? ' (' . $user_info['username'] . ')' : '');
     $subject = un_htmlspecialchars($message['subject']);
     // Get a list of members with the moderate_board permission.
     require_once SUBSDIR . '/Members.subs.php';
     $moderators = membersAllowedTo('moderate_board', $board);
     $result = getBasicMemberData($moderators, array('preferences' => true, 'sort' => 'lngfile'));
     $mod_to_notify = array();
     foreach ($result as $row) {
         if ($row['notify_types'] != 4) {
             $mod_to_notify[] = $row;
         }
     }
     // Check that moderators do exist!
     if (empty($mod_to_notify)) {
         fatal_lang_error('no_mods', false);
     }
     // If we get here, I believe we should make a record of this, for historical significance, yabber.
     if (empty($modSettings['disable_log_report'])) {
         require_once SUBSDIR . '/Messages.subs.php';
         $id_report = recordReport($message, $poster_comment);
         // If we're just going to ignore these, then who gives a monkeys...
         if ($id_report === false) {
             redirectexit('topic=' . $topic . '.msg' . $msg_id . '#msg' . $msg_id);
         }
     }
     // Find out who the real moderators are - for mod preferences.
     require_once SUBSDIR . '/Boards.subs.php';
     $real_mods = getBoardModerators($board, true);
     // Send every moderator an email.
     foreach ($mod_to_notify as $row) {
         // Maybe they don't want to know?!
         if (!empty($row['mod_prefs'])) {
             list(, , $pref_binary) = explode('|', $row['mod_prefs']);
             if (!($pref_binary & 1) && (!($pref_binary & 2) || !in_array($row['id_member'], $real_mods))) {
                 continue;
             }
         }
         $replacements = array('TOPICSUBJECT' => $subject, 'POSTERNAME' => $poster_name, 'REPORTERNAME' => $reporterName, 'TOPICLINK' => $scripturl . '?topic=' . $topic . '.msg' . $msg_id . '#msg' . $msg_id, 'REPORTLINK' => !empty($id_report) ? $scripturl . '?action=moderate;area=reports;report=' . $id_report : '', 'COMMENT' => $_POST['comment']);
         $emaildata = loadEmailTemplate('report_to_moderator', $replacements, empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']);
         // Send it to the moderator.
         sendmail($row['email_address'], $emaildata['subject'], $emaildata['body'], $user_info['email'], null, false, 2);
     }
     // Keep track of when the mod reports get updated, that way we know when we need to look again.
     updateSettings(array('last_mod_report_action' => time()));
     // Back to the post we reported!
     redirectexit('reportsent;topic=' . $topic . '.msg' . $msg_id . '#msg' . $msg_id);
 }
Exemple #6
0
 /**
  * Update the settings for a poll, or add a new one.
  * Must be called with a topic specified in the URL.
  * The user must have poll_edit_any/poll_add_any permission
  * for the relevant action. Otherwise they must be poll starter
  * with poll_edit_own permission for editing, or be topic starter
  * with poll_add_any permission for adding.
  * In the case of an error, this function will redirect back to
  * action_editpoll and display the relevant error message.
  * Upon successful completion of action will direct user back to topic.
  * Accessed via ?action=editpoll2.
  */
 public function action_editpoll2()
 {
     global $topic, $board, $user_info;
     // Sneaking off, are we?
     if (empty($_POST)) {
         redirectexit('action=editpoll;topic=' . $topic . '.0');
     }
     $poll_errors = Error_Context::context('poll');
     if (checkSession('post', '', false) != '') {
         $poll_errors->addError('session_timeout');
     }
     if (isset($_POST['preview'])) {
         return $this->action_editpoll();
     }
     // HACKERS (!!) can't edit :P.
     if (empty($topic)) {
         fatal_lang_error('no_access', false);
     }
     // Is this a new poll, or editing an existing?
     $isEdit = isset($_REQUEST['add']) ? 0 : 1;
     // Make sure we have our stuff.
     require_once SUBSDIR . '/Poll.subs.php';
     // Get the starter and the poll's ID - if it's an edit.
     $bcinfo = getPollStarter($topic);
     // Check their adding/editing is valid.
     if (!$isEdit && !empty($bcinfo['id_poll'])) {
         fatal_lang_error('poll_already_exists');
     } elseif ($isEdit && empty($bcinfo['id_poll'])) {
         fatal_lang_error('poll_not_found');
     }
     // Check if they have the power to add or edit the poll.
     if ($isEdit && !allowedTo('poll_edit_any')) {
         isAllowedTo('poll_edit_' . ($user_info['id'] == $bcinfo['id_member_started'] || $bcinfo['poll_starter'] != 0 && $user_info['id'] == $bcinfo['poll_starter'] ? 'own' : 'any'));
     } elseif (!$isEdit && !allowedTo('poll_add_any')) {
         isAllowedTo('poll_add_' . ($user_info['id'] == $bcinfo['id_member_started'] ? 'own' : 'any'));
     }
     $optionCount = 0;
     $idCount = 0;
     // Ensure the user is leaving a valid amount of options - there must be at least two.
     foreach ($_POST['options'] as $k => $option) {
         if (trim($option) != '') {
             $optionCount++;
             $idCount = max($idCount, $k);
         }
     }
     if ($optionCount < 2) {
         $poll_errors->addError('poll_few');
     } elseif ($optionCount > 256 || $idCount > 255) {
         $poll_errors->addError('poll_many');
     }
     // Also - ensure they are not removing the question.
     if (trim($_POST['question']) == '') {
         $poll_errors->addError('no_question');
     }
     // Got any errors to report?
     if ($poll_errors->hasErrors()) {
         return $this->action_editpoll();
     }
     // Prevent double submission of this form.
     checkSubmitOnce('check');
     // Now we've done all our error checking, let's get the core poll information cleaned... question first.
     $_POST['question'] = Util::htmlspecialchars($_POST['question']);
     $_POST['question'] = Util::substr($_POST['question'], 0, 255);
     $_POST['poll_hide'] = (int) $_POST['poll_hide'];
     $_POST['poll_expire'] = isset($_POST['poll_expire']) ? (int) $_POST['poll_expire'] : 0;
     $_POST['poll_change_vote'] = isset($_POST['poll_change_vote']) ? 1 : 0;
     $_POST['poll_guest_vote'] = isset($_POST['poll_guest_vote']) ? 1 : 0;
     // Make sure guests are actually allowed to vote generally.
     if ($_POST['poll_guest_vote']) {
         require_once SUBSDIR . '/Members.subs.php';
         $allowedGroups = groupsAllowedTo('poll_vote', $board);
         if (!in_array(-1, $allowedGroups['allowed'])) {
             $_POST['poll_guest_vote'] = 0;
         }
     }
     // Ensure that the number options allowed makes sense, and the expiration date is valid.
     if (!$isEdit || allowedTo('moderate_board')) {
         $_POST['poll_expire'] = $_POST['poll_expire'] > 9999 ? 9999 : ($_POST['poll_expire'] < 0 ? 0 : $_POST['poll_expire']);
         if (empty($_POST['poll_expire']) && $_POST['poll_hide'] == 2) {
             $_POST['poll_hide'] = 1;
         } elseif (!$isEdit || $_POST['poll_expire'] != ceil($bcinfo['expire_time'] <= time() ? -1 : ($bcinfo['expire_time'] - time()) / (3600 * 24))) {
             $_POST['poll_expire'] = empty($_POST['poll_expire']) ? '0' : time() + $_POST['poll_expire'] * 3600 * 24;
         } else {
             $_POST['poll_expire'] = $bcinfo['expire_time'];
         }
         if (empty($_POST['poll_max_votes']) || $_POST['poll_max_votes'] <= 0) {
             $_POST['poll_max_votes'] = 1;
         } else {
             $_POST['poll_max_votes'] = (int) $_POST['poll_max_votes'];
         }
     }
     // If we're editing, let's commit the changes.
     if ($isEdit) {
         modifyPoll($bcinfo['id_poll'], $_POST['question'], !empty($_POST['poll_max_votes']) ? $_POST['poll_max_votes'] : 0, $_POST['poll_hide'], !empty($_POST['poll_expire']) ? $_POST['poll_expire'] : 0, $_POST['poll_change_vote'], $_POST['poll_guest_vote']);
     } else {
         // Create the poll.
         $bcinfo['id_poll'] = createPoll($_POST['question'], $user_info['id'], $user_info['username'], $_POST['poll_max_votes'], $_POST['poll_hide'], $_POST['poll_expire'], $_POST['poll_change_vote'], $_POST['poll_guest_vote']);
         // Link the poll to the topic.
         associatedPoll($topic, $bcinfo['id_poll']);
     }
     // Get all the choices.  (no better way to remove all emptied and add previously non-existent ones.)
     $choices = array_keys(pollOptions($bcinfo['id_poll']));
     $add_options = array();
     $update_options = array();
     $delete_options = array();
     foreach ($_POST['options'] as $k => $option) {
         // Make sure the key is numeric for sanity's sake.
         $k = (int) $k;
         // They've cleared the box.  Either they want it deleted, or it never existed.
         if (trim($option) == '') {
             // They want it deleted.  Bye.
             if (in_array($k, $choices)) {
                 $delete_options[] = $k;
             }
             // Skip the rest...
             continue;
         }
         // Dress the option up for its big date with the database.
         $option = Util::htmlspecialchars($option);
         // If it's already there, update it.  If it's not... add it.
         if (in_array($k, $choices)) {
             $update_options[] = array($bcinfo['id_poll'], $k, $option);
         } else {
             $add_options[] = array($bcinfo['id_poll'], $k, $option, 0);
         }
     }
     if (!empty($update_options)) {
         modifyPollOption($update_options);
     }
     if (!empty($add_options)) {
         insertPollOptions($add_options);
     }
     // I'm sorry, but... well, no one was choosing you. Poor options, I'll put you out of your misery.
     if (!empty($delete_options)) {
         deletePollOptions($bcinfo['id_poll'], $delete_options);
     }
     // Shall I reset the vote count, sir?
     if (isset($_POST['resetVoteCount'])) {
         resetVotes($bcinfo['id_poll']);
     }
     call_integration_hook('integrate_poll_add_edit', array($bcinfo['id_poll'], $isEdit));
     // Off we go.
     redirectexit('topic=' . $topic . '.' . $_REQUEST['start']);
 }
 /**
  * Does the actual saving of the article data
  *
  * - validates the data is safe to save
  * - updates existing articles or creates new ones
  */
 private function _sportal_admin_article_edit_save()
 {
     global $context, $txt, $modSettings;
     // No errors, yet.
     $article_errors = Error_Context::context('article', 0);
     // Use our standard validation functions in a few spots
     require_once SUBSDIR . '/DataValidator.class.php';
     $validator = new Data_Validator();
     // If its not new, lets load the current data
     if (!$this->_is_new) {
         $_REQUEST['article_id'] = (int) $_REQUEST['article_id'];
         $context['article'] = sportal_get_articles($_REQUEST['article_id']);
     }
     // Clean and Review the post data for compliance
     $validator->sanitation_rules(array('title' => 'trim|Util::htmlspecialchars', 'namespace' => 'trim|Util::htmlspecialchars', 'article_id' => 'intval', 'category_id' => 'intval', 'permissions' => 'intval', 'type' => 'trim', 'content' => 'trim'));
     $validator->validation_rules(array('title' => 'required', 'namespace' => 'alpha_numeric|required', 'type' => 'required', 'content' => 'required'));
     $validator->text_replacements(array('title' => $txt['sp_admin_articles_col_title'], 'namespace' => $txt['sp_admin_articles_col_namespace'], 'content' => $txt['sp_admin_articles_col_body']));
     // If you messed this up, back you go
     if (!$validator->validate($_POST)) {
         foreach ($validator->validation_errors() as $id => $error) {
             $article_errors->addError($error);
         }
         $this->action_sportal_admin_article_edit();
     }
     // Lets make sure this namespace (article id) is unique
     $has_duplicate = sp_duplicate_articles($validator->article_id, $validator->namespace);
     if (!empty($has_duplicate)) {
         $article_errors->addError('sp_error_article_namespace_duplicate');
     }
     // And we can't have just a numeric namespace (article id)
     if (preg_replace('~[0-9]+~', '', $validator->namespace) === '') {
         $article_errors->addError('sp_error_article_namespace_numeric');
     }
     // Posting some PHP code, and allowed? Then we need to validate it will run
     if ($_POST['type'] === 'php' && !empty($_POST['content']) && empty($modSettings['sp_disable_php_validation'])) {
         $validator_php = new Data_Validator();
         $validator_php->validation_rules(array('content' => 'php_syntax'));
         // Bad PHP code
         if (!$validator_php->validate(array('content' => $_POST['content']))) {
             $article_errors->addError($validator_php->validation_errors());
         }
     }
     // None shall pass ... with errors
     if ($article_errors->hasErrors()) {
         $this->action_sportal_admin_article_edit();
     }
     // No errors then, prepare the data for saving
     $article_info = array('id' => $validator->article_id, 'id_category' => $validator->category_id, 'namespace' => $validator->namespace, 'title' => $validator->title, 'body' => Util::htmlspecialchars($_POST['content'], ENT_QUOTES), 'type' => in_array($validator->type, array('bbc', 'html', 'php')) ? $_POST['type'] : 'bbc', 'permissions' => $validator->permissions, 'status' => !empty($_POST['status']) ? 1 : 0);
     if ($article_info['type'] === 'bbc') {
         preparsecode($article_info['body']);
     }
     // Save away
     checkSession();
     sp_save_article($article_info, $this->_is_new);
     redirectexit('action=admin;area=portalarticles');
     return true;
 }
 /**
  * This function handles submitted forms that add, modify or remove ban triggers.
  */
 public function action_edit2()
 {
     global $context;
     require_once SUBSDIR . '/Bans.subs.php';
     // Check with security first
     checkSession();
     validateToken('admin-bet');
     $ban_errors = Error_Context::context('ban', 1);
     // Adding or editing a ban group
     if (isset($_POST['add_ban']) || isset($_POST['modify_ban'])) {
         $ban_info = array();
         // Let's collect all the information we need
         $ban_info['id'] = isset($_REQUEST['bg']) ? (int) $_REQUEST['bg'] : 0;
         $ban_info['is_new'] = empty($ban_info['id']);
         $ban_info['expire_date'] = !empty($_POST['expire_date']) ? (int) $_POST['expire_date'] : 0;
         $ban_info['expiration'] = array('status' => isset($_POST['expiration']) && in_array($_POST['expiration'], array('never', 'one_day', 'expired')) ? $_POST['expiration'] : 'never', 'days' => $ban_info['expire_date']);
         $ban_info['db_expiration'] = $ban_info['expiration']['status'] == 'never' ? 'NULL' : ($ban_info['expiration']['status'] == 'one_day' ? time() + 24 * 60 * 60 * $ban_info['expire_date'] : 0);
         $ban_info['full_ban'] = empty($_POST['full_ban']) ? 0 : 1;
         $ban_info['reason'] = !empty($_POST['reason']) ? Util::htmlspecialchars($_POST['reason'], ENT_QUOTES) : '';
         $ban_info['name'] = !empty($_POST['ban_name']) ? Util::htmlspecialchars($_POST['ban_name'], ENT_QUOTES) : '';
         $ban_info['notes'] = isset($_POST['notes']) ? Util::htmlspecialchars($_POST['notes'], ENT_QUOTES) : '';
         $ban_info['notes'] = str_replace(array("\r", "\n", '  '), array('', '<br />', '&nbsp; '), $ban_info['notes']);
         $ban_info['cannot']['access'] = empty($ban_info['full_ban']) ? 0 : 1;
         $ban_info['cannot']['post'] = !empty($ban_info['full_ban']) || empty($_POST['cannot_post']) ? 0 : 1;
         $ban_info['cannot']['register'] = !empty($ban_info['full_ban']) || empty($_POST['cannot_register']) ? 0 : 1;
         $ban_info['cannot']['login'] = !empty($ban_info['full_ban']) || empty($_POST['cannot_login']) ? 0 : 1;
         // Adding a new ban group
         if (empty($ban_info['id'])) {
             $ban_group_id = insertBanGroup($ban_info);
         } else {
             $ban_group_id = updateBanGroup($ban_info);
         }
         if ($ban_group_id !== false) {
             $ban_info['id'] = $ban_group_id;
             $ban_info['is_new'] = false;
         }
         $context['ban'] = $ban_info;
     }
     // Update the triggers associated with this ban
     if (isset($_POST['ban_suggestions'])) {
         $saved_triggers = saveTriggers($_POST['ban_suggestions'], $ban_info['id'], isset($_REQUEST['u']) ? (int) $_REQUEST['u'] : 0, isset($_REQUEST['bi']) ? (int) $_REQUEST['bi'] : 0);
         $context['ban_suggestions']['saved_triggers'] = $saved_triggers;
     }
     // Something went wrong somewhere, ban info or triggers, ... Oh well, let's go back.
     if ($ban_errors->hasErrors()) {
         $context['ban_suggestions'] = $saved_triggers;
         $context['ban']['from_user'] = true;
         // They may have entered a name not using the member select box
         if (isset($_REQUEST['u'])) {
             $context['ban_suggestions'] = array_merge($context['ban_suggestions'], getMemberData((int) $_REQUEST['u']));
         } elseif (isset($_REQUEST['user'])) {
             $context['ban']['from_user'] = false;
             $context['use_autosuggest'] = true;
             $context['ban_suggestions']['member']['name'] = $_REQUEST['user'];
         }
         // Not strictly necessary, but it's nice
         if (!empty($context['ban_suggestions']['member']['id'])) {
             $context['ban_suggestions']['other_ips'] = banLoadAdditionalIPs($context['ban_suggestions']['member']['id']);
         }
         return $this->action_edit();
     }
     if (isset($_POST['ban_items'])) {
         $ban_group_id = isset($_REQUEST['bg']) ? (int) $_REQUEST['bg'] : 0;
         $ban_items = array_map('intval', $_POST['ban_items']);
         removeBanTriggers($ban_items, $ban_group_id);
     }
     // Register the last modified date.
     updateSettings(array('banLastUpdated' => time()));
     // Update the member table to represent the new ban situation.
     updateBanMembers();
     // Go back to an appropriate spot
     redirectexit('action=admin;area=ban;sa=' . (isset($_POST['add_ban']) ? 'list' : 'edit;bg=' . $ban_group_id));
 }
Exemple #9
0
/**
 * Checks a username obeys a load of rules
 *
 * - Returns null if fine
 *
 * @package Authorization
 * @param int $memID
 * @param string $username
 * @param string $error_context
 * @param boolean $check_reserved_name
 * @param boolean $fatal pass through to isReservedName
 * @return string
 */
function validateUsername($memID, $username, $error_context = 'register', $check_reserved_name = true, $fatal = true)
{
    global $txt;
    $errors = Error_Context::context($error_context, 0);
    // Don't use too long a name.
    if (Util::strlen($username) > 25) {
        $errors->addError('error_long_name');
    }
    // No name?!  How can you register with no name?
    if ($username == '') {
        $errors->addError('need_username');
    }
    // Only these characters are permitted.
    if (in_array($username, array('_', '|')) || preg_match('~[<>&"\'=\\\\]~', preg_replace('~&#(?:\\d{1,7}|x[0-9a-fA-F]{1,6});~', '', $username)) != 0 || strpos($username, '[code') !== false || strpos($username, '[/code') !== false) {
        $errors->addError('error_invalid_characters_username');
    }
    if (stristr($username, $txt['guest_title']) !== false) {
        $errors->addError(array('username_reserved', array($txt['guest_title'])), 1);
    }
    if ($check_reserved_name) {
        require_once SUBSDIR . '/Members.subs.php';
        if (isReservedName($username, $memID, false, $fatal)) {
            $errors->addError(array('name_in_use', array(htmlspecialchars($username, ENT_COMPAT, 'UTF-8'))));
        }
    }
}
Exemple #10
0
/**
 * Registers a member to the forum.
 *
 * What it does:
 * - Allows two types of interface: 'guest' and 'admin'. The first
 * - includes hammering protection, the latter can perform the registration silently.
 * - The strings used in the options array are assumed to be escaped.
 * - Allows to perform several checks on the input, e.g. reserved names.
 * - The function will adjust member statistics.
 * - If an error is detected will fatal error on all errors unless return_errors is true.
 *
 * @package Members
 * @uses Auth.subs.php
 * @uses Mail.subs.php
 * @param mixed[] $regOptions
 * @param string $error_context
 * @return integer the ID of the newly created member
 */
function registerMember(&$regOptions, $error_context = 'register')
{
    global $scripturl, $txt, $modSettings, $user_info;
    $db = database();
    loadLanguage('Login');
    // We'll need some external functions.
    require_once SUBSDIR . '/Auth.subs.php';
    require_once SUBSDIR . '/Mail.subs.php';
    // Put any errors in here.
    $reg_errors = Error_Context::context($error_context, 0);
    // Registration from the admin center, let them sweat a little more.
    if ($regOptions['interface'] == 'admin') {
        is_not_guest();
        isAllowedTo('moderate_forum');
    } elseif ($regOptions['interface'] == 'guest') {
        // You cannot register twice...
        if (empty($user_info['is_guest'])) {
            redirectexit();
        }
        // Make sure they didn't just register with this session.
        if (!empty($_SESSION['just_registered']) && empty($modSettings['disableRegisterCheck'])) {
            fatal_lang_error('register_only_once', false);
        }
    }
    // What method of authorization are we going to use?
    if (empty($regOptions['auth_method']) || !in_array($regOptions['auth_method'], array('password', 'openid'))) {
        if (!empty($regOptions['openid'])) {
            $regOptions['auth_method'] = 'openid';
        } else {
            $regOptions['auth_method'] = 'password';
        }
    }
    // Spaces and other odd characters are evil...
    $regOptions['username'] = trim(preg_replace('~[\\t\\n\\r \\x0B\\0\\x{A0}\\x{AD}\\x{2000}-\\x{200F}\\x{201F}\\x{202F}\\x{3000}\\x{FEFF}]+~u', ' ', $regOptions['username']));
    // Valid emails only
    require_once SUBSDIR . '/DataValidator.class.php';
    if (!Data_Validator::is_valid($regOptions, array('email' => 'valid_email|required|max_length[255]'), array('email' => 'trim'))) {
        $reg_errors->addError('bad_email');
    }
    validateUsername(0, $regOptions['username'], $error_context, !empty($regOptions['check_reserved_name']));
    // Generate a validation code if it's supposed to be emailed.
    $validation_code = '';
    if ($regOptions['require'] == 'activation') {
        $validation_code = generateValidationCode();
    }
    // If you haven't put in a password generate one.
    if ($regOptions['interface'] == 'admin' && $regOptions['password'] == '' && $regOptions['auth_method'] == 'password') {
        mt_srand(time() + 1277);
        $regOptions['password'] = generateValidationCode();
        $regOptions['password_check'] = $regOptions['password'];
    } elseif ($regOptions['password'] != $regOptions['password_check'] && $regOptions['auth_method'] == 'password') {
        $reg_errors->addError('passwords_dont_match');
    }
    // That's kind of easy to guess...
    if ($regOptions['password'] == '') {
        if ($regOptions['auth_method'] == 'password') {
            $reg_errors->addError('no_password');
        } else {
            $regOptions['password'] = sha1(mt_rand());
        }
    }
    // Now perform hard password validation as required.
    if (!empty($regOptions['check_password_strength']) && $regOptions['password'] != '') {
        $passwordError = validatePassword($regOptions['password'], $regOptions['username'], array($regOptions['email']));
        // Password isn't legal?
        if ($passwordError != null) {
            $reg_errors->addError('profile_error_password_' . $passwordError);
        }
    }
    // You may not be allowed to register this email.
    if (!empty($regOptions['check_email_ban'])) {
        isBannedEmail($regOptions['email'], 'cannot_register', $txt['ban_register_prohibited']);
    }
    // Check if the email address is in use.
    $request = $db->query('', '
		SELECT id_member
		FROM {db_prefix}members
		WHERE email_address = {string:email_address}
			OR email_address = {string:username}
		LIMIT 1', array('email_address' => $regOptions['email'], 'username' => $regOptions['username']));
    if ($db->num_rows($request) != 0) {
        $reg_errors->addError(array('email_in_use', array(htmlspecialchars($regOptions['email'], ENT_COMPAT, 'UTF-8'))));
    }
    $db->free_result($request);
    // Perhaps someone else wants to check this user
    call_integration_hook('integrate_register_check', array(&$regOptions, &$reg_errors));
    // If there's any errors left return them at once!
    if ($reg_errors->hasErrors()) {
        return false;
    }
    $reservedVars = array('actual_theme_url', 'actual_images_url', 'base_theme_dir', 'base_theme_url', 'default_images_url', 'default_theme_dir', 'default_theme_url', 'default_template', 'images_url', 'number_recent_posts', 'smiley_sets_default', 'theme_dir', 'theme_id', 'theme_layers', 'theme_templates', 'theme_url');
    // Can't change reserved vars.
    if (isset($regOptions['theme_vars']) && count(array_intersect(array_keys($regOptions['theme_vars']), $reservedVars)) != 0) {
        fatal_lang_error('no_theme');
    }
    // New password hash
    require_once SUBSDIR . '/Auth.subs.php';
    // Some of these might be overwritten. (the lower ones that are in the arrays below.)
    $regOptions['register_vars'] = array('member_name' => $regOptions['username'], 'email_address' => $regOptions['email'], 'passwd' => validateLoginPassword($regOptions['password'], '', $regOptions['username'], true), 'password_salt' => substr(md5(mt_rand()), 0, 4), 'posts' => 0, 'date_registered' => !empty($regOptions['time']) ? $regOptions['time'] : time(), 'member_ip' => $regOptions['interface'] == 'admin' ? '127.0.0.1' : $regOptions['ip'], 'member_ip2' => $regOptions['interface'] == 'admin' ? '127.0.0.1' : $regOptions['ip2'], 'validation_code' => $validation_code, 'real_name' => $regOptions['username'], 'personal_text' => $modSettings['default_personal_text'], 'pm_email_notify' => 1, 'id_theme' => 0, 'id_post_group' => 4, 'lngfile' => '', 'buddy_list' => '', 'pm_ignore_list' => '', 'message_labels' => '', 'website_title' => '', 'website_url' => '', 'location' => '', 'time_format' => '', 'signature' => '', 'avatar' => '', 'usertitle' => '', 'secret_question' => '', 'secret_answer' => '', 'additional_groups' => '', 'ignore_boards' => '', 'smiley_set' => '', 'openid_uri' => !empty($regOptions['openid']) ? $regOptions['openid'] : '');
    // Setup the activation status on this new account so it is correct - firstly is it an under age account?
    if ($regOptions['require'] == 'coppa') {
        $regOptions['register_vars']['is_activated'] = 5;
        // @todo This should be changed.  To what should be it be changed??
        $regOptions['register_vars']['validation_code'] = '';
    } elseif ($regOptions['require'] == 'nothing') {
        $regOptions['register_vars']['is_activated'] = 1;
    } elseif ($regOptions['require'] == 'activation') {
        $regOptions['register_vars']['is_activated'] = 0;
    } else {
        $regOptions['register_vars']['is_activated'] = 3;
    }
    if (isset($regOptions['memberGroup'])) {
        // Make sure the id_group will be valid, if this is an administator.
        $regOptions['register_vars']['id_group'] = $regOptions['memberGroup'] == 1 && !allowedTo('admin_forum') ? 0 : $regOptions['memberGroup'];
        // Check if this group is assignable.
        $unassignableGroups = array(-1, 3);
        $request = $db->query('', '
			SELECT id_group
			FROM {db_prefix}membergroups
			WHERE min_posts != {int:min_posts}' . (allowedTo('admin_forum') ? '' : '
				OR group_type = {int:is_protected}'), array('min_posts' => -1, 'is_protected' => 1));
        while ($row = $db->fetch_assoc($request)) {
            $unassignableGroups[] = $row['id_group'];
        }
        $db->free_result($request);
        if (in_array($regOptions['register_vars']['id_group'], $unassignableGroups)) {
            $regOptions['register_vars']['id_group'] = 0;
        }
    }
    // Integrate optional member settings to be set.
    if (!empty($regOptions['extra_register_vars'])) {
        foreach ($regOptions['extra_register_vars'] as $var => $value) {
            $regOptions['register_vars'][$var] = $value;
        }
    }
    // Integrate optional user theme options to be set.
    $theme_vars = array();
    if (!empty($regOptions['theme_vars'])) {
        foreach ($regOptions['theme_vars'] as $var => $value) {
            $theme_vars[$var] = $value;
        }
    }
    // Right, now let's prepare for insertion.
    $knownInts = array('date_registered', 'posts', 'id_group', 'last_login', 'personal_messages', 'unread_messages', 'notifications', 'new_pm', 'pm_prefs', 'gender', 'hide_email', 'show_online', 'pm_email_notify', 'karma_good', 'karma_bad', 'notify_announcements', 'notify_send_body', 'notify_regularity', 'notify_types', 'id_theme', 'is_activated', 'id_msg_last_visit', 'id_post_group', 'total_time_logged_in', 'warning');
    $knownFloats = array('time_offset');
    // Call an optional function to validate the users' input.
    call_integration_hook('integrate_register', array(&$regOptions, &$theme_vars, &$knownInts, &$knownFloats));
    $column_names = array();
    $values = array();
    foreach ($regOptions['register_vars'] as $var => $val) {
        $type = 'string';
        if (in_array($var, $knownInts)) {
            $type = 'int';
        } elseif (in_array($var, $knownFloats)) {
            $type = 'float';
        } elseif ($var == 'birthdate') {
            $type = 'date';
        }
        $column_names[$var] = $type;
        $values[$var] = $val;
    }
    // Register them into the database.
    $db->insert('', '{db_prefix}members', $column_names, $values, array('id_member'));
    $memberID = $db->insert_id('{db_prefix}members', 'id_member');
    // Update the number of members and latest member's info - and pass the name, but remove the 's.
    if ($regOptions['register_vars']['is_activated'] == 1) {
        updateMemberStats($memberID, $regOptions['register_vars']['real_name']);
    } else {
        updateMemberStats();
    }
    // Theme variables too?
    if (!empty($theme_vars)) {
        $inserts = array();
        foreach ($theme_vars as $var => $val) {
            $inserts[] = array($memberID, $var, $val);
        }
        $db->insert('insert', '{db_prefix}themes', array('id_member' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'), $inserts, array('id_member', 'variable'));
    }
    // If it's enabled, increase the registrations for today.
    trackStats(array('registers' => '+'));
    // Administrative registrations are a bit different...
    if ($regOptions['interface'] == 'admin') {
        if ($regOptions['require'] == 'activation') {
            $email_message = 'admin_register_activate';
        } elseif (!empty($regOptions['send_welcome_email'])) {
            $email_message = 'admin_register_immediate';
        }
        if (isset($email_message)) {
            $replacements = array('REALNAME' => $regOptions['register_vars']['real_name'], 'USERNAME' => $regOptions['username'], 'PASSWORD' => $regOptions['password'], 'FORGOTPASSWORDLINK' => $scripturl . '?action=reminder', 'ACTIVATIONLINK' => $scripturl . '?action=activate;u=' . $memberID . ';code=' . $validation_code, 'ACTIVATIONLINKWITHOUTCODE' => $scripturl . '?action=activate;u=' . $memberID, 'ACTIVATIONCODE' => $validation_code);
            $emaildata = loadEmailTemplate($email_message, $replacements);
            sendmail($regOptions['email'], $emaildata['subject'], $emaildata['body'], null, null, false, 0);
        }
    } else {
        // Can post straight away - welcome them to your fantastic community...
        if ($regOptions['require'] == 'nothing') {
            if (!empty($regOptions['send_welcome_email'])) {
                $replacements = array('REALNAME' => $regOptions['register_vars']['real_name'], 'USERNAME' => $regOptions['username'], 'PASSWORD' => $regOptions['password'], 'FORGOTPASSWORDLINK' => $scripturl . '?action=reminder', 'OPENID' => !empty($regOptions['openid']) ? $regOptions['openid'] : '');
                $emaildata = loadEmailTemplate('register_' . ($regOptions['auth_method'] == 'openid' ? 'openid_' : '') . 'immediate', $replacements);
                sendmail($regOptions['email'], $emaildata['subject'], $emaildata['body'], null, null, false, 0);
            }
            // Send admin their notification.
            require_once SUBSDIR . '/Notification.subs.php';
            sendAdminNotifications('standard', $memberID, $regOptions['username']);
        } elseif ($regOptions['require'] == 'activation' || $regOptions['require'] == 'coppa') {
            $replacements = array('REALNAME' => $regOptions['register_vars']['real_name'], 'USERNAME' => $regOptions['username'], 'PASSWORD' => $regOptions['password'], 'FORGOTPASSWORDLINK' => $scripturl . '?action=reminder', 'OPENID' => !empty($regOptions['openid']) ? $regOptions['openid'] : '');
            if ($regOptions['require'] == 'activation') {
                $replacements += array('ACTIVATIONLINK' => $scripturl . '?action=activate;u=' . $memberID . ';code=' . $validation_code, 'ACTIVATIONLINKWITHOUTCODE' => $scripturl . '?action=activate;u=' . $memberID, 'ACTIVATIONCODE' => $validation_code);
            } else {
                $replacements += array('COPPALINK' => $scripturl . '?action=coppa;u=' . $memberID);
            }
            $emaildata = loadEmailTemplate('register_' . ($regOptions['auth_method'] == 'openid' ? 'openid_' : '') . ($regOptions['require'] == 'activation' ? 'activate' : 'coppa'), $replacements);
            sendmail($regOptions['email'], $emaildata['subject'], $emaildata['body'], null, null, false, 0);
        } else {
            $replacements = array('REALNAME' => $regOptions['register_vars']['real_name'], 'USERNAME' => $regOptions['username'], 'PASSWORD' => $regOptions['password'], 'FORGOTPASSWORDLINK' => $scripturl . '?action=reminder', 'OPENID' => !empty($regOptions['openid']) ? $regOptions['openid'] : '');
            $emaildata = loadEmailTemplate('register_' . ($regOptions['auth_method'] == 'openid' ? 'openid_' : '') . 'pending', $replacements);
            sendmail($regOptions['email'], $emaildata['subject'], $emaildata['body'], null, null, false, 0);
            // Admin gets informed here...
            require_once SUBSDIR . '/Notification.subs.php';
            sendAdminNotifications('approval', $memberID, $regOptions['username']);
        }
        // Okay, they're for sure registered... make sure the session is aware of this for security. (Just married :P!)
        $_SESSION['just_registered'] = 1;
    }
    // If they are for sure registered, let other people to know about it
    call_integration_hook('integrate_register_after', array($regOptions, $memberID));
    return $memberID;
}
Exemple #11
0
    /**
     * Used to edit the body or subject of a message inline
     * called from action=jsmodify from script and topic js
     */
    public function action_jsmodify()
    {
        global $modSettings, $board, $topic;
        global $user_info, $context;
        $db = database();
        // We have to have a topic!
        if (empty($topic)) {
            obExit(false);
        }
        checkSession('get');
        require_once SUBSDIR . '/Post.subs.php';
        // Assume the first message if no message ID was given.
        $request = $db->query('', '
			SELECT
				t.locked, t.num_replies, t.id_member_started, t.id_first_msg,
				m.id_msg, m.id_member, m.poster_time, m.subject, m.smileys_enabled, m.body, m.icon,
				m.modified_time, m.modified_name, m.approved
			FROM {db_prefix}messages AS m
				INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
			WHERE m.id_msg = {raw:id_msg}
				AND m.id_topic = {int:current_topic}' . (allowedTo('modify_any') || allowedTo('approve_posts') ? '' : (!$modSettings['postmod_active'] ? '
				AND (m.id_member != {int:guest_id} AND m.id_member = {int:current_member})' : '
				AND (m.approved = {int:is_approved} OR (m.id_member != {int:guest_id} AND m.id_member = {int:current_member}))')), array('current_member' => $user_info['id'], 'current_topic' => $topic, 'id_msg' => empty($_REQUEST['msg']) ? 't.id_first_msg' : (int) $_REQUEST['msg'], 'is_approved' => 1, 'guest_id' => 0));
        if ($db->num_rows($request) == 0) {
            fatal_lang_error('no_board', false);
        }
        $row = $db->fetch_assoc($request);
        $db->free_result($request);
        // Change either body or subject requires permissions to modify messages.
        if (isset($_POST['message']) || isset($_POST['subject']) || isset($_REQUEST['icon'])) {
            if (!empty($row['locked'])) {
                isAllowedTo('moderate_board');
            }
            if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any')) {
                if ((!$modSettings['postmod_active'] || $row['approved']) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time()) {
                    fatal_lang_error('modify_post_time_passed', false);
                } elseif ($row['id_member_started'] == $user_info['id'] && !allowedTo('modify_own')) {
                    isAllowedTo('modify_replies');
                } else {
                    isAllowedTo('modify_own');
                }
            } elseif ($row['id_member_started'] == $user_info['id'] && !allowedTo('modify_any')) {
                isAllowedTo('modify_replies');
            } else {
                isAllowedTo('modify_any');
            }
            // Only log this action if it wasn't your message.
            $moderationAction = $row['id_member'] != $user_info['id'];
        }
        $post_errors = Error_Context::context('post', 1);
        if (isset($_POST['subject']) && Util::htmltrim(Util::htmlspecialchars($_POST['subject'])) !== '') {
            $_POST['subject'] = strtr(Util::htmlspecialchars($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
            // Maximum number of characters.
            if (Util::strlen($_POST['subject']) > 100) {
                $_POST['subject'] = Util::substr($_POST['subject'], 0, 100);
            }
        } elseif (isset($_POST['subject'])) {
            $post_errors->addError('no_subject');
            unset($_POST['subject']);
        }
        if (isset($_POST['message'])) {
            if (Util::htmltrim(Util::htmlspecialchars($_POST['message'])) === '') {
                $post_errors->addError('no_message');
                unset($_POST['message']);
            } elseif (!empty($modSettings['max_messageLength']) && Util::strlen($_POST['message']) > $modSettings['max_messageLength']) {
                $post_errors->addError(array('long_message', array($modSettings['max_messageLength'])));
                unset($_POST['message']);
            } else {
                $_POST['message'] = Util::htmlspecialchars($_POST['message'], ENT_QUOTES);
                preparsecode($_POST['message']);
                if (Util::htmltrim(strip_tags(parse_bbc($_POST['message'], false), '<img>')) === '') {
                    $post_errors->addError('no_message');
                    unset($_POST['message']);
                }
            }
        }
        if (isset($_POST['lock'])) {
            if (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $user_info['id'] != $row['id_member']) {
                unset($_POST['lock']);
            } elseif (!allowedTo('lock_any')) {
                if ($row['locked'] == 1) {
                    unset($_POST['lock']);
                } else {
                    $_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
                }
            } elseif (!empty($row['locked']) && !empty($_POST['lock']) || $_POST['lock'] == $row['locked']) {
                unset($_POST['lock']);
            } else {
                $_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
            }
        }
        if (isset($_POST['sticky']) && !allowedTo('make_sticky')) {
            unset($_POST['sticky']);
        }
        if (!$post_errors->hasErrors()) {
            $msgOptions = array('id' => $row['id_msg'], 'subject' => isset($_POST['subject']) ? $_POST['subject'] : null, 'body' => isset($_POST['message']) ? $_POST['message'] : null, 'icon' => isset($_REQUEST['icon']) ? preg_replace('~[\\./\\\\*\':"<>]~', '', $_REQUEST['icon']) : null);
            $topicOptions = array('id' => $topic, 'board' => $board, 'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null, 'sticky_mode' => isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics']) ? (int) $_POST['sticky'] : null, 'mark_as_read' => false);
            $posterOptions = array();
            // Only consider marking as editing if they have edited the subject, message or icon.
            if (isset($_POST['subject']) && $_POST['subject'] != $row['subject'] || isset($_POST['message']) && $_POST['message'] != $row['body'] || isset($_REQUEST['icon']) && $_REQUEST['icon'] != $row['icon']) {
                // And even then only if the time has passed...
                if (time() - $row['poster_time'] > $modSettings['edit_wait_time'] || $user_info['id'] != $row['id_member']) {
                    $msgOptions['modify_time'] = time();
                    $msgOptions['modify_name'] = $user_info['name'];
                }
            } else {
                $moderationAction = false;
            }
            modifyPost($msgOptions, $topicOptions, $posterOptions);
            // If we didn't change anything this time but had before put back the old info.
            if (!isset($msgOptions['modify_time']) && !empty($row['modified_time'])) {
                $msgOptions['modify_time'] = $row['modified_time'];
                $msgOptions['modify_name'] = $row['modified_name'];
            }
            // Changing the first subject updates other subjects to 'Re: new_subject'.
            if (isset($_POST['subject']) && isset($_REQUEST['change_all_subjects']) && $row['id_first_msg'] == $row['id_msg'] && !empty($row['num_replies']) && (allowedTo('modify_any') || $row['id_member_started'] == $user_info['id'] && allowedTo('modify_replies'))) {
                // Get the proper (default language) response prefix first.
                $context['response_prefix'] = response_prefix();
                $db->query('', '
					UPDATE {db_prefix}messages
					SET subject = {string:subject}
					WHERE id_topic = {int:current_topic}
						AND id_msg != {int:id_first_msg}', array('current_topic' => $topic, 'id_first_msg' => $row['id_first_msg'], 'subject' => $context['response_prefix'] . $_POST['subject']));
            }
            if (!empty($moderationAction)) {
                logAction('modify', array('topic' => $topic, 'message' => $row['id_msg'], 'member' => $row['id_member'], 'board' => $board));
            }
        }
        if (isset($_REQUEST['xml'])) {
            $context['sub_template'] = 'modifydone';
            if (!$post_errors->hasErrors() && isset($msgOptions['subject']) && isset($msgOptions['body'])) {
                $context['message'] = array('id' => $row['id_msg'], 'modified' => array('time' => isset($msgOptions['modify_time']) ? standardTime($msgOptions['modify_time']) : '', 'html_time' => isset($msgOptions['modify_time']) ? htmlTime($msgOptions['modify_time']) : '', 'timestamp' => isset($msgOptions['modify_time']) ? forum_time(true, $msgOptions['modify_time']) : 0, 'name' => isset($msgOptions['modify_time']) ? $msgOptions['modify_name'] : ''), 'subject' => $msgOptions['subject'], 'first_in_topic' => $row['id_msg'] == $row['id_first_msg'], 'body' => strtr($msgOptions['body'], array(']]>' => ']]]]><![CDATA[>')));
                censorText($context['message']['subject']);
                censorText($context['message']['body']);
                $context['message']['body'] = parse_bbc($context['message']['body'], $row['smileys_enabled'], $row['id_msg']);
            } elseif (!$post_errors->hasErrors()) {
                $context['sub_template'] = 'modifytopicdone';
                $context['message'] = array('id' => $row['id_msg'], 'modified' => array('time' => isset($msgOptions['modify_time']) ? standardTime($msgOptions['modify_time']) : '', 'html_time' => isset($msgOptions['modify_time']) ? htmlTime($msgOptions['modify_time']) : '', 'timestamp' => isset($msgOptions['modify_time']) ? forum_time(true, $msgOptions['modify_time']) : 0, 'name' => isset($msgOptions['modify_time']) ? $msgOptions['modify_name'] : ''), 'subject' => isset($msgOptions['subject']) ? $msgOptions['subject'] : '');
                censorText($context['message']['subject']);
            } else {
                $context['message'] = array('id' => $row['id_msg'], 'errors' => array(), 'error_in_subject' => $post_errors->hasError('no_subject'), 'error_in_body' => $post_errors->hasError('no_message') || $post_errors->hasError('long_message'));
                $context['message']['errors'] = $post_errors->prepareErrors();
            }
        } else {
            obExit(false);
        }
    }
 /**
  * Send a personal message.
  */
 public function action_send2()
 {
     global $txt, $context, $user_info, $modSettings;
     // All the helpers we need
     require_once SUBSDIR . '/Auth.subs.php';
     require_once SUBSDIR . '/Post.subs.php';
     // PM Drafts enabled and needed?
     if ($context['drafts_pm_save'] && (isset($_POST['save_draft']) || isset($_POST['id_pm_draft']))) {
         require_once SUBSDIR . '/Drafts.subs.php';
     }
     loadLanguage('PersonalMessage', '', false);
     // Extract out the spam settings - it saves database space!
     list($modSettings['max_pm_recipients'], $modSettings['pm_posts_verification'], $modSettings['pm_posts_per_hour']) = explode(',', $modSettings['pm_spam_settings']);
     // Initialize the errors we're about to make.
     $post_errors = Error_Context::context('pm', 1);
     // Check whether we've gone over the limit of messages we can send per hour - fatal error if fails!
     if (!empty($modSettings['pm_posts_per_hour']) && !allowedTo(array('admin_forum', 'moderate_forum', 'send_mail')) && $user_info['mod_cache']['bq'] == '0=1' && $user_info['mod_cache']['gq'] == '0=1') {
         // How many have they sent this last hour?
         $pmCount = pmCount($user_info['id'], 3600);
         if (!empty($pmCount) && $pmCount >= $modSettings['pm_posts_per_hour']) {
             if (!isset($_REQUEST['xml'])) {
                 fatal_lang_error('pm_too_many_per_hour', true, array($modSettings['pm_posts_per_hour']));
             } else {
                 $post_errors->addError('pm_too_many_per_hour');
             }
         }
     }
     // If your session timed out, show an error, but do allow to re-submit.
     if (!isset($_REQUEST['xml']) && checkSession('post', '', false) != '') {
         $post_errors->addError('session_timeout');
     }
     $_REQUEST['subject'] = isset($_REQUEST['subject']) ? strtr(Util::htmltrim($_POST['subject']), array("\r" => '', "\n" => '', "\t" => '')) : '';
     $_REQUEST['to'] = empty($_POST['to']) ? empty($_GET['to']) ? '' : $_GET['to'] : $_POST['to'];
     $_REQUEST['bcc'] = empty($_POST['bcc']) ? empty($_GET['bcc']) ? '' : $_GET['bcc'] : $_POST['bcc'];
     // Route the input from the 'u' parameter to the 'to'-list.
     if (!empty($_POST['u'])) {
         $_POST['recipient_to'] = explode(',', $_POST['u']);
     }
     // Construct the list of recipients.
     $recipientList = array();
     $namedRecipientList = array();
     $namesNotFound = array();
     foreach (array('to', 'bcc') as $recipientType) {
         // First, let's see if there's user ID's given.
         $recipientList[$recipientType] = array();
         if (!empty($_POST['recipient_' . $recipientType]) && is_array($_POST['recipient_' . $recipientType])) {
             foreach ($_POST['recipient_' . $recipientType] as $recipient) {
                 $recipientList[$recipientType][] = (int) $recipient;
             }
         }
         // Are there also literal names set?
         if (!empty($_REQUEST[$recipientType])) {
             // We're going to take out the "s anyway ;).
             $recipientString = strtr($_REQUEST[$recipientType], array('\\"' => '"'));
             preg_match_all('~"([^"]+)"~', $recipientString, $matches);
             $namedRecipientList[$recipientType] = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $recipientString))));
             // Clean any literal names entered
             foreach ($namedRecipientList[$recipientType] as $index => $recipient) {
                 if (strlen(trim($recipient)) > 0) {
                     $namedRecipientList[$recipientType][$index] = Util::htmlspecialchars(Util::strtolower(trim($recipient)));
                 } else {
                     unset($namedRecipientList[$recipientType][$index]);
                 }
             }
             // Now see if we can resolove the entered name to an actual user
             if (!empty($namedRecipientList[$recipientType])) {
                 $foundMembers = findMembers($namedRecipientList[$recipientType]);
                 // Assume all are not found, until proven otherwise.
                 $namesNotFound[$recipientType] = $namedRecipientList[$recipientType];
                 // Make sure we only have each member listed once, incase they did not use the select list
                 foreach ($foundMembers as $member) {
                     $testNames = array(Util::strtolower($member['username']), Util::strtolower($member['name']), Util::strtolower($member['email']));
                     if (count(array_intersect($testNames, $namedRecipientList[$recipientType])) !== 0) {
                         $recipientList[$recipientType][] = $member['id'];
                         // Get rid of this username, since we found it.
                         $namesNotFound[$recipientType] = array_diff($namesNotFound[$recipientType], $testNames);
                     }
                 }
             }
         }
         // Selected a recipient to be deleted? Remove them now.
         if (!empty($_POST['delete_recipient'])) {
             $recipientList[$recipientType] = array_diff($recipientList[$recipientType], array((int) $_POST['delete_recipient']));
         }
         // Make sure we don't include the same name twice
         $recipientList[$recipientType] = array_unique($recipientList[$recipientType]);
     }
     // Are we changing the recipients some how?
     $is_recipient_change = !empty($_POST['delete_recipient']) || !empty($_POST['to_submit']) || !empty($_POST['bcc_submit']);
     // Check if there's at least one recipient.
     if (empty($recipientList['to']) && empty($recipientList['bcc'])) {
         $post_errors->addError('no_to');
     }
     // Make sure that we remove the members who did get it from the screen.
     if (!$is_recipient_change) {
         foreach (array_keys($recipientList) as $recipientType) {
             if (!empty($namesNotFound[$recipientType])) {
                 $post_errors->addError('bad_' . $recipientType);
                 // Since we already have a post error, remove the previous one.
                 $post_errors->removeError('no_to');
                 foreach ($namesNotFound[$recipientType] as $name) {
                     $context['send_log']['failed'][] = sprintf($txt['pm_error_user_not_found'], $name);
                 }
             }
         }
     }
     // Did they make any mistakes like no subject or message?
     if ($_REQUEST['subject'] == '') {
         $post_errors->addError('no_subject');
     }
     if (!isset($_REQUEST['message']) || $_REQUEST['message'] == '') {
         $post_errors->addError('no_message');
     } elseif (!empty($modSettings['max_messageLength']) && Util::strlen($_REQUEST['message']) > $modSettings['max_messageLength']) {
         $post_errors->addError('long_message');
     } else {
         // Preparse the message.
         $message = $_REQUEST['message'];
         preparsecode($message);
         // Make sure there's still some content left without the tags.
         if (Util::htmltrim(strip_tags(parse_bbc(Util::htmlspecialchars($message, ENT_QUOTES), false), '<img>')) === '' && (!allowedTo('admin_forum') || strpos($message, '[html]') === false)) {
             $post_errors->addError('no_message');
         }
     }
     // Wrong verification code?
     if (!$user_info['is_admin'] && !isset($_REQUEST['xml']) && !empty($modSettings['pm_posts_verification']) && $user_info['posts'] < $modSettings['pm_posts_verification']) {
         require_once SUBSDIR . '/VerificationControls.class.php';
         $verificationOptions = array('id' => 'pm');
         $context['require_verification'] = create_control_verification($verificationOptions, true);
         if (is_array($context['require_verification'])) {
             foreach ($context['require_verification'] as $error) {
                 $post_errors->addError($error);
             }
         }
     }
     // If they made any errors, give them a chance to make amends.
     if ($post_errors->hasErrors() && !$is_recipient_change && !isset($_REQUEST['preview']) && !isset($_REQUEST['xml'])) {
         return messagePostError($namedRecipientList, $recipientList);
     }
     // Want to take a second glance before you send?
     if (isset($_REQUEST['preview'])) {
         // Set everything up to be displayed.
         $context['preview_subject'] = Util::htmlspecialchars($_REQUEST['subject']);
         $context['preview_message'] = Util::htmlspecialchars($_REQUEST['message'], ENT_QUOTES, 'UTF-8', true);
         preparsecode($context['preview_message'], true);
         // Parse out the BBC if it is enabled.
         $context['preview_message'] = parse_bbc($context['preview_message']);
         // Censor, as always.
         censorText($context['preview_subject']);
         censorText($context['preview_message']);
         // Set a descriptive title.
         $context['page_title'] = $txt['preview'] . ' - ' . $context['preview_subject'];
         // Pretend they messed up but don't ignore if they really did :P.
         return messagePostError($namedRecipientList, $recipientList);
     } elseif ($is_recipient_change) {
         // Maybe we couldn't find one?
         foreach ($namesNotFound as $recipientType => $names) {
             $post_errors->addError('bad_' . $recipientType);
             foreach ($names as $name) {
                 $context['send_log']['failed'][] = sprintf($txt['pm_error_user_not_found'], $name);
             }
         }
         return messagePostError($namedRecipientList, $recipientList);
     }
     // Want to save this as a draft and think about it some more?
     if ($context['drafts_pm_save'] && isset($_POST['save_draft'])) {
         savePMDraft($recipientList);
         return messagePostError($namedRecipientList, $recipientList);
     } elseif (!empty($modSettings['max_pm_recipients']) && count($recipientList['to']) + count($recipientList['bcc']) > $modSettings['max_pm_recipients'] && !allowedTo(array('moderate_forum', 'send_mail', 'admin_forum'))) {
         $context['send_log'] = array('sent' => array(), 'failed' => array(sprintf($txt['pm_too_many_recipients'], $modSettings['max_pm_recipients'])));
         return messagePostError($namedRecipientList, $recipientList);
     }
     // Protect from message spamming.
     spamProtection('pm');
     // Prevent double submission of this form.
     checkSubmitOnce('check');
     // Finally do the actual sending of the PM.
     if (!empty($recipientList['to']) || !empty($recipientList['bcc'])) {
         $context['send_log'] = sendpm($recipientList, $_REQUEST['subject'], $_REQUEST['message'], true, null, !empty($_REQUEST['pm_head']) ? (int) $_REQUEST['pm_head'] : 0);
     } else {
         $context['send_log'] = array('sent' => array(), 'failed' => array());
     }
     // Mark the message as "replied to".
     if (!empty($context['send_log']['sent']) && !empty($_REQUEST['replied_to']) && isset($_REQUEST['f']) && $_REQUEST['f'] == 'inbox') {
         require_once SUBSDIR . '/PersonalMessage.subs.php';
         setPMRepliedStatus($user_info['id'], (int) $_REQUEST['replied_to']);
     }
     // If one or more of the recipients were invalid, go back to the post screen with the failed usernames.
     if (!empty($context['send_log']['failed'])) {
         return messagePostError($namesNotFound, array('to' => array_intersect($recipientList['to'], $context['send_log']['failed']), 'bcc' => array_intersect($recipientList['bcc'], $context['send_log']['failed'])));
     }
     // Message sent successfully?
     if (!empty($context['send_log']) && empty($context['send_log']['failed'])) {
         $context['current_label_redirect'] = $context['current_label_redirect'] . ';done=sent';
         // If we had a PM draft for this one, then its time to remove it since it was just sent
         if ($context['drafts_pm_save'] && !empty($_POST['id_pm_draft'])) {
             deleteDrafts($_POST['id_pm_draft'], $user_info['id']);
         }
     }
     // Go back to the where they sent from, if possible...
     redirectexit($context['current_label_redirect']);
 }
Exemple #13
0
/**
 * Saves a PM draft in the user_drafts table
 *
 * - The core draft feature must be enabled, as well as the pm draft option
 * - Determines if this is a new or and update to an existing pm draft
 *
 * @package Drafts
 * @param mixed[] $recipientList
 */
function savePMDraft($recipientList)
{
    global $context, $user_info, $modSettings;
    // Ajax calling
    if (!isset($context['drafts_pm_save'])) {
        $context['drafts_pm_save'] = !empty($modSettings['drafts_enabled']) && !empty($modSettings['drafts_pm_enabled']) && allowedTo('pm_draft');
    }
    // PM survey says ... can you stay or must you go
    if (empty($context['drafts_pm_save']) || !isset($_POST['save_draft']) || !isset($_POST['id_pm_draft'])) {
        return false;
    }
    // Read in what was sent
    $id_pm_draft = empty($_POST['id_pm_draft']) ? 0 : (int) $_POST['id_pm_draft'];
    $draft_info = loadDraft($id_pm_draft, 1);
    $post_errors = Error_Context::context('pm', 1);
    // 5 seconds is the same limit we have for posting
    if (isset($_REQUEST['xml']) && !empty($draft_info['poster_time']) && time() < $draft_info['poster_time'] + 5) {
        // Send something back to the javascript caller
        if (!empty($id_pm_draft)) {
            loadTemplate('Xml');
            $context['sub_template'] = 'xml_draft';
            $context['id_draft'] = $id_pm_draft;
            $context['draft_saved_on'] = $draft_info['poster_time'];
            obExit();
        }
        return true;
    }
    // Determine who this is being sent to
    if (isset($_REQUEST['xml'])) {
        $recipientList['to'] = isset($_POST['recipient_to']) ? explode(',', $_POST['recipient_to']) : array();
        $recipientList['bcc'] = isset($_POST['recipient_bcc']) ? explode(',', $_POST['recipient_bcc']) : array();
    } elseif (!empty($draft_info['to_list']) && empty($recipientList)) {
        $recipientList = unserialize($draft_info['to_list']);
    }
    // Prepare the data
    $draft = array('id_pm_draft' => $id_pm_draft, 'reply_id' => empty($_POST['replied_to']) ? 0 : (int) $_POST['replied_to'], 'body' => Util::htmlspecialchars($_POST['message'], ENT_QUOTES), 'subject' => strtr(Util::htmlspecialchars($_POST['subject']), array("\r" => '', "\n" => '', "\t" => '')), 'id_member' => $user_info['id']);
    // message and subject always need a bit more work
    preparsecode($draft['body']);
    if (Util::strlen($draft['subject']) > 100) {
        $draft['subject'] = Util::substr($draft['subject'], 0, 100);
    }
    // Modifying an existing PM draft?
    if (!empty($id_pm_draft) && !empty($draft_info)) {
        modify_pm_draft($draft, $recipientList);
        // some items to return to the form
        $context['draft_saved'] = true;
        $context['id_pm_draft'] = $id_pm_draft;
    } else {
        $id_pm_draft = create_pm_draft($draft, $recipientList);
        // Everything go as expected, if not toss back an error
        if (!empty($id_pm_draft)) {
            $context['draft_saved'] = true;
            $context['id_pm_draft'] = $id_pm_draft;
        } else {
            $post_errors->addError('draft_not_saved');
        }
    }
    // if we were called from the autosave function, send something back
    if (!empty($id_pm_draft) && isset($_REQUEST['xml']) && !$post_errors->hasError('session_timeout')) {
        loadTemplate('Xml');
        $context['sub_template'] = 'xml_draft';
        $context['id_draft'] = $id_pm_draft;
        $context['draft_saved_on'] = time();
        obExit();
    }
    return;
}
 public function action_register2()
 {
     global $txt, $modSettings, $context, $user_info;
     // Start collecting together any errors.
     $reg_errors = Error_Context::context('register', 0);
     // Check they are who they should be
     checkSession();
     if (!validateToken('register', 'post', true, false)) {
         $reg_errors->addError('token_verification');
     }
     // You can't register if it's disabled.
     if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 3) {
         fatal_lang_error('registration_disabled', false);
     }
     // Well, if you don't agree, you can't register.
     if (!empty($modSettings['requireAgreement']) && !isset($_POST['checkbox_agreement'])) {
         $reg_errors->addError('agreement_unchecked');
     }
     // Make sure they came from *somewhere*, have a session.
     if (!isset($_SESSION['old_url'])) {
         redirectexit('action=register');
     }
     // Check their provider deatils match up correctly in case they're pulling something funny
     if ($_POST['provider'] != $_SESSION['extauth_info']['provider']) {
         redirectexit('action=register');
     }
     // Clean up
     foreach ($_POST as $key => $value) {
         if (!is_array($_POST[$key])) {
             $_POST[$key] = htmltrim__recursive(str_replace(array("\n", "\r"), '', $_POST[$key]));
         }
     }
     // Needed for isReservedName() and registerMember()
     require_once SUBSDIR . '/Members.subs.php';
     // Needed for generateValidationCode()
     require_once SUBSDIR . '/Auth.subs.php';
     // Set the options needed for registration.
     $regOptions = array('interface' => 'guest', 'username' => !empty($_POST['user']) ? $_POST['user'] : '', 'email' => !empty($_POST['email']) ? $_POST['email'] : '', 'check_reserved_name' => true, 'check_password_strength' => true, 'check_email_ban' => true, 'send_welcome_email' => !empty($modSettings['send_welcomeEmail']), 'require' => empty($modSettings['registration_method']) ? 'nothing' : ($modSettings['registration_method'] == 1 ? 'activation' : 'approval'));
     // Lets check for other errors before trying to register the member.
     if ($reg_errors->hasErrors()) {
         return $this->action_register();
     }
     mt_srand(time() + 1277);
     $regOptions['password'] = generateValidationCode();
     $regOptions['password_check'] = $regOptions['password'];
     // Registration needs to know your IP
     $req = request();
     $regOptions['ip'] = $user_info['ip'];
     $regOptions['ip2'] = $req->ban_ip();
     $memberID = registerMember($regOptions, 'register');
     // If there are "important" errors and you are not an admin: log the first error
     // Otherwise grab all of them and don't log anything
     if ($reg_errors->hasErrors(1) && !$user_info['is_admin']) {
         foreach ($reg_errors->prepareErrors(1) as $error) {
             fatal_error($error, 'general');
         }
     }
     // One last error check
     if ($reg_errors->hasErrors()) {
         return $this->action_register();
     }
     // Do our spam protection now.
     spamProtection('register');
     // Since all is well, we'll go ahead and associate the member's external account
     addAuth($memberID, $_SESSION['extauth_info']['provider'], $_SESSION['extauth_info']['uid'], $_SESSION['extauth_info']['name']);
     // Basic template variable setup.
     if (!empty($modSettings['registration_method'])) {
         loadTemplate('Register');
         $context += array('page_title' => $txt['register'], 'title' => $txt['registration_successful'], 'sub_template' => 'after', 'description' => $modSettings['registration_method'] == 2 ? $txt['approval_after_registration'] : $txt['activate_after_registration']);
     } else {
         call_integration_hook('integrate_activate', array($regOptions['username']));
         setLoginCookie(60 * $modSettings['cookieTime'], $memberID, hash('sha256', Util::strtolower($regOptions['username']) . $regOptions['password'] . $regOptions['register_vars']['password_salt']));
         redirectexit('action=auth;sa=check;member=' . $memberID, $context['server']['needs_login_fix']);
     }
 }
 /**
  * Add an error
  *
  * @param string $error error code
  * @param string|null $lang_file = null
  */
 public function addError($error, $lang_file = null)
 {
     if (empty($error)) {
         return;
     }
     if ($this->_active_attach == 'generic') {
         if (!isset($this->_attachs[$this->_active_attach])) {
             $this->_generic_error = Error_Context::context('attach_generic_error', 1);
         }
         $this->_generic_error->addError($error, $lang_file);
         return;
     }
     $this->_attachs[$this->_active_attach]['error']->addError($error, $lang_file);
 }
 /**
  * Does the actual saving of the page data
  *
  * - validates the data is safe to save
  * - updates existing pages or creates new ones
  */
 private function _sportal_admin_page_edit_save()
 {
     global $txt, $context, $modSettings;
     // No errors, yet.
     $pages_errors = Error_Context::context('pages', 0);
     // Use our standard validation functions in a few spots
     require_once SUBSDIR . '/DataValidator.class.php';
     $validator = new Data_Validator();
     // Clean and Review the post data for compliance
     $validator->sanitation_rules(array('title' => 'trim|Util::htmlspecialchars', 'namespace' => 'trim|Util::htmlspecialchars', 'permissions' => 'intval', 'type' => 'trim', 'content' => 'trim'));
     $validator->validation_rules(array('title' => 'required', 'namespace' => 'alpha_numeric|required', 'type' => 'required', 'content' => 'required'));
     $validator->text_replacements(array('title' => $txt['sp_error_page_name_empty'], 'namespace' => $txt['sp_error_page_namespace_empty'], 'content' => $txt['sp_admin_pages_col_body']));
     // If you messed this up, back you go
     if (!$validator->validate($_POST)) {
         foreach ($validator->validation_errors() as $id => $error) {
             $pages_errors->addError($error);
         }
         $this->action_sportal_admin_page_edit();
     }
     // Can't have the same name in the same space twice
     $has_duplicate = sp_check_duplicate_pages($_POST['namespace'], $_POST['page_id']);
     if (!empty($has_duplicate)) {
         $pages_errors->addError('sp_error_page_namespace_duplicate');
     }
     // Can't have a simple numeric namespace
     if (preg_replace('~[0-9]+~', '', $_POST['namespace']) === '') {
         $pages_errors->addError('sp_error_page_namespace_numeric');
     }
     if ($_POST['type'] === 'php' && !allowedTo('admin_forum')) {
         fatal_lang_error('cannot_admin_forum', false);
     }
     // Running some php code, then we need to validate its legit code
     if ($_POST['type'] === 'php' && !empty($_POST['content']) && empty($modSettings['sp_disable_php_validation'])) {
         $validator_php = new Data_Validator();
         $validator_php->validation_rules(array('content' => 'php_syntax'));
         // Bad PHP code
         if (!$validator_php->validate(array('content' => $_POST['content']))) {
             $pages_errors->addError($validator_php->validation_errors());
         }
     }
     // None shall pass ... with errors
     if ($pages_errors->hasErrors()) {
         $this->action_sportal_admin_page_edit();
     }
     // If you made it this far, we are going to save the work
     if (!empty($_POST['blocks']) && is_array($_POST['blocks'])) {
         foreach ($_POST['blocks'] as $id => $block) {
             $_POST['blocks'][$id] = (int) $block;
         }
     } else {
         $_POST['blocks'] = array();
     }
     // The data for the fields
     $page_info = array('id' => (int) $_POST['page_id'], 'namespace' => Util::htmlspecialchars($_POST['namespace'], ENT_QUOTES), 'title' => Util::htmlspecialchars($_POST['title'], ENT_QUOTES), 'body' => Util::htmlspecialchars($_POST['content'], ENT_QUOTES), 'type' => in_array($_POST['type'], array('bbc', 'html', 'php')) ? $_POST['type'] : 'bbc', 'permissions' => (int) $_POST['permissions'], 'style' => sportal_parse_style('implode'), 'status' => !empty($_POST['status']) ? 1 : 0);
     if ($page_info['type'] === 'bbc') {
         preparsecode($page_info['body']);
     }
     // Save away
     sp_save_page($page_info, $context['SPortal']['is_new']);
     $to_show = array();
     $not_to_show = array();
     $changes = array();
     foreach ($context['page_blocks'] as $page_blocks) {
         foreach ($page_blocks as $block) {
             if ($block['shown'] && !in_array($block['id'], $_POST['blocks'])) {
                 $not_to_show[] = $block['id'];
             } elseif (!$block['shown'] && in_array($block['id'], $_POST['blocks'])) {
                 $to_show[] = $block['id'];
             }
         }
     }
     foreach ($to_show as $id) {
         if (empty($this->blocks[$id]['display']) && empty($this->blocks[$id]['display_custom']) || $this->blocks[$id]['display'] == 'sportal') {
             $changes[$id] = array('display' => 'portal,p' . $page_info['id'], 'display_custom' => '');
         } elseif (in_array($this->blocks[$id]['display'], array('allaction', 'allboard'))) {
             $changes[$id] = array('display' => '', 'display_custom' => $this->blocks[$id]['display'] . ',p' . $page_info['id']);
         } elseif (in_array('-p' . $page_info['id'], explode(',', $this->blocks[$id]['display_custom']))) {
             $changes[$id] = array('display' => $this->blocks[$id]['display'], 'display_custom' => implode(',', array_diff(explode(',', $this->blocks[$id]['display_custom']), array('-p' . $page_info['id']))));
         } elseif (empty($this->blocks[$id]['display_custom'])) {
             $changes[$id] = array('display' => implode(',', array_merge(explode(',', $this->blocks[$id]['display']), array('p' . $page_info['id']))), 'display_custom' => '');
         } else {
             $changes[$id] = array('display' => $this->blocks[$id]['display'], 'display_custom' => implode(',', array_merge(explode(',', $this->blocks[$id]['display_custom']), array('p' . $page_info['id']))));
         }
     }
     foreach ($not_to_show as $id) {
         if (count(array_intersect(array($this->blocks[$id]['display'], $this->blocks[$id]['display_custom']), array('sforum', 'allpages', 'all'))) > 0) {
             $changes[$id] = array('display' => '', 'display_custom' => $this->blocks[$id]['display'] . $this->blocks[$id]['display_custom'] . ',-p' . $page_info['id']);
         } elseif (empty($this->blocks[$id]['display_custom'])) {
             $changes[$id] = array('display' => implode(',', array_diff(explode(',', $this->blocks[$id]['display']), array('p' . $page_info['id']))), 'display_custom' => '');
         } else {
             $changes[$id] = array('display' => implode(',', array_diff(explode(',', $this->blocks[$id]['display']), array('p' . $page_info['id']))), 'display_custom' => implode(',', array_diff(explode(',', $this->blocks[$id]['display_custom']), array('p' . $page_info['id']))));
         }
     }
     // Update the blocks as needed
     foreach ($changes as $id => $data) {
         sp_update_block_visibility($id, $data);
     }
     redirectexit('action=admin;area=portalpages');
     return true;
 }
 /**
  * This function allows the admin to register a new member by hand.
  *
  * - It also allows assigning a primary group to the member being registered.
  * - Accessed by ?action=admin;area=regcenter;sa=register
  * - Requires the moderate_forum permission.
  *
  * @uses Register template, admin_register sub-template.
  */
 public function action_register()
 {
     global $txt, $context, $scripturl, $user_info;
     if (!empty($_POST['regSubmit'])) {
         checkSession();
         validateToken('admin-regc');
         foreach ($_POST as $key => $dummy) {
             if (!is_array($_POST[$key])) {
                 $_POST[$key] = htmltrim__recursive(str_replace(array("\n", "\r"), '', $_POST[$key]));
             }
         }
         $regOptions = array('interface' => 'admin', 'username' => $_POST['user'], 'email' => $_POST['email'], 'password' => $_POST['password'], 'password_check' => $_POST['password'], 'check_reserved_name' => true, 'check_password_strength' => true, 'check_email_ban' => false, 'send_welcome_email' => isset($_POST['emailPassword']) || empty($_POST['password']), 'require' => isset($_POST['emailActivate']) ? 'activation' : 'nothing', 'memberGroup' => empty($_POST['group']) || !allowedTo('manage_membergroups') ? 0 : (int) $_POST['group']);
         require_once SUBSDIR . '/Members.subs.php';
         $reg_errors = Error_Context::context('register', 0);
         $memberID = registerMember($regOptions, 'register');
         // If there are "important" errors and you are not an admin: log the first error
         // Otherwise grab all of them and don't log anything
         $error_severity = $reg_errors->hasErrors(1) && !$user_info['is_admin'] ? 1 : null;
         foreach ($reg_errors->prepareErrors($error_severity) as $error) {
             fatal_error($error, $error_severity === null ? false : 'general');
         }
         if (!empty($memberID)) {
             $context['new_member'] = array('id' => $memberID, 'name' => $_POST['user'], 'href' => $scripturl . '?action=profile;u=' . $memberID, 'link' => '<a href="' . $scripturl . '?action=profile;u=' . $memberID . '">' . $_POST['user'] . '</a>');
             $context['registration_done'] = sprintf($txt['admin_register_done'], $context['new_member']['link']);
         }
     }
     // Load the assignable member groups.
     if (allowedTo('manage_membergroups')) {
         require_once SUBSDIR . '/Membergroups.subs.php';
         if (allowedTo('admin_forum')) {
             $includes = array('admin', 'globalmod', 'member');
         } else {
             $includes = array('globalmod', 'member', 'custom');
         }
         $groups = array();
         $membergroups = getBasicMembergroupData($includes, array('hidden', 'protected'));
         foreach ($membergroups as $membergroup) {
             $groups[$membergroup['id']] = $membergroup['name'];
         }
         $context['member_groups'] = $groups;
     } else {
         $context['member_groups'] = array();
     }
     // Basic stuff.
     addInlineJavascript('disableAutoComplete();', true);
     $context['sub_template'] = 'admin_register';
     $context['page_title'] = $txt['registration_center'];
     createToken('admin-regc');
 }