【问题标题】:PDO INSERT not working with $_POST VariablesPDO INSERT 不适用于 $_POST 变量
【发布时间】:2013-03-02 16:37:55
【问题描述】:

我正在为此烦恼-希望这是一个容易的疏忽。

我打算使用 jQuery AJAX 函数向这个 PHP 文件发送一堆变量。我写了这个部分来将所有 $_POST 变量分配给 php 变量:

foreach($_POST as $key => $value){
    $$key = $value;
}

它似乎正在工作,因为我可以像这样操纵变量:

echo 'name: ' . $name . '<br>';
echo 'main_pic: ' . $main_pic . '<br>';
echo 'product_pic: ' . $product_pic . '<br>';
echo 'more_pic: ' . $more_pic . '<br>';
echo 'paypal_code: ' . $paypal_code . '<br>';
echo 'category_id: ' . $category_id . '<br>';
echo 'price: ' . $price . '<br>';
echo 'description: ' . $description . '<br>';
echo 'product_color: ' . $product_color . '<br>';
echo 'design_color: ' . $design_color;

现在我有了这些,我想将它们插入到我的表格中-

$qry = $pdo->prepare("INSERT INTO inventory (name, main_pic, product_pic, more_pic, paypal_code, category_id, price, description, product_color, design_color) 
                                            VALUES (:name, :main_pic, :product_pic, :more_pic, :paypal_code, :category_id, :price, :description, :product_color, :design_color)");

    $qry-> bindParam(':name', $name);
    $qry-> bindParam(':main_pic', $main_pic);
    $qry-> bindParam(':product_pic', $product_pic);
    $qry-> bindParam(':more_pic', $more_pic);
    $qry-> bindParam(':paypal_code', $paypal_code);
    $qry-> bindParam(':category_id', $category_id);
    $qry-> bindParam(':price', $price);
    $qry-> bindParam(':description', $description);
    $qry-> bindParam(':product_color', $product_color);
    $qry-> bindParam(':design_color', $design_color);
    $qry-> execute(); 

这不会运行 - 我不确定记录错误以查看原因的最佳方法。如果我手动分配变量并注释掉我之前的 $_POST 恶作剧,一切似乎都正常,并且 INSERT 运行良好。

有什么线索吗?我认为这可能是因为数据库需要某种变量类型,但我认为我已经充分探索了这一点。

任何人都知道手动分配变量会起作用但从 $_POST 获取它们不起作用的任何原因吗?

编辑:按照这些建议,我收到一条错误消息 SQLSTATE[23000]: 完整性约束违规: 1062 Duplicate entry '0' for key 1

好的,所以当我尝试这个插入时,我没有分配唯一的主键——我假设 PDO 会处理这个问题。处理分配唯一主键的最佳方法是什么?我想避免让用户手动分配它。

【问题讨论】:

  • 启用PDO::ERRMODE_WARNING 看看它是否发现您有任何不当行为。
  • 如果您将使用 AJAX 查询的 URL 放入浏览器,它应该(如果您已设置显示所有错误)会告诉您出了什么问题。或者,您的 web 文件夹的根目录中可能有一个 error_log 文件。来自这些的任何信息都会有所帮助。
  • 启用错误代码并使用更多信息编辑问题。谢谢!
  • 您的prepare/execute 与“POST 恶作剧”的功能相同吗?你的表结构是什么(DESCRIBE inventory)?
  • 接受了一个答案,但下面有一个很好的小讨论,说明为什么我在上面做的事情是一种编码恐惧。谢谢!

标签: php sql pdo


【解决方案1】:

这不是一个答案,但它看起来比评论更好。你为什么要这样做:

foreach($_POST as $key => $value){
    $$key = $value;
}

这是重新注册全局变量(有点)。使用上面的代码,你可以很容易地用意想不到的结果覆盖局部变量,甚至引入安全漏洞。

如果我发布$_POST['is_admin'] = 1 或类似的东西怎么办?不管怎样,我认为你明白了。你刚才做的很糟糕,可能很危险。

【讨论】:

  • 是否可以通过命名变量来解决这个问题,或者我应该完全避免这样做?我希望能够在我的表单中添加新字段并尽量减少任何代码更改。
  • @ThomasPatrickHorton 您最好创建一个白名单键数组,并遍历它以进行绑定。 将有助于最大限度地减少代码更改,并避免这种寄存器全局灾难等待发生。
  • @ThomasPatrickHorton 如果您添加字段,您将不得不更改代码,否则您的查询将无法正常工作。
  • 是的,这正是他们说不要推出自己的代码的原因。这实际上只是一个探索性项目——我知道有很多漏洞需要导航。感谢您的提示!
【解决方案2】:

就像@PeeHaa,这不是一个答案,而是扩展我对他的评论;删除伪寄存器全局功能:选择字段白名单,并将名称与发布的名称协调。

$fields = ['name', 'age', 'sex'];

$query = $pdo->prepare(sprintf('INSERT INTO `table` (%s) VALUES (%s)', 
    implode(',', $fields), 
    implode(',', array_map(function($field) {
        return ":{$field}";
    }, $fields))));

foreach($fields as $field) {
    $query->bind(":{$field}", $_POST[$field]);
}

$query->execute();

显然,这需要更多的验证、empty() 检查等,但你明白了。此外,您可以通过回调查找添加更多验证/清理:

$sanitizers = [
    'sex' => function($value) {
        $value = strtolower($value);
        return in_array($value, ['male', 'female', 'unknown']) 
            ? $value : 'unknown';
    },
];

foreach($sanitizers as $field => $sanitizer) {
    if (isset($_POST[$field])) {
        $_POST[$field] = $sanitizer($_POST[$field]);
    }
}

如果帖子中包含“sex”的“genderless”,您将得到“unknown”。


更完整的例子:

// whitelist keys and sanitizer values
$fields = [
    // limit to 255 
    'name' => function($value) {
        return substr($value, 0, 255);
    }, 
    // you can't be that old
    'age' => function($value) {
        return min(max((int) $value, 0), 100);
    },
    // starfish need not apply
    'sex' => function($value) {
        $value = strtolower($value);
        return in_array($value, ['male', 'female', 'unknown']) 
            ? $value : 'unknown';
    },
];

// build ye' old query
$query = $pdo->prepare(sprintf('INSERT INTO `table` (%s) VALUES (%s)', 
    implode(',', array_keys($fields)), 
    implode(',', array_map(function($fields){
        return ":${$field}";
    }, array_keys($fields)))));

// loop dee doop to sanitize and bind
foreach ($fields as $key => $sanitizer) {
    if (is_callable($sanitizer)) {
        $query->bind(":{$field}", $sanitizer($_POST[$field]));
        continue;
    }
    $query->bind(":{$field}", $_POST[$field]);
}

// fire the cannons!
$query->execute();

【讨论】:

  • 非常有帮助 - 这是一个很好的开始。
  • @ThomasPatrickHorton 没有概率 Bob;我更新了一个更完整的版本。
【解决方案3】:

清空您的数据库表,看看它是否有效...您的数据库表中可能有一个您正试图覆盖的主键。

检查您的数据库表,使用EXPLAIN inventory

【讨论】:

  • 原来就是这样——现在我必须修复它。谢谢!
【解决方案4】:

如果需要,您可以拥有一个自动递增的主键。假设你使用 mysql: http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html

【讨论】:

    【解决方案5】:

    OP 说: 好的,所以我在尝试时没有分配唯一的主键 这个插入 - 我假设 PDO 会处理这个问题。 处理分配唯一主键的最佳方法是什么? ID 希望避免让用户手动分配它。

    只是解决这部分或您的问题 - 您只需使用未引用的 0

    insert into table (id, name) values (0, 'Bob');
    

    但正如你所说,如果它是一个正确自动递增的 id,你不应该这样做。

    在旧版本的 Mysql (

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-14
      • 1970-01-01
      • 2012-12-27
      • 1970-01-01
      • 2019-10-25
      • 2014-11-25
      • 2011-12-24
      相关资源
      最近更新 更多