Home / Validating numbers with PHP

Validating numbers with PHP

Last week David Walsh posted about validating numeric values and digits with PHP on his excellent blog. I posted my own comments about his particular post but they never appeared so I decided to post a better response here.

The point of David’s post was that he needed to be able to validate between finding a numeric value (which might be a floating point number and therefore contain a decimal point) and whether a number only contains digits.

His solution was this:

/* numeric, decimal passes */
function validate_numeric($variable)
{
    return is_numeric($variable);
}

/* digits only, no dots */
function is_digits($element)
{
    return !preg_match ("/[^0-9]/", $element);
}

As I noted in my comment (which wasn’t published), I’m not sure why you’d wrap is_numeric() into his validate_numeric() function when all it’s doing is calling is_numeric(). Why not just call is_numeric() instead?

The is_digits() function on the other hand is actually pretty good. I initially thought there may be some issues with it but it works nicely but there is one simpler alternative.

is_integer – no good

In my comment I suggested that he could use the is_integer() function as long as the acceptable value was within the integer type range, and postive and negative values are acceptable. Of course, a digit only value might not be within the integer range, for example is_integer(12345678901234567890) would return false but does only contain numbers.

The problem with my initial assumption is that in PHP data submitted from a form that *does* only contain digits and *is* within the integer range will still return false from is_integer() because it will be considered to be a string. For example:

<form ...>
<input type="text" name="foo" value="123" />
</form>

And then doing this when the form is submitted:

echo (int)is_integer((int)$_POST['foo']);

will print 0, meaning false. D’oh! Also an integer can contain – if it is a negative value so -123 will return true even though it contains more than just digits.

ctype_digit – not much better

The other alternative is the ctype_digit() function which saves having to mess around with regular expressions. ctype_digit checks if all of the characters in the passed in value are numerical. Only the numbers 0 to 9 are valid, and it doesn’t matter if the value is type cast as a string, which is what will happen from a form post.

However, ctype_digit it expects the input to be a string and will return false if the value passed in is an ineteger…

For example:

var_dump(ctype_digit(123));
var_dump(ctype_digit('123'));
var_dump(ctype_digit(12345678901234567890));
var_dump(ctype_digit('12345678901234567890'));

These display:

bool(false)
bool(true)
bool(false)
bool(true)

You should be able to use (string), strval() etc to cast the value as a string first and then pass it to ctype_digit but I’ve found if the number is too large it still doesn’t work.

For example, the first four below return true, but the last one returns false:

ctype_digit(strval(12345678901));
ctype_digit(strval(123456789012));
ctype_digit(strval(1234567890123));
ctype_digit(strval(12345678901234));
ctype_digit(strval(123456789012345));

Use the regexp

So my initial thought was just use is_integer() and someone else suggested to use ctype_digit but it would turn out that using the regular expression with preg_match is the best solution after all. Just remember when using regular expressions with PHP to use the preg* functions and not the ereg* functions because the latter are deprecated in PHP 6.