22

假设用户输入

mysite.com/profile?identity=1
mysite.com/profile?identity=dinodsja
mysite.com/profile?identity=1a

获得价值

$identity = $_GET['identity']; // identity can be user_id or user_name

我有一个简单的选择查询:

SELECT * FROM lb_users WHERE (user_id = 'dinodsja' OR user_name = 'dinodsja') AND user_status = 1

它工作正常。但问题是:

SELECT * FROM lb_users WHERE (user_id = '1a' OR user_name = '1a') AND user_status = 1

当我执行此查询时,它还会返回结果而不满足条件

表结构:

user_id     bigint(25)
user_name   varchar(50)     utf8_general_ci

在此处输入图像描述

**

-> Is this a MySQL Bug ? 
-> How can we avoid this ? 
-> What will be the query ?

**

4

6 回答 6

32

原因是该列的数据类型user_ID是整数。

MySQL 默默地删除值中任何尾随 的非数字以及后面的任何内容),这就是为什么1a等于1因为a将在值中删除。

于 2013-03-30T06:35:18.397 回答
24

我记得很久以前有过类似的问题。

首先是一些背景:这不是一个错误。它实际上是一个功能。好的,这可能会导致这种意外行为,但 MySQL 因此非常容忍用户输入,相应的选择查询:

mysql> SELECT 'a' = 'a ';
        -> 1
mysql> SELECT 'A' = 'a';
        -> 1

因此,使用隐式类型转换,例如'1a'INTEGER 的结果是 1,但也:

mysql> SELECT 0 = 'x6';
        -> 1
mysql> SELECT 1 = ' 1';
        -> 1
mysql> SELECT 1 = ' 1a';
        -> 1

此功能也在其他非静态类型语言中实现。例如,PHP 将这种类型称为 juggling。请参阅文档中的PHP 字符串转换规则和此示例:

<?php
  $foo = "0";                     // $foo is string (ASCII 48)
  $foo += 2;                      // $foo is now an integer (2)
  $foo = $foo + 1.3;              // $foo is now a float (3.3)
  $foo = 5 + "10 Little Piggies"; // $foo is integer (15)
  $foo = 5 + "10 Small Pigs";     // $foo is integer (15)
?>

JavaScript

<script>
  document.write(parseInt("40 years") + "<br>");
</script>

=> 40

不过,您的问题的解决方案非常简单:只需将整数转换为 char 并进行比较:

mysql> SELECT * FROM lb_users WHERE (CAST(user_id AS CHAR) = '1' OR user_name = '1')
        -> 1
mysql> SELECT * FROM lb_users WHERE (CAST(user_id AS CHAR) = '1a' OR user_name = '1a')
        -> 0
mysql> SELECT * FROM lb_users WHERE (CAST(user_id AS CHAR) = 'dinodsja' OR user_name = 'dinodsja')
        -> 1

I made a fiddle for everyone to try it out: http://sqlfiddle.com/#!2/c2835/14/0

Hope that helps,

-Hannes

于 2013-04-03T05:24:14.223 回答
0

According to your previous message

its a user input for profile. user can provide user_id or user_name. so the input is valid. but no data. – DBK Mar 30 at 6:42

I'd recommend testing to see if its an integer and only search the user ID if it's an integer. It's really more of a workaround for mySQL not handling a STRING to INT comparison, but it should work.

declare @InputVar varchar(10)
set @InputVar = '1a'

SELECT *  
FROM lb_users
WHERE  
  (case when isnumeric(@InputVar) = 1 then 
    case when (user_id = @InputVar OR user_name = @InputVar) then 1 else 0 end
  else  
    case when user_name = @InputVar then 1 else 0 end
  end =1 )
And 
  user_status = 1
于 2013-04-04T19:36:24.540 回答
0

When dealing with strings I would use 'LIKE' instead of '=' to avoid this silent type conversion madness. LIKE is made to work with strings so why not use it.

于 2013-04-05T09:35:58.867 回答
0
SELECT * FROM lb_users WHERE (user_id = '1a' OR user_name = '1a') AND user_status = 1

you get 1 result if you change '1a' to 1a you get this:

#1064 - 您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以在第 1 行的 '1a LIMIT 0, 30' 附近使用正确的语法

这不是错误,请查看http://dev.mysql.com/doc/refman/5.0/en/where-optimizations.html

希望这可以帮助

于 2013-04-09T11:48:01.727 回答
0

我认为您不能复制主键和 ID,我对其进行了测试,然后得出了一个正在运行的数据。您是否设置了 user_id 及其属性,例如:

user_id bigint(50) auto_increment primary key

这不是mysql错误。

于 2013-04-10T04:58:32.440 回答