cakephp Validation rules aren't holding on submit - php

User Model
//...
public $validate = array(
"username" => array(
"alpha-numeric" => array(
'rule' => 'alphaNumeric',
'required' => true,
'message' => 'Username must contain only numbers and letters.'
),
"between" => array(
"rule" => array("between", 4, 25),
"message" => "Username must contain between 4 to 25 characters."
)
),
//...
User Controller
public function index() {
debug($this->data); // displays values as expected
debug($this->User->validates()); // always false, unless I remove alphanumeric rule
}
On submit, my form will always validate the username field as false (triggering its corresponding message), no matter what is in the text. The remaining fields are also not validated. If I remove the username validation rules all together, the remaining fields are still not validated. (Form is submitted as though validated)
What am I missing here?

Before manually calling $this->User->validates(), you must call the model's set method and provide the form's data.
public function index() {
$this->User->set($this->request->data); // Only way the next method will work.
debug($this->User->validates());
}

Related

CakePHP validation error on an optional field

I'm creating a form in CakePHP, where there is a field that is output only on certain conditions. However, when it is not output, validation invalidates it. I'm not sure where I did wrong?
Validation in Model:
public $validate = array(
'extra_requirement_ok' => array(
'notEmpty' => array(
'rule' => array('comparison', '!=', 0),
//'required' => false,
'message' => 'Must'
),
),
);
The input in the view:
if ($check) {
echo $this->Form->input('extra_requirement_ok');
}
EDITED:
When I check the data that is passed when is submitted, array key for extra_requirement_ok does not exist. But I created a custom validation and check the array that is passed to the custom validation function, it returns extra_requirement_ok = '0'. What gives?
I figured this out.
I set 0 as defined value in the database, as the data is being saved, 0 is generated by default and that triggered validation. Now the database column is set to NULL and it's fine now.

CakePHP: Edit Users without changing password

How do I save users in my CakePHP app without requiring them to change their password each time?
I have code in place to check the two password fields and apply some verification rules, which works great for registration and for changing passwords in the 'edit' view. However, how do I skip the verification rules and saving the password if the password fields are left empty in the Edit view? Obviously, I don't want to skip this requirement on registration.
register.ctp and edit.ctp:
echo $form->create('User');
echo $form->input('username');
echo $form->input('pwd');
echo $form->input('pwd_repeat');
echo $form->end('Submit');
User.ctp validation rules:
'pwd' => array(
'length' => array(
'rule' => array('between', 8, 40),
'message' => 'Your password must be between 8 and 40 characters.',
),
),
'pwd_repeat' => array(
'length' => array(
'rule' => array('between', 8, 40),
'message' => 'Your password must be between 8 and 40 characters.',
),
'compare' => array(
'rule' => array('validate_passwords'),
'message' => 'The passwords you entered do not match.',
),
),
and the User.ctp logic before saving:
public function validate_passwords() { //password match check
return $this->data[$this->alias]['pwd'] === $this->data[$this->alias]['pwd_repeat'];
}
public function beforeSave($options = array()) { //set alias to real thing and hash password
$this->data['User']['password'] = $this->data[$this->alias]['pwd'];
$this->data['User']['password'] = AuthComponent::password($this->data['User']['password']);
return true;
}
var $validate = array(
'pwd' => array(
'length' => array(
'rule' => array('between', 8, 40),
'message' => 'Your password must be between 8 and 40 characters.',
'on' => 'create', // we only need this validation on create
),
),
// if we have a password entered, we need it to match pwd_repeat (both create and update)
// we no longer need the length validation
'pwd_repeat' => array(
'compare' => array(
'rule' => array('validate_passwords'),
'message' => 'Please confirm the password',
),
),
);
public function validate_passwords() { //password match check
return $this->data[$this->alias]['pwd'] === $this->data[$this->alias]['pwd_repeat'];
}
public function beforeSave($options = Array()) {
// if we have a password, we hash it before saving
if (isset($this->data[$this->alias]['pwd'])) {
$this->data[$this->alias]['password'] = AuthComponent::password($this->data[$this->alias]['pwd_repeat']);
}
return true;
}
If you are using CakePHP 2.2:
http://book.cakephp.org/2.0/en/models/data-validation.html#removing-rules-from-the-set
Also in the beforeSave function wrap the first two lines in a conditional for if both the password fields are not empty.
For those who want something without changing the model (and keeping rule onUpdate if new password send) : Updating user with or without password - CakePHP
TL;DR :
// add in your view `app/View/Users/edit.ctp`
// a 'fake' field you'll only use on the controller
echo $this->Form->input('new_password');
// add in your controller `app/Model/User.php`
// if we have a new password, create key `password` in data
if(!empty($new_password = $this->request->data['User']['new_password']))
$this->request->data['User']['password'] = $new_password;
else // else, we remove the rules on password
$this->User->validator()->remove('password');
Just remove the field from edit.ctp
echo $form->create('User');
echo $form->input('username');
//echo $form->input('pwd');
//echo $form->input('pwd_repeat');
echo $form->end('Submit');
Because this->request->data populates hashed password in the password field. When you save the user password hashed again and become different then original one

Password Confirm Validation CakePHP

I have searched far and wide, tried every trick in the book, but I still can't get my CakePHP application to perform simple Password Confirm validation. I've tried creating a custom validation rule like this:
'passwordequal' => array('rule' => 'checkpasswords' , 'message' => 'Passwords Do Not Match')
Then defined 'checkpasswords' like this:
public function checkpasswords(){
if(strcmp($this->data['User']['new_password'],$this->data['User']['confirm_password']) == 0 )
{
return true;
}
return false;
}
'new_password' and 'confirm_password' are the password input fields. This didn't work. Then I tried one in which I hashed the 'confirm_password'. That didn't work either. I have other 'rules' as well that are not being validated, like 'notempty', which I believe is one of the standard CakePHP rules. Can anybody please help. I know this question has been asked a few times but none of those solutions have worked for me. CakePHP documentation hasn't helped much either.
two fields in view file
echo $this->Form->input('password');
echo $this->Form->input('repass');
Model file
<?php
class Post extends AppModel {
public $validate = array(
'repass' => array(
'equaltofield' => array(
'rule' => array('equaltofield','password'),
'message' => 'Require the same value to password.',
//'allowEmpty' => false,
//'required' => false,
//'last' => false, // Stop validation after this rule
'on' => 'create', // Limit validation to 'create' or 'update' operations
)
)
);
function equaltofield($check,$otherfield)
{
//get name of field
$fname = '';
foreach ($check as $key => $value){
$fname = $key;
break;
}
return $this->data[$this->name][$otherfield] === $this->data[$this->name][$fname];
}
}?>
Seems like your model is not loading correctly and using a dynamically generated model.
Comparing passwords in 2.x is nothing more than comparing any two fields as cake no longer hashes the pw automatically.
Can you confirm your validation method is being run, seems like its not especially if simple things like notEmpty is not working.

Displaying Form Error Messages from Array

I wanted to incorporate GUMP https://github.com/Wixel/GUMP into my site for server side validation. But unfortunately the documentation is light and I am new to PHP.
Here is my validation code:
//Validation
$gump = new GUMP();
$rules = array(
'dept' => 'required|numeric',
'hosp' => 'required|numeric',
'subhosp' => 'required|numeric',
'user' => 'required|numeric',
'gpo' => 'required|boolean|exact_len,1',
'clin' => 'required|valid_name',
'clinmail' => 'required|valid_email',
'comp' => 'required|alpha_dash',
'cpt' => 'required|alpha_dash',
'past' => 'required|boolean|exact_len,1',
'latex' => 'required|boolean|exact_len,1',
);
$validated = $gump->validate($_POST,$rules);
print_r($validated); // Something went wrong
The output from the above code gives me an array like so when I am looking at my AJAX response in FireBug:
Array
(
[0] => Array
(
[field] => clin
[value] => .-0
[rule] => validate_valid_name
)
[1] => Array
(
[field] => clinmail
[value] => %$sd
[rule] => validate_valid_email
)
)
And I what I need is something like so:
<div class="error-msg">You did not enter a valid email address</div><br>
<div class="error-msg">You did not enter a valid username</div><br>
From the documentation I get:
if($validated === TRUE)
{
// Do something, everything went well
}
else
{
// This is where I am stuck. Do I have to loop through and put my <div> tags here?
}
My question is how would the community handle outputting error messages with this class? My only thought is that I loop through the results above and output different messages depending on the field and the rule that was broken but that seems tedious. Is there a better way or a better class to use that does standalone PHP input validation? I was using another very easy to use class but it started breaking when I moved away from inline PHP to AJAX.
edit your code to:
$gump = new GUMP();
$rules = array(
'dept' => 'required|numeric',
'hosp' => 'required|numeric',
'subhosp' => 'required|numeric',
'user' => 'required|numeric',
'gpo' => 'required|boolean|exact_len,1',
'clin' => 'required|valid_name',
'clinmail' => 'required|valid_email',
'comp' => 'required|alpha_dash',
'cpt' => 'required|alpha_dash',
'past' => 'required|boolean|exact_len,1',
'latex' => 'required|boolean|exact_len,1',
);
$error_texts = array(
'dept' => 'You must enter a numeric value',
'hosp' => 'You must enter a numeric value',
'subhosp' => 'You must enter a numeric value',
'user' => 'You must enter a numeric value',
'gpo' => 'You must enter a boolean value',
'clin' => 'You must enter a valid name',
'clinmail' => 'You must enter a valid email',
'comp' => 'You must enter a valid alpha dash',
'cpt' => 'You must enter a valid alpha dash',
'past' => 'You must enter 1 char',
'latex' => 'You must enter 1 char',
);
$validated = $gump->validate($_POST,$rules);
if($validated === TRUE)
{
echo "Every thing is ok";
}
else
{
foreach($validated as $key=>$error)
{
echo '<div class="error-msg">' . $error_texts["{$error['field']}"] . '</div><br />';
}
}
I would like to add that if a validation fails twice, for example if a value is required and has to exist out of more than 10 characters then #semsems answer would print multiple lines for the same field.
I changed the above code and added:
$_validated = array();
foreach($validated as $key=>$error)
{
if ( !in_array($error['field'], $_validated) )
{
print '<div class="error-msg">' . $error_texts["{$error['field']}"] . '</div>';
$_validated[] = $error['field'];
}
}
I know this question is a year old and been answered, but since I based myself on the accepted answer and in my view made it a sweet better (completely generic with locale as extra), I thought it would be nice to share and get some feedback... what do you guys think about my code? Now based on semsem's answer... I like the way he coded part of it and I derived from it to come up with the following code:
First I extended GUMP with my own class so I could overwrite some functions
<?php
require("gump.class.php");
class GumpValidator extends GUMP
{
private $locale;
private $translator;
public function GumpValidator($lang = "en")
{
$this->locale = $lang;
$this->loadValidationLocales();
}
/** Overwrite the default validate() function of GUMP so that I can add an extra "message" property */
public function validate(array $input, array $ruleset)
{
$validated_data = GUMP::validate($input, $ruleset);
if(is_array($validated_data)) {
foreach($validated_data as $index=>$error) {
$validation = str_replace(":attribute", $error['field'], $this->translator[$error['rule']]);
$validation = str_replace(":param", $error['param'], $validation);
$validated_data[$index++]['message'] = $validation;
}
}
return $validated_data;
}
/** Depending on the language locale, load the proper set of validation messages */
private function loadValidationLocales()
{
$this->translator = require "/lang/" . $this->locale . "/validation.php";
return $this->translator;
}
} // EOC
Then as you can see from the extended class, I created myself a set of locale language message for validation and I took the full list of possible validation errors directly from the GUMP code on Github, take a look at the function get_readable_errors() to get the full list of errors. Github link here... The locales which I created are saved under separate language folders /lang/en/validation.php, /lang/fr/validation.php, etc... You can easily create as many as you want... I took the concept from Laravel Framework... These validation.php files looks for example, like this (1 file per language/locale), here is the English one:
<?php
return array(
"validate_alpha" => "The :attribute may only contain letters.",
"validate_alpha_numeric" => "The :attribute may only contain letters and numbers.",
.....
);
Then finally in my POST to validate code I just call it like this:
// load my extended class with language locale I want to use
$gump = new GumpValidator("en");
// now validate the data
$validated_data = $gump->validate( $_POST, $rules );
So at the end I get the extra property of message inside the $validated_data object returned with the option of whichever locale language I chose to display the error message...and voilĂ !!! In my case I read the code in javascript to display the errors in Bootstrap alert, but if you want PHP you can look at semsem answer as well. So at the end, I know it takes more code since I have an extra class to wrap it and extra locales, but isn't sweet to first have it generic (per validation errors) and second to have multiple locale language easily?

How to use only certain validation set for validating data in Cake PHP?

I was trying to validate my User model data and I came upon this problem.
Say i have the following validation rules, stored in $validate variable:
var $validate=array(
"username" => array(
"usernameCheckForRegister" => array(
"rule" => ...,
"message" => ...
),
"usernameCheckForLogin" => array(
"rule" => ...,
"message" => ...
)
),
//rules for other fields
);
In the UsersController controller, I have two actions: register() and login().
The problem is, how do I validate the username field in the register() action using ONLY the usernameCheckForRegister rule, and how do I validate the username field in the login() action, using the other rule, usernameCheckForLogin?
Is there any behaviour or method in CakePHP which allows me to choose which set of rules to apply to a form field when validating?
Thank you in advance for your help!
I think I ran over the solution that fits my needs.
http://bakery.cakephp.org/articles/view/multivalidatablebehavior-using-many-validation-rulesets-per-model
Instead of defining several rules for each field, this behaviour implies defining several "general" rules under which you define all your field-related rules.
So, instead of doing:
var $validate=array(
"username" => array(
"usernameCheckForRegister" => array(
"rule" => ...,
"message" => ...
),
"usernameCheckForLogin" => array(
"rule" => ...,
"message" => ...
)
),
//rules for other fields
);
you do:
/**
* Default validation ruleset
*/
var $validate = array(
'username' => /* rules */,
'password' => /* rules */,
'email' => /* rules */
);
/**
* Custom validation rulesets
*/
var $validationSets = array(
'register' => array(
'username' => /* rules */,
'password' => /* rules */,
'email' => /* rules */,
),
'login' => array(
'username' => /* rules */,
'password' => /* rules */
)
);
And then in your controller you toggle between validation sets like this:$this->User->setValidation('register');
Even though you have to write a little bit more code, I think this solution best fits my needs
Check the manual:
var $validate=array(
"username" => array(
"usernameCheckForRegister" => array(
"rule" => ...,
"message" => ...,
"on" => "create"
),
"usernameCheckForLogin" => array(
"rule" => ...,
"message" => ...,
"on" => "update"
)
),
//rules for other fields
);
UPDATE: Oh... I just noticed that it seems impossible to use validation rule on login unless you update the user at each login attempt. You can modify login() method to verify the username instead.
Bit of a clunky solution but I've just been unsetting the ones I don't use from within the Controller. Could get messy but for a simple login/register it does the trick.
unset($this->User->validate['username']['usernameCheckForRegister']);

Categories