[ Index ]

PHP Cross Reference of phpBB-3.1.12-deutsch

title

Body

[close]

/phpbb/captcha/plugins/ -> qa.php (source)

   1  <?php
   2  /**
   3  *
   4  * This file is part of the phpBB Forum Software package.
   5  *
   6  * @copyright (c) phpBB Limited <https://www.phpbb.com>
   7  * @license GNU General Public License, version 2 (GPL-2.0)
   8  *
   9  * For full copyright and license information, please see
  10  * the docs/CREDITS.txt file.
  11  *
  12  */
  13  
  14  namespace phpbb\captcha\plugins;
  15  
  16  /**
  17  * And now to something completely different. Let's make a captcha without extending the abstract class.
  18  * QA CAPTCHA sample implementation
  19  */
  20  class qa
  21  {
  22      var $confirm_id;
  23      var $answer;
  24      var $question_ids;
  25      var $question_text;
  26      var $question_lang;
  27      var $question_strict;
  28      var $attempts = 0;
  29      var $type;
  30      // dirty trick: 0 is false, but can still encode that the captcha is not yet validated
  31      var $solved = 0;
  32  
  33      protected $table_captcha_questions;
  34      protected $table_captcha_answers;
  35      protected $table_qa_confirm;
  36  
  37      /**
  38      * @var string name of the service.
  39      */
  40      protected $service_name;
  41  
  42      /**
  43      * Constructor
  44      *
  45      * @param string $table_captcha_questions
  46      * @param string $table_captcha_answers
  47      * @param string $table_qa_confirm
  48      */
  49  	function __construct($table_captcha_questions, $table_captcha_answers, $table_qa_confirm)
  50      {
  51          $this->table_captcha_questions = $table_captcha_questions;
  52          $this->table_captcha_answers = $table_captcha_answers;
  53          $this->table_qa_confirm = $table_qa_confirm;
  54      }
  55  
  56      /**
  57      * @param int $type  as per the CAPTCHA API docs, the type
  58      */
  59  	function init($type)
  60      {
  61          global $config, $db, $user;
  62  
  63          // load our language file
  64          $user->add_lang('captcha_qa');
  65  
  66          // read input
  67          $this->confirm_id = request_var('qa_confirm_id', '');
  68          $this->answer = utf8_normalize_nfc(request_var('qa_answer', '', true));
  69  
  70          $this->type = (int) $type;
  71          $this->question_lang = $user->lang_name;
  72  
  73          // we need all defined questions - shouldn't be too many, so we can just grab them
  74          // try the user's lang first
  75          $sql = 'SELECT question_id
  76              FROM ' . $this->table_captcha_questions . "
  77              WHERE lang_iso = '" . $db->sql_escape($user->lang_name) . "'";
  78          $result = $db->sql_query($sql, 3600);
  79  
  80          while ($row = $db->sql_fetchrow($result))
  81          {
  82              $this->question_ids[$row['question_id']] = $row['question_id'];
  83          }
  84          $db->sql_freeresult($result);
  85  
  86          // fallback to the board default lang
  87          if (!sizeof($this->question_ids))
  88          {
  89              $this->question_lang = $config['default_lang'];
  90  
  91              $sql = 'SELECT question_id
  92                  FROM ' . $this->table_captcha_questions . "
  93                  WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'";
  94              $result = $db->sql_query($sql, 7200);
  95  
  96              while ($row = $db->sql_fetchrow($result))
  97              {
  98                  $this->question_ids[$row['question_id']] = $row['question_id'];
  99              }
 100              $db->sql_freeresult($result);
 101          }
 102  
 103          // final fallback to any language
 104          if (!sizeof($this->question_ids))
 105          {
 106              $this->question_lang = '';
 107  
 108              $sql = 'SELECT q.question_id, q.lang_iso
 109                  FROM ' . $this->table_captcha_questions . ' q, ' . $this->table_captcha_answers . ' a
 110                  WHERE q.question_id = a.question_id
 111                  GROUP BY lang_iso';
 112              $result = $db->sql_query($sql, 7200);
 113  
 114              while ($row = $db->sql_fetchrow($result))
 115              {
 116                  if (empty($this->question_lang))
 117                  {
 118                      $this->question_lang = $row['lang_iso'];
 119                  }
 120                  $this->question_ids[$row['question_id']] = $row['question_id'];
 121              }
 122              $db->sql_freeresult($result);
 123          }
 124  
 125          // okay, if there is a confirm_id, we try to load that confirm's state. If not, we try to find one
 126          if (!$this->load_answer() && (!$this->load_confirm_id() || !$this->load_answer()))
 127          {
 128              // we have no valid confirm ID, better get ready to ask something
 129              $this->select_question();
 130          }
 131      }
 132  
 133      /**
 134      * See if the captcha has created its tables.
 135      */
 136  	public function is_installed()
 137      {
 138          global $db;
 139  
 140          $db_tool = new \phpbb\db\tools($db);
 141  
 142          return $db_tool->sql_table_exists($this->table_captcha_questions);
 143      }
 144  
 145      /**
 146      *  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
 147      */
 148  	public function is_available()
 149      {
 150          global $config, $db, $user;
 151  
 152          // load language file for pretty display in the ACP dropdown
 153          $user->add_lang('captcha_qa');
 154  
 155          if (!$this->is_installed())
 156          {
 157              return false;
 158          }
 159  
 160          $sql = 'SELECT COUNT(question_id) AS question_count
 161              FROM ' . $this->table_captcha_questions . "
 162              WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'";
 163          $result = $db->sql_query($sql);
 164          $row = $db->sql_fetchrow($result);
 165          $db->sql_freeresult($result);
 166  
 167          return ((bool) $row['question_count']);
 168      }
 169  
 170      /**
 171      *  API function
 172      */
 173  	function has_config()
 174      {
 175          return true;
 176      }
 177  
 178      /**
 179      *  API function
 180      */
 181  	static public function get_name()
 182      {
 183          return 'CAPTCHA_QA';
 184      }
 185  
 186      /**
 187      * @return string the name of the service corresponding to the plugin
 188      */
 189  	function get_service_name()
 190      {
 191          return $this->service_name;
 192      }
 193  
 194      /**
 195      * Set the name of the plugin
 196      *
 197      * @param string $name
 198      */
 199  	public function set_name($name)
 200      {
 201          $this->service_name = $name;
 202      }
 203  
 204      /**
 205      *  API function - not needed as we don't display an image
 206      */
 207  	function execute_demo()
 208      {
 209      }
 210  
 211      /**
 212      *  API function - not needed as we don't display an image
 213      */
 214  	function execute()
 215      {
 216      }
 217  
 218      /**
 219      *  API function - send the question to the template
 220      */
 221  	function get_template()
 222      {
 223          global $phpbb_log, $template, $user;
 224  
 225          if ($this->is_solved())
 226          {
 227              return false;
 228          }
 229          else if (empty($this->question_text) || !count($this->question_ids))
 230          {
 231              /** @var \phpbb\log\log_interface $phpbb_log */
 232              $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_ERROR_CAPTCHA', time(), array($user->lang('CONFIRM_QUESTION_MISSING')));
 233              return false;
 234          }
 235          else
 236          {
 237              $template->assign_vars(array(
 238                  'QA_CONFIRM_QUESTION'    => $this->question_text,
 239                  'QA_CONFIRM_ID'            => $this->confirm_id,
 240                  'S_CONFIRM_CODE'        => true,
 241                  'S_TYPE'                => $this->type,
 242              ));
 243  
 244              return 'captcha_qa.html';
 245          }
 246      }
 247  
 248      /**
 249      *  API function - we just display a mockup so that the captcha doesn't need to be installed
 250      */
 251  	function get_demo_template()
 252      {
 253          global $config, $db, $template;
 254  
 255          if ($this->is_available())
 256          {
 257              $sql = 'SELECT question_text
 258                  FROM ' . $this->table_captcha_questions . "
 259                  WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'";
 260              $result = $db->sql_query_limit($sql, 1);
 261              if ($row = $db->sql_fetchrow($result))
 262              {
 263                  $template->assign_vars(array(
 264                      'QA_CONFIRM_QUESTION'        => $row['question_text'],
 265                  ));
 266              }
 267              $db->sql_freeresult($result);
 268          }
 269          return 'captcha_qa_acp_demo.html';
 270      }
 271  
 272      /**
 273      *  API function
 274      */
 275  	function get_hidden_fields()
 276      {
 277          $hidden_fields = array();
 278  
 279          // this is required - otherwise we would forget about the captcha being already solved
 280          if ($this->solved)
 281          {
 282              $hidden_fields['qa_answer'] = $this->answer;
 283          }
 284          $hidden_fields['qa_confirm_id'] = $this->confirm_id;
 285  
 286          return $hidden_fields;
 287      }
 288  
 289      /**
 290      *  API function
 291      */
 292  	function garbage_collect($type = 0)
 293      {
 294          global $db;
 295  
 296          $sql = 'SELECT c.confirm_id
 297              FROM ' . $this->table_qa_confirm . ' c
 298              LEFT JOIN ' . SESSIONS_TABLE . ' s
 299                  ON (c.session_id = s.session_id)
 300              WHERE s.session_id IS NULL' .
 301                  ((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type);
 302          $result = $db->sql_query($sql);
 303  
 304          if ($row = $db->sql_fetchrow($result))
 305          {
 306              $sql_in = array();
 307  
 308              do
 309              {
 310                  $sql_in[] = (string) $row['confirm_id'];
 311              }
 312              while ($row = $db->sql_fetchrow($result));
 313  
 314              if (sizeof($sql_in))
 315              {
 316                  $sql = 'DELETE FROM ' . $this->table_qa_confirm . '
 317                      WHERE ' . $db->sql_in_set('confirm_id', $sql_in);
 318                  $db->sql_query($sql);
 319              }
 320          }
 321          $db->sql_freeresult($result);
 322      }
 323  
 324      /**
 325      *  API function - we don't drop the tables here, as that would cause the loss of all entered questions.
 326      */
 327  	function uninstall()
 328      {
 329          $this->garbage_collect(0);
 330      }
 331  
 332      /**
 333      *  API function - set up shop
 334      */
 335  	function install()
 336      {
 337          global $db;
 338  
 339          $db_tool = new \phpbb\db\tools($db);
 340  
 341          $schemas = array(
 342                  $this->table_captcha_questions        => array (
 343                      'COLUMNS' => array(
 344                          'question_id'    => array('UINT', null, 'auto_increment'),
 345                          'strict'        => array('BOOL', 0),
 346                          'lang_id'        => array('UINT', 0),
 347                          'lang_iso'        => array('VCHAR:30', ''),
 348                          'question_text'    => array('TEXT_UNI', ''),
 349                      ),
 350                      'PRIMARY_KEY'        => 'question_id',
 351                      'KEYS'                => array(
 352                          'lang'            => array('INDEX', 'lang_iso'),
 353                      ),
 354                  ),
 355                  $this->table_captcha_answers        => array (
 356                      'COLUMNS' => array(
 357                          'question_id'    => array('UINT', 0),
 358                          'answer_text'    => array('STEXT_UNI', ''),
 359                      ),
 360                      'KEYS'                => array(
 361                          'qid'            => array('INDEX', 'question_id'),
 362                      ),
 363                  ),
 364                  $this->table_qa_confirm        => array (
 365                      'COLUMNS' => array(
 366                          'session_id'    => array('CHAR:32', ''),
 367                          'confirm_id'    => array('CHAR:32', ''),
 368                          'lang_iso'        => array('VCHAR:30', ''),
 369                          'question_id'    => array('UINT', 0),
 370                          'attempts'        => array('UINT', 0),
 371                          'confirm_type'    => array('USINT', 0),
 372                      ),
 373                      'KEYS'                => array(
 374                          'session_id'            => array('INDEX', 'session_id'),
 375                          'lookup'                => array('INDEX', array('confirm_id', 'session_id', 'lang_iso')),
 376                      ),
 377                      'PRIMARY_KEY'        => 'confirm_id',
 378                  ),
 379          );
 380  
 381          foreach ($schemas as $table => $schema)
 382          {
 383              if (!$db_tool->sql_table_exists($table))
 384              {
 385                  $db_tool->sql_create_table($table, $schema);
 386              }
 387          }
 388      }
 389  
 390      /**
 391      *  API function - see what has to be done to validate
 392      */
 393  	function validate()
 394      {
 395          global $phpbb_log, $user;
 396  
 397          $error = '';
 398  
 399          if (!sizeof($this->question_ids))
 400          {
 401              /** @var \phpbb\log\log_interface $phpbb_log */
 402              $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_ERROR_CAPTCHA', time(), array($user->lang('CONFIRM_QUESTION_MISSING')));
 403              return $user->lang('CONFIRM_QUESTION_MISSING');
 404          }
 405  
 406          if (!$this->confirm_id)
 407          {
 408              $error = $user->lang['CONFIRM_QUESTION_WRONG'];
 409          }
 410          else
 411          {
 412              if ($this->check_answer())
 413              {
 414                  $this->solved = true;
 415              }
 416              else
 417              {
 418                  $error = $user->lang['CONFIRM_QUESTION_WRONG'];
 419              }
 420          }
 421  
 422          if (strlen($error))
 423          {
 424              // okay, incorrect answer. Let's ask a new question.
 425              $this->new_attempt();
 426              $this->solved = false;
 427  
 428              return $error;
 429          }
 430          else
 431          {
 432              return false;
 433          }
 434      }
 435  
 436      /**
 437      *  Select a question
 438      */
 439  	function select_question()
 440      {
 441          global $db, $user;
 442  
 443          if (!sizeof($this->question_ids))
 444          {
 445              return;
 446          }
 447          $this->confirm_id = md5(unique_id($user->ip));
 448          $this->question = (int) array_rand($this->question_ids);
 449  
 450          $sql = 'INSERT INTO ' . $this->table_qa_confirm . ' ' . $db->sql_build_array('INSERT', array(
 451              'confirm_id'    => (string) $this->confirm_id,
 452              'session_id'    => (string) $user->session_id,
 453              'lang_iso'        => (string) $this->question_lang,
 454              'confirm_type'    => (int) $this->type,
 455              'question_id'    => (int) $this->question,
 456          ));
 457          $db->sql_query($sql);
 458  
 459          $this->load_answer();
 460      }
 461  
 462      /**
 463      * New Question, if desired.
 464      */
 465  	function reselect_question()
 466      {
 467          global $db, $user;
 468  
 469          if (!sizeof($this->question_ids))
 470          {
 471              return;
 472          }
 473  
 474          $this->question = (int) array_rand($this->question_ids);
 475          $this->solved = 0;
 476  
 477          $sql = 'UPDATE ' . $this->table_qa_confirm . '
 478              SET question_id = ' . (int) $this->question . "
 479              WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "'
 480                  AND session_id = '" . $db->sql_escape($user->session_id) . "'";
 481          $db->sql_query($sql);
 482  
 483          $this->load_answer();
 484      }
 485  
 486      /**
 487      * Wrong answer, so we increase the attempts and use a different question.
 488      */
 489  	function new_attempt()
 490      {
 491          global $db, $user;
 492  
 493          // yah, I would prefer a stronger rand, but this should work
 494          $this->question = (int) array_rand($this->question_ids);
 495          $this->solved = 0;
 496  
 497          $sql = 'UPDATE ' . $this->table_qa_confirm . '
 498              SET question_id = ' . (int) $this->question . ",
 499                  attempts = attempts + 1
 500              WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "'
 501                  AND session_id = '" . $db->sql_escape($user->session_id) . "'";
 502          $db->sql_query($sql);
 503  
 504          $this->load_answer();
 505      }
 506  
 507  
 508      /**
 509      * See if there is already an entry for the current session.
 510      */
 511  	function load_confirm_id()
 512      {
 513          global $db, $user;
 514  
 515          $sql = 'SELECT confirm_id
 516              FROM ' . $this->table_qa_confirm . "
 517              WHERE
 518                  session_id = '" . $db->sql_escape($user->session_id) . "'
 519                  AND lang_iso = '" . $db->sql_escape($this->question_lang) . "'
 520                  AND confirm_type = " . $this->type;
 521          $result = $db->sql_query_limit($sql, 1);
 522          $row = $db->sql_fetchrow($result);
 523          $db->sql_freeresult($result);
 524  
 525          if ($row)
 526          {
 527              $this->confirm_id = $row['confirm_id'];
 528              return true;
 529          }
 530          return false;
 531      }
 532  
 533      /**
 534      * Look up everything we need and populate the instance variables.
 535      */
 536  	function load_answer()
 537      {
 538          global $db, $user;
 539  
 540          if (!strlen($this->confirm_id) || !sizeof($this->question_ids))
 541          {
 542              return false;
 543          }
 544  
 545          $sql = 'SELECT con.question_id, attempts, question_text, strict
 546              FROM ' . $this->table_qa_confirm . ' con, ' . $this->table_captcha_questions . " qes
 547              WHERE con.question_id = qes.question_id
 548                  AND confirm_id = '" . $db->sql_escape($this->confirm_id) . "'
 549                  AND session_id = '" . $db->sql_escape($user->session_id) . "'
 550                  AND qes.lang_iso = '" . $db->sql_escape($this->question_lang) . "'
 551                  AND confirm_type = " . $this->type;
 552          $result = $db->sql_query($sql);
 553          $row = $db->sql_fetchrow($result);
 554          $db->sql_freeresult($result);
 555  
 556          if ($row)
 557          {
 558              $this->question = $row['question_id'];
 559  
 560              $this->attempts = $row['attempts'];
 561              $this->question_strict = $row['strict'];
 562              $this->question_text = $row['question_text'];
 563  
 564              return true;
 565          }
 566  
 567          return false;
 568      }
 569  
 570      /**
 571      *  The actual validation
 572      */
 573  	function check_answer()
 574      {
 575          global $db;
 576  
 577          $answer = ($this->question_strict) ? utf8_normalize_nfc(request_var('qa_answer', '', true)) : utf8_clean_string(utf8_normalize_nfc(request_var('qa_answer', '', true)));
 578  
 579          $sql = 'SELECT answer_text
 580              FROM ' . $this->table_captcha_answers . '
 581              WHERE question_id = ' . (int) $this->question;
 582          $result = $db->sql_query($sql);
 583  
 584          while ($row = $db->sql_fetchrow($result))
 585          {
 586              $solution = ($this->question_strict) ? $row['answer_text'] : utf8_clean_string($row['answer_text']);
 587  
 588              if ($solution === $answer)
 589              {
 590                  $this->solved = true;
 591  
 592                  break;
 593              }
 594          }
 595          $db->sql_freeresult($result);
 596  
 597          return $this->solved;
 598      }
 599  
 600      /**
 601      *  API function
 602      */
 603  	function get_attempt_count()
 604      {
 605          return $this->attempts;
 606      }
 607  
 608      /**
 609      *  API function
 610      */
 611  	function reset()
 612      {
 613          global $db, $user;
 614  
 615          $sql = 'DELETE FROM ' . $this->table_qa_confirm . "
 616              WHERE session_id = '" . $db->sql_escape($user->session_id) . "'
 617                  AND confirm_type = " . (int) $this->type;
 618          $db->sql_query($sql);
 619  
 620          // we leave the class usable by generating a new question
 621          $this->select_question();
 622      }
 623  
 624      /**
 625      *  API function
 626      */
 627  	function is_solved()
 628      {
 629          if (request_var('qa_answer', false) && $this->solved === 0)
 630          {
 631              $this->validate();
 632          }
 633  
 634          return (bool) $this->solved;
 635      }
 636  
 637      /**
 638      *  API function - The ACP backend, this marks the end of the easy methods
 639      */
 640  	function acp_page($id, &$module)
 641      {
 642          global $user, $template;
 643          global $config;
 644  
 645          $user->add_lang('acp/board');
 646          $user->add_lang('captcha_qa');
 647  
 648          if (!self::is_installed())
 649          {
 650              $this->install();
 651          }
 652  
 653          $module->tpl_name = 'captcha_qa_acp';
 654          $module->page_title = 'ACP_VC_SETTINGS';
 655          $form_key = 'acp_captcha';
 656          add_form_key($form_key);
 657  
 658          $submit = request_var('submit', false);
 659          $question_id = request_var('question_id', 0);
 660          $action = request_var('action', '');
 661  
 662          // we have two pages, so users might want to navigate from one to the other
 663          $list_url = $module->u_action . "&amp;configure=1&amp;select_captcha=" . $this->get_service_name();
 664  
 665          $template->assign_vars(array(
 666              'U_ACTION'        => $module->u_action,
 667              'QUESTION_ID'    => $question_id ,
 668              'CLASS'            => $this->get_service_name(),
 669          ));
 670  
 671          // show the list?
 672          if (!$question_id && $action != 'add')
 673          {
 674              $this->acp_question_list($module);
 675          }
 676          else if ($question_id && $action == 'delete')
 677          {
 678              if ($this->get_service_name() !== $config['captcha_plugin'] || !$this->acp_is_last($question_id))
 679              {
 680                  if (confirm_box(true))
 681                  {
 682                      $this->acp_delete_question($question_id);
 683  
 684                      trigger_error($user->lang['QUESTION_DELETED'] . adm_back_link($list_url));
 685                  }
 686                  else
 687                  {
 688                      confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array(
 689                          'question_id'        => $question_id,
 690                          'action'            => $action,
 691                          'configure'            => 1,
 692                          'select_captcha'    => $this->get_service_name(),
 693                          ))
 694                      );
 695                  }
 696              }
 697              else
 698              {
 699                  trigger_error($user->lang['QA_LAST_QUESTION'] . adm_back_link($list_url), E_USER_WARNING);
 700              }
 701          }
 702          else
 703          {
 704              // okay, show the editor
 705              $question_input = $this->acp_get_question_input();
 706              $langs = $this->get_languages();
 707  
 708              foreach ($langs as $lang => $entry)
 709              {
 710                  $template->assign_block_vars('langs', array(
 711                      'ISO' => $lang,
 712                      'NAME' => $entry['name'],
 713                  ));
 714              }
 715  
 716              $template->assign_vars(array(
 717                  'U_LIST' => $list_url,
 718              ));
 719  
 720              if ($question_id)
 721              {
 722                  if ($question = $this->acp_get_question_data($question_id))
 723                  {
 724                      $template->assign_vars(array(
 725                          'QUESTION_TEXT'        => ($question_input['question_text']) ? $question_input['question_text'] : $question['question_text'],
 726                          'LANG_ISO'            => ($question_input['lang_iso']) ? $question_input['lang_iso'] : $question['lang_iso'],
 727                          'STRICT'            => (isset($_REQUEST['strict'])) ? $question_input['strict'] : $question['strict'],
 728                          'ANSWERS'            => implode("\n", $question['answers']),
 729                      ));
 730                  }
 731                  else
 732                  {
 733                      trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url));
 734                  }
 735              }
 736              else
 737              {
 738                  $template->assign_vars(array(
 739                      'QUESTION_TEXT'        => $question_input['question_text'],
 740                      'LANG_ISO'            => $question_input['lang_iso'],
 741                      'STRICT'            => $question_input['strict'],
 742                      'ANSWERS'            => (is_array($question_input['answers'])) ? implode("\n", $question_input['answers']) : '',
 743                  ));
 744              }
 745  
 746              if ($submit && check_form_key($form_key))
 747              {
 748                  if (!$this->validate_input($question_input))
 749                  {
 750                      $template->assign_vars(array(
 751                          'S_ERROR'            => true,
 752                      ));
 753                  }
 754                  else
 755                  {
 756                      if ($question_id)
 757                      {
 758                          $this->acp_update_question($question_input, $question_id);
 759                      }
 760                      else
 761                      {
 762                          $this->acp_add_question($question_input);
 763                      }
 764  
 765                      add_log('admin', 'LOG_CONFIG_VISUAL');
 766                      trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($list_url));
 767                  }
 768              }
 769              else if ($submit)
 770              {
 771                  trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url), E_USER_WARNING);
 772              }
 773          }
 774      }
 775  
 776      /**
 777      *  This handles the list overview
 778      */
 779  	function acp_question_list(&$module)
 780      {
 781          global $db, $template;
 782  
 783          $sql = 'SELECT *
 784              FROM ' . $this->table_captcha_questions;
 785          $result = $db->sql_query($sql);
 786  
 787          $template->assign_vars(array(
 788              'S_LIST'            => true,
 789          ));
 790  
 791          while ($row = $db->sql_fetchrow($result))
 792          {
 793              $url = $module->u_action . "&amp;question_id={$row['question_id']}&amp;configure=1&amp;select_captcha=" . $this->get_service_name() . '&amp;';
 794  
 795              $template->assign_block_vars('questions', array(
 796                  'QUESTION_TEXT'        => $row['question_text'],
 797                  'QUESTION_ID'        => $row['question_id'],
 798                  'QUESTION_LANG'        => $row['lang_iso'],
 799                  'U_DELETE'            => "{$url}action=delete",
 800                  'U_EDIT'            => "{$url}action=edit",
 801              ));
 802          }
 803          $db->sql_freeresult($result);
 804      }
 805  
 806      /**
 807      *  Grab a question and bring it into a format the editor understands
 808      */
 809  	function acp_get_question_data($question_id)
 810      {
 811          global $db;
 812  
 813          if ($question_id)
 814          {
 815              $sql = 'SELECT *
 816                  FROM ' . $this->table_captcha_questions . '
 817                  WHERE question_id = ' . $question_id;
 818              $result = $db->sql_query($sql);
 819              $question = $db->sql_fetchrow($result);
 820              $db->sql_freeresult($result);
 821  
 822              if (!$question)
 823              {
 824                  return false;
 825              }
 826  
 827              $question['answers'] = array();
 828  
 829              $sql = 'SELECT *
 830                  FROM ' . $this->table_captcha_answers . '
 831                  WHERE question_id = ' . $question_id;
 832              $result = $db->sql_query($sql);
 833  
 834              while ($row = $db->sql_fetchrow($result))
 835              {
 836                  $question['answers'][] = $row['answer_text'];
 837              }
 838              $db->sql_freeresult($result);
 839  
 840              return $question;
 841          }
 842  
 843          return false;
 844      }
 845  
 846      /**
 847      *  Grab a question from input and bring it into a format the editor understands
 848      */
 849  	function acp_get_question_input()
 850      {
 851          $answers = utf8_normalize_nfc(request_var('answers', '', true));
 852  
 853          // Convert answers into array and filter if answers are set
 854          if (strlen($answers))
 855          {
 856              $answers = array_filter(array_map('trim', explode("\n", $answers)), function ($value) {
 857                  return $value !== '';
 858              });
 859          }
 860  
 861          $question = array(
 862              'question_text'    => request_var('question_text', '', true),
 863              'strict'        => request_var('strict', false),
 864              'lang_iso'        => request_var('lang_iso', ''),
 865              'answers'        => $answers,
 866          );
 867          return $question;
 868      }
 869  
 870      /**
 871      *  Update a question.
 872      * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data
 873      */
 874  	function acp_update_question($data, $question_id)
 875      {
 876          global $db, $cache;
 877  
 878          // easier to delete all answers than to figure out which to update
 879          $sql = 'DELETE FROM ' . $this->table_captcha_answers . " WHERE question_id = $question_id";
 880          $db->sql_query($sql);
 881  
 882          $langs = $this->get_languages();
 883          $question_ary = $data;
 884          $question_ary['lang_id'] = $langs[$question_ary['lang_iso']]['id'];
 885          unset($question_ary['answers']);
 886  
 887          $sql = 'UPDATE ' . $this->table_captcha_questions . '
 888              SET ' . $db->sql_build_array('UPDATE', $question_ary) . "
 889              WHERE question_id = $question_id";
 890          $db->sql_query($sql);
 891  
 892          $this->acp_insert_answers($data, $question_id);
 893  
 894          $cache->destroy('sql', $this->table_captcha_questions);
 895      }
 896  
 897      /**
 898      *  Insert a question.
 899      * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data
 900      */
 901  	function acp_add_question($data)
 902      {
 903          global $db, $cache;
 904  
 905          $langs = $this->get_languages();
 906          $question_ary = $data;
 907  
 908          $question_ary['lang_id'] = $langs[$data['lang_iso']]['id'];
 909          unset($question_ary['answers']);
 910  
 911          $sql = 'INSERT INTO ' . $this->table_captcha_questions . ' ' . $db->sql_build_array('INSERT', $question_ary);
 912          $db->sql_query($sql);
 913  
 914          $question_id = $db->sql_nextid();
 915  
 916          $this->acp_insert_answers($data, $question_id);
 917  
 918          $cache->destroy('sql', $this->table_captcha_questions);
 919      }
 920  
 921      /**
 922      *  Insert the answers.
 923      * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data
 924      */
 925  	function acp_insert_answers($data, $question_id)
 926      {
 927          global $db, $cache;
 928  
 929          foreach ($data['answers'] as $answer)
 930          {
 931              $answer_ary = array(
 932                  'question_id'    => $question_id,
 933                  'answer_text'    => $answer,
 934              );
 935  
 936              $sql = 'INSERT INTO ' . $this->table_captcha_answers . ' ' . $db->sql_build_array('INSERT', $answer_ary);
 937              $db->sql_query($sql);
 938          }
 939  
 940          $cache->destroy('sql', $this->table_captcha_answers);
 941      }
 942  
 943      /**
 944      *  Delete a question.
 945      */
 946  	function acp_delete_question($question_id)
 947      {
 948          global $db, $cache;
 949  
 950          $tables = array($this->table_captcha_questions, $this->table_captcha_answers);
 951  
 952          foreach ($tables as $table)
 953          {
 954              $sql = "DELETE FROM $table
 955                  WHERE question_id = $question_id";
 956              $db->sql_query($sql);
 957          }
 958  
 959          $cache->destroy('sql', $tables);
 960      }
 961  
 962      /**
 963      *  Check if the entered data can be inserted/used
 964      * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data
 965      */
 966  	function validate_input($question_data)
 967      {
 968          $langs = $this->get_languages();
 969  
 970          if (!isset($question_data['lang_iso']) ||
 971              !isset($question_data['question_text']) ||
 972              !isset($question_data['strict']) ||
 973              !isset($question_data['answers']))
 974          {
 975              return false;
 976          }
 977  
 978          if (!isset($langs[$question_data['lang_iso']]) ||
 979              !strlen($question_data['question_text']) ||
 980              !sizeof($question_data['answers']) ||
 981              !is_array($question_data['answers']))
 982          {
 983              return false;
 984          }
 985  
 986          return true;
 987      }
 988  
 989      /**
 990      * List the installed language packs
 991      */
 992  	function get_languages()
 993      {
 994          global $db;
 995  
 996          $sql = 'SELECT *
 997              FROM ' . LANG_TABLE;
 998          $result = $db->sql_query($sql);
 999  
1000          $langs = array();
1001          while ($row = $db->sql_fetchrow($result))
1002          {
1003              $langs[$row['lang_iso']] = array(
1004                  'name'    => $row['lang_local_name'],
1005                  'id'    => (int) $row['lang_id'],
1006              );
1007          }
1008          $db->sql_freeresult($result);
1009  
1010          return $langs;
1011      }
1012  
1013  
1014  
1015      /**
1016      *  See if there is a question other than the one we have
1017      */
1018  	function acp_is_last($question_id)
1019      {
1020          global $config, $db;
1021  
1022          if ($question_id)
1023          {
1024              $sql = 'SELECT question_id
1025                  FROM ' . $this->table_captcha_questions . "
1026                  WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'
1027                      AND  question_id <> " .  (int) $question_id;
1028              $result = $db->sql_query_limit($sql, 1);
1029              $question = $db->sql_fetchrow($result);
1030              $db->sql_freeresult($result);
1031  
1032              if (!$question)
1033              {
1034                  return true;
1035              }
1036              return false;
1037          }
1038      }
1039  }


Generated: Thu Jan 11 00:25:41 2018 Cross-referenced by PHPXref 0.7.1