Files
adminer/plugins/drivers/elastic5.php

537 lines
13 KiB
PHP
Raw Normal View History

2013-07-09 17:38:13 -07:00
<?php
2025-03-05 11:28:53 +01:00
namespace Adminer;
add_driver("elastic5", "Elasticsearch 5 (beta)");
2013-07-09 17:38:13 -07:00
if (isset($_GET["elastic5"])) {
define("DRIVER", "elastic5");
if (ini_bool('allow_url_fopen')) {
2025-03-05 14:12:42 +01:00
class 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') {
2018-01-22 13:51:47 +01:00
$file = @file_get_contents("$this->_url/" . ltrim($path, '/'), false, stream_context_create(array('http' => array(
'method' => $method,
'content' => $content !== null ? json_encode($content) : $content,
'header' => $content !== null ? 'Content-Type: application/json' : array(),
2025-03-05 15:45:37 +01:00
'ignore_errors' => 1,
'follow_location' => 0,
'max_redirects' => 0,
2013-07-09 17:38:13 -07:00
))));
2025-02-18 08:16:53 +01:00
if (!$file || !preg_match('~^HTTP/[0-9.]+ 2~i', $http_response_header[0])) {
$this->error = lang('Invalid credentials.');
2013-07-09 17:38:13 -07:00
return false;
}
$return = json_decode($file, true);
if ($return === null) {
2013-07-09 17:38:13 -07:00
$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)) {
2013-07-09 17:38:13 -07:00
$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') {
2021-04-05 00:13:07 +02:00
// Support for global search through all tables
if ($path != "" && $path[0] == "S" && preg_match('/SELECT 1 FROM ([^ ]+) WHERE (.+) LIMIT ([0-9]+)/', $path, $matches)) {
$driver = get_driver();
2021-04-05 00:13:07 +02:00
$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);
}
2013-07-09 17:38:13 -07:00
function connect($server, $username, $password) {
2017-02-20 18:07:30 +01:00
preg_match('~^(https?://)?(.*)~', $server, $match);
2025-02-18 07:58:27 +01:00
$this->_url = ($match[1] ? $match[1] : "http://") . urlencode($username) . ":" . urlencode($password) . "@$match[2]";
2013-07-09 17:38:13 -07:00
$return = $this->query('');
if ($return) {
$this->server_info = $return['version']['number'];
}
return (bool) $return;
}
2013-07-09 17:38:13 -07:00
function select_db($database) {
$this->_db = $database;
2013-07-09 17:38:13 -07:00
return true;
}
2013-07-09 17:38:13 -07:00
function quote($string) {
return $string;
}
}
2025-03-05 14:12:42 +01:00
class Result {
2013-08-08 16:02:23 -07:00
var $num_rows, $_rows;
2015-08-15 17:04:21 +02:00
function __construct($rows) {
$this->num_rows = count($rows);
2013-07-09 17:38:13 -07:00
$this->_rows = $rows;
2013-07-09 17:38:13 -07:00
reset($this->_rows);
}
2013-07-09 17:38:13 -07:00
function fetch_assoc() {
$return = current($this->_rows);
next($this->_rows);
2013-07-09 17:38:13 -07:00
return $return;
}
2013-07-09 17:38:13 -07:00
function fetch_row() {
2021-04-05 00:13:07 +02:00
$row = $this->fetch_assoc();
return $row ? array_values($row) : false;
2013-07-09 17:38:13 -07:00
}
}
}
2025-03-05 14:12:42 +01:00
class Driver extends SqlDriver {
static $possibleDrivers = array("json + allow_url_fopen");
static $jush = "elastic";
2025-03-06 13:15:38 +01:00
var $editFunctions = array(array("json"));
var $operators = array("=", "must", "should", "must_not");
2025-03-06 13:15:38 +01:00
2025-03-06 12:35:20 +01:00
function __construct($connection) {
parent::__construct($connection);
$this->types = 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),
);
}
2014-01-15 08:23:26 -08:00
function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) {
2013-08-08 13:21:34 -07:00
$data = array();
if ($select != array("*")) {
$data["fields"] = array_values($select);
}
if ($order) {
$sort = array();
foreach ($order as $col) {
$col = preg_replace('~ DESC$~', '', $col, 1, $count);
$sort[] = ($count ? array($col => "desc") : $col);
2013-08-08 13:21:34 -07:00
}
$data["sort"] = $sort;
}
if ($limit) {
$data["size"] = +$limit;
if ($page) {
$data["from"] = ($page * $limit);
2013-08-08 13:21:34 -07:00
}
}
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);
2014-01-08 23:14:37 -08:00
if ($print) {
echo adminer()->selectQuery("$query: " . json_encode($data), $start, !$search);
2014-01-08 23:14:37 -08:00
}
2013-07-09 17:38:13 -07:00
if (!$search) {
return false;
}
2013-07-09 17:38:13 -07:00
$return = array();
foreach ($search['hits']['hits'] as $hit) {
$row = array();
if ($select == array("*")) {
2018-01-22 13:51:47 +01:00
$row["_id"] = $hit["_id"];
}
$fields = $hit['_source'];
if ($select != array("*")) {
$fields = array();
foreach ($select as $key) {
2025-02-17 15:48:23 +01:00
$fields[$key] = $key == "_id" ? array($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
2013-07-09 17:38:13 -07:00
}
2013-07-09 17:38:13 -07:00
$return[] = $row;
}
2025-03-05 14:12:42 +01:00
return new Result($return);
2013-07-09 17:38:13 -07:00
}
2018-03-11 16:07:54 +01:00
function update($type, $record, $queryWhere, $limit = 0, $separator = "\n") {
//! use $limit
2017-10-18 17:13:23 -02:00
$parts = preg_split('~ *= *~', $queryWhere);
if (count($parts) == 2) {
$id = trim($parts[1]);
$query = "$type/$id";
2017-10-18 17:13:23 -02:00
return $this->_conn->query($query, $record, 'POST');
}
2017-10-18 17:13:23 -02:00
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'];
2017-10-18 17:13:23 -02:00
return $response['created'];
}
2018-03-11 16:07:54 +01:00
function delete($type, $queryWhere, $limit = 0) {
//! use $limit
2017-10-18 17:13:23 -02:00
$ids = array();
if (isset($_GET["where"]["_id"]) && $_GET["where"]["_id"]) {
2017-10-18 17:13:23 -02:00
$ids[] = $_GET["where"]["_id"];
}
if (isset($_POST['check'])) {
2017-10-18 17:13:23 -02:00
foreach ($_POST['check'] as $check) {
$parts = preg_split('~ *= *~', $check);
if (count($parts) == 2) {
$ids[] = trim($parts[1]);
}
}
}
2017-10-18 17:13:23 -02:00
$this->_conn->affected_rows = 0;
2017-10-18 17:13:23 -02:00
foreach ($ids as $id) {
2025-02-21 10:57:11 +01:00
$query = "$type/$id";
$response = $this->_conn->query($query, null, 'DELETE');
if ((isset($response['found']) && $response['found']) || (isset($response['result']) && $response['result'] == 'deleted')) {
2017-10-18 17:13:23 -02:00
$this->_conn->affected_rows++;
}
}
2017-10-18 17:13:23 -02:00
return $this->_conn->affected_rows;
}
2021-04-05 00:13:07 +02:00
function convertOperator($operator) {
return $operator == "LIKE %%" ? "should" : $operator;
}
2013-07-09 17:38:13 -07:00
}
2013-07-09 17:38:13 -07:00
function connect() {
2025-03-05 14:12:42 +01:00
$connection = new Db;
list($server, $username, $password) = adminer()->credentials();
2025-02-18 07:58:27 +01:00
if (!preg_match('~^(https?://)?[-a-z\d.]+(:\d+)?$~', $server)) {
return lang('Invalid server.');
}
2018-05-04 16:52:41 +02:00
if ($password != "" && $connection->connect($server, $username, "")) {
return lang('Database does not support password.');
}
2018-05-04 16:52:41 +02:00
if ($connection->connect($server, $username, $password)) {
2013-07-09 17:38:13 -07:00
return $connection;
}
2013-07-09 17:38:13 -07:00
return $connection->error;
}
2013-07-09 17:38:13 -07:00
function support($feature) {
return preg_match("~database|table|columns~", $feature);
2013-07-09 17:38:13 -07:00
}
2013-07-09 17:38:13 -07:00
function logged_user() {
$credentials = adminer()->credentials();
2013-07-09 17:38:13 -07:00
return $credentials[1];
}
2013-07-09 17:38:13 -07:00
function get_databases() {
$return = connection()->rootQuery('_aliases');
2013-07-09 17:38:13 -07:00
if ($return) {
$return = array_keys($return);
2014-09-16 17:40:47 +02:00
sort($return, SORT_STRING);
2013-07-09 17:38:13 -07:00
}
2013-07-09 17:38:13 -07:00
return $return;
}
2021-04-05 00:13:07 +02:00
function limit($query, $where, $limit, $offset = 0, $separator = " ") {
return " $query$where" . ($limit !== null ? $separator . "LIMIT $limit" . ($offset ? " OFFSET $offset" : "") : "");
}
2013-07-09 17:38:13 -07:00
function collations() {
return array();
}
2013-07-09 17:38:13 -07:00
function db_collation($db, $collations) {
//
2013-07-09 17:38:13 -07:00
}
2025-02-21 13:53:18 +01:00
function engines() {
return array();
}
2013-07-09 17:38:13 -07:00
function count_tables($databases) {
$return = array();
$result = connection()->query('_stats');
2017-10-18 17:13:23 -02:00
if ($result && $result['indices']) {
$indices = $result['indices'];
2018-02-06 12:50:36 +01:00
foreach ($indices as $indice => $stats) {
2017-10-18 17:13:23 -02:00
$indexing = $stats['total']['indexing'];
$return[$indice] = $indexing['index_total'];
}
2013-07-09 17:38:13 -07:00
}
2013-07-09 17:38:13 -07:00
return $return;
}
2013-07-09 17:38:13 -07:00
function tables_list() {
if (min_version(7)) {
return array('_doc' => 'table');
}
$return = connection()->query('_mapping');
2013-07-09 17:38:13 -07:00
if ($return) {
$return = array_fill_keys(array_keys($return[connection()->_db]["mappings"]), 'table');
2013-07-09 17:38:13 -07:00
}
2013-07-09 17:38:13 -07:00
return $return;
}
2013-07-09 17:38:13 -07:00
function table_status($name = "", $fast = false) {
$search = connection()->query("_search", array(
2017-10-18 17:13:23 -02:00
"size" => 0,
"aggregations" => array(
"count_by_type" => array(
"terms" => array(
2017-10-18 17:13:23 -02:00
"field" => "_type"
)
)
)
), "POST");
$return = array();
if ($search) {
2017-10-18 17:13:23 -02:00
$tables = $search["aggregations"]["count_by_type"]["buckets"];
2017-10-18 17:13:23 -02:00
foreach ($tables as $table) {
$return[$table["key"]] = array(
"Name" => $table["key"],
"Engine" => "table",
2017-10-18 17:13:23 -02:00
"Rows" => $table["doc_count"],
);
2017-10-18 17:13:23 -02:00
if ($name != "" && $name == $table["key"]) {
2016-03-16 12:05:51 +01:00
return $return[$name];
}
2013-07-09 17:38:13 -07:00
}
}
2013-07-09 17:38:13 -07:00
return $return;
}
2013-07-09 17:38:13 -07:00
function error() {
return h(connection()->error);
2013-07-09 17:38:13 -07:00
}
2013-07-09 17:38:13 -07:00
function information_schema() {
}
2013-07-09 17:38:13 -07:00
function is_view($table_status) {
}
2013-07-09 17:38:13 -07:00
function indexes($table, $connection2 = null) {
return array(
array("type" => "PRIMARY", "columns" => array("_id")),
);
}
2013-07-09 17:38:13 -07:00
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"]);
}
2013-07-09 17:38:13 -07:00
}
}
2013-07-09 17:38:13 -07:00
return $return;
}
2013-07-09 17:38:13 -07:00
function foreign_keys($table) {
return array();
}
2013-07-09 17:38:13 -07:00
function table($idf) {
return $idf;
}
2013-07-09 17:38:13 -07:00
function idf_escape($idf) {
return $idf;
}
2013-07-09 17:38:13 -07:00
function convert_field($field) {
//
2013-07-09 17:38:13 -07:00
}
2013-07-09 17:38:13 -07:00
function unconvert_field($field, $return) {
return $return;
}
2013-07-09 17:38:13 -07:00
function fk_support($table_status) {
//
2013-07-09 17:38:13 -07:00
}
2013-07-09 17:38:13 -07:00
function found_rows($table_status, $where) {
return null;
}
2017-10-18 17:13:23 -02:00
/** Create index
* @param string
* @return mixed
*/
function create_database($db) {
return connection()->rootQuery(urlencode($db), null, 'PUT');
}
2017-10-18 17:13:23 -02:00
/** Remove index
* @param array
* @return mixed
*/
function drop_databases($databases) {
return connection()->rootQuery(urlencode(implode(',', $databases)), null, 'DELETE');
}
2017-10-18 17:13:23 -02:00
/** Alter type
* @param array
* @return mixed
*/
2017-10-18 17:13:23 -02:00
function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
$properties = array();
2018-02-06 12:50:36 +01:00
foreach ($fields as $f) {
2017-10-18 17:13:23 -02:00
$field_name = trim($f[1][0]);
2018-01-27 11:08:56 +01:00
$field_type = trim($f[1][1] ? $f[1][1] : "text");
2017-10-18 17:13:23 -02:00
$properties[$field_name] = array(
'type' => $field_type
);
}
2017-10-18 17:13:23 -02:00
if (!empty($properties)) {
$properties = array('properties' => $properties);
}
2025-02-21 10:57:11 +01:00
return connection()->query("_mapping/$name", $properties, 'PUT');
2017-10-18 17:13:23 -02:00
}
/** Drop types
* @param array
* @return bool
*/
function drop_tables($tables) {
2014-01-09 22:28:42 -08:00
$return = true;
foreach ($tables as $table) { //! convert to bulk api
$return = $return && connection()->query(urlencode($table), null, 'DELETE');
}
2014-01-09 22:28:42 -08:00
return $return;
}
2017-10-18 17:13:23 -02:00
function last_id() {
return connection()->last_id;
2017-10-18 17:13:23 -02:00
}
2013-07-09 17:38:13 -07:00
}