Перевірка, чи є змінна цілим числом у PHP


80

У мене такий код

    $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

які я збираюся використовувати для перегляду різних "сторінок" бази даних (результати 1-10, 11-20 тощо). Однак мені здається, що функція is_int () не працює належним чином. Поміщення "1" в URL-адресу (noobs.php? P = 1) дає мені помилку з помилкою сторінки, а також щось на зразок "asdf".

Відповіді:


184

Використання is_numeric()для перевірки, чи є змінна цілим числом, є поганою ідеєю. Ця функція повернеться TRUEдля3.14 наприклад. Це не очікувана поведінка.

Щоб зробити це правильно, ви можете скористатися одним із таких варіантів:

Враховуючи цей масив змінних:

$variables = [
    "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
];

Перший варіант (FILTER_VALIDATE_INT шлях):

# Check if your variable is an integer
if ( filter_var($variable, FILTER_VALIDATE_INT) === false ) {
  echo "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

Другий варіант (ШЛЯХ ПОРІВНЯННЯ):

# Check if your variable is an integer
if ( strval($variable) !== strval(intval($variable)) ) {
  echo "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

Третій варіант (CTYPE_DIGIT шлях):

# Check if your variable is an integer
if ( ! ctype_digit(strval($variable)) ) {
  echo "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

Четвертий варіант (спосіб REGEX):

# Check if your variable is an integer
if ( ! preg_match('/^\d+$/', $variable) ) {
  echo "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

10
Зверніть увагу, FILTER_VALIDATE_INT (ваш бажаний спосіб) 0 повертає false!
Niksac

13
Замість цього використовуйте filter_var ($ int, FILTER_VALIDATE_INT)! == false.
Niksac

1
Я думаю, що є! відсутній на if(filter_var($variable, FILTER_VALIDATE_INT) !== false) echo "its not an integer, так?
Адам

3
або текст слід змінити на `` це ітегер ''
Адам

3
'CTYPE_DIGIT way' і 'REGEX way' не вдаються для від'ємних цілих чисел. "Шлях REGEX" можна виправити, перевіривши, чи є провідний від'ємний знак ( -?), але я не вірю, що ctype_digitйого можна використовувати стисло для перевірки від'ємних цілих чисел. Крім того, розміщений код не може дати відповідні результати.
Dave F

33

Усі $_GETпараметри мають рядковий тип даних, отже,is_int завжди повертатимуть false.

Ви можете переконатися в цьому, зателефонувавши var_dump:

var_dump($_GET['p']); // string(2) "54"

Використання is_numericзабезпечить бажаний результат (майте на увазі, що допускає такі значення, як 0x24:).


3
Попередження: це повернеться правдою не лише для інтерів, використовуйте одне з наведених нижче рішень.
Натан Белл


12

Тільки для ударів я протестував декілька згаданих методів, а також один, який я використовував як рішення для переходу протягом багатьох років, коли знаю, що моє введення - це позитивне число або еквівалент рядка.

Я перевірив це за допомогою 125000 ітерацій, причому кожна ітерація передавалась в одному наборі типів змінних та значень.

Спосіб 1: is_int($value) || ctype_digit($value)
Спосіб 2: (string)(int)$value == (string)$value
Спосіб 3: strval(intval($value)) === strval($value)
Спосіб 4: ctype_digit(strval($value))
Спосіб 5: filter_var($value, FILTER_VALIDATE_INT) !== FALSE
Спосіб 6: is_int($value) || ctype_digit($value) || (is_string($value) && $value[0] === '-' && filter_var($value, FILTER_VALIDATE_INT) !== FALSE)

Метод 1: 0,0552167892456
Метод 2: 0,126773834229
Метод 3: 0,143012046814
Метод 4: 0,0979189872742
Метод 5: 0,112988948822
Метод 6: 0,0858821868896

(Я навіть не тестував регулярний вираз, я маю на увазі серйозно ... регулярний вираз для цього?)

Що слід зазначити:
Метод 4 завжди повертає значення false для від’ємних чисел (від’ємне ціле число або еквівалент рядка), тому це хороший метод для послідовного виявлення того, що значення є додатним цілим числом.
Метод 1 повертає true для від'ємного цілого числа, але false для рядкового еквівалента від'ємного цілого числа, тому не використовуйте цей метод, якщо ви не впевнені, що ваші дані ніколи не будуть містити від'ємне число у формі рядка або цілого числа, і що якщо це так , ваш процес не зламається від такої поведінки.

Висновки
Отже, якщо ви впевнені, що ваші дані не включатимуть від’ємне число, то це майже вдвічі швидше використовувати is_intі ctype_digitперевірити, що у вас ціле число. Використання методу 1 із запасним способом до методу 5, коли змінною є рядок, а першим символом є тире, є наступним найшвидшим (особливо, коли більшість вхідних даних - це фактичні цілі числа або додатні числа в рядку). Загалом, якщо вам потрібна тверда узгодженість, і ви не уявляєте, яка суміш даних надходить, і ви повинні послідовно обробляти негативи, filter_var($value, FILTER_VALIDATE_INT) !== FALSEвиграє.

Код, який використовується для отримання вихідних даних вище:

$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>";  

8

/! \ Найкращий anwser неправильний, is_numeric () повертає true для цілого числа І всіх числових форм, таких як "9.1"

Тільки для цілого числа ви можете використовувати недружній preg_match ('/ ^ \ d + $ /', $ var) або явне і в 2 рази швидше порівняння:

if ((int) $var == $var) {
    // $var is an integer
}

PS: Я знаю, що це стара публікація, але все ще третя в Google, яка шукає "php - це ціле число"


1
Це неправильно, оскільки ця умова буде виконуватися навіть тоді, коли, наприклад, $ var = "9". Це має бути if ((int) $ var === $ var). $ a == $ b Дорівнює TRUE, якщо $ a дорівнює $ b після жонглювання типом. $ a === $ b Ідентичне TRUE, якщо $ a дорівнює $ b, і вони одного типу.
valerij vasilcenko

зверніть увагу, що (int) $varповерне нуль, якщо рядок неможливо перетворити на число, отже: (int) 'banana' === 0
Ігнасіо Сегура

Проголосовано проти того, як коментарі виявляють, що ця відповідь неправильна.
EAmez

@IgnacioSegura, то чи безпечно, якщо використовувати його після такого валідатора, як if (is_numeric($var) && ((int) $var == $var)) {...}?
Guney Ozsan

@GuneyOzsan те, що ви пропонуєте, звучить правильно, але, чесно кажучи, я перестав кодувати PHP два роки тому і забув багато речей. На жаль, я не міг бути кориснішим.
Ігнасіо Сегура

3

Ви можете спробувати використовувати оператор кастингу, щоб перетворити його на ціле число:

$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

1
Добре, якщо спочатку ви is_intis_numeric
приведете

2

Цінності - $_GETце завжди рядки - ось що таке параметри GET. Тому is_int($_GET[...])завжди є помилковим.

Ви можете перевірити, чи рядок складається лише з цифр (тобто може бути інтерпретований як число) за допомогою is_numeric .


2

Щойно у мене була подібна проблема!

Ви можете використовувати filter_input()функцію з FILTER_VALIDATE_INTі FILTER_NULL_ON_FAILUREдля фільтрації лише цілочисельних значень з$_GET змінної. Працює досить точно! :)

Перевірте моє запитання тут: Як перевірити, чи є змінна в масиві $ _GET цілим числом?


2

рішення лікаря не є правильним. спробуйте це:

$var = '1a';
if ((int) $var == $var) {
    var_dump("$var is an integer, really?");
}

це друкує

1a - ціле число, справді? "

використовуйте filter_var () з аргументом FILTER_VALIDATE_INT

$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");
});

це друкує

1a is not int 
1.1 is not int
1e is not int
0x24 is not int
9.2233720368548E+18 is not int

Мені сподобалося ваше рішення ... приймає 0, але заперечує нецілі символи.
user2662680

1
$page = (isset($_GET['p']) ? (int)$_GET['p'] : 1);
if ($page > 0)
{
  ...
}

Спробуйте кинути та перевірити, чи це номер спочатку.


Дзвінок is_int()сюди зайвий. Змінна тут $pageзавжди буде цілим числом через попередній рядок коду.
Hammerite

@ netcoder / @ Hammerite: Туш, забув, що привід буде надавати значення за замовчуванням. Повинна перевіряти, чи >0. Мої вибачення.
Бред Крісті

1

Коли я починаю його читати, я помітив, що ви, хлопці, забули про очевидний тип думки, щоб перевірити, чи є у нас int, string, null або Boolean. Тому я думаю, що це gettype()має бути першою відповіддю. Поясніть: Отже, якщо у нас є, $test = [1,w2,3.45,sasd];ми почнемо тестувати

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";
        }
}

І вихід:

> This var is int 
> This var is string 
> This var is double 
> This var is string

Я думаю, що це найпростіший спосіб перевірити, чи є наш var int, string, double або Boolean.



0

Ціле число, що починається з 0, спричинить фатальну помилку станом на PHP 7, оскільки воно може інтерпретувати його як вісімковий символ.

Недійсні восьмеричні літерали

Раніше вісімкові літерали, що містили невірні числа, мовчки скорочувались (0128 приймався як 012). Тепер недійсний восьмеричний літерал спричинить помилку синтаксичного аналізу.

Отже, спочатку ви можете видалити провідні нулі з цілого числа:

$var = ltrim($var, 0);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.