How to check that a string is an int, but not a double, etc.?

Viewed 112285

PHP has an intval() function that will convert a string to an integer. However I want to check that the string is an integer beforehand, so that I can give a helpful error message to the user if it's wrong. PHP has is_int(), but that returns false for string like "2".

PHP has the is_numeric() function, but that will return true if the number is a double. I want something that will return false for a double, but true for an int.

e.g.:

my_is_int("2") == TRUE
my_is_int("2.1") == FALSE
28 Answers

How about using ctype_digit?

From the manual:

<?php
$strings = array('1820.20', '10002', 'wsl!12');
foreach ($strings as $testcase) {
    if (ctype_digit($testcase)) {
        echo "The string $testcase consists of all digits.\n";
    } else {
        echo "The string $testcase does not consist of all digits.\n";
    }
}
?>

The above example will output:

The string 1820.20 does not consist of all digits.
The string 10002 consists of all digits.
The string wsl!12 does not consist of all digits.

This will only work if your input is always a string:

$numeric_string = '42';
$integer        = 42;

ctype_digit($numeric_string);  // true
ctype_digit($integer);         // false

If your input might be of type int, then combine ctype_digit with is_int.

If you care about negative numbers, then you'll need to check the input for a preceding -, and if so, call ctype_digit on a substr of the input string. Something like this would do it:

function my_is_int($input) {
  if ($input[0] == '-') {
    return ctype_digit(substr($input, 1));
  }
  return ctype_digit($input);
}

filter_var should do it:

var_dump(filter_var('2', FILTER_VALIDATE_INT));   // 2
var_dump(filter_var('2.0', FILTER_VALIDATE_INT)); // false
var_dump(filter_var('2.1', FILTER_VALIDATE_INT)); // false

but

var_dump(filter_var(2, FILTER_VALIDATE_INT));     // 2
var_dump(filter_var(2.0, FILTER_VALIDATE_INT));   // 2
var_dump(filter_var(2.1, FILTER_VALIDATE_INT));   // false

If you just want Booleans as return values, wrap it into a function, e.g.

function validatesAsInt($number)
{
    $number = filter_var($number, FILTER_VALIDATE_INT);
    return ($number !== FALSE);
}

+1 to Dominic's answer (using ctype_digit). Another way you could do it is with type coercion:

$inty = "2";
$inty2 = " 2";
$floaty = "2.1";
$floaty2 = "2.0";

is_int($inty + 0); // true
is_int($floaty + 0); // false
is_int($floaty2 + 0); // false

// here's difference between this and the ctype functions.
is_int($inty2 + 0);  // true
ctype_digit($inty2); // false

Cast it to int. if it still have the same value its int;

function my_is_int($var) {
  $tmp = (int) $var;
  if($tmp == $var)
       return true;
  else
       return false;
}

One really clean way that I like to use is that one. You cast it twice, first in int, secondly in string, then you strict compare ===. See the example below:

$value === (string)(int)$value;

Now, about your function my_is_int, you can do something like this:

function my_is_int($value){ return $value === (string)(int)$value; }
my_is_int('2');  // true
my_is_int('2.1') // false
/**
 * Check if a number is a counting number by checking if it
 * is an integer primitive type, or if the string represents
 * an integer as a string
 */
function is_int_val($data) {
    if (is_int($data) === true) return true;
    if (is_string($data) === true && is_numeric($data) === true) {
        return (strpos($data, '.') === false);
    }
}

Source.

Here's a simple solution that uses is_numeric, floatval, and intval:

function is_string_an_int($string)
{
    if (is_string($string) === false)
    {
        //throw some kind of error, if needed
    }

    if (is_numeric($string) === false || floatval(intval($string)) !== floatval($string))
    {
        return false;
    }

    else
    {
        return true;
    }
}

Results:

is_string_an_int('-1'); //true
is_string_an_int('-1.0'); //true
is_string_an_int('-1.1'); //false
is_string_an_int('0'); //true
is_string_an_int('0.0'); //true
is_string_an_int('0.1'); //false
is_string_an_int('1'); //true
is_string_an_int('1.0'); //true
is_string_an_int('1.1'); //false
is_string_an_int('' . PHP_INT_MAX); //true
is_string_an_int('foobar'); //false
is_string_an_int('NaN'); //false
is_string_an_int('null'); //false
is_string_an_int('undefined'); //false

Note that values greater than PHP_INT_MAX may return false.

It works perfectly! Hope it will be helpful to you =)

$value = 1; // true
$value = '1'; // true
$value = '1.0'; // true
$value = ' 1'; // true
$value = '01'; // true

$value = -1; // true
$value = '-1'; // true
$value = '-1.0'; // true
$value = ' -1'; // true
$value = '-01'; // true

$value = PHP_INT_MIN; // true
$value = PHP_INT_MAX; // true
$value = 0x000001; // true

$value = 'a'; // false
$value = '1a'; // false
$value = 'a1'; // false
$value = 1.1; // false
$value = '1.1'; // false
$value = '--1'; // false
$value = []; // false
$value = [1,2]; // false
$value = true; // false
$value = false; // false
$value = null; // false
$value = 'NaN'; // false
$value = 'undefined'; // false

function isInt($value) {
    return is_numeric($value) && floatval(intval($value)) === floatval($value);
}

How about:

function isIntStr($str) {
   return preg_match('/^(-?\d+)(?:\.0+)?$/', trim($str), $ms)
       && bcComp($ms[1], PHP_INT_MAX) <= 0
       && bcComp($ms[1], -PHP_INT_MAX - 1) >= 0;
}

This function should only return true for any string number that can be cast to int with (int) or intval() without losing anything of mathematical significance (such as non-zeros after decimal point or numbers outside of PHP's integer range) while accepting things that aren't mathematically significant (such as whitespace; leading zeros; or, after the decimal point, zeros exclusively).

It will return false for '10.' but not for '10.0'. If you wanted '10.' to be true you could change the + after the 0 in the regular expression to *.

Here is a working 1 row example :

<?php
// combination of is_int and type coercion
// FALSE: 0, '0', null, ' 234.6',  234.6
// TRUE: 34185, ' 34185', '234', 2345
$mediaID =  34185;
if( is_int( $mediaID + 0) && ( $mediaID + 0 ) > 0 ){
    echo 'isint'.$mediaID;
}else{
    echo 'isNOTValidIDint';
}
?>

If you are handling numeric IDs from mysql and are trying to impose a validation for it to be a valid non zero int or an int but in string format (as mysql always returns everything in string format) and not NULL. You can use the following. This is the most error/warning/notice proof way to only allow int/string-ints which I found.

...
if(empty($id) || !is_scalar($id) || !ctype_digit($id)){
  throw("Invalid ID");
}
...

A simple way is to cast the number to both an integer and a float and check if they are the same

if ((int) $val == (float) $val) {
    echo 'AN INTEGER';
} else {
    echo 'NOT AN INTEGER';
}

Could either use is_numeric() then check for presence of "." in the string (not particularly culture-sensitive though).

Alternatively use is_numeric() then cast to a double and see if $var == floor($var) (should return true if it's an integer).

Related