PHP 7 strpos bug [duplicate] - php

This question already has answers here:
php 5 strpos() difference between returning 0 and false?
(5 answers)
Closed 1 year ago.
When using strpos() to find the following, there seems to be a bug.
$url = 'https://www.example.com';
if (strpos($url,'https')>0) the result is NOT found
if (strpos($url,'https',0)>0) the result is NOT found
if (strpos($url,'ttps')>0) the result is FOUND
Why is this happening?
Even though I indicate the starting position of 0, it is not finding it.
Is this a bug or is there something subtle I am missing?
Thanks

Per the manual: https://www.php.net/manual/en/function.strpos.php
Returns the position of [...] the needle [...] note that string positions start at 0, and not 1.
Returns false if the needle was not found
Warning:
This function may return Boolean false, but may also return a non-Boolean value which evaluates to false. Please read the section on Booleans for more information. Use the === operator for testing the return value of this function.
You need to check for strpos === false. Otherwise PHP implicitly converts the 0 to false.

The return value 0 means that the substring was found at position 0 in the searched string.
So, the check for > 0 is wrong.
Documentation says:
Returns the position of where the needle exists relative to the
beginning of the haystack string (independent of offset). Also note
that string positions start at 0, and not 1.
Returns false if the needle was not found. Warning
This function may return Boolean false, but may also return a
non-Boolean value which evaluates to false. Please read the section on
Booleans for more information. Use the === operator for testing the
return value of this function.
https://www.php.net/manual/en/function.strpos.php

Related

PHP's preg_match() acts weirdly

I found this, when I'm working in regex validation in PHP.
I've used preg_match function to validate a string.
I've just printed that value returned by preg_match to ensure working flow.
During that I've found a thing. But can't understand their concept.
That was preg_match() returns 1 if the match found. Otherwise, it will return 0. But sometimes my print function didn't print anything.
After I went through the PHP manual to know all of its return value...
There they posted as follows...
preg_match() returns 1 if the pattern matches given subject, 0 if it does not, or FALSE if an error occurred.
And then I used var_dump to know anything is printed or not...
This helped me to know that's a Boolean false.
But I'm curious to know why it returns boolean false, when I'm just putting " ! " (not) before the preg_match()?
Following is my code,
echo preg_match("/script/", "script") // ===> this returns 1
echo !preg_match("/script/", "script") // ===> this returns Boolean false
I think it has to return integer 0 (zero)... What is its functionality? Or did I do anything wrong in syntax?
I've tried this in the OpenCart 2.0.0.0 system administrator controller module.
The ! operator will always return a Boolean value.
For a unary ! operator the type of the result is bool. The value of the operand is converted to type bool and if it is TRUE then the of the operator result is FALSE, and the result is TRUE otherwise.
Language specification reference: Expressions
The normal conversion rules to a bool are applied to the value.
You're not echoing preg_match's return value when you put a ! in front of the function. You're using PHP's operator to determine if it loosely evaluates to true or false.
!preg_match("/script/","script") is the same as preg_match("/script/","script") == false. Note the == and not the ===. 0, null, empty string, and Boolean false will evaluate loosely to false.

in_array returns true if needle is 0 [duplicate]

This question already has answers here:
PHP in_array() / array_search() odd behaviour
(2 answers)
Closed 6 years ago.
I have an issue with in_array function. Test below returns true:
in_array(0, array('card', 'cash'))
How is it impossible, how can I prevent it ?
However
in_array(null, array('card', 'cash'))
returns false.
Casting any string that doesn't start with a digit to a number results in 0 in PHP. And this is exactly what happens when comparing 0 with some string. See the PHP docs for details about how comparisons between various types are done.
Use the third argument (set it to true) of in_array to avoid loose type comparison.
in_array(0, array('card', 'cash'), true) === false
when you compare in in_array
string is converted to int while comparing incompatible data types
it means cashor card is converted to 0
This is all because of type casting
You have 2 options
1 . Type casting
in_array(string(0), array('card', 'cash'))) === false;
2 .Use third parameter on in_array to true which will match the datatypes
in_array(0, array('card', 'cash'), true) === false;
see documentation
You can prevent it by using the 'strict' parameter:
var_export(in_array(0, array('card', 'cash'), true));
var_export(in_array(null, array('card', 'cash'), true));
returns false in both cases.
From the docs to in_array()
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.
An answer can be casting 0 to string, so:
in_array((string) 0, array('card', 'cash'))
Keep in mind that 0 can be some variable, so casting can be helpful.

Is There A Difference Between strlen()==0 and empty()?

I was looking at some form validation code someone else had written and I saw this:
strlen() == 0
When testing to see if a form variable is empty I use the empty() function. Is one way better than the other? Are they functionally equivalent?
There are a couple cases where they will have different behaviour:
empty('0'); // returns true,
strlen('0'); // returns 1.
empty(array()); // returns true,
strlen(array()); // returns null with a Warning in PHP>=5.3 OR 5 with a Notice in PHP<5.3.
empty(0); // returns true,
strlen(0); // returns 1.
strlen is to get the number of characters in a string while empty is used to test if a variable is empty
Meaning of empty:
empty("") //is empty for string
empty(0) // is empty for numeric types
empty(null) //is empty
empty(false) //is empty for boolean
The following things are considered to be empty:
"" (an empty string)
0 (0 as an integer)
0.0 (0 as a float)
"0" (0 as a string)
NULL
FALSE
array() (an empty array)
var $var; (a variable declared, but without a value in a class)
strlen() simply check if the the string len is 0. It does not check for int, float etc. What is your situation.
reference
empty() will return true if $x = "0". So there is a difference.
http://docs.php.net/manual/en/types.comparisons.php
$f = 0; echo empty($f)? 'Empty':'Full'; // empty
$f = 0; echo strlen($f); // 1
For forms I use isset. It's more explicit. ;-)
empty is the opposite of boolean false.
empty is a language construct.
strlen is a function.
strlen returns the length of bytes of a string.
strlen($str)==0 is a comparison of the byte-length being 0 (loose comparison).
That comparison will result to true in case the string is empty - as would the expression of empty($str) do in case of an empty (zero-length) string, too.
However for everything else:
empty is the opposite of boolean false.
strlen returns the length of bytes of a string.
They don't share much with each other.
The strlen way is almost perfect if you want to check if something is "empty as string", that is, when a single zero should NOT be counted as nothing but empty strings, empty arrays, null and false should all be considered no value. This is quite frequently needed.
So my recommendation would be:
count($x)*strlen("$x")
This gives you:
0 for false
0 for null
0 for "" (empty string)
0 for [ ] (empty array), no warning
1 for a numeric zero
1 for "0" (a string zero)
Surely you can do empty($x) && "$x"!=="0" - it's more to the point but a little noisier, and surprisingly their time cost is nearly equal (under 50ms for a million iterations) so no reason to choose one over the other. Also, if you add !! (boolean cast) before strlen, you'll get a clear 0/1 answer for the question and sometimes it can be more convenient than true/false (debugging situations, switch, etc).
Also note that objects can't be checked like this. If there's a chance that an object comes along, go for the empty()-method. Objects are stubborn creatures.
empty() is for all variables types. strlen(), I think, is better to use with strings or something that can be safely casted to strings. For examle,
strlen(array());
will throw PHP Warning: strlen() expects parameter 1 to be string, array given error
when the input is 0,
strlen(0) = 1
empty(0) = false <-- non-empty

strpos issue with 0==false?

I'm using strpos to find the position of a string in another string. I first check if the string is found at all in there. Here's my line:
if (strpos($grafik['data'],$ss1)<>false && strpos($grafik['data'],$ss2)<>false && strpos($grafik['data'],$ss1) < strpos($grafik['data'],$ss2))
I check if both strings are contained and then I want the first one to be placed before the second one. In the php manual it says that strpos returns false when string is not found. However if my string starts at the zero position (strpos returns 0 since its the beginning), it seems like this statement
strpos($grafik['data'],$ss1)<>false
is false. Somehow 0==false ? How do I make the statement true when strpos returns 0 ?
From http://www.php.net/manual/en/function.strpos.php:
Warning
This function may return Boolean
FALSE, but may also return a
non-Boolean value which evaluates to
FALSE, such as 0 or "". Please read
the section on Booleans for more
information. Use the === operator for
testing the return value of this
function.
You have to use the === operator instead of ==.
In your case, instead of using <>, use !==:
strpos($grafik['data'], $ss1) !== false
This will return TRUE if $ss1 is found in $grafik['data']
You need to check with ===. This will make sure you have exact false and not 0.
This function behaves unpredictably, so to be sure it'll have deterministic behavior use either
if(strpos($text,$string)===false)
or test it using a variable
$pos=strpos($text,$string);
if($pos===false)

Find text in string in PHP

This should be pretty straightforward, but I can't seem to find an explanation anywhere on how to do it.
I have a string in PHP. That string might contain within it somewhere the substring ":ERROR:". I need to find if it has that string. strpos() has worked perfectly up to this point, until today when ":ERROR:" was the first item in the string, so strpos() returned 0, so the program kept running thinking it had no error.
I don't need to replace the string, or do any manipulation to it, I just need a simple true/false answer to "does :ERROR: exist in the string?"
strpos returns false when the string is not found, so check for false instead of making an implicit condition.
if(strpos($string, ':ERROR:') !== false) {
// Do something...
}
As Anurag said in the comments, with functions like these it's always best to do a strict comparison (=== instead of just leaving out the operator or using ==) because that's a common source of bugs, especially in PHP, where many functions can return values of different types.
The PHP Manual on strpos():
This function may return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE, such as 0 or "". Please read the section on Booleans for more information. Use the === operator for testing the return value of this function.
if (strpos($myString, ":ERROR:") !== FALSE) {
// Error!
}
You can also avoid the strpos() problems of not checking with a strict type operator by using the lesser known strstr()
if(strpos($string, ':ERROR:') !== false){
//found ':ERROR:' in string
}
"[strpos()] [r]eturns the position as an integer. If needle is not found, strpos() will return boolean FALSE."
http://php.net/manual/en/function.strpos.php
If the position is 0, then merely using == or != will evaluate 0 and false as equivalent. So use === or !== to avoid type coercion.

Categories