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.

Aatch
  • 1,846
  • 10
  • 19
behz4d
  • 1,819
  • 5
  • 35
  • 59

5 Answers5

5

To check if numeric value is requested, use is_numeric.

dev-null-dweller
  • 29,274
  • 3
  • 65
  • 85
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.

berkes
  • 26,996
  • 27
  • 115
  • 206
  • I use mysql_real_escape_string($id), is that enough for preventing SQL Injections here? – behz4d Dec 08 '12 at 12:43
  • It [probably is](http://stackoverflow.com/questions/1220182/does-mysql-real-escape-string-fully-protect-against-sql-injection?rq=1) – berkes Dec 08 '12 at 13:30
  • 1
    `is_int` checks type of variable and `$_GET` contains only strings, so it will always return false. – dev-null-dweller Dec 09 '12 at 09:53
  • @dev-null-dweller: thank you for pointing out my flaw. I rewrote my answer a little and added explanation about your point. – berkes Dec 10 '12 at 09:41
  • 1
    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. – Marc Dingena Jan 14 '14 at 14:56
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.

Andrea Casaccia
  • 4,802
  • 4
  • 29
  • 54
  • '===' 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' – behz4d Dec 08 '12 at 11:18
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.

Aatch
  • 1,846
  • 10
  • 19
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.

Peter Kiss
  • 9,309
  • 2
  • 23
  • 38
  • exactly, that's true, but why would it's value be the same as the string!? what is the solution to the problem above? – behz4d Dec 08 '12 at 11:13
  • Becouse of the type juggling PHP will convert the string to match the type with the intval-ed variant. – Peter Kiss Dec 08 '12 at 11:14
  • 1
    This doesn't actually answer the question. – Aatch Dec 08 '12 at 11:16
  • 2
    How the PHP will evaluate your if statement: http://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) { /* ... */ } – Peter Kiss Dec 08 '12 at 11:22