The following codeigniter function takes a (string) parameter and returns the (integer) ID of the row. It works fine if i pass string values, but if integer 0 is passed, it returns ID of first row in database. In principle, it should return the user_id
only if the the user_name
exists in the database. Since there is no user_name called 0, it should return false.
Can someone tell why it is behaving like this and how it can be fixed?
Thanks.
public function get_user_id($user_name)
{
$this -> db -> select('user_id');
$this -> db -&g开发者_JS百科t; from('users');
$this -> db -> where('user_name', $user_name);
$this -> db -> limit(1);
$query = $this->db->get();
if ( $query->num_rows > 0 )
{
$row = $query->row();
return $row->user_id;
}
return false;
}
For example:
$user_name = "test"; //works fine, returns id.
$user_name = "0"; //works fine, doesnt return anything
$user_name = 0; //Problem. returns ID of first row.
You should add a test of the kind if ($user_name == "") return false;
to catch this.
Apparently where
with second argument 0 always matches, e.g. translates into SQL WHERE user_name
, rather than WHERE user_name = ""
, and WHERE user_name
is short-hand for WHERE user_name != ""
-- the opposite of what you wanted :-)
Running this test at the beginning saves you a full database query when you're passed an argument that will necessarily result in false
.
you can try to cast $user_name to string before pass it as a param:
$user_name = (string)$user_name;
You can use http://php.net/strval to force the variable to be a string:
$this -> db -> where('user_name', strval($user_name));
You can also try:
$this -> db -> where('user_name', "$user_name");
It's likely to be a type issue, and how the codeigniter or perhaps SQL is dealing with the integer.
Since you know username is going to be a string, cast everything to a string. I believe the following should fix any problems here;
$this -> db -> where('user_name', (string) $user_name);
If you expect objects may also be passed to this object, you'd best do a conditional:
if(is_object($user_name)) {
$user_name = $user_name->__toString();
} else {
$user_name = (string) $user_name;
}
Put that, of course, at the start of the function, before you select the database.
This has bugged me a few times, but so you know, some info from MySQL Documentation.
"this is known and documented feature of MySQL. When you compare numbers to strings, they are compared as float numbers. Any string that does NOT start with a digit is implicitly converted to number 0. Hence the results you get. Please, always compare numbers to numbers and strings to strings if you want to prevent undesired results."
Read http://dev.mysql.com/doc/refman/5.0/en/type-conversion.html for the details.
So, casting is the concrete way of ensuring proper comparison in the query... or from MySQL again... there is no real fix other than to make sure string literals are quoted.
精彩评论