EllisLab text mark
Advanced Search
     
Form validation with Greater Than won’t work with international currencies (comma separated decimal numbers)
Posted: 24 April 2012 07:31 PM
Joined: 2010-04-08
38 posts

Hi, I was trying out the form validation Greater Than like this:

$this->form_validation->set_rules('value','Value','required|max_length[128]|xss_clean|greater_than[299]'); 

I’m using this for currency. So I tested with the amount 300,50 and it shows a validation error. The error says it should be greater than 300. In Argentina (and many other countries I presume) currency numbers have the following format:

- 500,40
- 1.000,40

We use the comma to separate the cents and the dot to (optionally) notate thousands. Is there a way to extend the validation or set the separator to a custom value? I feel this could be useful to other international users.

 

 
Posted: 24 April 2012 10:12 PM   [ # 1 ]   [ Rating: 0 ]
Avatar
Joined: 2009-02-19
4325 posts

You could create a callback and convert the number to a float and then do the comparison.
Haven’t tested this, but the original conversion formula was found on php.net

public function greater_than_intl($str$max)
{
  
if (strpos($str'.') !== FALSE && strpos($str',') !== FALSE && strpos($str'.') < strpos($str','))
  
{
    $str 
str_replace('.''',$str);
    
$str strtr($str,',''.');           
  
}
  
else
  
{
    $str 
str_replace(','''$str);           
  
}
       
  $str 
float($str);

  
$this->form_validation->set_message('greater_than_intl''The %s field must be greater than ' $max);

  return (
$str $max);
 Signature 
 
Posted: 25 April 2012 01:18 AM   [ # 2 ]   [ Rating: 0 ]
Avatar
Joined: 2007-11-28
2435 posts

You also could extend the library and add your own custom rule, removing the need to add the “callback_” prefix. Good if you intend on using that rule throughout multiple controllers.

 
Posted: 26 April 2012 08:23 PM   [ # 3 ]   [ Rating: 0 ]
Joined: 2010-04-08
38 posts

I think extending the library would be nicer. Unfortunately I am not fluent enough in REGEX to do so. But I was able to do a minor hack to make the validation work with commas. Before validation I do a string replace to find the dot and turn it into a comma.

This is MY_Form_validation.php file

/**
  * Money
  *
  * @access public
  * @param string
  * @return bool
  */
 
public function is_money($input{
     
return (bool) preg_match('/^[0-9]+(\,[0-9]{0,2})?$/'$input);
 
}
 
    
 
/**
  * Greather than Money
  *
  * @access public
  * @param string
  * @return bool
  */
 
function greater_than_money($str$min)
 
{
  $str 
str_replace(",""."$str);
  if ( ! 
is_numeric($str))
  
{
   
return FALSE;
  
}
  
return $str $min;
 
 
Posted: 26 April 2012 08:44 PM   [ # 4 ]   [ Rating: 0 ]
Avatar
Joined: 2009-02-19
4325 posts

You forgot to create the error messages.

 Signature 
 
Posted: 26 April 2012 08:47 PM   [ # 5 ]   [ Rating: 0 ]
Joined: 2010-04-08
38 posts

Thanks for the remainder, but I’ve created them in the language files, so I’m set! smile

 
Posted: 26 April 2012 09:05 PM   [ # 6 ]   [ Rating: 0 ]
Avatar
Joined: 2009-02-19
4325 posts

Cool.  I never put them there because I copy rules a lot between different projects and it’s just easier if the error is contained within the rule.

 Signature 
 
Posted: 27 April 2012 12:04 AM   [ # 7 ]   [ Rating: 0 ]
Avatar
Joined: 2007-11-28
2435 posts

You’ll want to sanitize the numbers further, because given your example, a number with thousands would then contain more than one decimal point, providing incorrect results when comparing. For example:

$num1 '102,33';
$num2 '1.044,98';

$num1 str_replace(',''.'$num1); // 102.33
$num2 str_replace(',''.'$num2); // 1.044.98

var_dump($num1 $num2); // bool(true) 
 
Posted: 27 April 2012 12:58 AM   [ # 8 ]   [ Rating: 0 ]
Avatar
Joined: 2009-02-19
4325 posts

The one I posted had a check for that.

 Signature 
 
Posted: 27 April 2012 10:02 AM   [ # 9 ]   [ Rating: 0 ]
Joined: 2010-04-08
38 posts

I see. Good point. Would these 4 examples validate?

1.000
1.000,50
1000
1000.50

I would need to add a rule for the first example, right?