Code snippets for symfony 1.x

Navigation

Refine Tags

Snippets tagged "validation"

Disable fillin filter after validation success

When using fillin filter, after validation success (all form fields are ok) if you want display page without form, fillin filter is still enabled and throws exception "Exception - No form found in this page". Use this snippet to prevent it.

in sfFillInFormFilter.class.php file

  public function execute($filterChain)
  {
    // execute next filter
    $filterChain->execute();
 
    $context  = $this->getContext();
    $response = $context->getResponse();
    $request  = $context->getRequest();
 
    // add these two lines
    if(! $request->hasErrors())
        return;
 
by jarecky on 2007-11-20, tagged fillin  filter  form  validation 

YML validation in actions

Currently i had to do different validations of data depending the data entered by the user.

The solution i found, using the symfony built-in yml validation was:

action:

$validated = true;
$validationConfig = $this->getModuleName().'/'.sfConfig::get('sf_app_module_validate_dir_name').'/'.$validationFile.'.yml';
 
if (null !== $validateFile = sfConfigCache::getInstance()->checkConfig(sfConfig::get('sf_app_module_dir_name').'/'.$validationConfig, true))
{
    $context = $this->getContext();
    $validatorManager = new  sfValidatorManager();
        $validatorManager->initialize($context);
    require($validateFile);
    $validated = $validatorManager->execute();
}
 

refactoring:

public function validateParamsYml($validationFile) {
        $validated = true;
        $validationConfig = $this->getModuleName().'/'.sfConfig::get('sf_app_module_validate_dir_name').'/'.$validationFile.'.yml';
 
        if (null !== $validateFile = sfConfigCache::getInstance()->checkConfig(sfConfig::get('sf_app_module_dir_name').'/'.$validationConfig, true))
        {
            $context = $this->getContext();
            $validatorManager = new sfValidatorManager();
            $validatorManager->initialize($context);
            require($validateFile);
            $validated = $validatorManager->execute();
        }
        return $validated;
    }
 

Then you can call any validations rules at your action:

public function executeXXX() {
  [...]
  [...]
  $this->validateParamsYml('yml_1');
  $this->validateParamsYml('yml_2');
  [...]
}
 

and finally check if everything was validated then forward/save the data:

if($this->getRequest()->hasErrors()) {
            return $this->handleErrorXXXX();
        }
 

Cheers

by Lucas Peres on 2007-10-02, tagged validation 

Form validation in AJAX

The example is for a blog. The page that displays a post also proposes an AJAX form to add a comment. We want that when the validation of this form fails, it displays again in the page with an error message, and when the validation succeeds, the form is replaced byu the comment just posted.

The idea is to take advantage of the way the update option of the form_remote_tag() helper works. It accepts an associative array, where you can specify different zones to update in case of success and failure. The only problem is that for Prototype, a failure is a return code other than 2XX. So when we return the form showing the error message again, we need to set the status code to 404, for instance, for Prototype to choose to update the correct zone.

That, plus the usual use of partials here and there, and you have a working solution:

in modules/post/actions/action.class.php

// Display the form
public function executeShow()
{
  $this->post = PostPeer::retrieveByPk($this->getRequestParameter('post_id'));
}

in modules/post/templates/showSuccess.php

// Display question detail here
...
// Beginning of Comment zone
<div id="added_comment" style="display_none"> </div>
<div id="add_comment">
  <?php include_partial('comment/add_comment', array('post' => $post)) ?>
 </div>

in modules/comment/templates/_add_comment.php

<?php use_helper('Javascript', 'Validation') ?>
<?php echo form_remote_tag(array(
  'url'     => 'comment/add',
  'update'  => array('success' => 'added_comment', 'failure' => 'add_comment'),
  'script'  => true,
  'loading' => "Element.show('indicator')",
  'success' => "Element.hide('indicator');Element.show('added_comment');Element.hide('add_comment');",
  'failure' => "Element.hide('indicator');",
)) ?>
  <?php echo input_hidden_tag('post_id', $post->getId()) ?>
  <?php echo form_error('body') ?>
  <label for="body">Your comment</label>
  <?php echo textarea_tag('body') ?>
  <?php echo submit_tag('Send') ?>
</form>

in modules/comment/validate/add.yml

methods:
  post: [body]
 
fillin:
  activate:        Yes
 
names:
  body:
    required:      Yes
    required_msg:  You must provide a comment
    validators:    spamValidator
 
spamValidator:
   class:          sfRegexValidator
   param:
     match:        No     
     pattern:      /http.*http/
     match_error:  Do not provide more than one URL - It is considered Spam

in modules/comment/actions/action.class.php

public function handleErrorAdd()
{
  $this->post = PostPeer::retrieveByPk($this->getRequestParameter('post_id'));
  $this->getResponse()->setStatusCode(404);
  return sfView::ERROR;
}
 
public function executeAdd()
{
  $post = PostPeer::retrieveByPk($this->getRequestParameter('post_id'));
  $this->forward404Unless($post);
  $comment = new Comment();
  $comment->setPost($post);
  $comment->setAuthor($this->getUser()->getAuthor());
  $comment->setBody($this->getRequestParameter('body'));
  $comment->save();
  $this->comment = $comment;
}

in modules/comment/templates/addError.php

<?php include_partial('comment/add_comment', array('post' => $post)) ?>

in modules/comment/templates/addSuccess.php

Your comment has been added:
<div class="comment">
  <?php echo $comment->getBody() ?>
</div>

As a bonus, the form is still there after a successful submission (but hidden), so with a few more lines of code, you can still provide a Digg-like "edit comment for the next 60 seconds" feature.

by Francois Zaninotto on 2006-10-16, tagged ajax  forms  validation 
(10 comments)

sfCustomUniqueValidator:

This snippet allow to check if an entry allready exists in a database but, at the difference of the sfUniqueValidator, you can provide as many fields as desired to perform the verification.

Installation:

The first thing you need to do is to create the file sfCustomUniqueValidator.php in your project lib directory:

<?php
  /**
 * sfCustomUniqueValidator checks if a record exist in the database with all the mentionned fields.
 *
 * ex: Check if a companie with company_name exist in country_id 
 *   class:            sfCustomUniqueValidator
 *   param:
 *     class:          Companies    //the class on which the search is performed
 *     nb_fields:      2            //the number of fields on which the comparison is done
 *     field_1:        company_name //First field of the comparison
 *     field_2:        country_id   //Other country for the comparison
 *
 * @package    lib
 * @author     Joachim Martin
 * @date       15/06/2007
 */
 
class sfCustomUniqueValidator extends sfValidator {
 
   /**
   * Executes this validator.
   *
   * @param mixed A file or parameter value/array
   * @param error An error message reference
   *
   * @return bool true, if this validator executes successfully, otherwise false
   */
 
    public function execute(&$value, &$error) {
 
        $className  = $this->getParameter('class').'Peer';
 
        //Get fields number
        $nb_fields = $this->getParameter('nb_fields');
 
        //Define new criteria       
        $c = new Criteria();
 
        //Loop on the fields
        for($i = 1; $i <= $nb_fields ; $i++) {
            //Retrieve field_$i 
            $check_param = $this->getParameterHolder()->get("field_$i");
            $check_value = $this->getContext()->getRequest()->getParameter($check_param);
 
            //If check value defined        
            if ($check_value != '') {   
                //Adding field to the criteria
                $columnName = call_user_func(array($className, 'translateFieldName'), $check_param, BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_COLNAME);
                $c->add($columnName, $check_value);
            }
        }
 
        $object = call_user_func(array($className, 'doSelectOne'), $c);
 
        if ($object)
        {
          $tableMap = call_user_func(array($className, 'getTableMap'));
          foreach ($tableMap->getColumns() as $column)
          {
            if (!$column->isPrimaryKey())
            {
              continue;
            }
 
            $method = 'get'.$column->getPhpName();
            $primaryKey = call_user_func(array($className, 'translateFieldName'), $column->getPhpName(), BasePeer::TYPE_PHPNAME, BasePeer::TYPE_FIELDNAME);
            if ($object->$method() != $this->getContext()->getRequest()->getParameter($primaryKey))
            {
              $error = $this->getParameter('custom_unique_error');
 
              return false;
            }
          }
        }
 
        return true;
    } 
 
    public function initialize ($context, $parameters = null) {
        // initialize parent
        parent::initialize($context);
 
        //Set default parameters value
        $this->setParameter('custom_unique_error','The value is not unique');
 
        $this->getParameterHolder()->add($parameters);
 
        // check parameters
        if (!$this->getParameter('class'))
        {
          throw new sfValidatorException('The "class" parameter is mandatory for the sfCustomUniqueValidator validator.');
        }
 
        if (!$this->getParameter('nb_fields'))
        {
          throw new sfValidatorException('The "nb_fields" parameter is mandatory for the sfCustomUniqueValidator validator.');
        }
 
        return true;
    }
}

Usage:

The following code check if a companie with the same name and same activity exists in the same country

sfCustomUniqueValidator:
      class:                   Companies
      nb_fields:               3
      field_1:                 company_name
      field_2:                 activity_id
      field_3:                 country_id
      custom_unique_error:     This company already exist for this country

class: the model to test

nb_fields: how many fields will be checked

field_x: a field to test, obviously you need to have as many field_x as the nb_fields value

custom_unique_error: your error message

This is my very first contribution to symfony so feel free to comment/optimize.

by joachim martin on 2007-06-21, tagged unique  validation  validator 
(5 comments)

sfFileImageValidator

Description:

This images validations is an extention for the sfFileValidator. You can use it for validate uploaded images maximum width and height, minimum width and height and if the images have square dimensions.

<?php
 
/**
 * sfFileImageValidator allows you to apply constraints to image file upload, it extend the sfFileValidator functions.
 *
 * <b>Optional parameters:</b>
 *
 * # <b>max_height</b>         - [none]                                - Maximum images height in pixels.
 * # <b>max_height_error</b>   - [The file height is too large]        - An error message to use when
 *                                                                       images height is too large.
 * # <b>max_width</b>          - [none]                                - Maximum images width in pixels.
 * # <b>max_width_error</b>    - [The file width is too large]         - An error message to use when
 *                                                                       images width is too large.
 * # <b>min_height</b>         - [none]                                - Minimum images height in pixels.
 * # <b>min_height_error</b>   - [The file height is too small]        - An error message to use when
 *                                                                       images height is too small.
 * # <b>min_width</b>          - [none]                                - Minimum images width in pixels.
 * # <b>min_width_error</b>    - [The file width is too small]         - An error message to use when
 *                                                                       images width is too small.
 * # <b>is_square</b>          - [false]                               - The image is a square
 * # <b>is_square_error</b>    - [The file is not a square]            - An error message to use when
 *                                                                       the images is not a square
 *                                                                       (The width size is not equal
 *                                                                       to the height size).
 * @package    symfony
 * @subpackage validator
 * @author     Daniel Santiago 
 */
 
class sfFileImageValidator extends sfFileValidator
{
  /**
   * Executes this validator.
   *
   * @param mixed A file or parameter value/array
   * @param error An error message reference
   *
   * @return bool true, if this validator executes successfully, otherwise false
   */
 
  public function execute(&$value, &$error)
  {
    if (parent::execute($value, $error))
    {
      list($width, $height) = @getimagesize($value['tmp_name']);
 
      // File is not a square
      $is_square = $this->getParameter('is_square');
      if ($is_square && $width != $height)
      {
        $error = $this->getParameter('is_square_error');
 
        return false;
      }
 
      // File height too large
      $max_height = $this->getParameter('max_height');
      if ($max_height !== null && $max_height < $height)
      {
        $error = $this->getParameter('max_height_error');
 
        return false;
      }
 
      // File width too large
      $max_width = $this->getParameter('max_width');
      if ($max_width !== null && $max_width < $width)
      {
        $error = $this->getParameter('max_width_error');
 
        return false;
      }
 
      // File height too small
      $min_height = $this->getParameter('min_height');
      if ($min_height !== null && $min_height > $height)
      {
        $error = $this->getParameter('min_height_error');
 
        return false;
      }
 
      // File width too small
      $min_width = $this->getParameter('min_width');
      if ($min_width !== null && $min_width > $width)
      {
        $error = $this->getParameter('min_width_error');
 
        return false;
      }
 
      return true;
    }
  }
 
  /**
   * Initializes this validator.
   *
   * @param sfContext The current application context
   * @param array   An associative array of initialization parameters
   *
   * @return bool true, if initialization completes successfully, otherwise false
   */
  public function initialize($context, $parameters = null)
  {
    // initialize parent
    parent::initialize($context, $parameters);
 
    // set defaults
    $this->getParameterHolder()->set('max_height',        null);
    $this->getParameterHolder()->set('max_height_error',  'The file height is too large');
    $this->getParameterHolder()->set('max_width',         null);
    $this->getParameterHolder()->set('max_width_error',   'The file width is too large');
    $this->getParameterHolder()->set('min_height',        null);
    $this->getParameterHolder()->set('min_height_error',  'The file height is too small');
    $this->getParameterHolder()->set('min_width',         null);
    $this->getParameterHolder()->set('min_width_error',   'The file width is too small');
    $this->getParameterHolder()->set('is_square',         false);
    $this->getParameterHolder()->set('is_square_error',   'The file is not a square');
 
    $this->getParameterHolder()->add($parameters);
 
    return true;
  }
}
 

How to use it?

In the YAML validation file put this:

  news{photo}:
    file:     yes
    sfFileImageValidator:
      min_height:       100
      min_height_error: 'The image height is too small, it must have minimum 100px'
      min_width:        120
      min_width_error: 'The image width is too small, it must have minimum 120px'
      max_height:       960
      max_height_error: 'The image height is too large, it must have maximum 960px'
      max_width:        450
      max_width_error: 'The image width is too large, it must have maximum 450px'
      is_square:        true
      is_square_error:  'The images must be a square (The height be equal to the width)'
 
      max_size:         256000
      max_size_error:   'The maximum images size is 250Kb'
      mime_types_error: 'We only accept GIF, PNG and JPEG.'
      mime_types:
        - 'image/jpeg'
        - 'image/png'
        - 'image/gif'
 
by Daniel Santiago on 2007-12-26, tagged image  images  validation  validator 

Pass multiple parameters to sfCallbackValidator

I love sfCallbackValidator and use it all the time, but found it was somewhat limiting in that only the value being validated could be passed to the function or method that is doing the validating. So, I've extended it, overriding the execute method:

myCallbackValidator.class.php:

<?php
 
class myCallbackValidator extends sfCallbackValidator {
 
  public function execute(&$value, &$error) {
 
    $callback = $this->getParameterHolder()->get('callback');
    if (!call_user_func($callback, $value, $this->getParameterHolder()->get('parameters'))) {
      $error = $this->getParameterHolder()->get('invalid_error');
      return false;
    }
    return true;
 
  }
 
}

You can specify the parameters in your validation yaml file like so...

  birthdate:
    myCallbackValidator:
      callback:       [myValidationTools, birthDate]
      invalid_error:  Birthdate is invalid. You must be at least 18 years old to apply.
      parameters:
        min_age:      18

And then the parameters can be accessed in the callback function like so:

  public static function birthDate($string, $params = null) {
    if (isset($params['min_age'])) {
      ... etc...
by east3rd on 2007-06-27, tagged callback  validation  validator 
(2 comments)

Credit Card Validator II

Here is another variation on the credit card validator. In your validate/[action].yml file, you can implement this helper like so:

fields:
  cc_type:
    required:
      msg:      Please select a card type
    sfStringValidator:
      values:       [Visa, MasterCard, Discover, American Express]
      values_error: Please select a credit card type
      insensitive:  true
 
  cc_number:
    required:
      msg:      Please provide a credit card number
    myCreditCardValidator:
      card_name: cc_type    # refers to field name in form that contains card type, like Visa, MasteCard, etc.

Place this file, myCreditCardValidator.class.php, in you application's /lib directory and clear the cache.

<?php
 
/**
 * This class has been converted to a Symfony Validator from original code
 * created by John Gardner, 4th January 2005. 
 * http://www.braemoor.co.uk/software/index.shtml
 *
 * Symfony conversion by Scott Meves, Stereo Interactive & Design, 2007
 * http://www.stereointeractive.com
 * 
 * This routine checks the credit card number. The following checks are made:
 * 
 * 1. A number has been provided
 * 2. The number is a right length for the card
 * 3. The number has an appropriate prefix for the card
 * 4. The number has a valid modulus 10 number check digit if required
 * 
 **/
 
class myCreditCardValidator extends sfValidator
{    
 
    static protected $CARDS = array (
        array ('name'           => 'American Express', 
            'length'            => '15', 
            'prefixes'      => '34,37',
            'checkdigit'    => true
    ),
        array ('name'           => 'Carte Blanche', 
               'length'         => '14', 
               'prefixes'   => '300,301,302,303,304,305,36,38',
               'checkdigit' => true
        ),
        array ('name'       => 'Diners Club', 
               'length'         => '14',
               'prefixes'   => '300,301,302,303,304,305,36,38',
               'checkdigit' => true
    ),
        array ('name'       => 'Discover', 
               'length'         => '16', 
               'prefixes'   => '6011',
               'checkdigit' => true
    ),
        array ('name'       => 'Enroute', 
               'length'         => '15', 
               'prefixes'   => '2014,2149',
               'checkdigit' => true
    ),
        array ('name'       => 'JCB', 
               'length'         => '15,16', 
               'prefixes'   => '3,1800,2131',
               'checkdigit' => true
    ),
        array ('name'       => 'Maestro', 
               'length'         => '16', 
               'prefixes'   => '5020,6',
               'checkdigit' => true
    ),
        array ('name'       => 'MasterCard', 
               'length'         => '16', 
               'prefixes'   => '51,52,53,54,55',
               'checkdigit' => true
    ),
        array ('name'       => 'Solo', 
               'length'         => '16,18,19', 
               'prefixes'   => '6334, 6767',
               'checkdigit' => true
    ),
        array ('name'       => 'Switch', 
               'length'         => '16,18,19', 
               'prefixes'   => '4903,4905,4911,4936,564182,633110,6333,6759',
               'checkdigit' => true
    ),
        array ('name'       => 'Visa', 
               'length'         => '13,16', 
               'prefixes'   => '4',
               'checkdigit' => true
    ),
        array ('name'       => 'Visa Electron', 
               'length'         => '16', 
               'prefixes'   => '417500,4917,4913',
               'checkdigit' => true
        )
  );
 
  public function initialize($context, $parameters = null)
  {
    // initialize parent
    parent::initialize($context);
 
    // set defaults
    $parameterHolder = $this->getParameterHolder();
    $parameterHolder->set('cc_error_type',      'Unknown card type');
    $parameterHolder->set('cc_error_missing', 'No card number provided');
    $parameterHolder->set('cc_error_format',    'Credit card number has invalid format');
    $parameterHolder->set('cc_error_number',    'Credit card number is invalid');
    $parameterHolder->set('cc_error_length',    'Credit card number is wrong length');
 
    $this->getParameterHolder()->add($parameters);
 
    return true;
  }
 
  public function execute(&$value, &$error)
  {
    $cardName = $this->getParameterHolder()->get('card_name');
    $cardName = $this->getContext()->getRequest()->getParameter($cardName);
 
    $cardNumber = $value;
 
      // Establish card type
      $cardType = -1;
      for ($i=0; $i<sizeof(self::$CARDS); $i++) 
        {   // See if it is this card (ignoring the case of the string)
        if (strtolower($cardName) == strtolower(self::$CARDS[$i]['name']))
            {
          $cardType = $i;
          break;
        }
      }
 
      // If card type not found, report an error
      if ($cardType == -1) 
        {
            $error = $this->getParameterHolder()->get('cc_error_type');
        return false; 
      }
 
      // Ensure that the user has provided a credit card number
      if (strlen($cardNumber) == 0)
        {
         $error = $this->getParameterHolder()->get('cc_error_missing');
         return false; 
      }
 
      // Remove any non-digits   from the credit card number
      $cardNo = preg_replace('/[^0-9]/', '', $cardNumber);
 
      // Check that the number is numeric and of the right sort of length.
      if (!eregi('^[0-9]{13,19}$',$cardNo))
        {
         $error = $this->getParameterHolder()->get('cc_error_format');
         return false; 
      }
 
      // Now check the modulus 10 check digit - if required
      if (self::$CARDS[$cardType]['checkdigit'])
        {
        $checksum = 0;   // running checksum total
        $mychar = "";    // next char to process
        $j = 1;          // takes value of 1 or 2
 
        // Process each digit one by one starting at the right
        for ($i = strlen($cardNo) - 1; $i >= 0; $i--) 
            {
          // Extract the next digit and multiply by 1 or 2 on alternative digits.      
          $calc = $cardNo{$i} * $j;
 
          // If the result is in two digits add 1 to the checksum total
          if ($calc > 9) {
            $checksum = $checksum + 1;
            $calc = $calc - 10;
          }
 
          // Add the units element to the checksum total
          $checksum = $checksum + $calc;
 
          // Switch the value of j
          if ($j ==1) {$j = 2;} else {$j = 1;};
        } 
 
        // All done - if checksum is divisible by 10, it is a valid modulus 10.
        // If not, report an error.
        if ($checksum % 10 != 0)
            {
            $error = $this->getParameterHolder()->get('cc_error_number');
            return false; 
        }
      }  
 
      // The following are the card-specific checks we undertake.
 
      // Load an array with the valid prefixes for this card
      $prefix = split(',',self::$CARDS[$cardType]['prefixes']);
 
      // Now see if any of them match what we have in the card number  
      $prefixValid = false; 
      for ($i=0; $i<sizeof($prefix); $i++)
        {
        $exp = '^' . $prefix[$i];
        if (ereg($exp,$cardNo))
            {
          $prefixValid = true;
          break;
        }
      }
 
      // If it isn't a valid prefix there's no point at looking at the length
      if (!$prefixValid)
        {
         $error = $this->getParameterHolder()->get('cc_error_number');
         return false; 
      }
 
      // See if the length is valid for this card
      $lengthValid = false;
      $lengths = split(',',self::$CARDS[$cardType]['length']);
      for ($j=0; $j<sizeof($lengths); $j++)
        {
        if (strlen($cardNo) == $lengths[$j])
            {
          $lengthValid = true;
          break;
        }
      }
 
      // See if all is OK by seeing if the length was valid. 
      if (!$lengthValid)
        {
         $error = $this->getParameterHolder()->get('cc_error_length');
         return false; 
      };   
 
      // The credit card is in the required format.
      return true;
  }
}
by scott meves on 2007-04-08, tagged cc  creditcard  validation  validator 

turn on form repopulation

add this to your validation file for the action.

eg: indexSuccess.php would have have a file called index.yml in the validate directory for that module if you configured validation.

fillin:
  activate: on   # activate the form repopulation
  param:
    name: test   # name of the form
by Russ Cann on 2006-05-23, tagged forms  repopulation  symfony  validation  yml 
(2 comments)

Credit Card validator

sfValidator extension based on Credit Card Validator code by Harish Chauhan (from phpclasses.org). With this extension you can validate this type of credit cards: VISA, MASTERCARD, DISCOVER, AMEX, DINERS,JCB, Australian Bankcard, EnRoute And Switch Solo.

IMHO isn't a bad idea to include anything like this in standard sfValidator code. While here you have the source code of my adaptation of credit cards validator.

<?php
 
/*
 
Symfony integration as sfValidator of CCVAL
Date - Jun 17, 2006
Author - Oriol Rius (oriol@joor.net)
 
Credit CArd Validator
Date - Jan 14, 2005
Author - Harish Chauhan
 
 
ABOUT
This PHP script will calidate credit cards by checking there length
and pattern and checksum using mod 10.
 
Supported credit cards are VISA, MASTERCARD, DISCOVER, AMEX, DINERS,
JCB, Australian Bankcard, EnRoute And Switch Solo.
*/
 
class CCVAL extends sfValidator
{
 
    public function execute (&$value, &$error)
    {       
        // Recuperamos parámetros validar
        $num_param = $this->getParameterHolder()->get('num');
        $num = $this->getContext()->getRequest()->getParameter($num_param);
        $tipo_param = $this->getParameterHolder()->get('tipo');
        $tipo = $this->getContext()->getRequest()->getParameter($tipo_param);
 
        // Lanzamos la validación
        $validada=$this->_isVAlidCreditCard($num,$tipo,false);
 
        // Informamos de como ha ido la validación
        sfContext::getInstance()->getLogger()->info("CCVAL.class.php: Tipo: ".$tipo." Num: ".$num." Validada: ".$validada);             
 
        if ($validada==false)
        {
            $error = $this->getParameterHolder()->get('error');
            return false;
        }
        return true;
    }
 
    public function initialize ($context, $parameters = null)
    {
        // initialize parent
        parent::initialize($context);
 
        $this->getParameterHolder()->add($parameters);
 
        return true;
    }
 
    /**
     * Testing checksum
     *
     * @param integer $ccnum
     * @return boolean
     */
    private function _checkSum($ccnum)
    {
        $checksum = 0;
        for ($i=(2-(strlen($ccnum) % 2)); $i<=strlen($ccnum); $i+=2)
        {
            $checksum += (int)($ccnum{$i-1});
        }
        // Analyze odd digits in even length strings or even digits in odd length strings.
        for ($i=(strlen($ccnum)% 2) + 1; $i<strlen($ccnum); $i+=2)
        {
            $digit = (int)($ccnum{$i-1}) * 2;
            if ($digit < 10)
            { $checksum += $digit; }
            else
            { $checksum += ($digit-9); }
        }
        if (($checksum % 10) == 0)
        return true;
        else
        return false;
 
    }
 
    /**
     * Launch validation
     *
     * @param integer $ccnum
     * @param string $type
     * @param boolean $returnobj
     * @return boolean
     */
    private function _isVAlidCreditCard($ccnum,$type="",$returnobj=false)
    {
        $creditcard=array(  "visa"=>"/^4\d{3}-?\d{4}-?\d{4}-?\d{4}$/",
        "mastercard"=>"/^5[1-5]\d{2}-?\d{4}-?\d{4}-?\d{4}$/",
        "discover"=>"/^6011-?\d{4}-?\d{4}-?\d{4}$/",
        "amex"=>"/^3[4,7]\d{13}$/",
        "diners"=>"/^3[0,6,8]\d{12}$/",
        "bankcard"=>"/^5610-?\d{4}-?\d{4}-?\d{4}$/",
        "jcb"=>"/^[3088|3096|3112|3158|3337|3528]\d{12}$/",
        "enroute"=>"/^[2014|2149]\d{11}$/",
        "switch"=>"/^[4903|4911|4936|5641|6333|6759|6334|6767]\d{12}$/");
        if(empty($type))
        {
            $match=false;
            foreach($creditcard as $type=>$pattern)
            if(preg_match($pattern,$ccnum)==1)
            {
                $match=true;
                break;
            }
 
            if(!$match)
            return false;
            else
            {
                if($returnobj)
                {
                    $return=new stdclass;
                    $return->valid=$this->_checkSum($ccnum);
                    $return->ccnum=$ccnum;
                    $return->type=$type;
                    return $return;
                }
                else
                return $this->_checkSum($ccnum);
            }
 
        }
        else
        {
            if(@preg_match($creditcard[strtolower(trim($type))],$ccnum)==0)
            return false;
            else
            {
                if($returnobj)
                {
                    $return=new stdclass;
                    $return->valid=$this->_checkSum($ccnum);
                    $return->ccnum=$ccnum;
                    $return->type=$type;
                    return $return;
                }
                else
                return $this->_checkSum($ccnum);
            }
        }
    }
}
?>

An example of how you can call CCVAL validator from validate yml file:

methods:
  post: [ntarjeta]
names:
  ntarjeta:
    required:     Yes
    required_msg: Credit Card number is required
    validators:   validarCC
 
validarCC:
    class:       CCVAL
    param:
      num:       ntarjeta
      tipo:      tipoCC
      error:     Your credit card number is invalid

Sorry for my poor english.

by Oriol Rius on 2006-06-24, tagged cc  validation  validator 

Password Strength validator

This its a password strength validator, with ajax request for checking the password field.

First create a validator in lib/validators/sfPasswordStrengthValidator.class.php

<?php
class sfPasswordStrengthValidator extends sfValidator
{
    public function execute (&$value, &$error)
    {
        $weakness = $this->Password_Strength($value);
 
        if($weakness==1) {
            $error = $this->getParameter('strength_error');
            return false;
        }
 
        return $weakness;
    }
 
    public function initialize ($context, $parameters = null)
    {
        // Initialize parent
        parent::initialize($context);
 
        // Set default parameters value
        $this->setParameter('strength_error', 'Weak password');
 
        // Set parameters
        $this->getParameterHolder()->add($parameters);
 
        return true;
    }
        // Thanks for: Alix Axel Weblog
    // URL: http://www.alixaxel.com/wordpress/wp-content/2007/06/Password_Strength.phps
    function Password_Strength($password, $username = null)
    {
        if (!empty($username))
        {
            $password = str_replace($username, '', $password);
        }
 
        $strength = 0;
        $password_length = strlen($password);
 
        if ($password_length < 5)
        {
            return $strength;
        }
 
        else
        {
            $strength = $password_length * 4;
        }
 
        for ($i = 2; $i <= 4; $i++)
        {
            $temp = str_split($password, $i);
 
            $strength -= (ceil($password_length / $i) - count(array_unique($temp)));
        }
 
        preg_match_all('/[0-9]/', $password, $numbers);
 
        if (!empty($numbers))
        {
            $numbers = count($numbers[0]);
 
            if ($numbers >= 3)
            {
                $strength += 5;
            }
        }
 
        else
        {
            $numbers = 0;
        }
 
        preg_match_all('/[|!@#$%&*\/=?,;.:\-_+~^¨\\\]/', $password, $symbols);
 
        if (!empty($symbols))
        {
            $symbols = count($symbols[0]);
 
            if ($symbols >= 2)
            {
                $strength += 5;
            }
        }
 
        else
        {
            $symbols = 0;
        }
 
        preg_match_all('/[a-z]/', $password, $lowercase_characters);
        preg_match_all('/[A-Z]/', $password, $uppercase_characters);
 
        if (!empty($lowercase_characters))
        {
            $lowercase_characters = count($lowercase_characters[0]);
        }
 
        else
        {
            $lowercase_characters = 0;
        }
 
        if (!empty($uppercase_characters))
        {
            $uppercase_characters = count($uppercase_characters[0]);
        }
 
        else
        {
            $uppercase_characters = 0;
        }
 
        if (($lowercase_characters > 0) && ($uppercase_characters > 0))
        {
            $strength += 10;
        }
 
        $characters = $lowercase_characters + $uppercase_characters;
 
        if (($numbers > 0) && ($symbols > 0))
        {
            $strength += 15;
        }
 
        if (($numbers > 0) && ($characters > 0))
        {
            $strength += 15;
        }
 
        if (($symbols > 0) && ($characters > 0))
        {
            $strength += 15;
        }
 
        if (($numbers == 0) && ($symbols == 0))
        {
            $strength -= 10;
        }
 
        if (($symbols == 0) && ($characters == 0))
        {
            $strength -= 10;
        }
 
        if ($strength < 0)
        {
            $strength = 0;
        }
 
        if ($strength > 100)
        {
            $strength = 100;
        }
 
        return $strength;
    }
}
 

Then in your view template use:

<?php echo observe_field('password', array(
                          'update'   => 'passwordStatus',
                          'url'      => 'sfGuardAuth/checkPasswordStrength',
                          'with' => "'id='+encodeURIComponent($('password').value)",
                          'loading'=>"Element.show('indicator_passwordstatus')",
                          'complete'=>"Element.hide('indicator_passwordstatus');Element.show('passwordStatus');",
                      )) ?>
 

That code will monitor changes at password input field, and submit the updated value to the defined route.

Then add the following to your actions file:

public function executeCheckPasswordStrength() {
        $password = $this->getRequestParameter('id');
        $strengthValidator = new sfPasswordStrengthValidator();
        $strengthValidator->initialize($this->getContext());
        $error='none';
        $score = $strengthValidator->execute($password,$error);
        if(!$score)
        return $this->renderText('too short');
        if($score < 20) {
            return $this->renderText('not weak');
        } else if($score < 50) {
            return $this->renderText('relevant');
        } else {
            return $this->renderText('strong');
        }
 
        return true;
    }
 

Cheers

by Lucas Peres on 2007-10-05, tagged validation  validator 

Age Validation

Say you wanted to validate that someone was over 18 years of age, its acutally quite simple once you know what your doing, but it took me a while to work out all the bits, so i thought i would put it in here to save some one a bit of time...

on the template you have

<p>
 
  <label for="date_of_birth">Date of Birth:</label>
  <?php echo form_error('day');  ?>
  <?php echo form_error('month');  ?>
  <?php echo form_error('year');  ?>
  <?php echo select_day_tag('day', $sf_params->get('day')) ?>
 
  <?php echo select_month_tag('month', $sf_params->get('month')) ?>
  <?php echo select_year_tag('year', $sf_params->get('year'),array('year_start'=>'1900','year_end'=>date("Y"))) ?>
</p>
 

in signup.yml (due to the way i built my form, you dont actually need to validate the day and month, since there is no way to leave them empty, but i have put the code in for completness)

methods:
  post: [day, month, year, gender]
 
names:
  day:
    required:     true
    required_msg: You must verify your age.
 
  month:
    required:     true
    required_msg: You must verify your age.
 
  year:
    required:     true
    required_msg: You must verify your age.
    validators:   ageValidator
 
 
ageValidator:
    class:         myAgeValidator
    param:
      too_young_error: You must be over 18 to enter.
 

now in /lib/AgeValidator.class.php, we put the code to check the dates.

class myAgeValidator extends sfValidator
{
  public function initialize($context, $parameters = null)
  {
    // initialize parent
    parent::initialize($context);
 
    // set defaults
    $this->setParameter('too_young_error', 'Invalid input');
    $this->getParameterHolder()->add($parameters);
 
    return true;
  }
 
  public function execute(&$value, &$error)
  {
 
// get the passed values for the date fields
    $day_param = sfContext::getInstance()->getRequest()->getParameter('day');
    $month_param = sfContext::getInstance()->getRequest()->getParameter('month');
    $year_param = sfContext::getInstance()->getRequest()->getParameter('year');
 
    $min_age=strtotime("-18 YEAR");
    $entrant_age= strtotime( $year_param . "-" . $month_param . "-" . $day_param);
 
# just in case ;-)
#sfContext::getInstance()->getLogger()->debug('min_age->'.$min_age);
#sfContext::getInstance()->getLogger()->debug('entrant_age->'.$entrant_age);
#sfContext::getInstance()->getLogger()->debug('param-day->'.$day_param);
#sfContext::getInstance()->getLogger()->debug('param-month->'.$month_param);
#sfContext::getInstance()->getLogger()->debug('param-year->'.$year_param);
 
if ($entrant_age <$min_age ){
    return true;
}
 
$error = this->getParameter('too_young_error');
return false;
  }
}
 
by excessive demon on 2008-04-16, tagged age  dateofbirth  validation 

jsValidator integration helper

A real client-side validation with some nice features, without Ajax tricks provided by sfYzAjaxValidationPlugin may be easily done using jsValidator (http://sourceforge.net/projects/jsformutils/) and little helper that follows.

<?php
/**
 * Generates JavaScript code to validate a form using 
 * jsValidator as client-side validation engine (see http://sourceforge.net/projects/jsformutils/)
 * 
 * @param string $targetForm id attribute of the form to be validated
 * @param mixed $options associative array of options
 * @param string $action action to validated, defaults to current
 * 
 * Options are:
 *  stopOnFirstError: boolean, default: false
 *  labelMessageDelimiter: string, default: ' : ',
 *  messageSeparator: string, default: "\n",
 *  messageHeader: string, default: 'These fields are invalid:\n---\n' + 
 *  highlightErrors: boolean, whether to mark erroneous fields 
 *  errorElementClass: string, CSS class name to be applied to wrong fields
 *  highlightLabels: boolean, whether to mark fields or fields' labels
 */
function generate_validator($targetForm, $options, $action)
{
  $NL = "\n";
  $funcPrefix = 'validate_';
  $labelsKey = 'labels';
  $fieldsKey = 'fields';
  $jsCode = '';
 
  $paramHolder = sfContext::getInstance()->getRequest()->getParameterHolder();  
  $rulesFilePath = sfConfig::get('sf_app_module_dir').'/'.$paramHolder->get('module').'/'.
    sfConfig::get('sf_app_module_validate_dir_name').'/';
 
  // Load rules from YAML file.   
  if (file_exists($rulesFilePath.$paramHolder->get('action').'.yml'))
    $rules = sfYaml::load($rulesFilePath.$paramHolder->get('action').'.yml');
  else
    $rules = sfYaml::load($rulesFilePath.$action.'.yml');
 
  // Generate jsValidator compliant rules.  
  $jsRules = array();
  foreach ($rules['fields'] as $fieldId => $validationRule)
  {
    foreach ($validationRule as $validator=>$rule)
    {
      // Remove server-side sfCallbackValidator.
      if ($validator == 'sfCallbackValidator')
      {
        unset($validationRule[$validator]);
        continue;
      }
      // Map Symfony validators to jsValidator.
      $jsvalidator = preg_replace('/^sf(\w+Validator)$/', 'js\\1', $validator);
      if ($jsvalidator != $validator)
      {
        $validationRule[$jsvalidator] = $validationRule[$validator];
        unset($validationRule[$validator]); 
      }
    }
    $jsRules[] = array_merge ( 
      array ('field' => $fieldId, 'label' => $rules['labels'][$fieldId]),
      $validationRule
    );    
  }
 
  // Generate final JavaScript code. 
  $jsCode .= 'function '.$funcPrefix.$targetForm.'()'.$NL;
  $jsCode .= 
  '{'.$NL.
  ' var options = '.json_encode($options).';'.$NL.
  ' var rules = '.json_encode($jsRules).';'.$NL.
  ' var jsv = new jsValidator();'.$NL.
  ' jsv.SetOptions(options);'.$NL.$NL.
  ' if (!jsv.Validate(rules))'.$NL.
  ' {'.$NL.
  '   alert(jsv.GetErrorMessage());'.$NL.
  '   return false;'.$NL.  
  ' }'.$NL.
  ' return true;'.$NL.  
  '}'.$NL;
 
  return javascript_tag($jsCode);
}
?>
 

However, I need to clear this out. Besides placing this code into jsValidatorHelper.php either in modules' lib directory or symfony's one, we need to call it properly in the corresponding view.

First of all, include the helper (use JavaScript as well, jsValidator depends on it)

<?php use_helper('JavaScript', 'jsValidator') ?>
 

Validation is performed based on the same simple rule mechanism that Symfony provides. The only difference is that JavaScript validator needs these rules to be in JSON format and it needs some more options, that configure it's behavior.

<?php
// Here we set validation options.
// For more information please refer to documentation of jsValidator
$options = array(
  'stopOnFirstError' => false,
  'labelMessageDelimiter' => ' : ',
  'messageSeparator' => "\n",
  'messageHeader' => "These fields are invalid:\n---\n",
  'highlightErrors' => true,
  'errorElementClass' => 'errClass',
  'highlightLabels' => true
  ); 
// Output auto-generated JavaScript code.
echo generate_validator('editComment', $options, 'update'); 
?>
 

We also have to set up form to point to our validator before submitting. Note, that callback in onsubmit is named by concatenating "validate_" and form's id attribute.

<?php echo form_tag('comment/update', array('id'=>'editComment','onsubmit' => 'return validate_editComment()')) ?>
 

Each field must be somehow identified in the resulting error message. We achieve this by adding some extra information to <action>.yml configuration file.

# define labels for erroneous fields
labels:
  <field_id>: <field_label_text>
 

There is a limitation to validation *.yml file structure. The syntax should be something like this:

# define labels for erroneous fields
labels:
  author: Author
  email: E-mail
  body: Body
 
fields:
  author:
    required:
      msg: The name field cannot be left blank
  email:
    sfEmailValidator:
      email_error: The email address is not valid.
  body:
    required:
      msg: The text field cannot be left blank
 
fillin:
  enabled:       on
 

And finally, don't forget to place jsValidator into /web/js folder, and include it in view.yml

<actionTemplate>:
  javascripts: [jsvalidator]
 

Feel free to modify the snippet code and validator to achieve best results!

by Alex Oroshchuk on 2007-12-04, tagged helper  javascript  validation 
(1 comment)

Simple CAPTCHA

Hi!

This code is about a very simple CAPTCHA validation. I am pretty sure that you all know what CAPTCHA is, so I won't explain it. This CAPTCHA is based on the color-blindness test that operates with various colored balls.

The class:

class Captcha
{
    protected $value;
    protected $image_name;
 
    public function __construct( $image_name )
    {
        $this->image_name = $image_name;
    }
 
    public static function createNumber( $length = 4 )
    {
        $num = "";
        for ( $i = 0; $i < $length; $i++ )
        {
            $r = mt_rand( 0, 9 );
            $num = $num.$r;
        }
        return $num;
    }
 
    public static function createString( $length = 4 )
    {
        $val = "";
        $values = "abcdefghijklmnopqrstuvwyz";
        for ( $i = 0; $i < $length; $i++ )
        {
            $r = mt_rand( 0, 24 );
            $val = $val.$values[$r];
        }
        return $val;        
    }
 
    public function setValue( $value )
    {
        $this->value = $value;
    }
 
    public function getValue( )
    {
        return $this->value;
    }
 
    public function showImage( $channel = null )
    {
        $im = imageCreate( 160, 60 );
        $white = imagecolorallocate( $im, 255, 255, 255 );
        $black = imagecolorallocate( $im, 0, 0, 0 );
 
        $intensity = rand ( 200, 230 );
 
        if ( !$channel )
        {
            $channel = rand ( 1, 3 );
        }
        $ratio = rand ( 80, 100 );
 
        switch ( $channel )
        {
                case 1:
                        $colorBgR = $intensity * $ratio / 100;
                        $colorBgG = $intensity * ( 100 - $ratio ) / 100;
                        $colorBgB = 0;
 
                        for ( $i = 0; $i < 5; $i++ )
                        {
                                $shift = rand( 100 - ( $i+1)*3, 100 + ( $i+1)*3 );
                                $new = $shift * $colorBgR / 100;    
 
                                $bgColors[] = iMagecolorallocate( $im, $new, $intensity-$new, 0 );
                        }
 
                        for ( $i = 0; $i < 3; $i++ )
                        {
                                $shift = rand( 100 - ( $i+1)*7, 100 + ( $i+1)*7 );
                                $new = $shift * $colorBgR / 100;    
 
                                $bgColors[] = iMagecolorallocate( $im, $intensity-$new, $new, 0 );
                        }
                break;
 
                case 2:
                        $colorBgG = $intensity * $ratio / 100;
                        $colorBgB = $intensity * ( 100 - $ratio ) / 100;
                        $colorBgR = 0;
 
                        for ( $i = 0; $i < 5; $i++ )
                        {
                                $shift = rand( 100 - ( $i+1)*3, 100 + ($i+1)*3 );
                                $new = $shift * $colorBgR / 100;    
 
                                $bgColors[] = iMagecolorallocate( $im, 0, $new, $intensity-$new );
                        }
 
                        for ( $i = 0; $i < 3; $i++ )
                        {
                                $shift = rand( 100 - ( $i+1)*7, 100 + ( $i+1)*7 );
                                $new = $shift * $colorBgR / 100;    
 
                                $bgColors[] = iMagecolorallocate( $im, 0 , $intensity-$new, $new );
                        }
 
                case 3:
                        $colorBgB = $intensity * $ratio / 100;
                        $colorBgR = $intensity * ( 100 - $ratio ) / 100;
                        $colorBgG = 0;
 
                        for ( $i = 0; $i < 5; $i++ )
                        {
                                $shift = rand( 100 - ( $i+1)*3, 100 + ( $i+1)*3 );
                                $new = $shift * $colorBgR / 100;    
 
                                $bgColors[] = iMagecolorallocate( $im, $intensity-$new, 0, $new );
                        }
 
                        for ( $i = 0; $i < 3; $i++ )
                        {
                            // to make it harder do symmetric range ^^ 
                                $shift = rand( 100 , 100 + ( $i+1)*20 );
                                $new = $shift * $colorBgR / 100;    
 
                                $bgColors[] = iMagecolorallocate( $im, $new , 0, $intensity-$new );
                        }
                break;
        }
 
 
 
 
        $bgColor = imagecolorallocate( $im, $colorBgR, $colorBgG, $colorBgB );
 
 
        for ( $i = 0; $i < strlen( $this->value ); $i++ )
        {
            $rotate = rand(-15, 15);
 
            $fontSize = rand(28, 36);
            imagettftext($im, $fontSize ,$rotate , 10+$i*31, 50, $black, "impact.ttf",$this->value[$i] ); 
        }
 
 
 
 
        for ( $i = 0; $i < 160; $i++ )
        {
                for ( $j = 0; $j  < 60; $j++ )
                {
                        $pos = rand( 0, 7 );
 
                        if ( imagecolorat( $im, $i, $j ) == $black )
                        {
                                $pos = rand( 6, 7 );
 
 
 
                                imagesetpixel( $im, $i, $j, $bgColors[$pos] );
                        }
                        else
                        {
                                imagesetpixel( $im, $i, $j, $bgColors[$pos] );
                        }
                }
        }
 
        imagejpeg( $im, "images/".$this->image_name.".jpg" );
        imagedestroy( $im );
        echo" <img src='/images/".$this->image_name.".jpg' style='border: 1px solid #000;' width='160' >";
    }
}

The random string/number generator functions are static, so that they can be used anytime.

The string to be shown is stored in the class member value, this is to be set manually using setValue( $value ).

Function showImage renders and shows the image. It uses the 3 base colors Red Green and Blue ( $channel ) to generate the background color. This can be set as a parameter so images get only green ( $channel = 2 ) background, this my be important to exclude variations that are hard to read.

The logic is the following:

In the action you use to render the template where the CAPCTHA is to be shown, generate a value for it ( you can use the createString or createNumber functions ). Flash this value in the action ( $this->setFlash( 'captcha', $this->value ), and "pass" it to the template ( set the value as a member of the action $this->value = $value ).

In the template create an instance of class Captcha. Set the value by using the setValue function. And call showImage().

Create an input field on the template, and override the validate() function in your action.class.php. The logic is simple we have two strings and we want to know if they match or not. So we make an insatnce of confirm validaor, set the check parameter to the original captcha value ( $this->getFlash( 'captcha' ) ) and execute the validator on the input field's post value ( $this->getRequestParameter('name_of_input_field' ) ).

Many of the parameters that are actually fixed in the code should be members of the class and should have proper set/get functions. I've played with this for a short period of time, so feel free to complement the code.

by Kormany Gabor on 2007-06-30, tagged captcha  validation 

easy cookie validation for user login systems

If you're building a site with a user login system (like Askeet) and your PHP is configured to store session variables in a client-side cookie, the following snippet will improve the usability for users who have disabled cookies.

The following example assumes you already have at least a simple user login system on your site. If not, check out the Askeet tutorial for a great example to get you started.

All users who have disabled cookies will be unable to log into any site that relies on client-side cookies to store session variables. If you don't validate cookies and provide notification, these users will never know why they couldn't log in to your site.

Try the following if you'd like to see this firsthand.

Unfortunately, Askeet also provides the perfect example here as well. (Sorry guys!)

Not much happened, right? You're not logged in and you don't know why. (Well, you do now.)

What we're going to do is augment an existing login system to provide users with notification that your site requires cookies.

To do this, we're going to attempt to set a cookie on the login page and verify that it was created once the login form is submitted. Since a cookie is stored only after the page is loaded, it takes two pages to validate the user's setting. Fortunately, the login process takes two pages!

Edit your existing login action code by adding the following two setCookie() functions.

The first setCookie() sets the validation cookie when the login action is first loaded. (If you use your login on several pages as a component/partial, move this first setCookie() to the login form component.)

The second setCookie() deletes the validation cookie upon successful login. If this cookie is not deleted, the validation could return a false positive if the user disables cookies at a later date. (When cookies are disabled, new cookies can't be written, but old cookies can be read.)

module_dir/actions/actions.class.php:

public function executeLogin()
{
  if ($this->getRequest()->getMethod() != sfRequest::POST)
  {      
    sfContext::getInstance()->getResponse()->setCookie('cookies_enabled', 'true', time()+60*60*24, '/');    
  }
  else
  {
    sfContext::getInstance()->getResponse()->setCookie('cookies_enabled', '', 0, '/');    
    $this->redirect('@homepage');
  }
}

Enable cookie validation by adding the following code to your existing login validation. The validator takes two parameters, cookie_name and cookie_error. The cookie_name parameter is, oddly enough, the name of the cookie we'll use to validate and it should match the cookie set in the above code.

The other parameter, cookie_error, is the error message that will be returned if the user has cookies disabled. Typically, validation errors are phrases like "Invalid username" or "Password must contain 6-8 characters". But we're going to use "cookies_disabled" and I'll show you why in a few minutes.

IMPORTANT: The cookie validation should occur first.

module_dir/validate/login.yml:

methods:
  post: [username]
 
names:
  username:
    required:     true
    required_msg: 
    validators:   [cookiesEnabledValidator, userValidator]
 
cookiesEnabledValidator:
  class:          myCookiesEnabledValidator
  param:
    cookie_name:  cookies_enabled
    cookie_error: cookies_disabled
 
userValidator:
  class:          myLoginValidator
  param:
    password:     password
    username_error: Invalid username.
    password_error: Invalid password.

Copy the following code to one of your lib directories. Since it only deals with the login action, I choose to keep it in my user module's lib directory.

module_dir/lib/myCookiesEnabledValidator.class.php:

class myCookiesEnabledValidator extends sfValidator
{    
  public function initialize($context, $parameters = null)
  {
    // initialize parent
    parent::initialize($context);
 
    // set defaults
    $this->setParameter('cookie_name', sfContext::getInstance()->getStorage()->getParameter('session_name'));
    $this->setParameter('cookie_error', 'This site requires cookies.');
    $this->getParameterHolder()->add($parameters);
 
    return true;
  }
 
  public function execute(&$value, &$error)
  {    
    if (sfContext::getInstance()->getRequest()->getCookie($this->getParameter('cookie_name')) === null)
    {
      $error = $this->getParameter('cookie_error');
      return false;
    }
    return true;
  }
}

Now, since it takes two pages to set and read a cookie it wouldn't make sense to return the user to the form right away. If they enable their cookies they'll still have to submit the form twice before they'll login successfully. I prefer to send them to a page which notifies them that the site requires cookies and explains how they can enable them. (Plus, this gives us the extra click we need to set that validation cookie!)

So we'll check for the cookie validation error before returning to the form so we can redirect the user to our help page if necessary. The error we check for in the username parameter must match the cookie_error we defined in the login.yml.

module_dir/actions/actions.class.php:

public function handleErrorLogin()
{
  if (sfContext::getInstance()->getRequest()->getError('username') == 'cookies_disabled')
  {
    $this->redirect('@about_cookies');
  }
  return sfView::SUCCESS;
}

So that's it. Throw in an about cookies page and you're all set.

If I made any mistakes, I apologize. It's 5am on a school night.

by dave furf on 2007-05-11, tagged cookie  login  session  storage  usability  validation 
(1 comment)

easy cookie validation for user login systems

If you're building a site with a user login system (like Askeet) and your PHP is configured to store session variables in a client-side cookie, the following snippet will improve the usability for users who have disabled cookies.

The following example assumes you already have at least a simple user login system on your site. If not, check out the Askeet tutorial for a great example to get you started.

All users who have disabled cookies will be unable to log into any site that relies on client-side cookies to store session variables. If you don't validate cookies and provide notification, these users will never know why they couldn't log in to your site.

Try the following if you'd like to see this firsthand.

Unfortunately, Askeet also provides the perfect example here as well. (Sorry guys!)

Not much happened, right? You're not logged in and you don't know why. (Well, you do now.)

What we're going to do is augment an existing login system to provide users with notification that your site requires cookies.

To do this, we're going to attempt to set a cookie on the login page and verify that it was created once the login form is submitted. Since a cookie is stored only after the page is loaded, it takes two pages to validate the user's setting. Fortunately, the login process takes two pages!

Edit your existing login action code by adding the following two setCookie() functions.

The first setCookie() sets the validation cookie when the login action is first loaded. (If you use your login on several pages as a component/partial, move this first setCookie() to the login form component.)

The second setCookie() deletes the validation cookie upon successful login. If this cookie is not deleted, the validation could return a false positive if the user disables cookies at a later date. (When cookies are disabled, new cookies can't be written, but old cookies can be read.)

module_dir/actions/actions.class.php:

public function executeLogin()
{
  if ($this->getRequest()->getMethod() != sfRequest::POST)
  {      
    sfContext::getInstance()->getResponse()->setCookie('cookies_enabled', 'true', time()+60*60*24, '/');    
  }
  else
  {
    sfContext::getInstance()->getResponse()->setCookie('cookies_enabled', '', 0, '/');    
    $this->redirect('@homepage');
  }
}

Enable cookie validation by adding the following code to your existing login validation. The validator takes two parameters, cookie_name and cookie_error. The cookie_name parameter is, oddly enough, the name of the cookie we'll use to validate and it should match the cookie set in the above code.

The other parameter, cookie_error, is the error message that will be returned if the user has cookies disabled. Typically, validation errors are phrases like "Invalid username" or "Password must contain 6-8 characters". But we're going to use "cookies_disabled" and I'll show you why in a few minutes.

IMPORTANT: The cookie validation should occur first.

module_dir/validate/login.yml:

methods:
  post: [username]
 
names:
  username:
    required:     true
    required_msg: 
    validators:   [cookiesEnabledValidator, userValidator]
 
cookiesEnabledValidator:
  class:          myCookiesEnabledValidator
  param:
    cookie_name:  cookies_enabled
    cookie_error: cookies_disabled
 
userValidator:
  class:          myLoginValidator
  param:
    password:     password
    username_error: Invalid username.
    password_error: Invalid password.

Copy the following code to one of your lib directories. Since it only deals with the login action, I choose to keep it in my user module's lib directory.

module_dir/lib/myCookiesEnabledValidator.class.php:

class myCookiesEnabledValidator extends sfValidator
{    
  public function initialize($context, $parameters = null)
  {
    // initialize parent
    parent::initialize($context);
 
    // set defaults
    $this->setParameter('cookie_name', sfContext::getInstance()->getStorage()->getParameter('session_name'));
    $this->setParameter('cookie_error', 'This site requires cookies.');
    $this->getParameterHolder()->add($parameters);
 
    return true;
  }
 
  public function execute(&$value, &$error)
  {    
    if (sfContext::getInstance()->getRequest()->getCookie($this->getParameter('cookie_name')) === null)
    {
      $error = $this->getParameter('cookie_error');
      return false;
    }
    return true;
  }
}

Now, since it takes two pages to set and read a cookie it wouldn't make sense to return the user to the form right away. If they enable their cookies they'll still have to submit the form twice before they'll login successfully. I prefer to send them to a page which notifies them that the site requires cookies and explains how they can enable them. (Plus, this gives us the extra click we need to set that validation cookie!)

So we'll check for the cookie validation error before returning to the form so we can redirect the user to our help page if necessary. The error we check for in the username parameter must match the cookie_error we defined in the login.yml.

module_dir/actions/actions.class.php:

public function handleErrorLogin()
{
  if (sfContext::getInstance()->getRequest()->getError('username') == 'cookies_disabled')
  {
    $this->redirect('@about_cookies');
  }
  return sfView::SUCCESS;
}

So that's it. Throw in an about cookies page and you're all set.

If I made any mistakes, I apologize. It's 5am on a school night.

by whoknows on 2007-05-11, tagged cookie  login  session  storage  usability  validation 

CUIT/CUIL Validator

This is a CUIT validator for argentinian users.

/**
 * albaCUITValidator Valida el CUIT
 *
 * @package    alba
 * @author     Héctor Sanchez <hsanchez@pressenter.com.ar>
 * @author     José Luis Di Biase <josx@interorganic.com.ar>
 * @author     Fernando Toledo <ftoledo@pressenter.com.ar>
 * @version    SVN: $Id: albaCUITValidator.class.php 4347 2007-02-28 21:19:57Z josx $
 * @filesource
 * @license GPL
 */
 
class albaCUITValidator extends sfValidator {
 
    function initialize($context, $parameters = null)
    {
        // initialize parent
        parent::initialize($context);
 
        // set defaults
        $this->getParameterHolder()->set('cuit_error', 'CUIT Invalido');
        $this->getParameterHolder()->add($parameters);
        return true;
    }
 
    public function execute(&$value, &$error)
    {
        $cuit = $value;
        $coeficiente = array(5,4,3,2,7,6,5,4,3,2);
        $cuit_rearmado = "";
        //separo cualquier caracter que no tenga que ver con numeros
        for ($i=0; $i < strlen($cuit); $i= $i +1) {
            if ((Ord(substr($cuit, $i, 1)) >= 48) && (Ord(substr($cuit, $i, 1)) <= 57))
                $cuit_rearmado = $cuit_rearmado . substr($cuit, $i, 1);
        }
 
        // si no estan todos los digitos
        if (strlen($cuit_rearmado) <> 11) {
            $error = $this->getParameterHolder()->get('cuit_error');
            return false;
        } else {
            $sumador = 0;
            $verificador = substr($cuit_rearmado, 10, 1); //tomo el digito verificador
 
            for ($i=0; $i <=9; $i=$i+1)
                $sumador = $sumador + (substr($cuit_rearmado, $i, 1)) * $coeficiente[$i];//separo cada digito y lo multiplico por el coeficiente
 
            $resultado = $sumador % 11;
            $resultado = 11 - $resultado;  //saco el digito verificador
 
            if (intval($verificador) <> $resultado) {
                $error = $this->getParameterHolder()->get('cuit_error');
                return false;
            } else {
                //$cuit_rearmado = substr($cuit_rearmado, 0, 2) . "-" . substr($cuit_rearmado, 2, 8) . "-" . substr($cuit_rearmado, 10, 1);
                return true;
            }
        }
    }
}
?>
by Héctor Sanchez on 2007-04-30, tagged cuil  cuit  validation  validator 

CNPJ and CPF validator

A CNPJ and CPF validator for brazilian users...

Just add this in the module/lib/myCpfValidator.class.php path...

//Symfony integration as sfValidator of CPF and //CNPJ
//Date - Jul 11, 2006
//Author - Lucas Peres (mysyfy@gmail.com)
 
//CNPJ and CPF Validator
//Author: Marcelo Bom Jardim
 
//ABOUT
//This PHP script will validate CNPJ and CPF //number by checking there length
//and some other validations.
 
 
class myCpfValidator extends sfValidator {
 
    private function validaCPF($cpf) {
        $soma = 0;
 
        if (strlen($cpf) <> 11)
        return false;
 
        // Verifica 1º digito
        for ($i = 0; $i < 9; $i++) {
            $soma += (($i+1) * $cpf[$i]);
        }
 
        $d1 = ($soma % 11);
 
        if ($d1 == 10) {
            $d1 = 0;
        }
 
        $soma = 0;
 
        // Verifica 2º digito
        for ($i = 9, $j = 0; $i > 0; $i--, $j++) {
            $soma += ($i * $cpf[$j]);
        }
 
        $d2 = ($soma % 11);
 
        if ($d2 == 10) {
            $d2 = 0;
        }
 
        if ($d1 == $cpf[9] && $d2 == $cpf[10]) {
            return true;
        }
        else {
            return false;
        }
    }
 
    private function validaCNPJ($cnpj) {
 
        if (strlen($cnpj) <> 14)
        return false;
 
        $soma = 0;
 
        $soma += ($cnpj[0] * 5);
        $soma += ($cnpj[1] * 4);
        $soma += ($cnpj[2] * 3);
        $soma += ($cnpj[3] * 2);
        $soma += ($cnpj[4] * 9);
        $soma += ($cnpj[5] * 8);
        $soma += ($cnpj[6] * 7);
        $soma += ($cnpj[7] * 6);
        $soma += ($cnpj[8] * 5);
        $soma += ($cnpj[9] * 4);
        $soma += ($cnpj[10] * 3);
        $soma += ($cnpj[11] * 2);
 
        $d1 = $soma % 11;
        $d1 = $d1 < 2 ? 0 : 11 - $d1;
 
        $soma = 0;
        $soma += ($cnpj[0] * 6);
        $soma += ($cnpj[1] * 5);
        $soma += ($cnpj[2] * 4);
        $soma += ($cnpj[3] * 3);
        $soma += ($cnpj[4] * 2);
        $soma += ($cnpj[5] * 9);
        $soma += ($cnpj[6] * 8);
        $soma += ($cnpj[7] * 7);
        $soma += ($cnpj[8] * 6);
        $soma += ($cnpj[9] * 5);
        $soma += ($cnpj[10] * 4);
        $soma += ($cnpj[11] * 3);
        $soma += ($cnpj[12] * 2);
 
 
        $d2 = $soma % 11;
        $d2 = $d2 < 2 ? 0 : 11 - $d2;
 
        if ($cnpj[12] == $d1 && $cnpj[13] == $d2) {
            return true;
        } else {
            return false;
        }
    }
 
 
 
    public function execute (&$value, &$error)
    {
        if($this->getParameter('tipo') == 'cpf') {
            if(!$this->validaCPF($value)) {
                $error = $this->getParameter('msg_error');
                return false;
            }
        } else if($this->getParameter('tipo') == 'cnpj') {
            if(!$this->validaCNPJ($value)) {
                $error = $this->getParameter('msg_error');
                return false;
            }
        } else {
            $error = $this->getParameter('msg_error');
            return false;
        }       
        return true;
    }
 
    public function initialize ($context, $parameters = null)
    {
 
        // initialize parent
        parent::initialize($context, $parameters);
 
        // set defaults
        $this->setParameter('msg_error', 'Invalid input');
 
        $this->getParameterHolder()->add($parameters);
 
        return true;
 
 
    }
}

Then at the module/validate.yml add:

names:
  [...]
  cpf:
    required:      Yes
    required_msg:  O campo CPF &eacute; requerido
    validators:    cpfValidator
 
cpfValidator:
  class:          myCpfValidator    
  param:
    tipo:         cpf
    msg_error:    CPF inv&aacute;lido
by Lucas Peres on 2006-07-12, tagged cnpj  validation  validator 
(1 comment)