A password validator for symfony form framework

November 4, 2009

I’ve seen quite a few posts in the symonfy forum, asking for a password validation that allows to leave the password field blank if a password is already set. But of course the field should be required if no password exists.

There are different ways to solve this. For example you can set the a validator or the ‘required’ option depending on if the object is new or not. In this post I want to present a password validator so that a distinction by the developer is not necessary.

The validator

<?php

/**
 * Description of fkValidatorPasswordclass
 *
 * @author kling
 */
class fkValidatorPassword extends sfValidatorBase
{
  /**
  * Configures the current validator.
  *
  * Available options:
  *
  *  * password: The password that is already set (required)
  *  * pattern: A regex pattern or an array of regex patterns compatible
  *             with PCRE
  *  * password_field: The name of the password field
  *  * password_check_field: The name of the field to conpare the password with
  *
  * Available error codes:
  *
  *  * notequal
  *  * invalid
  *  * required
  *
  * @param array $options   An array of options
  * @param array $messages  An array of error messages
  *
  * @see sfValidatorBase
  */
  public function configure($options = array(), $messages = array())
  {
    $this->addRequiredOption('password', '');
    $this->addOption('pattern',array());
    $this->addOption('password_field', 'password');
    $this->addOption('password_check_field', 'password_check');

    $this->addMessage('notequal', 'Passwords are not euqal.');
  }

  protected function doClean($values)
  {
    $defaultPassword = (string) $this->getOption('password');
    $password = isset($values[$this->getOption('password_field')]) ? $values[$this->getOption('password_field')] : '';
    $password_check = isset($values[$this->getOption('password_check_field')]) ? $values[$this->getOption('password_check_field')] : '';

    $patterns = is_array($this->getOption('pattern')) ? $this->getOption('pattern') : array($this->getOption('pattern'));

    // check if a password is set in the form...
    if(!empty($password))
    {
      if(!empty($patterns))
      {
         foreach($patterns as $pattern)
         {
           if(!preg_match($pattern, $password))
           {
             throw new sfValidatorErrorSchema($this, array($this->getOption('password_field') => new sfValidatorError($this, 'invalid')));
           }
         }
      }
      // verify password
      if($password !== $password_check)
      {
        throw new sfValidatorErrorSchema($this, array($this->getOption('password_check_field') => new sfValidatorError($this, 'notequal')));
      }

    }
    else
    {
      // no password set in the form, check if a password is already set...
      if(empty($defaultPassword))
      {
        throw new sfValidatorErrorSchema($this, array($this->getOption('password_field') => new sfValidatorError($this, 'required')));
      }
      else
      {
         unset($values['password']);
      }
    }
    return $values;
  }
}

The options

This validator takes 4 options:

  • password: This option either takes an existing password or an empty string if no such exists. If an empty string is given, the user has to provide a password.
  • pattern: An array of regular expression. The password provided by the user has to match against these. It is an array so that it is possible to test the password against multiple requirements (although it is also possible to use Lookahead/Lookbehind, but to split it in serveral expression can increase readability).
  • password_field: The name of the password field, default to ‘password’.
  • password_check_field: The name of the field to verify the password. Default to ‘password_check’.

How the valditor works

First the validator checks, if a password is provided by the user:

YES:

  1. Test the password against regular expressions. If a test fails, throw an error for the password field.
  2. Verify the password. If the values of both fields don’t correspond and error for the second password field is thrown.

NO:

Test if a password is already set. If not, a ‘required’ for the password field is thrown. Otherwise the value ist just removed from the value array to not set it again.

Please feel free to use or change this code. I am also happy to hear about improvements!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: