Last active
June 8, 2017 15:26
-
-
Save postpostscript/045f588c1790fbcc4ea52e2429623fad to your computer and use it in GitHub Desktop.
PDO safe query generation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Args: | |
// SafeQuery::safe_query($table, $select_fields = array("*"), $where = array(), $order_by = array(), $limit = array(0,100)) | |
$ops = array( | |
"equals" => array("="), | |
"not_equals" => array("!="), | |
"greater_than" => array(">"), | |
"greater_than_or_equal" => array(">="), | |
"less_than" => array("<"), | |
"less_than_or_equal" => array("<="), | |
"like" => array("~="), | |
"in" => array(), | |
"and" => array("&&"), | |
"or" => array("||"), | |
"not" => array("!"), | |
"field" => array(), | |
"arg" => array(), | |
); | |
$operator_map = array(); | |
foreach ($ops as $key => $aliases) { | |
$operator_map[$key] = $key; | |
if (!count($aliases)) continue; | |
foreach ($aliases as $alias) { | |
$operator_map[$alias] = $key; | |
} | |
} | |
class SafeQuery { | |
static function get_op($op) { | |
global $operator_map; | |
if (!isset($operator_map[$op])) return; | |
return $operator_map[$op]; | |
} | |
static function backtick($table) { | |
if (!$table) return; | |
return "`".str_replace("`","``",$table)."`"; | |
} | |
static function safe_expr($field1, $op, $field2 = "", $queries = array(), $query_args = array()) { | |
if (!is_array($queries)) $queries = array(); | |
if (!is_array($query_args)) $query_args = array(); | |
$op = "op_" . self::get_op($op); | |
if (!is_callable("self::$op") && $field1) { | |
$op = "op_field"; | |
} | |
if (is_callable("self::$op")) { | |
$res = self::$op($field1, $field2); | |
$queries[] = $res[0]; | |
if (count($res[1])) { | |
$query_args = array_merge($query_args, $res[1]); | |
} | |
} | |
return array($queries, $query_args); | |
} | |
static function safe_select($select_fields = array("*")) { | |
$raw_select_fields = array("*"); | |
$select_query = ""; | |
foreach ($select_fields as $k => $field) { | |
if ($k) $select_query .= ", "; | |
if (in_array($field, $raw_select_fields) !== FALSE) { | |
$select_query .= $field; | |
} else { | |
$select_query .= self::backtick($field); | |
} | |
} | |
return $select_query; | |
} | |
static function safe_where($where = array(), $query_args = array()) { | |
if (empty($where)) return array("", $query_args); | |
$where_exprs = array(); | |
foreach ($where as $expr) { | |
list($where_exprs, $query_args) = self::safe_expr($expr[0], $expr[1], $expr[2], $where_exprs, $query_args); | |
} | |
return array( | |
"WHERE " . implode(" AND ", $where_exprs), | |
$query_args, | |
); | |
} | |
static function safe_order_by($order_by = array(), $query_args = array()) { | |
if (empty($order_by)) return array("", $query_args); | |
$order_by_exprs = array(); | |
foreach ($order_by as $expr) { | |
list($order_by_exprs, $query_args) = self::safe_expr($expr[1], $expr[2], $expr[3], $order_by_exprs, $query_args); | |
$i = count($order_by_exprs) - 1; | |
if (strtolower($expr[0]) == "asc") { | |
$order_by_exprs[$i] .= " ASC"; | |
} else { | |
$order_by_exprs[$i] .= " DESC"; | |
} | |
} | |
return array( | |
"ORDER BY " . implode(",", $order_by_exprs), | |
$query_args, | |
); | |
} | |
static function safe_set($set_fields = array(), $query_args = array()) { | |
$set_exprs = array(); | |
foreach ($set_fields as $field => $val) { | |
$set_exprs[] = self::backtick($field) . " = ?"; | |
$query_args[] = $val; | |
} | |
return array( | |
"SET " . implode(", ", $set_exprs), | |
$query_args, | |
); | |
} | |
static function safe_limit($limit = array()) { | |
if (empty($limit)) return ""; | |
$limit = array_slice($limit, 0, 2); | |
$limit_query = "LIMIT "; | |
foreach ($limit as $k => $n) { | |
if ($k) $limit_query .= ","; | |
$limit_query .= (int) $n; | |
} | |
return $limit_query; | |
} | |
static function safe_query($table, $select_fields = array("*"), $where = array(), $order_by = array(), $limit = array()) { | |
$table = self::backtick($table); | |
$select_query = self::safe_select($select_fields); | |
$query_args = array(); | |
list($where_query, $query_args) = self::safe_where($where, $query_args); | |
list($order_by_query, $query_args) = self::safe_order_by($order_by, $query_args); | |
$limit_query = self::safe_limit($limit); | |
return array( | |
"SELECT $select_query FROM $table $where_query $order_by_query $limit_query", | |
$query_args, | |
); | |
} | |
static function safe_insert($table, $set_fields = array()) { | |
$table = self::backtick($table); | |
$query_args = array(); | |
list($set_query, $query_args) = self::safe_set($set_fields, $query_args); | |
return array( | |
"INSERT INTO $table $set_query", | |
$query_args, | |
); | |
} | |
static function safe_update($table, $set_fields = array(), $where = array(), $limit = array()) { | |
$table = self::backtick($table); | |
$query_args = array(); | |
list($set_query, $query_args) = self::safe_set($set_fields, $query_args); | |
list($where_query, $query_args) = self::safe_where($where, $query_args); | |
$limit_query = self::safe_limit($limit); | |
return array( | |
"UPDATE $table $set_query $where_query $limit_query", | |
$query_args, | |
); | |
} | |
static function safe_delete($table, $where = array(), $limit = array()) { | |
$table = self::backtick($table); | |
$query_args = array(); | |
list($where_query, $query_args) = self::safe_where($where, $query_args); | |
$limit_query = self::safe_limit($limit); | |
return array( | |
"DELETE FROM $table $where_query $limit_query", | |
$query_args, | |
); | |
} | |
// operator functions | |
static function op_equals($field, $value) { | |
return array( | |
self::backtick($field) . " = ?", | |
array($value), | |
); | |
} | |
static function op_not_equal($field1, $field2) { | |
return array( | |
self::backtick($field) . " != ?", | |
array($value), | |
); | |
} | |
static function op_greater_than($field, $value) { | |
return array( | |
self::backtick($field) . " > ?", | |
array($value), | |
); | |
} | |
static function op_greater_than_or_equal($field, $value) { | |
return array( | |
self::backtick($field) . " >= ?", | |
array($value), | |
); | |
} | |
static function op_less_than($field, $value) { | |
return array( | |
self::backtick($field) . " < ?", | |
array($value), | |
); | |
} | |
static function op_less_than_or_equal($field, $value) { | |
return array( | |
self::backtick($field) . " <= ?", | |
array($value), | |
); | |
} | |
static function op_like($field, $value) { | |
return array( | |
self::backtick($field) . " LIKE ?", | |
array("%$value%"), | |
); | |
} | |
static function op_in($field, $value) { | |
return array( | |
self::backtick($field) . " IN (" . str_repeat("?,", count($value)-1) . "?)", | |
$value, | |
); | |
} | |
static function op_and($expr1, $expr2) { | |
$expr1 = call_user_func_array("self::safe_expr", $expr1); | |
$expr2 = call_user_func_array("self::safe_expr", $expr2); | |
return array( | |
"({$expr1[0][0]}) AND ({$expr2[0][0]})", | |
array_merge($expr1[1], $expr2[1]), | |
); | |
} | |
static function op_or($expr1, $expr2) { | |
$expr1 = call_user_func_array("self::safe_expr", $expr1); | |
$expr2 = call_user_func_array("self::safe_expr", $expr2); | |
return array( | |
"({$expr1[0][0]}) OR ({$expr2[0][0]})", | |
array_merge($expr1[1], $expr2[1]), | |
); | |
} | |
static function op_not($expr) { | |
$expr = call_user_func_array("self::safe_expr", $expr); | |
return array( | |
"NOT ({$expr[0][0]})", | |
$expr[1], | |
); | |
} | |
static function op_field($expr) { | |
return array( | |
"(" . self::backtick($expr) . ")", | |
array(), | |
); | |
} | |
static function op_arg($expr) { | |
return array( | |
"?", | |
$expr, | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// basic select | |
list($query, $args) = SafeQuery::safe_query("user", array("id","username"), array( | |
array("id",">","5"), | |
array("active","=",1), | |
), array( | |
array("asc", "id") | |
)); | |
// $query -> "SELECT `id`, `username` FROM `user` WHERE 1 AND `id` > ? AND `active` = ? ORDER BY (`id`) ASC LIMIT 0,100" | |
// $args -> array(5, 1) | |
// select with logic operators | |
list($query,$args) = SafeQuery::safe_query("user", array("id","username"), array( | |
array( | |
array( | |
array("id",">","0"), | |
"and", | |
array("id","<","3") | |
), | |
"or", | |
array( | |
array("id",">","10"), | |
"and", | |
array("id","<","15") | |
), | |
), | |
)); | |
// $query -> "SELECT `id`, `username` FROM `user` WHERE 1 AND ((`id` > ?) AND (`id` < ?)) OR ((`id` > ?) AND (`id` < ?)) LIMIT 0,100" | |
// $args -> array(0, 3, 10, 15) | |
// basic insert | |
list($query,$args) = SafeQuery::safe_insert("user", array( | |
"username" => "some_user", | |
"active" => 1 | |
)); | |
// $query -> "INSERT INTO `user` SET `username` = ?, `active` = ?" | |
// $args -> array("username", 1) | |
// basic update | |
list($query,$args) = SafeQuery::safe_update("user", array( | |
"username" => "new_username" | |
), array( | |
array("username","=","some_user"), | |
)); | |
// $query -> "UPDATE `user` SET `username` = ? WHERE `username` = ?" | |
// $args -> array("new_username", "some_user") | |
// basic delete | |
list($query,$args) = SafeQuery::safe_delete("user", array( | |
array("id","=","101"), | |
)); | |
// $query -> "DELETE FROM `user` WHERE `id` = ?" | |
// $args -> array(101) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment