I have already developed a webform validation. By adding a new option is limited to select submit.
The solution file. webform_validation->webform_validation.validators.inc
<?php
/**
* @file
* Provides validation functionality and hooks
*/
/**
* Implementation of hook_webform_validation_validators().
*
* This function returns an array of validators, in the validator key => options array form.
* Possible options:
* - name (required): name of the validator
* - component types (required): defines which component types can be validated by this validator. Specify 'all' to allow all types
* - custom_error (optional): define whether a user can specify a custom error message upon creating the validation rule.
* - custom_data (optional): define whether custom data can be added to the validation rule
* - min_components (optional): define the minimum number of components to be selected for creating a validation rule
* - max_components (optional): define the maximum number of components to be selected for creating a validation rule
* - description (optional): provide a descriptive explanation about the validator
*/
function webform_validation_webform_validation_validators() {
return array(
'numeric' => array(
'name' => "Numeric values",
'component_types' => array(
'textfield',
'hidden',
),
'custom_data' => array(
'label' => t('Specify numeric validation range'),
'description' => t('Optionally specify the minimum-maximum range to validate the user-entered numeric value against.') . ' ' . t('Usage') . ':'
. theme('item_list', array(t('empty: no value validation'), t('"100": greater than or equal to 100'), t('"|100": less than or equal to 100 (including negative numbers)'), t('"0|100": greater than or equal to 0 & less than or equal to 100'), t('"10|100": greater than or equal to 10 & less than or equal to 100'), t('"-100|-10": greater than or equal to -100 & less than or equal to -10'))),
'required' => FALSE,
),
'description' => t('Verifies that user-entered values are numeric, with the option to specify min and / or max values.'),
),
'min_length' => array(
'name' => "Minimum length",
'component_types' => array(
'textfield',
'textarea',
'email',
'hidden',
),
'custom_data' => array(
'label' => t('Minimum number of characters'),
'description' => t('Specify the minimum number of characters that have to be entered to pass validation.')
),
'description' => t('Verifies that a user-entered value contains at least the specified number of characters'),
),
'max_length' => array(
'name' => "Maximum length",
'component_types' => array(
'textfield',
'textarea',
'email',
'hidden',
),
'custom_data' => array(
'label' => t('Maximum number of characters'),
'description' => t('Specify the maximum number of characters that can be entered to pass validation.')
),
'description' => t('Verifies that a user-entered value contains at most the specified number of characters'),
),
'min_words' => array(
'name' => "Minimum number of words",
'component_types' => array(
'textfield',
'textarea',
'hidden',
),
'custom_data' => array(
'label' => t('Minimum number of words'),
'description' => t('Specify the minimum number of words that have to be entered to pass validation. Words are defined as strings of letters separated by spaces.')
),
'description' => t('Verifies that a user-entered value contains at least the specified number of words'),
),
'max_words' => array(
'name' => "Maximum number of words",
'component_types' => array(
'textfield',
'textarea',
'hidden',
),
'custom_data' => array(
'label' => t('Maximum number of words'),
'description' => t('Specify the maximum number of words that have to be entered to pass validation. Words are defined as strings of letters separated by spaces.')
),
'description' => t('Verifies that a user-entered value contains at most the specified number of words'),
),
'equal' => array(
'name' => "Equal values",
'component_types' => array(
'textfield',
'email',
'select',
'hidden',
),
'min_components' => 2,
'description' => t('Verifies that all specified components contain equal values'),
),
'unique' => array(
'name' => "Unique values",
'component_types' => array(
'textfield',
'email',
'select',
'hidden',
),
'min_components' => 2,
'description' => t('Verifies that all specified components contain unique values'),
),
'specific_value' => array(
'name' => "Specific value(s)",
'component_types' => array(
'select',
'textfield',
'textarea',
'email',
'hidden',
),
'custom_error' => TRUE,
'custom_data' => array(
'label' => t('(Key) value'),
'description' => t('Specify the specific value(s) you want the component to contain. Separate multiple options by a comma. For components that have keys, use the key value instead.')
),
'max_components' => 1,
'description' => t('Verifies that the specified component contains a defined value'),
),
'oneoftwo' => array(
'name' => "Require at least one of two fields",
'component_types' => array(
'textfield',
'textarea',
'email',
'select',
),
'min_components' => 2,
'max_components' => 2,
'description' => t('Forces the user to specify / select at least one of two selected webform components'),
),
'oneofseveral' => array(
'name' => "Require at least one of several fields",
'component_types' => array(
'textfield',
'textarea',
'email',
'select',
),
'min_components' => 2,
'description' => t('Forces the user to specify / select at least one of several selected webform components'),
),
'select_min' => array(
'name' => "Minimum number of selections required",
'component_types' => array(
'select',
),
'custom_data' => array(
'label' => t('Minimum number of selections'),
'description' => t('Specify the minimum number of options a user should select.')
),
'description' => t('Forces the user to select at least a defined number of options from the specified webform components'),
),
'select_max' => array(
'name' => "Maximum number of selections allowed",
'component_types' => array(
'select',
),
'custom_data' => array(
'label' => t('Maximum number of selections'),
'description' => t('Specify the maximum number of options a user can select.')
),
'description' => t('Forces the user to select at most a defined number of options from the specified webform components'),
),
'select_exact' => array(
'name' => "Exact number of selections required",
'component_types' => array(
'select',
),
'custom_data' => array(
'label' => t('Number of selections'),
'description' => t('Specify how many options a user can select.')
),
'description' => t('Forces the user to select exactly the defined number of options from the specified webform components'),
),
+ //---------------------------------------
+ 'select_limit' => array(
+ 'name' => "limit of selections",
+ 'component_types' => array(
+ 'select',
+ ),
+ 'custom_error' => TRUE,
+ 'custom_data' => array(
+ 'label' => t('limit of selections'),
+ 'description' => t('a limited number.')
+ ),
+ 'description' => t("Limited selection."),
+ ),
+ //-----------------------------------------
'plain_text' => array(
'name' => "Plain text (disallow tags)",
'component_types' => array(
'textfield',
'textarea',
'email',
'hidden',
),
'description' => t("Verifies that user-entered data doesn't contain HTML tags"),
),
'regex' => array(
'name' => "Regular expression",
'component_types' => array(
'textfield',
'textarea',
'email',
'hidden',
),
'custom_error' => TRUE,
'custom_data' => array(
'label' => t('Regex code'),
'description' => t('Specify regex code to validate the user input against.')
),
'description' => t("Validates user-entered text against a specified regular expression. Note: don't include delimiters such as /."),
),
'must_be_empty' => array(
'name' => "Must be empty",
'component_types' => array(
'textfield',
'hidden',
),
'description' => t('Verifies that a specified textfield remains empty - Recommended use case: used as an anti-spam measure by hiding the element with CSS'),
),
'blacklist' => array(
'name' => "Words blacklist",
'component_types' => array(
'textfield',
'textarea',
'email',
'hidden',
),
'custom_error' => TRUE,
'custom_data' => array(
'label' => t('Blacklisted words'),
'description' => t('Specify illegal words, seperated by commas. Make sure to escape reserved regex characters with an escape (\) character.')
),
'description' => t("Validates that user-entered data doesn't contain any of the specified illegal words"),
),
'username' => array(
'name' => "Must match a username",
'component_types' => array(
'textfield',
'hidden',
),
'description' => t("Validates that user-entered data matches a username"),
),
);
}
/**
* Implementation of hook_webform_validation_validate().
*/
function webform_validation_webform_validation_validate($validator_name, $items, $components, $rule) {
/**
* Preparation for select_* validation rules and the handling of key 0 for select components
*
* Only webform 3 handles a select list with key 0 properly.
* The array_filter callback function is only loaded for webform 3 to make sure
* it works perfectly for webform 3, and works in all cases except with key 0 for webform 2
*/
$version = $version = webform_validation_check_version();
$check_false_callback = ($version == 3) ? '_webform_validation_check_false' : NULL;
if ($items) {
$errors = array();
switch ($validator_name) {
case 'numeric':
$num_range = _webform_numeric_check_data($rule['data']);
foreach ($items as $key => $val) {
if ($val != '') {
// first check if the value is numeric
if (!is_numeric($val)) {
$errors[$key] = t('%item is not numeric', array('%item' => $components[$key]['name']));
}
// now validate the entered numeric value against the validator range settings, if appropriate
// a. validate min & max
if (isset($num_range['min']) && isset($num_range['max'])) {
// validate the min - max range
if ($val < $num_range['min'] || $val > $num_range['max']) {
$errors[$key] = t('%item is not within the allowed range %range', array('%item' => $components[$key]['name'], '%range' => str_replace('|' , ' - ', $rule['data'])));
}
}
else {
// b. validate min
if (isset($num_range['min'])) {
if ($val < $num_range['min']) {
$errors[$key] = t('%item should be greater than or equal to %val', array('%item' => $components[$key]['name'], '%val' => $num_range['min']));
}
}
// c. validate max
if (isset($num_range['max'])) {
if ($val > $num_range['max']) {
$errors[$key] = t('%item should be less than or equal to %val', array('%item' => $components[$key]['name'], '%val' => $num_range['max']));
}
}
}
}
}
return $errors;
break;
case 'min_length':
$min_length = $rule['data'];
foreach ($items as $key => $val) {
if ($val != '' && (drupal_strlen($val) < $min_length)) {
$errors[$key] = t('%item needs to be at least %num characters long', array('%item' => $components[$key]['name'], '%num' => $min_length));
}
}
return $errors;
break;
case 'max_length':
$max_length = $rule['data'];
foreach ($items as $key => $val) {
if ($val != '' && (drupal_strlen($val) > $max_length)) {
$errors[$key] = t('%item can be maximum %num characters long', array('%item' => $components[$key]['name'], '%num' => $max_length));
}
}
return $errors;
break;
case 'min_words':
$min_words = $rule['data'];
foreach ($items as $key => $val) {
if ($val != '' && (count(preg_split("/[\s]+/", trim($val))) < $min_words)) {
$error = format_plural($min_words, '%item needs to be at least 1 word long', '%item needs to be at least @count words long', array('%item' => $components[$key]['name']));
$errors[$key] = $error;
}
}
return $errors;
break;
case 'max_words':
$max_words = $rule['data'];
foreach ($items as $key => $val) {
if ($val != '' && (count(preg_split("/[\s]+/", trim($val))) > $max_words)) {
$error = format_plural($max_words, '%item can be maximum 1 word long', '%item can be maximum @count words long', array('%item' => $components[$key]['name']));
$errors[$key] = $error;
}
}
return $errors;
break;
case "equal":
$first_entry_key = key($items);
$first_entry = array_shift($items);
$first_entry = _webform_validation_flatten_array($first_entry); // flatten in case of array
// now check if following components equal the first one
foreach ($items as $key => $val) {
$val = _webform_validation_flatten_array($val); // flatten in case of array
if ($val !== $first_entry) {
$errors[$key] = t('%item_checked does not match %item_first', array('%item_checked' => $components[$key]['name'], '%item_first' => $components[$first_entry_key]['name']));
}
}
return $errors;
break;
case "unique":
foreach ($items as $key => $val) {
if (is_array($val)) {
// make sure to flatten arrays first
$items[$key] = _webform_validation_flatten_array($val);
}
if (empty($items[$key])) {
// items without a value selected shouldn't be validated
unset($items[$key]);
}
}
// now we count how many times each value appears, and find out which values appear more than once
$items_count = array_count_values(array_map('strtolower', array_map('trim', $items)));
$doubles = array_filter($items_count, create_function('$x', 'return $x > 1;'));
foreach ($items as $key => $val) {
if (in_array(strtolower($val), array_keys($doubles))) {
$errors[$key] = t('The value of %item is not unique', array('%item' => $components[$key]['name']));
}
}
return $errors;
break;
case "specific_value":
$specific_values = explode(',', $rule['data']);
$specific_values = array_map('trim', $specific_values);
foreach ($items as $key => $val) {
if (is_array($val)) {
$val = _webform_validation_flatten_array($val);
}
if (!in_array($val, $specific_values)) {
$errors[$key] = _webform_validation_i18n_error_message($rule);
}
}
return $errors;
break;
case "oneoftwo":
// $components should have 2 items
$keys = array_keys($items);
$item1 = array_shift($keys);
$item2 = array_shift($keys);
$entry1 = _webform_validation_flatten_array($items[$item1]);
$entry2 = _webform_validation_flatten_array($items[$item2]);
if (empty($entry1) && empty($entry2)) {
return array($item1 => t('You have to specify %item1 or %item2 (or both)', array('%item1' => $components[$item1]['name'], '%item2' => $components[$item2]['name'])));
}
break;
case "oneofseveral":
foreach ($items as $key => $val) {
if (is_array($val)) {
// make sure to flatten arrays first
$items[$key] = _webform_validation_flatten_array($val);
}
}
// $components should have at least one of several items
if (count(array_filter($items)) < 1) {
$keys = array_keys($items);
$names = array();
foreach ($keys as $value) {
$names[] = $components[$value]['name'];
}
return array($keys[0] => t('You have to specify at least one of these items:') . theme('item_list', $names));
}
break;
case "select_min":
$min_selections = $rule['data'];
foreach ($items as $key => $val) {
$val = (is_array($val)) ? $val : array($val); // workaround for single select components
$selected_values = isset($check_false_callback) ? array_filter($val, $check_false_callback): array_filter($val);
if (is_array($val) && (count($selected_values) < $min_selections)) {
$errors[$key] = t('Please select at least %num options for %item', array('%num' => $min_selections, '%item' => $components[$key]['name']));
}
}
return $errors;
break;
case "select_max":
$max_selections = $rule['data'];
foreach ($items as $key => $val) {
$val = (is_array($val)) ? $val : array($val); // workaround for single select components
$selected_values = isset($check_false_callback) ? array_filter($val, $check_false_callback): array_filter($val);
if (is_array($val) && (count($selected_values) > $max_selections)) {
$errors[$key] = t('Please select maximum %num options for %item', array('%num' => $max_selections, '%item' => $components[$key]['name']));
}
}
return $errors;
break;
case "select_exact":
$allowed_selections = $rule['data'];
foreach ($items as $key => $val) {
$selected_values = isset($check_false_callback) ? array_filter($val, $check_false_callback): array_filter($val);
if (is_array($val) && (count($selected_values) != $allowed_selections)) {
$errors[$key] = t('Please select %num options for %item', array('%num' => $allowed_selections, '%item' => $components[$key]['name']));
}
}
return $errors;
break;
+ //-------------------------------------------------------------
+ case "select_limit":
+ $limit_selections = $rule['data'];
+ $ni=arg(1);
+ foreach ($items as $key => $val) {
+ $ci=substr($key,5,1);
+ $result=db_query("SELECT data FROM webform_submitted_data WHERE nid = '$ni' and cid = '$ci' GROUP BY data Having COUNT(*) >= $limit_selections");
+ $x=0;
+ while($row = mysql_fetch_array($result)){
+ $check[$x]=t($row['data']);
+ if($val==$check[$x]){
+ $errors[$key] = _webform_validation_i18n_error_message($rule);
+ }
+ $x++;
+ }
+ }
+ return $errors;
+ break;
+ //-----------------------------------------------------------------
case "plain_text":
foreach ($items as $key => $val) {
if ($val != '' && (strcmp($val, strip_tags($val)))) {
$errors[$key] = t('%item only allows the use of plain text', array('%item' => $components[$key]['name']));
}
}
return $errors;
break;
case "regex":
mb_regex_encoding('UTF-8');
$regex = $rule['data'];
foreach ($items as $key => $val) {
if ($val != '' && (!mb_ereg("$regex", $val))) {
$errors[$key] = _webform_validation_i18n_error_message($rule);
}
}
return $errors;
break;
case 'must_be_empty':
foreach ($items as $key => $val) {
if ($val) {
$errors[$key] = t('%item does not contain the correct data', array('%item' => $components[$key]['name']));
}
}
return $errors;
break;
case "blacklist":
$blacklist = explode(',', $rule['data']);
$blacklist = array_map('trim', $blacklist);
$blacklist_regex = implode('|', $blacklist);
foreach ($items as $key => $val) {
if ($val != '' && (preg_match("/$blacklist_regex/i", $val))) {
$errors[$key] = _webform_validation_i18n_error_message($rule);
}
}
return $errors;
break;
case "username":
foreach ($items as $key => $val) {
// load user - if username does not match or status 0 throw error
if ($val != '') {
if (!db_result(db_query("SELECT COUNT(*) FROM {users} WHERE name = '%s' AND status = 1", $val))) {
// Username doesn't exist
$errors[$key] = t('The %item field does not match an active username.', array('%item' => $components[$key]['name']));
}
}
}
return $errors;
break;
}
}
}
/**
* Helper function to deal with submitted values that are arrays (e.g. multiple select component)
* We flatten the array as a comma-separated list to do the comparison.
*/
function _webform_validation_flatten_array($val) {
if (is_array($val)) {
$arr = array_filter($val, '_webform_validation_check_false');
return implode(',', $arr);
}
return $val;
}
/**
* Get a list of validator definitions
*/
function webform_validation_get_validators() {
$validators = module_invoke_all("webform_validation_validators");
// let modules use hook_webform_validator_alter($validators) to change validator settings
drupal_alter('webform_validator', $validators);
return $validators;
}
function webform_validation_get_validators_selection() {
$selection = array();
$validators = webform_validation_get_validators();
if ($validators) {
foreach ($validators as $validator_key => $validator_info) {
$selection[$validator_key] = $validator_info['name'];
}
}
return $selection;
}
/**
* Get a list of valid component types per validator, as defined via hook_webform_validation_validators().
* If 'all' is specified, all available component types will be returned.
*/
function webform_validation_valid_component_types($validator) {
$validators = webform_validation_get_validators();
if ($info = $validators[$validator]) {
$allowed_types = $info['component_types'];
if (_webform_validation_all_allowed($allowed_types)) {
$version = webform_validation_check_version();
if ($version == 2) {
return webform_load_components();
}
else {
return array_keys(webform_components());
}
return $componentslist_function();
}
return $info['component_types'];
}
}
/**
* Helper function to check whether all components are allowed to be used for a certain validator
*/
function _webform_validation_all_allowed($allowed) {
if ($allowed) {
foreach ($allowed as $type) {
if ($type == "all") {
return TRUE;
}
}
}
return FALSE;
}
function webform_validation_get_validator_info($validator_key) {
$validators = webform_validation_get_validators();
return $validators[$validator_key];
}
/**
* Handle translatable error messages, if available
*/
function _webform_validation_i18n_error_message($rule) {
if (module_exists('i18nstrings')) {
return i18nstrings('webform_validation:error_message:' . $rule['ruleid'] . ':message', $rule['error_message']);
}
return $rule['error_message'];
}
/**
* Helper function used by array_filter to determine if a value was selected or not
*/
function _webform_validation_check_false($var) {
return $var !== FALSE;
}
/**
* Process the numeric value validation range that was provided in the numeric validator options
*/
function _webform_numeric_check_data($data) {
$range = array('min' => NULL, 'max' => NULL);
// if no value was specified, don't validate
if ($data == '') {
return $range;
}
// If only one numeric value was specified, this is the min value
if (is_numeric($data)) {
$range['min'] = (int) $data;
}
if (strpos($data, '|') !== FALSE) {
list($min, $max) = explode('|', $data);
if ($min != '' && is_numeric($min)) {
$range['min'] = (int) $min;
}
if ($max != '' && is_numeric($max)) {
$range['max'] = (int) $max;
}
}
return $range;
}
Good enough to try it. But there are problems, select submit to the constraints that have been irretrievable. I can see how that should be developed further.
Comments
Comment #1
svendecabooterCould you describe the problem you are solving, because that's unclear from your post.
And please provide the solution in a patch format, for easier review.
Thanks
Comment #2
liam morlandDrupal 6 is no longer supported. If this issue exists in a later version of webform_validation, please re-open and update the version number.
Comment #3
liam morland