Page 1 of 3

flaw in php ?

Posted: Tue Mar 10, 2009 8:35 am
by php_east

Code: Select all

 
    function handle_event($function,$event='')
    {
 
    switch ($function)
    {
        case 'execute'  : 
        {
            switch ($event)
            {
            case        'abort' : 
            $response   = ('abort');
            break;
 
            default         : 
            $response   = ('default');
            break;
            } // end switch (event)
        break;
        }
 
        default     : break;
 
    } // end switch (function)
} // end function
 
this is part of the codes of a certain function i am writing. the problem is, when $event coming from elsewhere is zero, default does not take over. nothing happens.

i have solved this by typecasting, but i feel very much this is a php bug. what do you think ?

Re: flaw in php ?

Posted: Tue Mar 10, 2009 8:53 am
by Mark Baker
php_east wrote:this is part of the codes of a certain function i am writing. the problem is, when $event coming from elsewhere is zero, default does not take over. nothing happens.

i have solved this by typecasting, but i feel very much this is a php bug. what do you think ?
It would be a bug if it was unexpected behaviour, but PHP's behaviour when comparing string values with numeric values is very well documented, and the manual explicitly states that the comparison used in switch/case statements is "loose" (ie. not typed)

It doesn't work the way you'd like it to work, but that doesn't qualify it as a bug

Re: flaw in php ?

Posted: Tue Mar 10, 2009 9:13 am
by php_east
alright, thanks.

Re: flaw in php ?

Posted: Tue Mar 10, 2009 9:23 am
by php_east
ah, but wait a minute, isn't default supposed to cater for all other cases except the one that matched ?
meaning that if $event is not a string 'abort' , regardless of what type $event is, it should still revert to the default ?
i read it as ( if event = string abort else do default ) in psuedo language.

Re: flaw in php ?

Posted: Tue Mar 10, 2009 1:26 pm
by Mark Baker
php_east wrote:i read it as ( if event = string abort else do default ) in psuedo language.
Nope:
using true if tests
if ($event == "abort")
is not the same as
if ($event === "abort")
so
PHP casts the string to a numeric (giving 0), not the numeric to a string

Re: flaw in php ?

Posted: Tue Mar 10, 2009 6:21 pm
by php_east
i found the rationale, the reasoning. maybe others might want to take note.

interestingly , if an integer is fed into the switch codes i.e. $event=0, the switch function
evaluates to true ( it evaluates to int 0 which is true and because of the 'loose' type comparison of the switches as mentioned in ealier post ). thus it enters the cases.

it then peforms the case comparison, but could not find a $event = 0 instance ( i.e. case 0: ).
so it then does nothing. the default is not executed, and there is no true case so there is effectively no statement to execute.

this i found out by breaking up the switch into individual if's and re-evaluating its behavior. the results are laid out below.

if this is what is said to be documented and intended behavior, so be it.
but certainly to me, such behaviour is wrong. upon not finding a match, the default must be executed. programs must do this, because we rely on defaults, regardless of input.

at the very least, a warning produced to indicate an input type mismatch. this will allows us to handle uncertain inputs. of course it is easily solved by type casting as i mentioned, but just having to do that means lesser flexibility of the switches, and take more energy form the coder to focus on langauge, instead of the intended functionality.

Code: Select all

$event  = 0;
echo test($event);
 
$event  = (string) 0;
echo test($event);
 
$event  = 'abort';
echo test($event);
 
 
 
function test($event)
{
echo '<hr />';
echo '$event = '; var_dump($event);
echo '<hr />';
echo '$event is of type '.gettype($event);
echo '<br />';
 
echo 'comparison is $event==\'abort\'         : result => ';
if ($event=='abort') echo gettype($event).' is equal to '.$event; else echo gettype($event).' is NOT equal to (DEFAULT) '.$event;
echo '<br />';
 
 
echo 'comparison is $event===\'abort\'         : result => ';
if ($event==='abort') echo gettype($event).' is identical to '.$event; else echo gettype($event).' is NOT identical to (DEFAULT) '.$event;
echo '<br />EOT<br />';
}
 
 
die();
 
Results

Code: Select all

 
$event = int(0) $event is of type integer
comparison is $event=='abort' : result => integer is equal to 0
comparison is $event==='abort' : result => integer is NOT identical to (DEFAULT) 0
EOT
$event = string(1) "0" $event is of type string
comparison is $event=='abort' : result => string is NOT equal to (DEFAULT) 0
comparison is $event==='abort' : result => string is NOT identical to (DEFAULT) 0
EOT
$event = string(5) "abort" $event is of type string
comparison is $event=='abort' : result => string is equal to abort
comparison is $event==='abort' : result => string is identical to abort
EOT

Re: flaw in php ?

Posted: Tue Mar 10, 2009 6:30 pm
by php_east
additionally, if you feed int -1 into it, it evaluates to false and the DEFAULT will be executed.

thus, what we have is a grey area, where when the switch is entered, nothing comes out.
i call this a dead switch. a nightmare for coding/decoding/debugging critical functions.

in conclusion, i would agree it is not a bug if the intended behavior is as such. but it is something one need to watch out for very carefully. to enter into a function without getting any output leaves much room for headaches.

Re: flaw in php ?

Posted: Tue Mar 10, 2009 6:40 pm
by Benjamin
php_east wrote: but certainly to me, such behaviour is wrong. upon not finding a match, the default must be executed.
I agree, this is ridiculous:

Code: Select all

function test($test) {
    echo sprintf("received \$test as value %s which ", $test);
    switch($test) {
        case 'foo':
            echo "matches foo<br />";
            break;
        default:
            echo "matches default<br />";
            break;
    }
    echo "<br />";
}
 
 
test(0);
test(false);
test(1);
test(true);
test('bar');
test('string');
received $test as value 0 which matches foo

received $test as value which matches default

received $test as value 1 which matches default

received $test as value 1 which matches foo

received $test as value bar which matches default

received $test as value string which matches default
0 is not a string, it is not true, and it doesn't match foo. WTH?

Re: flaw in php ?

Posted: Tue Mar 10, 2009 7:04 pm
by kaisellgren
@astions: I use this behavior often to exploit serialization vulnerabilities. Since strings match 0, I often use 0 to bypass checks.

Re: flaw in php ?

Posted: Tue Mar 10, 2009 7:08 pm
by Benjamin
kaisellgren wrote:@astions: I use this behavior often to exploit serialization vulnerabilities. Since strings match 0, I often use 0 to bypass checks.
That's funny. I can't imagine how many unknown bugs are in PHP applications because of this. And not only that, but it's a security issue as well. Nice...

Re: flaw in php ?

Posted: Tue Mar 10, 2009 7:37 pm
by josh
How do you get an int in user input?

Re: flaw in php ?

Posted: Tue Mar 10, 2009 7:41 pm
by semlar
I have never used a switch statement in my life. What does it offer over using if/else?

Re: flaw in php ?

Posted: Tue Mar 10, 2009 7:45 pm
by kaisellgren
josh wrote:How do you get an int in user input?
There are a couple of ways. Most popular way would be to serialize zero and during unserializing it becomes out as an integer. This applies to many scenarios, e.g. one that my friend just had a few days ago - JSON encoding and decoding. These kind of security issues are unfortunately pretty unknown to some developers.

Re: flaw in php ?

Posted: Tue Mar 10, 2009 9:31 pm
by requinix
You think the most popular way to convert a string into a number is with serialization?

Who, exactly, have you been talking to?

intval
See also: type-casting, loosely-defined types, and Google.

Re: flaw in php ?

Posted: Tue Mar 10, 2009 9:33 pm
by Benjamin
Keep it friendly and respectful folks.

intval won't do much good on the client side BTW. Neither will type-casting, loosely-defined types or Google.