From 75d94397cfcf96e66ab3d32c0903627a80704b17 Mon Sep 17 00:00:00 2001 From: Manuel Herrmann <0@0x17.de> Date: Thu, 19 Oct 2017 23:42:28 +0200 Subject: [PATCH] updated the medoo db library --- .../frameworks/Environment.php | 3 +- registration-system/frameworks/medoo.php | 1228 +++++++++++------ 2 files changed, 809 insertions(+), 422 deletions(-) diff --git a/registration-system/frameworks/Environment.php b/registration-system/frameworks/Environment.php index e4e1dbb..8af7c90 100644 --- a/registration-system/frameworks/Environment.php +++ b/registration-system/frameworks/Environment.php @@ -6,6 +6,7 @@ require_once __DIR__ . '/medoo.php'; require_once __DIR__ . '/soft_protect.php'; require_once __DIR__ . '/Fahrt.php'; require_once __DIR__ . '/Bachelor.php'; +use Medoo\Medoo; class Environment { @@ -42,7 +43,7 @@ class Environment { $this->adminEnv = $admin; - $this->database = new medoo(array( + $this->database = new Medoo(array( 'database_type' => $config_db["type"], 'database_name' => $config_db["name"], 'server' => $config_db["host"], diff --git a/registration-system/frameworks/medoo.php b/registration-system/frameworks/medoo.php index cc10923..097d998 100644 --- a/registration-system/frameworks/medoo.php +++ b/registration-system/frameworks/medoo.php @@ -1,57 +1,45 @@ <?php /*! * Medoo database framework - * http://medoo.in - * Version 1.1.3 + * https://medoo.in + * Version 1.4.5 * - * Copyright 2016, Angel Lai + * Copyright 2017, Angel Lai * Released under the MIT license */ -class medoo -{ - // General - protected $database_type; - - protected $charset; - - protected $database_name; - // For MySQL, MariaDB, MSSQL, Sybase, PostgreSQL, Oracle - protected $server; +namespace Medoo; - protected $username; +use PDO; +use Exception; +use PDOException; - protected $password; - - // For SQLite - protected $database_file; +class Medoo +{ + protected $database_type; - // For MySQL or MariaDB with unix_socket - protected $socket; + protected $prefix; - // Optional - protected $port; + protected $statement; - protected $prefix; + protected $option = []; - protected $option = array(); + protected $logs = []; - // Variable - protected $logs = array(); + protected $logging = false; protected $debug_mode = false; + protected $guid = 0; + public function __construct($options = null) { try { - $commands = array(); - $dsn = ''; - if (is_array($options)) { - foreach ($options as $option => $value) + if (isset($options[ 'database_type' ])) { - $this->$option = $value; + $this->database_type = strtolower($options[ 'database_type' ]); } } else @@ -59,86 +47,188 @@ class medoo return false; } - if ( - isset($this->port) && - is_int($this->port * 1) - ) + if (isset($options[ 'prefix' ])) { - $port = $this->port; + $this->prefix = $options[ 'prefix' ]; } - $type = strtolower($this->database_type); - $is_port = isset($port); + if (isset($options[ 'option' ])) + { + $this->option = $options[ 'option' ]; + } - if (isset($options[ 'prefix' ])) + if (isset($options[ 'logging' ]) && is_bool($options[ 'logging' ])) { - $this->prefix = $options[ 'prefix' ]; + $this->logging = $options[ 'logging' ]; } - switch ($type) + if (isset($options[ 'command' ]) && is_array($options[ 'command' ])) + { + $commands = $options[ 'command' ]; + } + else { - case 'mariadb': - $type = 'mysql'; + $commands = []; + } - case 'mysql': - if ($this->socket) - { - $dsn = $type . ':unix_socket=' . $this->socket . ';dbname=' . $this->database_name; - } - else - { - $dsn = $type . ':host=' . $this->server . ($is_port ? ';port=' . $port : '') . ';dbname=' . $this->database_name; - } + if (isset($options[ 'dsn' ])) + { + if (isset($options[ 'dsn' ][ 'driver' ])) + { + $attr = $options[ 'dsn' ]; + } + else + { + return false; + } + } + else + { + if ( + isset($options[ 'port' ]) && + is_int($options[ 'port' ] * 1) + ) + { + $port = $options[ 'port' ]; + } - // Make MySQL using standard quoted identifier - $commands[] = 'SET SQL_MODE=ANSI_QUOTES'; - break; + $is_port = isset($port); - case 'pgsql': - $dsn = $type . ':host=' . $this->server . ($is_port ? ';port=' . $port : '') . ';dbname=' . $this->database_name; - break; + switch ($this->database_type) + { + case 'mariadb': + case 'mysql': + $attr = [ + 'driver' => 'mysql', + 'dbname' => $options[ 'database_name' ] + ]; + + if (isset($options[ 'socket' ])) + { + $attr[ 'unix_socket' ] = $options[ 'socket' ]; + } + else + { + $attr[ 'host' ] = $options[ 'server' ]; - case 'sybase': - $dsn = 'dblib:host=' . $this->server . ($is_port ? ':' . $port : '') . ';dbname=' . $this->database_name; - break; + if ($is_port) + { + $attr[ 'port' ] = $port; + } + } - case 'oracle': - $dbname = $this->server ? - '//' . $this->server . ($is_port ? ':' . $port : ':1521') . '/' . $this->database_name : - $this->database_name; + // Make MySQL using standard quoted identifier + $commands[] = 'SET SQL_MODE=ANSI_QUOTES'; + break; + + case 'pgsql': + $attr = [ + 'driver' => 'pgsql', + 'host' => $options[ 'server' ], + 'dbname' => $options[ 'database_name' ] + ]; - $dsn = 'oci:dbname=' . $dbname . ($this->charset ? ';charset=' . $this->charset : ''); - break; + if ($is_port) + { + $attr[ 'port' ] = $port; + } - case 'mssql': - $dsn = strstr(PHP_OS, 'WIN') ? - 'sqlsrv:server=' . $this->server . ($is_port ? ',' . $port : '') . ';database=' . $this->database_name : - 'dblib:host=' . $this->server . ($is_port ? ':' . $port : '') . ';dbname=' . $this->database_name; + break; - // Keep MSSQL QUOTED_IDENTIFIER is ON for standard quoting - $commands[] = 'SET QUOTED_IDENTIFIER ON'; - break; + case 'sybase': + $attr = [ + 'driver' => 'dblib', + 'host' => $options[ 'server' ], + 'dbname' => $options[ 'database_name' ] + ]; - case 'sqlite': - $dsn = $type . ':' . $this->database_file; - $this->username = null; - $this->password = null; - break; + if ($is_port) + { + $attr[ 'port' ] = $port; + } + + break; + + case 'oracle': + $attr = [ + 'driver' => 'oci', + 'dbname' => $options[ 'server' ] ? + '//' . $options[ 'server' ] . ($is_port ? ':' . $port : ':1521') . '/' . $options[ 'database_name' ] : + $options[ 'database_name' ] + ]; + + if (isset($options[ 'charset' ])) + { + $attr[ 'charset' ] = $options[ 'charset' ]; + } + + break; + + case 'mssql': + if (strstr(PHP_OS, 'WIN')) + { + $attr = [ + 'driver' => 'sqlsrv', + 'Server' => $options[ 'server' ] . ($is_port ? ',' . $port : ''), + 'Database' => $options[ 'database_name' ] + ]; + } + else + { + $attr = [ + 'driver' => 'dblib', + 'host' => $options[ 'server' ] . ($is_port ? ':' . $port : ''), + 'dbname' => $options[ 'database_name' ] + ]; + } + + // Keep MSSQL QUOTED_IDENTIFIER is ON for standard quoting + $commands[] = 'SET QUOTED_IDENTIFIER ON'; + + // Make ANSI_NULLS is ON for NULL value + $commands[] = 'SET ANSI_NULLS ON'; + break; + + case 'sqlite': + $this->pdo = new PDO('sqlite:' . $options[ 'database_file' ], null, null, $this->option); + + return; + } + } + + $driver = $attr[ 'driver' ]; + + unset($attr[ 'driver' ]); + + $stack = []; + + foreach ($attr as $key => $value) + { + if (is_int($key)) + { + $stack[] = $value; + } + else + { + $stack[] = $key . '=' . $value; + } } + $dsn = $driver . ':' . implode($stack, ';'); + if ( - in_array($type, array('mariadb', 'mysql', 'pgsql', 'sybase', 'mssql')) && - $this->charset + in_array($this->database_type, ['mariadb', 'mysql', 'pgsql', 'sybase', 'mssql']) && + isset($options[ 'charset' ]) ) { - $commands[] = "SET NAMES '" . $this->charset . "'"; + $commands[] = "SET NAMES '" . $options[ 'charset' ] . "'"; } $this->pdo = new PDO( - $dsn, - $this->username, - $this->password, - $this->option + $dsn, + $options[ 'username' ], + $options[ 'password' ], + $this->option ); foreach ($commands as $value) @@ -151,36 +241,101 @@ class medoo } } - public function query($query) + public function query($query, $map = []) { - if ($this->debug_mode) + if (!empty($map)) { - echo $query; + foreach ($map as $key => $value) + { + switch (gettype($value)) + { + case 'NULL': + $map[ $key ] = [null, PDO::PARAM_NULL]; + break; - $this->debug_mode = false; + case 'resource': + $map[ $key ] = [$value, PDO::PARAM_LOB]; + break; - return false; - } + case 'boolean': + $map[ $key ] = [($value ? '1' : '0'), PDO::PARAM_BOOL]; + break; - $this->logs[] = $query; + case 'integer': + case 'double': + $map[ $key ] = [$value, PDO::PARAM_INT]; + break; + + case 'string': + $map[ $key ] = [$value, PDO::PARAM_STR]; + break; + } + } + } - return $this->pdo->query($query); + return $this->exec($query, $map); } - public function exec($query) + public function exec($query, $map = []) { if ($this->debug_mode) { - echo $query; + echo $this->generate($query, $map); $this->debug_mode = false; return false; } - $this->logs[] = $query; + if ($this->logging) + { + $this->logs[] = [$query, $map]; + } + else + { + $this->logs = [[$query, $map]]; + } + + $statement = $this->pdo->prepare($query); + + if ($statement) + { + foreach ($map as $key => $value) + { + $statement->bindValue($key, $value[ 0 ], $value[ 1 ]); + } + + $statement->execute(); + + $this->statement = $statement; + + return $statement; + } + else + { + return false; + } + } + + protected function generate($query, $map) + { + foreach ($map as $key => $value) + { + if ($value[ 1 ] === PDO::PARAM_STR) + { + $query = str_replace($key, $this->quote($value[ 0 ]), $query); + } + elseif ($value[ 1 ] === PDO::PARAM_NULL) + { + $query = str_replace($key, 'NULL', $query); + } + else + { + $query = str_replace($key, $value[ 0 ], $query); + } + } - return $this->pdo->exec($query); + return $query; } public function quote($string) @@ -188,14 +343,19 @@ class medoo return $this->pdo->quote($string); } - protected function table_quote($table) + protected function tableQuote($table) { return '"' . $this->prefix . $table . '"'; } - protected function column_quote($string) + protected function mapKey() { - preg_match('/(\(JSON\)\s*|^#)?([a-zA-Z0-9_]*)\.([a-zA-Z0-9_]*)/', $string, $column_match); + return ':MeDoO_' . $this->guid++ . '_mEdOo'; + } + + protected function columnQuote($string) + { + preg_match('/(^#)?([a-zA-Z0-9_]*)\.([a-zA-Z0-9_]*)(\s*\[JSON\]$)?/', $string, $column_match); if (isset($column_match[ 2 ], $column_match[ 3 ])) { @@ -205,39 +365,39 @@ class medoo return '"' . $string . '"'; } - protected function column_push(&$columns) + protected function columnPush(&$columns) { - if ($columns == '*') + if ($columns === '*') { return $columns; } + $stack = []; + if (is_string($columns)) { - $columns = array($columns); + $columns = [$columns]; } - $stack = array(); - foreach ($columns as $key => $value) { if (is_array($value)) { - $stack[] = $this->column_push($value); + $stack[] = $this->columnPush($value); } else { - preg_match('/([a-zA-Z0-9_\-\.]*)\s*\(([a-zA-Z0-9_\-]*)\)/i', $value, $match); + preg_match('/(?<column>[a-zA-Z0-9_\.]+)(?:\s*\((?<alias>[a-zA-Z0-9_]+)\)|\s*\[(?<type>(String|Bool|Int|Number|Object|JSON))\])?/i', $value, $match); - if (isset($match[ 1 ], $match[ 2 ])) + if (!empty($match[ 'alias' ])) { - $stack[] = $this->column_quote( $match[ 1 ] ) . ' AS ' . $this->column_quote( $match[ 2 ] ); + $stack[] = $this->columnQuote( $match[ 'column' ] ) . ' AS ' . $this->columnQuote( $match[ 'alias' ] ); - $columns[ $key ] = $match[ 2 ]; + $columns[ $key ] = $match[ 'alias' ]; } else { - $stack[] = $this->column_quote( $value ); + $stack[] = $this->columnQuote( $match[ 'column' ] ); } } } @@ -245,180 +405,216 @@ class medoo return implode($stack, ','); } - protected function array_quote($array) + protected function arrayQuote($array) { - $temp = array(); + $stack = []; foreach ($array as $value) { - $temp[] = is_int($value) ? $value : $this->pdo->quote($value); + $stack[] = is_int($value) ? $value : $this->pdo->quote($value); } - return implode($temp, ','); + return implode($stack, ','); } - protected function inner_conjunct($data, $conjunctor, $outer_conjunctor) + protected function innerConjunct($data, $map, $conjunctor, $outer_conjunctor) { - $haystack = array(); + $stack = []; foreach ($data as $value) { - $haystack[] = '(' . $this->data_implode($value, $conjunctor) . ')'; + $stack[] = '(' . $this->dataImplode($value, $map, $conjunctor) . ')'; } - return implode($outer_conjunctor . ' ', $haystack); + return implode($outer_conjunctor . ' ', $stack); } - protected function fn_quote($column, $string) + protected function fnQuote($column, $string) { return (strpos($column, '#') === 0 && preg_match('/^[A-Z0-9\_]*\([^)]*\)$/', $string)) ? - $string : + $string : - $this->quote($string); + $this->quote($string); } - protected function data_implode($data, $conjunctor, $outer_conjunctor = null) + protected function dataImplode($data, &$map, $conjunctor) { - $wheres = array(); + $wheres = []; foreach ($data as $key => $value) { + $map_key = $this->mapKey(); + $type = gettype($value); if ( - preg_match("/^(AND|OR)(\s+#.*)?$/i", $key, $relation_match) && - $type == 'array' + preg_match("/^(AND|OR)(\s+#.*)?$/i", $key, $relation_match) && + $type === 'array' ) { $wheres[] = 0 !== count(array_diff_key($value, array_keys(array_keys($value)))) ? - '(' . $this->data_implode($value, ' ' . $relation_match[ 1 ]) . ')' : - '(' . $this->inner_conjunct($value, ' ' . $relation_match[ 1 ], $conjunctor) . ')'; + '(' . $this->dataImplode($value, $map, ' ' . $relation_match[ 1 ]) . ')' : + '(' . $this->innerConjunct($value, $map, ' ' . $relation_match[ 1 ], $conjunctor) . ')'; } else { - preg_match('/(#?)([\w\.\-]+)(\[(\>|\>\=|\<|\<\=|\!|\<\>|\>\<|\!?~)\])?/i', $key, $match); - $column = $this->column_quote($match[ 2 ]); - - if (isset($match[ 4 ])) + if ( + is_int($key) && + preg_match('/([a-zA-Z0-9_\.]+)\[(?<operator>\>|\>\=|\<|\<\=|\!|\=)\]([a-zA-Z0-9_\.]+)/i', $value, $match) + ) { - $operator = $match[ 4 ]; + $wheres[] = $this->columnQuote($match[ 1 ]) . ' ' . $match[ 'operator' ] . ' ' . $this->columnQuote($match[ 3 ]); + } + else + { + preg_match('/(#?)([a-zA-Z0-9_\.]+)(\[(?<operator>\>|\>\=|\<|\<\=|\!|\<\>|\>\<|\!?~)\])?/i', $key, $match); + $column = $this->columnQuote($match[ 2 ]); - if ($operator == '!') + if (!empty($match[ 1 ])) { - switch ($type) + $wheres[] = $column . + (isset($match[ 'operator' ]) ? ' ' . $match[ 'operator' ] . ' ' : ' = ') . + $this->fnQuote($key, $value); + + continue; + } + + if (isset($match[ 'operator' ])) + { + $operator = $match[ 'operator' ]; + + if ($operator === '!') { - case 'NULL': - $wheres[] = $column . ' IS NOT NULL'; - break; + switch ($type) + { + case 'NULL': + $wheres[] = $column . ' IS NOT NULL'; + break; + + case 'array': + $wheres[] = $column . ' NOT IN (' . $this->arrayQuote($value) . ')'; + break; + + case 'integer': + case 'double': + $wheres[] = $column . ' != ' . $map_key; + $map[ $map_key ] = [$value, PDO::PARAM_INT]; + break; + + case 'boolean': + $wheres[] = $column . ' != ' . $map_key; + $map[ $map_key ] = [($value ? '1' : '0'), PDO::PARAM_BOOL]; + break; + + case 'string': + $wheres[] = $column . ' != ' . $map_key; + $map[ $map_key ] = [$value, PDO::PARAM_STR]; + break; + } + } - case 'array': - $wheres[] = $column . ' NOT IN (' . $this->array_quote($value) . ')'; - break; + if ($operator === '<>' || $operator === '><') + { + if ($type === 'array') + { + if ($operator === '><') + { + $column .= ' NOT'; + } - case 'integer': - case 'double': - $wheres[] = $column . ' != ' . $value; - break; + $wheres[] = '(' . $column . ' BETWEEN ' . $map_key . 'a AND ' . $map_key . 'b)'; - case 'boolean': - $wheres[] = $column . ' != ' . ($value ? '1' : '0'); - break; + $data_type = (is_numeric($value[ 0 ]) && is_numeric($value[ 1 ])) ? PDO::PARAM_INT : PDO::PARAM_STR; - case 'string': - $wheres[] = $column . ' != ' . $this->fn_quote($key, $value); - break; + $map[ $map_key . 'a' ] = [$value[ 0 ], $data_type]; + $map[ $map_key . 'b' ] = [$value[ 1 ], $data_type]; + } } - } - if ($operator == '<>' || $operator == '><') - { - if ($type == 'array') + if ($operator === '~' || $operator === '!~') { - if ($operator == '><') + if ($type !== 'array') { - $column .= ' NOT'; + $value = [ $value ]; } - if (is_numeric($value[ 0 ]) && is_numeric($value[ 1 ])) + $connector = ' OR '; + $stack = array_values($value); + + if (is_array($stack[ 0 ])) { - $wheres[] = '(' . $column . ' BETWEEN ' . $value[ 0 ] . ' AND ' . $value[ 1 ] . ')'; + if (isset($value[ 'AND' ]) || isset($value[ 'OR' ])) + { + $connector = ' ' . array_keys($value)[ 0 ] . ' '; + $value = $stack[ 0 ]; + } } - else + + $like_clauses = []; + + foreach ($value as $index => $item) { - $wheres[] = '(' . $column . ' BETWEEN ' . $this->quote($value[ 0 ]) . ' AND ' . $this->quote($value[ 1 ]) . ')'; + $item = strval($item); + + if (!preg_match('/(\[.+\]|_|%.+|.+%)/', $item)) + { + $item = '%' . $item . '%'; + } + + $like_clauses[] = $column . ($operator === '!~' ? ' NOT' : '') . ' LIKE ' . $map_key . 'L' . $index; + $map[ $map_key . 'L' . $index ] = [$item, PDO::PARAM_STR]; } - } - } - if ($operator == '~' || $operator == '!~') - { - if ($type != 'array') - { - $value = array($value); + $wheres[] = '(' . implode($connector, $like_clauses) . ')'; } - $like_clauses = array(); - - foreach ($value as $item) + if (in_array($operator, ['>', '>=', '<', '<='])) { - $item = strval($item); + $condition = $column . ' ' . $operator . ' '; - if (preg_match('/^(?!(%|\[|_])).+(?<!(%|\]|_))$/', $item)) + if (is_numeric($value)) + { + $condition .= $map_key; + $map[ $map_key ] = [$value, PDO::PARAM_INT]; + } + else { - $item = '%' . $item . '%'; + $condition .= $map_key; + $map[ $map_key ] = [$value, PDO::PARAM_STR]; } - $like_clauses[] = $column . ($operator === '!~' ? ' NOT' : '') . ' LIKE ' . $this->fn_quote($key, $item); + $wheres[] = $condition; } - - $wheres[] = implode(' OR ', $like_clauses); } - - if (in_array($operator, array('>', '>=', '<', '<='))) + else { - $condition = $column . ' ' . $operator . ' '; - - if (is_numeric($value)) - { - $condition .= $value; - } - elseif (strpos($key, '#') === 0) - { - $condition .= $this->fn_quote($key, $value); - } - else + switch ($type) { - $condition .= $this->quote($value); - } - - $wheres[] = $condition; - } - } - else - { - switch ($type) - { - case 'NULL': - $wheres[] = $column . ' IS NULL'; - break; + case 'NULL': + $wheres[] = $column . ' IS NULL'; + break; - case 'array': - $wheres[] = $column . ' IN (' . $this->array_quote($value) . ')'; - break; + case 'array': + $wheres[] = $column . ' IN (' . $this->arrayQuote($value) . ')'; + break; - case 'integer': - case 'double': - $wheres[] = $column . ' = ' . $value; - break; + case 'integer': + case 'double': + $wheres[] = $column . ' = ' . $map_key; + $map[ $map_key ] = [$value, PDO::PARAM_INT]; + break; - case 'boolean': - $wheres[] = $column . ' = ' . ($value ? '1' : '0'); - break; + case 'boolean': + $wheres[] = $column . ' = ' . $map_key; + $map[ $map_key ] = [($value ? '1' : '0'), PDO::PARAM_BOOL]; + break; - case 'string': - $wheres[] = $column . ' = ' . $this->fn_quote($key, $value); - break; + case 'string': + $wheres[] = $column . ' = ' . $map_key; + $map[ $map_key ] = [$value, PDO::PARAM_STR]; + break; + } } } } @@ -427,7 +623,7 @@ class medoo return implode($conjunctor . ' ', $wheres); } - protected function where_clause($where) + protected function whereClause($where, &$map) { $where_clause = ''; @@ -438,14 +634,14 @@ class medoo $where_OR = preg_grep("/^OR\s*#?$/i", $where_keys); $single_condition = array_diff_key($where, array_flip( - array('AND', 'OR', 'GROUP', 'ORDER', 'HAVING', 'LIMIT', 'LIKE', 'MATCH') + ['AND', 'OR', 'GROUP', 'ORDER', 'HAVING', 'LIMIT', 'LIKE', 'MATCH'] )); - if ($single_condition != array()) + if (!empty($single_condition)) { - $condition = $this->data_implode($single_condition, ''); + $condition = $this->dataImplode($single_condition, $map, ' AND'); - if ($condition != '') + if ($condition !== '') { $where_clause = ' WHERE ' . $condition; } @@ -454,13 +650,13 @@ class medoo if (!empty($where_AND)) { $value = array_values($where_AND); - $where_clause = ' WHERE ' . $this->data_implode($where[ $value[ 0 ] ], ' AND'); + $where_clause = ' WHERE ' . $this->dataImplode($where[ $value[ 0 ] ], $map, ' AND'); } if (!empty($where_OR)) { $value = array_values($where_OR); - $where_clause = ' WHERE ' . $this->data_implode($where[ $value[ 0 ] ], ' OR'); + $where_clause = ' WHERE ' . $this->dataImplode($where[ $value[ 0 ] ], $map, ' OR'); } if (isset($where[ 'MATCH' ])) @@ -469,17 +665,51 @@ class medoo if (is_array($MATCH) && isset($MATCH[ 'columns' ], $MATCH[ 'keyword' ])) { - $where_clause .= ($where_clause != '' ? ' AND ' : ' WHERE ') . ' MATCH ("' . str_replace('.', '"."', implode($MATCH[ 'columns' ], '", "')) . '") AGAINST (' . $this->quote($MATCH[ 'keyword' ]) . ')'; + $mode = ''; + + $mode_array = [ + 'natural' => 'IN NATURAL LANGUAGE MODE', + 'natural+query' => 'IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION', + 'boolean' => 'IN BOOLEAN MODE', + 'query' => 'WITH QUERY EXPANSION' + ]; + + if (isset($MATCH[ 'mode' ], $mode_array[ $MATCH[ 'mode' ] ])) + { + $mode = ' ' . $mode_array[ $MATCH[ 'mode' ] ]; + } + + $columns = implode(array_map([$this, 'columnQuote'], $MATCH[ 'columns' ]), ', '); + $map_key = $this->mapKey(); + $map[ $map_key ] = [$MATCH[ 'keyword' ], PDO::PARAM_STR]; + + $where_clause .= ($where_clause !== '' ? ' AND ' : ' WHERE') . ' MATCH (' . $columns . ') AGAINST (' . $map_key . $mode . ')'; } } if (isset($where[ 'GROUP' ])) { - $where_clause .= ' GROUP BY ' . $this->column_quote($where[ 'GROUP' ]); + $GROUP = $where[ 'GROUP' ]; + + if (is_array($GROUP)) + { + $stack = []; + + foreach ($GROUP as $column => $value) + { + $stack[] = $this->columnQuote($value); + } + + $where_clause .= ' GROUP BY ' . implode($stack, ','); + } + else + { + $where_clause .= ' GROUP BY ' . $this->columnQuote($where[ 'GROUP' ]); + } if (isset($where[ 'HAVING' ])) { - $where_clause .= ' HAVING ' . $this->data_implode($where[ 'HAVING' ], ' AND'); + $where_clause .= ' HAVING ' . $this->dataImplode($where[ 'HAVING' ], $map, ' AND'); } } @@ -489,21 +719,21 @@ class medoo if (is_array($ORDER)) { - $stack = array(); + $stack = []; foreach ($ORDER as $column => $value) { if (is_array($value)) { - $stack[] = 'FIELD(' . $this->column_quote($column) . ', ' . $this->array_quote($value) . ')'; + $stack[] = 'FIELD(' . $this->columnQuote($column) . ', ' . $this->arrayQuote($value) . ')'; } else if ($value === 'ASC' || $value === 'DESC') { - $stack[] = $this->column_quote($column) . ' ' . $value; + $stack[] = $this->columnQuote($column) . ' ' . $value; } else if (is_int($column)) { - $stack[] = $this->column_quote($value); + $stack[] = $this->columnQuote($value); } } @@ -511,11 +741,33 @@ class medoo } else { - $where_clause .= ' ORDER BY ' . $this->column_quote($ORDER); + $where_clause .= ' ORDER BY ' . $this->columnQuote($ORDER); + } + + if ( + isset($where[ 'LIMIT' ]) && + in_array($this->database_type, ['oracle', 'mssql']) + ) + { + $LIMIT = $where[ 'LIMIT' ]; + + if (is_numeric($LIMIT)) + { + $where_clause .= ' FETCH FIRST ' . $LIMIT . ' ROWS ONLY'; + } + + if ( + is_array($LIMIT) && + is_numeric($LIMIT[ 0 ]) && + is_numeric($LIMIT[ 1 ]) + ) + { + $where_clause .= ' OFFSET ' . $LIMIT[ 0 ] . ' ROWS FETCH NEXT ' . $LIMIT[ 1 ] . ' ROWS ONLY'; + } } } - if (isset($where[ 'LIMIT' ])) + if (isset($where[ 'LIMIT' ]) && !in_array($this->database_type, ['oracle', 'mssql'])) { $LIMIT = $where[ 'LIMIT' ]; @@ -525,25 +777,18 @@ class medoo } if ( - is_array($LIMIT) && - is_numeric($LIMIT[ 0 ]) && - is_numeric($LIMIT[ 1 ]) + is_array($LIMIT) && + is_numeric($LIMIT[ 0 ]) && + is_numeric($LIMIT[ 1 ]) ) { - if ($this->database_type === 'pgsql') - { - $where_clause .= ' OFFSET ' . $LIMIT[ 0 ] . ' LIMIT ' . $LIMIT[ 1 ]; - } - else - { - $where_clause .= ' LIMIT ' . $LIMIT[ 0 ] . ',' . $LIMIT[ 1 ]; - } + $where_clause .= ' LIMIT ' . $LIMIT[ 1 ] . ' OFFSET ' . $LIMIT[ 0 ]; } } } else { - if ($where != null) + if ($where !== null) { $where_clause .= ' ' . $where; } @@ -552,19 +797,19 @@ class medoo return $where_clause; } - protected function select_context($table, $join, &$columns = null, $where = null, $column_fn = null) + protected function selectContext($table, &$map, $join, &$columns = null, $where = null, $column_fn = null) { - preg_match('/([a-zA-Z0-9_\-]*)\s*\(([a-zA-Z0-9_\-]*)\)/i', $table, $table_match); + preg_match('/(?<table>[a-zA-Z0-9_]+)\s*\((?<alias>[a-zA-Z0-9_]+)\)/i', $table, $table_match); - if (isset($table_match[ 1 ], $table_match[ 2 ])) + if (isset($table_match[ 'table' ], $table_match[ 'alias' ])) { - $table = $this->table_quote($table_match[ 1 ]); + $table = $this->tableQuote($table_match[ 'table' ]); - $table_query = $this->table_quote($table_match[ 1 ]) . ' AS ' . $this->table_quote($table_match[ 2 ]); + $table_query = $table . ' AS ' . $this->tableQuote($table_match[ 'alias' ]); } else { - $table = $this->table_quote($table); + $table = $this->tableQuote($table); $table_query = $table; } @@ -572,24 +817,24 @@ class medoo $join_key = is_array($join) ? array_keys($join) : null; if ( - isset($join_key[ 0 ]) && - strpos($join_key[ 0 ], '[') === 0 + isset($join_key[ 0 ]) && + strpos($join_key[ 0 ], '[') === 0 ) { - $table_join = array(); + $table_join = []; - $join_array = array( - '>' => 'LEFT', - '<' => 'RIGHT', - '<>' => 'FULL', - '><' => 'INNER' - ); + $join_array = [ + '>' => 'LEFT', + '<' => 'RIGHT', + '<>' => 'FULL', + '><' => 'INNER' + ]; foreach($join as $sub_table => $relation) { - preg_match('/(\[(\<|\>|\>\<|\<\>)\])?([a-zA-Z0-9_\-]*)\s?(\(([a-zA-Z0-9_\-]*)\))?/', $sub_table, $match); + preg_match('/(\[(?<join>\<|\>|\>\<|\<\>)\])?(?<table>[a-zA-Z0-9_]+)\s?(\((?<alias>[a-zA-Z0-9_]+)\))?/', $sub_table, $match); - if ($match[ 2 ] != '' && $match[ 3 ] != '') + if ($match[ 'join' ] !== '' && $match[ 'table' ] !== '') { if (is_string($relation)) { @@ -605,34 +850,34 @@ class medoo } else { - $joins = array(); + $joins = []; foreach ($relation as $key => $value) { $joins[] = ( - strpos($key, '.') > 0 ? - // For ['tableB.column' => 'column'] - $this->column_quote($key) : - - // For ['column1' => 'column2'] - $table . '."' . $key . '"' - ) . - ' = ' . - $this->table_quote(isset($match[ 5 ]) ? $match[ 5 ] : $match[ 3 ]) . '."' . $value . '"'; + strpos($key, '.') > 0 ? + // For ['tableB.column' => 'column'] + $this->columnQuote($key) : + + // For ['column1' => 'column2'] + $table . '."' . $key . '"' + ) . + ' = ' . + $this->tableQuote(isset($match[ 'alias' ]) ? $match[ 'alias' ] : $match[ 'table' ]) . '."' . $value . '"'; } $relation = 'ON ' . implode($joins, ' AND '); } } - $table_name = $this->table_quote($match[ 3 ]) . ' '; + $table_name = $this->tableQuote($match[ 'table' ]) . ' '; - if (isset($match[ 5 ])) + if (isset($match[ 'alias' ])) { - $table_name .= 'AS ' . $this->table_quote($match[ 5 ]) . ' '; + $table_name .= 'AS ' . $this->tableQuote($match[ 'alias' ]) . ' '; } - $table_join[] = $join_array[ $match[ 2 ] ] . ' JOIN ' . $table_name . $relation; + $table_join[] = $join_array[ $match[ 'join' ] ] . ' JOIN ' . $table_name . $relation; } } @@ -645,8 +890,8 @@ class medoo if (is_null($where)) { if ( - is_array($join) && - isset($column_fn) + is_array($join) && + isset($column_fn) ) { $where = $join; @@ -673,7 +918,7 @@ class medoo if (isset($column_fn)) { - if ($column_fn == 1) + if ($column_fn === 1) { $column = '1'; @@ -690,70 +935,118 @@ class medoo $where = $join; } - $column = $column_fn . '(' . $this->column_push($columns) . ')'; + $column = $column_fn . '(' . $this->columnPush($columns) . ')'; } } else { - $column = $this->column_push($columns); + $column = $this->columnPush($columns); } - return 'SELECT ' . $column . ' FROM ' . $table_query . $this->where_clause($where); + return 'SELECT ' . $column . ' FROM ' . $table_query . $this->whereClause($where, $map); } - protected function data_map($index, $key, $value, $data, &$stack) + protected function columnMap($columns, &$stack) { - if (is_array($value)) + if ($columns === '*') { - $sub_stack = array(); + return $stack; + } - foreach ($value as $sub_key => $sub_value) + foreach ($columns as $key => $value) + { + if (is_int($key)) { - if (is_array($sub_value)) - { - $current_stack = $stack[ $index ][ $key ]; + preg_match('/(?<column>[a-zA-Z0-9_\.]*)(?:\s*\((?<alias>[a-zA-Z0-9_]+)\)|\s*\[(?<type>(String|Bool|Int|Number|Object|JSON))\])?/i', $value, $key_match); - $this->data_map(false, $sub_key, $sub_value, $data, $current_stack); + $column_key = !empty($key_match[ 'alias' ]) ? + $key_match[ 'alias' ] : + preg_replace('/^[\w]*\./i', '', $key_match[ 'column' ]); - $stack[ $index ][ $key ][ $sub_key ] = $current_stack[ 0 ][ $sub_key ]; + if (isset($key_match[ 'type' ])) + { + $stack[ $value ] = [$column_key, $key_match[ 'type' ]]; } else { - $this->data_map(false, preg_replace('/^[\w]*\./i', "", $sub_value), $sub_key, $data, $sub_stack); - - $stack[ $index ][ $key ] = $sub_stack; + $stack[ $value ] = [$column_key, 'String']; } } + else + { + $this->columnMap($value, $stack); + } } - else + + return $stack; + } + + protected function dataMap($data, $columns, $column_map, &$stack) + { + foreach ($columns as $key => $value) { - if ($index !== false) + if (is_int($key)) { - $stack[ $index ][ $value ] = $data[ $value ]; + $map = $column_map[ $value ]; + $column_key = $map[ 0 ]; + + if (isset($map[ 1 ])) + { + switch ($map[ 1 ]) + { + case 'Number': + case 'Int': + $stack[ $column_key ] = (int) $data[ $column_key ]; + break; + + case 'Bool': + $stack[ $column_key ] = (bool) $data[ $column_key ]; + break; + + case 'Object': + $stack[ $column_key ] = unserialize($data[ $column_key ]); + break; + + case 'JSON': + $stack[ $column_key ] = json_decode($data[ $column_key ], true); + break; + + case 'String': + $stack[ $column_key ] = $data[ $column_key ]; + break; + } + } + else + { + $stack[ $column_key ] = $data[ $column_key ]; + } } else { - if (preg_match('/[a-zA-Z0-9_\-\.]*\s*\(([a-zA-Z0-9_\-]*)\)/i', $key, $key_match)) - { - $key = $key_match[ 1 ]; - } + $current_stack = []; + + $this->dataMap($data, $value, $column_map, $current_stack); - $stack[ $key ] = $data[ $key ]; + $stack[ $key ] = $current_stack; } } } public function select($table, $join, $columns = null, $where = null) { - $column = $where == null ? $join : $columns; + $map = []; + $stack = []; + $column_map = []; - $is_single_column = (is_string($column) && $column !== '*'); + $index = 0; - $query = $this->query($this->select_context($table, $join, $columns, $where)); + $column = $where === null ? $join : $columns; - $stack = array(); + $is_single_column = (is_string($column) && $column !== '*'); - $index = 0; + $query = $this->exec($this->selectContext($table, $map, $join, $columns, $where), $map); + + $this->columnMap($columns, $column_map); if (!$query) { @@ -770,19 +1063,13 @@ class medoo return $query->fetchAll(PDO::FETCH_COLUMN); } - while ($row = $query->fetch(PDO::FETCH_ASSOC)) + while ($data = $query->fetch(PDO::FETCH_ASSOC)) { - foreach ($columns as $key => $value) - { - if (is_array($value)) - { - $this->data_map($index, $key, $value, $row, $stack); - } - else - { - $this->data_map($index, $key, preg_replace('/^[\w]*\./i', "", $value), $row, $stack); - } - } + $current_stack = []; + + $this->dataMap($data, $columns, $column_map, $current_stack); + + $stack[ $index ] = $current_stack; $index++; } @@ -792,158 +1079,229 @@ class medoo public function insert($table, $datas) { - $lastId = array(); + $stack = []; + $columns = []; + $fields = []; + $map = []; - // Check indexed or associative array if (!isset($datas[ 0 ])) { - $datas = array($datas); + $datas = [$datas]; } foreach ($datas as $data) { - $values = array(); - $columns = array(); - foreach ($data as $key => $value) { - $columns[] = $this->column_quote(preg_replace("/^(\(JSON\)\s*|#)/i", "", $key)); + $columns[] = $key; + } + } - switch (gettype($value)) + $columns = array_unique($columns); + + foreach ($datas as $data) + { + $values = []; + + foreach ($columns as $key) + { + if (strpos($key, '#') === 0) { - case 'NULL': - $values[] = 'NULL'; - break; + $values[] = $this->fnQuote($key, $data[ $key ]); + continue; + } - case 'array': - preg_match("/\(JSON\)\s*([\w]+)/i", $key, $column_match); + $map_key =$this->mapKey(); - $values[] = isset($column_match[ 0 ]) ? - $this->quote(json_encode($value)) : - $this->quote(serialize($value)); - break; + $values[] = $map_key; - case 'boolean': - $values[] = ($value ? '1' : '0'); - break; + if (!isset($data[ $key ])) + { + $map[ $map_key ] = [null, PDO::PARAM_NULL]; + } + else + { + $value = $data[ $key ]; - case 'integer': - case 'double': - case 'string': - $values[] = $this->fn_quote($key, $value); - break; + switch (gettype($value)) + { + case 'NULL': + $map[ $map_key ] = [null, PDO::PARAM_NULL]; + break; + + case 'array': + $map[ $map_key ] = [ + strpos($key, '[JSON]') === strlen($key) - 6 ? + json_encode($value) : + serialize($value), + PDO::PARAM_STR + ]; + break; + + case 'object': + $map[ $map_key ] = [serialize($value), PDO::PARAM_STR]; + break; + + case 'resource': + $map[ $map_key ] = [$value, PDO::PARAM_LOB]; + break; + + case 'boolean': + $map[ $map_key ] = [($value ? '1' : '0'), PDO::PARAM_BOOL]; + break; + + case 'integer': + case 'double': + $map[ $map_key ] = [$value, PDO::PARAM_INT]; + break; + + case 'string': + $map[ $map_key ] = [$value, PDO::PARAM_STR]; + break; + } } } - $this->exec('INSERT INTO ' . $this->table_quote($table) . ' (' . implode(', ', $columns) . ') VALUES (' . implode($values, ', ') . ')'); + $stack[] = '(' . implode($values, ', ') . ')'; + } - $lastId[] = $this->pdo->lastInsertId(); + foreach ($columns as $key) + { + $fields[] = $this->columnQuote(preg_replace("/(^#|\s*\[JSON\]$)/i", '', $key)); } - return count($lastId) > 1 ? $lastId : $lastId[ 0 ]; + return $this->exec('INSERT INTO ' . $this->tableQuote($table) . ' (' . implode(', ', $fields) . ') VALUES ' . implode(', ', $stack), $map); } public function update($table, $data, $where = null) { - $fields = array(); + $fields = []; + $map = []; foreach ($data as $key => $value) { - preg_match('/([\w]+)(\[(\+|\-|\*|\/)\])?/i', $key, $match); + $column = $this->columnQuote(preg_replace("/(^#|\s*\[(JSON|\+|\-|\*|\/)\]$)/i", '', $key)); - if (isset($match[ 3 ])) + if (strpos($key, '#') === 0) + { + $fields[] = $column . ' = ' . $value; + continue; + } + + $map_key = $this->mapKey(); + + preg_match('/(?<column>[a-zA-Z0-9_]+)(\[(?<operator>\+|\-|\*|\/)\])?/i', $key, $match); + + if (isset($match[ 'operator' ])) { if (is_numeric($value)) { - $fields[] = $this->column_quote($match[ 1 ]) . ' = ' . $this->column_quote($match[ 1 ]) . ' ' . $match[ 3 ] . ' ' . $value; + $fields[] = $column . ' = ' . $column . ' ' . $match[ 'operator' ] . ' ' . $value; } } else { - $column = $this->column_quote(preg_replace("/^(\(JSON\)\s*|#)/i", "", $key)); + $fields[] = $column . ' = ' . $map_key; switch (gettype($value)) { case 'NULL': - $fields[] = $column . ' = NULL'; + $map[ $map_key ] = [null, PDO::PARAM_NULL]; break; case 'array': - preg_match("/\(JSON\)\s*([\w]+)/i", $key, $column_match); + $map[ $map_key ] = [ + strpos($key, '[JSON]') === strlen($key) - 6 ? + json_encode($value) : + serialize($value), + PDO::PARAM_STR + ]; + break; - $fields[] = $column . ' = ' . $this->quote( - isset($column_match[ 0 ]) ? json_encode($value) : serialize($value) - ); + case 'object': + $map[ $map_key ] = [serialize($value), PDO::PARAM_STR]; + break; + + case 'resource': + $map[ $map_key ] = [$value, PDO::PARAM_LOB]; break; case 'boolean': - $fields[] = $column . ' = ' . ($value ? '1' : '0'); + $map[ $map_key ] = [($value ? '1' : '0'), PDO::PARAM_BOOL]; break; case 'integer': case 'double': + $map[ $map_key ] = [$value, PDO::PARAM_INT]; + break; + case 'string': - $fields[] = $column . ' = ' . $this->fn_quote($key, $value); + $map[ $map_key ] = [$value, PDO::PARAM_STR]; break; } } } - return $this->exec('UPDATE ' . $this->table_quote($table) . ' SET ' . implode(', ', $fields) . $this->where_clause($where)); + return $this->exec('UPDATE ' . $this->tableQuote($table) . ' SET ' . implode(', ', $fields) . $this->whereClause($where, $map), $map); } public function delete($table, $where) { - return $this->exec('DELETE FROM ' . $this->table_quote($table) . $this->where_clause($where)); + $map = []; + + return $this->exec('DELETE FROM ' . $this->tableQuote($table) . $this->whereClause($where, $map), $map); } - public function replace($table, $columns, $search = null, $replace = null, $where = null) + public function replace($table, $columns, $where = null) { + $map = []; + if (is_array($columns)) { - $replace_query = array(); + $replace_query = []; foreach ($columns as $column => $replacements) { - foreach ($replacements as $replace_search => $replace_replacement) + if (is_array($replacements[ 0 ])) { - $replace_query[] = $column . ' = REPLACE(' . $this->column_quote($column) . ', ' . $this->quote($replace_search) . ', ' . $this->quote($replace_replacement) . ')'; - } - } + foreach ($replacements as $replacement) + { + $map_key = $this->mapKey(); - $replace_query = implode(', ', $replace_query); - $where = $search; - } - else - { - if (is_array($search)) - { - $replace_query = array(); + $replace_query[] = $this->columnQuote($column) . ' = REPLACE(' . $this->columnQuote($column) . ', ' . $map_key . 'a, ' . $map_key . 'b)'; - foreach ($search as $replace_search => $replace_replacement) - { - $replace_query[] = $columns . ' = REPLACE(' . $this->column_quote($columns) . ', ' . $this->quote($replace_search) . ', ' . $this->quote($replace_replacement) . ')'; + $map[ $map_key . 'a' ] = [$replacement[ 0 ], PDO::PARAM_STR]; + $map[ $map_key . 'b' ] = [$replacement[ 1 ], PDO::PARAM_STR]; + } } + else + { + $map_key = $this->mapKey(); - $replace_query = implode(', ', $replace_query); - $where = $replace; - } - else - { - $replace_query = $columns . ' = REPLACE(' . $this->column_quote($columns) . ', ' . $this->quote($search) . ', ' . $this->quote($replace) . ')'; + $replace_query[] = $this->columnQuote($column) . ' = REPLACE(' . $this->columnQuote($column) . ', ' . $map_key . 'a, ' . $map_key . 'b)'; + + $map[ $map_key . 'a' ] = [$replacements[ 0 ], PDO::PARAM_STR]; + $map[ $map_key . 'b' ] = [$replacements[ 1 ], PDO::PARAM_STR]; + } } + + $replace_query = implode(', ', $replace_query); } - return $this->exec('UPDATE ' . $this->table_quote($table) . ' SET ' . $replace_query . $this->where_clause($where)); + return $this->exec('UPDATE ' . $this->tableQuote($table) . ' SET ' . $replace_query . $this->whereClause($where, $map), $map); } public function get($table, $join = null, $columns = null, $where = null) { - $column = $where == null ? $join : $columns; + $map = []; + $stack = []; + $column_map = []; + + $column = $where === null ? $join : $columns; $is_single_column = (is_string($column) && $column !== '*'); - $query = $this->query($this->select_context($table, $join, $columns, $where) . ' LIMIT 1'); + $query = $this->exec($this->selectContext($table, $map, $join, $columns, $where) . ' LIMIT 1', $map); if ($query) { @@ -951,31 +1309,21 @@ class medoo if (isset($data[ 0 ])) { - if ($is_single_column) - { - return $data[ 0 ][ preg_replace('/^[\w]*\./i', "", $column) ]; - } - if ($column === '*') { return $data[ 0 ]; } - $stack = array(); + $this->columnMap($columns, $column_map); - foreach ($columns as $key => $value) + $this->dataMap($data[ 0 ], $columns, $column_map, $stack); + + if ($is_single_column) { - if (is_array($value)) - { - $this->data_map(0, $key, $value, $data[ 0 ], $stack); - } - else - { - $this->data_map(0, $key, preg_replace('/^[\w]*\./i', "", $value), $data[ 0 ], $stack); - } + return $stack[ $column_map[ $column ][ 0 ] ]; } - return $stack[ 0 ]; + return $stack; } else { @@ -990,9 +1338,10 @@ class medoo public function has($table, $join, $where = null) { + $map = []; $column = null; - $query = $this->query('SELECT EXISTS(' . $this->select_context($table, $join, $column, $where, 1) . ')'); + $query = $this->exec('SELECT EXISTS(' . $this->selectContext($table, $map, $join, $column, $where, 1) . ')', $map); if ($query) { @@ -1006,14 +1355,18 @@ class medoo public function count($table, $join = null, $column = null, $where = null) { - $query = $this->query($this->select_context($table, $join, $column, $where, 'COUNT')); + $map = []; + + $query = $this->exec($this->selectContext($table, $map, $join, $column, $where, 'COUNT'), $map); return $query ? 0 + $query->fetchColumn() : false; } public function max($table, $join, $column = null, $where = null) { - $query = $this->query($this->select_context($table, $join, $column, $where, 'MAX')); + $map = []; + + $query = $this->exec($this->selectContext($table, $map, $join, $column, $where, 'MAX'), $map); if ($query) { @@ -1029,7 +1382,9 @@ class medoo public function min($table, $join, $column = null, $where = null) { - $query = $this->query($this->select_context($table, $join, $column, $where, 'MIN')); + $map = []; + + $query = $this->exec($this->selectContext($table, $map, $join, $column, $where, 'MIN'), $map); if ($query) { @@ -1045,14 +1400,18 @@ class medoo public function avg($table, $join, $column = null, $where = null) { - $query = $this->query($this->select_context($table, $join, $column, $where, 'AVG')); + $map = []; + + $query = $this->exec($this->selectContext($table, $map, $join, $column, $where, 'AVG'), $map); return $query ? 0 + $query->fetchColumn() : false; } public function sum($table, $join, $column = null, $where = null) { - $query = $this->query($this->select_context($table, $join, $column, $where, 'SUM')); + $map = []; + + $query = $this->exec($this->selectContext($table, $map, $join, $column, $where, 'SUM'), $map); return $query ? 0 + $query->fetchColumn() : false; } @@ -1080,6 +1439,26 @@ class medoo } } + public function id() + { + $type = $this->database_type; + + if ($type === 'oracle') + { + return 0; + } + elseif ($type === 'mssql') + { + return $this->pdo->query('SELECT SCOPE_IDENTITY()')->fetchColumn(); + } + elseif ($type === 'pgsql') + { + return $this->pdo->query('SELECT LASTVAL()')->fetchColumn(); + } + + return $this->pdo->lastInsertId(); + } + public function debug() { $this->debug_mode = true; @@ -1089,32 +1468,39 @@ class medoo public function error() { - return $this->pdo->errorInfo(); + return $this->statement ? $this->statement->errorInfo() : null; } - public function last_query() + public function last() { - return end($this->logs); + $log = end($this->logs); + + return $this->generate($log[ 0 ], $log[ 1 ]); } public function log() { - return $this->logs; + return array_map(function ($log) + { + return $this->generate($log[ 0 ], $log[ 1 ]); + }, + $this->logs + ); } public function info() { - $output = array( - 'server' => 'SERVER_INFO', - 'driver' => 'DRIVER_NAME', - 'client' => 'CLIENT_VERSION', - 'version' => 'SERVER_VERSION', - 'connection' => 'CONNECTION_STATUS' - ); + $output = [ + 'server' => 'SERVER_INFO', + 'driver' => 'DRIVER_NAME', + 'client' => 'CLIENT_VERSION', + 'version' => 'SERVER_VERSION', + 'connection' => 'CONNECTION_STATUS' + ]; foreach ($output as $key => $value) { - $output[ $key ] = $this->pdo->getAttribute(constant('PDO::ATTR_' . $value)); + $output[ $key ] = @$this->pdo->getAttribute(constant('PDO::ATTR_' . $value)); } return $output; -- GitLab