php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #25566 Casting of strings to integers is flawed, no checking for non numeric chars.
Submitted: 2003-09-16 18:41 UTC Modified: 2003-09-21 11:59 UTC
Votes:2
Avg. Score:5.0 ± 0.0
Reproduced:2 of 2 (100.0%)
Same Version:1 (50.0%)
Same OS:1 (50.0%)
From: Jared dot Williams1 at ntlworld dot com Assigned:
Status: Not a bug Package: Scripting Engine problem
PHP Version: 4.3.3 OS:
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: Jared dot Williams1 at ntlworld dot com
New email:
PHP Version: OS:

 

 [2003-09-16 18:41 UTC] Jared dot Williams1 at ntlworld dot com
Description:
------------
Switched expressions seem to be cast to a type before case matching occurs.

If all case expressions are of the same type, either numeric, or string, this problem does not arise.

It is not clear why, or really what type the switched expression is cast to before comparision.





Reproduce code:
---------------
$t = array(0,1,2,3,'*','+','a', 'b')
foreach($t as $v)
	switch ($v)
	{
		case 0: echo('0'); break;
		case 1: echo('1'); break;
		case 2: echo('2'); break;
		case 3: echo('3'); break;
		case '*': echo('*'); break;
		default: echo($v); break;
	}

Expected result:
----------------
0123*+ab


The first 5 array elements are output their respective case statements, and the latter 3 are handled by the default case.

Actual result:
--------------
01230000 

The first 5 array elements are output their respective case statements, and the latter 3 are handled the 0 case.


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2003-09-16 18:47 UTC] Jared dot Williams1 at ntlworld dot com
"The first 5 array" should read "The first 4 array"
 [2003-09-20 00:40 UTC] shadowfaxx at cc dot com
To add to the above, it seems that the '0' case is the culprit. If you use the code below where '10' replaces '0', the weird behavior does not occur:

$t = array(10,1,2,3,'*','+','a', 'b');
foreach($t as $v)
	switch ($v)
	{
		case 10: echo('0'); break;
		case 1: echo('1'); break;
		case 2: echo('2'); break;
		case 3: echo('3'); break;
		case '*': echo('*'); break;
		default: echo($v); break;
	}
OutPut: 0123*+ab


So it seems that Case 0: grabs all the cases which are of a different data type if the case expressions are not of the same type i.e. numeric and string.
 [2003-09-20 05:51 UTC] Jared dot Williams1 at ntlworld dot com
The non-numeric string values are getting cast to integer value 0, which then match case 0:.

$t = array(10,1,2,3,'*','+','3a', 'b');
foreach($t as $v)
	switch ($v)
	{
		case 10: echo('0'); break;
		case 1: echo('1'); break;
		case 2: echo('2'); break;
		case 3: echo('3'); break;
		case '*': echo('*'); break;
		default: echo($v); break;
	}
Outputs:
0123*+3b

as 3a gets cast to 3. so seems there is a missing a condition in the code somewhere, to see if the switched expression can actually be a numeric type.


Also

$t = array(10,1,2,3,'*','+','3a', 'b');
foreach($t as $v)
	switch ($v)
	{
		case 10: echo('0'); break;
		case 1: echo('1'); break;
		case 2: echo('2'); break;
		case '*': echo('*'); break;
		case '3a': echo('!!'); break;
		default: echo($v); break;
	}
?>

Outputs:
012!!*+!!b

So the case labels are getting cast too without the check.
 [2003-09-20 06:08 UTC] Jared dot Williams1 at ntlworld dot com
Oh erm, seems its not limited to switch either. :/

echo('a' == 0 ? 'YES' : 'NO');
Outputs: YES

echo('3a' == 3 ? 'YES' : 'NO');
Outputs: YES

echo(4 == '4a' ? 'YES' : 'NO');
Outputs: YES

Surely these cant be considered equivalent.
 [2003-09-20 06:20 UTC] Jared dot Williams1 at ntlworld dot com
How's this for an impossibility..

echo('a' != 0 ? 'TRUE' : 'FALSE');
echo('<br />');
echo('a' ? 'TRUE' : 'FALSE');

Outputs:
FALSE
TRUE
 [2003-09-20 17:58 UTC] sniper@php.net
See these manual pages:

http://www.php.net/switch
http://www.php.net/manual/en/types.comparisons.php

Maybe the manual should explain this a bit better.

 [2003-09-20 19:29 UTC] Jared dot Williams1 at ntlworld dot com
The documentation does not help.

a string containing a beginning with a numeric character, but also containing non-numerics surely should not be cast to an integer before comparision?

I understand that "12345" == 12345 but the string "12345xxx" isnt 12345.
 [2003-09-20 20:17 UTC] rasmus@php.net
That's why you have the === operator.  "12345aaaa" has always evaluated to 12345 when cast to an integer and it always will.  That also means that it must be equivalent to 12345 when used in an integer comparison.  You need to be explicit in your comparisons and use explicit casting elsewhere.
 [2003-09-21 11:51 UTC] Jared dot Williams1 at ntlworld dot com
I do understand that time has fixed this "feature".

As for explicit casting, it does result in different behaviour, when comparing string/values.

$x = '0xF';
$y = (int)$x;
echo($x == 15 ? 'YES' : 'NO');
echo('<br />');
echo($y == 15 ? 'YES' : 'NO');

Outputs:
YES
NO

Strict equivalence testing doesnt help when you wish 
"1234" and 1234 to be considered equal.
 [2003-09-21 11:59 UTC] rasmus@php.net
No, but if you want them to be compared as strings, just cast to a string then, or use a strcmp() call.  PHP can't read your mind.  
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 26 05:01:30 2024 UTC