Php PDO使用MySQL';s现在()

Php PDO使用MySQL';s现在(),php,mysql,sql,pdo,Php,Mysql,Sql,Pdo,我应该如何在PDO准备的语句中使用MySQL的NOW(),或者我应该如何使用它,同时要记住,Apache服务器和数据库服务器可能存在轻微的当前时间不匹配(几秒钟),或者在极少数情况下可能存在时区差异 我的代码中有以下功能: try { $dbh->insert("users", array( "email" => $email, "password" => $password, "salt" => $salt,

我应该如何在PDO准备的语句中使用MySQL的
NOW()
,或者我应该如何使用它,同时要记住,Apache服务器和数据库服务器可能存在轻微的当前时间不匹配(几秒钟),或者在极少数情况下可能存在时区差异

我的代码中有以下功能:

try {
    $dbh->insert("users", array(
        "email" => $email,
        "password" => $password,
        "salt" => $salt,
        "ingame" => $ingame,
        "kiosk" => $kiosk
    ));
} catch (PDOException $ex) {
    error($ex);
}
这要求:

/**
 * Inserts data into a table. Data must be given in key-value pairs.
 * 
 * Example: $dbh->insert("table", array(
 *                                  "data1" => $data1,
 *                                  "data2" => $data2
 *                                  );
 * 
 * @param type $table   The table to insert to
 * @param type $keyvaluepairs   The key-value pairs.
 * @return type The statement that this query produced.
 */
public function insert($table, $keyvaluepairs) {
    $sql = "INSERT INTO `{$table}` (";
    $values_sql = ") VALUES(";
    $values = array();
    foreach ($keyvaluepairs as $key => $value) {
        $sql .= "`${key}`, ";
        $values_sql .= "?, ";
        $values[] = $value;
    }
    $query = substr($sql, 0, -2).substr($values_sql, 0, -2).")";
    return $this->query($query, $values);
}
//TODO update documentation to show it also handles associative arrays with bindvalue
/**
 * Can be called to create a query. Use either unnamed or named placeholders for the prepared statements.
 * 
 * Example: $dbh->query("INSERT INTO table (data1, data2) VALUES(?, ?)", array($data1, $data2));
 * 
 * @param type $query   The input query, including unnamed or named placeholders
 * @param type $values  The input values. If it's not an array, then it will be an one-element array
 * @return type The statement constructed by this query
 */
public function query($query, $values = array()) {
    if (!is_array($values)) {
        $values = array($values);
    }
    $statement = $this->dbh->prepare($query);
    $statement->setFetchMode(PDO::FETCH_OBJ);
    $i = 1;
    if (is_assoc($values)) {
        foreach ($values as $key => $value) {
            $statement->bindValue($key, $value);
        }
    }
    else {
        foreach ($values as $value) {
            $statement->bindValue($i++, $value);
        }
    }
    $statement->execute();
    return $statement;
}
这要求:

/**
 * Inserts data into a table. Data must be given in key-value pairs.
 * 
 * Example: $dbh->insert("table", array(
 *                                  "data1" => $data1,
 *                                  "data2" => $data2
 *                                  );
 * 
 * @param type $table   The table to insert to
 * @param type $keyvaluepairs   The key-value pairs.
 * @return type The statement that this query produced.
 */
public function insert($table, $keyvaluepairs) {
    $sql = "INSERT INTO `{$table}` (";
    $values_sql = ") VALUES(";
    $values = array();
    foreach ($keyvaluepairs as $key => $value) {
        $sql .= "`${key}`, ";
        $values_sql .= "?, ";
        $values[] = $value;
    }
    $query = substr($sql, 0, -2).substr($values_sql, 0, -2).")";
    return $this->query($query, $values);
}
//TODO update documentation to show it also handles associative arrays with bindvalue
/**
 * Can be called to create a query. Use either unnamed or named placeholders for the prepared statements.
 * 
 * Example: $dbh->query("INSERT INTO table (data1, data2) VALUES(?, ?)", array($data1, $data2));
 * 
 * @param type $query   The input query, including unnamed or named placeholders
 * @param type $values  The input values. If it's not an array, then it will be an one-element array
 * @return type The statement constructed by this query
 */
public function query($query, $values = array()) {
    if (!is_array($values)) {
        $values = array($values);
    }
    $statement = $this->dbh->prepare($query);
    $statement->setFetchMode(PDO::FETCH_OBJ);
    $i = 1;
    if (is_assoc($values)) {
        foreach ($values as $key => $value) {
            $statement->bindValue($key, $value);
        }
    }
    else {
        foreach ($values as $value) {
            $statement->bindValue($i++, $value);
        }
    }
    $statement->execute();
    return $statement;
}
我的职责是:

function is_assoc($array) {
    return (bool)count(array_filter(array_keys($array), 'is_string'));
}
因此,这里的交易是,我不能使用自定义的
MySQL
查询进行插入,因为为了方便起见,我封装了这些查询,但我仍然希望能够插入
NOW()
,而不使用
时间戳
/
当前的时间戳()

我希望您理解,这个问题需要一个解释性的答案,因为我已经阅读了“正常”答案,并表明它们不满足我的需要

更新:我添加了
const SQL\u NOW=1
到我的
DBH
类,但是现在我想修改
insert
如下:

public function insert($table, $keyvaluepairs) {
    $sql = "INSERT INTO `{$table}` (";
    $values_sql = ") VALUES(";
    $values = array();
    foreach ($keyvaluepairs as $key => $value) {
        if ($value == SELF::SQL_NOW) {
            $sql .= "NOW(), ";
        }
        else {
            $sql .= "`${key}`, ";
            $values_sql .= "?, ";
            $values[] = $value;
        }
    }
    $query = substr($sql, 0, -2).substr($values_sql, 0, -2).")";
    return $this->query($query, $values);
}
function pInsertFunc($action, $table, $values, $sqlfunctions)
{

    global $pdb;

    // There's no way to pass an SQL function like "NOW()" as a PDO parameter,
    // so this function builds the query string with those functions.  $values
    // and $sqlfunctions should be key => value arrays, with column names
    // as keys.  The $values values will be passed in as parameters, and the
    // $sqlfunction values will be made part of the query string.

    $value_columns = array_keys($values);
    $sqlfunc_columns = array_keys($sqlfunctions);
    $columns = array_merge($value_columns, $sqlfunc_columns);

    // Only $values become ':paramname' PDO parameters.
    $value_parameters = array_map(function($col) {return (':' . $col);}, $value_columns);
    // SQL functions go straight in as strings.
    $sqlfunc_parameters = array_values($sqlfunctions);
    $parameters = array_merge($value_parameters, $sqlfunc_parameters);

    $column_list = join(', ', $columns);
    $parameter_list = join(', ', $parameters);

    $query = "$action $table ($column_list) VALUES ($parameter_list)";

    $stmt = $pdb->prepare($query);
    $stmt->execute($values);

}
$values = array(
    'ID' => NULL,
    'name' => $username,
    'address' => $address,
);

$sqlfuncs = array(
    'date' => 'NOW()',
);

pInsertFunc("INSERT INTO", "addresses", $values, $sqlfuncs);
INSERT INTO addresses (ID, name, address, date) VALUES (:ID, :name, :address, NOW())
这可能是一个合适的解决方案,但是我现在不能将
1
用作
SQL\u
值,因为如果我想插入一个整数
1
,它就会失败。如果我使用这个解决方案,那么
SQL\u现在有什么价值?甚至可以不给它任何价值吗?

好问题

这是一个完美的例子,清楚地说明了为什么所有这些旨在取代SQL的众多
insert()、update()
和所有其他东西在设计上都是错误的

现在()不是您将面临的唯一问题。仅仅因为SQL并不像乍一看那样是一种愚蠢的语言。它是故意发明的。几十年来,它的可靠性得到了证明。这意味着,在学习PHP时,编写整个SQL并不是那么容易

因此,您可以做的最好的事情是保持SQL的原样。

你真正需要的是一两个助手函数。使重复的任务自动化。仅此而已。而SQL必须保持原样。这将允许您使用它的所有功能,包括使用函数、带参数的函数(!)、查询修饰符(如“插入忽略”或扩展语法(如联接)

在使用PDO的情况下,它不是那么简单,而是可行的

但是,唯一正确的解决方案是为SET语句使用特殊类型的占位符

$data = array(
        "email"    => $email,
        "password" => $password,
        "salt"     => $salt,
        "ingame"   => $ingame,
        "kiosk"    => $kiosk,
);
$dbh->query("INSERT INTO ?n SET reg = NOW(), ?u","users", $data);
只要一句话就可以解决所有这些混乱和许多其他问题。
只需一个
query()
方法即可运行您想要的任何查询,甚至
替换为

更新

看看你在干什么! 你在计划你的课程来简化事情。但是现在你正在使它变得越来越复杂。最终,你会有一个庞大的巨人,它对许多异常的语法不一致,甚至连它的创建者和其他人都难以理解。而且仍然不允许您运行一些查询


请在为时已晚之前重新考虑您的设计。

如果您向它传递一个包含所需的所有column=>SQLfunction值的附加参数,您可以编写一个包装器来实现这一点

我的看起来像这样:

public function insert($table, $keyvaluepairs) {
    $sql = "INSERT INTO `{$table}` (";
    $values_sql = ") VALUES(";
    $values = array();
    foreach ($keyvaluepairs as $key => $value) {
        if ($value == SELF::SQL_NOW) {
            $sql .= "NOW(), ";
        }
        else {
            $sql .= "`${key}`, ";
            $values_sql .= "?, ";
            $values[] = $value;
        }
    }
    $query = substr($sql, 0, -2).substr($values_sql, 0, -2).")";
    return $this->query($query, $values);
}
function pInsertFunc($action, $table, $values, $sqlfunctions)
{

    global $pdb;

    // There's no way to pass an SQL function like "NOW()" as a PDO parameter,
    // so this function builds the query string with those functions.  $values
    // and $sqlfunctions should be key => value arrays, with column names
    // as keys.  The $values values will be passed in as parameters, and the
    // $sqlfunction values will be made part of the query string.

    $value_columns = array_keys($values);
    $sqlfunc_columns = array_keys($sqlfunctions);
    $columns = array_merge($value_columns, $sqlfunc_columns);

    // Only $values become ':paramname' PDO parameters.
    $value_parameters = array_map(function($col) {return (':' . $col);}, $value_columns);
    // SQL functions go straight in as strings.
    $sqlfunc_parameters = array_values($sqlfunctions);
    $parameters = array_merge($value_parameters, $sqlfunc_parameters);

    $column_list = join(', ', $columns);
    $parameter_list = join(', ', $parameters);

    $query = "$action $table ($column_list) VALUES ($parameter_list)";

    $stmt = $pdb->prepare($query);
    $stmt->execute($values);

}
$values = array(
    'ID' => NULL,
    'name' => $username,
    'address' => $address,
);

$sqlfuncs = array(
    'date' => 'NOW()',
);

pInsertFunc("INSERT INTO", "addresses", $values, $sqlfuncs);
INSERT INTO addresses (ID, name, address, date) VALUES (:ID, :name, :address, NOW())
像这样使用它:

public function insert($table, $keyvaluepairs) {
    $sql = "INSERT INTO `{$table}` (";
    $values_sql = ") VALUES(";
    $values = array();
    foreach ($keyvaluepairs as $key => $value) {
        if ($value == SELF::SQL_NOW) {
            $sql .= "NOW(), ";
        }
        else {
            $sql .= "`${key}`, ";
            $values_sql .= "?, ";
            $values[] = $value;
        }
    }
    $query = substr($sql, 0, -2).substr($values_sql, 0, -2).")";
    return $this->query($query, $values);
}
function pInsertFunc($action, $table, $values, $sqlfunctions)
{

    global $pdb;

    // There's no way to pass an SQL function like "NOW()" as a PDO parameter,
    // so this function builds the query string with those functions.  $values
    // and $sqlfunctions should be key => value arrays, with column names
    // as keys.  The $values values will be passed in as parameters, and the
    // $sqlfunction values will be made part of the query string.

    $value_columns = array_keys($values);
    $sqlfunc_columns = array_keys($sqlfunctions);
    $columns = array_merge($value_columns, $sqlfunc_columns);

    // Only $values become ':paramname' PDO parameters.
    $value_parameters = array_map(function($col) {return (':' . $col);}, $value_columns);
    // SQL functions go straight in as strings.
    $sqlfunc_parameters = array_values($sqlfunctions);
    $parameters = array_merge($value_parameters, $sqlfunc_parameters);

    $column_list = join(', ', $columns);
    $parameter_list = join(', ', $parameters);

    $query = "$action $table ($column_list) VALUES ($parameter_list)";

    $stmt = $pdb->prepare($query);
    $stmt->execute($values);

}
$values = array(
    'ID' => NULL,
    'name' => $username,
    'address' => $address,
);

$sqlfuncs = array(
    'date' => 'NOW()',
);

pInsertFunc("INSERT INTO", "addresses", $values, $sqlfuncs);
INSERT INTO addresses (ID, name, address, date) VALUES (:ID, :name, :address, NOW())
生成的查询字符串如下所示:

public function insert($table, $keyvaluepairs) {
    $sql = "INSERT INTO `{$table}` (";
    $values_sql = ") VALUES(";
    $values = array();
    foreach ($keyvaluepairs as $key => $value) {
        if ($value == SELF::SQL_NOW) {
            $sql .= "NOW(), ";
        }
        else {
            $sql .= "`${key}`, ";
            $values_sql .= "?, ";
            $values[] = $value;
        }
    }
    $query = substr($sql, 0, -2).substr($values_sql, 0, -2).")";
    return $this->query($query, $values);
}
function pInsertFunc($action, $table, $values, $sqlfunctions)
{

    global $pdb;

    // There's no way to pass an SQL function like "NOW()" as a PDO parameter,
    // so this function builds the query string with those functions.  $values
    // and $sqlfunctions should be key => value arrays, with column names
    // as keys.  The $values values will be passed in as parameters, and the
    // $sqlfunction values will be made part of the query string.

    $value_columns = array_keys($values);
    $sqlfunc_columns = array_keys($sqlfunctions);
    $columns = array_merge($value_columns, $sqlfunc_columns);

    // Only $values become ':paramname' PDO parameters.
    $value_parameters = array_map(function($col) {return (':' . $col);}, $value_columns);
    // SQL functions go straight in as strings.
    $sqlfunc_parameters = array_values($sqlfunctions);
    $parameters = array_merge($value_parameters, $sqlfunc_parameters);

    $column_list = join(', ', $columns);
    $parameter_list = join(', ', $parameters);

    $query = "$action $table ($column_list) VALUES ($parameter_list)";

    $stmt = $pdb->prepare($query);
    $stmt->execute($values);

}
$values = array(
    'ID' => NULL,
    'name' => $username,
    'address' => $address,
);

$sqlfuncs = array(
    'date' => 'NOW()',
);

pInsertFunc("INSERT INTO", "addresses", $values, $sqlfuncs);
INSERT INTO addresses (ID, name, address, date) VALUES (:ID, :name, :address, NOW())

我可能有点固执,但我认为仅使用
insert()
我不打算为其他功能编写函数对于普通插入来说更容易,而
NOW()
是一个需要插入的普通值。不过,我确实同意不应该重写所有其他功能。我还为这个问题添加了我自己的“解决方案”(带有一个bug),如果您也能回答我的问题,我将不胜感激。@Downvoter:Care to explain?改天我将需要使用用户提供的数据调用一个函数,比如INET_ATON(:ip)。你的这种方法是一条无路可走的路。它是一种方便的辅助功能。它自动化了一些重复的任务。这就是全部。我觉得它很有用。这并不能阻止我在需要时使用SQL的全部功能。更不用说它非常容易进行SQL注入。只有允许用户在$values中定义键时,才有可能进行SQL注入,你可以看到我在这里没有这样做。$values中的所有值都将安全地传递到数据库,不会有SQL注入的风险。