From 2e17e448deed073f8614bb555a8ef20c57291c2a Mon Sep 17 00:00:00 2001 From: Meik Sievertsen Date: Sun, 4 Oct 2009 18:14:59 +0000 Subject: Copy 3.0.x branch to trunk git-svn-id: file:///svn/phpbb/trunk@10211 89ea8834-ac86-4346-8a33-228a782c2dd0 --- .../captcha/plugins/phpbb_captcha_qa_plugin.php | 945 +++++++++++++++++++++ 1 file changed, 945 insertions(+) create mode 100644 phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php (limited to 'phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php') diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php new file mode 100644 index 0000000000..c17cfa7bbe --- /dev/null +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -0,0 +1,945 @@ +add_lang('captcha_qa'); + + // read input + $this->confirm_id = request_var('qa_confirm_id', ''); + $this->answer = request_var('qa_answer', '', true); + + $this->type = (int) $type; + $this->question_lang = $user->lang_name; + + // we need all defined questions - shouldn't be too many, so we can just grab them + // try the user's lang first + $sql = 'SELECT question_id + FROM ' . CAPTCHA_QUESTIONS_TABLE . " + WHERE lang_iso = '" . $db->sql_escape($user->lang_name) . "'"; + $result = $db->sql_query($sql, 3600); + + while ($row = $db->sql_fetchrow($result)) + { + $this->question_ids[$row['question_id']] = $row['question_id']; + } + $db->sql_freeresult($result); + + // fallback to the board default lang + if (!sizeof($this->question_ids)) + { + $this->question_lang = $config['default_lang']; + + $sql = 'SELECT question_id + FROM ' . CAPTCHA_QUESTIONS_TABLE . " + WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; + $result = $db->sql_query($sql, 7200); + + while ($row = $db->sql_fetchrow($result)) + { + $this->question_ids[$row['question_id']] = $row['question_id']; + } + $db->sql_freeresult($result); + } + + // okay, if there is a confirm_id, we try to load that confirm's state + if (!strlen($this->confirm_id) || !$this->load_answer()) + { + // we have no valid confirm ID, better get ready to ask something + $this->select_question(); + } + } + + /** + * API function + */ + function &get_instance() + { + $instance =& new phpbb_captcha_qa(); + + return $instance; + } + + /** + * See if the captcha has created its tables. + */ + function is_installed() + { + global $db, $phpbb_root_path, $phpEx; + + if (!class_exists('phpbb_db_tools')) + { + include("$phpbb_root_path/includes/db/db_tools.$phpEx"); + } + $db_tool = new phpbb_db_tools($db); + + return $db_tool->sql_table_exists(CAPTCHA_QUESTIONS_TABLE); + } + + /** + * API function - for the captcha to be available, it must have installed itself and there has to be at least one question in the board's default lang + */ + function is_available() + { + global $config, $db, $phpbb_root_path, $phpEx, $user; + + // load language file for pretty display in the ACP dropdown + $user->add_lang('captcha_qa'); + + if (!phpbb_captcha_qa::is_installed()) + { + return false; + } + + $sql = 'SELECT COUNT(question_id) as count + FROM ' . CAPTCHA_QUESTIONS_TABLE . " + WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + return ((bool) $row['count']); + } + + /** + * API function + */ + function has_config() + { + return true; + } + + /** + * API function + */ + function get_name() + { + return 'CAPTCHA_QA'; + } + + /** + * API function + */ + function get_class_name() + { + return 'phpbb_captcha_qa'; + } + + /** + * API function - not needed as we don't display an image + */ + function execute_demo() + { + } + + /** + * API function - not needed as we don't display an image + */ + function execute() + { + } + + /** + * API function - send the question to the template + */ + function get_template() + { + global $template; + + if ($this->is_solved()) + { + return false; + } + else + { + $template->assign_vars(array( + 'QA_CONFIRM_QUESTION' => $this->question_text, + 'QA_CONFIRM_ID' => $this->confirm_id, + 'S_CONFIRM_CODE' => true, + 'S_TYPE' => $this->type, + )); + + return 'captcha_qa.html'; + } + } + + /** + * API function - we just display a mockup so that the captcha doesn't need to be installed + */ + function get_demo_template() + { + return 'captcha_qa_acp_demo.html'; + } + + /** + * API function + */ + function get_hidden_fields() + { + $hidden_fields = array(); + + // this is required - otherwise we would forget about the captcha being already solved + if ($this->solved) + { + $hidden_fields['qa_answer'] = $this->answer; + } + $hidden_fields['qa_confirm_id'] = $this->confirm_id; + + return $hidden_fields; + } + + /** + * API function + */ + function garbage_collect($type) + { + global $db, $config; + + $sql = 'SELECT DISTINCT c.session_id + FROM ' . CAPTCHA_QA_CONFIRM_TABLE . ' c + LEFT JOIN ' . SESSIONS_TABLE . ' s + ON (c.session_id = s.session_id) + WHERE s.session_id IS NULL' . + ((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type); + $result = $db->sql_query($sql); + + if ($row = $db->sql_fetchrow($result)) + { + $sql_in = array(); + + do + { + $sql_in[] = (string) $row['session_id']; + } + while ($row = $db->sql_fetchrow($result)); + + if (sizeof($sql_in)) + { + $sql = 'DELETE FROM ' . CAPTCHA_QA_CONFIRM_TABLE . ' + WHERE ' . $db->sql_in_set('session_id', $sql_in); + $db->sql_query($sql); + } + } + $db->sql_freeresult($result); + } + + /** + * API function - we don't drop the tables here, as that would cause the loss of all entered questions. + */ + function uninstall() + { + $this->garbage_collect(0); + } + + /** + * API function - set up shop + */ + function install() + { + global $db, $phpbb_root_path, $phpEx; + + if (!class_exists('phpbb_db_tools')) + { + include("$phpbb_root_path/includes/db/db_tools.$phpEx"); + } + $db_tool = new phpbb_db_tools($db); + + $tables = array(CAPTCHA_QUESTIONS_TABLE, CAPTCHA_ANSWERS_TABLE, CAPTCHA_QA_CONFIRM_TABLE); + + $schemas = array( + CAPTCHA_QUESTIONS_TABLE => array ( + 'COLUMNS' => array( + 'question_id' => array('UINT', Null, 'auto_increment'), + 'strict' => array('BOOL', 0), + 'lang_id' => array('UINT', 0), + 'lang_iso' => array('VCHAR:30', ''), + 'question_text' => array('TEXT_UNI', ''), + ), + 'PRIMARY_KEY' => 'question_id', + 'KEYS' => array( + 'lang_iso' => array('INDEX', 'lang_iso'), + ), + ), + CAPTCHA_ANSWERS_TABLE => array ( + 'COLUMNS' => array( + 'question_id' => array('UINT', 0), + 'answer_text' => array('STEXT_UNI', ''), + ), + 'KEYS' => array( + 'question_id' => array('INDEX', 'question_id'), + ), + ), + CAPTCHA_QA_CONFIRM_TABLE => array ( + 'COLUMNS' => array( + 'session_id' => array('CHAR:32', ''), + 'confirm_id' => array('CHAR:32', ''), + 'lang_iso' => array('VCHAR:30', ''), + 'question_id' => array('UINT', 0), + 'attempts' => array('UINT', 0), + 'confirm_type' => array('USINT', 0), + ), + 'KEYS' => array( + 'session_id' => array('INDEX', 'session_id'), + 'lookup' => array('INDEX', array('confirm_id', 'session_id', 'lang_iso')), + ), + 'PRIMARY_KEY' => 'confirm_id', + ), + ); + + foreach($schemas as $table => $schema) + { + if (!$db_tool->sql_table_exists($table)) + { + $db_tool->sql_create_table($table, $schema); + } + } + } + + /** + * API function - see what has to be done to validate + */ + function validate() + { + global $config, $db, $user; + + $error = ''; + + if (!sizeof($this->question_ids)) + { + return false; + } + + if (!$this->confirm_id) + { + $error = $user->lang['CONFIRM_QUESTION_WRONG']; + } + else + { + if ($this->check_answer()) + { + // $this->delete_code(); commented out to allow posting.php to repeat the question + $this->solved = true; + } + else + { + $error = $user->lang['CONFIRM_QUESTION_WRONG']; + } + } + + if (strlen($error)) + { + // okay, incorrect answer. Let's ask a new question. + $this->new_attempt(); + $this->solved = false; + + return $error; + } + else + { + return false; + } + } + + /** + * Select a question + */ + function select_question() + { + global $db, $user; + + + if (!sizeof($this->question_ids)) + { + return false; + } + $this->confirm_id = md5(unique_id($user->ip)); + $this->question = (int) array_rand($this->question_ids); + + $sql = 'INSERT INTO ' . CAPTCHA_QA_CONFIRM_TABLE . ' ' . $db->sql_build_array('INSERT', array( + 'confirm_id' => (string) $this->confirm_id, + 'session_id' => (string) $user->session_id, + 'lang_iso' => (string) $this->question_lang, + 'confirm_type' => (int) $this->type, + 'question_id' => (int) $this->question, + )); + $db->sql_query($sql); + + $this->load_answer(); + } + + /** + * New Question, if desired. + */ + function reselect_question() + { + global $db, $user; + + if (!sizeof($this->question_ids)) + { + return false; + } + + $this->question = (int) array_rand($this->question_ids); + $this->solved = 0; + + $sql = 'UPDATE ' . CAPTCHA_QA_CONFIRM_TABLE . ' + SET question_id = ' . (int) $this->question . " + WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' + AND session_id = '" . $db->sql_escape($user->session_id) . "'"; + $db->sql_query($sql); + + $this->load_answer(); + } + + /** + * Wrong answer, so we increase the attempts and use a different question. + */ + function new_attempt() + { + global $db, $user; + + // yah, I would prefer a stronger rand, but this should work + $this->question = (int) array_rand($this->question_ids); + $this->solved = 0; + + $sql = 'UPDATE ' . CAPTCHA_QA_CONFIRM_TABLE . ' + SET question_id = ' . (int) $this->question . ", + attempts = attempts + 1 + WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' + AND session_id = '" . $db->sql_escape($user->session_id) . "'"; + $db->sql_query($sql); + + $this->load_answer(); + } + + /** + * Look up everything we need and populate the instance variables. + */ + function load_answer() + { + global $db, $user; + + if (!sizeof($this->question_ids)) + { + return false; + } + + $sql = 'SELECT con.question_id, attempts, question_text, strict + FROM ' . CAPTCHA_QA_CONFIRM_TABLE . ' con, ' . CAPTCHA_QUESTIONS_TABLE . " qes + WHERE con.question_id = qes.question_id + AND confirm_id = '" . $db->sql_escape($this->confirm_id) . "' + AND session_id = '" . $db->sql_escape($user->session_id) . "' + AND qes.lang_iso = '" . $db->sql_escape($this->question_lang) . "' + AND confirm_type = " . $this->type; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if ($row) + { + $this->question = $row['question_id']; + + $this->attempts = $row['attempts']; + $this->question_strict = $row['strict']; + $this->question_text = $row['question_text']; + + return true; + } + + return false; + } + + /** + * The actual validation + */ + function check_answer() + { + global $db; + + $answer = ($this->question_strict) ? request_var('qa_answer', '', true) : utf8_clean_string(request_var('qa_answer', '', true)); + + $sql = 'SELECT answer_text + FROM ' . CAPTCHA_ANSWERS_TABLE . ' + WHERE question_id = ' . (int) $this->question; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $solution = ($this->question_strict) ? $row['answer_text'] : utf8_clean_string($row['answer_text']); + + if ($solution === $answer) + { + $this->solved = true; + + break; + } + } + $db->sql_freeresult($result); + + return $this->solved; + } + + /** + * API function - clean the entry + */ + function delete_code() + { + global $db, $user; + + $sql = 'DELETE FROM ' . CAPTCHA_QA_CONFIRM_TABLE . " + WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' + AND session_id = '" . $db->sql_escape($user->session_id) . "' + AND confirm_type = " . $this->type; + $db->sql_query($sql); + } + + /** + * API function + */ + function get_attempt_count() + { + return $this->attempts; + } + + /** + * API function + */ + function reset() + { + global $db, $user; + + $sql = 'DELETE FROM ' . CAPTCHA_QA_CONFIRM_TABLE . " + WHERE session_id = '" . $db->sql_escape($user->session_id) . "' + AND confirm_type = " . (int) $this->type; + $db->sql_query($sql); + + // we leave the class usable by generating a new question + $this->select_question(); + } + + /** + * API function + */ + function is_solved() + { + if (request_var('qa_answer', false) && $this->solved === 0) + { + $this->validate(); + } + + return (bool) $this->solved; + } + + /** + * API function - The ACP backend, this marks the end of the easy methods + */ + function acp_page($id, &$module) + { + global $db, $user, $auth, $template; + global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; + + $user->add_lang('acp/board'); + $user->add_lang('captcha_qa'); + + if (!$this->is_installed()) + { + $this->install(); + } + + $module->tpl_name = 'captcha_qa_acp'; + $module->page_title = 'ACP_VC_SETTINGS'; + $form_key = 'acp_captcha'; + add_form_key($form_key); + + $submit = request_var('submit', false); + $question_id = request_var('question_id', 0); + $action = request_var('action', ''); + + // we have two pages, so users might want to navigate from one to the other + $list_url = $module->u_action . "&configure=1&select_captcha=" . $this->get_class_name(); + + $template->assign_vars(array( + 'U_ACTION' => $module->u_action, + 'QUESTION_ID' => $question_id , + 'CLASS' => $this->get_class_name(), + )); + + // show the list? + if (!$question_id && $action != 'add') + { + $this->acp_question_list($module); + } + else if ($question_id && $action == 'delete') + { + if (confirm_box(true)) + { + $this->acp_delete_question($question_id); + + trigger_error($user->lang['QUESTION_DELETED'] . adm_back_link($list_url)); + } + else + { + confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( + 'question_id' => $question_id, + 'action' => $action, + 'configure' => 1, + 'select_captcha' => $this->get_class_name(), + )) + ); + } + } + else + { + // okay, show the editor + $error = false; + $input_question = request_var('question_text', '', true); + $input_answers = request_var('answers', '', true); + $input_lang = request_var('lang_iso', '', true); + $input_strict = request_var('strict', false); + $langs = $this->get_languages(); + + foreach ($langs as $lang => $entry) + { + $template->assign_block_vars('langs', array( + 'ISO' => $lang, + 'NAME' => $entry['name'], + )); + } + + $template->assign_vars(array( + 'U_LIST' => $list_url, + )); + + if ($question_id) + { + if ($question = $this->acp_get_question_data($question_id)) + { + $answers = (isset($input_answers[$lang])) ? $input_answers[$lang] : implode("\n", $question['answers']); + + $template->assign_vars(array( + 'QUESTION_TEXT' => ($input_question) ? $input_question : $question['question_text'], + 'LANG_ISO' => ($input_lang) ? $input_lang : $question['lang_iso'], + 'STRICT' => (isset($_REQUEST['strict'])) ? $input_strict : $question['strict'], + 'ANSWERS' => $answers, + )); + } + else + { + trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url)); + } + } + else + { + $template->assign_vars(array( + 'QUESTION_TEXT' => $input_question, + 'LANG_ISO' => $input_lang, + 'STRICT' => $input_strict, + 'ANSWERS' => $input_answers, + )); + } + + if ($submit && check_form_key($form_key)) + { + $data = $this->acp_get_question_input(); + + if (!$this->validate_input($data)) + { + $template->assign_vars(array( + 'S_ERROR' => true, + )); + } + else + { + if ($question_id) + { + $this->acp_update_question($data, $question_id); + } + else + { + $this->acp_add_question($data); + } + + add_log('admin', 'LOG_CONFIG_VISUAL'); + trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($list_url)); + } + } + else if ($submit) + { + trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url)); + } + } + } + + /** + * This handles the list overview + */ + function acp_question_list(&$module) + { + global $db, $template; + + $sql = 'SELECT * + FROM ' . CAPTCHA_QUESTIONS_TABLE; + $result = $db->sql_query($sql); + + $template->assign_vars(array( + 'S_LIST' => true, + )); + + while ($row = $db->sql_fetchrow($result)) + { + $url = $module->u_action . "&question_id={$row['question_id']}&configure=1&select_captcha=" . $this->get_class_name() . '&'; + + $template->assign_block_vars('questions', array( + 'QUESTION_TEXT' => $row['question_text'], + 'QUESTION_ID' => $row['question_id'], + 'QUESTION_LANG' => $row['lang_iso'], + 'U_DELETE' => "{$url}action=delete", + 'U_EDIT' => "{$url}action=edit", + )); + } + $db->sql_freeresult($result); + } + + /** + * Grab a question and bring it into a format the editor understands + */ + function acp_get_question_data($question_id) + { + global $db; + + if ($question_id) + { + $sql = 'SELECT * + FROM ' . CAPTCHA_QUESTIONS_TABLE . ' + WHERE question_id = ' . $question_id; + $result = $db->sql_query($sql); + $question = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if (!$question) + { + return false; + } + + $question['answers'] = array(); + + $sql = 'SELECT * + FROM ' . CAPTCHA_ANSWERS_TABLE . ' + WHERE question_id = ' . $question_id; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $question['answers'][] = $row['answer_text']; + } + $db->sql_freeresult($result); + + return $question; + } + } + + /** + * Grab a question from input and bring it into a format the editor understands + */ + function acp_get_question_input() + { + $question = array( + 'question_text' => request_var('question_text', '', true), + 'strict' => request_var('strict', false), + 'lang_iso' => request_var('lang_iso', ''), + 'answers' => explode("\n", request_var('answers', '', true)), + ); + + return $question; + } + + /** + * Update a question. + * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data + */ + function acp_update_question($data, $question_id) + { + global $db, $cache; + + // easier to delete all answers than to figure out which to update + $sql = 'DELETE FROM ' . CAPTCHA_ANSWERS_TABLE . " WHERE question_id = $question_id"; + $db->sql_query($sql); + + $langs = $this->get_languages(); + $question_ary = $data; + $question_ary['lang_id'] = $langs[$question_ary['lang_iso']]['id']; + unset($question_ary['answers']); + + $sql = 'UPDATE ' . CAPTCHA_QUESTIONS_TABLE . ' + SET ' . $db->sql_build_array('UPDATE', $question_ary) . " + WHERE question_id = $question_id"; + $db->sql_query($sql); + + $this->acp_insert_answers($data, $question_id); + + $cache->destroy('sql', CAPTCHA_QUESTIONS_TABLE); + } + + /** + * Insert a question. + * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data + */ + function acp_add_question($data) + { + global $db, $cache; + + $langs = $this->get_languages(); + $question_ary = $data; + + $question_ary['lang_id'] = $langs[$data['lang_iso']]['id']; + unset($question_ary['answers']); + + $sql = 'INSERT INTO ' . CAPTCHA_QUESTIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $question_ary); + $db->sql_query($sql); + + $question_id = $db->sql_nextid(); + + $this->acp_insert_answers($data, $question_id); + + $cache->destroy('sql', CAPTCHA_QUESTIONS_TABLE); + } + + /** + * Insert the answers. + * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data + */ + function acp_insert_answers($data, $question_id) + { + global $db, $cache; + + foreach ($data['answers'] as $answer) + { + $answer_ary = array( + 'question_id' => $question_id, + 'answer_text' => $answer, + ); + + $sql = 'INSERT INTO ' . CAPTCHA_ANSWERS_TABLE . ' ' . $db->sql_build_array('INSERT', $answer_ary); + $db->sql_query($sql); + } + + $cache->destroy('sql', CAPTCHA_ANSWERS_TABLE); + } + + /** + * Delete a question. + */ + function acp_delete_question($question_id) + { + global $db, $cache; + + $tables = array(CAPTCHA_QUESTIONS_TABLE, CAPTCHA_ANSWERS_TABLE); + + foreach ($tables as $table) + { + $sql = "DELETE FROM $table + WHERE question_id = $question_id"; + $db->sql_query($sql); + } + + $cache->destroy('sql', $tables); + } + + /** + * Check if the entered data can be inserted/used + * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data + */ + function validate_input($question_data) + { + $langs = $this->get_languages(); + + if (!isset($question_data['lang_iso']) || + !isset($question_data['question_text']) || + !isset($question_data['strict']) || + !isset($question_data['answers'])) + { + return false; + } + + if (!isset($langs[$question_data['lang_iso']]) || + !$question_data['question_text'] || + !sizeof($question_data['answers'])) + { + return false; + } + + return true; + } + + /** + * List the installed language packs + */ + function get_languages() + { + global $db; + + $sql = 'SELECT * + FROM ' . LANG_TABLE; + $result = $db->sql_query($sql); + + $langs = array(); + while ($row = $db->sql_fetchrow($result)) + { + $langs[$row['lang_iso']] = array( + 'name' => $row['lang_local_name'], + 'id' => (int) $row['lang_id'], + ); + } + $db->sql_freeresult($result); + + return $langs; + } +} + +?> \ No newline at end of file -- cgit v1.2.1 From b68de2323d6444b4b3685a98bbcb9500a38e45cb Mon Sep 17 00:00:00 2001 From: Meik Sievertsen Date: Wed, 16 Dec 2009 15:48:23 +0000 Subject: merge changes from 3.0.x branch git-svn-id: file:///svn/phpbb/trunk@10342 89ea8834-ac86-4346-8a33-228a782c2dd0 --- phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php') diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php index c17cfa7bbe..45811c5d26 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -53,7 +53,7 @@ class phpbb_captcha_qa // read input $this->confirm_id = request_var('qa_confirm_id', ''); - $this->answer = request_var('qa_answer', '', true); + $this->answer = utf8_normalize_nfc(request_var('qa_answer', '', true)); $this->type = (int) $type; $this->question_lang = $user->lang_name; @@ -502,7 +502,7 @@ class phpbb_captcha_qa { global $db; - $answer = ($this->question_strict) ? request_var('qa_answer', '', true) : utf8_clean_string(request_var('qa_answer', '', true)); + $answer = ($this->question_strict) ? utf8_normalize_nfc(request_var('qa_answer', '', true)) : utf8_clean_string(utf8_normalize_nfc(request_var('qa_answer', '', true))); $sql = 'SELECT answer_text FROM ' . CAPTCHA_ANSWERS_TABLE . ' @@ -789,11 +789,12 @@ class phpbb_captcha_qa */ function acp_get_question_input() { + $answers = utf8_normalize_nfc(request_var('answers', '', true)); $question = array( 'question_text' => request_var('question_text', '', true), 'strict' => request_var('strict', false), 'lang_iso' => request_var('lang_iso', ''), - 'answers' => explode("\n", request_var('answers', '', true)), + 'answers' => (strlen($answers)) ? explode("\n", $answers) : '', ); return $question; @@ -908,8 +909,9 @@ class phpbb_captcha_qa } if (!isset($langs[$question_data['lang_iso']]) || - !$question_data['question_text'] || - !sizeof($question_data['answers'])) + !strlen($question_data['question_text']) || + !sizeof($question_data['answers']) || + !is_array($question_data['answers'])) { return false; } -- cgit v1.2.1 From dea1d660fb63b07451f1a43310de359251462644 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Fri, 25 Jun 2010 14:38:53 +0200 Subject: [feature/auto-loading] Added autoloader to common and ensured compatability The autoloader is registered in install without caching, since caching is set up during installation. This provides the same functionality, performance is not a concern during installation anyway. In common.php the autoloader is instantiated after the cache is initialised and is started with the standard cache backend used for other cached values. A few places in the code using class_exists had to be updated to explicitly avoid autoloading, since they are used to check whether a file needs to be included which does not (yet) follow the naming scheme the autoloader follows. PHPBB3-9682 --- .../captcha/plugins/phpbb_captcha_qa_plugin.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php') diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php index 49a64b9339..c0cdc83fa1 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -87,7 +87,7 @@ class phpbb_captcha_qa } $db->sql_freeresult($result); } - + // okay, if there is a confirm_id, we try to load that confirm's state. If not, we try to find one if (!$this->load_answer() && (!$this->load_confirm_id() || !$this->load_answer())) { @@ -113,7 +113,7 @@ class phpbb_captcha_qa { global $db, $phpbb_root_path, $phpEx; - if (!class_exists('phpbb_db_tools')) + if (!class_exists('phpbb_db_tools', false)) { include("$phpbb_root_path/includes/db/db_tools.$phpEx"); } @@ -365,12 +365,12 @@ class phpbb_captcha_qa global $config, $db, $user; $error = ''; - + if (!sizeof($this->question_ids)) { return false; } - + if (!$this->confirm_id) { $error = $user->lang['CONFIRM_QUESTION_WRONG']; @@ -434,7 +434,7 @@ class phpbb_captcha_qa function reselect_question() { global $db, $user; - + if (!sizeof($this->question_ids)) { return false; @@ -482,8 +482,8 @@ class phpbb_captcha_qa global $db, $user; $sql = 'SELECT confirm_id - FROM ' . CAPTCHA_QA_CONFIRM_TABLE . " - WHERE + FROM ' . CAPTCHA_QA_CONFIRM_TABLE . " + WHERE session_id = '" . $db->sql_escape($user->session_id) . "' AND lang_iso = '" . $db->sql_escape($this->question_lang) . "' AND confirm_type = " . $this->type; @@ -505,7 +505,7 @@ class phpbb_captcha_qa function load_answer() { global $db, $user; - + if (!strlen($this->confirm_id) || !sizeof($this->question_ids)) { return false; @@ -990,9 +990,9 @@ class phpbb_captcha_qa return $langs; } - - - + + + /** * See if there is a question other than the one we have */ -- cgit v1.2.1 From af5b9a96409d788733fcb1ff367e0c7fb0583702 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Tue, 9 Nov 2010 08:59:25 +0100 Subject: [ticket/9556] Drop php closing tags, add trailing newline Closing tags converted using Oleg's script. remove-php-end-tags.py -a . Trailing newlines added using the following where $ext is file extension. find . -type f -name "*.$ext" -print | xargs printf "e %s\nw\n" | ed -s; Extensions: php, css, html, js, xml. PHPBB3-9556 --- phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php | 2 -- 1 file changed, 2 deletions(-) (limited to 'phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php') diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php index c0cdc83fa1..14dce3cbe3 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -1018,5 +1018,3 @@ class phpbb_captcha_qa } } } - -?> \ No newline at end of file -- cgit v1.2.1 From f0facd4c9df3a9f100ef8ae021485a203f86f774 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Tue, 1 Mar 2011 23:21:48 +0100 Subject: [ticket/9766] Delete delete_code() from CAPTCHA classes as it's never called. Delete phpbb_default_captcha:delete_code() and phpbb_captcha_qa::delete_code() methods. We never call it and it has a bogus body. PHPBB3-9766 --- .../includes/captcha/plugins/phpbb_captcha_qa_plugin.php | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php') diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php index 14dce3cbe3..75fef25a9f 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -379,7 +379,6 @@ class phpbb_captcha_qa { if ($this->check_answer()) { - // $this->delete_code(); commented out to allow posting.php to repeat the question $this->solved = true; } else @@ -566,20 +565,6 @@ class phpbb_captcha_qa return $this->solved; } - /** - * API function - clean the entry - */ - function delete_code() - { - global $db, $user; - - $sql = 'DELETE FROM ' . CAPTCHA_QA_CONFIRM_TABLE . " - WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . $this->type; - $db->sql_query($sql); - } - /** * API function */ -- cgit v1.2.1 From 4bdad7125a34e121f7857c34480d0527c1925384 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Wed, 13 Jul 2011 11:32:38 +0200 Subject: [ticket/9608] Remove use of references in captcha and other places References are not really needed in PHP due to copy-on-write. Since PHP5, objects are always passed around as identifiers, which means they are mutable. So it is no longer required to pass these by reference either. PHPBB3-9608 --- phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php') diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php index 3bc727da41..272c0cd4d2 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -99,9 +99,9 @@ class phpbb_captcha_qa /** * API function */ - function &get_instance() + function get_instance() { - $instance =& new phpbb_captcha_qa(); + $instance = new phpbb_captcha_qa(); return $instance; } -- cgit v1.2.1 From 7a04c9048c110f0bd21ea3e9e869e17b408d640e Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 31 Dec 2011 13:32:52 +0000 Subject: [ticket/9916] Updating header license and removing Version $Id$ PHPBB3-9916 --- phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php') diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php index 272c0cd4d2..e12ad00d25 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -2,9 +2,8 @@ /** * * @package VC -* @version $Id$ * @copyright (c) 2006, 2008 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 * */ -- cgit v1.2.1 From c8da69d9c26e0017f13abb2c954e52c4cd593fdc Mon Sep 17 00:00:00 2001 From: Bruno Ais Date: Thu, 5 Apr 2012 14:14:40 +0100 Subject: [ticket/10575] Fixing non-static access to static functions get_instance These changes should solve the strict standards error about accessing the non-static get_instance() in a non-static way. For that, I changed the get_instance methods to static methods. PHPBB3-10575 --- phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php') diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php index e12ad00d25..412b332c3a 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -98,7 +98,7 @@ class phpbb_captcha_qa /** * API function */ - function get_instance() + static function get_instance() { $instance = new phpbb_captcha_qa(); -- cgit v1.2.1 From 2bf1c4eb32f1e668a215f1dabb42fe88e8a9cd11 Mon Sep 17 00:00:00 2001 From: Bruno Ais Date: Thu, 5 Apr 2012 14:16:56 +0100 Subject: [ticket/10575] Adding public visibility to the methods. Added public visibility to the methods PHPBB3-10575 --- phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php') diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php index 412b332c3a..99813189d7 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -98,7 +98,7 @@ class phpbb_captcha_qa /** * API function */ - static function get_instance() + public static function get_instance() { $instance = new phpbb_captcha_qa(); -- cgit v1.2.1 From 14a6e5ec73779d18cc6f09cb3b1cb4fd08f024f8 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Mon, 29 Oct 2012 09:34:51 -0400 Subject: [ticket/11157] Fix remaining captcha spam. PHPBB3-11157 --- phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php') diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php index 99813189d7..c005d478a2 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -108,7 +108,7 @@ class phpbb_captcha_qa /** * See if the captcha has created its tables. */ - function is_installed() + public static function is_installed() { global $db, $phpbb_root_path, $phpEx; @@ -124,14 +124,14 @@ class phpbb_captcha_qa /** * API function - for the captcha to be available, it must have installed itself and there has to be at least one question in the board's default lang */ - function is_available() + public static function is_available() { global $config, $db, $phpbb_root_path, $phpEx, $user; // load language file for pretty display in the ACP dropdown $user->add_lang('captcha_qa'); - if (!phpbb_captcha_qa::is_installed()) + if (!self::is_installed()) { return false; } @@ -157,7 +157,7 @@ class phpbb_captcha_qa /** * API function */ - function get_name() + public static function get_name() { return 'CAPTCHA_QA'; } @@ -612,7 +612,7 @@ class phpbb_captcha_qa $user->add_lang('acp/board'); $user->add_lang('captcha_qa'); - if (!$this->is_installed()) + if (!self::is_installed()) { $this->install(); } -- cgit v1.2.1 From d602f13d7f6ba7ee67a5286befd8afd9f8f0cd15 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Mon, 29 Oct 2012 14:54:54 -0400 Subject: [ticket/11157] static public is the currently approved order. PHPBB3-11157 --- phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php') diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php index c005d478a2..0eae643d33 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -108,7 +108,7 @@ class phpbb_captcha_qa /** * See if the captcha has created its tables. */ - public static function is_installed() + static public function is_installed() { global $db, $phpbb_root_path, $phpEx; @@ -124,7 +124,7 @@ class phpbb_captcha_qa /** * API function - for the captcha to be available, it must have installed itself and there has to be at least one question in the board's default lang */ - public static function is_available() + static public function is_available() { global $config, $db, $phpbb_root_path, $phpEx, $user; @@ -157,7 +157,7 @@ class phpbb_captcha_qa /** * API function */ - public static function get_name() + static public function get_name() { return 'CAPTCHA_QA'; } -- cgit v1.2.1 From 31781adf0ca9880069c8831177b34d573456f5d4 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Mon, 29 Oct 2012 14:57:27 -0400 Subject: [ticket/11159] static public is the currently approved order. PHPBB3-11159 --- phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php') diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php index 99813189d7..8fc45db8cb 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -98,7 +98,7 @@ class phpbb_captcha_qa /** * API function */ - public static function get_instance() + static public function get_instance() { $instance = new phpbb_captcha_qa(); -- cgit v1.2.1 From 057d860d07fe829104aa938338830787415bc1c6 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Sun, 14 Jul 2013 00:56:37 -0400 Subject: [ticket/11696] Rename db_tools.php so it can be autoloaded PHPBB3-11696 --- phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php') diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php index ec7636f511..6843f25d72 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -110,12 +110,8 @@ class phpbb_captcha_qa */ static public function is_installed() { - global $db, $phpbb_root_path, $phpEx; + global $db; - if (!class_exists('phpbb_db_tools', false)) - { - include("$phpbb_root_path/includes/db/db_tools.$phpEx"); - } $db_tool = new phpbb_db_tools($db); return $db_tool->sql_table_exists(CAPTCHA_QUESTIONS_TABLE); @@ -297,12 +293,8 @@ class phpbb_captcha_qa */ function install() { - global $db, $phpbb_root_path, $phpEx; + global $db; - if (!class_exists('phpbb_db_tools')) - { - include("$phpbb_root_path/includes/db/db_tools.$phpEx"); - } $db_tool = new phpbb_db_tools($db); $tables = array(CAPTCHA_QUESTIONS_TABLE, CAPTCHA_ANSWERS_TABLE, CAPTCHA_QA_CONFIRM_TABLE); -- cgit v1.2.1 From b95fdacdd378877d277e261465da73deb06e50da Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Tue, 10 Sep 2013 14:01:09 +0200 Subject: [ticket/11700] Move all recent code to namespaces PHPBB3-11700 --- phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php') diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php index 6843f25d72..82333f739e 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -112,7 +112,7 @@ class phpbb_captcha_qa { global $db; - $db_tool = new phpbb_db_tools($db); + $db_tool = new \phpbb\db\tools($db); return $db_tool->sql_table_exists(CAPTCHA_QUESTIONS_TABLE); } @@ -295,7 +295,7 @@ class phpbb_captcha_qa { global $db; - $db_tool = new phpbb_db_tools($db); + $db_tool = new \phpbb\db\tools($db); $tables = array(CAPTCHA_QUESTIONS_TABLE, CAPTCHA_ANSWERS_TABLE, CAPTCHA_QA_CONFIRM_TABLE); -- cgit v1.2.1 From a759704b39fc1c1353f865a633759b1369589b67 Mon Sep 17 00:00:00 2001 From: Yuriy Rusko Date: Tue, 27 May 2014 20:18:06 +0200 Subject: [ticket/12594] Remove @package tags and update file headers PHPBB3-12594 --- phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php') diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php index 82333f739e..5a44755365 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -1,9 +1,13 @@ +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. * */ @@ -24,8 +28,6 @@ define('CAPTCHA_QA_CONFIRM_TABLE', $table_prefix . 'qa_confirm'); /** * And now to something completely different. Let's make a captcha without extending the abstract class. * QA CAPTCHA sample implementation -* -* @package VC */ class phpbb_captcha_qa { -- cgit v1.2.1 From 160ff7b912243dc14d871b820213ddcd20dd06f4 Mon Sep 17 00:00:00 2001 From: Tristan Darricau Date: Fri, 8 Aug 2014 18:02:03 +0200 Subject: [ticket/11854] Move captcha stuff to phpbb/ and use DI for plugins PHPBB3-11854 --- .../captcha/plugins/phpbb_captcha_qa_plugin.php | 998 --------------------- 1 file changed, 998 deletions(-) delete mode 100644 phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php (limited to 'phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php') diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php deleted file mode 100644 index 5a44755365..0000000000 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ /dev/null @@ -1,998 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -global $table_prefix; - -define('CAPTCHA_QUESTIONS_TABLE', $table_prefix . 'captcha_questions'); -define('CAPTCHA_ANSWERS_TABLE', $table_prefix . 'captcha_answers'); -define('CAPTCHA_QA_CONFIRM_TABLE', $table_prefix . 'qa_confirm'); - -/** -* And now to something completely different. Let's make a captcha without extending the abstract class. -* QA CAPTCHA sample implementation -*/ -class phpbb_captcha_qa -{ - var $confirm_id; - var $answer; - var $question_ids; - var $question_text; - var $question_lang; - var $question_strict; - var $attempts = 0; - var $type; - // dirty trick: 0 is false, but can still encode that the captcha is not yet validated - var $solved = 0; - - /** - * @param int $type as per the CAPTCHA API docs, the type - */ - function init($type) - { - global $config, $db, $user; - - // load our language file - $user->add_lang('captcha_qa'); - - // read input - $this->confirm_id = request_var('qa_confirm_id', ''); - $this->answer = utf8_normalize_nfc(request_var('qa_answer', '', true)); - - $this->type = (int) $type; - $this->question_lang = $user->lang_name; - - // we need all defined questions - shouldn't be too many, so we can just grab them - // try the user's lang first - $sql = 'SELECT question_id - FROM ' . CAPTCHA_QUESTIONS_TABLE . " - WHERE lang_iso = '" . $db->sql_escape($user->lang_name) . "'"; - $result = $db->sql_query($sql, 3600); - - while ($row = $db->sql_fetchrow($result)) - { - $this->question_ids[$row['question_id']] = $row['question_id']; - } - $db->sql_freeresult($result); - - // fallback to the board default lang - if (!sizeof($this->question_ids)) - { - $this->question_lang = $config['default_lang']; - - $sql = 'SELECT question_id - FROM ' . CAPTCHA_QUESTIONS_TABLE . " - WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; - $result = $db->sql_query($sql, 7200); - - while ($row = $db->sql_fetchrow($result)) - { - $this->question_ids[$row['question_id']] = $row['question_id']; - } - $db->sql_freeresult($result); - } - - // okay, if there is a confirm_id, we try to load that confirm's state. If not, we try to find one - if (!$this->load_answer() && (!$this->load_confirm_id() || !$this->load_answer())) - { - // we have no valid confirm ID, better get ready to ask something - $this->select_question(); - } - } - - /** - * API function - */ - static public function get_instance() - { - $instance = new phpbb_captcha_qa(); - - return $instance; - } - - /** - * See if the captcha has created its tables. - */ - static public function is_installed() - { - global $db; - - $db_tool = new \phpbb\db\tools($db); - - return $db_tool->sql_table_exists(CAPTCHA_QUESTIONS_TABLE); - } - - /** - * API function - for the captcha to be available, it must have installed itself and there has to be at least one question in the board's default lang - */ - static public function is_available() - { - global $config, $db, $phpbb_root_path, $phpEx, $user; - - // load language file for pretty display in the ACP dropdown - $user->add_lang('captcha_qa'); - - if (!self::is_installed()) - { - return false; - } - - $sql = 'SELECT COUNT(question_id) AS question_count - FROM ' . CAPTCHA_QUESTIONS_TABLE . " - WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - return ((bool) $row['question_count']); - } - - /** - * API function - */ - function has_config() - { - return true; - } - - /** - * API function - */ - static public function get_name() - { - return 'CAPTCHA_QA'; - } - - /** - * API function - */ - function get_class_name() - { - return 'phpbb_captcha_qa'; - } - - /** - * API function - not needed as we don't display an image - */ - function execute_demo() - { - } - - /** - * API function - not needed as we don't display an image - */ - function execute() - { - } - - /** - * API function - send the question to the template - */ - function get_template() - { - global $template; - - if ($this->is_solved()) - { - return false; - } - else - { - $template->assign_vars(array( - 'QA_CONFIRM_QUESTION' => $this->question_text, - 'QA_CONFIRM_ID' => $this->confirm_id, - 'S_CONFIRM_CODE' => true, - 'S_TYPE' => $this->type, - )); - - return 'captcha_qa.html'; - } - } - - /** - * API function - we just display a mockup so that the captcha doesn't need to be installed - */ - function get_demo_template() - { - global $config, $db, $template; - - if ($this->is_available()) - { - $sql = 'SELECT question_text - FROM ' . CAPTCHA_QUESTIONS_TABLE . " - WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; - $result = $db->sql_query_limit($sql, 1); - if ($row = $db->sql_fetchrow($result)) - { - $template->assign_vars(array( - 'QA_CONFIRM_QUESTION' => $row['question_text'], - )); - } - $db->sql_freeresult($result); - } - return 'captcha_qa_acp_demo.html'; - } - - /** - * API function - */ - function get_hidden_fields() - { - $hidden_fields = array(); - - // this is required - otherwise we would forget about the captcha being already solved - if ($this->solved) - { - $hidden_fields['qa_answer'] = $this->answer; - } - $hidden_fields['qa_confirm_id'] = $this->confirm_id; - - return $hidden_fields; - } - - /** - * API function - */ - function garbage_collect($type = 0) - { - global $db, $config; - - $sql = 'SELECT c.confirm_id - FROM ' . CAPTCHA_QA_CONFIRM_TABLE . ' c - LEFT JOIN ' . SESSIONS_TABLE . ' s - ON (c.session_id = s.session_id) - WHERE s.session_id IS NULL' . - ((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type); - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $sql_in = array(); - - do - { - $sql_in[] = (string) $row['confirm_id']; - } - while ($row = $db->sql_fetchrow($result)); - - if (sizeof($sql_in)) - { - $sql = 'DELETE FROM ' . CAPTCHA_QA_CONFIRM_TABLE . ' - WHERE ' . $db->sql_in_set('confirm_id', $sql_in); - $db->sql_query($sql); - } - } - $db->sql_freeresult($result); - } - - /** - * API function - we don't drop the tables here, as that would cause the loss of all entered questions. - */ - function uninstall() - { - $this->garbage_collect(0); - } - - /** - * API function - set up shop - */ - function install() - { - global $db; - - $db_tool = new \phpbb\db\tools($db); - - $tables = array(CAPTCHA_QUESTIONS_TABLE, CAPTCHA_ANSWERS_TABLE, CAPTCHA_QA_CONFIRM_TABLE); - - $schemas = array( - CAPTCHA_QUESTIONS_TABLE => array ( - 'COLUMNS' => array( - 'question_id' => array('UINT', Null, 'auto_increment'), - 'strict' => array('BOOL', 0), - 'lang_id' => array('UINT', 0), - 'lang_iso' => array('VCHAR:30', ''), - 'question_text' => array('TEXT_UNI', ''), - ), - 'PRIMARY_KEY' => 'question_id', - 'KEYS' => array( - 'lang' => array('INDEX', 'lang_iso'), - ), - ), - CAPTCHA_ANSWERS_TABLE => array ( - 'COLUMNS' => array( - 'question_id' => array('UINT', 0), - 'answer_text' => array('STEXT_UNI', ''), - ), - 'KEYS' => array( - 'qid' => array('INDEX', 'question_id'), - ), - ), - CAPTCHA_QA_CONFIRM_TABLE => array ( - 'COLUMNS' => array( - 'session_id' => array('CHAR:32', ''), - 'confirm_id' => array('CHAR:32', ''), - 'lang_iso' => array('VCHAR:30', ''), - 'question_id' => array('UINT', 0), - 'attempts' => array('UINT', 0), - 'confirm_type' => array('USINT', 0), - ), - 'KEYS' => array( - 'session_id' => array('INDEX', 'session_id'), - 'lookup' => array('INDEX', array('confirm_id', 'session_id', 'lang_iso')), - ), - 'PRIMARY_KEY' => 'confirm_id', - ), - ); - - foreach($schemas as $table => $schema) - { - if (!$db_tool->sql_table_exists($table)) - { - $db_tool->sql_create_table($table, $schema); - } - } - } - - /** - * API function - see what has to be done to validate - */ - function validate() - { - global $config, $db, $user; - - $error = ''; - - if (!sizeof($this->question_ids)) - { - return false; - } - - if (!$this->confirm_id) - { - $error = $user->lang['CONFIRM_QUESTION_WRONG']; - } - else - { - if ($this->check_answer()) - { - $this->solved = true; - } - else - { - $error = $user->lang['CONFIRM_QUESTION_WRONG']; - } - } - - if (strlen($error)) - { - // okay, incorrect answer. Let's ask a new question. - $this->new_attempt(); - $this->solved = false; - - return $error; - } - else - { - return false; - } - } - - /** - * Select a question - */ - function select_question() - { - global $db, $user; - - if (!sizeof($this->question_ids)) - { - return false; - } - $this->confirm_id = md5(unique_id($user->ip)); - $this->question = (int) array_rand($this->question_ids); - - $sql = 'INSERT INTO ' . CAPTCHA_QA_CONFIRM_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'confirm_id' => (string) $this->confirm_id, - 'session_id' => (string) $user->session_id, - 'lang_iso' => (string) $this->question_lang, - 'confirm_type' => (int) $this->type, - 'question_id' => (int) $this->question, - )); - $db->sql_query($sql); - - $this->load_answer(); - } - - /** - * New Question, if desired. - */ - function reselect_question() - { - global $db, $user; - - if (!sizeof($this->question_ids)) - { - return false; - } - - $this->question = (int) array_rand($this->question_ids); - $this->solved = 0; - - $sql = 'UPDATE ' . CAPTCHA_QA_CONFIRM_TABLE . ' - SET question_id = ' . (int) $this->question . " - WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "'"; - $db->sql_query($sql); - - $this->load_answer(); - } - - /** - * Wrong answer, so we increase the attempts and use a different question. - */ - function new_attempt() - { - global $db, $user; - - // yah, I would prefer a stronger rand, but this should work - $this->question = (int) array_rand($this->question_ids); - $this->solved = 0; - - $sql = 'UPDATE ' . CAPTCHA_QA_CONFIRM_TABLE . ' - SET question_id = ' . (int) $this->question . ", - attempts = attempts + 1 - WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "'"; - $db->sql_query($sql); - - $this->load_answer(); - } - - - /** - * See if there is already an entry for the current session. - */ - function load_confirm_id() - { - global $db, $user; - - $sql = 'SELECT confirm_id - FROM ' . CAPTCHA_QA_CONFIRM_TABLE . " - WHERE - session_id = '" . $db->sql_escape($user->session_id) . "' - AND lang_iso = '" . $db->sql_escape($this->question_lang) . "' - AND confirm_type = " . $this->type; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $this->confirm_id = $row['confirm_id']; - return true; - } - return false; - } - - /** - * Look up everything we need and populate the instance variables. - */ - function load_answer() - { - global $db, $user; - - if (!strlen($this->confirm_id) || !sizeof($this->question_ids)) - { - return false; - } - - $sql = 'SELECT con.question_id, attempts, question_text, strict - FROM ' . CAPTCHA_QA_CONFIRM_TABLE . ' con, ' . CAPTCHA_QUESTIONS_TABLE . " qes - WHERE con.question_id = qes.question_id - AND confirm_id = '" . $db->sql_escape($this->confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND qes.lang_iso = '" . $db->sql_escape($this->question_lang) . "' - AND confirm_type = " . $this->type; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $this->question = $row['question_id']; - - $this->attempts = $row['attempts']; - $this->question_strict = $row['strict']; - $this->question_text = $row['question_text']; - - return true; - } - - return false; - } - - /** - * The actual validation - */ - function check_answer() - { - global $db; - - $answer = ($this->question_strict) ? utf8_normalize_nfc(request_var('qa_answer', '', true)) : utf8_clean_string(utf8_normalize_nfc(request_var('qa_answer', '', true))); - - $sql = 'SELECT answer_text - FROM ' . CAPTCHA_ANSWERS_TABLE . ' - WHERE question_id = ' . (int) $this->question; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $solution = ($this->question_strict) ? $row['answer_text'] : utf8_clean_string($row['answer_text']); - - if ($solution === $answer) - { - $this->solved = true; - - break; - } - } - $db->sql_freeresult($result); - - return $this->solved; - } - - /** - * API function - */ - function get_attempt_count() - { - return $this->attempts; - } - - /** - * API function - */ - function reset() - { - global $db, $user; - - $sql = 'DELETE FROM ' . CAPTCHA_QA_CONFIRM_TABLE . " - WHERE session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . (int) $this->type; - $db->sql_query($sql); - - // we leave the class usable by generating a new question - $this->select_question(); - } - - /** - * API function - */ - function is_solved() - { - if (request_var('qa_answer', false) && $this->solved === 0) - { - $this->validate(); - } - - return (bool) $this->solved; - } - - /** - * API function - The ACP backend, this marks the end of the easy methods - */ - function acp_page($id, &$module) - { - global $db, $user, $auth, $template; - global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; - - $user->add_lang('acp/board'); - $user->add_lang('captcha_qa'); - - if (!self::is_installed()) - { - $this->install(); - } - - $module->tpl_name = 'captcha_qa_acp'; - $module->page_title = 'ACP_VC_SETTINGS'; - $form_key = 'acp_captcha'; - add_form_key($form_key); - - $submit = request_var('submit', false); - $question_id = request_var('question_id', 0); - $action = request_var('action', ''); - - // we have two pages, so users might want to navigate from one to the other - $list_url = $module->u_action . "&configure=1&select_captcha=" . $this->get_class_name(); - - $template->assign_vars(array( - 'U_ACTION' => $module->u_action, - 'QUESTION_ID' => $question_id , - 'CLASS' => $this->get_class_name(), - )); - - // show the list? - if (!$question_id && $action != 'add') - { - $this->acp_question_list($module); - } - else if ($question_id && $action == 'delete') - { - if ($this->get_class_name() !== $config['captcha_plugin'] || !$this->acp_is_last($question_id)) - { - if (confirm_box(true)) - { - $this->acp_delete_question($question_id); - - trigger_error($user->lang['QUESTION_DELETED'] . adm_back_link($list_url)); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'question_id' => $question_id, - 'action' => $action, - 'configure' => 1, - 'select_captcha' => $this->get_class_name(), - )) - ); - } - } - else - { - trigger_error($user->lang['QA_LAST_QUESTION'] . adm_back_link($list_url), E_USER_WARNING); - } - } - else - { - // okay, show the editor - $error = false; - $input_question = request_var('question_text', '', true); - $input_answers = request_var('answers', '', true); - $input_lang = request_var('lang_iso', '', true); - $input_strict = request_var('strict', false); - $langs = $this->get_languages(); - - foreach ($langs as $lang => $entry) - { - $template->assign_block_vars('langs', array( - 'ISO' => $lang, - 'NAME' => $entry['name'], - )); - } - - $template->assign_vars(array( - 'U_LIST' => $list_url, - )); - - if ($question_id) - { - if ($question = $this->acp_get_question_data($question_id)) - { - $answers = (isset($input_answers[$lang])) ? $input_answers[$lang] : implode("\n", $question['answers']); - - $template->assign_vars(array( - 'QUESTION_TEXT' => ($input_question) ? $input_question : $question['question_text'], - 'LANG_ISO' => ($input_lang) ? $input_lang : $question['lang_iso'], - 'STRICT' => (isset($_REQUEST['strict'])) ? $input_strict : $question['strict'], - 'ANSWERS' => $answers, - )); - } - else - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url)); - } - } - else - { - $template->assign_vars(array( - 'QUESTION_TEXT' => $input_question, - 'LANG_ISO' => $input_lang, - 'STRICT' => $input_strict, - 'ANSWERS' => $input_answers, - )); - } - - if ($submit && check_form_key($form_key)) - { - $data = $this->acp_get_question_input(); - - if (!$this->validate_input($data)) - { - $template->assign_vars(array( - 'S_ERROR' => true, - )); - } - else - { - if ($question_id) - { - $this->acp_update_question($data, $question_id); - } - else - { - $this->acp_add_question($data); - } - - add_log('admin', 'LOG_CONFIG_VISUAL'); - trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($list_url)); - } - } - else if ($submit) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url), E_USER_WARNING); - } - } - } - - /** - * This handles the list overview - */ - function acp_question_list(&$module) - { - global $db, $template; - - $sql = 'SELECT * - FROM ' . CAPTCHA_QUESTIONS_TABLE; - $result = $db->sql_query($sql); - - $template->assign_vars(array( - 'S_LIST' => true, - )); - - while ($row = $db->sql_fetchrow($result)) - { - $url = $module->u_action . "&question_id={$row['question_id']}&configure=1&select_captcha=" . $this->get_class_name() . '&'; - - $template->assign_block_vars('questions', array( - 'QUESTION_TEXT' => $row['question_text'], - 'QUESTION_ID' => $row['question_id'], - 'QUESTION_LANG' => $row['lang_iso'], - 'U_DELETE' => "{$url}action=delete", - 'U_EDIT' => "{$url}action=edit", - )); - } - $db->sql_freeresult($result); - } - - /** - * Grab a question and bring it into a format the editor understands - */ - function acp_get_question_data($question_id) - { - global $db; - - if ($question_id) - { - $sql = 'SELECT * - FROM ' . CAPTCHA_QUESTIONS_TABLE . ' - WHERE question_id = ' . $question_id; - $result = $db->sql_query($sql); - $question = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$question) - { - return false; - } - - $question['answers'] = array(); - - $sql = 'SELECT * - FROM ' . CAPTCHA_ANSWERS_TABLE . ' - WHERE question_id = ' . $question_id; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $question['answers'][] = $row['answer_text']; - } - $db->sql_freeresult($result); - - return $question; - } - } - - /** - * Grab a question from input and bring it into a format the editor understands - */ - function acp_get_question_input() - { - $answers = utf8_normalize_nfc(request_var('answers', '', true)); - $question = array( - 'question_text' => request_var('question_text', '', true), - 'strict' => request_var('strict', false), - 'lang_iso' => request_var('lang_iso', ''), - 'answers' => (strlen($answers)) ? explode("\n", $answers) : '', - ); - - return $question; - } - - /** - * Update a question. - * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data - */ - function acp_update_question($data, $question_id) - { - global $db, $cache; - - // easier to delete all answers than to figure out which to update - $sql = 'DELETE FROM ' . CAPTCHA_ANSWERS_TABLE . " WHERE question_id = $question_id"; - $db->sql_query($sql); - - $langs = $this->get_languages(); - $question_ary = $data; - $question_ary['lang_id'] = $langs[$question_ary['lang_iso']]['id']; - unset($question_ary['answers']); - - $sql = 'UPDATE ' . CAPTCHA_QUESTIONS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $question_ary) . " - WHERE question_id = $question_id"; - $db->sql_query($sql); - - $this->acp_insert_answers($data, $question_id); - - $cache->destroy('sql', CAPTCHA_QUESTIONS_TABLE); - } - - /** - * Insert a question. - * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data - */ - function acp_add_question($data) - { - global $db, $cache; - - $langs = $this->get_languages(); - $question_ary = $data; - - $question_ary['lang_id'] = $langs[$data['lang_iso']]['id']; - unset($question_ary['answers']); - - $sql = 'INSERT INTO ' . CAPTCHA_QUESTIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $question_ary); - $db->sql_query($sql); - - $question_id = $db->sql_nextid(); - - $this->acp_insert_answers($data, $question_id); - - $cache->destroy('sql', CAPTCHA_QUESTIONS_TABLE); - } - - /** - * Insert the answers. - * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data - */ - function acp_insert_answers($data, $question_id) - { - global $db, $cache; - - foreach ($data['answers'] as $answer) - { - $answer_ary = array( - 'question_id' => $question_id, - 'answer_text' => $answer, - ); - - $sql = 'INSERT INTO ' . CAPTCHA_ANSWERS_TABLE . ' ' . $db->sql_build_array('INSERT', $answer_ary); - $db->sql_query($sql); - } - - $cache->destroy('sql', CAPTCHA_ANSWERS_TABLE); - } - - /** - * Delete a question. - */ - function acp_delete_question($question_id) - { - global $db, $cache; - - $tables = array(CAPTCHA_QUESTIONS_TABLE, CAPTCHA_ANSWERS_TABLE); - - foreach ($tables as $table) - { - $sql = "DELETE FROM $table - WHERE question_id = $question_id"; - $db->sql_query($sql); - } - - $cache->destroy('sql', $tables); - } - - /** - * Check if the entered data can be inserted/used - * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data - */ - function validate_input($question_data) - { - $langs = $this->get_languages(); - - if (!isset($question_data['lang_iso']) || - !isset($question_data['question_text']) || - !isset($question_data['strict']) || - !isset($question_data['answers'])) - { - return false; - } - - if (!isset($langs[$question_data['lang_iso']]) || - !strlen($question_data['question_text']) || - !sizeof($question_data['answers']) || - !is_array($question_data['answers'])) - { - return false; - } - - return true; - } - - /** - * List the installed language packs - */ - function get_languages() - { - global $db; - - $sql = 'SELECT * - FROM ' . LANG_TABLE; - $result = $db->sql_query($sql); - - $langs = array(); - while ($row = $db->sql_fetchrow($result)) - { - $langs[$row['lang_iso']] = array( - 'name' => $row['lang_local_name'], - 'id' => (int) $row['lang_id'], - ); - } - $db->sql_freeresult($result); - - return $langs; - } - - - - /** - * See if there is a question other than the one we have - */ - function acp_is_last($question_id) - { - global $config, $db; - - if ($question_id) - { - $sql = 'SELECT question_id - FROM ' . CAPTCHA_QUESTIONS_TABLE . " - WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "' - AND question_id <> " . (int) $question_id; - $result = $db->sql_query_limit($sql, 1); - $question = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$question) - { - return true; - } - return false; - } - } -} -- cgit v1.2.1