+++ /dev/null
-<?php
-$drivers["elastic"] = "Elasticsearch (beta)";
-
-if (isset($_GET["elastic"])) {
- define("DRIVER", "elastic");
-
- if (function_exists('json_decode') && ini_bool('allow_url_fopen')) {
- class Min_DB {
- var $extension = "JSON", $server_info, $errno, $error, $_url, $_db;
-
- /** Performs query
- * @param string
- * @param array
- * @param string
- * @return mixed
- */
- function rootQuery($path, $content = array(), $method = 'GET') {
- @ini_set('track_errors', 1); // @ - may be disabled
-
- $file = @file_get_contents("$this->_url/" . ltrim($path, '/'), false, stream_context_create(array('http' => array(
- 'method' => $method,
- 'content' => $content === null ? $content : json_encode($content),
- 'header' => 'Content-Type: application/json',
- 'ignore_errors' => 1, // available since PHP 5.2.10
- 'follow_location' => 0,
- 'max_redirects' => 0,
- ))));
- if (!$file) {
- $this->error = $php_errormsg;
- return $file;
- }
- if (!preg_match('~^HTTP/[0-9.]+ 2~i', $http_response_header[0])) {
- $this->error = lang('Invalid credentials.') . " $http_response_header[0]";
- return false;
- }
- $return = json_decode($file, true);
- if ($return === null) {
- $this->errno = json_last_error();
- if (function_exists('json_last_error_msg')) {
- $this->error = json_last_error_msg();
- } else {
- $constants = get_defined_constants(true);
- foreach ($constants['json'] as $name => $value) {
- if ($value == $this->errno && preg_match('~^JSON_ERROR_~', $name)) {
- $this->error = $name;
- break;
- }
- }
- }
- }
- return $return;
- }
-
- /** Performs query relative to actual selected DB
- * @param string
- * @param array
- * @param string
- * @return mixed
- */
- function query($path, $content = array(), $method = 'GET') {
- // Support for global search through all tables
- if ($path != "" && $path[0] == "S" && preg_match('/SELECT 1 FROM ([^ ]+) WHERE (.+) LIMIT ([0-9]+)/', $path, $matches)) {
- global $driver;
-
- $where = explode(" AND ", $matches[2]);
-
- return $driver->select($matches[1], array("*"), $where, null, array(), $matches[3]);
- }
-
- return $this->rootQuery(($this->_db != "" ? "$this->_db/" : "/") . ltrim($path, '/'), $content, $method);
- }
-
- function connect($server, $username, $password) {
- preg_match('~^(https?://)?(.*)~', $server, $match);
- $this->_url = ($match[1] ? $match[1] : "http://") . "$username:$password@$match[2]";
- $return = $this->query('');
- if ($return) {
- $this->server_info = $return['version']['number'];
- }
- return (bool) $return;
- }
-
- function select_db($database) {
- $this->_db = $database;
-
- return true;
- }
-
- function quote($string) {
- return $string;
- }
- }
-
- class Min_Result {
- var $num_rows, $_rows;
-
- function __construct($rows) {
- $this->num_rows = count($rows);
- $this->_rows = $rows;
-
- reset($this->_rows);
- }
-
- function fetch_assoc() {
- $return = current($this->_rows);
- next($this->_rows);
-
- return $return;
- }
-
- function fetch_row() {
- $row = $this->fetch_assoc();
-
- return $row ? array_values($row) : false;
- }
- }
- }
-
- class Min_Driver extends Min_SQL {
-
- function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) {
- global $adminer;
-
- $data = array();
- if ($select != array("*")) {
- $data["fields"] = $select;
- }
-
- if ($order) {
- $sort = array();
- foreach ($order as $col) {
- $col = preg_replace('~ DESC$~', '', $col, 1, $count);
- $sort[] = ($count ? array($col => "desc") : $col);
- }
- $data["sort"] = $sort;
- }
-
- if ($limit) {
- $data["size"] = +$limit;
- if ($page) {
- $data["from"] = ($page * $limit);
- }
- }
-
- foreach ($where as $val) {
- if (preg_match('~^\((.+ OR .+)\)$~', $val, $matches)) {
- $parts = explode(" OR ", $matches[1]);
- $terms = array();
- foreach ($parts as $part) {
- list($col, $op, $val) = explode(" ", $part, 3);
- $term = array($col => $val);
- if ($op == "=") {
- $terms[] = array("term" => $term);
- } elseif (in_array($op, array("must", "should", "must_not"))) {
- $data["query"]["bool"][$op][]["match"] = $term;
- }
- }
-
- if (!empty($terms)) {
- $data["query"]["bool"]["filter"][]["bool"]["should"] = $terms;
- }
- } else {
- list($col, $op, $val) = explode(" ", $val, 3);
- $term = array($col => $val);
- if ($op == "=") {
- $data["query"]["bool"]["filter"][] = array("term" => $term);
- } elseif (in_array($op, array("must", "should", "must_not"))) {
- $data["query"]["bool"][$op][]["match"] = $term;
- }
- }
- }
-
- $query = (min_version(7) ? "" : "$table/") . "_search";
- $start = microtime(true);
- $search = $this->_conn->query($query, $data);
-
- if ($print) {
- echo $adminer->selectQuery("$query: " . json_encode($data), $start, !$search);
- }
- if (!$search) {
- return false;
- }
-
- $return = array();
- foreach ($search['hits']['hits'] as $hit) {
- $row = array();
- if ($select == array("*")) {
- $row["_id"] = $hit["_id"];
- }
-
- $fields = $hit['_source'];
- if ($select != array("*")) {
- $fields = array();
- foreach ($select as $key) {
- $fields[$key] = $key == "_id" ? [$hit["_id"]] : $hit['fields'][$key];
- }
- }
-
- foreach ($fields as $key => $val) {
- if ($data["fields"]) {
- $val = $val[0];
- }
- $row[$key] = (is_array($val) ? json_encode($val) : $val); //! display JSON and others differently
- }
-
- $return[] = $row;
- }
-
- return new Min_Result($return);
- }
-
- function update($type, $record, $queryWhere, $limit = 0, $separator = "\n") {
- //! use $limit
- $parts = preg_split('~ *= *~', $queryWhere);
- if (count($parts) == 2) {
- $id = trim($parts[1]);
- $query = "$type/$id";
-
- return $this->_conn->query($query, $record, 'POST');
- }
-
- return false;
- }
-
- function insert($type, $record) {
- $id = ""; //! user should be able to inform _id
- $query = "$type/$id";
- $response = $this->_conn->query($query, $record, 'POST');
- $this->_conn->last_id = $response['_id'];
-
- return $response['created'];
- }
-
- function delete($type, $queryWhere, $limit = 0) {
- //! use $limit
- $ids = array();
- if (isset($_GET["where"]["_id"]) && $_GET["where"]["_id"]) {
- $ids[] = $_GET["where"]["_id"];
- }
- if (isset($_POST['check'])) {
- foreach ($_POST['check'] as $check) {
- $parts = preg_split('~ *= *~', $check);
- if (count($parts) == 2) {
- $ids[] = trim($parts[1]);
- }
- }
- }
-
- $this->_conn->affected_rows = 0;
-
- foreach ($ids as $id) {
- $query = "{$type}/{$id}";
- $response = $this->_conn->query($query, null, 'DELETE');
- if ((isset($response['found']) && $response['found']) || (isset($response['result']) && $response['result'] == 'deleted')) {
- $this->_conn->affected_rows++;
- }
- }
-
- return $this->_conn->affected_rows;
- }
-
- function convertOperator($operator) {
- return $operator == "LIKE %%" ? "should" : $operator;
- }
- }
-
- function connect() {
- global $adminer;
-
- $connection = new Min_DB;
-
- list($server, $username, $password) = $adminer->credentials();
- if ($password != "" && $connection->connect($server, $username, "")) {
- return lang('Database does not support password.');
- }
-
- if ($connection->connect($server, $username, $password)) {
- return $connection;
- }
-
- return $connection->error;
- }
-
- function support($feature) {
- return preg_match("~database|table|columns~", $feature);
- }
-
- function logged_user() {
- global $adminer;
-
- $credentials = $adminer->credentials();
-
- return $credentials[1];
- }
-
- function get_databases() {
- global $connection;
-
- $return = $connection->rootQuery('_aliases');
- if ($return) {
- $return = array_keys($return);
- sort($return, SORT_STRING);
- }
-
- return $return;
- }
-
- function limit($query, $where, $limit, $offset = 0, $separator = " ") {
- return " $query$where" . ($limit !== null ? $separator . "LIMIT $limit" . ($offset ? " OFFSET $offset" : "") : "");
- }
-
- function collations() {
- return array();
- }
-
- function db_collation($db, $collations) {
- //
- }
-
- function engines() {
- return array();
- }
-
- function count_tables($databases) {
- global $connection;
-
- $result = $connection->query('_stats');
-
- $return = array();
- if ($result && $result['indices']) {
- $indices = $result['indices'];
- foreach ($indices as $indice => $stats) {
- $indexing = $stats['total']['indexing'];
- $return[$indice] = $indexing['index_total'];
- }
- }
-
- return $return;
- }
-
- function tables_list() {
- global $connection;
-
- if (min_version(7)) {
- return array('_doc' => 'table');
- }
-
- $return = $connection->query('_mapping');
- if ($return) {
- $return = array_fill_keys(array_keys($return[$connection->_db]["mappings"]), 'table');
- }
-
- return $return;
- }
-
- function table_status($name = "", $fast = false) {
- global $connection;
-
- $search = $connection->query("_search", array(
- "size" => 0,
- "aggregations" => array(
- "count_by_type" => array(
- "terms" => array(
- "field" => "_type"
- )
- )
- )
- ), "POST");
-
- $return = array();
-
- if ($search) {
- $tables = $search["aggregations"]["count_by_type"]["buckets"];
-
- foreach ($tables as $table) {
- $return[$table["key"]] = array(
- "Name" => $table["key"],
- "Engine" => "table",
- "Rows" => $table["doc_count"],
- );
-
- if ($name != "" && $name == $table["key"]) {
- return $return[$name];
- }
- }
- }
-
- return $return;
- }
-
- function error() {
- global $connection;
-
- return h($connection->error);
- }
-
- function information_schema() {
- }
-
- function is_view($table_status) {
- }
-
- function indexes($table, $connection2 = null) {
- return array(
- array("type" => "PRIMARY", "columns" => array("_id")),
- );
- }
-
- function fields($table) {
- global $connection;
-
- $mappings = array();
-
- if (min_version(7)) {
- $result = $connection->query("_mapping");
- if ($result) {
- $mappings = $result[$connection->_db]['mappings']['properties'];
- }
- } else {
- $result = $connection->query("$table/_mapping");
- if ($result) {
- $mappings = $result[$table]['properties'];
- if (!$mappings) {
- $mappings = $result[$connection->_db]['mappings'][$table]['properties'];
- }
- }
- }
-
- $return = array(
- "_id" => array(
- "field" => "_id",
- "full_type" => "text",
- "type" => "text",
- "privileges" => array("insert" => 1, "select" => 1),
- )
- );
-
- foreach ($mappings as $name => $field) {
- if (!isset($field["index"]) || $field["index"]) {
- $return[$name] = array(
- "field" => $name,
- "full_type" => $field["type"],
- "type" => $field["type"],
- "privileges" => array(
- "insert" => 1,
- "select" => 1,
- "update" => 1,
- ),
- );
- if ($field["properties"]) { // only leaf fields can be edited
- unset($return[$name]["privileges"]["insert"]);
- unset($return[$name]["privileges"]["update"]);
- }
- }
- }
-
- return $return;
- }
-
- function foreign_keys($table) {
- return array();
- }
-
- function table($idf) {
- return $idf;
- }
-
- function idf_escape($idf) {
- return $idf;
- }
-
- function convert_field($field) {
- //
- }
-
- function unconvert_field($field, $return) {
- return $return;
- }
-
- function fk_support($table_status) {
- //
- }
-
- function found_rows($table_status, $where) {
- return null;
- }
-
- /** Create index
- * @param string
- * @return mixed
- */
- function create_database($db) {
- global $connection;
-
- return $connection->rootQuery(urlencode($db), null, 'PUT');
- }
-
- /** Remove index
- * @param array
- * @return mixed
- */
- function drop_databases($databases) {
- global $connection;
-
- return $connection->rootQuery(urlencode(implode(',', $databases)), null, 'DELETE');
- }
-
- /** Alter type
- * @param array
- * @return mixed
- */
- function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
- global $connection;
-
- $properties = array();
- foreach ($fields as $f) {
- $field_name = trim($f[1][0]);
- $field_type = trim($f[1][1] ? $f[1][1] : "text");
- $properties[$field_name] = array(
- 'type' => $field_type
- );
- }
-
- if (!empty($properties)) {
- $properties = array('properties' => $properties);
- }
-
- return $connection->query("_mapping/{$name}", $properties, 'PUT');
- }
-
- /** Drop types
- * @param array
- * @return bool
- */
- function drop_tables($tables) {
- global $connection;
-
- $return = true;
- foreach ($tables as $table) { //! convert to bulk api
- $return = $return && $connection->query(urlencode($table), null, 'DELETE');
- }
-
- return $return;
- }
-
- function last_id() {
- global $connection;
-
- return $connection->last_id;
- }
-
- function driver_config() {
- $types = array();
- $structured_types = array();
-
- foreach (array(
- lang('Numbers') => array("long" => 3, "integer" => 5, "short" => 8, "byte" => 10, "double" => 20, "float" => 66, "half_float" => 12, "scaled_float" => 21),
- lang('Date and time') => array("date" => 10),
- lang('Strings') => array("string" => 65535, "text" => 65535),
- lang('Binary') => array("binary" => 255),
- ) as $key => $val) {
- $types += $val;
- $structured_types[$key] = array_keys($val);
- }
-
- return array(
- 'possible_drivers' => array("json + allow_url_fopen"),
- 'jush' => "elastic",
- 'operators' => array("=", "must", "should", "must_not"),
- 'functions' => array(),
- 'grouping' => array(),
- 'edit_functions' => array(array("json")),
- 'types' => $types,
- 'structured_types' => $structured_types,
- );
- }
-}
+++ /dev/null
-<?php
-$drivers["elastic7"] = "Elasticsearch 7 (beta)";
-
-if (isset($_GET["elastic7"])) {
- define("DRIVER", "elastic7");
-
- if (function_exists('json_decode') && ini_bool('allow_url_fopen')) {
- define("ELASTIC_DB_NAME", "elastic");
-
- class Min_DB {
- var $extension = "JSON", $server_info, $errno, $error, $_url;
-
- /**
- * @param string $path
- * @param array|null $content
- * @param string $method
- * @return array|false
- */
- function rootQuery($path, array $content = null, $method = 'GET') {
- @ini_set('track_errors', 1); // @ - may be disabled
-
- $file = @file_get_contents("$this->_url/" . ltrim($path, '/'), false, stream_context_create(array('http' => array(
- 'method' => $method,
- 'content' => $content !== null ? json_encode($content) : null,
- 'header' => $content !== null ? 'Content-Type: application/json' : [],
- 'ignore_errors' => 1,
- 'follow_location' => 0,
- 'max_redirects' => 0,
- ))));
-
- if ($file === false) {
- $this->error = lang('Invalid server or credentials.');
- return false;
- }
-
- $return = json_decode($file, true);
- if ($return === null) {
- $this->error = lang('Invalid server or credentials.');
- return false;
- }
-
- if (!preg_match('~^HTTP/[0-9.]+ 2~i', $http_response_header[0])) {
- if (isset($return['error']['root_cause'][0]['type'])) {
- $this->error = $return['error']['root_cause'][0]['type'] . ": " . $return['error']['root_cause'][0]['reason'];
- } elseif (isset($return['status']) && isset($return['error']) && is_string($return['error'])) {
- $this->error = $return['error'];
- }
-
- return false;
- }
-
- return $return;
- }
-
- /** Performs query relative to actual selected DB
- * @param string $path
- * @param array|null $content
- * @param string $method
- * @return array|false
- */
- function query($path, array $content = null, $method = 'GET') {
- // Support for global search through all tables
- if ($path != "" && $path[0] == "S" && preg_match('/SELECT 1 FROM ([^ ]+) WHERE (.+) LIMIT ([0-9]+)/', $path, $matches)) {
- global $driver;
-
- $where = explode(" AND ", $matches[2]);
-
- return $driver->select($matches[1], array("*"), $where, null, array(), $matches[3]);
- }
-
- return $this->rootQuery($path, $content, $method);
- }
-
- /**
- * @param string $server
- * @param string $username
- * @param string $password
- * @return bool
- */
- function connect($server, $username, $password) {
- $this->_url = build_http_url($server, $username, $password, "localhost", 9200);
-
- $return = $this->query('');
- if (!$return) {
- return false;
- }
-
- if (!isset($return['version']['number'])) {
- $this->error = lang('Invalid server or credentials.');
- return false;
- }
-
- $this->server_info = $return['version']['number'];
- return true;
- }
-
- function select_db($database) {
- return true;
- }
-
- function quote($string) {
- return $string;
- }
- }
-
- class Min_Result {
- var $num_rows, $_rows;
-
- function __construct($rows) {
- $this->num_rows = count($rows);
- $this->_rows = $rows;
-
- reset($this->_rows);
- }
-
- function fetch_assoc() {
- $return = current($this->_rows);
- next($this->_rows);
-
- return $return;
- }
-
- function fetch_row() {
- $row = $this->fetch_assoc();
-
- return $row ? array_values($row) : false;
- }
- }
- }
-
- class Min_Driver extends Min_SQL {
-
- function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) {
- global $adminer;
-
- $data = array();
- if ($select != array("*")) {
- $data["fields"] = $select;
- }
-
- if ($order) {
- $sort = array();
- foreach ($order as $col) {
- $col = preg_replace('~ DESC$~', '', $col, 1, $count);
- $sort[] = ($count ? array($col => "desc") : $col);
- }
- $data["sort"] = $sort;
- }
-
- if ($limit) {
- $data["size"] = +$limit;
- if ($page) {
- $data["from"] = ($page * $limit);
- }
- }
-
- foreach ($where as $val) {
- if (preg_match('~^\((.+ OR .+)\)$~', $val, $matches)) {
- $parts = explode(" OR ", $matches[1]);
- $terms = array();
- foreach ($parts as $part) {
- list($col, $op, $val) = explode(" ", $part, 3);
- $term = array($col => $val);
- if ($op == "=") {
- $terms[] = array("term" => $term);
- } elseif (in_array($op, array("must", "should", "must_not"))) {
- $data["query"]["bool"][$op][]["match"] = $term;
- }
- }
-
- if (!empty($terms)) {
- $data["query"]["bool"]["filter"][]["bool"]["should"] = $terms;
- }
- } else {
- list($col, $op, $val) = explode(" ", $val, 3);
- $term = array($col => $val);
- if ($op == "=") {
- $data["query"]["bool"]["filter"][] = array("term" => $term);
- } elseif (in_array($op, array("must", "should", "must_not"))) {
- $data["query"]["bool"][$op][]["match"] = $term;
- }
- }
- }
-
- $query = "$table/_search";
- $start = microtime(true);
- $search = $this->_conn->rootQuery($query, $data);
-
- if ($print) {
- echo $adminer->selectQuery("$query: " . json_encode($data), $start, !$search);
- }
- if (empty($search)) {
- return false;
- }
-
- $return = array();
- foreach ($search["hits"]["hits"] as $hit) {
- $row = array();
- if ($select == array("*")) {
- $row["_id"] = $hit["_id"];
- }
-
- if ($select != array("*")) {
- $fields = array();
- foreach ($select as $key) {
- $fields[$key] = $key == "_id" ? $hit["_id"] : $hit["_source"][$key];
- }
- } else {
- $fields = $hit["_source"];
- }
- foreach ($fields as $key => $val) {
- $row[$key] = (is_array($val) ? json_encode($val) : $val);
- }
-
- $return[] = $row;
- }
-
- return new Min_Result($return);
- }
-
- function update($type, $record, $queryWhere, $limit = 0, $separator = "\n") {
- //! use $limit
- $parts = preg_split('~ *= *~', $queryWhere);
- if (count($parts) == 2) {
- $id = trim($parts[1]);
- $query = "$type/$id";
-
- return $this->_conn->query($query, $record, 'POST');
- }
-
- return false;
- }
-
- function insert($type, $record) {
- $id = ""; //! user should be able to inform _id
- $query = "$type/$id";
- $response = $this->_conn->query($query, $record, 'POST');
- $this->_conn->last_id = $response['_id'];
-
- return $response['created'];
- }
-
- function delete($table, $queryWhere, $limit = 0) {
- //! use $limit
- $ids = array();
- if (isset($_GET["where"]["_id"]) && $_GET["where"]["_id"]) {
- $ids[] = $_GET["where"]["_id"];
- }
- if (isset($_POST['check'])) {
- foreach ($_POST['check'] as $check) {
- $parts = preg_split('~ *= *~', $check);
- if (count($parts) == 2) {
- $ids[] = trim($parts[1]);
- }
- }
- }
-
- $this->_conn->affected_rows = 0;
-
- foreach ($ids as $id) {
- $query = "$table/_doc/$id";
- $response = $this->_conn->query($query, null, 'DELETE');
- if (isset($response['result']) && $response['result'] == 'deleted') {
- $this->_conn->affected_rows++;
- }
- }
-
- return $this->_conn->affected_rows;
- }
-
- function convertOperator($operator) {
- return $operator == "LIKE %%" ? "should" : $operator;
- }
- }
-
- function connect() {
- global $adminer;
-
- $connection = new Min_DB;
-
- list($server, $username, $password) = $adminer->credentials();
- if ($password != "" && $connection->connect($server, $username, "")) {
- return lang('Database does not support password.');
- }
-
- if ($connection->connect($server, $username, $password)) {
- return $connection;
- }
-
- return $connection->error;
- }
-
- function support($feature) {
- return preg_match("~table|columns~", $feature);
- }
-
- function logged_user() {
- global $adminer;
-
- $credentials = $adminer->credentials();
-
- return $credentials[1];
- }
-
- function get_databases() {
- return array(ELASTIC_DB_NAME);
- }
-
- function limit($query, $where, $limit, $offset = 0, $separator = " ") {
- return " $query$where" . ($limit !== null ? $separator . "LIMIT $limit" . ($offset ? " OFFSET $offset" : "") : "");
- }
-
- function collations() {
- return array();
- }
-
- function db_collation($db, $collations) {
- //
- }
-
- function engines() {
- return array();
- }
-
- function count_tables($databases) {
- global $connection;
-
- $return = $connection->rootQuery('_aliases');
- if (empty($return)) {
- return array(
- ELASTIC_DB_NAME => 0
- );
- }
-
- return array(
- ELASTIC_DB_NAME => count($return)
- );
- }
-
- function tables_list() {
- global $connection;
-
- $aliases = $connection->rootQuery('_aliases');
- if (empty($aliases)) {
- return array();
- }
-
- ksort($aliases);
-
- $tables = array();
- foreach ($aliases as $name => $index) {
- $tables[$name] = "table";
-
- ksort($index["aliases"]);
- $tables += array_fill_keys(array_keys($index["aliases"]), "view");
- }
-
- return $tables;
- }
-
- function table_status($name = "", $fast = false) {
- global $connection;
-
- $stats = $connection->rootQuery('_stats');
- $aliases = $connection->rootQuery('_aliases');
-
- if (empty($stats) || empty($aliases)) {
- return array();
- }
-
- $result = array();
-
- if ($name != "") {
- if (isset($stats["indices"][$name])) {
- return format_index_status($name, $stats["indices"][$name]);
- } else foreach ($aliases as $index_name => $index) {
- foreach ($index["aliases"] as $alias_name => $alias) {
- if ($alias_name == $name) {
- return format_alias_status($alias_name, $stats["indices"][$index_name]);
- }
- }
- }
- }
-
- ksort($stats["indices"]);
- foreach ($stats["indices"] as $name => $index) {
- if ($name[0] == ".") {
- continue;
- }
-
- $result[$name] = format_index_status($name, $index);
-
- if (!empty($aliases[$name]["aliases"])) {
- ksort($aliases[$name]["aliases"]);
- foreach ($aliases[$name]["aliases"] as $alias_name => $alias) {
- $result[$alias_name] = format_alias_status($alias_name, $stats["indices"][$name]);
- }
- }
- }
-
- return $result;
- }
-
- function format_index_status($name, $index) {
- return array(
- "Name" => $name,
- "Engine" => "Lucene",
- "Oid" => $index["uuid"],
- "Rows" => $index["total"]["docs"]["count"],
- "Auto_increment" => 0,
- "Data_length" => $index["total"]["store"]["size_in_bytes"],
- "Index_length" => 0,
- "Data_free" => $index["total"]["store"]["reserved_in_bytes"],
- );
- }
-
- function format_alias_status($name, $index) {
- return array(
- "Name" => $name,
- "Engine" => "view",
- "Rows" => $index["total"]["docs"]["count"],
- );
- }
-
- function is_view($table_status) {
- return $table_status["Engine"] == "view";
- }
-
- function error() {
- global $connection;
-
- return h($connection->error);
- }
-
- function information_schema() {
- //
- }
-
- function indexes($table, $connection2 = null) {
- return array(
- array("type" => "PRIMARY", "columns" => array("_id")),
- );
- }
-
- function fields($table) {
- global $connection;
-
- $mappings = array();
- $mapping = $connection->rootQuery("_mapping");
-
- if (!isset($mapping[$table])) {
- $aliases = $connection->rootQuery('_aliases');
-
- foreach ($aliases as $index_name => $index) {
- foreach ($index["aliases"] as $alias_name => $alias) {
- if ($alias_name == $table) {
- $table = $index_name;
- break;
- }
- }
- }
- }
-
- if (!empty($mapping)) {
- $mappings = $mapping[$table]["mappings"]["properties"];
- }
-
- $result = array(
- "_id" => array(
- "field" => "_id",
- "full_type" => "text",
- "type" => "text",
- "privileges" => array("insert" => 1, "select" => 1, "where" => 1, "order" => 1),
- )
- );
-
- foreach ($mappings as $name => $field) {
- $has_index = !isset($field["index"]) || $field["index"];
-
- // TODO: privileges: where => $has_index
- // TODO: privileges: sort => $field["type"] != "text"
-
- $result[$name] = array(
- "field" => $name,
- "full_type" => $field["type"],
- "type" => $field["type"],
- "privileges" => array(
- "insert" => 1,
- "select" => 1,
- "update" => 1,
- "where" => !isset($field["index"]) || $field["index"] ?: null,
- "order" => $field["type"] != "text" ?: null
- ),
- );
- }
-
- return $result;
- }
-
- function foreign_keys($table) {
- return array();
- }
-
- function table($idf) {
- return $idf;
- }
-
- function idf_escape($idf) {
- return $idf;
- }
-
- function convert_field($field) {
- //
- }
-
- function unconvert_field($field, $return) {
- return $return;
- }
-
- function fk_support($table_status) {
- //
- }
-
- function found_rows($table_status, $where) {
- return null;
- }
-
- /** Create index
- * @param string
- * @return mixed
- */
- function create_database($db) {
- global $connection;
-
- return $connection->rootQuery(urlencode($db), null, 'PUT');
- }
-
- /** Remove index
- * @param array
- * @return mixed
- */
- function drop_databases($databases) {
- global $connection;
-
- return $connection->rootQuery(urlencode(implode(',', $databases)), null, 'DELETE');
- }
-
- /** Alter type
- * @param array
- * @return mixed
- */
- function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
- global $connection;
-
- $properties = array();
- foreach ($fields as $f) {
- $field_name = trim($f[1][0]);
- $field_type = trim($f[1][1] ? $f[1][1] : "text");
- $properties[$field_name] = array(
- 'type' => $field_type
- );
- }
-
- if (!empty($properties)) {
- $properties = array('properties' => $properties);
- }
-
- return $connection->query("_mapping/{$name}", $properties, 'PUT');
- }
-
- /** Drop types
- * @param array
- * @return bool
- */
- function drop_tables($tables) {
- global $connection;
-
- $return = true;
- foreach ($tables as $table) { //! convert to bulk api
- $return = $return && $connection->query(urlencode($table), null, 'DELETE');
- }
-
- return $return;
- }
-
- function last_id() {
- global $connection;
-
- return $connection->last_id;
- }
-
- function driver_config() {
- $types = array();
- $structured_types = array();
-
- foreach (array(
- lang('Numbers') => array("long" => 3, "integer" => 5, "short" => 8, "byte" => 10, "double" => 20, "float" => 66, "half_float" => 12, "scaled_float" => 21),
- lang('Date and time') => array("date" => 10),
- lang('Strings') => array("string" => 65535, "text" => 65535),
- lang('Binary') => array("binary" => 255),
- ) as $key => $val) {
- $types += $val;
- $structured_types[$key] = array_keys($val);
- }
-
- return array(
- 'possible_drivers' => array("json + allow_url_fopen"),
- 'jush' => "elastic",
- 'operators' => array("=", "must", "should", "must_not"),
- 'functions' => array(),
- 'grouping' => array(),
- 'edit_functions' => array(array("json")),
- 'types' => $types,
- 'structured_types' => $structured_types,
- );
- }
-}
--- /dev/null
+<?php
+function adminer_object() {
+ include_once "../plugins/plugin.php";
+ include_once "../plugins/login-password-less.php";
+ include_once "../plugins/drivers/elastic.php";
+ include_once "../plugins/drivers/elastic5.php";
+ return new AdminerPlugin([
+ // TODO: inline the result of password_hash() so that the password is not visible in source codes
+ new AdminerLoginPasswordLess(password_hash("YOUR_PASSWORD_HERE", PASSWORD_DEFAULT)),
+ ]);
+}
+
+include "./index.php";
include "../adminer/drivers/oracle.inc.php";
include "../adminer/drivers/mssql.inc.php";
include "../adminer/drivers/mongo.inc.php";
-include "../adminer/drivers/elastic.inc.php";
include "./include/adminer.inc.php";
$adminer = (function_exists('adminer_object') ? adminer_object() : new Adminer);
include "../adminer/drivers/mysql.inc.php"; // must be included as last driver
--- /dev/null
+<?php
+add_driver("elastic", "Elasticsearch 7 (beta)");
+
+if (isset($_GET["elastic"])) {
+ define("DRIVER", "elastic");
+
+ if (ini_bool('allow_url_fopen')) {
+ define("ELASTIC_DB_NAME", "elastic");
+
+ class Min_DB {
+ var $extension = "JSON", $server_info, $errno, $error, $_url;
+
+ /**
+ * @param string $path
+ * @param array|null $content
+ * @param string $method
+ * @return array|false
+ */
+ function rootQuery($path, array $content = null, $method = 'GET') {
+ @ini_set('track_errors', 1); // @ - may be disabled
+
+ $file = @file_get_contents("$this->_url/" . ltrim($path, '/'), false, stream_context_create(array('http' => array(
+ 'method' => $method,
+ 'content' => $content !== null ? json_encode($content) : null,
+ 'header' => $content !== null ? 'Content-Type: application/json' : [],
+ 'ignore_errors' => 1,
+ 'follow_location' => 0,
+ 'max_redirects' => 0,
+ ))));
+
+ if ($file === false) {
+ $this->error = lang('Invalid server or credentials.');
+ return false;
+ }
+
+ $return = json_decode($file, true);
+ if ($return === null) {
+ $this->error = lang('Invalid server or credentials.');
+ return false;
+ }
+
+ if (!preg_match('~^HTTP/[0-9.]+ 2~i', $http_response_header[0])) {
+ if (isset($return['error']['root_cause'][0]['type'])) {
+ $this->error = $return['error']['root_cause'][0]['type'] . ": " . $return['error']['root_cause'][0]['reason'];
+ } elseif (isset($return['status']) && isset($return['error']) && is_string($return['error'])) {
+ $this->error = $return['error'];
+ }
+
+ return false;
+ }
+
+ return $return;
+ }
+
+ /** Performs query relative to actual selected DB
+ * @param string $path
+ * @param array|null $content
+ * @param string $method
+ * @return array|false
+ */
+ function query($path, array $content = null, $method = 'GET') {
+ // Support for global search through all tables
+ if ($path != "" && $path[0] == "S" && preg_match('/SELECT 1 FROM ([^ ]+) WHERE (.+) LIMIT ([0-9]+)/', $path, $matches)) {
+ global $driver;
+
+ $where = explode(" AND ", $matches[2]);
+
+ return $driver->select($matches[1], array("*"), $where, null, array(), $matches[3]);
+ }
+
+ return $this->rootQuery($path, $content, $method);
+ }
+
+ /**
+ * @param string $server
+ * @param string $username
+ * @param string $password
+ * @return bool
+ */
+ function connect($server, $username, $password) {
+ $this->_url = build_http_url($server, $username, $password, "localhost", 9200);
+
+ $return = $this->query('');
+ if (!$return) {
+ return false;
+ }
+
+ if (!isset($return['version']['number'])) {
+ $this->error = lang('Invalid server or credentials.');
+ return false;
+ }
+
+ $this->server_info = $return['version']['number'];
+ return true;
+ }
+
+ function select_db($database) {
+ return true;
+ }
+
+ function quote($string) {
+ return $string;
+ }
+ }
+
+ class Min_Result {
+ var $num_rows, $_rows;
+
+ function __construct($rows) {
+ $this->num_rows = count($rows);
+ $this->_rows = $rows;
+
+ reset($this->_rows);
+ }
+
+ function fetch_assoc() {
+ $return = current($this->_rows);
+ next($this->_rows);
+
+ return $return;
+ }
+
+ function fetch_row() {
+ $row = $this->fetch_assoc();
+
+ return $row ? array_values($row) : false;
+ }
+ }
+ }
+
+ class Min_Driver extends Min_SQL {
+
+ function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) {
+ $data = array();
+ if ($select != array("*")) {
+ $data["fields"] = $select;
+ }
+
+ if ($order) {
+ $sort = array();
+ foreach ($order as $col) {
+ $col = preg_replace('~ DESC$~', '', $col, 1, $count);
+ $sort[] = ($count ? array($col => "desc") : $col);
+ }
+ $data["sort"] = $sort;
+ }
+
+ if ($limit) {
+ $data["size"] = +$limit;
+ if ($page) {
+ $data["from"] = ($page * $limit);
+ }
+ }
+
+ foreach ($where as $val) {
+ if (preg_match('~^\((.+ OR .+)\)$~', $val, $matches)) {
+ $parts = explode(" OR ", $matches[1]);
+ $terms = array();
+ foreach ($parts as $part) {
+ list($col, $op, $val) = explode(" ", $part, 3);
+ $term = array($col => $val);
+ if ($op == "=") {
+ $terms[] = array("term" => $term);
+ } elseif (in_array($op, array("must", "should", "must_not"))) {
+ $data["query"]["bool"][$op][]["match"] = $term;
+ }
+ }
+
+ if (!empty($terms)) {
+ $data["query"]["bool"]["filter"][]["bool"]["should"] = $terms;
+ }
+ } else {
+ list($col, $op, $val) = explode(" ", $val, 3);
+ $term = array($col => $val);
+ if ($op == "=") {
+ $data["query"]["bool"]["filter"][] = array("term" => $term);
+ } elseif (in_array($op, array("must", "should", "must_not"))) {
+ $data["query"]["bool"][$op][]["match"] = $term;
+ }
+ }
+ }
+
+ $query = "$table/_search";
+ $start = microtime(true);
+ $search = $this->_conn->rootQuery($query, $data);
+
+ if ($print) {
+ echo adminer()->selectQuery("$query: " . json_encode($data), $start, !$search);
+ }
+ if (empty($search)) {
+ return false;
+ }
+
+ $return = array();
+ foreach ($search["hits"]["hits"] as $hit) {
+ $row = array();
+ if ($select == array("*")) {
+ $row["_id"] = $hit["_id"];
+ }
+
+ if ($select != array("*")) {
+ $fields = array();
+ foreach ($select as $key) {
+ $fields[$key] = $key == "_id" ? $hit["_id"] : $hit["_source"][$key];
+ }
+ } else {
+ $fields = $hit["_source"];
+ }
+ foreach ($fields as $key => $val) {
+ $row[$key] = (is_array($val) ? json_encode($val) : $val);
+ }
+
+ $return[] = $row;
+ }
+
+ return new Min_Result($return);
+ }
+
+ function update($type, $record, $queryWhere, $limit = 0, $separator = "\n") {
+ //! use $limit
+ $parts = preg_split('~ *= *~', $queryWhere);
+ if (count($parts) == 2) {
+ $id = trim($parts[1]);
+ $query = "$type/$id";
+
+ return $this->_conn->query($query, $record, 'POST');
+ }
+
+ return false;
+ }
+
+ function insert($type, $record) {
+ $id = ""; //! user should be able to inform _id
+ $query = "$type/$id";
+ $response = $this->_conn->query($query, $record, 'POST');
+ $this->_conn->last_id = $response['_id'];
+
+ return $response['created'];
+ }
+
+ function delete($table, $queryWhere, $limit = 0) {
+ //! use $limit
+ $ids = array();
+ if (isset($_GET["where"]["_id"]) && $_GET["where"]["_id"]) {
+ $ids[] = $_GET["where"]["_id"];
+ }
+ if (isset($_POST['check'])) {
+ foreach ($_POST['check'] as $check) {
+ $parts = preg_split('~ *= *~', $check);
+ if (count($parts) == 2) {
+ $ids[] = trim($parts[1]);
+ }
+ }
+ }
+
+ $this->_conn->affected_rows = 0;
+
+ foreach ($ids as $id) {
+ $query = "$table/_doc/$id";
+ $response = $this->_conn->query($query, null, 'DELETE');
+ if (isset($response['result']) && $response['result'] == 'deleted') {
+ $this->_conn->affected_rows++;
+ }
+ }
+
+ return $this->_conn->affected_rows;
+ }
+
+ function convertOperator($operator) {
+ return $operator == "LIKE %%" ? "should" : $operator;
+ }
+ }
+
+ function connect() {
+ $connection = new Min_DB;
+
+ list($server, $username, $password) = adminer()->credentials();
+ if ($password != "" && $connection->connect($server, $username, "")) {
+ return lang('Database does not support password.');
+ }
+
+ if ($connection->connect($server, $username, $password)) {
+ return $connection;
+ }
+
+ return $connection->error;
+ }
+
+ function support($feature) {
+ return preg_match("~table|columns~", $feature);
+ }
+
+ function logged_user() {
+ $credentials = adminer()->credentials();
+
+ return $credentials[1];
+ }
+
+ function get_databases() {
+ return array(ELASTIC_DB_NAME);
+ }
+
+ function limit($query, $where, $limit, $offset = 0, $separator = " ") {
+ return " $query$where" . ($limit !== null ? $separator . "LIMIT $limit" . ($offset ? " OFFSET $offset" : "") : "");
+ }
+
+ function collations() {
+ return array();
+ }
+
+ function db_collation($db, $collations) {
+ //
+ }
+
+ function engines() {
+ return array();
+ }
+
+ function count_tables($databases) {
+ $return = connection()->rootQuery('_aliases');
+ if (empty($return)) {
+ return array(
+ ELASTIC_DB_NAME => 0
+ );
+ }
+
+ return array(
+ ELASTIC_DB_NAME => count($return)
+ );
+ }
+
+ function tables_list() {
+ $aliases = connection()->rootQuery('_aliases');
+ if (empty($aliases)) {
+ return array();
+ }
+
+ ksort($aliases);
+
+ $tables = array();
+ foreach ($aliases as $name => $index) {
+ $tables[$name] = "table";
+
+ ksort($index["aliases"]);
+ $tables += array_fill_keys(array_keys($index["aliases"]), "view");
+ }
+
+ return $tables;
+ }
+
+ function table_status($name = "", $fast = false) {
+ $stats = connection()->rootQuery('_stats');
+ $aliases = connection()->rootQuery('_aliases');
+
+ if (empty($stats) || empty($aliases)) {
+ return array();
+ }
+
+ $result = array();
+
+ if ($name != "") {
+ if (isset($stats["indices"][$name])) {
+ return format_index_status($name, $stats["indices"][$name]);
+ } else foreach ($aliases as $index_name => $index) {
+ foreach ($index["aliases"] as $alias_name => $alias) {
+ if ($alias_name == $name) {
+ return format_alias_status($alias_name, $stats["indices"][$index_name]);
+ }
+ }
+ }
+ }
+
+ ksort($stats["indices"]);
+ foreach ($stats["indices"] as $name => $index) {
+ if ($name[0] == ".") {
+ continue;
+ }
+
+ $result[$name] = format_index_status($name, $index);
+
+ if (!empty($aliases[$name]["aliases"])) {
+ ksort($aliases[$name]["aliases"]);
+ foreach ($aliases[$name]["aliases"] as $alias_name => $alias) {
+ $result[$alias_name] = format_alias_status($alias_name, $stats["indices"][$name]);
+ }
+ }
+ }
+
+ return $result;
+ }
+
+ function format_index_status($name, $index) {
+ return array(
+ "Name" => $name,
+ "Engine" => "Lucene",
+ "Oid" => $index["uuid"],
+ "Rows" => $index["total"]["docs"]["count"],
+ "Auto_increment" => 0,
+ "Data_length" => $index["total"]["store"]["size_in_bytes"],
+ "Index_length" => 0,
+ "Data_free" => $index["total"]["store"]["reserved_in_bytes"],
+ );
+ }
+
+ function format_alias_status($name, $index) {
+ return array(
+ "Name" => $name,
+ "Engine" => "view",
+ "Rows" => $index["total"]["docs"]["count"],
+ );
+ }
+
+ function is_view($table_status) {
+ return $table_status["Engine"] == "view";
+ }
+
+ function error() {
+ return h(connection()->error);
+ }
+
+ function information_schema() {
+ //
+ }
+
+ function indexes($table, $connection2 = null) {
+ return array(
+ array("type" => "PRIMARY", "columns" => array("_id")),
+ );
+ }
+
+ function fields($table) {
+ $mappings = array();
+ $mapping = connection()->rootQuery("_mapping");
+
+ if (!isset($mapping[$table])) {
+ $aliases = connection()->rootQuery('_aliases');
+
+ foreach ($aliases as $index_name => $index) {
+ foreach ($index["aliases"] as $alias_name => $alias) {
+ if ($alias_name == $table) {
+ $table = $index_name;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!empty($mapping)) {
+ $mappings = $mapping[$table]["mappings"]["properties"];
+ }
+
+ $result = array(
+ "_id" => array(
+ "field" => "_id",
+ "full_type" => "text",
+ "type" => "text",
+ "privileges" => array("insert" => 1, "select" => 1, "where" => 1, "order" => 1),
+ )
+ );
+
+ foreach ($mappings as $name => $field) {
+ $has_index = !isset($field["index"]) || $field["index"];
+
+ // TODO: privileges: where => $has_index
+ // TODO: privileges: sort => $field["type"] != "text"
+
+ $result[$name] = array(
+ "field" => $name,
+ "full_type" => $field["type"],
+ "type" => $field["type"],
+ "privileges" => array(
+ "insert" => 1,
+ "select" => 1,
+ "update" => 1,
+ "where" => !isset($field["index"]) || $field["index"] ?: null,
+ "order" => $field["type"] != "text" ?: null
+ ),
+ );
+ }
+
+ return $result;
+ }
+
+ function foreign_keys($table) {
+ return array();
+ }
+
+ function table($idf) {
+ return $idf;
+ }
+
+ function idf_escape($idf) {
+ return $idf;
+ }
+
+ function convert_field($field) {
+ //
+ }
+
+ function unconvert_field($field, $return) {
+ return $return;
+ }
+
+ function fk_support($table_status) {
+ //
+ }
+
+ function found_rows($table_status, $where) {
+ return null;
+ }
+
+ /** Create index
+ * @param string
+ * @return mixed
+ */
+ function create_database($db) {
+ return connection()->rootQuery(urlencode($db), null, 'PUT');
+ }
+
+ /** Remove index
+ * @param array
+ * @return mixed
+ */
+ function drop_databases($databases) {
+ return connection()->rootQuery(urlencode(implode(',', $databases)), null, 'DELETE');
+ }
+
+ /** Alter type
+ * @param array
+ * @return mixed
+ */
+ function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
+ $properties = array();
+ foreach ($fields as $f) {
+ $field_name = trim($f[1][0]);
+ $field_type = trim($f[1][1] ? $f[1][1] : "text");
+ $properties[$field_name] = array(
+ 'type' => $field_type
+ );
+ }
+
+ if (!empty($properties)) {
+ $properties = array('properties' => $properties);
+ }
+
+ return connection()->query("_mapping/{$name}", $properties, 'PUT');
+ }
+
+ /** Drop types
+ * @param array
+ * @return bool
+ */
+ function drop_tables($tables) {
+ $return = true;
+ foreach ($tables as $table) { //! convert to bulk api
+ $return = $return && connection()->query(urlencode($table), null, 'DELETE');
+ }
+
+ return $return;
+ }
+
+ function last_id() {
+ return connection()->last_id;
+ }
+
+ function driver_config() {
+ $types = array();
+ $structured_types = array();
+
+ foreach (array(
+ lang('Numbers') => array("long" => 3, "integer" => 5, "short" => 8, "byte" => 10, "double" => 20, "float" => 66, "half_float" => 12, "scaled_float" => 21),
+ lang('Date and time') => array("date" => 10),
+ lang('Strings') => array("string" => 65535, "text" => 65535),
+ lang('Binary') => array("binary" => 255),
+ ) as $key => $val) {
+ $types += $val;
+ $structured_types[$key] = array_keys($val);
+ }
+
+ return array(
+ 'possible_drivers' => array("json + allow_url_fopen"),
+ 'jush' => "elastic",
+ 'operators' => array("=", "must", "should", "must_not"),
+ 'functions' => array(),
+ 'grouping' => array(),
+ 'edit_functions' => array(array("json")),
+ 'types' => $types,
+ 'structured_types' => $structured_types,
+ );
+ }
+}
--- /dev/null
+<?php
+add_driver("elastic5", "Elasticsearch 5 (beta)");
+
+if (isset($_GET["elastic5"])) {
+ define("DRIVER", "elastic5");
+
+ if (ini_bool('allow_url_fopen')) {
+ class Min_DB {
+ var $extension = "JSON", $server_info, $errno, $error, $_url, $_db;
+
+ /** Performs query
+ * @param string
+ * @param array
+ * @param string
+ * @return mixed
+ */
+ function rootQuery($path, $content = array(), $method = 'GET') {
+ @ini_set('track_errors', 1); // @ - may be disabled
+
+ $file = @file_get_contents("$this->_url/" . ltrim($path, '/'), false, stream_context_create(array('http' => array(
+ 'method' => $method,
+ 'content' => $content === null ? $content : json_encode($content),
+ 'header' => 'Content-Type: application/json',
+ 'ignore_errors' => 1, // available since PHP 5.2.10
+ 'follow_location' => 0,
+ 'max_redirects' => 0,
+ ))));
+ if (!$file) {
+ $this->error = $php_errormsg;
+ return $file;
+ }
+ if (!preg_match('~^HTTP/[0-9.]+ 2~i', $http_response_header[0])) {
+ $this->error = lang('Invalid credentials.') . " $http_response_header[0]";
+ return false;
+ }
+ $return = json_decode($file, true);
+ if ($return === null) {
+ $this->errno = json_last_error();
+ if (function_exists('json_last_error_msg')) {
+ $this->error = json_last_error_msg();
+ } else {
+ $constants = get_defined_constants(true);
+ foreach ($constants['json'] as $name => $value) {
+ if ($value == $this->errno && preg_match('~^JSON_ERROR_~', $name)) {
+ $this->error = $name;
+ break;
+ }
+ }
+ }
+ }
+ return $return;
+ }
+
+ /** Performs query relative to actual selected DB
+ * @param string
+ * @param array
+ * @param string
+ * @return mixed
+ */
+ function query($path, $content = array(), $method = 'GET') {
+ // Support for global search through all tables
+ if ($path != "" && $path[0] == "S" && preg_match('/SELECT 1 FROM ([^ ]+) WHERE (.+) LIMIT ([0-9]+)/', $path, $matches)) {
+ global $driver;
+
+ $where = explode(" AND ", $matches[2]);
+
+ return $driver->select($matches[1], array("*"), $where, null, array(), $matches[3]);
+ }
+
+ return $this->rootQuery(($this->_db != "" ? "$this->_db/" : "/") . ltrim($path, '/'), $content, $method);
+ }
+
+ function connect($server, $username, $password) {
+ preg_match('~^(https?://)?(.*)~', $server, $match);
+ $this->_url = ($match[1] ? $match[1] : "http://") . "$username:$password@$match[2]";
+ $return = $this->query('');
+ if ($return) {
+ $this->server_info = $return['version']['number'];
+ }
+ return (bool) $return;
+ }
+
+ function select_db($database) {
+ $this->_db = $database;
+
+ return true;
+ }
+
+ function quote($string) {
+ return $string;
+ }
+ }
+
+ class Min_Result {
+ var $num_rows, $_rows;
+
+ function __construct($rows) {
+ $this->num_rows = count($rows);
+ $this->_rows = $rows;
+
+ reset($this->_rows);
+ }
+
+ function fetch_assoc() {
+ $return = current($this->_rows);
+ next($this->_rows);
+
+ return $return;
+ }
+
+ function fetch_row() {
+ $row = $this->fetch_assoc();
+
+ return $row ? array_values($row) : false;
+ }
+ }
+ }
+
+ class Min_Driver extends Min_SQL {
+
+ function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) {
+ $data = array();
+ if ($select != array("*")) {
+ $data["fields"] = $select;
+ }
+
+ if ($order) {
+ $sort = array();
+ foreach ($order as $col) {
+ $col = preg_replace('~ DESC$~', '', $col, 1, $count);
+ $sort[] = ($count ? array($col => "desc") : $col);
+ }
+ $data["sort"] = $sort;
+ }
+
+ if ($limit) {
+ $data["size"] = +$limit;
+ if ($page) {
+ $data["from"] = ($page * $limit);
+ }
+ }
+
+ foreach ($where as $val) {
+ if (preg_match('~^\((.+ OR .+)\)$~', $val, $matches)) {
+ $parts = explode(" OR ", $matches[1]);
+ $terms = array();
+ foreach ($parts as $part) {
+ list($col, $op, $val) = explode(" ", $part, 3);
+ $term = array($col => $val);
+ if ($op == "=") {
+ $terms[] = array("term" => $term);
+ } elseif (in_array($op, array("must", "should", "must_not"))) {
+ $data["query"]["bool"][$op][]["match"] = $term;
+ }
+ }
+
+ if (!empty($terms)) {
+ $data["query"]["bool"]["filter"][]["bool"]["should"] = $terms;
+ }
+ } else {
+ list($col, $op, $val) = explode(" ", $val, 3);
+ $term = array($col => $val);
+ if ($op == "=") {
+ $data["query"]["bool"]["filter"][] = array("term" => $term);
+ } elseif (in_array($op, array("must", "should", "must_not"))) {
+ $data["query"]["bool"][$op][]["match"] = $term;
+ }
+ }
+ }
+
+ $query = (min_version(7) ? "" : "$table/") . "_search";
+ $start = microtime(true);
+ $search = $this->_conn->query($query, $data);
+
+ if ($print) {
+ echo adminer()->selectQuery("$query: " . json_encode($data), $start, !$search);
+ }
+ if (!$search) {
+ return false;
+ }
+
+ $return = array();
+ foreach ($search['hits']['hits'] as $hit) {
+ $row = array();
+ if ($select == array("*")) {
+ $row["_id"] = $hit["_id"];
+ }
+
+ $fields = $hit['_source'];
+ if ($select != array("*")) {
+ $fields = array();
+ foreach ($select as $key) {
+ $fields[$key] = $key == "_id" ? [$hit["_id"]] : $hit['fields'][$key];
+ }
+ }
+
+ foreach ($fields as $key => $val) {
+ if ($data["fields"]) {
+ $val = $val[0];
+ }
+ $row[$key] = (is_array($val) ? json_encode($val) : $val); //! display JSON and others differently
+ }
+
+ $return[] = $row;
+ }
+
+ return new Min_Result($return);
+ }
+
+ function update($type, $record, $queryWhere, $limit = 0, $separator = "\n") {
+ //! use $limit
+ $parts = preg_split('~ *= *~', $queryWhere);
+ if (count($parts) == 2) {
+ $id = trim($parts[1]);
+ $query = "$type/$id";
+
+ return $this->_conn->query($query, $record, 'POST');
+ }
+
+ return false;
+ }
+
+ function insert($type, $record) {
+ $id = ""; //! user should be able to inform _id
+ $query = "$type/$id";
+ $response = $this->_conn->query($query, $record, 'POST');
+ $this->_conn->last_id = $response['_id'];
+
+ return $response['created'];
+ }
+
+ function delete($type, $queryWhere, $limit = 0) {
+ //! use $limit
+ $ids = array();
+ if (isset($_GET["where"]["_id"]) && $_GET["where"]["_id"]) {
+ $ids[] = $_GET["where"]["_id"];
+ }
+ if (isset($_POST['check'])) {
+ foreach ($_POST['check'] as $check) {
+ $parts = preg_split('~ *= *~', $check);
+ if (count($parts) == 2) {
+ $ids[] = trim($parts[1]);
+ }
+ }
+ }
+
+ $this->_conn->affected_rows = 0;
+
+ foreach ($ids as $id) {
+ $query = "{$type}/{$id}";
+ $response = $this->_conn->query($query, null, 'DELETE');
+ if ((isset($response['found']) && $response['found']) || (isset($response['result']) && $response['result'] == 'deleted')) {
+ $this->_conn->affected_rows++;
+ }
+ }
+
+ return $this->_conn->affected_rows;
+ }
+
+ function convertOperator($operator) {
+ return $operator == "LIKE %%" ? "should" : $operator;
+ }
+ }
+
+ function connect() {
+ $connection = new Min_DB;
+
+ list($server, $username, $password) = adminer()->credentials();
+ if ($password != "" && $connection->connect($server, $username, "")) {
+ return lang('Database does not support password.');
+ }
+
+ if ($connection->connect($server, $username, $password)) {
+ return $connection;
+ }
+
+ return $connection->error;
+ }
+
+ function support($feature) {
+ return preg_match("~database|table|columns~", $feature);
+ }
+
+ function logged_user() {
+ $credentials = adminer()->credentials();
+
+ return $credentials[1];
+ }
+
+ function get_databases() {
+ $return = connection()->rootQuery('_aliases');
+ if ($return) {
+ $return = array_keys($return);
+ sort($return, SORT_STRING);
+ }
+
+ return $return;
+ }
+
+ function limit($query, $where, $limit, $offset = 0, $separator = " ") {
+ return " $query$where" . ($limit !== null ? $separator . "LIMIT $limit" . ($offset ? " OFFSET $offset" : "") : "");
+ }
+
+ function collations() {
+ return array();
+ }
+
+ function db_collation($db, $collations) {
+ //
+ }
+
+ function engines() {
+ return array();
+ }
+
+ function count_tables($databases) {
+ $return = array();
+
+ $result = connection()->query('_stats');
+ if ($result && $result['indices']) {
+ $indices = $result['indices'];
+ foreach ($indices as $indice => $stats) {
+ $indexing = $stats['total']['indexing'];
+ $return[$indice] = $indexing['index_total'];
+ }
+ }
+
+ return $return;
+ }
+
+ function tables_list() {
+ if (min_version(7)) {
+ return array('_doc' => 'table');
+ }
+
+ $return = connection()->query('_mapping');
+ if ($return) {
+ $return = array_fill_keys(array_keys($return[connection()->_db]["mappings"]), 'table');
+ }
+
+ return $return;
+ }
+
+ function table_status($name = "", $fast = false) {
+ $search = connection()->query("_search", array(
+ "size" => 0,
+ "aggregations" => array(
+ "count_by_type" => array(
+ "terms" => array(
+ "field" => "_type"
+ )
+ )
+ )
+ ), "POST");
+
+ $return = array();
+
+ if ($search) {
+ $tables = $search["aggregations"]["count_by_type"]["buckets"];
+
+ foreach ($tables as $table) {
+ $return[$table["key"]] = array(
+ "Name" => $table["key"],
+ "Engine" => "table",
+ "Rows" => $table["doc_count"],
+ );
+
+ if ($name != "" && $name == $table["key"]) {
+ return $return[$name];
+ }
+ }
+ }
+
+ return $return;
+ }
+
+ function error() {
+ return h(connection()->error);
+ }
+
+ function information_schema() {
+ }
+
+ function is_view($table_status) {
+ }
+
+ function indexes($table, $connection2 = null) {
+ return array(
+ array("type" => "PRIMARY", "columns" => array("_id")),
+ );
+ }
+
+ function fields($table) {
+ $mappings = array();
+
+ if (min_version(7)) {
+ $result = connection()->query("_mapping");
+ if ($result) {
+ $mappings = $result[connection()->_db]['mappings']['properties'];
+ }
+ } else {
+ $result = connection()->query("$table/_mapping");
+ if ($result) {
+ $mappings = $result[$table]['properties'];
+ if (!$mappings) {
+ $mappings = $result[connection()->_db]['mappings'][$table]['properties'];
+ }
+ }
+ }
+
+ $return = array(
+ "_id" => array(
+ "field" => "_id",
+ "full_type" => "text",
+ "type" => "text",
+ "privileges" => array("insert" => 1, "select" => 1),
+ )
+ );
+
+ foreach ($mappings as $name => $field) {
+ if (!isset($field["index"]) || $field["index"]) {
+ $return[$name] = array(
+ "field" => $name,
+ "full_type" => $field["type"],
+ "type" => $field["type"],
+ "privileges" => array(
+ "insert" => 1,
+ "select" => 1,
+ "update" => 1,
+ ),
+ );
+ if ($field["properties"]) { // only leaf fields can be edited
+ unset($return[$name]["privileges"]["insert"]);
+ unset($return[$name]["privileges"]["update"]);
+ }
+ }
+ }
+
+ return $return;
+ }
+
+ function foreign_keys($table) {
+ return array();
+ }
+
+ function table($idf) {
+ return $idf;
+ }
+
+ function idf_escape($idf) {
+ return $idf;
+ }
+
+ function convert_field($field) {
+ //
+ }
+
+ function unconvert_field($field, $return) {
+ return $return;
+ }
+
+ function fk_support($table_status) {
+ //
+ }
+
+ function found_rows($table_status, $where) {
+ return null;
+ }
+
+ /** Create index
+ * @param string
+ * @return mixed
+ */
+ function create_database($db) {
+ return connection()->rootQuery(urlencode($db), null, 'PUT');
+ }
+
+ /** Remove index
+ * @param array
+ * @return mixed
+ */
+ function drop_databases($databases) {
+ return connection()->rootQuery(urlencode(implode(',', $databases)), null, 'DELETE');
+ }
+
+ /** Alter type
+ * @param array
+ * @return mixed
+ */
+ function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
+ $properties = array();
+ foreach ($fields as $f) {
+ $field_name = trim($f[1][0]);
+ $field_type = trim($f[1][1] ? $f[1][1] : "text");
+ $properties[$field_name] = array(
+ 'type' => $field_type
+ );
+ }
+
+ if (!empty($properties)) {
+ $properties = array('properties' => $properties);
+ }
+ return connection()->query("_mapping/{$name}", $properties, 'PUT');
+ }
+
+ /** Drop types
+ * @param array
+ * @return bool
+ */
+ function drop_tables($tables) {
+ $return = true;
+ foreach ($tables as $table) { //! convert to bulk api
+ $return = $return && connection()->query(urlencode($table), null, 'DELETE');
+ }
+
+ return $return;
+ }
+
+ function last_id() {
+ return connection()->last_id;
+ }
+
+ function driver_config() {
+ $types = array();
+ $structured_types = array();
+
+ foreach (array(
+ lang('Numbers') => array("long" => 3, "integer" => 5, "short" => 8, "byte" => 10, "double" => 20, "float" => 66, "half_float" => 12, "scaled_float" => 21),
+ lang('Date and time') => array("date" => 10),
+ lang('Strings') => array("string" => 65535, "text" => 65535),
+ lang('Binary') => array("binary" => 255),
+ ) as $key => $val) {
+ $types += $val;
+ $structured_types[$key] = array_keys($val);
+ }
+
+ return array(
+ 'possible_drivers' => array("json + allow_url_fopen"),
+ 'jush' => "elastic",
+ 'operators' => array("=", "must", "should", "must_not"),
+ 'functions' => array(),
+ 'grouping' => array(),
+ 'edit_functions' => array(array("json")),
+ 'types' => $types,
+ 'structured_types' => $structured_types,
+ );
+ }
+}