User validation not working properly in CakePHP through the User Model - php

For some reason, I can't get this validation to work as I'd like it to, specifically with the password minLength field.
Everything else is fine (even the minLength for Username works). For some reason, when I add the same minLength rule into the password field, it just ignores it and when I actually do enter in a password, it tells me that I need to enter a password:
var $validate = array(
'email' => array(
'email' => array(
'rule' => array('email', true),
'required' => true,
'allowEmpty' => false,
'message' => 'Please enter a valid email address'
),
'isUnique' => array(
'rule' => 'isUnique',
'message' => 'This email is already in use'
)
),
'username' => array(
'notEmpty' => array(
'rule' => 'notEmpty',
'required' => true,
'message' => 'Please enter a valid username'
),
'allowedCharacters' => array(
'rule' => '/^[a-zA-Z]+[0-9]*$/',
'message' => 'Please enter a valid username'
),
'minLength' => array(
'rule' => array('minLength', 3),
'message' => 'Please enter a longer username'
),
'maxLength' => array(
'rule' => array('maxLength', 23),
'message' => 'Please enter a shorter username'
),
'isUnique' => array(
'rule' => 'isUnique',
'message' => 'That username is already taken'
)
),
'password' => array(
'notEmpty' => array(
'required' => true,
'allowEmpty' => false,
'message' => 'Please enter a password'
),
'minLength' => array(
'rule' => array('minLength', 4),
'message' => 'Please enter a longer password'
),
'passwordConfirm' => array(
'rule' => array('checkPasswords'),
'message' => 'Passwords must match'
)
),
);
Am I overlooking something minor? It's driving me nuts.

This happens because in Cake, the password field is automatically hashed as soon as you submit it; which will break your validation rules (a 5 character password suddenly becomes a 40+ digit hash). There are various proposed fixes for this problem.
One that sounds the most promising:
Create two fields e.g pw and pw_confirm as opposed to password and confirm_password. Use these values for your password validation (so, max length etc)
Then something like:
$this->User->set($this->data);
if ($this->User->validates()) {
// all your data validates, so hash the password submitted,
// ready for storage as normal.
$password_hash = $this->Auth->password($this->data['User']['pw'];
$this->data['User']['password'] = $password_hash;
}
This way, Cake won't automatically hash the passed that's entered - allowing your validation to function as you intended.
To visualise this, add this to your register/add user method:
function admin_add() {
if (!empty($this->data)) {
debug($this->data);
exit;
You'll get:
Array
(
[User] => Array
(
[username] => somename
[password] => 25ae3c1689d26b20e03abc049982349482faa64e
)
)
before validation takes place.

It looks like you have a small mistake in your validation array.
Every validation for a field must have a 'rule' key, and you don't have that in your 'notEmpty' validation.
Try updating the password validation like this:
<?php
array(
'password' => array(
'notEmpty' => array(
'rule' => 'notEmpty',
'required' => true,
'allowEmpty' => false,
'message' => 'Please enter a password'
),
'minLength' => array(
'rule' => array('minLength', 4),
'message' => 'Please enter a longer password'
),
'passwordConfirm' => array(
'rule' => array('checkPasswords'),
'message' => 'Passwords must match'
)
))
?>
Also, note that if you're using the Auth component your password will be hashed BEFORE it is validated. This means that even if you enter a 3-character password you'll end up with a 40-character hash, which obviously will validate as being longer than the minLength.

use my change password behavior. it takes care of all those things at a single and clean place:
http://www.dereuromark.de/2011/08/25/working-with-passwords-in-cakephp/
you will most certainly have more problems later on otherwise
because you need a lost password and change password functionality as well.
and maybe a backend for the admin to simply change passwords as well
and to your problem i already commented:
"you should also use last=>true here! otherwise it doesnt make much sense"
i believe this is also part of your problem. all your rules need this param to make it work properly. the error messages will be off otherwise.

Related

Changing validation on the fly in CakePHP

I'm using CakePHP 2.3.8 and I'm trying to figure out if there's a way to set certain validation rules to required on the fly.
For example, my User model has phone_number, username, email, and password validation. If a user wants to change their username, their phone number isn't required to do so. That means I can't set it to required, because then when changing a username, the phone_number will be expected to be present in the data.
public $validate = array(
'username' => array(
'minLength' => array(
'rule' => array('minLength', '3'),
'message' => 'A username with a minimum length of 3 characters is required'
),
'unique' => array(
'rule' => 'isUnique',
'message' => 'This username has already been taken.'
)
),
'email' => array(
'email' => array(
'rule' => array('email'),
'message' => 'Please enter a valid email address.',
),
'unique' => array(
'rule' => 'isUnique',
'message' => 'This email address is already in use'
)
),
'password' => array(
'rule' => array('minLength', '8'),
'message' => 'A password with a minimum length of 8 characters is required'
),
'phone_number' => array(
'rule' => array('valid_phone'),
'message' => 'Invalid phone number',
)
);
To get around this problem, in my controller for the corresponding action what I've been doing is checking to make sure the expected inputs have been posted. If not, set that index to null so that it is validated...such as
public function change_username(){
if(!isset($this->request->data['username'])){
$this->request->data['username'] = null;
}
$this->ExampleModel->set($this->request->data);
//if it wasn't posted, the username index will be created but set to null. This is my workaround for setting something to "required"
if($this->ExampleModel->validates() == true){
//do something
}
else{
//do something
}
}
While this works, I feel like it makes for a lot of extra coding, especially if I have a form that has a lot of inputs.
I've also tried to validate only the inputs that I need, but unless the data was posted, it ignores them. For example
if($this->ExampleModel->validates(array('fieldList' => array('phone')) == true){
.....
}
If "phone" wasn't posted, it doesn't validate it.
Is there any way to set required for a given input's validation to true on the fly? I found this article on using multiple validation rulesets and while it would accomplish what I want, there would be a lot of re-coding involved.
Before validation, can I set an input to required?
Firstly, in your Model validation rules you have phone_number but yet trying to validate phone, there aren't validation rules for phone.
It would be ideal request->data[] to match model fields, you can rebuild an array etc.
From book.cakephp:
This will add a single rule to the password field in the model. You can chain multiple calls to add to create as many rules as you like:
$this->validator()
->add('password', 'required', array(
'rule' => 'notEmpty',
'required' => 'create'
))
->add('password', 'size', array(
'rule' => array('between', 8, 20),
'message' => 'Password should be at least 8 chars long'
));

how to validate multiple model in cakephp

I want to use model validation.
lets i explain here clearly. in my view there is a file called "register.ctp". Also i have two table one is users and another is profiles, according to cakephp concept also i have two model that user model(User.php) and profile model(Profile.php).
My register.ctp contains the follow fields
name, email, address and phone all are mandatory - when i submit, name and email will store in users table and address and phone will store in profiles table
when i use model validation i have tried by using the below code that is working only for name and email but not working on for other fields.
here is my code for for model validation in user model(User.php)
public $validate = array(
'email' => array(
'blank' => array(
'rule' => 'notEmpty',
'message' => 'Please enter Email.'
)
),
'name' => array(
'rule' => 'notEmpty',
'message' => 'Please enter Name'
),
'address' => array(
'rule' => 'notEmpty',
'message' => 'Please enter Address'
),
'phone' => array(
'rule' => 'notEmpty',
'message' => 'Please enter Phone'
),
);
Thanks
You need to set the validation per model.
So in User.php:
public $validate = array(
'email' => array(
'blank' => array(
'rule' => 'notEmpty',
'message' => 'Please enter Email.'
)
),
'name' => array(
'rule' => 'notEmpty',
'message' => 'Please enter Name'
)
);
And in Profile.php:
public $validate = array(
'address' => array(
'rule' => 'notEmpty',
'message' => 'Please enter Address'
),
'phone' => array(
'rule' => 'notEmpty',
'message' => 'Please enter Phone'
)
);
And you need to validate both models in the Controller:
$this->User->set($this->data());
$valid = $this->User->validates();
$this->Profile->set($this->data);
$valid = $valid && $this->Profile->validates();
See these two model methods.
Model::validateAssociated() Validates a single record, as well as all its directly associated records.
Model::validateMany() validates multiple individual records for a single model
See Model::saveAll() as well. It can be used to validate the whole set of records and associated records. This will only validate but not save the reocrds as well:
$this->saveAll($data, array('validate' => 'only'));
I recommend you to read the whole documentation about saveAll() to understand how it works and what it will return when you only validate the data.
There is no need to manually validate each model one by one like noslone suggested. The single line above will do it as well.

cakephp ignores numeric validation - saves everything

my problem is that the numeric validation in cakephp doesn't work for one model. I can't find the reason. Other validations in this model work fine, like email...
my rules:
...
'fone' => array(
'Not empty' => array(
'rule' => 'notEmpty',
'message' => 'Please enter your fonenumber.'
),
'Numeric' => array(
'rule' => 'numeric',
'message' => 'Please enter your fonenumber.'
)
),
...
The db-field is varchar, and if I try something like 123abc it is saved. No error-message!
I tried:
public function beforeValidate($options) {
debug($this->data);
exit;
}
to see if the fields are transmitted - they are, else the values wouldn't be saved.
$this->Address->save($this->request->data) returns always true.
Thanks in advance!
try changing to this
'fone' => array(
'Numeric' => array(
'rule' => 'numeric',
'message' => 'Please enter your fonenumber.'
),
'Not empty' => array(
'rule' => 'notEmpty',
'message' => 'Please enter your fonenumber.'
),
),
Hoping it helps.
I got it,
it was my fault... I had an uninvalidate Function in the Model, which was called in the controller. I found it by checking other forms which access this model
Sorry!!!

Unique username and email with CakePHP Auth component

I'm new to Cake and building an application to learn it. I'm having a few troubles with my user registration system. So far this is my registration code in my Users controller:
public function register() {
$this->set('title_for_layout', 'Register');
if ($this->request->is('post')) {
$this->User->create();
if ($this->User->save($this->request->data)) {
$this->Session->setFlash('The user has been saved');
$this->redirect(array('action' => 'register'));
} else {
$this->Session->setFlash('The user could not be saved. Please, try again.');
}
}
}
And within my User model I have this method where I hash the passwords:
public function beforeSave() {
if (isset($this->data[$this->alias]['password'])) {
$this->data[$this->alias]['password'] = AuthComponent::password($this->data[$this->alias]['password']);
}
return true;
}
This works, the user is added to my users table in my database with their username, email and hashed password. However, there are no checks done to make sure the username and email are unique.
From my limited understanding, I would need to add some validation rules to my User model to make sure the username and email fields are unique before they're entered into the table? At the moment I just have these validation rules:
public $validate = array(
'username' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'A username is required'
)
),
'email' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'An email is required'
)
),
'password' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'A password is required'
)
)
);
Also, my registration form has a Password (confirm) field called passwordConf. I would like to check if the user entered his passwords correctly before they're entered into the users table, but I'm not sure how to do that. I'm guessing that somewhere in my register method I need to check if the two passwords are the same.
Thanks for any help.
The isUnique rule will work with your username and email fields. Here is a sample of code that shows how to use multiple rules per field:
public $validate = array(
'username' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'You must enter a username.'
),
'length' => array(
'rule' => array('between', 3, 15),
'message' => 'Your username must be between 3 and 15 characters long.'
),
'unique' => array(
'rule' => 'isUnique',
'message' => 'This username has already been taken.'
)
),
'password' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'You must enter a password.'
),
'length' => array(
'rule' => array('minLength', '6'),
'message' => 'Your password must be at least 6 characters long.'
)
),
'email' => array(
'email' => array(
'rule' => array('email'),
'message' => 'Please enter a valid email address.'
)
)
);
As for comparing the passwords just edit your beforeSave callback and check the passwords against each other, returning true if they match and false if they do not. Something like this:
public function beforeSave() {
if (isset($this->data[$this->alias]['password'])) {
if($this->data[$this->alias]['password'] === $this->data[$this->alias]['passwordConf']) {
$this->data[$this->alias]['password'] = AuthComponent::password($this->data[$this->alias]['password']);
return true;
} else {
return false;
}
}
return true;
}
CakePHP actually has a validation rule called isUnique, which you can use to check the username and e-mail. A list of built in rules can be found here. You can use this and the Data Validation Tutorial to check the user name and e-mail. As to checking if the passwords are the same, you MAY be able to use the EqualTo rule shown in the rules list, assuming you can make your validation rules on the fly every request.

cakephp: model validation rules, form field, ===

After studying Miles Jones cupcake forum plugin, I have a couple of questions here:
1)Is it compulsory for each field (that appears in a model's validation rules) to be a field in a database table? I found the following validation rules in the User model of cupcake forum plugin. oldPassword and newPassword are not fields in the users table. I'm confused coz' I thought I should only make validation rules for fields of table.
public $validate = array(
'username' => array(
'isUnique' => array(
'rule' => 'isUnique',
'message' => 'That username has already been taken',
'on' => 'create'
),
'notEmpty' => array(
'rule' => 'notEmpty',
'message' => 'Please enter a username'
)
),
'password' => array(
'rule' => 'notEmpty',
'message' => 'Please enter a password'
),
'oldPassword' => array(
'rule' => array('isPassword'),
'message' => 'The old password did not match'
),
'newPassword' => array(
'isMatch' => array(
'rule' => array('isMatch', 'confirmPassword'),
'message' => 'The passwords did not match'
),
'custom' => array(
'rule' => array('custom', '/^[-_a-zA-Z0-9]+$/'),
'message' => 'Your password may only be alphanumeric'
),
'between' => array(
'rule' => array('between', 6, 20),
'message' => 'Your password must be 6-20 characters in length'
),
'notEmpty' => array(
'rule' => 'notEmpty',
'message' => 'Please enter a password'
)
),
'email' => array(
'isUnique' => array(
'rule' => 'isUnique',
'message' => 'That email has already been taken',
'on' => 'create'
),
'email' => array(
//'rule' => array('email', true),//boolean true as second parameter verifies that the host for the address is valid -- to be uncommented once website is uploaded
'rule' => array('email'),
'message' => 'Your email is invalid'
),
'notEmpty' => array(
'rule' => 'notEmpty',
'message' => 'Your email is required'
)
)
);
2)Does each form field need to be a field in a database table?
For example when I ask a user to signup there will be: username, email addr, password and confirm password. But confirm password field doesn't need to be a field in a table right?
Is that a good practice?
I found the following isMatch function in form_app_model.php:
/**
* Validates two inputs against each other
* #access public
* #param array $data
* #param string $confirmField
* #return boolean
*/
public function isMatch($data, $confirmField) {
$data = array_values($data);
$var1 = $data[0];
$var2 = (isset($this->data[$this->name][$confirmField])) ? $this->data[$this->name][$confirmField] : '';
return ($var1 === $var2);
}
Can someone tell me on what is === in the last line of the above code?
Thank you.
That mean exactly equal (without type conversion) . For example: if y = 25, then y === 25 is true and y == '25' is true, but y === '25' is not true.
== means equal
=== mean identical
http://www.techsww.com/tutorials/web_development/php/tips_and_tricks/difference_between_equal_and_identical_comparison_operators_php.php

Categories