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