1

I'm encountering something weird and I don't know why it is happening!

I have a URL like:

http://mysite.com/users/USER_ID

this user id could be INT and could be STRING, it's something like Facebook page addresses, if you call the page with page ID it loads it, also you could call it with page name like "my_page_name"

So imagine a user which it's ID is 1 and it's address is my_name On my php page I need query db, but before that I need to know which column to look, id or page_name

So I came with this solution:

<?php $id = $_GET['id']; $id_inted = intval($_GET['id']); if($id == $id_inted){ // The column which I should look into is id $column = 'id'; }else{ // The column which I should look into is page_name $column = 'page_name'; } $query = mysql_qyery(SELECT * FROM members WHERE $column = '$id'); ?> 

So I tested it, but the results is weird, even if I call this URL:

http://mysite.com/users/page_name

This happens: $column = 'id';

I opened a new test page:

<?php $real_string = 'abcdefg'; $string_inted = intval($real_string); echo "Real String is: " . $real_string . "<br />"; echo "The same string as int is: " . $string_inted . "<br />"; if($real_string == $string_inted) echo "Weird!"; else echo "Fine..."; ?> 

and the results:

Real String is: abcdefg The same string as int is: 0 Weird! 

Why this is happening?

Thanks in advance.

4
  • 1
    congratulations on managing to consistently misspell weird as wired... Commented Dec 8, 2012 at 11:09
  • @Aatch congratulations on getting to the point of the question! :-D Commented Dec 8, 2012 at 11:11
  • 2
    I did answer the question as well. I was just amazed that you managed to write 'wired' instead of 'weird' 4 times. Commented Dec 8, 2012 at 11:18
  • @Aatch I always misspell this word, I need more exercise on English thought, thanks for the answer. Commented Dec 8, 2012 at 11:20

5 Answers 5

5

PHP is really "wired" with so called type-juggling. It is the most error-prone part of most PHP-scripts. As such, you should always stay on the safe side and use the most robust check. For example intval("twelve") will return 0, which is a valid integer. But also considered "false": print if (intval("one")) ? "yup" : "nope" will print "nope".

In this case, using intval, in combination with a check if the integer is larger then zero, should do the trick:

<?php $id = intval($_GET['id']); if($id > 0){ // The column which I should look into is id $column = 'id'; }else{ // The column which I should look into is page_name $column = 'page_name'; } $query = mysql_qyery(SELECT * FROM members WHERE $column = '$id'); ?> 

Or, shorter:

$id = intval($_GET['id']); $column = ($id > 0) ? "id" : "page_name"; $query = mysql_qyery(SELECT * FROM members WHERE $column = '$id'); 

Aso note that $_GET["id"] might not be set, which would throw a notice in your code.

And last, but certainly not least: the SQL-injection: ?id=LittleBobby';Drop table users.

edit As commentor points out, there was a logical flaw in my code, stemming form the fact I tested it in phpsh only. I refactored it from using is_int() to intval and > 0. In a web-environment, $_GET["id"] is always a string; no matter what. Hence is_int() will always return FALSE.

Sign up to request clarification or add additional context in comments.

5 Comments

I use mysql_real_escape_string($id), is that enough for preventing SQL Injections here?
is_int checks type of variable and $_GET contains only strings, so it will always return false.
@dev-null-dweller: thank you for pointing out my flaw. I rewrote my answer a little and added explanation about your point.
You're using $id in your SQL statement, but since you intval it at the beginning of your script, it will no longer contain a string in the event $column is determined to be 'page_name'. Also, it's mysql_query. Not trying to be pedantic, but since it should serve as a working example, I think you should fix it.
5

To check if numeric value is requested, use is_numeric.

Comments

2

PHP is a little odd when it comes to types.

Basically, what you are doing is parsing the string into a number (so 'abcdef' returns 0 because it isn't a number at all), then comparing the original string to the number.

Now, I can see why you would assume that it should be false, but PHP tries to be clever. Basically, == will coerce types, and almost always coerces to numbers if one of it's values is a number. So it is using the same conversion that you did on the string, then comparing.

It is a better idea to use === which also checks types.

Comments

2

From http://php.net/manual/en/language.operators.comparison.php

Example Name Result $a == $b Equal TRUE if $a is equal to $b after type juggling. $a === $b Identical TRUE if $a is equal to $b, and they are of the same type. 

Your string is casted to integer because of type juggling on == operator and intval() of a string returns 0

This explains why $id == $id_inted in your code evaluates to true.

If you make your test with === instead of == no type juggling will be performed.

1 Comment

'===' solved the problem, thanks, but still I don't get the logic that my code echos "Weird!", so my string will be 0 after inted, but why the if() statement goes to the first echo? even with your answer, 0 != 'abcdefg'
1

The integer value of var on success, or 0 on failure. Empty arrays return 0, non-empty arrays return 1. (From php.net intval().)

intval('abcdefg') will trigger an error and the function return with 0.

4 Comments

exactly, that's true, but why would it's value be the same as the string!? what is the solution to the problem above?
Becouse of the type juggling PHP will convert the string to match the type with the intval-ed variant.
This doesn't actually answer the question.
How the PHP will evaluate your if statement: php.net/manual/en/language.operators.comparison.php --> string, resource or number string, resource or number Translate strings and resources to numbers, usual math ## So the PHP will evaluate something like this: if (intval($real_string) == $string_inted) { /* ... */ }

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.