View source
<?php
require_once drupal_get_path('module', 'phrase_captcha') . '/../text_captcha.inc';
define('PHRASE_CAPTCHA_GENERATE_NONSENSE_WORDS', 0);
define('PHRASE_CAPTCHA_USER_DEFINED_WORDS', 1);
function phrase_captcha_help($section) {
switch ($section) {
case 'admin/user/captcha/phrase_captcha':
return '<p>' . t('This phrase based CAPTCHA presents a CAPTCHA phrase of a given number of words and asks to pick the right word (based on counting, alphabetical order, etc).') . '</p>';
}
}
function phrase_captcha_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'admin/user/captcha/phrase_captcha',
'title' => t('Phrase CAPTCHA'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'phrase_captcha_settings_form',
),
'type' => MENU_LOCAL_TASK,
);
}
return $items;
}
function phrase_captcha_settings_form() {
$form = array();
$form['phrase_captcha_words'] = array(
'#type' => 'radios',
'#title' => t('Kind of words to use in the CAPTCHA phrase'),
'#options' => array(
PHRASE_CAPTCHA_GENERATE_NONSENSE_WORDS => t('Generate nonsense words'),
PHRASE_CAPTCHA_USER_DEFINED_WORDS => t('Use user defined words'),
),
'#default_value' => variable_get('phrase_captcha_words', PHRASE_CAPTCHA_GENERATE_NONSENSE_WORDS),
'#required' => TRUE,
);
_text_captcha_word_pool_form_items($form, 'phrase_captcha_userdefined_word_pool', t('User defined word pool'), t('Enter the words to use in the CAPTCHA phrase (space separated, no punctuation).'), '');
$form['phrase_captcha_word_quantity'] = array(
'#type' => 'select',
'#title' => t('Number of words in the CAPTCHA phrase'),
'#default_value' => (int) variable_get('phrase_captcha_word_quantity', 5),
'#options' => array(
4 => 4,
5 => 5,
6 => 6,
7 => 7,
8 => 8,
9 => 9,
10 => 10,
),
'#required' => TRUE,
);
$form['phrase_captcha_additional_word_quantity'] = array(
'#type' => 'select',
'#title' => t('Maximum number of additional words to let the user choose from'),
'#default_value' => (int) variable_get('phrase_captcha_additional_word_quantity', 1),
'#options' => array(
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => 4,
5 => 5,
),
'#required' => TRUE,
);
$form['phrase_captcha_word_selection_challenges'] = array(
'#type' => 'checkboxes',
'#title' => t('Word selection challenges'),
'#options' => _phrase_captcha_available_word_challenges(),
'#default_value' => _phrase_captcha_enabled_word_challenges(),
);
return system_settings_form($form);
}
function phrase_captcha_settings_form_validate($form_id, $form_values) {
if ($form_id == 'phrase_captcha_settings_form') {
if ($form_values['phrase_captcha_words'] == PHRASE_CAPTCHA_USER_DEFINED_WORDS) {
$word_count_minimum = (int) $form_values['phrase_captcha_word_quantity'] + (int) $form_values['phrase_captcha_additional_word_quantity'] + 2;
_text_captcha_word_pool_validate('phrase_captcha_userdefined_word_pool', $form_values, $word_count_minimum, NULL, NULL);
}
if (count(array_filter($form_values['phrase_captcha_word_selection_challenges'])) < 1) {
form_set_error('phrase_captcha_word_selection_challenges', t('You need to select at least one word selection criterium'));
}
}
}
function _phrase_captcha_generate_nonsense_word($characters) {
$vowels = 'bcdfghjklmnpqrstvwxyz';
$consonants = 'aeiou';
$vowel_max = strlen($vowels) - 1;
$consonant_max = strlen($consonants) - 1;
$word = '';
$o = mt_rand(0, 1);
for ($i = 0; $i < $characters; ++$i) {
if (($i + $o) % 2) {
$word .= $consonants[mt_rand(0, $consonant_max)];
}
else {
$word .= $vowels[mt_rand(0, $vowel_max)];
}
}
return $word;
}
function _phrase_captcha_generate_words($num) {
$words = array();
if (variable_get('phrase_captcha_words', PHRASE_CAPTCHA_GENERATE_NONSENSE_WORDS) == PHRASE_CAPTCHA_USER_DEFINED_WORDS) {
$uwords = _text_captcha_word_pool_get_content('phrase_captcha_userdefined_word_pool', NULL, '', TRUE);
switch ($num) {
case 0:
break;
case 1:
$words[] = $uwords[array_rand($uwords, $num)];
break;
default:
$keys = array_rand($uwords, $num);
foreach ($keys as $key) {
$words[] = $uwords[$key];
}
break;
}
}
else {
for ($w = 0; $w < $num; ++$w) {
$words[] = _phrase_captcha_generate_nonsense_word(mt_rand(3, 7));
}
}
return $words;
}
function _phrase_captcha_ordinal($n) {
$ordinalmap = array(
1 => t('first'),
2 => t('second'),
3 => t('third'),
4 => t('fourth'),
5 => t('fifth'),
6 => t('sixth'),
7 => t('seventh'),
8 => t('eighth'),
9 => t('ninth'),
10 => t('tenth'),
);
if (array_key_exists($n, $ordinalmap)) {
return $ordinalmap[$n];
}
else {
return "{$n}th";
}
}
function _phrase_captcha_available_word_challenges() {
return array(
'_phrase_captcha_word_question_word_index' => 'Word index',
'_phrase_captcha_word_question_alphabetical_misplaced' => 'Alphabetical misplacement',
'_phrase_captcha_word_question_double_occurence' => 'Double occurence',
);
}
function _phrase_captcha_enabled_word_challenges() {
$word_challenges = variable_get('phrase_captcha_word_selection_challenges', array());
if ($word_challenges) {
return array_keys(array_filter($word_challenges));
}
else {
return array_keys(_phrase_captcha_available_word_challenges());
}
}
function _phrase_captcha_word_question_word_index($words) {
$key = array_rand($words, 1);
$answer = $words[$key];
if (mt_rand(0, 1)) {
$description = t('What is the @nth word in the CAPTCHA phrase above?', array(
'@nth' => _phrase_captcha_ordinal($key + 1),
));
}
else {
$n = count($words) - $key;
if ($n == 1) {
$description = t('What is the last word in the CAPTCHA phrase above?');
}
else {
$description = t('What is the @nth last word in the CAPTCHA phrase above?', array(
'@nth' => _phrase_captcha_ordinal($n),
));
}
}
return array(
$words,
$description,
$answer,
);
}
function _phrase_captcha_word_question_alphabetical_misplaced($words) {
mt_rand(0, 1) ? sort($words) : rsort($words);
$from = $to = 0;
while (abs($from - $to) < 2) {
$from = array_rand($words, 1);
$to = array_rand($words, 1);
}
$answer = $words[$from];
unset($words[$from]);
array_splice($words, $to, 0, $answer);
$description = t('Which word does not follow the alphabetical order in the CAPTCHA phrase above?');
return array(
$words,
$description,
$answer,
);
}
function _phrase_captcha_word_question_double_occurence($words) {
$words = array_unique($words);
$key = array_rand($words, 1);
$answer = $words[$key];
while (($pos = array_rand($words, 1)) == $key) {
}
array_splice($words, $pos, 1, $answer);
$description = t('Which word occurs two times in the CAPTCHA phrase above?');
return array(
$words,
$description,
$answer,
);
}
function phrase_captcha_captcha($op, $captcha_type = '') {
switch ($op) {
case 'list':
return array(
'Phrase CAPTCHA',
);
case 'generate':
if ($captcha_type == 'Phrase CAPTCHA') {
$words = _phrase_captcha_generate_words((int) variable_get('phrase_captcha_word_quantity', 5));
$word_challenges = _phrase_captcha_enabled_word_challenges();
$key = array_rand($word_challenges);
$function = $word_challenges[$key];
list($phrase_words, $question, $solution) = call_user_func($function, $words);
$all_words = array_merge($words, _phrase_captcha_generate_words((int) variable_get('phrase_captcha_additional_word_quantity', 1)));
shuffle($all_words);
$options = array();
foreach ($all_words as $word) {
$options[$word] = $word;
}
$captcha = array();
$captcha['solution'] = $solution;
$captcha['form']['captcha_phrase'] = array(
'#type' => 'markup',
'#value' => '"' . implode(' ', $phrase_words) . '"',
'#weight' => -2,
);
$captcha['form']['captcha_response'] = array(
'#type' => 'radios',
'#title' => $question,
'#options' => $options,
'#attributes' => array(
'class' => 'text-captcha-word-list-radios',
),
'#DANGEROUS_SKIP_CHECK' => TRUE,
'#required' => TRUE,
);
drupal_add_css(drupal_get_path('module', 'phrase_captcha') . '/../text_captcha.css');
return $captcha;
}
}
}