0

我有以下 MySQL 命令尝试获取用户的登录信息:

$requete = "SELECT login, pass FROM membres WHERE login='$login' AND pass='$pass'";
echo ("$requete");

它不工作。问题是,在执行此代码时,我看到以下输出(而不是执行查询的结果):

SELECT login, pass FROM membres WHERE login='$login' AND pass='$pass'

在 PHP 中将变量传递给 MySQL 查询的正确方法是什么?

4

1 回答 1

10

在 PHP 中,与许多其他编程语言一样,=运算符将右侧操作数的值分配给左侧操作数变量。即这样的命令执行后,符号左侧命名的变量=将包含符号右侧表达式的值=

您的右手操作数是一个双引号字符串字面量,其中 PHP 用它们的值扩展(替换)变量;但是,结果(分配给左侧操作数)只是一个字符序列。

PHP 的echo构造将其参数转换为字符串,按顺序连接它们并将结果发送到输出缓冲区。

在您的情况下,唯一的参数是另一个双引号字符串 literal "$requete",其中 PHP 再次使用它们的值扩展变量:这次文字的内容仅仅是 variable $requete,因此引用它只会导致多余的解析开销;并且由于该变量被分配了前一个字符串文字,因此结果字符串(由 输出echo)等于原始字符串文字。因此,您的两个陈述具有相同的效果:

echo "SELECT login, pass FROM membres WHERE login='$login' AND pass='$pass'";

PHP 没有被告知存在 RDBMS,这是您希望由该 RDBMS 评估的 SQL,或者您希望输出生成的结果集。

更糟糕的是,除非您绝对确定并且$login$pass包含未转义'的字符,否则为 SQL 解析该字符串可能会导致意外行为。 攻击者经常利用这种疏忽来执行SQL 注入攻击,这可能会危及您的整个数据库。避免这种情况的最安全方法是永远不要评估SQL 的变量,而是使用准备好的语句,将变量作为参数传递到其中。

我建议您研究PHP Data Objects,它使安全数据库访问变得非常容易:

$dbh = new PDO("mysql:dbname=$dbname;charset=utf8", $username, $password);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

$qry = $dbh->prepare('
  SELECT login, pass
  FROM   membres
  WHERE  login = ? AND pass = ?
');

$qry->execute(array($login, $pass));
while ($row = $qry->fetch(PDO::FETCH_ASSOC)) print_r($row);

不过,有几点需要注意:

  1. 您只是从与常量值匹配的数据库字段中进行选择,这是毫无意义的:从此类查询中可以获得的唯一信息是数据库中匹配记录的数量,但是在返回多余的数据时会浪费资源。

    相反,您可以SELECT COUNT(*) FROM membres WHERE ...在不浪费任何开销的情况下获取相同的信息;或者如果您只想发现是否有一条或多条匹配记录,SELECT EXISTS (SELECT * FROM membres WHERE ...)效率会更高。

  2. 您似乎正在创建一个登录脚本,以安全的方式完成这项工作并非易事:如果您有兴趣了解更多信息,请阅读The Definitive Guide To Forms based Website Authentication 。那里有一些库和工具,您可以将它们放入您的项目中,以避免在重新发明轮子上浪费资源(以及其他人从艰难中学到的所有许多痛苦的错误)。

于 2012-09-14T13:08:56.590 回答