-2

使用简单的 mysql 而不是 PDO 或任何东西会更专业和防错方法

我通常这样做

    $sql_request = "SELECT * 
                      FROM myusers 
                          WHERE user_id = {$user_id} 
                            AND email = '{$email_address}' 
                              LIMIT 0,1";

但是我也应该引用{$user_id}吗?

即使当我得到用户输入时,我也不会引用数字,但是我会在处理它们之前检查 ctype_digit()。

4

7 回答 7

7

不,不需要在数字文字周围加上引号。

对于 MySQL,如果数字文字用单引号括起来就可以了;我认为我们经常看到它这样做的原因是为了方便程序员不必关心它是字符还是数字,只需在所有文字周围加上引号即可。

当值不是数字文字时,引用值和不引用值时的行为有所不同。例如,给定一个id类型为 的列INTEGER,在这种情况下

... WHERE id = '1X'

这里'1X'将被解释为值为 1 的文字数字,但在此上下文中

... WHERE id = 1X

这里1X将被解释为列名,而不是数字文字。这可能会导致 MySQL 抛出“未知列”异常。

考虑如何解释这些差异......

... WHERE id = 'id'   -- 'id' will be interpreted as numeric literal value 0

... WHERE id = id     -- id will be interpreted as a column name

因此,当您期望被解释为数字文字的东西不是数字时,它真的归结为哪种行为最适合您的应用程序。


我个人的偏好是引用数字文字。这可能是由于我使用其他 DBMS 的经验以及需要避免由隐式数据转换引起的问题。我个人的偏好也是使用准备好的语句,并避免我的语句在 SQL 文本中包含值作为文字。(对于 MySQL,这一点主要是没有意义的,因为带有绑定变量的准备好的语句在发送到数据库时会转换为纯 SQL 文本......但这是由 MySQL 库完成的,而不是我的代码。再说一次,这是偏好可能最了解我使用其他 RDBMS(Oracle、Teradata、DB2、SQL Server)而不是 MySQL 本身的长期经验。

于 2012-08-31T19:42:08.337 回答
2

我强烈建议在引用数值时要小心——这就是发生在我身上的事情:一个优化的、经常运行的查询产生了疯狂的 IO 和相当多的 CPU 负载:

SELECT blah FROM foo WHERE intcolumn='17';

选择性是数百万行中的大约 100 行。我检查了执行计划:你瞧,对驱动表进行全表扫描。foo(intcolumn)我一次又一次地检查索引,甚至删除并重新创建它,没有运气。查询时间以分钟为单位。

SELECT blah FROM foo WHERE intcolumn=17;

不到0.1秒。出于某种原因,MySQL 选择将 allfoo.intcolumn转换为VARCHAR,然后进行字符串比较'17'。当然,这包括忽略索引。

我不知道,如果我在旧版本的 MySQL 中遇到了一个奇异的错误,但我肯定会带走一件事:确保解析器知道我打算使用什么数据类型。这个ofocurse可能会因引用数字而变得棘手。

于 2012-08-31T19:51:21.040 回答
1

普遍的共识是,将 SQL 语句编写为插值(您的示例)或连接字符串不是一个好主意(即,既不专业也不防错)。您应该改用准备好的语句。

在黑暗时代,我使用了如下函数:

// This is obsolete!!
function escape_input($s) {
  if (!ctype_digit($s))
    return "'" . mysql_real_escape_string($s) . "'";
  else
    return $s;
}

如您所见,我引用了字符串输入,但允许整数输入不带引号通过。(尽管你可以引用整数输入而不会产生任何不良影响。)我在每个 MySQL 输入上都使用了这个函数,无论我是否知道输入是整数。通过强迫自己遵循这种模式,我认为我从来没有向 SQL 注入攻击敞开心扉。但同样,我不会再这样做了。我会使用 PDO 或 mysqli_* 中的准备好的语句。

于 2012-08-31T19:52:00.540 回答
1

使用简单的 mysql 而不是 PDO 或任何东西会更专业和防错方法

我会说它是sprintf并且编写可读的代码。您通常不希望将变量名称放入字符串中,而是稍后根据顺序添加它们。这使它更加解耦并且更易于阅读。

您还可以指定数字数据,%d以确保它是整数值并且不易发生字符串注入。数字文字通常不需要引号。所以sprintf和 SQL 在这里配合得很好。%s需要引号,%d不需要。然而,报价也不会受到伤害:

$sql_request = "SELECT * 
                  FROM myusers 
                      WHERE user_id = '%d'
                        AND email = '%s' 
                          LIMIT 0,1";

$query = sprintf($sql_request, $user_id, mysql_real_escape_string($email_address, $link));

但是,我在您的问题中读到了关于不是 mysqli 或 PDO 的问题。如果可以,切换到 PDO 并使用准备好的语句/参数化查询。如果这是一个旧应用程序,请在mysql_*函数前面加上一些东西,然后根据 PDO 自己实现它们,然后缓慢而稳定地用新代码替换旧代码。

还请看一下这个问题,它也应该可以帮助您开始移植代码,它的工作速度相对较快:

以及如何切换到 PDO:

于 2012-08-31T19:44:21.777 回答
0

不应引用 User_id 列,因为它是数字的。但是您必须确保传递了数值。

于 2012-08-31T19:39:15.160 回答
0

$user_id只要确保变量包含数字,就不需要引用。

如果不是这样,它可能会破坏您的查询,甚至损坏您的数据库!

更好的解决方案是使用使用 PDO 或其他库的准备好的语句。

于 2012-08-31T19:40:19.480 回答
-1

我会推荐引用。你永远不能太确定!(你会让 MySQL 处理可能的错误)。此外,习惯在变量周围添加引号可以帮助您记住一旦习惯了就始终将它们放在引号中,从而减少错误。(也不要忘记转义您的输入)

或者,将 PDO 或 MySQLi 与准备好的语句一起使用!你甚至不必再引用了。(是的,对不起。回答一个真正想要使用已弃用的东西的问题会让我提供更好的选择)

于 2012-08-31T19:39:08.077 回答