如何在MySQL语句中包含一个PHP变量

71 人关注

我试图在内容表中插入数值。如果我在VALUES里面没有一个PHP变量,它就能正常工作。当我把变量 $type 放在 VALUES 里面时,就不能工作了。我做错了什么?

$type = 'testing';
mysql_query("INSERT INTO contents (type, reporter, description) 
     VALUES($type, 'john', 'whatever')");
1 个评论
重要提示: 将变量直接插入到你的SQL中是 SQL注入攻击 的一个主要来源。
php
mysql
sql
string
variables
Pinkie
Pinkie
发布于 2011-09-24
5 个回答
Your Common Sense
Your Common Sense
发布于 2016-09-19
已采纳
0 人赞同

在任何MySQL语句中添加PHP变量的规则都是简单明了的。

  • 任何代表 SQL数据字面 的变量,(或者,简单地说--一个SQL字符串,或者一个数字)都必须通过一个准备好的语句来添加。没有例外。
  • 任何其他查询部分,如SQL关键字、表或字段名,或运算符--必须通过 白名单 过滤。
  • 因此,由于你的例子只涉及数据字面,那么所有的变量必须通过占位符(也称为参数)来添加。要做到这一点。

  • 在你的SQL语句中,用 占位符 替换所有变量
  • 准备 所产生的查询
  • 将变量与占位符 绑定
  • 执行 查询
  • 这里是如何使用所有流行的PHP数据库驱动程序的方法。

    使用mysql ext添加数据字段

    这样的司机 并不存在

    使用 mysqli 添加数据字段

    $type = 'testing';
    $reporter = "John O'Hara";
    $query = "INSERT INTO contents (type, reporter, description) 
                 VALUES(?, ?, 'whatever')";
    $stmt = $mysqli->prepare($query);
    $stmt->bind_param("ss", $type, $reporter);
    $stmt->execute();
    

    代码有点复杂,但所有这些运算符的详细解释可以在我的文章《如何使用Mysqli运行INSERT查询》中找到,还有一个解决方案可以极大地缓解这个过程。

    对于一个SELECT查询,你只需要添加一个对get_result()方法的调用,以获得一个熟悉的mysqli_result,你可以用通常的方法从中获取数据。

    $reporter = "John O'Hara";
    $stmt = $mysqli->prepare("SELECT * FROM users WHERE name=?");
    $stmt->bind_param("s", $reporter);
    $stmt->execute();
    $result = $stmt->get_result();
    $row = $result->fetch_assoc(); // or while (...)
    

    使用PDO添加数据字段

    $type = 'testing';
    $reporter = "John O'Hara";
    $query = "INSERT INTO contents (type, reporter, description) 
                 VALUES(?, ?, 'whatever')";
    $stmt = $pdo->prepare($query);
    $stmt->execute([$type, $reporter]);
    

    在PDO中,我们可以将绑定和执行部分结合起来,这非常方便。PDO还支持命名的占位符,有些人认为这非常方便。

    添加关键词或标识符

    有时我们必须添加一个变量,代表查询的另一部分,如一个关键词或一个标识符(数据库、表或字段名)。这是一种罕见的情况,但最好有所准备。

    在这种情况下,你的变量必须与你的脚本中明确写出的数值列表进行检查。这在我的另一篇文章《根据用户的选择在ORDER BY子句中添加字段名》中有所解释。

    不幸的是,PDO没有标识符(表和字段名)的占位符,因此开发者必须手动过滤掉它们。这样的过滤器通常被称为 "白名单"(我们只列出允许的值),而不是 "黑名单",我们列出不允许的值。

    所以我们必须在PHP代码中明确列出所有可能的变体,然后从中选择。

    下面是一个例子。

    $orderby = $_GET['orderby'] ?: "name"; // set the default value
    $allowed = ["name","price","qty"]; // the white list of allowed field names
    $key = array_search($orderby, $allowed, true); // see if we have such a name
    if ($key === false) { 
        throw new InvalidArgumentException("Invalid field name"); 
    

    对方向应使用完全相同的方法。

    $direction = $_GET['direction'] ?: "ASC";
    $allowed = ["ASC","DESC"];
    $key = array_search($direction, $allowed, true);
    if ($key === false) { 
        throw new InvalidArgumentException("Invalid ORDER BY direction"); 
    

    在这样的代码之后,$direction$orderby两个变量都可以安全地放在SQL查询中,因为它们要么等于允许的变体之一,要么会有一个错误被抛出。

    最后要提到的是关于标识符,它们也必须根据特定的数据库语法进行格式化。对于MySQL来说,它应该是标识符周围的backtick字符。因此,我们的例子中的订单的最终查询字符串将是

    $query = "SELECT * FROM `table` ORDER BY `$orderby` $direction";
    
    Stefan
    Stefan
    发布于 2016-09-19
    0 人赞同

    为了避免SQL注入,插入语句应采用

    $type = 'testing';
    $name = 'john';
    $description = 'whatever';
    $con = new mysqli($user, $pass, $db);
    $stmt = $con->prepare("INSERT INTO contents (type, reporter, description) VALUES (?, ?, ?)");
    $stmt->bind_param("sss", $type , $name, $description);
    $stmt->execute();
    
    DrFaraday
    如果我想显示一个简介,在我的$stmt中我有'SELECT * FROM Profile WHERE profile_id LIKE (?)' ......我只有一个参数要插入我的SQL,我该怎么做?
    Tel
    Tel
    发布于 2016-09-19
    0 人赞同

    最好的选择是准备好的报表。 乱用引号和转义是更难的工作,而且难以维护。迟早你会不小心忘了引号,或者把同一个字符串转义两次,或者把类似的事情弄乱。在你发现这些类型的错误之前,可能已经过了很多年。

    http://php.net/manual/en/pdo.prepared-statements.php

    Spencer Rose
    Spencer Rose
    发布于 2016-09-19
    0 人赞同

    $type里面的文本被直接替换成插入字符串,因此MySQL得到了这个。

    ... VALUES(testing, 'john', 'whatever')
    

    注意,测试周围没有引号,你需要像这样把这些东西放进去。

    $type = 'testing';
    mysql_query("INSERT INTO contents (type, reporter, description) VALUES('$type', 'john', 'whatever')");
    

    我还建议你阅读关于SQL注入的文章,因为如果你不对使用的数据进行消毒,这种参数传递很容易被黑客尝试。

  • MySQL - 预防SQL注入
  • Baloomba
    Baloomba
    发布于 2016-09-19
    0 人赞同

    这是个简单的答案。

    $query="SELECT * FROM CountryInfo WHERE Name = '".$name."'";
    

    而你对$name的定义是你想要的。
    而另一种方式,即复杂的方式,是这样的。

    $query = " SELECT '" . $GLOBALS['Name'] . "' .* " .
             " FROM CountryInfo " .
             " INNER JOIN District " .
             " ON District.CountryInfoId = CountryInfo.CountryInfoId " .
             " INNER JOIN City " .
             " ON City.DistrictId = District.DistrictId " .