View source
<?php
module_load_include('inc', 'botcha', 'controller/botcha.controller');
define('BOTCHA_LOG', 'BOTCHA');
define('BOTCHA_LOGLEVEL', variable_get('botcha_loglevel', 2));
function botcha_help($path, $arg) {
switch ($path) {
case 'admin/help#botcha':
$output = '<p>' . t('"BOTCHA" is an acronym for "BOT Computerized Heuristic Analysis". It is a method of protection from automated form submissions by performing analysis of submitted data that determines whether the user is a bot. The BOTCHA module is a tool to fight automated submission by malicious users that utilize automated form submission (e.g. for spamming) of for example comments forms, user registration forms, guestbook forms, etc. BOTCHA inserts elements into the desired forms that will not be shown to normal users. These elements have no impact on humans and require no puzzles to solve, but they are easy enough for automated scripts and spam bots to trip on.') . '</p>';
return $output;
case Botcha::BOTCHA_ADMIN_PATH:
$output = t('A BOTCHA protection consists of these parts:
<ul>
<li><b>Forms</b>: By default BOTCHA protection is enabled for concrete list of forms. Those forms that are not in the list are not protected. You could manage the list of protected forms on <a href="@forms_page">Forms</a> page.</li>
<li><b>Recipe books</b>: Recipe books are containers for recipes. You could use them to organize your defense lines against spam. To control your recipe books go to <a href="@recipebooks_page">Recipe books</a> page.</li>
<li><b>Recipes</b>: Each recipe has its own method to differ a human visitor and a spam bot. Some of them are flexible enough to provide UI for controlling its behavior. See the list of available recipes on <a href="@recipes_page">Recipes</a> page.</li>
</ul>', array(
'@forms_page' => url(Botcha::BOTCHA_ADMIN_PATH . '/form'),
'@recipebooks_page' => url(Botcha::BOTCHA_ADMIN_PATH . '/recipebook'),
'@recipes_page' => url(Botcha::BOTCHA_ADMIN_PATH . '/recipe'),
));
return $output;
case Botcha::BOTCHA_ADMIN_PATH . '/form':
$output = '<p>' . t('A BOTCHA protection can be added to virtually each Drupal form. Some default forms are already provided in the form list and more can be added using form internal name.') . '</p>';
$output .= '<p>' . t('All existing forms can be easily added and managed when the option "%adminlinks" is enabled.', array(
'%adminlinks' => t('Add BOTCHA administration links to forms'),
)) . '</p>';
if (module_exists('captcha')) {
$output .= '<p>' . t('Other forms will be added automatically based on CAPTCHA settings when the option "%usecaptcha" is enabled.', array(
'%usecaptcha' => t('Add BOTCHA to forms selected for CAPTCHA'),
)) . '</p>';
}
$output .= '<p>' . t('Forms served to users with the "%skipbotcha" <a href="@perm">permission</a> won\'t be protected. Be sure to grant this permission to the trusted users (e.g. site administrators). If you want to test a protected form, be sure to do it as a user without the "%skipbotcha" permission (e.g. as anonymous user).', array(
'%skipbotcha' => t('skip BOTCHA'),
'@perm' => url('admin/people/permissions/list', array(
'fragment' => 'module-' . 'botcha',
)),
)) . '</p>';
$output .= '<p>' . t('Select which forms to protect with BOTCHA.');
return $output;
case Botcha::BOTCHA_ADMIN_PATH . '/recipebook':
$output = t('Recipe book is a glue that connects all the parts. Each recipe book is binded to the forms in one hand and to the recipes - in another.');
return $output;
}
}
function botcha_menu() {
$items = array();
$items[Botcha::BOTCHA_ADMIN_PATH] = array(
'title' => 'BOTCHA',
'description' => 'Administer how and where BOTCHAs are used.',
'file' => 'botcha.admin.inc',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'botcha_admin_settings',
),
'access arguments' => array(
'administer BOTCHA settings',
),
'type' => MENU_NORMAL_ITEM,
);
$items[Botcha::BOTCHA_ADMIN_PATH . '/general'] = array(
'title' => 'General',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
$items[Botcha::BOTCHA_ADMIN_PATH . '/form'] = array(
'title' => 'Forms',
'description' => 'Administer BOTCHA forms.',
'file' => 'botcha.admin.inc',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'botcha_forms_form',
),
'access arguments' => array(
'administer BOTCHA settings',
),
'type' => MENU_LOCAL_TASK,
);
$items[Botcha::BOTCHA_ADMIN_PATH . '/form/add'] = array(
'title' => 'Add BOTCHA protection to form',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'botcha_form_form',
),
'access arguments' => array(
'administer BOTCHA settings',
),
'file' => 'botcha.admin.inc',
'type' => MENU_LOCAL_ACTION,
);
$items[Botcha::BOTCHA_ADMIN_PATH . '/form/%botcha_form'] = array(
'title' => 'BOTCHA form administration',
'file' => 'botcha.admin.inc',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'botcha_form_form',
5,
),
'access callback' => 'botcha_form_access',
'access arguments' => array(
5,
),
'type' => MENU_CALLBACK,
);
$items[Botcha::BOTCHA_ADMIN_PATH . '/form/%botcha_form/edit'] = array(
'title' => 'Edit',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => 1,
);
$items[Botcha::BOTCHA_ADMIN_PATH . '/form/%botcha_form/delete'] = array(
'title' => 'Delete',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'botcha_form_delete_form',
5,
),
'access callback' => 'botcha_form_access',
'access arguments' => array(
5,
),
'file' => 'botcha.admin.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 4,
);
$items[Botcha::BOTCHA_ADMIN_PATH . '/recipebook'] = array(
'title' => 'Recipe books',
'description' => 'Administer BOTCHA recipe books.',
'file' => 'botcha.admin.inc',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'botcha_recipebooks_form',
),
'access arguments' => array(
'administer BOTCHA settings',
),
'type' => MENU_LOCAL_TASK,
);
$items[Botcha::BOTCHA_ADMIN_PATH . '/recipebook/add'] = array(
'title' => 'Add recipe book',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'botcha_recipebook_form',
),
'access arguments' => array(
'administer BOTCHA settings',
),
'file' => 'botcha.admin.inc',
'type' => MENU_LOCAL_ACTION,
);
$items[Botcha::BOTCHA_ADMIN_PATH . '/recipebook/%botcha_recipebook'] = array(
'title callback' => 'botcha_recipebook_title',
'title arguments' => array(
5,
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'botcha_recipebook_form',
5,
),
'access callback' => 'botcha_recipebook_access',
'access arguments' => array(
5,
),
'file' => 'botcha.admin.inc',
'type' => MENU_NORMAL_ITEM,
);
$items[Botcha::BOTCHA_ADMIN_PATH . '/recipebook/%botcha_recipebook/edit'] = array(
'title' => 'Edit',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => 1,
);
$items[Botcha::BOTCHA_ADMIN_PATH . '/recipebook/%botcha_recipebook/delete'] = array(
'title' => 'Delete',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'botcha_recipebook_delete_form',
5,
),
'access callback' => 'botcha_recipebook_access',
'access arguments' => array(
5,
),
'file' => 'botcha.admin.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 4,
);
$items[Botcha::BOTCHA_ADMIN_PATH . '/recipe'] = array(
'title' => 'Recipes',
'description' => 'Administer BOTCHA recipes.',
'file' => 'botcha.admin.inc',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'botcha_recipes_form',
),
'access arguments' => array(
'administer BOTCHA settings',
),
'type' => MENU_LOCAL_TASK,
);
return $items;
}
function botcha_form_load($form_id) {
return Botcha::getForm($form_id, FALSE);
}
function botcha_form_access($botcha_form) {
$access = user_access('administer BOTCHA settings');
if (in_array($botcha_form->id, array(
'update_script_selection_form',
'user_login',
'user_login_block',
)) && in_array($botcha_form
->getRecipebook()->id, array(
'forbidden_forms',
))) {
$access = FALSE;
}
return $access;
}
function botcha_recipebook_load($rbid) {
return Botcha::getRecipebook($rbid, FALSE);
}
function botcha_recipebook_access($recipebook) {
$access = user_access('administer BOTCHA settings');
if (in_array($recipebook->id, array(
'forbidden_forms',
))) {
$access = FALSE;
}
return $access;
}
function botcha_recipebook_title($recipebook) {
return "Edit recipe book \"{$recipebook->title}\"";
}
function botcha_permission() {
return array(
'administer BOTCHA settings' => array(
'title' => t('Administer BOTCHA settings'),
),
'skip BOTCHA' => array(
'title' => t('Skip BOTCHA'),
'description' => t('Users with this permission will not be subjected to BOTCHA.'),
),
);
}
function botcha_theme() {
return array(
'botcha_forms_form_botcha_forms' => array(
'render element' => 'form',
'file' => 'botcha.admin.inc',
),
'botcha_recipebooks_form' => array(
'render element' => 'form',
'file' => 'botcha.admin.inc',
),
);
}
function botcha_form_alter(&$form, &$form_state, $form_id) {
$botcha_form = Botcha::getForm($form_id, FALSE);
if ($botcha_form
->isEnabled()) {
$botcha_form
->addAdminLinks($form);
$recipebook = $botcha_form
->getRecipebook();
if ($recipebook
->isApplicable($form, $form_state)) {
$recipebook
->apply($form, $form_state);
}
}
}
function _botcha_variables($i18n = FALSE) {
$ret = array();
if (!$i18n) {
$ret += array(
'botcha_secret',
'botcha_loglevel',
'botcha_form_passed_counter',
'botcha_form_blocked_counter',
);
}
return $ret;
}
function _botcha_i18n() {
$variables = _botcha_variables(TRUE);
$i18n_variables = variable_get('i18n_variables', array());
if (in_array($variables[0], $i18n_variables)) {
return;
}
$i18n_variables = array_merge($i18n_variables, $variables);
variable_set('i18n_variables', $i18n_variables);
}
function _botcha_form_validate($form, &$form_state) {
unset($form_state['values']['']);
$botcha_form = Botcha::getForm($form['form_id']['#value'], FALSE);
if ($botcha_form
->isEnabled()) {
$recipebook = $botcha_form
->getRecipebook();
if ($recipebook
->isApplicable($form, $form_state)) {
if ($recipebook
->isSpam($form, $form_state)) {
$recipebook
->handle('spam', $form, $form_state);
}
else {
$recipebook
->handle('success', $form, $form_state);
}
}
}
}