Skip to content

Instantly share code, notes, and snippets.

@postpostscript
Last active June 8, 2017 15:26
Show Gist options
  • Save postpostscript/045f588c1790fbcc4ea52e2429623fad to your computer and use it in GitHub Desktop.
Save postpostscript/045f588c1790fbcc4ea52e2429623fad to your computer and use it in GitHub Desktop.
PDO safe query generation
<?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,
);
}
}
<?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