I was asked to take a look at several free and opensource software web-projects which are capable for so called “ISP configuration management”, managing web-, mail-, database-servers, etc. – handling clients, resellers and admins and having specialized frontends for them…
Anyway… I trigerred a weird bug in one of the projects where I got into an if-condition where I shouldn’t get into… which not just caused a weird behaviour of the application but was also a big security hole in this special case.
The code was something like that (simplified and not tested):
get_sql($value) {
if ($ret = mysql_query ("SELECT * FROM `table` WHERE foo='%s'"),
mysql_real_escape_string($value))
{
return $ret;
}
else
{
return false;
}
}
<br />
$result = get_sql($foo);
if (count($result) > 0) {
// privileged area...
}
Ugly code – anyway… how it was expected to behave by the author?
1) function
get_sql()
gets executed and therefore a sql-query2)
get_sql()
returns an array of results3) the number of results is checked via
count($result)
and when the result-array is greater than 0
jump into the if-block
Okay, so far so good…
However – I finally found out the SQL-query in get_sql()
fails because of a typo.
No error was thrown in the above code – so what’s happening?
1) function get_sql()
gets executed and therefore a sql-query
2) get_sql()
returns the boolean false
, because the sql-query failed
3) count($result)
, evaluated count(false)
is called
As the software just did behave different and didn’t throw an error an intermediate result is:
count()
applied on a boolean is valid !
So what’s count(false)
going to return?
1! – the integer one!
count(false)
is 1 and in PHP therefore true!
Proof:
$ php
<? echo count(false); ?>
1
$
Even better: this behaviour is kind of “documented” within an example at http://php.net/manual/en/function.count.php without any comment.
Okay, now guess:
What’s count(true)
returning? And this is not documented!
1! – the integer one!
PHP – dine in hell…
2 replies on “PHP – fooled me once again…”
Ja!! Das ist, was ich an PHP so liebe. Man _DARF_ sich schlicht weg auf gar nichts verlassen und muss alles nachlesen, weil alles anders ist als in anderen Programmiersprachen/-umgebungen … was sich aber auch wieder in der nächsten PHP-Version ändern kann. 😉
It seems to me that it is quite a basic error to perform a check on $result that is inconsistent for some of the possible values of $result. If $result gets its value from a get_sql(), the test on it should be made robust towards any conceivable output of get_sql().
OTOH, count(bool) returning 1 for both False and True is as (little) surprising as having it return 1 for a one-element list, regardless of the value of the element.