I've been building a PDO PHP DB class and I just wonder if someone could give me some feedback (regarding security, how the code is written and how I can optimize it).
This class is not finished function wise, but I would like the code I have currently to be reviewed.
<?php
Class DB {
public static $init = null;
private $_pdo = null,
$_query = null,
$_sql = null,
$_bounds = null, // array
$_error = false,
$_select = array(
"SQL" => null,
"BOUNDS" => null),
$_insert = array(
"SQL" => null,
"BOUNDS" => null),
$_update = array(
"SQL" => null,
"BOUNDS" => null),
$_delete = array(
"SQL" => null,
"BOUNDS" => null),
$_where = null,
$_results = null, // array
$_countRow = false,
$_countCol = false;
public static function init() {
if(!isset(static::$init)) {
static::$init = new DB();
}
return static::$init;
}
private function __construct() {
try {
$this->_pdo = new PDO('mysql:host=' . Config::get('mysql/host') . ';dbname=' . Config::get('mysql/db'), Config::get('mysql/username'), Config::get('mysql/password'));
$this->_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->_pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
} catch(PDOException $e) {
$this->_error = $e->getMessage();
return $this->_error;
}
}
public function query() {
}
public function prepare() {
// create sql-string
$this->_select["SQL"] == null ? $this->_sql .= $this->_select["SQL"] : $this->_sql .= "{$this->_select['SQL']}; ";
$this->_insert["SQL"] == null ? $this->_sql .= $this->_insert["SQL"] : $this->_sql .= "{$this->_insert['SQL']}; ";
$this->_update["SQL"] == null ? $this->_sql .= $this->_update["SQL"] : $this->_sql .= "{$this->_update['SQL']}; ";
$this->_delete["SQL"] == null ? $this->_sql .= $this->_delete["SQL"] : $this->_sql .= "{$this->_delete['SQL']}; ";
// create bounds-array()
$selects = array();
$inserts = array();
$updates = array();
$deletes = array();
if(!$this->_select["BOUNDS"] == null) {
$selects = explode(", ", $this->_select["BOUNDS"]);
}
if(!$this->_insert["BOUNDS"] == null) {
$inserts = explode(", ", $this->_insert["BOUNDS"]);
}
if(!$this->_update["BOUNDS"] == null) {
$updates = explode(", ", $this->_update["BOUNDS"]);
}
if(!$this->_delete["BOUNDS"] == null) {
$deletes = explode(", ", $this->_delete["BOUNDS"]);
}
$this->_bounds = array_merge($selects, $inserts, $updates, $deletes);
if($this->_query = $this->_pdo->prepare($this->_sql)) {
if(!$this->_bounds == null) {
// check if bounds array have empty elements and delete it
$x = 0;
foreach($this->_bounds as $bounds) {
if(empty($this->_bounds[$x])) {
unset($this->_bounds[$x]);
}
$x++;
}
$x = 1;
foreach($this->_bounds as $keys) {
$this->_query->bindValue($x, $keys);
$x++;
}
} else {
$this->_feedback = "Fail in Method: BOUNDS()";
}
}
return $this;
}
public function execute() {
if($this->_query->execute()) {
if(substr($this->_select["SQL"], 0, 6) == "SELECT") {
// finding amount of SELECTS in prepare query
$check = explode("; ", $this->_select["SQL"]);
$count = count($check);
$x = 0;
while($count > $x) {
// fetching all
$this->_results[] = $this->_query->fetchAll();
$this->_query->nextRowset();
$x++;
}
$this->_countRow = $this->_query->rowCount();
$this->_countCol = $this->_query->columnCount();
}
return $this;
}
}
public function select($table, $what = false) {
$this->_select["BOUNDS"] == null ? $this->_select["BOUNDS"] : $this->_select["BOUNDS"] .= ", ";
$this->_select["SQL"] == null ? $this->_select["SQL"] : $this->_select["SQL"] .= "; ";
$what == false ? $what = "*" : $what;
$this->_select["SQL"] .= "SELECT {$what} FROM {$table}";
$this->_where = "SELECT";
return $this;
}
public function insert($table, $fields = array()) {
$this->_insert["BOUNDS"] == null ? $this->_insert["BOUNDS"] : $this->_insert["BOUNDS"] .= ", ";
$this->_insert["SQL"] == null ? $this->_insert["SQL"] : $this->_insert["SQL"] .= "; ";
$keys = array_keys($fields);
$values = null;
$x = 1;
foreach($fields as $value) {
$values .= "?";
if($x < count($fields)) {
$values .= ", ";
}
$x++;
}
$this->_insert["SQL"] .= "INSERT INTO {$table} (`" . implode('`, `', $keys) . "`) VALUES ({$values})";
$this->_insert["BOUNDS"] .= implode(", ", array_values($fields));
return $this;
}
public function update($table, $fields = array()) {
$this->_update["BOUNDS"] == null ? $this->_update["BOUNDS"] : $this->_update["BOUNDS"] .= ", ";
$this->_update["SQL"] == null ? $this->_update["SQL"] : $this->_update["SQL"] .= "; ";
$set = null;
$x = 1;
foreach($fields as $name => $value) {
$set .= "{$name} = ?";
$this->_update["BOUNDS"] .= "{$value}, ";
if($x < count($fields)) {
$set .= ", ";
}
$x++;
}
$this->_update["SQL"] .= "UPDATE {$table} SET {$set}";
$this->_where = "UPDATE";
return $this;
}
public function delete($table, $fields = array()) {
$this->_delete["SQL"] == null ? $this->_delete["SQL"] : $this->_delete["SQL"] .= "; ";
$this->_delete["BOUNDS"] == null ? $this->_delete["BOUNDS"] : $this->_delete["BOUNDS"] .= ", ";
$this->_delete["SQL"] .= "DELETE FROM {$table}";
$this->_where = "DELETE";
return $this;
}
public function where($fields = array(), $what = false) {
$what == false ? $what = " AND " : $what = " {$what} ";
$x = 1;
$operators = array("<", "<=", "=", ">=", ">");
if($this->_where == "SELECT") {
$this->_select["SQL"] .= " WHERE ";
} elseif($this->_where == "UPDATE") {
$this->_update["SQL"] .= " WHERE ";
} elseif($this->_where == "DELETE") {
$this->_delete["SQL"] .= " WHERE ";
}
foreach($fields as $field) {
$key = $field[0];
$operator = $field[1];
$value = $field[2];
if(in_array($operator, $operators)) {
if($this->_where == "SELECT") {
$this->_select["SQL"] .= "{$key} {$operator} ?";
$this->_select["BOUNDS"] .= $value;
if($x < count($fields)) {
$this->_select["SQL"] .= $what;
$this->_select["BOUNDS"] .= ", ";
}
} elseif($this->_where == "UPDATE") {
$this->_update["SQL"] .= "{$key} {$operator} ?";
$this->_update["BOUNDS"] .= $value;
if($x < count($fields)) {
$this->_update["SQL"] .= $what;
$this->_update["BOUNDS"] .= ", ";
}
} elseif($this->_where == "DELETE") {
$this->_delete["SQL"] .= "{$key} {$operator} ?";
$this->_delete["BOUNDS"] .= $value;
if($x < count($fields)) {
$this->_delete["SQL"] .= $what;
$this->_delete["BOUNDS"] .= ", ";
}
}
}
$x++;
}
return $this;
}
public function andWhere($fields = array(), $what = false) {
$what == false ? $what = " AND " : $what = " {$what} ";
$x = 1;
$operators = array("<", "<=", "=", ">=", ">");
if($this->_where == "SELECT") {
$this->_select["SQL"] .= " AND ";
$this->_select["BOUNDS"] .= ", ";
} elseif($this->_where == "UPDATE") {
$this->_update["SQL"] .= " AND ";
$this->_update["BOUNDS"] .= ", ";
} elseif($this->_where == "DELETE") {
$this->_delete["SQL"] .= " AND ";
$this->_delete["BOUNDS"] .= ", ";
}
foreach($fields as $field) {
$key = $field[0];
$operator = $field[1];
$value = $field[2];
if(in_array($operator, $operators)) {
if($this->_where == "SELECT") {
$this->_select["SQL"] .= "{$key} {$operator} ?";
$this->_select["BOUNDS"] .= $value;
if($x < count($fields)) {
$this->_select["SQL"] .= $what;
$this->_select["BOUNDS"] .= ", ";
}
} elseif($this->_where == "UPDATE") {
$this->_update["SQL"] .= "{$key} {$operator} ?";
$this->_update["BOUNDS"] .= $value;
if($x < count($fields)) {
$this->_update["SQL"] .= $what;
$this->_update["BOUNDS"] .= ", ";
}
} elseif($this->_where == "DELETE") {
$this->_delete["SQL"] .= "{$key} {$operator} ?";
$this->_delete["BOUNDS"] .= $value;
if($x < count($fields)) {
$this->_delete["SQL"] .= $what;
$this->_delete["BOUNDS"] .= ", ";
}
}
}
$x++;
}
return $this;
}
public function orWhere($fields = array(), $what = false) {
$what == false ? $what = " AND " : $what = " {$what} ";
$x = 1;
$operators = array("<", "<=", "=", ">=", ">");
if($this->_where == "SELECT") {
$this->_select["SQL"] .= " OR ";
$this->_select["BOUNDS"] .= ", ";
} elseif($this->_where == "UPDATE") {
$this->_update["SQL"] .= " OR ";
$this->_update["BOUNDS"] .= ", ";
} elseif($this->_where == "DELETE") {
$this->_delete["SQL"] .= " OR ";
$this->_delete["BOUNDS"] .= ", ";
}
foreach($fields as $field) {
$key = $field[0];
$operator = $field[1];
$value = $field[2];
if(in_array($operator, $operators)) {
if($this->_where == "SELECT") {
$this->_select["SQL"] .= "{$key} {$operator} ?";
$this->_select["BOUNDS"] .= $value;
if($x < count($fields)) {
$this->_select["SQL"] .= $what;
$this->_select["BOUNDS"] .= ", ";
}
} elseif($this->_where == "UPDATE") {
$this->_update["SQL"] .= "{$key} {$operator} ?";
$this->_update["BOUNDS"] .= $value;
if($x < count($fields)) {
$this->_update["SQL"] .= $what;
$this->_update["BOUNDS"] .= ", ";
}
} elseif($this->_where == "DELETE") {
$this->_delete["SQL"] .= "{$key} {$operator} ?";
$this->_delete["BOUNDS"] .= $value;
if($x < count($fields)) {
$this->_delete["SQL"] .= $what;
$this->_delete["BOUNDS"] .= ", ";
}
}
}
$x++;
}
return $this;
}
public function results() {
// return all
}
public function error() {
return $this->_error;
}
public function countRow() {
// return numbers of rows
}
public function countCol() {
// return numbers of cols
}
}
To use:
The where()
, andWhere()
and orWhere()
methods can be chained. You can use the where()
on its own if that's all you need, but andWhere()
and orWhere()
need to be chained on where()
. You can modify AND/OR inside where()
, andWhere()
and orWhere()
(AND is default inside all of them).
All results from selects will be fetched inside execute()
and saved in results array.
Some examples:
// SELECT:
select("users")->where(array(array("username", "=", "name"), array("password", "=", "12345")), "AND")->orWhere(array(array("username", "=", "name2"), array("password", "=", "12345")))->andWhere(array(array("email", "=", "[email protected]"), array("age", "=", "1")), "OR");
// SELECT * FROM users WHERE username = ? AND password = ? OR username = ? AND password = ? AND email = ? OR age = ?
select("users")->where(array(array("username", "=", "thename")));
// SELECT * FROM users WHERE username = ?
select("users");
// SELECT * FROM users
// INSERT:
insert("users", array("username" => "name", "password" => "12345"));
// INSERT INTO users (`username`, `password`) VALUES (?, ?)
// UPDATE:
update("users", array("username" => "newname", "password" => "12345"))->where(array(array("username", "=", "oldname"), array("password", "=", "1")))->andWhere(array(array("email", "=", "[email protected]"), array("email", "=", "[email protected]")), "OR")->orWhere(array(array("username", "=", "name2"), array("age", "=", "1")));
// UPDATE users SET username = ?, password = ? WHERE username = ? AND password = ? AND email = ? OR email = ? OR username = ? AND age = ?
update("users", array("username" => "newname")->where(array(array("username", "=", "oldname"), array("password", "=", "1")));
// UPDATE users SET username = ?, password = ? WHERE username = ? AND password = ?
// DELETE:
delete("users")->where(array(array("username", "=", "oldname"), array("password", "=", "1")))->andWhere(array(array("email", "=", "[email protected]"), array("email", "=", "[email protected]")), "OR")->orWhere(array(array("username", "=", "name2"), array("age", "=", "1")));
// DELETE FROM users WHERE username = ? AND password = ? AND email = ? OR email = ? OR username = ? AND age = ?
delete("users")->where(array(array("username", "=", "oldname"), array("password", "=", "1")));
// DELETE FROM users WHERE username = ? AND password = ?
// PREPARE AND EXECUTE
prepare()->execute();
// prepare() binding values and execute() executes everything above at once.
AND
andOR
clauses, I'm also using parentheses. E.g.SELECT * FROM table WHERE col1 = v1 AND ( col2 = v2 OR col3 = v3 )
. This might makeorWhere
andandWhere
less useful than they first seem. \$\endgroup\$