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