Verzeichnisstruktur phpBB-3.3.15
- Veröffentlicht
- 28.08.2024
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
qa.php
0001 <?php
0002 /**
0003 *
0004 * This file is part of the phpBB Forum Software package.
0005 *
0006 * @copyright (c) phpBB Limited <https://www.phpbb.com>
0007 * @license GNU General Public License, version 2 (GPL-2.0)
0008 *
0009 * For full copyright and license information, please see
0010 * the docs/CREDITS.txt file.
0011 *
0012 */
0013
0014 namespace phpbb\captcha\plugins;
0015
0016 /**
0017 * And now to something completely different. Let's make a captcha without extending the abstract class.
0018 * QA CAPTCHA sample implementation
0019 */
0020 class qa
0021 {
0022 var $confirm_id;
0023 var $answer;
0024 var $question_ids = [];
0025 var $question_text;
0026 var $question_lang;
0027 var $question_strict;
0028 var $attempts = 0;
0029 var $type;
0030 // dirty trick: 0 is false, but can still encode that the captcha is not yet validated
0031 var $solved = 0;
0032
0033 protected $table_captcha_questions;
0034 protected $table_captcha_answers;
0035 protected $table_qa_confirm;
0036
0037 /**
0038 * @var string name of the service.
0039 */
0040 protected $service_name;
0041
0042 /**
0043 * Constructor
0044 *
0045 * @param string $table_captcha_questions
0046 * @param string $table_captcha_answers
0047 * @param string $table_qa_confirm
0048 */
0049 function __construct($table_captcha_questions, $table_captcha_answers, $table_qa_confirm)
0050 {
0051 $this->table_captcha_questions = $table_captcha_questions;
0052 $this->table_captcha_answers = $table_captcha_answers;
0053 $this->table_qa_confirm = $table_qa_confirm;
0054 }
0055
0056 /**
0057 * @param int $type as per the CAPTCHA API docs, the type
0058 */
0059 function init($type)
0060 {
0061 global $config, $db, $user, $request;
0062
0063 // load our language file
0064 $user->add_lang('captcha_qa');
0065
0066 // read input
0067 $this->confirm_id = $request->variable('qa_confirm_id', '');
0068 $this->answer = $request->variable('qa_answer', '', true);
0069
0070 $this->type = (int) $type;
0071 $this->question_lang = $user->lang_name;
0072
0073 // we need all defined questions - shouldn't be too many, so we can just grab them
0074 // try the user's lang first
0075 $sql = 'SELECT question_id
0076 FROM ' . $this->table_captcha_questions . "
0077 WHERE lang_iso = '" . $db->sql_escape($user->lang_name) . "'";
0078 $result = $db->sql_query($sql, 3600);
0079
0080 while ($row = $db->sql_fetchrow($result))
0081 {
0082 $this->question_ids[$row['question_id']] = $row['question_id'];
0083 }
0084 $db->sql_freeresult($result);
0085
0086 // fallback to the board default lang
0087 if (!count($this->question_ids))
0088 {
0089 $this->question_lang = $config['default_lang'];
0090
0091 $sql = 'SELECT question_id
0092 FROM ' . $this->table_captcha_questions . "
0093 WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'";
0094 $result = $db->sql_query($sql, 7200);
0095
0096 while ($row = $db->sql_fetchrow($result))
0097 {
0098 $this->question_ids[$row['question_id']] = $row['question_id'];
0099 }
0100 $db->sql_freeresult($result);
0101 }
0102
0103 // final fallback to any language
0104 if (!count($this->question_ids))
0105 {
0106 $this->question_lang = '';
0107
0108 $sql = 'SELECT q.question_id, q.lang_iso
0109 FROM ' . $this->table_captcha_questions . ' q, ' . $this->table_captcha_answers . ' a
0110 WHERE q.question_id = a.question_id';
0111 $result = $db->sql_query($sql, 7200);
0112
0113 while ($row = $db->sql_fetchrow($result))
0114 {
0115 if (empty($this->question_lang))
0116 {
0117 $this->question_lang = $row['lang_iso'];
0118 }
0119 $this->question_ids[$row['question_id']] = $row['question_id'];
0120 }
0121 $db->sql_freeresult($result);
0122 }
0123
0124 // okay, if there is a confirm_id, we try to load that confirm's state. If not, we try to find one
0125 if (!$this->load_answer() && (!$this->load_confirm_id() || !$this->load_answer()))
0126 {
0127 // we have no valid confirm ID, better get ready to ask something
0128 $this->select_question();
0129 }
0130 }
0131
0132 /**
0133 * See if the captcha has created its tables.
0134 */
0135 public function is_installed()
0136 {
0137 global $phpbb_container;
0138
0139 $db_tool = $phpbb_container->get('dbal.tools');
0140
0141 return $db_tool->sql_table_exists($this->table_captcha_questions);
0142 }
0143
0144 /**
0145 * 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
0146 */
0147 public function is_available()
0148 {
0149 global $config, $db, $user;
0150
0151 // load language file for pretty display in the ACP dropdown
0152 $user->add_lang('captcha_qa');
0153
0154 if (!$this->is_installed())
0155 {
0156 return false;
0157 }
0158
0159 $sql = 'SELECT COUNT(question_id) AS question_count
0160 FROM ' . $this->table_captcha_questions . "
0161 WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'";
0162 $result = $db->sql_query($sql);
0163 $row = $db->sql_fetchrow($result);
0164 $db->sql_freeresult($result);
0165
0166 return ((bool) $row['question_count']);
0167 }
0168
0169 /**
0170 * API function
0171 */
0172 function has_config()
0173 {
0174 return true;
0175 }
0176
0177 /**
0178 * API function
0179 */
0180 static public function get_name()
0181 {
0182 return 'CAPTCHA_QA';
0183 }
0184
0185 /**
0186 * @return string the name of the service corresponding to the plugin
0187 */
0188 function get_service_name()
0189 {
0190 return $this->service_name;
0191 }
0192
0193 /**
0194 * Set the name of the plugin
0195 *
0196 * @param string $name
0197 */
0198 public function set_name($name)
0199 {
0200 $this->service_name = $name;
0201 }
0202
0203 /**
0204 * API function - not needed as we don't display an image
0205 */
0206 function execute_demo()
0207 {
0208 }
0209
0210 /**
0211 * API function - not needed as we don't display an image
0212 */
0213 function execute()
0214 {
0215 }
0216
0217 /**
0218 * API function - send the question to the template
0219 */
0220 function get_template()
0221 {
0222 global $phpbb_log, $template, $user;
0223
0224 if ($this->is_solved())
0225 {
0226 return false;
0227 }
0228 else if (empty($this->question_text) || !count($this->question_ids))
0229 {
0230 /** @var \phpbb\log\log_interface $phpbb_log */
0231 $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_ERROR_CAPTCHA', time(), array($user->lang('CONFIRM_QUESTION_MISSING')));
0232 return false;
0233 }
0234 else
0235 {
0236 $template->assign_vars(array(
0237 'QA_CONFIRM_QUESTION' => $this->question_text,
0238 'QA_CONFIRM_ID' => $this->confirm_id,
0239 'S_CONFIRM_CODE' => true,
0240 'S_TYPE' => $this->type,
0241 ));
0242
0243 return 'captcha_qa.html';
0244 }
0245 }
0246
0247 /**
0248 * API function - we just display a mockup so that the captcha doesn't need to be installed
0249 */
0250 function get_demo_template()
0251 {
0252 global $config, $db, $template;
0253
0254 if ($this->is_available())
0255 {
0256 $sql = 'SELECT question_text
0257 FROM ' . $this->table_captcha_questions . "
0258 WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'";
0259 $result = $db->sql_query_limit($sql, 1);
0260 if ($row = $db->sql_fetchrow($result))
0261 {
0262 $template->assign_vars(array(
0263 'QA_CONFIRM_QUESTION' => $row['question_text'],
0264 ));
0265 }
0266 $db->sql_freeresult($result);
0267 }
0268 return 'captcha_qa_acp_demo.html';
0269 }
0270
0271 /**
0272 * API function
0273 */
0274 function get_hidden_fields()
0275 {
0276 $hidden_fields = array();
0277
0278 // this is required - otherwise we would forget about the captcha being already solved
0279 if ($this->solved)
0280 {
0281 $hidden_fields['qa_answer'] = $this->answer;
0282 }
0283 $hidden_fields['qa_confirm_id'] = $this->confirm_id;
0284
0285 return $hidden_fields;
0286 }
0287
0288 /**
0289 * API function
0290 */
0291 function garbage_collect($type = 0)
0292 {
0293 global $db;
0294
0295 $sql = 'SELECT c.confirm_id
0296 FROM ' . $this->table_qa_confirm . ' c
0297 LEFT JOIN ' . SESSIONS_TABLE . ' s
0298 ON (c.session_id = s.session_id)
0299 WHERE s.session_id IS NULL' .
0300 ((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type);
0301 $result = $db->sql_query($sql);
0302
0303 if ($row = $db->sql_fetchrow($result))
0304 {
0305 $sql_in = array();
0306
0307 do
0308 {
0309 $sql_in[] = (string) $row['confirm_id'];
0310 }
0311 while ($row = $db->sql_fetchrow($result));
0312
0313 if (count($sql_in))
0314 {
0315 $sql = 'DELETE FROM ' . $this->table_qa_confirm . '
0316 WHERE ' . $db->sql_in_set('confirm_id', $sql_in);
0317 $db->sql_query($sql);
0318 }
0319 }
0320 $db->sql_freeresult($result);
0321 }
0322
0323 /**
0324 * API function - we don't drop the tables here, as that would cause the loss of all entered questions.
0325 */
0326 function uninstall()
0327 {
0328 $this->garbage_collect(0);
0329 }
0330
0331 /**
0332 * API function - set up shop
0333 */
0334 function install()
0335 {
0336 global $phpbb_container;
0337
0338 $db_tool = $phpbb_container->get('dbal.tools');
0339 $schemas = array(
0340 $this->table_captcha_questions => array (
0341 'COLUMNS' => array(
0342 'question_id' => array('UINT', null, 'auto_increment'),
0343 'strict' => array('BOOL', 0),
0344 'lang_id' => array('UINT', 0),
0345 'lang_iso' => array('VCHAR:30', ''),
0346 'question_text' => array('TEXT_UNI', ''),
0347 ),
0348 'PRIMARY_KEY' => 'question_id',
0349 'KEYS' => array(
0350 'lang' => array('INDEX', 'lang_iso'),
0351 ),
0352 ),
0353 $this->table_captcha_answers => array (
0354 'COLUMNS' => array(
0355 'question_id' => array('UINT', 0),
0356 'answer_text' => array('STEXT_UNI', ''),
0357 ),
0358 'KEYS' => array(
0359 'qid' => array('INDEX', 'question_id'),
0360 ),
0361 ),
0362 $this->table_qa_confirm => array (
0363 'COLUMNS' => array(
0364 'session_id' => array('CHAR:32', ''),
0365 'confirm_id' => array('CHAR:32', ''),
0366 'lang_iso' => array('VCHAR:30', ''),
0367 'question_id' => array('UINT', 0),
0368 'attempts' => array('UINT', 0),
0369 'confirm_type' => array('USINT', 0),
0370 ),
0371 'KEYS' => array(
0372 'session_id' => array('INDEX', 'session_id'),
0373 'lookup' => array('INDEX', array('confirm_id', 'session_id', 'lang_iso')),
0374 ),
0375 'PRIMARY_KEY' => 'confirm_id',
0376 ),
0377 );
0378
0379 foreach ($schemas as $table => $schema)
0380 {
0381 if (!$db_tool->sql_table_exists($table))
0382 {
0383 $db_tool->sql_create_table($table, $schema);
0384 }
0385 }
0386 }
0387
0388 /**
0389 * API function - see what has to be done to validate
0390 */
0391 function validate()
0392 {
0393 global $phpbb_log, $user;
0394
0395 $error = '';
0396
0397 if (!count($this->question_ids))
0398 {
0399 /** @var \phpbb\log\log_interface $phpbb_log */
0400 $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_ERROR_CAPTCHA', time(), array($user->lang('CONFIRM_QUESTION_MISSING')));
0401 return $user->lang('CONFIRM_QUESTION_MISSING');
0402 }
0403
0404 if (!$this->confirm_id)
0405 {
0406 $error = $user->lang['CONFIRM_QUESTION_WRONG'];
0407 }
0408 else
0409 {
0410 if ($this->check_answer())
0411 {
0412 $this->solved = true;
0413 }
0414 else
0415 {
0416 $error = $user->lang['CONFIRM_QUESTION_WRONG'];
0417 }
0418 }
0419
0420 if (strlen($error))
0421 {
0422 // okay, incorrect answer. Let's ask a new question.
0423 $this->new_attempt();
0424 $this->solved = false;
0425
0426 return $error;
0427 }
0428 else
0429 {
0430 return false;
0431 }
0432 }
0433
0434 /**
0435 * Select a question
0436 */
0437 function select_question()
0438 {
0439 global $db, $user;
0440
0441 if (!count($this->question_ids))
0442 {
0443 return;
0444 }
0445 $this->confirm_id = md5(unique_id($user->ip));
0446 $this->question = (int) array_rand($this->question_ids);
0447
0448 $sql = 'INSERT INTO ' . $this->table_qa_confirm . ' ' . $db->sql_build_array('INSERT', array(
0449 'confirm_id' => (string) $this->confirm_id,
0450 'session_id' => (string) $user->session_id,
0451 'lang_iso' => (string) $this->question_lang,
0452 'confirm_type' => (int) $this->type,
0453 'question_id' => (int) $this->question,
0454 ));
0455 $db->sql_query($sql);
0456
0457 $this->load_answer();
0458 }
0459
0460 /**
0461 * New Question, if desired.
0462 */
0463 function reselect_question()
0464 {
0465 global $db, $user;
0466
0467 if (!count($this->question_ids))
0468 {
0469 return;
0470 }
0471
0472 $this->question = (int) array_rand($this->question_ids);
0473 $this->solved = 0;
0474
0475 $sql = 'UPDATE ' . $this->table_qa_confirm . '
0476 SET question_id = ' . (int) $this->question . "
0477 WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "'
0478 AND session_id = '" . $db->sql_escape($user->session_id) . "'";
0479 $db->sql_query($sql);
0480
0481 $this->load_answer();
0482 }
0483
0484 /**
0485 * Wrong answer, so we increase the attempts and use a different question.
0486 */
0487 function new_attempt()
0488 {
0489 global $db, $user;
0490
0491 // yah, I would prefer a stronger rand, but this should work
0492 $this->question = (int) array_rand($this->question_ids);
0493 $this->solved = 0;
0494
0495 $sql = 'UPDATE ' . $this->table_qa_confirm . '
0496 SET question_id = ' . (int) $this->question . ",
0497 attempts = attempts + 1
0498 WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "'
0499 AND session_id = '" . $db->sql_escape($user->session_id) . "'";
0500 $db->sql_query($sql);
0501
0502 $this->load_answer();
0503 }
0504
0505
0506 /**
0507 * See if there is already an entry for the current session.
0508 */
0509 function load_confirm_id()
0510 {
0511 global $db, $user;
0512
0513 $sql = 'SELECT confirm_id
0514 FROM ' . $this->table_qa_confirm . "
0515 WHERE
0516 session_id = '" . $db->sql_escape($user->session_id) . "'
0517 AND lang_iso = '" . $db->sql_escape($this->question_lang) . "'
0518 AND confirm_type = " . $this->type;
0519 $result = $db->sql_query_limit($sql, 1);
0520 $row = $db->sql_fetchrow($result);
0521 $db->sql_freeresult($result);
0522
0523 if ($row)
0524 {
0525 $this->confirm_id = $row['confirm_id'];
0526 return true;
0527 }
0528 return false;
0529 }
0530
0531 /**
0532 * Look up everything we need and populate the instance variables.
0533 */
0534 function load_answer()
0535 {
0536 global $db, $user;
0537
0538 if (!strlen($this->confirm_id) || !count($this->question_ids))
0539 {
0540 return false;
0541 }
0542
0543 $sql = 'SELECT con.question_id, attempts, question_text, strict
0544 FROM ' . $this->table_qa_confirm . ' con, ' . $this->table_captcha_questions . " qes
0545 WHERE con.question_id = qes.question_id
0546 AND confirm_id = '" . $db->sql_escape($this->confirm_id) . "'
0547 AND session_id = '" . $db->sql_escape($user->session_id) . "'
0548 AND qes.lang_iso = '" . $db->sql_escape($this->question_lang) . "'
0549 AND confirm_type = " . $this->type;
0550 $result = $db->sql_query($sql);
0551 $row = $db->sql_fetchrow($result);
0552 $db->sql_freeresult($result);
0553
0554 if ($row)
0555 {
0556 $this->question = $row['question_id'];
0557
0558 $this->attempts = $row['attempts'];
0559 $this->question_strict = $row['strict'];
0560 $this->question_text = $row['question_text'];
0561
0562 return true;
0563 }
0564
0565 return false;
0566 }
0567
0568 /**
0569 * The actual validation
0570 */
0571 function check_answer()
0572 {
0573 global $db, $request;
0574
0575 $answer = ($this->question_strict) ? $request->variable('qa_answer', '', true) : utf8_clean_string($request->variable('qa_answer', '', true));
0576
0577 $sql = 'SELECT answer_text
0578 FROM ' . $this->table_captcha_answers . '
0579 WHERE question_id = ' . (int) $this->question;
0580 $result = $db->sql_query($sql);
0581
0582 while ($row = $db->sql_fetchrow($result))
0583 {
0584 $solution = ($this->question_strict) ? $row['answer_text'] : utf8_clean_string($row['answer_text']);
0585
0586 if ($solution === $answer)
0587 {
0588 $this->solved = true;
0589
0590 break;
0591 }
0592 }
0593 $db->sql_freeresult($result);
0594
0595 return $this->solved;
0596 }
0597
0598 /**
0599 * API function
0600 */
0601 function get_attempt_count()
0602 {
0603 return $this->attempts;
0604 }
0605
0606 /**
0607 * API function
0608 */
0609 function reset()
0610 {
0611 global $db, $user;
0612
0613 $sql = 'DELETE FROM ' . $this->table_qa_confirm . "
0614 WHERE session_id = '" . $db->sql_escape($user->session_id) . "'
0615 AND confirm_type = " . (int) $this->type;
0616 $db->sql_query($sql);
0617
0618 // we leave the class usable by generating a new question
0619 $this->select_question();
0620 }
0621
0622 /**
0623 * API function
0624 */
0625 function is_solved()
0626 {
0627 global $request;
0628
0629 if ($request->variable('qa_answer', false) && $this->solved === 0)
0630 {
0631 $this->validate();
0632 }
0633
0634 return (bool) $this->solved;
0635 }
0636
0637 /**
0638 * API function - The ACP backend, this marks the end of the easy methods
0639 */
0640 function acp_page($id, $module)
0641 {
0642 global $config, $request, $phpbb_log, $template, $user;
0643
0644 $user->add_lang('acp/board');
0645 $user->add_lang('captcha_qa');
0646
0647 if (!self::is_installed())
0648 {
0649 $this->install();
0650 }
0651
0652 $module->tpl_name = 'captcha_qa_acp';
0653 $module->page_title = 'ACP_VC_SETTINGS';
0654 $form_key = 'acp_captcha';
0655 add_form_key($form_key);
0656
0657 $submit = $request->variable('submit', false);
0658 $question_id = $request->variable('question_id', 0);
0659 $action = $request->variable('action', '');
0660
0661 // we have two pages, so users might want to navigate from one to the other
0662 $list_url = $module->u_action . "&configure=1&select_captcha=" . $this->get_service_name();
0663
0664 $template->assign_vars(array(
0665 'U_ACTION' => $module->u_action,
0666 'QUESTION_ID' => $question_id ,
0667 'CLASS' => $this->get_service_name(),
0668 ));
0669
0670 // show the list?
0671 if (!$question_id && $action != 'add')
0672 {
0673 $this->acp_question_list($module);
0674 }
0675 else if ($question_id && $action == 'delete')
0676 {
0677 if ($this->get_service_name() !== $config['captcha_plugin'] || !$this->acp_is_last($question_id))
0678 {
0679 if (confirm_box(true))
0680 {
0681 $this->acp_delete_question($question_id);
0682
0683 trigger_error($user->lang['QUESTION_DELETED'] . adm_back_link($list_url));
0684 }
0685 else
0686 {
0687 confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array(
0688 'question_id' => $question_id,
0689 'action' => $action,
0690 'configure' => 1,
0691 'select_captcha' => $this->get_service_name(),
0692 ))
0693 );
0694 }
0695 }
0696 else
0697 {
0698 trigger_error($user->lang['QA_LAST_QUESTION'] . adm_back_link($list_url), E_USER_WARNING);
0699 }
0700 }
0701 else
0702 {
0703 // okay, show the editor
0704 $question_input = $this->acp_get_question_input();
0705 $langs = $this->get_languages();
0706
0707 foreach ($langs as $lang => $entry)
0708 {
0709 $template->assign_block_vars('langs', array(
0710 'ISO' => $lang,
0711 'NAME' => $entry['name'],
0712 ));
0713 }
0714
0715 $template->assign_vars(array(
0716 'U_LIST' => $list_url,
0717 ));
0718
0719 if ($question_id)
0720 {
0721 if ($question = $this->acp_get_question_data($question_id))
0722 {
0723 $template->assign_vars(array(
0724 'QUESTION_TEXT' => ($question_input['question_text']) ? $question_input['question_text'] : $question['question_text'],
0725 'LANG_ISO' => ($question_input['lang_iso']) ? $question_input['lang_iso'] : $question['lang_iso'],
0726 'STRICT' => (isset($_REQUEST['strict'])) ? $question_input['strict'] : $question['strict'],
0727 'ANSWERS' => implode("\n", $question['answers']),
0728 ));
0729 }
0730 else
0731 {
0732 trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url));
0733 }
0734 }
0735 else
0736 {
0737 $template->assign_vars(array(
0738 'QUESTION_TEXT' => $question_input['question_text'],
0739 'LANG_ISO' => $question_input['lang_iso'],
0740 'STRICT' => $question_input['strict'],
0741 'ANSWERS' => (is_array($question_input['answers'])) ? implode("\n", $question_input['answers']) : '',
0742 ));
0743 }
0744
0745 if ($submit && check_form_key($form_key))
0746 {
0747 if (!$this->validate_input($question_input))
0748 {
0749 $template->assign_vars(array(
0750 'S_ERROR' => true,
0751 ));
0752 }
0753 else
0754 {
0755 if ($question_id)
0756 {
0757 $this->acp_update_question($question_input, $question_id);
0758 }
0759 else
0760 {
0761 $this->acp_add_question($question_input);
0762 }
0763
0764 $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_VISUAL');
0765 trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($list_url));
0766 }
0767 }
0768 else if ($submit)
0769 {
0770 trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url), E_USER_WARNING);
0771 }
0772 }
0773 }
0774
0775 /**
0776 * This handles the list overview
0777 */
0778 function acp_question_list($module)
0779 {
0780 global $db, $template;
0781
0782 $sql = 'SELECT *
0783 FROM ' . $this->table_captcha_questions;
0784 $result = $db->sql_query($sql);
0785
0786 $template->assign_vars(array(
0787 'S_LIST' => true,
0788 ));
0789
0790 while ($row = $db->sql_fetchrow($result))
0791 {
0792 $url = $module->u_action . "&question_id={$row['question_id']}&configure=1&select_captcha=" . $this->get_service_name() . '&';
0793
0794 $template->assign_block_vars('questions', array(
0795 'QUESTION_TEXT' => $row['question_text'],
0796 'QUESTION_ID' => $row['question_id'],
0797 'QUESTION_LANG' => $row['lang_iso'],
0798 'U_DELETE' => "{$url}action=delete",
0799 'U_EDIT' => "{$url}action=edit",
0800 ));
0801 }
0802 $db->sql_freeresult($result);
0803 }
0804
0805 /**
0806 * Grab a question and bring it into a format the editor understands
0807 */
0808 function acp_get_question_data($question_id)
0809 {
0810 global $db;
0811
0812 if ($question_id)
0813 {
0814 $sql = 'SELECT *
0815 FROM ' . $this->table_captcha_questions . '
0816 WHERE question_id = ' . $question_id;
0817 $result = $db->sql_query($sql);
0818 $question = $db->sql_fetchrow($result);
0819 $db->sql_freeresult($result);
0820
0821 if (!$question)
0822 {
0823 return false;
0824 }
0825
0826 $question['answers'] = array();
0827
0828 $sql = 'SELECT *
0829 FROM ' . $this->table_captcha_answers . '
0830 WHERE question_id = ' . $question_id;
0831 $result = $db->sql_query($sql);
0832
0833 while ($row = $db->sql_fetchrow($result))
0834 {
0835 $question['answers'][] = $row['answer_text'];
0836 }
0837 $db->sql_freeresult($result);
0838
0839 return $question;
0840 }
0841
0842 return false;
0843 }
0844
0845 /**
0846 * Grab a question from input and bring it into a format the editor understands
0847 */
0848 function acp_get_question_input()
0849 {
0850 global $request;
0851
0852 $answers = $request->variable('answers', '', true);
0853
0854 // Convert answers into array and filter if answers are set
0855 if (strlen($answers))
0856 {
0857 $answers = array_filter(array_map('trim', explode("\n", $answers)), function ($value) {
0858 return $value !== '';
0859 });
0860 }
0861
0862 $question = array(
0863 'question_text' => $request->variable('question_text', '', true),
0864 'strict' => $request->variable('strict', false),
0865 'lang_iso' => $request->variable('lang_iso', ''),
0866 'answers' => $answers,
0867 );
0868 return $question;
0869 }
0870
0871 /**
0872 * Update a question.
0873 * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data
0874 */
0875 function acp_update_question($data, $question_id)
0876 {
0877 global $db, $cache;
0878
0879 // easier to delete all answers than to figure out which to update
0880 $sql = 'DELETE FROM ' . $this->table_captcha_answers . " WHERE question_id = $question_id";
0881 $db->sql_query($sql);
0882
0883 $langs = $this->get_languages();
0884 $question_ary = $data;
0885 $question_ary['lang_id'] = $langs[$question_ary['lang_iso']]['id'];
0886 unset($question_ary['answers']);
0887
0888 $sql = 'UPDATE ' . $this->table_captcha_questions . '
0889 SET ' . $db->sql_build_array('UPDATE', $question_ary) . "
0890 WHERE question_id = $question_id";
0891 $db->sql_query($sql);
0892
0893 $this->acp_insert_answers($data, $question_id);
0894
0895 $cache->destroy('sql', $this->table_captcha_questions);
0896 }
0897
0898 /**
0899 * Insert a question.
0900 * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data
0901 */
0902 function acp_add_question($data)
0903 {
0904 global $db, $cache;
0905
0906 $langs = $this->get_languages();
0907 $question_ary = $data;
0908
0909 $question_ary['lang_id'] = $langs[$data['lang_iso']]['id'];
0910 unset($question_ary['answers']);
0911
0912 $sql = 'INSERT INTO ' . $this->table_captcha_questions . ' ' . $db->sql_build_array('INSERT', $question_ary);
0913 $db->sql_query($sql);
0914
0915 $question_id = $db->sql_nextid();
0916
0917 $this->acp_insert_answers($data, $question_id);
0918
0919 $cache->destroy('sql', $this->table_captcha_questions);
0920 }
0921
0922 /**
0923 * Insert the answers.
0924 * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data
0925 */
0926 function acp_insert_answers($data, $question_id)
0927 {
0928 global $db, $cache;
0929
0930 foreach ($data['answers'] as $answer)
0931 {
0932 $answer_ary = array(
0933 'question_id' => $question_id,
0934 'answer_text' => $answer,
0935 );
0936
0937 $sql = 'INSERT INTO ' . $this->table_captcha_answers . ' ' . $db->sql_build_array('INSERT', $answer_ary);
0938 $db->sql_query($sql);
0939 }
0940
0941 $cache->destroy('sql', $this->table_captcha_answers);
0942 }
0943
0944 /**
0945 * Delete a question.
0946 */
0947 function acp_delete_question($question_id)
0948 {
0949 global $db, $cache;
0950
0951 $tables = array($this->table_captcha_questions, $this->table_captcha_answers);
0952
0953 foreach ($tables as $table)
0954 {
0955 $sql = "DELETE FROM $table
0956 WHERE question_id = $question_id";
0957 $db->sql_query($sql);
0958 }
0959
0960 $cache->destroy('sql', $tables);
0961 }
0962
0963 /**
0964 * Check if the entered data can be inserted/used
0965 * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data
0966 */
0967 function validate_input($question_data)
0968 {
0969 $langs = $this->get_languages();
0970
0971 if (!isset($question_data['lang_iso']) ||
0972 !isset($question_data['question_text']) ||
0973 !isset($question_data['strict']) ||
0974 !isset($question_data['answers']))
0975 {
0976 return false;
0977 }
0978
0979 if (!isset($langs[$question_data['lang_iso']]) ||
0980 !strlen($question_data['question_text']) ||
0981 !count($question_data['answers']) ||
0982 !is_array($question_data['answers']))
0983 {
0984 return false;
0985 }
0986
0987 return true;
0988 }
0989
0990 /**
0991 * List the installed language packs
0992 */
0993 function get_languages()
0994 {
0995 global $db;
0996
0997 $sql = 'SELECT *
0998 FROM ' . LANG_TABLE;
0999 $result = $db->sql_query($sql);
1000
1001 $langs = array();
1002 while ($row = $db->sql_fetchrow($result))
1003 {
1004 $langs[$row['lang_iso']] = array(
1005 'name' => $row['lang_local_name'],
1006 'id' => (int) $row['lang_id'],
1007 );
1008 }
1009 $db->sql_freeresult($result);
1010
1011 return $langs;
1012 }
1013
1014
1015
1016 /**
1017 * See if there is a question other than the one we have
1018 */
1019 function acp_is_last($question_id)
1020 {
1021 global $config, $db;
1022
1023 if ($question_id)
1024 {
1025 $sql = 'SELECT question_id
1026 FROM ' . $this->table_captcha_questions . "
1027 WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'
1028 AND question_id <> " . (int) $question_id;
1029 $result = $db->sql_query_limit($sql, 1);
1030 $question = $db->sql_fetchrow($result);
1031 $db->sql_freeresult($result);
1032
1033 if (!$question)
1034 {
1035 return true;
1036 }
1037 return false;
1038 }
1039 }
1040 }
1041