2

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

我计划使用 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 会处理这个问题。处理分配唯一主键的最佳方法是什么?我想避免让用户手动分配它。

4

5 回答 5

3

这不是一个答案,但它看起来比评论更好。您为什么要执行以下操作:

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

这是重新注册全局变量(有点)。使用上面的代码,您可以轻松地覆盖具有意外结果的局部变量,甚至引入安全漏洞。

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

于 2013-03-02T17:06:39.990 回答
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]);
    }
}

如果帖子包含“性别”的“无性别”,您将得到“未知”。


更完整的例子:

// 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();
于 2013-03-02T17:21:48.603 回答
1

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

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

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

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

在旧版本的 Mysql (< 5) 中,您可以使用一个空字符串,当 5.0 发布时它会爆炸,以防万一读到这篇文章的人违反了以前未记录的功能。

于 2013-03-02T17:19:51.470 回答
1

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

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

于 2013-03-02T16:58:49.107 回答
1

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

于 2013-03-02T17:01:12.267 回答