1

我正在创建一个自定义类,以使连接和使用 mysql 通常更容易。我已经创建了许多功能,除了一个部分之外,所有功能都可以正常工作。我似乎无法弄清楚如何确定一个字符串是一个实际的字符串还是一个 mysql 函数,以便在它周围加上引号。我整理了一个可以传递两个参数的函数,它将插入到数据库中。第一个参数是要插入的表,而第二个参数是列、值对的数组。也许这个代码示例将帮助您了解更多。注意:我已经转义了所有字符串并删除了该代码以显示问题的简单性。

function insert($table,array $array){
    $table = "`".$table."`";
    $columns = "";
    $values = "";
    foreach($array as $key => $value){
        $columns = ($columns=="") ? "`".$key."`" : $columns.", `".$key."`";
        if($value===NULL || $value=="NULL"){
            $value = "NULL";
        } else {
            $value = "'".$value."'";
        }
        $values = ($values=="") ? "".$value."" : $values.", ".$value."";
    }
    $query = "INSERT INTO $table ($columns) VALUES ($values)";
    return $this->query($query);
}

这是两个不同用途的示例以及预期结果或每个

$data = array(
  "first_name"=>"John",
  "last_name"=>"Doe",
  "entry_date"=>"2013-08-26"
);
$MyClass->insert("people",$data);

会执行

INSERT INTO `people` (`first_name`,`last_name`,`entry_date`) VALUES ('John','Doe','2013-08-26')

这是预期的但是以下用途:

$data = array(
  "first_name"=>"John",
  "last_name"=>"Doe",
  "entry_date"=>"NOW()"
);
$MyClass->insert("people",$data);

将执行为

INSERT INTO `people` (`first_name`,`last_name`,`entry_date`) VALUES ('John','Doe','NOW()')

这将不起作用,因为如果 MySQL 函数带有引号,则不会对其进行操作。我知道这可能是一个小的安全风险,因为如果没有被捕获,它将允许用户使用功能。有没有更好的方法来做到这一点,或者在这样的类插入函数中不允许使用 MySQL 函数?如果有人整理了一个正则表达式来查找并允许 mysql 函数,那么这可能是一个解决方案。如果不存在这样的正则表达式,那么一种可能性是从头开始编写一个我不太擅长的...

编辑:

同时我将使用的另一个解决方案是在形成数组时使用 PHP 获取日期。如果可能的话,我还是想使用 MySQL 函数。这是我当前的代码,它解决了这个问题,但不是我喜欢的:

$data = array(
  "first_name"=>"John",
  "last_name"=>"Doe",
  "entry_date"=>date('Y-m-d H:i:s'),
);
$MyClass->insert("people",$data);
4

2 回答 2

2

几年前,我实现了一个功能来执行您为 Zend Framework 1.0 描述的功能。

我通过区分纯字符串标量和包含字符串的对象来解决它。

$data = array(
  "first_name"=>"John",
  "last_name"=>"Doe",
  "entry_date"=>new Zend_Db_Expr("NOW()")
);
$MyClass->insert("people",$data);

这样,我的框架可以区分我打算被视为 SQL 字符串(即引用)的 PHP 字符串与在对象中汇总的字符串之间的区别。

if($value===NULL || $value=="NULL"){
    $value = "NULL";
} else if ($value instanceof Zend_Db_Expr) {
    $value = $value->__toString(); // no quotes
} else {
    $value = "'".$value."'";
}

PS:有些人可能会建议您使用查询参数而不是像您那样连接转义变量。我同意这个建议,但它与你原来的问题几乎没有关系,所以我不会深入探讨。还有许多其他 StackOverflow 问题涉及使用查询参数。


回复您的评论:

您可以使用正则表达式来匹配NOW()所有其他 MySQL 函数并对其进行特殊处理,但是如何插入文字字符串“NOW()”(不是该名称的函数的结果)?

答:你不能——就像你不能在你当前的代码中插入文字字符串“NULL”一样,因为你已经把这个词当作一个特殊情况。

您需要一些方法来区分 SQL 表达式NOW()和“NOW()”。仅仅因为您今天不需要将该字符串插入到您的数据库中并不意味着您永远不需要该功能。请记住,您正在设计此 insert() 函数,以便针对当前或未来的 任何表进行一般使用。

你实际上是在设计一个框架。

于 2013-08-26T20:30:43.797 回答
0

感谢@phpisuber1 的正则表达式if(preg_match("/^[A-Z_]+\(.*?\)/", $value)) { // Mysql function },感谢@BillKarwin,我和你们两个一起创建了一个结合你们输入的解决方案。

对我来说,解决方案是在我的类函数中添加更多参数,并使用默认值告诉函数是否插入为 MySQL 函数或字符串,以及是否插入为NULL字符串或字符串,"NULL"请参见下面的新函数:

/**
 * @param string $table the table to insert array into
 * @param array $array contains column => value pairs values may be MySQL Function
 * @param bool $mysql_functions true to insert mysql functions as function, false to insert mysql functions as string
 * @param bool $null_string_is_null true to insert string "NULL" as NULL; false to insert string "NULL" as string "NULL"
 * @param bool $empty_string_is_null true to insert string "" as NULL; false to insert string "" as string ""
 * @return bool Returns FALSE on failure. For successful queries will return TRUE.
 */
function insert($table,array $array,$mysql_functions = false,$null_string_is_null = true,$empty_string_is_null = false){
    $table = "`".$table."`";
    $columns = "";
    $values = "";
    foreach($array as $key => $value){
        $columns = ($columns=="") ? "`".$key."`" : $columns.", `".$key."`";
        if($value===NULL || ($value=="NULL" && $null_string_is_null) || ($value=="" && $empty_string_is_null)){
            $value = "NULL";
        } else if(preg_match("/^[A-Z_]+\(.*?\)/", $value) && $mysql_functions) {
            $value = "".$value."";
        } else {
            $value = "'".$value."'";
        }
        $values = ($values=="") ? "".$value."" : $values.", ".$value."";
    }
    $query = "INSERT INTO $table ($columns) VALUES ($values)";
    return $this->query($query);
}

这又不是完整的功能,因为出于安全原因我省略了部分功能,但这是一个功能版本。我将研究查询参数,看看它是否会增加这个函数和其他函数的安全性,而不是连接转义字符串。此函数的默认参数适用于我的默认使用,并且可以更改以备将来使用。总的来说,我认为这是最好的解决方案。如果您不这么认为,我很乐意阅读您的评论。

于 2013-08-27T15:36:40.730 回答