View source
<?php
define('BOTCHA_SECRET', variable_get('botcha_secret', '3288039533f40382398a85d52a8da366'));
function _botcha_error_text() {
return 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).');
}
function _botcha_error_text_javascript() {
return t('Please enable Javascript to use this form.');
}
function _botcha_error_text_errorcode($seed) {
return t('Error #@err.', array(
'@err' => substr($seed, 1, 2) . substr($seed, 1, 1) . substr($seed, 2, 1) . substr($seed, 5, 2) . substr($seed, 6, 1) . substr($seed, 0, 1),
));
}
function _botcha_error_noscript() {
return '<noscript>' . t('Please enable Javascript to use this form.') . '</noscript>';
}
function _botcha_pick_patsy_field($form, $fields) {
if (!is_array($fields)) {
$fields = array(
$fields,
);
}
foreach ($fields as $field) {
return $field;
}
}
function _botcha_url($url, $options = array()) {
global $base_url;
$path = '';
$query = '';
$abs_base = $base_url . '/';
$absolute = 0 === strpos($url, $abs_base);
$base = $absolute ? $abs_base_url : base_path();
$url = 0 === strpos($url, $base) ? substr($url, strlen($base)) : ltrim($url, '/');
extract(parse_url(urldecode($url)));
if (!empty($query) && !is_array($query)) {
$params = explode('&', $query);
$query = array();
foreach ($params as $param) {
$param = explode('=', $param, 2);
$query[$param[0]] = isset($param[1]) ? rawurldecode($param[1]) : '';
}
}
foreach ($options as $key => $value) {
${$key} = is_array($value) && is_array(${$key}) ? array_merge(${$key}, $value) : $value;
}
$fragment = !empty($fragment) ? '#' . $fragment : '';
if (is_array($query)) {
$query = drupal_query_string_encode($query);
}
$prefix = !empty($prefix) ? $prefix : '';
$prefix = empty($path) ? rtrim($prefix, '/') : $prefix;
$path = drupal_urlencode($prefix . $path);
if (variable_get('clean_url', '0')) {
$result = !empty($query) ? $base . $path . '?' . $query . $fragment : $base . $path . $fragment;
}
else {
$variables = array();
if (!empty($path)) {
$variables[] = 'q=' . $path;
}
if (!empty($query)) {
$variables[] = $query;
}
$query = join('&', $variables);
if (!empty($query)) {
static $script;
if (!isset($script)) {
$script = strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') === FALSE ? 'index.php' : '';
}
$result = $base . $script . '?' . $query . $fragment;
}
else {
$result = $base . $fragment;
}
}
return $result;
}
function _botcha_recipe_test1($form, $secret, $error_field) {
$myseed = 'itr_r2' . substr($secret, 0, 7);
$spf = md5($myseed . substr('secret', 0, -4));
$field_class = 'botcha_field';
$field_name = 'botcha_response';
$secure_token = 'Test 123';
$field_dflt = 'Test 123';
$recipe = new stdClass();
$recipe->name = 'test_honeypot_field';
$recipe->description = t('Insert CSS+honeypot field');
$recipe->description_bots = t('Bots will will mess with the field value');
$recipe->description_how = t('%parts is added to the form.', array(
'%parts' => t('Honeypot field') . ',CSS',
)) . ' ' . t('CSS hides the input field.');
$recipe->error_field = $error_field;
$recipe->error_text = _botcha_error_text_errorcode($spf) . '<li>' . _botcha_error_text();
$recipe->form_elements = array(
$field_name => array(
'#type' => 'textfield',
'#title' => t('Enter your name'),
'#default_value' => $field_dflt,
'#description' => t('Your first name.'),
'#prefix' => '<div class="' . $field_class . '">' . '<span class="description"> (' . t('If you\'re a human, don\'t change the following field') . ')</span>',
'#suffix' => '</div>',
'#attributes' => array(
'class' => $field_class,
'autocomplete' => 'off',
),
'#weight' => -20,
'!valid_token' => $secure_token,
),
);
$recipe->css = 'div.' . $field_class . ' { display: none; visibility: hidden; }';
return $recipe;
}
function _botcha_recipe1($form, $secret, $error_field) {
$myseed = 'itr_r1' . substr($secret, 0, 7);
$spf = md5($myseed . substr('secret', 0, -4));
$recipe = new stdClass();
$recipe->name = 'noresubmit';
$recipe->description = t('Prevent form resubmission');
$recipe->description_bots = t('Bots will try to resubmit old form');
$recipe->description_how = t('prepared form is remembered, and only one submission is allowed.');
$recipe->error_field = $error_field;
$recipe->error_text = t('Form session reuse detected.') . ' ' . t('An old form was submitted again, which may happen if it was retrieved from browser history using "Back" button.') . '<br />' . t('Please try again - fill all entries on this page without going "Back".');
$recipe->proc = 'check_cache';
return $recipe;
}
function _botcha_recipe2($form, $secret, $error_field) {
$myseed = 'itr_r2' . substr($secret, 0, 7);
$spf = md5($myseed . substr('secret', 0, -4));
$field_class = 'a' . substr($spf, 1, 4) . '_field';
$field_name = substr($spf, 0, 3) . '_name';
$field_prefx = substr($spf, 10, mt_rand(3, 6));
$secure_token = substr($spf, 4, -2) . '_form';
$js_name = substr($myseed, 0, 10) . substr($spf, 6, 8);
$chop1 = 2;
$chop2 = mt_rand(5, 8);
$js_tok1 = substr($secure_token, 0, $chop1);
$field_dflt = $field_prefx . substr($secure_token, $chop1, $chop2);
$js_tok2 = substr($secure_token, $chop1 + $chop2);
$js_match = substr($field_dflt, 0, strlen($field_prefx) + mt_rand(2, $chop2));
$js_pos = strlen($field_prefx);
$recipe = new stdClass();
$recipe->name = 'honeypot_js_field';
$recipe->description = t('Insert JS+CSS+honeypot field');
$recipe->description_bots = t('Bots will not run JS or will mess with the field value');
$recipe->description_how = t('%parts is added to the form.', array(
'%parts' => t('Honeypot field') . ',CSS , JS',
)) . ' ' . t('CSS hides the input field.') . ' ' . t('JS enters key value into the field.');
$recipe->error_field = $error_field;
$recipe->error_text = _botcha_error_text_errorcode($spf) . '<li>' . _botcha_error_text_javascript() . '<li>' . _botcha_error_text();
$recipe->form_elements = array(
$field_name => array(
'#type' => 'textfield',
'#title' => t('Enter your name'),
'#default_value' => $field_dflt,
'#description' => t('Your first name.'),
'#prefix' => '<div class="' . $field_class . '">' . '<span class="description"> (' . t('If you\'re a human, don\'t change the following field') . ')</span>',
'#suffix' => '</div>' . _botcha_error_noscript(),
'#attributes' => array(
'class' => $field_class,
'autocomplete' => 'off',
),
'#weight' => -20,
'!valid_token' => $secure_token,
),
);
$selector = "input.{$field_class}";
$recipe->css = 'div.' . $field_class . ' { display: none; visibility: hidden; }';
$recipe->js = <<<END
Drupal.behaviors.{<span class="php-variable">$js_name</span>} = function() {
\$("{<span class="php-variable">$selector</span>}").each(function() {
f=\$(this)[0];
if (f.value.indexOf("{<span class="php-variable">$js_match</span>}")==0){f.value="{<span class="php-variable">$js_tok1</span>}"+f.value.substring({<span class="php-variable">$js_pos</span>})+"{<span class="php-variable">$js_tok2</span>}";}
});
};
END;
return $recipe;
}
function _botcha_recipe3($form, $secret, $error_field) {
$form_id = $form['#id'];
if (strpos($form_id, '-node-form') !== false) {
$js_form_id = 'node-form';
}
else {
$js_form_id = $form_id;
}
$myseed = 'itr_r3' . substr($secret, 0, 7);
$spf = md5($myseed . substr('secret', 0, -4));
$field_class = 'a' . substr($spf, 1, 4) . '_field';
$field_name = substr($spf, 0, 3) . '_name';
$field_name_url = substr($spf, 1, 4) . '_name';
$field_prefx = substr($spf, 10, mt_rand(3, 6));
$secure_token = substr($spf, 4, -2) . '_form';
$js_name = substr($myseed, 0, 10) . substr($spf, 6, 8);
$chop1 = 2;
$chop2 = mt_rand(5, 8);
$js_tok1 = substr($secure_token, 0, $chop1);
$field_dflt = $field_prefx . substr($secure_token, $chop1, $chop2);
$js_tok2 = substr($secure_token, $chop1 + $chop2);
$js_match = substr($field_dflt, 0, strlen($field_prefx) + mt_rand(2, $chop2));
$js_pos = strlen($field_prefx);
$recipe = new stdClass();
$recipe->name = 'obscure_url_field';
$recipe->description = t('Insert a new field into form action URL');
$recipe->description_bots = t('Bots will not run JS and miss the field');
$recipe->description_how = t('%parts is added to the form.', array(
'%parts' => 'JS',
)) . ' ' . t('JS enters key value into the field.');
$recipe->error_field = $error_field;
$recipe->error_text = _botcha_error_text_errorcode($spf) . '<li>' . _botcha_error_text_javascript() . '<li>' . _botcha_error_text();
$recipe->form_elements = array(
$field_name => array(
'#type' => 'hidden',
'#default_value' => $field_dflt,
'#attributes' => array(
'class' => $field_class,
),
'#weight' => 20,
),
);
$recipe->url_elements = array(
$field_name_url => array(
'#type' => 'textfield',
'#default_value' => '',
'!valid_token' => $secure_token,
),
);
$selector = "input.{$field_class}";
$submit = _botcha_url($form['#action'], array(
'query' => array(
$field_name_url => '__replace__',
),
));
$submit = preg_replace('/__replace__/', $js_tok1 . '\'+v+\'' . $js_tok2, $submit);
$recipe->js = <<<END
Drupal.behaviors.{<span class="php-variable">$js_name</span>} = function() {
\$("{<span class="php-variable">$selector</span>}").each(function() {
f=\$(this)[0];
if (f.value.indexOf("{<span class="php-variable">$js_match</span>}")==0){
v=f.value.substring({<span class="php-variable">$js_pos</span>});
form=\$(this).parents("form#{<span class="php-variable">$js_form_id</span>}")[0];
\$(form)[0].action ='{<span class="php-variable">$submit</span>}';
}
});
};
END;
return $recipe;
}
function _botcha_recipe4($form, $secret, $error_field) {
$myseed = 'itr_r4' . substr($secret, 0, 8);
$spf = md5($myseed . substr('secret', 0, -4));
$field_class = 'a' . substr($spf, 1, 4) . '_field';
$field_name = substr($spf, 0, 3) . '_name';
$field_prefx = substr($spf, 10, mt_rand(3, 6));
$secure_token = substr($spf, 4, -2) . '_form';
$js_name = substr($myseed, 0, 10) . substr($spf, 6, 8);
$chop1 = 2;
$chop2 = mt_rand(5, 8);
$js_tok1 = substr($secure_token, 0, $chop1);
$field_dflt = $field_prefx . substr($secure_token, $chop1, $chop2);
$css_tok2 = substr($secure_token, $chop1 + $chop2);
$js_match = substr($field_dflt, 0, strlen($field_prefx) + mt_rand(2, $chop2));
$js_pos = strlen($field_prefx);
$recipe = new stdClass();
$recipe->name = 'honeypot_js_css2field';
$recipe->description = t('Insert JS+CSS+honeypot field');
$recipe->description_bots = t('Bots will not run JS or not load CSS or will mess with the field value');
$recipe->description_how = t('%parts is added to the form.', array(
'%parts' => t('Honeypot field') . ',CSS , JS',
)) . ' ' . t('CSS carries secret data and hides the input field.') . ' ' . t('JS enters key value into the field.');
$recipe->error_field = $error_field;
$recipe->error_text = _botcha_error_text_errorcode($spf) . '<li>' . _botcha_error_text_javascript() . '<li>' . _botcha_error_text();
$recipe->form_elements = array(
$field_name => array(
'#type' => 'textfield',
'#title' => t('Enter your name'),
'#default_value' => $field_dflt,
'#description' => t('Your first name.'),
'#prefix' => '<div class="' . $field_class . '">' . '<span class="description"> (' . t('If you\'re a human, don\'t change the following field') . ')</span>',
'#suffix' => '</div>' . _botcha_error_noscript(),
'#attributes' => array(
'class' => $field_class,
'autocomplete' => 'off',
),
'#weight' => -20,
'!valid_token' => $secure_token,
),
);
$selector = "input.{$field_class}";
$recipe->css = 'div.' . $field_class . ' { display: none; visibility: hidden; } input.' . $field_class . ' { font-family: sans-serif,"' . $css_tok2 . '" !important; }';
$recipe->js = <<<END
Drupal.behaviors.{<span class="php-variable">$js_name</span>} = function() {
\$("{<span class="php-variable">$selector</span>}").each(function() {
f=\$(this)[0];
tok2=\$.trim(\$(f).css('fontFamily').split(',')[1]);
if(tok2[0] == "'" || tok2[0] == '"') tok2=tok2.substring(1, tok2.length-1);
if (f.value.indexOf("{<span class="php-variable">$js_match</span>}")==0){f.value="{<span class="php-variable">$js_tok1</span>}"+f.value.substring({<span class="php-variable">$js_pos</span>})+tok2;}
});
};
END;
return $recipe;
}
function _botcha_recipes($form, $botcha, $secret) {
static $recipes_cache = array();
$cache_id = $form['#build_id'] . '_' . $botcha . '_' . $secret;
if (isset($recipes_cache[$cache_id])) {
if (BOTCHA_LOGLEVEL >= 6) {
watchdog(BOTCHA_LOG, 'Found cached recipes book for %cache_id', array(
'%cache_id' => $cache_id,
), WATCHDOG_INFO);
}
return $recipes_cache[$cache_id];
}
if (BOTCHA_LOGLEVEL >= 6) {
watchdog(BOTCHA_LOG, 'Built new recipes book for %cache_id', array(
'%cache_id' => $cache_id,
), WATCHDOG_INFO);
}
if ($botcha == 'test') {
$recipe_book = array(
'_botcha_recipe_test1',
'_botcha_recipe1',
);
}
else {
$recipe_book = array(
'_botcha_recipe1',
'_botcha_recipe2',
'_botcha_recipe3',
);
if ($botcha == '') {
$botcha = 'default';
}
elseif ($botcha != 'default') {
$botcha = split(',', $botcha);
}
}
$error_field = _botcha_pick_patsy_field($form, 'mail');
$recipes = array();
foreach ($recipe_book as $recipe_page) {
if (!function_exists($recipe_page)) {
continue;
}
$recipe = $recipe_page($form, $secret, $error_field);
if (!is_array($botcha) || isset($recipe->name) && isset($botcha[$recipe->name])) {
$recipe->source = $recipe_page;
$recipe->secret = $secret;
$recipes[] = $recipe;
}
}
if ($cache_id) {
$recipes_cache[$cache_id] = $recipes;
}
return $recipes;
}
function _botcha_filter_form_values_log($values) {
if (is_array($values) && isset($values['pass']) && is_string($values['pass'])) {
$values['pass'] = '********';
}
return $values;
}
function _botcha_filter_form_log($form, $level = 0) {
if (is_array($form) && !is_string($form)) {
foreach ($form as $key => $value) {
if ($key == '#post') {
$form[$key] = $level == 0 ? _botcha_filter_form_values_log($value) : t('...[redundand entry - removed]');
}
elseif ($key == '#parameters') {
foreach ($value as $n => $arg) {
$value[$n] = _botcha_filter_form_log($arg, -1);
}
$form[$key] = $value;
}
elseif (!element_property($key)) {
if ($level == -1) {
$form[$key] = $key == 'pass' ? '********' : _botcha_filter_form_log($value, -1);
}
else {
$form[$key] = _botcha_filter_form_log($value, $level + 1);
if ($key == 'pass' && isset($form[$key]['#value'])) {
$form[$key]['#value'] = '********';
}
}
}
}
}
return $form;
}
function botcha_form_alter_botcha(&$form, &$form_state, $form_id, $botcha) {
$build_id = $form['#build_id'];
$build_id_subm = isset($_POST['form_build_id']) ? $_POST['form_build_id'] : FALSE;
$form_state['botcha_submit_values'] = array();
if ($build_id_subm) {
$secret = md5($build_id_subm . BOTCHA_SECRET);
$recipes = _botcha_recipes($form, $botcha, $secret);
foreach ($recipes as $recipe) {
if (isset($recipe->form_elements)) {
foreach ($recipe->form_elements as $field => $value) {
if (isset($_POST[$field])) {
$form_state['botcha_submit_values'][$field] = $_POST[$field];
}
}
}
}
$form_state['#botcha_recipes_subm'] = $recipes;
}
$secret = md5($build_id . BOTCHA_SECRET);
$recipes = _botcha_recipes($form, $botcha, $secret);
$form_state['#botcha_recipes'] = $recipes;
$added_botchas = array();
$jss = array();
$csss = array();
foreach ($recipes as $recipe) {
if (isset($recipe->form_elements)) {
foreach ($recipe->form_elements as $field => $value) {
unset($value['!valid_token']);
$form[$field] = $value;
if ($build_id_subm && isset($value['#default_value'])) {
$form[$field]['#value'] = $value['#default_value'];
$form_state['post'][$field] = $value['#default_value'];
$_POST[$field] = $value['#default_value'];
}
}
}
if (isset($recipe->js)) {
drupal_add_js($recipe->js, 'inline');
$jss[] = $recipe->js;
}
if (isset($recipe->css)) {
drupal_set_html_head('<style type="text/css">' . $recipe->css . '</style>');
$csss[] = $recipe->css;
}
$added_botchas[] = $recipe->name;
}
if (is_array($form['#validate'])) {
array_unshift($form['#validate'], '_botcha_form_validate');
}
else {
$form['#validate'] = array(
'_botcha_form_validate',
);
}
$form_state['#botcha'] = $botcha;
if (BOTCHA_LOGLEVEL >= 4) {
watchdog(BOTCHA_LOG, '%form_id form prepared by BOTCHA: added recipes - !botchas!more', array(
'%form_id' => $form_id,
'!botchas' => join(', ', $added_botchas),
'!more' => '' . (BOTCHA_LOGLEVEL >= 5 ? '<br /><br />' . 'POST=<pre>' . print_r(_botcha_filter_form_values_log($_POST), 1) . '</pre>' : '') . (BOTCHA_LOGLEVEL >= 5 ? '<br /><br />' . 'GET=<pre>' . print_r(_botcha_filter_form_values_log($_GET), 1) . '</pre>' : '') . (BOTCHA_LOGLEVEL >= 5 ? '<br /><br />' . 'SERVER=<pre>' . print_r($_SERVER, 1) . '</pre>' : '') . (BOTCHA_LOGLEVEL >= 5 ? '<br /><br />' . 'form=<pre>' . print_r(_botcha_filter_form_log($form), 1) . '</pre>' : '') . (BOTCHA_LOGLEVEL >= 5 && count($jss) ? '<br /><br />' . 'JS=<pre>' . join("\n", $jss) . '</pre>' : '') . (BOTCHA_LOGLEVEL >= 5 && count($csss) ? '<br /><br />' . 'CSS=<pre>' . join("\n", $csss) . '</pre>' : ''),
), WATCHDOG_NOTICE);
}
if ($build_id_subm != $build_id) {
$form_state['post']['form_build_id'] = $build_id;
}
_botcha_set_form_cache($build_id);
}
function _botcha_set_form_cache($form_build_id) {
$expire = 21600;
$data = array();
$data['#cache_token'] = _botcha_get_token();
cache_set('botcha_' . $form_build_id, $data, 'cache_form', time() + $expire);
}
function _botcha_get_form_cache($form_build_id) {
if ($cached = cache_get('botcha_' . $form_build_id, 'cache_form')) {
$data = $cached->data;
if (isset($data['#cache_token']) && _botcha_valid_token($data['#cache_token'])) {
return TRUE;
}
}
return FALSE;
}
function _botcha_clear_form_cache($form_build_id) {
$expire = 0;
$data = NULL;
cache_set('botcha_' . $form_build_id, $data, 'cache_form', time() + $expire);
}
function _botcha_get_token($value = '') {
if (empty($_SESSION['botcha_session'])) {
$_SESSION['botcha_session'] = session_id();
}
return md5($value . $_SESSION['botcha_session'] . drupal_get_private_key());
}
function _botcha_valid_token($token) {
return $token == _botcha_get_token();
}
function _botcha_form_validate($form, &$form_state) {
unset($form_state['values']['']);
$build_id = isset($_POST['form_build_id']) ? $_POST['form_build_id'] : $form['#build_id'];
$recipes = isset($form_state['#botcha_recipes_subm']) ? $form_state['#botcha_recipes_subm'] : $form_state['#botcha_recipes'];
$botcha_names = array();
$i = 0;
$fail = '';
foreach ($recipes as $recipe) {
if (isset($recipe->form_elements)) {
foreach ($recipe->form_elements as $field => $value) {
if (isset($value['!valid_token']) && $form_state['botcha_submit_values'][$field] !== $value['!valid_token']) {
$fail = $form_state['botcha_submit_values'][$field] . '!=' . $value['!valid_token'];
break 2;
}
}
}
if (isset($recipe->url_elements)) {
foreach ($recipe->url_elements as $field => $value) {
if (isset($value['!valid_token']) && $_GET[$field] !== $value['!valid_token']) {
$fail = $_GET[$field] . '!=' . $value['!valid_token'];
unset($_GET[$field]);
break 2;
}
unset($_GET[$field]);
}
}
if (!empty($recipe->proc)) {
switch ($recipe->proc) {
case 'check_cache':
if (!_botcha_get_form_cache($build_id)) {
$fail = 'botcha_resubmit';
break 2;
}
break;
}
}
$botcha_names[] = $recipe->name;
$i++;
}
_botcha_clear_form_cache($build_id);
if ($i < count($recipes)) {
variable_set('botcha_form_blocked_counter', variable_get('botcha_form_blocked_counter', 0) + 1);
form_set_error($recipe->error_field, $recipe->error_text);
if (BOTCHA_LOGLEVEL >= 1) {
watchdog(BOTCHA_LOG, '%form_id post blocked by BOTCHA: submission looks like from a spambot.!more', array(
'%form_id' => $form['#id'],
'!more' => '' . (BOTCHA_LOGLEVEL >= 2 ? '<br /><br />' . ' Failed [' . $fail . '] botcha \'' . $recipe->name . '\' #' . ($i + 1) . ' of ' . count($recipes) . ' recipes from "' . $form_state['#botcha'] . '" book.' : '') . (BOTCHA_LOGLEVEL >= 5 ? '<br /><br />' . 'POST=<pre>' . print_r(_botcha_filter_form_values_log($_POST), 1) . '</pre>' : '') . (BOTCHA_LOGLEVEL >= 5 ? '<br /><br />' . 'GET=<pre>' . print_r(_botcha_filter_form_values_log($_GET), 1) . '</pre>' : '') . (BOTCHA_LOGLEVEL >= 5 ? '<br /><br />' . 'SERVER=<pre>' . print_r($_SERVER, 1) . '</pre>' : '') . (BOTCHA_LOGLEVEL >= 5 ? '<br /><br />' . ' values=<pre>' . print_r(_botcha_filter_form_values_log($form_state['values']), 1) . '</pre>' : ''),
), WATCHDOG_WARNING);
}
$rules_event_name = 'botcha_form_rejected';
}
else {
variable_set('botcha_form_passed_counter', variable_get('botcha_form_passed_counter', 0) + 1);
if (BOTCHA_LOGLEVEL >= 3) {
watchdog(BOTCHA_LOG, '%form_id post approved by BOTCHA.!more', array(
'%form_id' => $form['#id'],
'!more' => '' . (BOTCHA_LOGLEVEL >= 3 ? ' Checked ' . count($recipes) . ' botchas (' . join(', ', $botcha_names) . ').' : '') . (BOTCHA_LOGLEVEL >= 5 ? '<br /><br />' . 'POST=<pre>' . print_r(_botcha_filter_form_values_log($_POST), 1) . '</pre>' : '') . (BOTCHA_LOGLEVEL >= 5 ? '<br /><br />' . 'GET=<pre>' . print_r(_botcha_filter_form_values_log($_GET), 1) . '</pre>' : '') . (BOTCHA_LOGLEVEL >= 5 ? '<br /><br />' . 'SERVER=<pre>' . print_r($_SERVER, 1) . '</pre>' : '') . (BOTCHA_LOGLEVEL >= 5 ? '<br /><br />' . ' form=<pre>' . print_r(_botcha_filter_form_log($form), 1) . '</pre>' : '') . (BOTCHA_LOGLEVEL >= 5 ? '<br /><br />' . ' values=<pre>' . print_r(_botcha_filter_form_values_log($form_state['values']), 1) . '</pre>' : ''),
), WATCHDOG_INFO);
}
$rules_event_name = 'botcha_form_approved';
}
if (module_exists('rules')) {
$arguments = array(
'form_id' => $form['#id'],
'total_recipes' => count($recipes),
'passed_recipes' => $i,
'passed_recipes_names' => join(', ', $botcha_names),
'last_recipe_name' => $recipe->name,
'fail' => $fail,
'failed_field' => $recipe->error_field,
'failed_error' => $recipe->error_text,
);
rules_invoke_event($rules_event_name, $arguments);
}
}