abstract class BotchaRecipe in BOTCHA Spam Prevention 7.3
Same name and namespace in other branches
- 6.2 controller/botcha_recipe.controller.inc \BotchaRecipe
- 6.3 controller/recipe/botcha.recipe.controller.inc \BotchaRecipe
- 7.2 controller/botcha_recipe.controller.inc \BotchaRecipe
Abstract class to describe recipe data structure.
Hierarchy
- class \BotchaRecipe
Expanded class hierarchy of BotchaRecipe
File
- controller/
recipe/ botcha.recipe.controller.inc, line 60 - Controller layer of the BotchaRecipe objects.
View source
abstract class BotchaRecipe {
/**
* Identifier of the recipe.
*/
public $id;
/**
* Brief description of the recipe.
* It should contain explanation of how bots would fail with it
* and what the recipe exactly does.
*/
protected $description;
/**
* Options that received as parameters turned into settings
* by merging with default values.
*/
protected $settings = array();
/**
* Secret.
*/
protected $secret;
/**
* Method of recipe genration.
*/
protected $method;
/**
* CSS to add to the page.
*/
protected $css;
/**
* Javascript to add to the page.
*/
protected $js;
/**
* Name of the field in the form to use in error messages
* (to mask botcha fields).
*/
public $error_field;
/**
* Text to give users if botcha recipe blocks submission.
* It should give some help to real human users in cases
* of disabled Javascript or CSS.
*/
public $error_text;
protected $recipebooks = array();
public function setRecipebook($rbid) {
$this->recipebooks[$rbid] = $rbid;
return $this;
}
public function setTitle($title) {
$this->title = $title;
return $this;
}
public function getTitle() {
return $this->title;
}
public function setDescription($description) {
$this->description = $description;
return $this;
}
public function getDescription() {
return $this->description;
}
public function setSecret($secret) {
$this->secret = $secret;
return $this;
}
public function getSecret($build_id = NULL) {
if (empty($this->secret) || !empty($build_id)) {
$this->secret = md5($build_id . BOTCHA_SECRET);
}
return $this->secret;
}
public function setMethod($method) {
$this->method = $method;
return $this;
}
public function getMethod() {
return $this->method;
}
// @todo ?Do we need it?
public function getSetting($key, $default = NULL) {
return !empty($this->settings[$key]) ? $this->settings[$key] : $default;
}
// @todo ?Do we need it?
public function setSetting($key, $value) {
$this->settings[$key] = $value;
return $this;
}
/**
* Magic method __construct.
*/
public function __construct($id) {
$this->id = $id;
// Get human-readable description about this recipe
// to clarify its work process.
$this
->getInfo();
}
/**
* Used to get information about the recipe.
* Must be overridden.
*/
public function getInfo() {
$this->error_field = 'mail';
$this->error_text = t('You must be a human, not a spam bot, to submit forms on this website.') . ' ' . t('If you insist that you are a human, please try again.') . ' ' . t('If error persists, contact webmaster using contact link at the bottom of this page and give all the details of this error (your browser, version, OS).');
}
/**
* Used to get default recipe data structure.
* @todo ?Do we need it?
*/
public function getDefaultSettings() {
return array(
'fields' => $this
->getFields(),
'css' => $this
->getCss(),
'js' => $this
->getJs(),
);
}
/**
* Universal getter.
* Wrapper getProperty is used to let class methods be used not only in getting
* default settings. It gives flexibility to make calls to the class methods
* in any order: the first of them will always calculate the property value
* and set the setting, while others will just get this already calculated value.
* It also provides consistency: we are sure that when we get some property,
* it is set appropriately.
* @todo ?Do we need it?
*/
protected function getProperty(&$value, $getter_callback, $parameters = NULL) {
if (empty($value)) {
$value = $this
->{$getter_callback}($parameters);
}
return $value;
}
/*
* Apply recipe modifying form properties.
*/
public function apply(&$form, &$form_state) {
$this
->prepare($form, $form_state);
// Apply recipe to the concrete form.
// Add BOTCHA fields to the form.
$form_elements = $this
->generateFormElements();
foreach ($form_elements as $field_name => $field_properties) {
unset($field_properties['!valid_token']);
$form[$field_name] = $field_properties;
if ($this->method == 'build_id_submit') {
// Save submitted values in our stash for later use in _validate,
// as we have to reset them here at _form_alter stage.
// It won't be possible to reset after validation as there is no
// reliable mechanism in Form API, i.e. form_set_value() does not
// change rendered form and form errors disable whole 'rebuild' business.
if (isset($_POST[$field_name])) {
$form_state['botcha_submit_values'][$field_name] = $_POST[$field_name];
}
if (isset($field_properties['#default_value'])) {
// Reset our controls to defaults here (as explained above).
$form[$field_name]['#value'] = $field_properties['#default_value'];
$form_state['post'][$field_name] = $field_properties['#default_value'];
$_POST[$field_name] = $field_properties['#default_value'];
}
}
else {
//unset($field_properties['!valid_token']);
}
}
}
protected function prepare($form, $form_state) {
if (!empty($_POST['form_build_id'])) {
$build_id = $_POST['form_build_id'];
$method = 'build_id_submit';
}
else {
$build_id = $form['#build_id'];
$method = 'build_id';
}
$secret = $this
->getSecret($build_id);
// Set necessary parameters.
$this
->setSecret($secret)
->setMethod($method);
}
/**
* Spam check.
*
* @param array $form
* @param array $form_state
*/
public function isSpam($form, $form_state) {
$this
->prepare($form, $form_state);
return FALSE;
}
/**
* Handle form depending on the result of spam check.
*
* @param string $result
* @param array $form
* @param array $form_state
*/
public function handle($result, $form, $form_state) {
$this
->prepare($form, $form_state);
switch ($result) {
case 'success':
break;
case 'spam':
default:
form_set_error($this->error_field, $this->error_text);
break;
}
}
protected function getSeed() {
return md5(get_class($this) . substr($this->secret, 0, -4));
}
protected function getFields() {
$fields_count = $this
->getFieldCount();
$fields = array();
for ($i = 0; $i < $fields_count; $i++) {
$fields[$i] = $this
->getField($i);
}
return $fields;
}
// @todo Replace deltas with machine names for better readability.
// @see?
protected function getField($delta) {
return array(
'name' => $this
->getProperty($this->settings['fields'][$delta]['name'], 'getFieldName', $delta),
'class' => $this
->getProperty($this->settings['fields'][$delta]['class'], 'getFieldClass', $delta),
'prefix' => $this
->getProperty($this->settings['fields'][$delta]['prefix'], 'getFieldPrefix', $delta),
);
}
/**
* Should be overridden.
*
* @return string
*/
public function getCss() {
}
/**
* Should be overridden.
*
* @return array
*/
public function getJs() {
}
// @todo Replace deltas with machine names for better readability.
// @see?
protected function getFieldName($delta) {
return substr($this
->getProperty($this->seed, 'getSeed'), 0, 3) . '_name';
}
// @todo Replace deltas with machine names for better readability.
// @see?
protected function getFieldClass($delta) {
// 'a' fix for Firefox - it breaks on ".<number>" class in CSS filter!
return 'a' . substr($this
->getProperty($this->seed, 'getSeed'), 1, 4) . '_field';
}
// @todo Replace deltas with machine names for better readability.
// @see?
protected function getFieldPrefix($delta) {
return substr($this
->getProperty($this->seed, 'getSeed'), 10, mt_rand(3, 6));
}
/**
* Used to get information about the recipe.
* Must be overridden with calling to parent::generateFormElements.
* @todo Switch from indexed array to associative.
* @see?
*/
public function generateFormElements() {
$css = $this
->getProperty($this->settings['css'], 'getCss');
if (!empty($css)) {
// @todo Abstract it.
//drupal_set_html_head('<style type="text/css">' . $css . '</style>');
drupal_add_css("{$this->settings['css']}", array(
'type' => 'inline',
));
}
return array();
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
BotchaRecipe:: |
protected | property | CSS to add to the page. | |
BotchaRecipe:: |
protected | property | Brief description of the recipe. It should contain explanation of how bots would fail with it and what the recipe exactly does. | |
BotchaRecipe:: |
public | property | Name of the field in the form to use in error messages (to mask botcha fields). | |
BotchaRecipe:: |
public | property | Text to give users if botcha recipe blocks submission. It should give some help to real human users in cases of disabled Javascript or CSS. | |
BotchaRecipe:: |
public | property | Identifier of the recipe. | |
BotchaRecipe:: |
protected | property | Javascript to add to the page. | |
BotchaRecipe:: |
protected | property | Method of recipe genration. | |
BotchaRecipe:: |
protected | property | ||
BotchaRecipe:: |
protected | property | Secret. | |
BotchaRecipe:: |
protected | property | Options that received as parameters turned into settings by merging with default values. | |
BotchaRecipe:: |
public | function | 1 | |
BotchaRecipe:: |
public | function | Used to get information about the recipe. Must be overridden with calling to parent::generateFormElements. @todo Switch from indexed array to associative. @see? | 2 |
BotchaRecipe:: |
public | function | Should be overridden. | 1 |
BotchaRecipe:: |
public | function | Used to get default recipe data structure. @todo ?Do we need it? | |
BotchaRecipe:: |
public | function | ||
BotchaRecipe:: |
protected | function | 1 | |
BotchaRecipe:: |
protected | function | ||
BotchaRecipe:: |
protected | function | 3 | |
BotchaRecipe:: |
protected | function | ||
BotchaRecipe:: |
protected | function | ||
BotchaRecipe:: |
public | function | Used to get information about the recipe. Must be overridden. | 3 |
BotchaRecipe:: |
public | function | Should be overridden. | 1 |
BotchaRecipe:: |
public | function | ||
BotchaRecipe:: |
protected | function | Universal getter. Wrapper getProperty is used to let class methods be used not only in getting default settings. It gives flexibility to make calls to the class methods in any order: the first of them will always calculate the property value and set… | |
BotchaRecipe:: |
public | function | ||
BotchaRecipe:: |
protected | function | ||
BotchaRecipe:: |
public | function | ||
BotchaRecipe:: |
public | function | ||
BotchaRecipe:: |
public | function | Handle form depending on the result of spam check. | 1 |
BotchaRecipe:: |
public | function | Spam check. | 4 |
BotchaRecipe:: |
protected | function | 1 | |
BotchaRecipe:: |
public | function | ||
BotchaRecipe:: |
public | function | ||
BotchaRecipe:: |
public | function | ||
BotchaRecipe:: |
public | function | ||
BotchaRecipe:: |
public | function | ||
BotchaRecipe:: |
public | function | ||
BotchaRecipe:: |
public | function | Magic method __construct. |