Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

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