2

好的,我对绑定很陌生,这里有一些有效的代码。我从教程中学习了这种格式,但我想有更有效的方法可以做到这一点。在我的示例中,有 4 个名称,但实际上我将在我正在处理的项目中进行大量插入和更新,该项目将有 20 个左右的字段。我喜欢这种方法的清晰性,但很明显,当您谈论 20 个或更多字段时,它确实需要大量的空间。让我们先看看我的代码。

以下是它使用的功能:

// prepare the statement
public function query($query){
    $this->stmt = $this->dbh->prepare($query);
}

public function bind($param, $value, $type = null){
    if (is_null($type)) {
        switch (true) {
            case is_int($value):
                $type = PDO::PARAM_INT;
                break;
            case is_bool($value):
                $type = PDO::PARAM_BOOL;
                break;
            case is_null($value):
                $type = PDO::PARAM_NULL;
                break;
            default:
                $type = PDO::PARAM_STR;
        }
    }
// run the binding process
$this->stmt->bindValue($param, $value, $type);
}

// execute the prepared statement
public function execute(){
    return $this->stmt->execute();
}

现在是实际的代码

$database->query("
    INSERT INTO users(
        user_name,
        user_password_hash,
        user_email,
        user_activation_hash
)

    VALUES(
        :user_name,
        :user_password_hash,
        :user_email,
        :user_activation_hash
    )
");

// bind the values
$database->bind(":user_name", "$this->user_name");
$database->bind(":user_password_hash", "$this->user_password_hash");
$database->bind(":user_email", "$this->user_email");
$database->bind(":user_activation_hash", "$this->user_activation_hash");

// execute the statement and insert the values into the database
$database->execute();

它只是呼唤一个循环,特别是因为我有一个习惯叫帖子字段,输入字段,变量和占位符同名,不确定这是好事还是坏事,但我发现它在处理时对我很有帮助我会的大表格。

无论如何,我可以做这样的事情:

$placeholder_array = array(
    "user_name"               => "\$this->user_name",
    "user_password_hash"      => "\$this->user_password_hash",
    "user_email"              => "\$this->user_email",
    "user_activation_hash"    => "\$this->user_activation_hash"
);

// well use this copy to edit the array keys and keep original for the binding
$placeholder_copy = $placeholder_array;


// turn the array into a string i.e user_name, user_password_hash....
$fields = implode (", ", array_keys($placeholder_array));

// foreach to add : placeholder prefix for binding
foreach ($placeholder_copy as $key => $value){
$placeholder_copy [':'.$key] = $value;
unset($placeholder_copy[$key]);
}

// turn the copy array which has prefix :user_name into a string 
$placeholders = implode (", ", array_keys($placeholder_copy));

$database->query("
    INSERT INTO users($fields)
    VALUES($placeholders) 
");

// bind the values
foreach ($placeholder_copy as $bind_values => $value){
    echo '$database->bind("'.$bind_values.'", "'.$value.'");' . "<br />";
}

// execute the statement and insert the values into the database
$database->execute();

然后我可以把它变成一个带有参数的函数,用于传递关联数组和表名,以使我的主代码更简洁。

现在想象一下,我将做任何数量的这些,因为我正在从事的项目涉及大量向用户提交数据的大型表单。我是 PDO 的新手并试图掌握它,因此可能有一种更简单的方式来构建这些类型的查询,我查看了 google 和 stackflow,但我并没有真正了解他们在做什么,所以我认为自己做一个会允许人们可以更好地向我解释发生了什么,我宁愿在我的项目开始时正确地解决这个问题,也不愿回头再改变一切。那么有没有更好的方法或者这个可以吗?

非常感谢任何反馈,我很高兴现在我在这里接受了人们的建议并转向 PDO。

4

2 回答 2

2

不,遗憾的是,PDO 对此事没有提供任何帮助。
然而,在我看来,您自己的方法也不是一种有效的方法。

首先,让我表明您的功能集毫无用处。我理解没有这样直接重写 API 函数。PDO 已经在做所有这些事情。

使用原始 PDO,您可以获得更简洁的代码:

$stm  = $pdo->prepare("INSERT INTO users VALUES(NULL,?,?,?,?)");
$data = array($this->user_name, 
              $this->user_password_hash, 
              $this->user_email, 
              $this->user_activation_hash
);
$stm->execute($data);

关于您的动态查询构建,我发现它过于臃肿但仍然不安全。有些缺陷是

  • 没有必要打扰 ":named" 占位符,因为它们应该是人类可读的,但没有人应该在这里阅读它们。更不用说 PDO 在发送到 mysql 之前会将它们转换回 ?s
  • 对命名占位符的另一个反对意见 - 虽然 Mysql(以及 HTTP)可以让您在字段名称中有一个空格,但带有空格的占位符只会使您的查询崩溃。
  • 从您的同名方法中,这段代码没有真正的好处 - 请注意,您必须每次手动编写它们几次
  • 但是,如果要使用它,您将没有白名单来检查您的字段列表,这可能是一个很大的安全漏洞
  • 代码太多
  • 不支持UPDATE查询,这也可能非常方便(如果您使用的是 mysql)
  • 当你把这段代码放到函数中时,你会陷入和其他人一样糟糕的境地,被节省你整个两个词的可能性所诱惑!

这是我之前对此事的处理方法

$allowed = array(
    "user_name", "user_password_hash", "user_email", "user_activation_hash"
);
$sql = "INSERT INTO users SET ".pdoSet($allowed, $values);
$stmt = $dbh->prepare($sql);
$stmt->execute($values);

这是我目前的方法,最好的(虽然使用 mysqli,而不是 PDO 实现),使用数组数据的自定义占位符:

$placeholder_array = array(
    "user_name"               => $this->user_name,
    "user_password_hash"      => $this->user_password_hash,
    "user_email"              => $this->user_email,
    "user_activation_hash"    => $this->user_activation_hash
);
$db->query("INSERT INTO users SET ?u", $placeholder_array);

或者,在表单字段和 SQL 列之间直接连接的情况下

$allowed = array(
    "user_name", "user_password_hash", "user_email", "user_activation_hash"
);
$insert = $db->filterArray($_POST,$allowed);
$db->query("INSERT INTO users SET ?u", $insert);

这样我就可以使用INSERT IGNORE, INSERT DELAYED, INSERT.. ON DUPLICATE UPDATE, UPDATE,UPDATE和 join 以及无数其他选项,支持完整的SQL 语言。

于 2013-08-20T07:23:38.200 回答
1

我最近所做并继续改进的是构建一个帮助类来简化我的应用程序中基于 PDO 的 SQL 语句。

让我们以您的示例进行游览。您想将数据插入到用户表中:

INSERT INTO users(
    user_name,
    user_password_hash,
    user_email,
    user_activation_hash
) VALUES(
    :user_name,
    :user_password_hash,
    :user_email,
    :user_activation_hash
)

为了插入一条记录,我的 SQL 构造如下:

function myInsertSingle($PDO, $table, $ins_array) {
    $SQL = "INSERT INTO `".$table."` (".dbFieldList($ins_array)
            .") VALUES (".dbValuePList($ins_array).")";

...继续准备。

  • $PDO: 我的 PDO 连接。
  • $table: 我要插入的表。
  • $ins_array:用于插入数据的结构化数组。

对于您的示例,数组$ins_array将如下所示:

$ins_array = array(
    "user_name"               => "your_user",
    "user_password_hash"      => "your_pw_hash",
    "user_email"              => "your@mail.xyz",
    "user_activation_hash"    => "your_other_Hash"
);

注意与您的阵列的相似性!

涉及两个功能。第一个给了我一个(转义的)字段名列表。

function dbFieldList($fields) {
    $set = '';
    foreach ($fields as $field => $item) {
        $set .= "`".$field."`,";
    }   
    return rtrim($set, ',');
}

基本上从上面的数组示例中,函数返回

`user_name`, `user_password_hash`, `user_email`, `user_activation_hash`

...这是 - 语句中所需字段的列表INSERT

另一个对值做了类似的事情。

function dbValuePList($fields) {
    $set = '';
    foreach ($fields as $field => $item) {
        $set .= ":".$field.",";
    }   
    return rtrim($set, ',');
}

你猜对了,结果是这样的:

:user_name, :user_password_hash, :user_email, :user_activation_hash

现在您有了可以准备的 SQL 语句。要绑定值,如果我正确理解您的类,只需使用如下所示的循环:

foreach ($ins_array as $field => $item) {
    $PDO->bind(':'.$field,$item);
}

现在您可以执行该语句。

概括。基本上,使用我的方法,单个 INSERT 语句被简化为:

$ins_array = array(
    "user_name"               => "your_user",
    "user_password_hash"      => "your_pw_hash",
    "user_email"              => "your@mail.xyz",
    "user_activation_hash"    => "your_other_Hash"
);

myInsertSingle($PDO, 'your_table', $ins_array);

如果这看起来只是另一个开销,请记住,我在其他 SQL 语句(如 SELECT、UPDATE、DELETE 等)中使用这些函数。

于 2013-08-20T04:38:56.430 回答