From 6a8d4f817d2e9ecda61183142c71b44e83d15eb3 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Wed, 19 Apr 2017 11:24:58 +0200 Subject: [inc/Database] Support expanding nested arrays In parametrized queries, you can now pass an array as an argument. This will result in the arguments being expanded to :a1,:a2,:a3 which is suitable for "IN (:slist)" constructs. --- inc/database.inc.php | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'inc') diff --git a/inc/database.inc.php b/inc/database.inc.php index ff98f5ee..f3a90fe7 100644 --- a/inc/database.inc.php +++ b/inc/database.inc.php @@ -100,6 +100,8 @@ class Database public static function simpleQuery($query, $args = array(), $ignoreError = false) { self::init(); + // Support passing nested arrays for IN statements, automagically refactor + self::handleArrayArgument($query, $args); try { if (!isset(self::$statements[$query])) { self::$statements[$query] = self::$dbh->prepare($query); @@ -122,6 +124,46 @@ class Database return false; } + /** + * Convert nested array argument to multiple arguments. + * If you have: + * $query = 'SELECT * FROM tbl WHERE bcol = :bool AND col IN (:list) + * $args = ( 'bool' => 1, 'list' => ('foo', 'bar') ) + * it results in: + * $query = '...WHERE bcol = :bool AND col IN (:list_0, :list_1) + * $args = ( 'bool' => 1, 'list_0' => 'foo', 'list_1' => 'bar' ) + * + * @param string $query sql query string + * @param array $args query arguments + */ + private static function handleArrayArgument(&$query, &$args) + { + foreach (array_keys($args) as $key) { + if (is_numeric($key) || $key === '?') + continue; + if (is_array($args[$key])) { + if (empty($args[$key])) { + // Empty list - what to do? We try to generate a query string that will not yield any result + $args[$key] = 'asdf' . mt_rand(0,PHP_INT_MAX) . mt_rand(0,PHP_INT_MAX) + . mt_rand(0,PHP_INT_MAX) . '@' . microtime(true); + continue; + } + $newkey = $key; + if ($newkey{0} !== ':') { + $newkey = ":$newkey"; + } + $new = array(); + foreach ($args[$key] as $subIndex => $sub) { + $new[] = $newkey . '_' . $subIndex; + $args[$newkey . '_' . $subIndex] = $sub; + } + unset($args[$key]); + $new = implode(',', $new); + $query = preg_replace('/' . $newkey . '\b/', $new, $query); + } + } + } + /** * Simply calls PDO::prepare and returns the PDOStatement. * You must call PDOStatement::execute manually on it. -- cgit v1.2.3-55-g7522