I have the following code
$page = $_GET['p'];
if($page == "")
{
$page = 1;
}
if(is_int($page) == false)
{
setcookie("error", "Invalid page.", time()+3600);
header("location:somethingwentwrong.php");
die();
}
//else continue with code
which I am going to use for looking at different "pages" of a database (results 1-10, 11-20, etc). I can't seem to get the is_int() function to work correctly, however. Putting "1" into the url (noobs.php?p=1) gives me the invalid page error, as well as something like "asdf".
13 Answers 13
Using is_numeric() for checking if a variable is an integer is a bad idea. This function will return TRUE for 3.14 for example. It's not the expected behavior.
To do this correctly, you can use one of these options:
Considering this variables array :
$variables = [
"TEST -1" => -1,
"TEST 0" => 0,
"TEST 1" => 42,
"TEST 2" => 4.2,
"TEST 3" => .42,
"TEST 4" => 42.,
"TEST 5" => "42",
"TEST 6" => "a42",
"TEST 7" => "42a",
"TEST 8" => 0x24,
"TEST 9" => 1337e0
];
The first option (FILTER_VALIDATE_INT way) :
# Check if your variable is an integer
if ( filter_var($variable, FILTER_VALIDATE_INT) === false ) {
echo "Your variable is not an integer";
}
Output :
TEST -1: -1 (type:integer) Your variable is an integer ✔
TEST 0 : 0 (type:integer) is an integer ✔
TEST 1 : 42 (type:integer) is an integer ✔
TEST 2 : 4.2 (type:double) is not an integer ✘
TEST 3 : 0.42 (type:double) is not an integer ✘
TEST 4 : 42 (type:double) is an integer ✔
TEST 5 : 42 (type:string) is an integer ✔
TEST 6 : a42 (type:string) is not an integer ✘
TEST 7 : 42a (type:string) is not an integer ✘
TEST 8 : 36 (type:integer) is an integer ✔
TEST 9 : 1337 (type:double) is an integer ✔
The second option (CASTING COMPARISON way) :
# Check if your variable is an integer
if ( strval($variable) !== strval(intval($variable)) ) {
echo "Your variable is not an integer";
}
Output :
TEST -1: -1 (type:integer) Your variable is an integer ✔
TEST 0 : 0 (type:integer) is an integer ✔
TEST 1 : 42 (type:integer) is an integer ✔
TEST 2 : 4.2 (type:double) is not an integer ✘
TEST 3 : 0.42 (type:double) is not an integer ✘
TEST 4 : 42 (type:double) is an integer ✔
TEST 5 : 42 (type:string) is an integer ✔
TEST 6 : a42 (type:string) is not an integer ✘
TEST 7 : 42a (type:string) is not an integer ✘
TEST 8 : 36 (type:integer) is an integer ✔
TEST 9 : 1337 (type:double) is an integer ✔
The third option (CTYPE_DIGIT way) (positive numbers and 0 only):
# Check if your variable is an integer
if ( ! ctype_digit(strval($variable)) ) {
echo "Your variable is not an integer";
}
Output :
TEST -1: -1 (type:integer) # Your variable is not an integer ✘
TEST 0 : 0 (type:integer) is an integer ✔
TEST 1 : 42 (type:integer) is an integer ✔
TEST 2 : 4.2 (type:double) is not an integer ✘
TEST 3 : 0.42 (type:double) is not an integer ✘
TEST 4 : 42 (type:double) is an integer ✔
TEST 5 : 42 (type:string) is an integer ✔
TEST 6 : a42 (type:string) is not an integer ✘
TEST 7 : 42a (type:string) is not an integer ✘
TEST 8 : 36 (type:integer) is an integer ✔
TEST 9 : 1337 (type:double) is an integer ✔
The fourth option (REGEX way) :
# Check if your variable is an integer
if ( ! preg_match('/^-?\d+$/', $variable) ) {
echo "Your variable is not an integer";
}
Output :
TEST -1: -1 (type:integer) Your variable is an integer ✔
TEST 0 : 0 (type:integer) is an integer ✔
TEST 1 : 42 (type:integer) is an integer ✔
TEST 2 : 4.2 (type:double) is not an integer ✘
TEST 3 : 0.42 (type:double) is not an integer ✘
TEST 4 : 42 (type:double) is an integer ✔
TEST 5 : 42 (type:string) is an integer ✔
TEST 6 : a42 (type:string) is not an integer ✘
TEST 7 : 42a (type:string) is not an integer ✘
TEST 8 : 36 (type:integer) is an integer ✔
TEST 9 : 1337 (type:double) is an integer ✔
11 Comments
if(filter_var($variable, FILTER_VALIDATE_INT) !== false) echo "its not an integer ,right?-?), but I don't believe that ctype_digit can be used in a concise way to check for negative integers. Also, the posted code cannot produce the corresponding outputs.All $_GET parameters have a string datatype, therefore, is_int will always return false.
You can see this by calling var_dump:
var_dump($_GET['p']); // string(2) "54"
Using is_numeric will provide the desired result (mind you, that allows values such as: 0x24).
1 Comment
When the browser sends p in the querystring, it is received as a string, not an int. is_int() will therefore always return false.
Instead try is_numeric() or ctype_digit()
Comments
Just for kicks, I tested out a few of the mentioned methods, plus one I've used as my go to solution for years when I know my input is a positive number or string equivalent.
I tested this with 125,000 iterations, with each iteration passing in the same set of variable types and values.
Method 1: is_int($value) || ctype_digit($value)
Method 2: (string)(int)$value == (string)$value
Method 3: strval(intval($value)) === strval($value)
Method 4: ctype_digit(strval($value))
Method 5: filter_var($value, FILTER_VALIDATE_INT) !== FALSE
Method 6: is_int($value) || ctype_digit($value) || (is_string($value) && $value[0] === '-' && filter_var($value, FILTER_VALIDATE_INT) !== FALSE)
Method 1: 0.0552167892456
Method 2: 0.126773834229
Method 3: 0.143012046814
Method 4: 0.0979189872742
Method 5: 0.112988948822
Method 6: 0.0858821868896
(I didn't even test the regex, I mean, seriously... regex for this?)
Things to note:
Method 4 always returns false for negative numbers (negative integer or string equivalent), so is a good method to consistently detect that a value is a positive integer.
Method 1 returns true for a negative integer, but false for a string equivalent of a negative integer, so don't use this method unless you are certain your input will never contain a negative number in string or integer form, and that if it does, your process won't break from this behavior.
Conclusions
So it seems that if you are certain that your input will not include a negative number, then it is almost twice as fast to use is_int and ctype_digit to validate that you have an integer. Using Method 1 with a fallback to method 5 when the variable is a string and the first character is a dash is the next fastest (especially when a majority of the input is actual integers or positive numbers in a string). All in all, if you need solid consistency, and you have no idea what the mix of data is coming in, and you must handle negatives in a consistent fashion, filter_var($value, FILTER_VALIDATE_INT) !== FALSE wins.
Code used to get the output above:
$u = "-10";
$v = "0";
$w = 0;
$x = "5";
$y = "5c";
$z = 1.44;
function is_int1($value){
return (is_int($value) || ctype_digit($value));
}
function is_int2($value) {
return ((string)(int)$value == (string)$value);
}
function is_int3($value) {
return (strval(intval($value)) === strval($value));
}
function is_int4($value) {
return (ctype_digit(strval($value)));
}
function is_int5($value) {
return filter_var($value, FILTER_VALIDATE_INT) !== FALSE;
}
function is_int6($value){
return (is_int($value) || ctype_digit($value) || (is_string($value) && $value[0] === '-' && filter_var($value, FILTER_VALIDATE_INT)) !== FALSE);
}
$start = microtime(TRUE);
for ($i=0; $i < 125000; $i++) {
is_int1($u);
is_int1($v);
is_int1($w);
is_int1($x);
is_int1($y);
is_int1($z);
}
$stop = microtime(TRUE);
$start2 = microtime(TRUE);
for ($j=0; $j < 125000; $j++) {
is_int2($u);
is_int2($v);
is_int2($w);
is_int2($x);
is_int2($y);
is_int2($z);
}
$stop2 = microtime(TRUE);
$start3 = microtime(TRUE);
for ($k=0; $k < 125000; $k++) {
is_int3($u);
is_int3($v);
is_int3($w);
is_int3($x);
is_int3($y);
is_int3($z);
}
$stop3 = microtime(TRUE);
$start4 = microtime(TRUE);
for ($l=0; $l < 125000; $l++) {
is_int4($u);
is_int4($v);
is_int4($w);
is_int4($x);
is_int4($y);
is_int4($z);
}
$stop4 = microtime(TRUE);
$start5 = microtime(TRUE);
for ($m=0; $m < 125000; $m++) {
is_int5($u);
is_int5($v);
is_int5($w);
is_int5($x);
is_int5($y);
is_int5($z);
}
$stop5 = microtime(TRUE);
$start6 = microtime(TRUE);
for ($n=0; $n < 125000; $n++) {
is_int6($u);
is_int6($v);
is_int6($w);
is_int6($x);
is_int6($y);
is_int6($z);
}
$stop6 = microtime(TRUE);
$time = $stop - $start;
$time2 = $stop2 - $start2;
$time3 = $stop3 - $start3;
$time4 = $stop4 - $start4;
$time5 = $stop5 - $start5;
$time6 = $stop6 - $start6;
print "**Method 1:** $time <br>";
print "**Method 2:** $time2 <br>";
print "**Method 3:** $time3 <br>";
print "**Method 4:** $time4 <br>";
print "**Method 5:** $time5 <br>";
print "**Method 6:** $time6 <br>";
2 Comments
preg_match('/^[0-9]+$/', $value) easier to understand, and it performs as well as some of the other methods here./!\ Best anwser is not correct, is_numeric() returns true for integer AND all numeric forms like "9.1"
For integer only you can use the unfriendly preg_match('/^\d+$/', $var) or the explicit and 2 times faster comparison :
if ((int) $var == $var) {
// $var is an integer
}
PS: i know this is an old post but still the third in google looking for "php is integer"
6 Comments
(int) $var will return zero if the string can't be made into a number, so: (int) 'banana' === 0if (is_numeric($var) && ((int) $var == $var)) {...}?doctormad's solution is not correct. try this:
$var = '1a';
if ((int) $var == $var) {
var_dump("$var is an integer, really?");
}
this prints
1a is an integer, really?"
use filter_var() with FILTER_VALIDATE_INT argument
$data = Array('0', '1', '1a', '1.1', '1e', '0x24', PHP_INT_MAX+1);
array_walk($data, function ($num){
$is_int = filter_var($num, FILTER_VALIDATE_INT);
if ($is_int === false)
var_dump("$num is not int");
});
this prints
1a is not int
1.1 is not int
1e is not int
0x24 is not int
9.2233720368548E+18 is not int
1 Comment
I had a similar problem just now!
You can use the filter_input() function with FILTER_VALIDATE_INT and FILTER_NULL_ON_FAILURE to filter only integer values out of the $_GET variable. Works pretty accurately! :)
Check out my question here: How to check whether a variable in $_GET Array is an integer?
Comments
When i start reading it i did notice that you guys forgot about abvious think like type of to check if we have int, string, null or Boolean.
So i think gettype() should be as 1st answer.
Explain:
So if we have $test = [1,w2,3.45,sasd]; we start test it
foreach ($test as $value) {
$check = gettype($value);
if($check == 'integer'){
echo "This var is int\r\n";
}
if($check != 'integer'){
echo "This var is {$check}\r\n";
}
}
And output:
> This var is int
> This var is string
> This var is double
> This var is string
I think this is easiest way to check if our var is int, string, double or Boolean.
Comments
Values $_GET are always strings – that's what GET paramters come as. Therefore, is_int($_GET[...]) is always false.
You can test if a string consists only of digits(i.e. could be interpreted as a number) with is_numeric.
Comments
You could try using a casting operator to convert it to an integer:
$page = (int) $_GET['p'];
if($page == "")
{
$page = 1;
}
if(empty($page) || !$page)
{
setcookie("error", "Invalid page.", time()+3600);
header("location:somethingwentwrong.php");
die();
}
//else continue with code
$page = (isset($_GET['p']) ? (int)$_GET['p'] : 1);
if ($page > 0)
{
...
}
Try casting and checking if it's a number initially.
2 Comments
is_int() here is redundant. The variable $page will always be an integer here, due to the previous line of code.>0. My apologies.In my opinion the correct function should look as following:
public function checkIfValueIsInt($value): bool
{
if (is_bool($value)) {
return false;
}
if (0 === filter_var($value, FILTER_VALIDATE_INT) || filter_var($value, FILTER_VALIDATE_INT)) {
return true;
}
return false;
}
given set of tests is validated correctly using it:
[
true,
false,
],
[
false,
false,
],
[
'false',
false,
],
[
'true',
false,
],
[
'some random string',
false,
],
[
[],
false,
],
[
['some string', 1],
false,
],
[
(object) [],
false,
],
[
2.222,
false,
],
[
rand(0, 99999),
true,
],
[
1,
true,
],
[
0,
true,
],
[
-1,
true,
],
the reason I added is_bool check is that
true
value is handle incorrectly by:
0 === filter_var($value, FILTER_VALIDATE_INT) || filter_var($value, FILTER_VALIDATE_INT)
Comments
Check int and float types:
private function isInteger(mixed $val): bool
{
if (!is_scalar($val) || is_bool($val)) {
return false;
}
return !$this->isFloat($val) && preg_match('~^((?:\+|-)?[0-9]+)$~', $val) === 1;
}
private function isFloat(mixed $val): bool
{
if (!is_scalar($val) || is_bool($val)) {
return false;
}
return gettype($val) === "double" || preg_match("/^([+-]*\\d+)*\\.(\\d+)*$/", $val) === 1;
}
}