PHP isset() function misfiring - php

I'm having a problem with PHP's isset function. It's often and mysteriously (to me) misfiring.
For instance, when I have a variable that can be either a string or an error array, I try using isset to see if the variable contains one of the known indexes of the array, like so:
$a = "72";
if(isset($a["ErrorTable"]))
echo "YES";
else
echo "NO";
This bad boy prints YES all the way on my server. I tried it on Ideone (online interpreter thingie. It's cool!) here: http://ideone.com/r6QKhK and it prints out NO.
I'm thinking this has something to do with the PHP version we're using. Can someone shed some light into this?

Consider the following piece of code:
$a = "72";
var_dump( isset($a["ErrorTable"]) );
You're checking if $a["ErrorTable"] is set. PHP first typecasts any non-numeric offset to int and this makes ErrorTable equal to 0.
Essentially, you're just doing:
if ( isset($a[0]) )
Strings in PHP can be accessed an array, and $a[0] is definitely set and the condition will evaluate to TRUE.
However, this weird behavior was fixed in PHP 5.4.0 and the changelog for isset() says:
5.4.0 -- Checking non-numeric offsets of strings now returns FALSE.
Your server is probably using an older version of PHP and that would explain why it outputs YES.
You can use array_key_exists() instead:
$a = "72";
if ( is_array($a) && array_key_exists('ErrorTable', $a) ) {
echo 'YES';
} else {
echo 'NO';
}
The output will be NO on all PHP versions.

I usually use the empty function like:
$a = "72";
if(!empty($a["ErrorTable"]))
echo "YES";
else
echo "NO";

$a[0] is a way of referencing the 1st character in the string, which is the value "7". Because string characters are simply referenced by their numeric value, the "ErrorTable" is typecast to an int (0)
This is the case in PHP 5.2.17 and 5.3.23, but not in 5.4.15 or 5.5.0

Related

Why empty('0') = true; empty('00') = false;

I eval $var using
if(empty($_GET['var'])){
...
}
I take TRUE from
https://myweb.com/?var=0
I take FALSE from
https://myweb.com/?var=00
The empty pseudo-function shares its logic with casting to boolean - if something is equivalent to "false", it is considered "empty".
The list of values which are considered "empty" is intended to be helpful, but is occasionally confusing, because there isn't really one perfect answer. Starting off with integers, it seems reasonable that 0 is "empty", but for instance 1 is not. Because user input almost always comes in the form of strings (particularly on the web, where PHP is most at home), it's also useful for the string "0" to behave the same as the integer 0.
On the face of it, "00" should also be equivalent to 0, and therefore "empty", but now things start getting messy: if you convert the string "hello" to an integer, that is also 0, so is "hello" also empty? That wouldn't be very useful.
The truth is, casts such as this can only really work one of two ways:
Throw an error on any conversion which is not 100% unambiguous.
Pick a set of compromises which is mostly useful, but not entirely consistent.
PHP picked the second route, and the difference between empty("0") and empty("00") is one of the side effects of the particular compromise chosen. Other languages which took a similar route (e.g. Perl, JavaScript) have different compromises, with different surprising outcomes.
See also my answer to a similar question here.
Because 0 gives empty in PHP if you check without type, but I think 00 type-cast to a string value and thus it's not empty.
You can strict check with type via the operator ===
I think it's probably because you are receiving the 00 as string value in your code. Because 0 and 00 are both considered as empty by the empty function in PHP. Try executing the code below in one of your PHP's to understand better. You can even check out the sandbox link.
<?php
$a = 0;
$b = 00;
$c = '00';
if(empty($a)) echo 'empty a';
if(empty($b)) echo 'empty b';
if(empty($c)) echo 'empty c';
?>
Check the documentation of empty() function, there are a list of values that are considered as empty by it.
The empty() function checks whether a variable is empty or not.
This function returns false if the variable exists and is not empty,
otherwise it returns true.
The following values evaluates to empty:
0
0.0
"0"
""
NULL
FALSE
array()
Additionally, when you are dealing with numeric check, you should always typecast the value to integer and then compare if it's 0 or not. This would be the ideal approach.
<?php
$a = 0;
$b = '0';
$c = '00';
$d = 1;
$e = '1';
if(!intval($a)) echo 'empty a ';
if(!intval($b)) echo 'empty b ';
if(!intval($c)) echo 'empty c ';
if(!intval($d)) echo 'empty d ';
if(!intval($e)) echo 'empty e ';
?>

php variables, strings and arrays: associative array returns first letter of string

I understand that, with a sting assigned to a variable, individual characters can be expressed by using the variable as an indexed array, but why does the code below, using an associative array, not just die with missing required? Why does 'isset' not throw FALSE on an array key that definitely doesn't exist?
unset($a);
$a = 'TESTSTRING';
if(!isset($a['anystring'])){
die('MISSING REQUIRED');
}else{
var_dump($a['anystring']);
}
The above example will output:
string(1) "T"
EDIT:
As indicated by Jelle Keiser, this is probably the safer thing to do:
if(!array_key_exists('required',$_POST)){
die('MISSING REQUIRED');
}else{
echo $_POST['required'];
}
What PHP is doing is using your string as a numeric index. In this case, 'anystring' is the equivalent of 0. You can test this by doing
<?php
echo (int)'anystring';
// 0
var_dump('anystring' == 0);
// bool(true)
PHP does a lot of type juggling, which can lead to "interesting" results.
$a is a string not an associative array.
If you want to access it that way you have to do something like this.
$a['anystring'] = 'TESTSTRING';
You need to use array_key_exists() to test if a key exists
The working of isset is correct in your case.
Because $a is a string, the index-operator will give you the specified char in the string at the declared position. (like a "Char-Array")
A small example:
$a = 'TESTSTRING';
echo $a[0]; // Output: T
echo $a[1]; // Output: E
// ...
This will output the first and the second character at index 0 and 1 of the string.
And because the index-operator always expects an integer value on strings. The given value will be automatically casted to an integer. You can see this, when you cast the string to an integer, like this:
echo (int) 'TESTSTRING'; // Output: 0
For char-access on strings, also see the PHP-Manual.
Try enabling PHP to show all errors by using error_reporting(E_ALL);
This should give you a warning saying you are using an illegal offset. PHP therefore automatically assumes you are looking for the first element in the array or letter in this case.
it works as expected for... it returned false... but when I force it to return true ... itz throws an error saying illegal offset somekind.... but still output the first string.... as anystring casted as int equals to 0.. check the version of php you are using bro... I used notepad++ to create the php file... no special ide...

PHP : is it dynamich thing or any thing else

Anyone can explain it why is it true
$a = Array('b' = > 'okokokok');
if ( isset( $a['b']['ok'] ) ) {
echo $a['b']['ok']; // Print 0
} else {
echo "else";
}
This was for backward compatibility with PHP 4 (see PHP Bug #29883). When casting a string to an integer, and the string is not a valid integer, it becomes 0 (zero). The letter "o" is printed because that is the character at offset 0 in the string.
In PHP 5.4, the behavior intentionally changed (see PHP Bug #60362); that PHP version instead prints "else".
First of all, it doesn't print '0', but lowercase 'o'.
Try this:
$string = 'abc';
echo $string['omgwhysuchkeyworks'];
It will print 'a'. That is because it seems in PHP when you try any key (other than numeric) on string variable it will return the first character of the string. That's also why isset($a['b']['ok']) returns true.
And it might be an issue of the PHP version. Perhaps on newer version it will work as intended (it will write 'else')
It prints else. 'ok' is no array index but a value on index 'b' of array $a:
Array
(
[b] => okokokok
)
See http://ideone.com/50EhGW
$a = Array('b' = > 'okokokok');
if ( isset( $a['b']['ok'] ) ) {
echo $a['b']['ok']; // Print 0
} else {
echo "else";
}
When you have a string ,you can treat it as array. its indexes would be numerical, starting from zero to string length minus one. But if you try to pass a string as index (ok in this case) , PHP tries to convert it to integer , evaluates it as zero(intval('ok')). On systems with php 5.4, it treat differently and checks the key itself and doesn't do the converting .So, in one system it may print else and on the other it prints o.

Finding common characters in strings

I am tring this method to find the common characters in two strings namely, $a and $r, but the first character isn't getting printed . Moreover the $already collects the common characters and prevents them from being printed for multiple times( I need each character to be printed once only) but it isn't doing so. Please tell me what errors I am making.
<?php
$a="BNJUBCI CBDIDIBO";
$r="SBKJOJLBOU";
$already="";
for($i=0;$i<strlen($r);$i++)
{
if (stripos($a,$r[$i])!=FALSE)
{
if (stripos($already,$r[$i])==FALSE)
{
$already=$already.$r[$i];
echo "already=".$already."<br>";
echo $r[$i]."<br>";
}
}
}
?>
Use !==FALSE instead of !=FALSE. The problem is that stripos returns 0 if the needle is at the start of the haystack, and 0 is falsy. By using !== you are forcing it to ensure the result is actually false, and not just 0.
This is actually listed in the docs. An "RTM" might be appropriate here.
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.
The simplest way to find the intersection of the two strings in PHP is to turn them into arrays and use the built-in functions for that purpose.
The following will show all the unique and common characters between the two strings.
<?php
$a="BNJUBCI CBDIDIBO";
$r="SBKJOJLBOU";
$a_arr = str_split($a);
$r_arr = str_split($r);
$common = implode(array_unique(array_intersect($a_arr, $r_arr)));
echo "'$common'";
?>
I would think a much simpler solution to this would be to make the strings into arrays and compare those no?
Something like:
<?php
$a="BNJUBCI CBDIDIBO";
$r="SBKJOJLBOU";
$shared = implode( '' , array_intersect( str_split($a) , str_split($r) ) );
?>
That should return you a string of all the characters in $a that are present in $r

Weird PHP String Integer Comparison and Conversion

I was working on some data parsing code while I came across the following.
$line = "100 something is amazingly cool";
$key = 100;
var_dump($line == $key);
Well most of us would expect the dump to produce a false, but to my surprise the dump was a true!
I do understand that in PHP there is type conversion like that:
$x = 5 + "10 is a cool number"; // as documented on PHP manual
var_dump($x); // int(15) as documented.
But why does a comparison like how I mentioned in the first example converts my string to integer instead of converting the integer to string.
I do understand that you can do a === strict-comparison to my example, but I just want to know:
Is there any part of the PHP documentation mentioning on this behaviour?
Can anyone give an explanation why is happening in PHP?
How can programmers prevent such problem?
If I recal correcly PHP 'casts' the two variables to lowest possible type.
They call it type juggling.
try: var_dump("something" == 0);
for example, that'll give you true . . had that bite me once before.
More info: http://php.net/manual/en/language.operators.comparison.php
I know this is already answered and accepted, but I wanted to add something that may help others who find this via search.
I had this same problem when I was comparing a post array vs. keys in a PHP array where in my post array, I had an extra string value.
$_POST["bar"] = array("other");
$foo = array(array("name"=>"foobar"));
foreach($foo as $key=>$data){
$foo[$key]["bar"]="0";
foreach($_POST["bar"] as $bar){
if($bar==$key){
$foo[$key]["bar"]="1";
}
}
}
From this you would think that at the end $foo[0]["bar"] would be equal to "0" but what was happening is that when $key = int 0 was loosely compared against $bar = string "other" the result was true to fix this, I strictly compared, but then needed to convert the $key = int 0 into a $key = string "0" for when the POST array was defined as array("other","0"); The following worked:
$_POST["bar"] = array("other");
$foo = array(array("name"=>"foobar"));
foreach($foo as $key=>$data){
$foo[$key]["bar"]="0";
foreach($_POST["bar"] as $bar){
if($bar==="$key"){
$foo[$key]["bar"]="1";
}
}
}
The result was $foo[0]["bar"]="1" if "0" was in the POST bar array and $foo[0]["bar"]="0" if "0" was not in the POST bar array.
Remember that when comparing variables that your variables may not being compared as you think due to PHP's loose variable typing.

Categories