0

I've noticed a strange thing about PHP's in_array function. For some reason, it will only check if the first character(s) of the needle match with any of the values of the haystack - as opposed to if the whole needle is in the haystack.

For example, in a situation where $string equals 1thisisatest, the following script will return In array.

$allowed = [0, 1];
if(in_array($string, $allowed)){
    echo "In array";
} else {
    echo "Not in array";
}

Whereas if $string equals 2thisatest, the script will return Not in array.

Now either this is a bug, or a very strange feature. Wouldn't you want it to check needles against the haystack exactly as they appear?

If this is, indeed, how the function is supposed to work, how does one go about getting the intended result without iterating over every single element in the array? Seems kind of pointless.

EDIT:

Some of you are saying to use strict mode. This is all fine and dandy, until you checking against $_GET data, which is always a string. So the following will return false:

$value = $_GET["value"]; // this returns "1"
in_array($value, [0, 1], true)
GROVER.
  • 4,071
  • 2
  • 19
  • 66
  • Use the `strict` parameter to check. From the [manual](https://www.php.net/manual/en/function.in-array.php): "_If the third parameter strict is set to TRUE then the in_array() function will also check the types of the needle in the haystack._" – brombeer Nov 05 '19 at 17:09
  • @kerbholz does that not just enforce type checking? :o – GROVER. Nov 05 '19 at 17:10
  • Probably due to [Comparing String to Integer gives strange results](https://stackoverflow.com/questions/672040/comparing-string-to-integer-gives-strange-results) – Nigel Ren Nov 05 '19 at 17:11
  • Make the array an array of strings rather than numbers. – Barmar Nov 05 '19 at 17:35
  • @Barmar I like your style – GROVER. Nov 05 '19 at 17:35

4 Answers4

3

Because the in_array function uses the == operator. Thus 1 == "1thisisatest" - so, in_array will return true.

To fix this you can enabled strict mode:

// in the third parameter (to use === instead of ==)
in_array($search_value, $array_name, true)`
GROVER.
  • 4,071
  • 2
  • 19
  • 66
Ali Khalili
  • 1,504
  • 3
  • 18
  • 19
1

in_array by default uses == which will follow the rules of type juggling

The solution is to use strict comparison:

in_array($value, [0, 1], true);

If you are concerned about $_GET variables you need to ensure you always validate and sanitize your input before using it otherwise you might end up with strange results:

$value = filter_input(INPUT_GET, 'value', FILTER_VALIDATE_INT);
in_array($value, [0, 1], true);

It is always good to validate and sanitize your input to avoid things like e.g. someone calling your URL as ?value[]=1 which will mean $_GET['value'] will be an array causing (most likely) errors in the best case and strange undocumented behaviour in the worst case.

apokryfos
  • 38,771
  • 9
  • 70
  • 114
1

Make $allowed an array of strings and use strict mode.

$allowed = ["0", "1"];
if (in_array($_GET['value'], $allowed, true)) {
    echo "In array";
} else {
    echo "Not in array";
}
Barmar
  • 741,623
  • 53
  • 500
  • 612
1

If you need to be more accurate you have to put the boolean true in your function like this:

$string = "1thisisatest";
$allowed = array(0, 1);
if(in_array($string, $allowed, true)){
    echo "In array";
} else {
    echo "Not in array";
}
GROVER.
  • 4,071
  • 2
  • 19
  • 66