aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB
diff options
context:
space:
mode:
authorHenry Sudhof <kellanved@phpbb.com>2009-07-18 23:37:09 +0000
committerHenry Sudhof <kellanved@phpbb.com>2009-07-18 23:37:09 +0000
commitba0d8b5a55ae69e228f303c01ba0fe2f545489ee (patch)
tree035fcb195e2cc6dde8a1fd4d1834d149e44f82d3 /phpBB
parentd61afd3509de3823c4f405fc95f8f799f073c505 (diff)
downloadforums-ba0d8b5a55ae69e228f303c01ba0fe2f545489ee.tar
forums-ba0d8b5a55ae69e228f303c01ba0fe2f545489ee.tar.gz
forums-ba0d8b5a55ae69e228f303c01ba0fe2f545489ee.tar.bz2
forums-ba0d8b5a55ae69e228f303c01ba0fe2f545489ee.tar.xz
forums-ba0d8b5a55ae69e228f303c01ba0fe2f545489ee.zip
Initial commit for the QA captcha. Needs language & style finetuning and bug searching & fixing
git-svn-id: file:///svn/phpbb/branches/phpBB-3_0_0@9786 89ea8834-ac86-4346-8a33-228a782c2dd0
Diffstat (limited to 'phpBB')
-rwxr-xr-xphpBB/adm/style/captcha_qa_acp.html93
-rwxr-xr-xphpBB/adm/style/captcha_qa_acp_demo.html7
-rwxr-xr-xphpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php758
-rwxr-xr-xphpBB/language/en/captcha_qa.php61
-rwxr-xr-xphpBB/styles/prosilver/template/captcha_qa.html23
-rwxr-xr-xphpBB/styles/subsilver2/template/captcha_qa.html5
6 files changed, 947 insertions, 0 deletions
diff --git a/phpBB/adm/style/captcha_qa_acp.html b/phpBB/adm/style/captcha_qa_acp.html
new file mode 100755
index 0000000000..2ff35bcef1
--- /dev/null
+++ b/phpBB/adm/style/captcha_qa_acp.html
@@ -0,0 +1,93 @@
+<!-- INCLUDE overall_header.html -->
+
+<a name="maincontent"></a>
+
+
+
+ <a href="{U_BACK}" style="float: {S_CONTENT_FLOW_END};">&laquo; {L_BACK}</a>
+
+ <h1>{L_QUESTIONS}</h1>
+
+ <p>{L_QUESTIONS_EXPLAIN}</p>
+<!-- IF S_LIST -->
+ <form id="captcha_qa" method="post" action="{U_ACTION}">
+
+ <fieldset class="tabulated">
+ <legend>{L_QUESTIONS}</legend>
+
+ <table cellspacing="1">
+ <thead>
+ <tr>
+ <th colspan="3">{L_QUESTIONS}</th>
+ </tr>
+ <tr class="row3">
+ <td style="text-align: center;">{L_QUESTION_TEXT}</td>
+ <td style="text-align: center;">{L_QUESTION_LANG}</td>
+ <td style="text-align: center;">{L_ACTION}</td>
+ </tr>
+ </thead>
+ <tbody>
+ <!-- BEGIN questions -->
+
+ <!-- IF questions.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
+
+ <td style="text-align: center;">{questions.QUESTION_TEXT}</td>
+ <td style="text-align: center;">{questions.QUESTION_LANG}</td>
+ <td style="text-align: center;"><a href="{questions.U_EDIT}">{ICON_EDIT}</a><a href="{questions.U_DELETE}">{ICON_DELETE}</a></td>
+ </tr>
+ <!-- END questions -->
+ </tbody>
+ </table>
+ <fieldset class="quick">
+ <input class="button1" type="submit" name="add" value="{L_ADD}" />
+ <input type="hidden" name="action" value="add" />
+ <input type="hidden" name="configure" value="1" />
+ <input type="hidden" name="select_captcha" value="{CLASS}" />
+
+ {S_FORM_TOKEN}
+ </fieldset>
+ {S_FORM_TOKEN}
+ </fieldset>
+ </form>
+<!-- ELSE -->
+ <!-- IF S_ERROR -->
+ <div class="errorbox">
+ <h3>{L_WARNING}</h3>
+ <p>{QA_ERROR_MSG}</p>
+ </div>
+ <!-- ENDIF -->
+ <form id="captcha_qa" method="post" action="{U_ACTION}">
+ <fieldset>
+ <legend>{L_QUESTIONS}</legend>
+ <dl>
+ <dt><label for="strict">{L_QUESTION_STRICT}:</label><br /><span>{L_QUESTION_STRICT_EXPLAIN}</span></dt>
+ <dd><label><input type="radio" class="radio" name="strict" value="1"<!-- IF STRICT --> id="strict" checked="checked"<!-- ENDIF --> /> {L_YES}</label>
+ <label><input type="radio" class="radio" name="strict" value="0"<!-- IF not STRICT --> id="strict" checked="checked"<!-- ENDIF --> /> {L_NO}</label></dd>
+ </dl>
+
+ <dl>
+ <dt><label for="lang_iso">{L_QUESTION_LANG}</label><br /><span>{L_QUESTION_LANG_EXPLAIN}</span></dt>
+ <dd><select id="lang_iso" name="lang_iso"><!-- BEGIN langs --><option value="{langs.ISO}" <!-- IF langs.ISO == LANG_ISO --> selected="selected" <!-- ENDIF -->>{langs.NAME}</option><!-- END langs --></select></dd>
+ </dl>
+ <dl>
+ <dt><label for="question_text">{L_QUESTION_TEXT}</label><br /><span>{L_QUESTION_TEXT_EXPLAIN}</span></dt>
+ <dd><input id="question_text" name="question_text" type="text" value="{QUESTION_TEXT}" /></dd>
+ </dl>
+ <dl>
+ <dt><label for="answers">{L_QUESTION_ANSWERS}</label><br /><span>{L_ANSWERS_EXPLAIN}</span></dt>
+ <dd><textarea id="answers" name="answers">{ANSWERS}</textarea></dd>
+ </dl>
+ </fieldset>
+ <fieldset class="quick">
+ <input class="button1" type="submit" name="submit" value="{L_SUBMIT}" />
+ <input type="hidden" name="question_id" value="{QUESTION_ID}" />
+ <input type="hidden" name="action" value="add" />
+ <input type="hidden" name="configure" value="1" />
+ <input type="hidden" name="select_captcha" value="{CLASS}" />
+
+ {S_FORM_TOKEN}
+ </fieldset>
+ </form>
+<!-- ENDIF -->
+
+<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/adm/style/captcha_qa_acp_demo.html b/phpBB/adm/style/captcha_qa_acp_demo.html
new file mode 100755
index 0000000000..5c3f9c320e
--- /dev/null
+++ b/phpBB/adm/style/captcha_qa_acp_demo.html
@@ -0,0 +1,7 @@
+<dl>
+ <dt><label for="answer">{L_QUESTION}:</label><br /><span>{L_QUESTION_EXPLAIN}</span></dt>
+
+ <dd>
+ <input type="text" />
+ </dd>
+</dl>
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 100755
index 0000000000..fe8a14c70f
--- /dev/null
+++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php
@@ -0,0 +1,758 @@
+<?php
+/**
+*
+* @package VC
+* @version $Id: captcha_abstract.php 9709 2009-06-30 14:23:16Z Kellanved $
+* @copyright (c) 2006, 2008 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+global $table_prefix;
+define('QUESTIONS_TABLE', $table_prefix . 'captcha_questions');
+define('ANSWERS_TABLE', $table_prefix . 'captcha_answers');
+define('QA_CONFIRM_TABLE', $table_prefix . 'qa_confirm');
+
+
+
+/**
+* QA CAPTCHA sample implementation
+*
+* @package VC
+*/
+class phpbb_captcha_qa
+{
+ var $confirm_id;
+ var $confirm_code;
+ var $answer;
+ var $question_ids;
+ var $question_text;
+ var $question_lang;
+ var $question_strict;
+ var $attempts = 0;
+ var $type;
+ var $solved = 0;
+ var $captcha_vars = false;
+
+ function init($type)
+ {
+ global $config, $db, $user;
+
+ $user->add_lang('captcha_qa');
+ // read input
+ $this->confirm_id = request_var('confirm_id', '');
+ $this->answer = request_var('answer', '');
+
+ $this->type = (int) $type;
+ $this->question_lang = $user->data['user_lang'];
+
+ $sql = 'SELECT question_id FROM ' . QUESTIONS_TABLE . ' WHERE lang_iso = \'' . $db->sql_escape($user->data['user_lang']) . '\'';
+ $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);
+ if (!sizeof($this->question_ids))
+ {
+ $this->question_lang = $config['default_lang'];
+ $sql = 'SELECT question_id FROM ' . 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);
+ }
+
+ if (!strlen($this->confirm_id) || !$this->load_answer())
+ {
+ // we have no confirm ID, better get ready to display something
+ $this->select_question();
+ }
+ }
+
+
+ function &get_instance()
+ {
+ $instance =& new phpbb_captcha_qa();
+ return $instance;
+ }
+
+
+ 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);
+ if (!$db_tool->sql_table_exists(QUESTIONS_TABLE))
+ {
+ return false;
+ }
+ }
+
+ function is_available()
+ {
+ global $config, $db, $phpbb_root_path, $phpEx, $user;
+
+ $user->add_lang('captcha_qa');
+
+ if (self::is_installed())
+ {
+ return false;
+ }
+ $sql = 'SELECT COUNT(question_id) as count FROM ' . 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']);
+ }
+
+ function get_name()
+ {
+ return 'CAPTCHA_QA';
+ }
+
+ function get_class_name()
+ {
+ return 'phpbb_captcha_qa';
+ }
+
+
+ function execute_demo()
+ {
+ }
+
+ function execute()
+ {
+ }
+
+ function get_template()
+ {
+ global $config, $user, $template, $phpEx, $phpbb_root_path;
+
+ $template->assign_vars(array(
+ 'CONFIRM_QUESTION' => $this->question_text,
+ 'CONFIRM_ID' => $this->confirm_id,
+ 'S_CONFIRM_CODE' => true,
+ 'S_TYPE' => $this->type,
+ ));
+
+ return 'captcha_qa.html';
+ }
+
+ function get_demo_template($id)
+ {
+ return 'captcha_qa_acp_demo.html';
+ }
+
+ 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['answer'] = $this->answer;
+ }
+ $hidden_fields['confirm_id'] = $this->confirm_id;
+ return $hidden_fields;
+ }
+
+ function garbage_collect($type)
+ {
+ global $db, $config;
+
+ $sql = 'SELECT DISTINCT c.session_id
+ FROM ' . 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 ' . QA_CONFIRM_TABLE . '
+ WHERE ' . $db->sql_in_set('session_id', $sql_in);
+ $db->sql_query($sql);
+ }
+ }
+ $db->sql_freeresult($result);
+ }
+
+ function uninstall()
+ {
+ $this->garbage_collect(0);
+ }
+
+ 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(QUESTIONS_TABLE, ANSWERS_TABLE, QA_CONFIRM_TABLE);
+
+ $schemas = array(
+ 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', 0),
+ 'question_text' => array('TEXT', 0),
+ ),
+ 'PRIMARY_KEY' => 'question_id',
+ 'KEYS' => array(
+ 'question_id' => array('INDEX', array('question_id', 'language_iso')),
+ ),
+ ),
+ ANSWERS_TABLE => array (
+ 'COLUMNS' => array(
+ 'question_id' => array('UINT', 0),
+ 'answer_text' => array('TEXT', 0),
+ ),
+ 'KEYS' => array(
+ 'question_id' => array('INDEX', 'question_id'),
+ ),
+ ),
+ QA_CONFIRM_TABLE => array (
+ 'COLUMNS' => array(
+ 'session_id' => array('CHAR:32', ''),
+ 'confirm_id' => array('CHAR:32', ''),
+ 'lang_iso' => array('VCHAR:30', 0),
+ 'question_id' => array('UINT', 0),
+ 'attempts' => array('UINT', 0),
+ 'confirm_type' => array('USINT', 0),
+ ),
+ 'KEYS' => array(
+ 'confirm_id' => array('INDEX', 'confirm_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);
+ }
+ }
+ }
+
+
+ function validate()
+ {
+ global $config, $db, $user;
+
+ $error = '';
+ 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();
+ return $error;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Select a question
+ */
+ function select_question()
+ {
+ global $db, $user;
+
+ $this->confirm_id = md5(unique_id($user->ip));
+ $this->question = (int) array_rand($this->question_ids);
+
+ $sql = 'INSERT INTO ' . 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;
+
+ $this->question = (int) array_rand($this->question_ids);
+ $this->solved = 0;
+ // compute $seed % 0x7fffffff
+
+ $sql = 'UPDATE ' . QA_CONFIRM_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array(
+ 'question' => (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();
+ }
+
+ /**
+ * New Question, if desired.
+ */
+ function new_attempt()
+ {
+ global $db, $user;
+
+ $this->question = (int) array_rand($this->question_ids);
+ $this->solved = 0;
+ // compute $seed % 0x7fffffff
+
+ $sql = 'UPDATE ' . QA_CONFIRM_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array(
+ '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.
+ */
+ function load_answer()
+ {
+ global $db, $user;
+
+ $sql = 'SELECT con.question_id, attempts, question_text, strict
+ FROM ' . QA_CONFIRM_TABLE . ' con, ' . 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;
+ }
+
+ function check_answer()
+ {
+ global $db;
+
+ $answer = ($this->question_strict) ? request_var('answer', '') : utf8_clean_string(request_var('answer', ''));
+
+ $sql = 'SELECT answer_text
+ FROM ' . 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;
+ }
+
+ function delete_code()
+ {
+ global $db, $user;
+
+ $sql = 'DELETE FROM ' . 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);
+ }
+
+ function get_attempt_count()
+ {
+ return $this->attempts;
+ }
+
+ function reset()
+ {
+ global $db, $user;
+
+ $sql = 'DELETE FROM ' . 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->generate_code();
+ }
+
+ function is_solved()
+ {
+ if (request_var('answer', false) && $this->solved === 0)
+ {
+ $this->validate();
+ }
+ return (bool) $this->solved;
+ }
+
+ 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', '');
+
+
+ $template->assign_vars(array(
+ 'U_ACTION' => $module->u_action,
+ 'QUESTION_ID' => $question_id ,
+ 'CLASS' => $this->get_class_name(),
+ ));
+
+ 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($module->u_action));
+ }
+ 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
+ {
+
+ $error = false;
+ $input_question = request_var('question_text', '');
+ $input_answers = request_var('answers', '');
+ $input_lang = request_var('lang_iso', '');
+ $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'],
+ ));
+ }
+
+ 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($module->u_action));
+ }
+ }
+ 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);
+ }
+
+ trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($module->u_action . "&amp;configure=1&amp;select_captcha=" . $this->get_class_name()));
+ }
+ }
+ else if ($submit)
+ {
+ trigger_error($user->lang['FORM_INVALID'] . adm_back_link($module->u_action));
+ }
+ }
+ }
+
+ function acp_question_list(&$module)
+ {
+ global $db, $template;
+
+ $sql = 'SELECT * FROM ' . QUESTIONS_TABLE . ' WHERE 1';
+ $result = $db->sql_query($sql);
+ $template->assign_vars(array(
+ 'S_LIST' => true,
+ ));
+
+ while($row = $db->sql_fetchrow($result))
+ {
+ $url = $module->u_action . "&amp;question_id={$row['question_id']}&amp;configure=1&amp;select_captcha=" . $this->get_class_name() . "&amp;";
+
+ $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);
+ }
+
+ function acp_get_question_data($question_id)
+ {
+ global $db;
+
+
+ if ($question_id)
+ {
+ $sql = 'SELECT * FROM ' . QUESTIONS_TABLE . ' WHERE question_id = ' . $question_id;
+ $result = $db->sql_query($sql);
+ if ($row = $db->sql_fetchrow($result))
+ {
+ $question = $row;
+ }
+ else
+ {
+ $db->sql_freeresult($result);
+ return false;
+ }
+ $question['answers'] = array();
+ $sql = 'SELECT * FROM ' . 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;
+ }
+
+ }
+
+
+ function acp_get_question_input()
+ {
+ global $db;
+
+ $question = array(
+ 'question_text' => request_var('question_text', ''),
+ 'strict' => request_var('strict', false),
+ 'lang_iso' => request_var('lang_iso', ''),
+ 'answers' => explode("\n", request_var('answers', '')),
+ );
+
+ return $question;
+ }
+
+
+
+ function acp_update_question($data, $question_id)
+ {
+ global $db;
+
+ $sql = "DELETE FROM " . 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 " . 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);
+ }
+
+ function acp_add_question($data)
+ {
+ global $db;
+
+ $langs = $this->get_languages();
+ $question_ary = $data;
+
+ $question_ary['lang_id'] = $langs[$data['lang_iso']]['id'];
+ unset($question_ary['answers']);
+ $sql = "INSERT INTO " . 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);
+ }
+
+ function acp_insert_answers($data, $question_id)
+ {
+ global $db;
+
+ foreach($data['answers'] as $answer)
+ {
+ $answer_ary = array(
+ 'question_id' => $question_id,
+ 'answer_text' => $answer,
+ );
+ $sql = "INSERT INTO " . ANSWERS_TABLE . $db->sql_build_array('INSERT', $answer_ary);
+ $db->sql_query($sql);
+ }
+ }
+
+
+
+ function acp_delete_question($question_id)
+ {
+ global $db;
+
+ $tables = array(QUESTIONS_TABLE, ANSWERS_TABLE);
+ foreach($tables as $table)
+ {
+ $sql = "DELETE FROM $table WHERE question_id = $question_id";
+ $db->sql_query($sql);
+ }
+ }
+
+
+ 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;
+ }
+
+ function get_languages()
+ {
+ global $db;
+
+ $langs = array();
+ $sql = 'SELECT * FROM ' . LANG_TABLE . ' WHERE 1';
+ $result = $db->sql_query($sql);
+ while($row = $db->sql_fetchrow($result))
+ {
+ $langs[$row['lang_iso']] = array(
+ 'name' => $row['lang_local_name'],
+ 'id' => $row['lang_id'],
+ );
+ }
+ $db->sql_freeresult($result);
+ return $langs;
+ }
+
+}
+
+?> \ No newline at end of file
diff --git a/phpBB/language/en/captcha_qa.php b/phpBB/language/en/captcha_qa.php
new file mode 100755
index 0000000000..03721cc8a9
--- /dev/null
+++ b/phpBB/language/en/captcha_qa.php
@@ -0,0 +1,61 @@
+<?php
+/**
+*
+* recaptcha [English]
+*
+* @package language
+* @version $Id: recaptcha.php 9709 2009-06-30 14:23:16Z Kellanved $
+* @copyright (c) 2008 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*
+*/
+
+/**
+* DO NOT CHANGE
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+if (empty($lang) || !is_array($lang))
+{
+ $lang = array();
+}
+
+// DEVELOPERS PLEASE NOTE
+//
+// All language files should use UTF-8 as their encoding and the files must not contain a BOM.
+//
+// Placeholders can now contain order information, e.g. instead of
+// 'Page %s of %s' you can (and should) write 'Page %1$s of %2$s', this allows
+// translators to re-order the output of data while ensuring it remains correct
+//
+// You do not need this where single placeholders are used, e.g. 'Message %d' is fine
+// equally where a string contains only two placeholders which are used to wrap text
+// in a url you again do not need to specify an order e.g., 'Click %sHERE%s' is fine
+
+$lang = array_merge($lang, array(
+ 'CAPTCHA_QA' => 'Q&amp;A CAPTCHA',
+ 'CONFIRM_QUESTION_EXPLAIN' => 'Please answer this question to avoid automatted registrations.',
+ 'CONFIRM_QUESTION_WRONG' => 'The answer to the confirmation question was not recognized.',
+
+ 'QUESTION_ANSWERS' => 'Answers',
+ 'ANSWERS_EXPLAIN' => 'The Answers. Please write one answer per line.',
+ 'QUESTIONS' => 'Questions',
+ 'QUESTIONS_EXPLAIN' => 'Here you can add enter and edit questions to be asked on registration to ward against automatted installs.',
+ 'QUESTION_DELETED' => 'Question deleted',
+ 'QUESTION_LANG' => 'Language',
+ 'QUESTION_LANG_EXPLAIN' => 'The language this question and its answers is written in.',
+ 'QUESTION_STRICT' => 'Strict check',
+ 'QUESTION_STRICT_EXPLAIN' => 'If enabled, the check also recognizes capitalization and whitespaces.',
+
+ 'QUESTION_TEXT' => 'Question',
+ 'QUESTION_TEXT_EXPLAIN' => 'The question that will be asked on registration.',
+
+ 'QA_ERROR_MSG' => 'Please fill out all fields and enter at least one answer.',
+
+
+));
+
+?> \ No newline at end of file
diff --git a/phpBB/styles/prosilver/template/captcha_qa.html b/phpBB/styles/prosilver/template/captcha_qa.html
new file mode 100755
index 0000000000..2f57afc61a
--- /dev/null
+++ b/phpBB/styles/prosilver/template/captcha_qa.html
@@ -0,0 +1,23 @@
+<!-- IF S_TYPE == 1 -->
+<div class="panel">
+ <div class="inner"><span class="corners-top"><span></span></span>
+
+ <h3>{L_CONFIRMATION}</h3>
+ <fieldset class="fields2">
+
+<!-- ENDIF -->
+
+ <dl>
+ <dt><label>{CONFIRM_QUESTION}</label>:<br /><span>{L_CONFIRM_QUESTION_EXPLAIN}</span></dt>
+ <dd>
+ <input type="text" tabindex="10" name="answer" id="answer" size="25" value="{USERNAME}" class="inputbox autowidth" title="{L_ANSWER}" />
+ <input type="hidden" name="confirm_id" id="confirm_id" value="{CONFIRM_ID}" />
+ </dd>
+ </dl>
+
+<!-- IF S_TYPE == 1 -->
+ </fieldset>
+ <span class="corners-bottom"><span></span></span></div>
+</div>
+<!-- ENDIF -->
+
diff --git a/phpBB/styles/subsilver2/template/captcha_qa.html b/phpBB/styles/subsilver2/template/captcha_qa.html
new file mode 100755
index 0000000000..08b267b8fb
--- /dev/null
+++ b/phpBB/styles/subsilver2/template/captcha_qa.html
@@ -0,0 +1,5 @@
+ <tr>
+ <td class="row1"><b class="genmed">{CONFIRM_QUESTION}: </b><br /></td>
+ <td class="row2"><input class="post" type="text" name="answer" size="80" /></td>
+ <input type="hidden" name="confirm_id" id="confirm_id" value="{CONFIRM_ID}" /></td>
+ </tr> \ No newline at end of file