PDO INSERT无法使用$ _POST变量

时间:2013-03-02 16:37:56

标签: php sql pdo

我把头发拉过来 - 希望这是一个容易的疏忽。

我打算用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 shenanigans,一切似乎都有效,INSERT运行正常。

任何线索?我想这可能是因为数据库期望某种变量类型,但我想我已经充分探索过了。

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

编辑:按照这些建议,我收到了一条错误消息     SQLSTATE [23000]:完整性约束违规:1062密钥1的重复条目“0”

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

5 个答案:

答案 0 :(得分:3)

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

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

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

如果我发布$_POST['is_admin'] = 1或类似内容怎么办?无论哪种方式,我认为你明白了。你刚刚做的很糟糕,可能很危险。

答案 1 :(得分: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();

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

$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();

答案 2 :(得分:1)

清空数据库表并查看它是否有效...可能你在db表中有一个主键,你试图覆盖它。

使用EXPLAIN inventory

检查您的数据库表

答案 3 :(得分:1)

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

答案 4 :(得分:1)

  

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

只是解决这一部分或您的问题 - 您只需使用不带引号的0

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

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

在旧版本的Mysql(&lt; 5)中,你可以使用一个空字符串,当5.0出现时它会爆炸,以防万一有人读到这个字符串与之前未记录的功能相违背。