[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/includes/captcha/plugins/ -> phpbb_captcha_qa_plugin.php (source)

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


Generated: Wed Oct 2 15:03:47 2013 Cross-referenced by PHPXref 0.7.1