我试图在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语句......它不能是最好的解决方案......必须有一个更简单的方法......
答案 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注入漏洞更新
我还添加了update
和backtick
方法来说明可能的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 );