Skip to content
Share this..

Complex Validation in CakePHP 1.2

2008 November 18
by Eddie

With version 1.2 we got a much more powerful validation feature. I think that many people migrating from version 1.1 may not realize how much it offers.

I offer a simple Users model. It has fields like username, password and email that require special and perhaps multiple validation rules. Here’s how we’ll get tricky;

  • Username must be atleast X characters without spaces,
  • Username must of course, Be unique!
  • Email must be valid email and Unique
  • Password must be confirmed during registration or renewal process
    That is to say compared.

We can also set a unique error message to each rule, and it will apply to both our add and edit forms.

 1. Controller

 2. Model

      2.1. 1.2 Users – In app/models/user.php

 3. View

      3.1. in app/views/users/register.ctp,

1. Controller

No special work is done in the controller, so you can just use your basic scaffolded controller action and $this->Model->save() method. All the trickery can be handled within the model.

2. Model

Here’s where the magic happens. We can use multiple rules per field. This included minimum / maximum length requirements; and for username, a special RegEX. The password field also has a basic RegEx check before calling in a method to compare the two password fields before signing off and hashing the field. Each individual rule is assigned its own error message.

2.1. 1.2 Users – In app/models/user.php

 
<!--?php <br ?--> class User extends AppModel{
var $name = 'User';
var $actsAs = array ('Userban'=&gt;array());
var $displayField = 'first_name';
var $recursive = 0;
var $validate = array(
'username' =&gt; array(
'required' =&gt; array('rule'=&gt;VALID_NOT_EMPTY,'message'=&gt;'Please enter your login name'),
'pattern' =&gt; array('rule' =&gt; array('custom','/[a-zA-Z0-9\_\-]{6,30}$/i'),'message'=&gt;'Must be 4 characters or longer with no spaces.'),
'unique' =&gt; array('rule' =&gt; array('validateUniqueUsername'),'message'=&gt;'This username is already in use, please try another.'),
),
'first_name' =&gt; array(
'required' =&gt; array('rule'=&gt;VALID_NOT_EMPTY,'message'=&gt;'You\'ll need a name friends and family will recognize!'),
'length' =&gt; array( 'rule' =&gt; array('maxLength', 60),'message'=&gt;'That names a bit too long, keep it under 60 characters' )
),
'last_name' =&gt; array(
'required' =&gt; array('rule'=&gt;VALID_NOT_EMPTY,'message'=&gt;'You\'ll need a name friends and family will recognize!'),
'length' =&gt; array( 'rule' =&gt; array('maxLength', 60),'message'=&gt;'That names a bit too long, keep it under 60 characters' )
),
'password' =&gt; array(
'required' =&gt; array('rule' =&gt; array('custom','/[a-zA-Z0-9\_\-]{6,}$/i'),'message'=&gt;'Must be 6 characters or longer'),
'length' =&gt; array( 'rule' =&gt; 'validatePassword','message'=&gt;'Your passwords dont match!' )
),
'email' =&gt; array('rule'=&gt;'email','message'=&gt;'Please enter your email address')
);
 
/**
* validation functions
*/
 
/**
* Check for existing user
*/
function validateUniqueUsername(){
$error=0;
//Attempt to load based on data in the field
$someone = $this-&gt;findByUsername($this-&gt;data['User']['username']);
// if we get a result, this user name is in use, try again!
if (isset($someone['User']))
{
$error++;
//debug($someone);
//exit;
 
}
return $error==0;
}
 
function validatePassword(){
$passed=true;
//only run if there are two password feield (like NOT on the contact or signin pages..)
if(isset($this-&gt;data['User']['confirmpassword'])){
 
if($this-&gt;data['User']['password'] != $this-&gt;data['User']['confirmpassword']){
//die('you fail');
$this-&gt;invalidate('checkpassword');
//they didnt condifrm password
$passed=false;
}else{
//hash passwordbefore saving
$this-&gt;data['User']['password']=md5($this-&gt;data['User']['password']);
}
}
 
return $passed;
}
 
}?&gt;

3. View

3.1. in app/views/users/register.ctp,

<div id="view_page">
<h2>register</h2>
<form action="&lt;?php echo $html-&gt;url('/users/register'); ?&gt;" method="post">
<div class="required"></div>
<div class="required"></div>
<div class="required"></div>
&nbsp;
 
&nbsp;
<div class="required"><!--?php echo $form--->input('User.email', array('size' =&gt; '40','div'=&gt; false ));?&gt;
<!--?php echo $form--->error('User.duplicateemail','Sorry, <b> That email is already is use</b>
'.$html-&gt;link('Is it yours?','/users/resetpassword/'.$this-&gt;data['User']['email']).' ',array('escape'=&gt;false))?&gt;</div>
<div class="required"><!--?php echo $form--->input('User.check', array('size'=&gt;'10','label'=&gt;$botQuestion,'error'=&gt;'Are you human?','div'=&gt;false));?&gt;
<!--?php echo $form--->error('User.', 'Are you human!');?&gt;</div>
<div class="submit"></div>
</form></div>
<!--?php echo pr($this--->data);?&gt;

As you can see, the limits to validation are endless because worse scenario you write your own method unique to the situation.

Post Script:

Any feedback on the new syntax highlighting would be appreciated.  This one allows direct copy to your clipboard, and plain text viewing but trashes the formatting.  Maybe someone knows of another plugin for wordpress to do the same. If not I think I’ll stick with GeSHi

11 Responses leave one →
  1. Javier permalink
    November 20, 2008

    AFAIK, you don’t need to write your own custom ValidateUniqueUsername function. You can just specify the rule:

    array('rule' => 'isUnique', 'field' => 'username', 'message' => 'This username is already in use, please try another')

  2. November 20, 2008

    Hi, thanks very much for this post. Saved me time.

    Little recommendation, though. In the model, instead of manually hash the password, try this better:

    Security::hash($this->data['User']['password'],null,true);

    that will use default hashing algorithm and salt.

  3. Eddie permalink*
    November 20, 2008

    @Javier
    Excellent correction, I completely looked over that method myself.

    Anyone else may find more info on the isUnique method,
    http://api.cakephp.org/class_model.html#e631f2cba7ec7fff079d3a7b62c46f0e

    @Zarate, glad it helped you, and thanks for the tip!

    Anyone who wants to know more about the Hash function should visit the API,
    http://api.cakephp.org/security_8php-source.html#l00119.

    For a bit more info on SHA1 and MD5 encryption this thread may be interesting,
    http://www.sandelman.ottawa.on.ca/ipsec/1996/05/msg00116.html.

  4. December 12, 2008

    Just a quick note…

    VALID_NOT_EMPTY has deprecated and is now replaced by the ‘notEmpty’ rule…

    so ‘rule’=>’notEmpty’ is the “new” way of handling that validation.

  5. Mirthis permalink
    January 26, 2009

    Pretty interesting, I’ll use it as starting point for my user model. Thanks^^

  6. Eddie permalink*
    January 26, 2009

    @Mirthis
    Glad you found it useful. You may be interested to check out http://edwardawebb.com/programming/php-programming/cakephp/reset-lost-passwords-cakephp for some additional requirements in a User model.

  7. sooid permalink
    February 9, 2009

    Nice tutorial but I’m missing one thing that was explained in the previous tutorial concerning passwords. The password length is no problem, those rules are all pretty easy to handle. But I want my passwords to have at least 1 upper case and 1 special character and I just can’t figure out a proper rule for that. How would I do that? Thanks in advance.

  8. Eddie permalink*
    February 9, 2009

    @sooid Thanks.
    I think if you have a look at my article on validating passwords you’ll find what you need.

    This password must be 8 characters
    Contain a Number
    Contain a special character
    Contain a Capital Letter
    Contain a Lowercase Letter

    Basically you just remove the original parentheses grouping digits and non-words in the original regex I think you refer to.

    I added a Ludicrously Complex regex on that page.

  9. LaneOlson permalink
    September 17, 2009

    Just a quick question… Isn’t the password hashed before the validation takes place? Wouldn’t this make checking password complexity inaccurate because you are checking the length of the hash opposed to the actual password the user has entered?

  10. Eddie permalink*
    September 17, 2009

    @Lane
    Good Question

    I don’t use the Auth component and hash the password myself after I do validation. You’ll notice these lines in the code above in the model’s validation

    //hash passwordbefore saving
    $this->data['User']['password']=md5($this->data['User']['password']);
    }

Trackbacks and Pingbacks

  1. Validating complex passwords with CakePHP | Edward A. Webb (.com)

Leave a Reply

Note: You can use basic XHTML in your comments. Your email address will never be published.

Subscribe to this comment feed via RSS