How do i apply same validation rule for 50 fields in 2.0
i am not interested in repeating rule for different field
public $validate = array(
'company' => array(
'notempty' => array(
'rule' => array('notempty'),
'message' => 'Cannot be Empty',
),
),
// rule for other 50 fields....
);
Possible solution:
$validate_items = array('company', 'other', 'one_more');
$validate_rule = array(
'notempty' => array(
'rule' => array('notempty'),
'message' => 'Cannot be Empty')
);
$validate = array();
foreach ($validate_items as $validate_item) {
$validate[$validate_item] = $validate_rule;
}
echo "<pre>".print_r($validate, true)."</pre>";
Don't understand why you want to determinate same validation 50 times. You can declare just one rule and use it for all your fields.
May be I misunderstood your question?
You can dynamically build your $validate rules before you perform the save in your controller:
public function add() {
if (!empty($this->request->data) {
$validate = array();
foreach($fields as $field) {
$validate[$field] = array(
'required'=>array(
'rule'='notEmpty',
'message'=>'Cannot be empty'
)
);
}
$this->ModelName->validate = $validate;
if (!$this->ModelName->save($this->request->data)) {
// didn't save
}
else {
// did save
}
}
}
Where $fields is an array containing a list of the fields you want to apply the validation to.
Idealy, You'd shift the code that builds the validation array to the model, but the effect is the same
You can apply the same technique to allow you to have multiple validation rules for a model.
New example:
$fields_to_check = array('company', 'field_2', 'field_5'); // declare here all the fields you want to check on "not empty"
$errors = 0;
foreach ($_POST as $key => $value) {
if (in_array($key, $fields_to_check)) {
if ($value == "") $errors++;
}
}
if ($errors > 0) echo "There are ".$errors." errors in the form. Chech if all requered fields are filled in!"; //error! Not all fields are set correctly
else //do some action
Related
Currently I'm trying to validate an email address via OOP php with arrays so I can add additional functions later, however when I insert a valid email address the validation still fails, I think perhaps my arrays are set up wrong but I'm not entirely sure, additionally I had tried different different operators to check if the email function would output different results however as mentioned it always seems to fail, any advice would be appreciated
class Login
{
private
$email,
$password,
$database,
$db = null;
public function __construct()
{
$this->db = new Database;
}
public function validEmail($email)
{
return (filter_var($email, FILTER_VALIDATE_EMAIL) !== FALSE);
}
}
<?php
require "classes/Login.class.php";
$validate = new Login();
require "loadclasses.php";
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
$email = $pass = "";
$post = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
$email = $post['email-login'];
$pass = $post['password-login'];
$errors = array();
$fields = array(
'email-login' => array(
'validate' => 'validEmail',
'message' => 'Enter a valid email address'
)
);
foreach($fields as $key => $value)
{
if(isset($fields[$key]))
{
$errors[] = ['name' => $key, 'error' => $fields[$key]['message']];
}
}
if(empty($errors))
{
$success = ['response' => 'true'];
session_start();
}
}
header('Content-Type: application/json');
if (empty($errors))
{
echo json_encode($success);
}
else
{
echo json_encode(["errors" => $errors]);
}
As already mentioned in comments - you don't use functions from your Login class.
So, how you current code works:
$fields = array(
'email-login' => array(
'validate' => 'validEmail',
'message' => 'Enter a valid email address'
)
);
foreach($fields as $key => $value)
{
// isset($fields[$key]) is ALWAYS true
if(isset($fields[$key]))
{
$errors[] = ['name' => $key, 'error' => $fields[$key]['message']];
}
}
What you really should do is something like:
$fields = array(
'email-login' => array(
'validate' => 'validEmail',
'message' => 'Enter a valid email address'
)
);
// instantiate object of Login class
$login = new Login();
foreach($fields as $key => $value)
{
// call a function `$value['validate']` (it is `validEmail`)
$validation_result = $login->{$value['validate']}($email);
// if validation fails - add error message
if(!$validation_result)
{
$errors[] = ['name' => $key, 'error' => $value['message']];
}
}
And btw $post is a wrong variable name, I suppose it is $_POST.
I'm trying to customize a php script to make it adapted to my needs.
Here's the code :
<?php
if (isset($_POST['email']))
{
$error = '';
$name = $_POST['name'];
$email = $_POST['email'];
if($name=='' || $email=='')
{
$error = 'Name and email are mandatory';
}
if ($error == '')
{
$custom_field1 = $_POST['custom_field1'];
$custom_field2 = $_POST['custom_field2'];
$custom_field3 = $_POST['custom_field3'];
$boolean = 'true';
$postdata = http_build_query(
array(
'name' => $name,
'email' => $email,
'custom_field1' => $custom_field1,
'custom_field2' => $custom_field2,
'custom_field3' => $custom_field3,
'list' => $list,
'boolean' => 'true'
)
);
$opts = array('http' => array('method' => 'POST', 'header' => 'Content-type: application/x-www-form-urlencoded', 'content' => $postdata));
$context = stream_context_create($opts);
$result = file_get_contents($app_url.'/signin', false, $context);
if ($result != 1)
$error = $result;
}
}
?>
By default the name and the email are the two mandatory fields, i would like the custom fields 1 & 2 to be mandatory as well.
I'd also like the error message to be specific to the missing field(s).
With the current code, even if the name is filled, the message says :
Name and email are mandatory
Thanks
try this:
$name = $_POST['name'];
$email = $_POST['email'];
$custom_field1 = $_POST['custom_field1'];
$custom_field2 = $_POST['custom_field2'];
$error = array();
if($name=='')
{
$error[] = 'Name are mandatory';
}
if($email == '')
{
$error[] = 'Email are mandatory';
}
if($custom_field1 == '')
{
$error[] = 'Custom field 1 is mandatory';
}
if($custom_field2 == '')
{
$error[] = 'Custom field 2 is mandatory';
}
if (!empty($error))
{
$custom_field3 = $_POST['custom_field3'];
$boolean = 'true';
$postdata = http_build_query(
array(
'name' => $name,
'email' => $email,
'custom_field1' => $custom_field1,
'custom_field2' => $custom_field2,
'custom_field3' => $custom_field3,
'list' => $list,
'boolean' => 'true'
)
);
$opts = array('http' => array('method' => 'POST', 'header' => 'Content-type: application/x-www-form-urlencoded', 'content' => $postdata));
$context = stream_context_create($opts);
$result = file_get_contents($app_url.'/signin', false, $context);
if ($result != 1)
$error[] = $result;
}
}
When you displaying the error messages, make a loop in $error array
foreach ($error as $errstr)
{
echo "<p>{$errstr}</p>";
}
or implode to string and echoes like
echo "<p>" . implode("</p><p>", $error) . "</p>";
This block says if name is empty || (or) email is empty the error is "Name and email are mandatory".
if($name=='' || $email=='') {
$error = 'Name and email are mandatory';
}
If you would like to create seperate error messages, just follow this pattern. I'm sure you will figure it out if you give it a try.
You can make an if statement with a custom error for each field you'd like to check:
if ($name == '')
{
$error = 'Name is mandatory';
}
You can repeat this pattern for each field you'd like to check. You will need to assign $custom_field1 and $custom_field2 before you do this check (your script is doing this on the two lines after it checks to make sure $error is empty).
You may want to read through the PHP manual about variables and the if statement.
The most simple solution would be to create an array with the required fields and loop though them. This enables you to both check mandatory fields in a flexible way and have error messages for individual fields:
// required fields
$required = [
'name' => 'Name',
'email' => 'Emailaddress',
'custom_field1' => 'My awesome field 1',
'custom_field2' => 'My awesome field 2',
];
// list of errors
$errors = [];
if (isset($_POST['email'])) {
// loop through required fields
foreach ($required as $key => $name) {
if ($_POST[$key] !== '') {
continue;
}
$errors[$key] = $name . ' is required';
}
}
// check if there were errors
if (!empty($errors)) {
// display errors
}
The advantage of this solution is that you can easily add more required field by simply adding it to the $required array.
You could even easily add other validation like that. For example:
// validation of fields
$validation= [
'name' => [
'name' => 'Name',
'required' => true,
],
'email' => [
'name' => 'Emailaddress',
'required' => true,
'validation' => 'email',
],
'custom_field1' => [
'name' => 'My awesome field 1',
'required' => true,
'validation' => '/^[a-z]{2,}$/i',
],
'custom_field2' => [
'name' => 'My awesome field 2',
'required' => true,
],
];
function validateEmail($key, $data, $errors) {
if (!filter_var($_POST[$key], FILTER_VALIDATE_EMAIL)) {
$errors[$key] = $data['name'] . ' must be a valid emailaddress';
}
return $errors;
}
function validatePattern($key, $data, $errors) {
if (preg_match($data['validation'], $_POST[$key]) !== 1) {
$errors[$key] = $data['name'] . ' has an incorrect format';
}
return $errors;
}
// list of errors
$errors = [];
if (isset($_POST['email'])) {
// loop fields to be validated
foreach ($validationas $key => $data) {
if (array_key_exists('validation', $data)) {
switch($data['validation']) {
case 'email':
$errors = validateEmail($key, $data, $errors);
break;
default:
validatePattern($key, $data, $errors)
break;
}
}
if ($data['required'] !== true) {
continue;
}
if ($_POST[$key] === '') {
$errors[$key] = $data['name'] . ' is required';
}
}
}
You could also add client side validation as in LMT-PhD's answer but you should always have at least server side validation. Client side validation should be treated as a nice thing to do for users and nothing more.
I have a site developed in cakephp.
I have a model called User like this:
class User extends AppModel {
public $name = 'User';
public $validate = array(
'username' => array(
'not_empty' => array(
'rule'=> 'notEmpty',
'message'=> 'Username not empty'
)
),
'email' => array(
'email_invalid' => array(
'rule' => 'email',
'message' => 'Invalid mail'
),
'email_unique' => array(
'rule' => 'isUnique',
'message' => 'Mail already exist inside database'
)
)
);
public function beforeSave(){
if (isset($this->data['User']['password'])){
$this->data['User']['password'] = AuthComponent::password($this->data['User']['password']);
}
}
}
Into my validate I have the rules email_unique that check if inside the database is already present another email equal.
When I update a user I make this inside my controller:
$this->User->id = $this->request->data['User']['id'];
if ($this->User->save($this->request->data)) {
$this->redirect (array ('action'=>'index'));
}
else{
$this->Session->write('flash_element','error');
$this->Session->setFlash ('Error');
}
It always fail because email isn't unique but is the same record!
I would like to know what is the best method to escape the validation if the save is an update not a create?
Or something like: check if the page is edit escape validation or I don't know.. maybe there are many system, I would like to know what is the more correct for my problem.
Thanks
You can adjust your validation rules to only apply when a new record is created, not when an existing record is updated. You can do this by setting the on key in your validation rule to create, so it will look like this:
'email_unique' => array(
'rule' => 'isUnique',
'message' => 'Mail already exist inside database',
'on' => 'create' // Only apply this rule upon creation of a new record
)
See the documentation on this for further details.
If you also want to block duplicate e-mails upon updating, create a beforeSave method in your User model, looking for the e-mail address:
public function beforeSave($options = array()) {
// If the email key is set in the data to be saved...
if (isset($this->data[$this->alias]['email'])) {
// Make sure the email is not already in use by another user
if ($this->find('count', array(
'conditions' => array(
$this->alias . '.id !=' => $this->data[$this->alias]['id'],
$this->alias . '.email' => $this->data[$this->alias]['email']
)
)) > 0) {
// The email is found for a user with another id, abort!
return false;
}
}
}
I have a model Interesttype where i want two fields to be validated one should not be more than the other and none should be less than a particular set value. Here is my model.
class Interesttype extends AppModel
{
public $primaryKey = 'int_id';
public $displayField = 'int_name';
public $hasMany= array(
'Loan' => array(
'className' => 'Loan',
'foreignKey' => 'lon_int_id'
)
);
public $validate = array(
'int_name'=> array(
'rule' => 'notEmpty',
'allowEmpty' => false,
'message' => 'The interest type name is required.'
),
'int_active'=>array(
'rule'=>array('boolean'),
'allowEmpty'=>false,
'message'=>'Please select the status of this interest type'
),
'int_max'=> array(
'numeric'=>array(
'rule' => 'numeric',
'allowEmpty' => false,
'message' => 'Please specify a valid maximum interest rate.'
),
'comparison'=>array(
'rule' => array('comparison','>',1000),
'allowEmpty' => false,
'message' => 'The Maximum interest rate cannot be less than the special rate.'
),
'checklimits'=>array(
'rule' => array('checkRateLimits','int_min'),
'allowEmpty' => false,
'message' => 'The Maximum interest rate cannot be less than the minimum rate.'
)
),
'int_min'=> array(
'numeric'=>array(
'rule' => 'numeric',
'allowEmpty' => false,
'message' => 'Please specify a valid minimum interest rate.'
),
'comparison'=>array(
'rule' => array('comparison','>',1000),
'allowEmpty' => false,
'message' => 'The Minimum interest rate cannot be less than the special rate.'
))
);
function checkRateLimits($maxr,$minr){
if($maxr>=$minr){
return true;
}
else{
return false;
}
}
}
the above model validates my forms well except that one check will not be done, it will not check if the maximum interest rate is indeed more than or equal to the minimum inerest rate.
Where am i going wrong on the validation?
You'll have to add your own Validation Method to make this possible. Here's a pretty generic example that makes use of Validation::comparison() and supports all of its operators (>, <, >=, <=, ==, !=, isgreater, isless, greaterorequal, lessorequal, equalto, notequal) as the second argument in the options array and a field name to compare the validated value to as a third parameter.
class MyModel extends AppModel
{
/* Example usage of custom validation function */
public $validate = array(
'myfield' => array(
'lessThanMyOtherField' => array(
'rule' => array('comparisonWithField', '<', 'myotherfield'),
'message' => 'Myfield value has to be lower then Myotherfield value.',
),
),
);
/* Custom validation function */
public function comparisonWithField($validationFields = array(), $operator = null, $compareFieldName = '') {
if (!isset($this->data[$this->name][$compareFieldName])) {
throw new CakeException(sprintf(__('Can\'t compare to the non-existing field "%s" of model %s.'), $compareFieldName, $this->name));
}
$compareTo = $this->data[$this->name][$compareFieldName];
foreach ($validationFields as $key => $value) {
if (!Validation::comparison($value, $operator, $compareTo)) {
return false;
}
}
return true;
}
}
This is generic, so you could throw the function in your AppModel if you want to make use of it in multiple models in your App. You could also make this a Behavior to share it between different models.
I won't help you to do your code however I will suggest you to read the following backery article http://bakery.cakephp.org/articles/aranworld/2008/01/14/using-equalto-validation-to-compare-two-form-fields
<?php
class Contact extends AppModel
{
var $name = 'Contact';
var $validate = array(
'email' => array(
'identicalFieldValues' => array(
'rule' => array('identicalFieldValues', 'confirm_email' ),
'message' => 'Please re-enter your password twice so that the values match'
)
)
);
function identicalFieldValues( $field=array(), $compare_field=null )
{
foreach( $field as $key => $value ){
$v1 = $value;
$v2 = $this->data[$this->name][ $compare_field ];
if($v1 !== $v2) {
return FALSE;
} else {
continue;
}
}
return TRUE;
}
}
?>
modify the code I think it should be easy from here.
I don't think you can achieve this with directly inserting it into the validate array in a model. You can however specify your own validation function. An example is given here (look at the model code):
Example custom validation function
In your Model your validate should be field name with rule pointing to the function you want to run.
And "None should be less than a particular set value" I would use the "range" validation as seen below. The example will accept any value which is larger than 0 (e.g., 1) and less than 10
public $validate = array(
'maxr'=>array(
'Rate Limits'=>array(
'rule'=>'checkRateLimits',
'message'=>'Your Error Message'
),
'Greater Than'=>array(
'rule'=>array('range', -1, 11),
'message'=>'Please enter a number between 0 and 10'
)
),
);
In the function you pass $data which is the fields being passed. If $data doesn't work try $this->data['Model']['field'] ex($this->data['Model']['maxr'] >= $this->data['Model']['minr'])
function checkRateLimits($data){
if ( $data['maxr'] >= $data['minr'] ) {
return true;
} else {
$this->invalidate('minr', 'Your error message here');
return false;
}
}
Your Form would be something like
echo $this->Form->create('Model');
echo $this->Form->input('maxr');
echo $this->Form->input('minr');
echo $this->Form->end('Submit');
I'm trying to set up validation for user registration but I'm having troubles. When I only have the email,role and password fields in the $validation array (remove the others) it works and will save a new user. When I try to add the other fields it fails and gives the flash message error "The user could not be saved. Please, try again."
I'm pretty sure it's the re_password check. When I remove the validation for that it works. However, the re_password validation does display an error when the passwords are different, so I'm not sure where to look
Here's my users table
id | email | password | location | website | role | created | modified
Here's the validation requirements. To get it to save a new user I have to remove everything but email, password and role.
public $validate = array(
'email' => 'email'
,
'password' => array(
'required' => array(
'rule' => array('minLength', '8'),
'message' => 'A password with a minimum length of 8 characters is required'
)
),
're_password' => array(
'required' => array(
'rule' => array('equalTo', 'password' ),
'message' => 'Both password fields must be filled out'
)
),
'role' => array(
'valid' => array(
'rule' => array('inList', array('admin', 'author')),
'message' => 'Please enter a valid role',
'allowEmpty' => false
)
),
'location' => array(
'valid' => array(
'rule' => array('notEmpty'),
'message' => 'Please select a location'
)
)
);
Here's the form (the options array is above, figured it's not necessary to show)
echo $this->Form->input('email');
echo $this->Form->input('password');
echo $this->Form->input('re_password', array('type'=>'password', 'label'=>'Re-Enter Password', 'value'=>'', 'autocomplete'=>'off'));
echo $this->Form->input('location', array('options' => $options, 'label' => 'Select Nearest Location'));
echo $this->Form->input('website',array('label'=>'Enter your website, such as www.example.com. '));
echo $this->Form->input('role', array('type' => 'hidden', 'default' => 'user'));
Here's the re_password checking function in the User model
function check_user_password($userid) {
$salt = Configure::read('Security.salt');
$this->User->id = $userid;
$hashed_password = $this->User->field('password');
// check password
if($hashed_password == md5($data['User']['re_password'].$salt)) {
return true;
} else {
return false;
}
}
And finally, here's the add function in UsersController
public function add() {
if ($this->request->is('post')) {
$this->User->create(); //create initiates a form on User/add.ctp
if ($this->User->save($this->request->data)) { //save the form data
$this->Session->setFlash(__('The user has been saved'));
$this->redirect(array('controller' => 'demos', 'action' => 'index'));
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
}
}
Please let me know if there's anything else you need to see
I believe that your re_passwords valiadtion rule equalTo compares its value to string password and not the actual field. I like to use custom functions for this.
so try replacing re_passwords rule array
//'rule' => array('equalTo', 'password' ),
'rule' => array('equalToField', 'password'),
and declare equalToField function in that model
function equalToField($array, $field) {
return strcmp($this->data[$this->alias][key($array)], $this->data[$this->alias][$field]) == 0;
}
** Also in the future when you seem to have a problem with validation rules
try this in your controllers action (its faster than removing every single rule)
if ($this->User->save($this->request->data)) {
...
} else {
debug($this->User->validationErrors);
...
}
I hope this helps.
Hi Please use following code for your requirement :
override equalTo function by putting your own method in user model:
function equalTo( $field=array(), $compare_field=null )
{
foreach( $field as $key => $value ){
$v1 = $value;
$v2 = $this->data[$this->name][ $compare_field ];
if($v1 !== $v2) {
return FALSE;
} else {
continue;
}
}
return TRUE;
}
Attention, in #luboss answer, where he declares:
function equalToField($array, $field) {
return strcmp($this->data[$this->alias][key($array)], $this->data[$this->alias][$field]) == 0;
}
That cannot work as we are comparing inconsistent fields:
the left member of strcmp has already been hashed, but not the right member.
This happens as a CakePHP automation because the field is called password.
The way I got this to work was to reuse the hashing function in the equalToField helper:
public function equalToField($array, $field) {
$valueFirstOccurrence = $this->data[$this->alias][$field];
$valueSecondOccurrence = Security::hash($this->data[$this->alias][key($array)], $type = 'sha1', $salt = true) ;
return !strcmp($valueFirstOccurrence, $valueSecondOccurrence);
}
Other point :
If you are interested in adding a minLength validation field for your password field, you want to read this good post first:
minLength data validation is not working with Auth component for CakePHP