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.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

qa.php

Zuletzt modifiziert: 09.10.2024, 12:54 - Dateigröße: 24.24 KiB


 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 . "&amp;configure=1&amp;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 . "&amp;question_id={$row['question_id']}&amp;configure=1&amp;select_captcha=" . $this->get_service_name() . '&amp;';
 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