【问题标题】:PHP MariaDB Insert NULL Value Not WorkingPHP MariaDB插入NULL值不起作用
【发布时间】:2018-09-12 15:08:01
【问题描述】:

使用 PHP 版本 7.1.9,MariaDB 10.1.26。

我正在向 MySQL 数据库提交表单数据,我的值之一是 NULL 但在数据库中它是空的。

我已确保我的数据库表设置为;

  • 允许 null = 是
  • 默认 - 空

我的代码在下面(请忽略任何安全漏洞,这是简化的代码);

$id = $_POST['id '];
$name = $_POST['name'] ? $_POST['name'] : NULL ;
$sql = "INSERT INTO staff (id, name) VALUES ('".$id."', '".$name."')
// query runs and inserts successfully

当我var_dump($name) 时,我得到NULL,尽管我数据库中的name 值为空(即不是null

任何想法我做错了什么?

【问题讨论】:

  • 您是否可以插入一个空字符串而不是 NULL?
  • 如果您没有 $name 的值,则您的查询应该只是 $sql = "INSERT INTO staff (id) VALUES ('".$id.") 以使数据库中的名称为 NULL
  • @GeorgeHanson 这实际上是他的查询所发生的事情
  • 另外,id 不是自增主键吗?那么你根本不应该将它包含在查询中。
  • 我想指出原始发帖人说“请忽略任何安全漏洞,这是简化的代码”......似乎每个人都在他们的回复中忽略了这一点。我认为该声明的意思是“我知道安全措施并且我正在使用它们。”

标签: php mysql null


【解决方案1】:

编辑

原发帖人说

我的代码如下(请忽略任何安全漏洞,这是简化代码)

我将其解释为“我知道 SQL 注入,并且我正在采取措施防止它出现在我的代码中。我已经简化了我的帖子,以便更容易获得答案。”

我在下面的回复遵循他们的格式。这就是为什么我没有在我的帖子中使用 PDO、mysqli、prepared statements/escape 措施。如果我亲自编写将数据插入数据库的代码,我会确保我的数据已经过清理,并且我会使用像 Doctrine 这样的 ORM(它是 PDO 的包装器)直接与数据库交互。

我的答案

参考原帖中的代码:

$id = $_POST['id '];
$name = $_POST['name'] ? $_POST['name'] : NULL ;
$sql = "INSERT INTO staff (id, name) VALUES ('".$id."', '".$name."')
// query runs and inserts successfully

您的查询的行为方式与您编写代码的方式相同。如果您在将 PHP 变量设置为 NULL 后将其回显/打印到标准输出,您将根本看不到任何值。 Null 是没有价值。因为你已经用单引号包裹了 value 的缺失 (no value, null),所以你告诉 MySQL 你想在 name 列中插入一个空字符串。

我会重写代码如下:

$id = $_POST['id '];
$name = $_POST['name'] ? "'$_POST[name]'" : 'NULL';
$sql = "INSERT INTO staff (id, name) VALUES ('$id', $name)";

请注意我如何将 NULL 放入 name 变量的字符串中。当我在查询中包含 name 变量时,我不会用引号括起来。这是显式向 MySQL 中的列添加空值的正确方法。

PHP 的双引号允许变量插值。这意味着您不必将字符串分解为单独的部分并将字符串值连接在一起。这使代码更清晰,更易于阅读。

【讨论】:

  • 感谢您的精彩解释! :)
【解决方案2】:

首先,您显然没有使用准备好的语句。我强烈建议您以安全和稳定的名义使用准备好的语句。

然后,谈谈手头的问题。数据库不知道 PHP null 是什么,只会看到要插入到代码中的空字符串。

"" . null . "" === ""

保留您的(非常危险和易受攻击的)示例代码,并修改您在要插入的字符串周围添加“引号”的位置。如果名称为空,只需插入NULL,不带引号。数据库服务器会将其解释为必须插入空值

$name = $_POST['name'] ? "'".$_POST['name']."'" : 'NULL';
$sql = "INSERT INTO staff (id, name) VALUES ('".$id."', ".$name.")";

现在,真的,研究如何进行准备好的查询以防止 SQL 注入 或者至少使用 mysqli_real_escape_string 或类似的东西。

这是更安全的版本,使用 PDO。

$sql = "INSERT INTO staff (id,name) VALUES (:id,:name)";
$stmt= $dpo->prepare($sql);
$stmnt->bindParam(':id', $id, PDO::PARAM_INT);

if(!$POST['name']) {
    $stmnt->bindParam(':name', null, PDO::PARAM_NULL);
}
else {
   $stmnt->bindParam(':name', $POST['name'], PDO::PARAM_STR);
}
$stmt->execute();

【讨论】:

  • 这很棒,而且效果很好 - 也感谢您的解释!我了解您的 cmets 关于安全性的问题并带他们上船 :)
  • @TheOrdinaryGeek 我为您添加了一个粗略的 PDO 示例。这不考虑 '0' 的帐户名称或其他代表错误的真实值。当然,验证需要预先进行。
【解决方案3】:

我会改为使用 PDO 准备好的语句。那应该将值设置为 NULL 而不是空字符串。因为您正在包装'".$name"',所以它正在查询'') - 即一个空字符串。

【讨论】:

    【解决方案4】:

    我会这样做:

    $id = $_POST['id '];
    if(isset($_POST['name'])){
        $sql = "INSERT INTO staff (id, name) VALUES ('".$id."', '".$name."')
    }else{
        $sql = "INSERT INTO staff (id) VALUES ('".$id."')
    }
    

    如果我从表单中收到名称,则区分查询。 您应该使用准备好的语句将变量(用户输入)传递给 mysql 查询。否则,您对 SQL 注入持开放态度。

    【讨论】:

    • 然后给出一个对slq注入不开放的答案
    • 我目前正在回复 OP 发布的与他发布的代码严格相关的问题。
    • 好像大家一直无视原贴说“我的代码在下面(请忽略任何安全漏洞这是简化代码)”意味着他们已经知道sql注入并正在采取措施在他们的代码中防止它。我想该帖子已被简化以获得快速答案,在这种情况下,Lelio 的帖子很合适。
    猜你喜欢
    • 2016-01-16
    • 1970-01-01
    • 2017-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多