坚持制作数据库插入类功能

时间:2016-03-30 14:06:54

标签: php pdo

我试图在PHP中创建一个基于OOP的论坛,目前我正在制作数据库类。特别是Iam坚持为Datatable类制作一个“通用”插入类函数(使用PDO btw)。

class DB
            {
                private $dbconn;

                public function __construct(){

                }

                protected function connect($dbname,  $dbhost='127.0.0.1', $dbuser='root', $dbpass=''){

                    try{
                     $this->dbconn = new PDO("mysql:host=$dbhost;dbname=$dbname;", $dbuser, $dbpass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'"));
                    }

                    catch(PDOException $e){
                        echo 'Connection failed: '.$e->getMessage()."<br />";
                    }
                }

                protected function disconnect(){
                    $this->dbconn = null;
                }

                public function insert($dbname, ){
                     $this->connect($dbname);

                    try{
                        # prepare
                        $sql = "INSERT INTO pdodemotable (firstname, lastname, age, reg_date) 
                          VALUES (?, ?, ?, now())";
                        $stmt = $dbconn->prepare($sql);
                        # the data we want to insert
                        $data = array($firstname, $lastname, $age);
                        # execute width array-parameter
                        $stmt->execute($data);

                        echo "New record created successfully";
                    }
                    catch(PDOException $e){
                        echo $sql . "<br>" . $e->getMessage();
                    }
                }
            }

插入功能就像你看到未完成的那样。我无法弄清楚如何使插入函数适应任意数量的参数,任意数量的数据库列和任何表。现在函数中的代码来自我使用过程编程的其他项目之一。它首次将OOP与数据库结合使用。

我是OOP和PDO的新手。必须有某种方法或功能可以帮助我,我失踪了。我现在看到的唯一解决方案是使用ridicoulus数量的字符串处理和if语句......它不能是最好的解决方案......必须有一个更简单的方法......

2 个答案:

答案 0 :(得分:1)

首先注意 - 您不需要插入方法的$dbname参数,而应该是构造函数参数:

class DB {

    private $dbconn;

    public function __construct($dbname, $dbhost='127.0.0.1', $dbuser='root', $dbpass='') {
        // also don't catch the error here, let it propagate, you will clearly see
        // what happend from the original exception message
        $this->dbconn = new PDO("mysql:host=$dbhost;dbname=$dbname;", $dbuser, $dbpass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'"));
    }

    ...

}

对于insert方法 - 首先尝试想象它将如何使用。 例如,它可以是这样的:

$db = new DB('mydb');
$db->insert('mytable', array('firstname'=>'Pete', 'lastname'=>'Smith'));

然后您可以将表名和数据(键/值)传递给方法:

public function insert($table, $data) {
    // again, no need to try / catch here, let the exceptions
    // do their job
    // handle errors only in the case you are going to fix them
    // and not just to ingnore them and 'echo', this can lead to much worse problems
    // see the explanation below regarding the `backtick` method
    $table = $this->backtick($table);
    $fields = array();
    $placeholders = array();
    $values = array();
    foreach($data as $key=>$value) {
        $fields[] = $this->backtick($key);
        // you can also process some special values like 'now()' here
        $placeholders[] = '?';
    }
    $fields = implode($fields, ','); // firstname, lastname
    $placeholders = implode($placeholders, ','); // ?, ?
    $sql = "INSERT INTO $table ($fields) values ($placeholders)";
    $stmt = $this->dbconn->prepare($sql);
    $stmt->execute(array_values($data));
}


public function update($table, $id, $data) {
    $table = $this->backtick($table);
    $fields = array();
    foreach($data as $key=>$value) {
        $fields[] = $this->backtick($key) . " = ?";
    }
    $fields = implode($fields, ','); // firstname=?, lastname=?
    $sql = "UPDATE $table SET $fields where id=?";
    $stmt = $this->dbconn->prepare($sql);
    $data['id'] = $id;
    $stmt->execute(array_values($data));
    if ($stmt->execute(array_values($data)) === false) {
        print 'Error: ' . json_encode($stmt->errorInfo()). PHP_EOL;
    }
    while ($row = $stmt->fetchAll()) {
        print json_encode($row) . PHP_EOL;
    }
}

private function backtick($key) {
    return "`".str_replace("`","``",$key)."`";
}

另一种方法是创建一个单独的对象,它将代表一个表行(ActiveRecord模式)。 使用此类对象的代码可能如下所示:

$person = new Person($db);
$person->firstName = 'Pete';
$person->lastName = 'Smith';
$person->save(); // insert or update the table row

可能的SQL注入漏洞更新

我还添加了updatebacktick方法来说明可能的SQL注入。 如果没有backtick,则可能会使用以下内容调用update

$db->updateUnsafe('users', 2, array(
    "name=(SELECT'bad guy')WHERE`id`=1#"=>'', 
    'name'=>'user2', 'password'=>'text'));

这将导致这样的SQL语句:

UPDATE users SET name=(SELECT'bad guy')WHERE`id`=1# = ?,name = ?,password = ? where id=?

因此,我们不会更新ID为2的用户的数据,而是更改ID为1的用户的名称。 由于backtick方法,上述语句将失败,并显示Unknown column 'name=(SELECT'bad guy')WHERE id =2#' in 'field list'Here is我的测试的完整代码。

无论如何,这可能无法保护您免受任何可能的SQL注入,因此最好不要将用户输入用于已知参数,如表名和字段名。

不要执行$db->insert('mytable', $_POST)之类的操作,而是执行$db->insert('mytable', array('first'=>$_POST['first']))

答案 1 :(得分:-1)

尝试传递带有数组的参数,然后,在方法insert中,做一个foreach。

类似的东西:

$data['first_name'] = 'your name';
...
$data['twentieth_name'] = 'twentieth name';

foreach( $data as $key => $value )
    $final_array[':'.$key] = $value;

$stmt->execute( $final_array );
相关问题