Files
adminer/plugins/drivers/simpledb.php

473 lines
12 KiB
PHP
Raw Normal View History

2013-07-06 10:31:21 -07:00
<?php
2025-03-05 11:28:53 +01:00
namespace Adminer;
add_driver("simpledb", "SimpleDB");
2013-07-06 10:31:21 -07:00
if (isset($_GET["simpledb"])) {
2025-03-06 17:34:21 +01:00
define('Adminer\DRIVER', "simpledb");
if (class_exists('SimpleXMLElement') && ini_bool('allow_url_fopen')) {
2025-03-05 14:12:42 +01:00
class Db {
2025-03-11 08:08:32 +01:00
public $extension = "SimpleXML", $server_info = '2009-04-15', $error, $timeout, $next, $affected_rows;
2025-03-11 07:46:31 +01:00
private $result;
2013-07-06 10:31:21 -07:00
function select_db($database) {
return ($database == "domain");
}
2013-07-06 10:31:21 -07:00
function query($query, $unbuffered = false) {
$params = array('SelectExpression' => $query, 'ConsistentRead' => 'true');
if ($this->next) {
$params['NextToken'] = $this->next;
}
$result = sdb_request_all('Select', 'Item', $params, $this->timeout); //! respect $unbuffered
2018-03-09 18:06:19 +01:00
$this->timeout = 0;
2013-07-06 10:31:21 -07:00
if ($result === false) {
return $result;
}
if (preg_match('~^\s*SELECT\s+COUNT\(~i', $query)) {
$sum = 0;
foreach ($result as $item) {
$sum += $item->Attribute->Value;
}
$result = array((object) array('Attribute' => array((object) array(
'Name' => 'Count',
'Value' => $sum,
))));
}
2025-03-05 14:12:42 +01:00
return new Result($result);
2013-07-06 10:31:21 -07:00
}
2013-07-06 10:31:21 -07:00
function multi_query($query) {
2025-03-11 07:46:31 +01:00
return $this->result = $this->query($query);
2013-07-06 10:31:21 -07:00
}
2013-07-06 10:31:21 -07:00
function store_result() {
2025-03-11 07:46:31 +01:00
return $this->result;
2013-07-06 10:31:21 -07:00
}
2013-07-06 10:31:21 -07:00
function next_result() {
return false;
}
2013-07-06 10:31:21 -07:00
function quote($string) {
return "'" . str_replace("'", "''", $string) . "'";
}
}
2025-03-05 14:12:42 +01:00
class Result {
2025-03-11 08:08:32 +01:00
public $num_rows;
2025-03-11 07:46:31 +01:00
private $rows = array(), $offset = 0;
2015-08-15 17:04:21 +02:00
function __construct($result) {
2013-07-06 10:31:21 -07:00
foreach ($result as $item) {
$row = array();
if ($item->Name != '') { // SELECT COUNT(*)
$row['itemName()'] = (string) $item->Name;
}
foreach ($item->Attribute as $attribute) {
2025-03-11 07:56:28 +01:00
$name = $this->processValue($attribute->Name);
$value = $this->processValue($attribute->Value);
2013-08-06 14:55:56 -07:00
if (isset($row[$name])) {
$row[$name] = (array) $row[$name];
$row[$name][] = $value;
} else {
$row[$name] = $value;
}
2013-07-06 10:31:21 -07:00
}
2025-03-11 07:46:31 +01:00
$this->rows[] = $row;
2013-07-06 10:31:21 -07:00
foreach ($row as $key => $val) {
2025-03-11 07:46:31 +01:00
if (!isset($this->rows[0][$key])) {
$this->rows[0][$key] = null;
2013-07-06 10:31:21 -07:00
}
}
}
2025-03-11 07:46:31 +01:00
$this->num_rows = count($this->rows);
2013-07-06 10:31:21 -07:00
}
2025-03-11 07:56:28 +01:00
private function processValue($element) {
2013-07-06 10:31:21 -07:00
return (is_object($element) && $element['encoding'] == 'base64' ? base64_decode($element) : (string) $element);
}
2013-07-06 10:31:21 -07:00
function fetch_assoc() {
2025-03-11 07:46:31 +01:00
$row = current($this->rows);
2013-07-06 10:31:21 -07:00
if (!$row) {
return $row;
}
$return = array();
2025-03-11 07:46:31 +01:00
foreach ($this->rows[0] as $key => $val) {
2013-07-06 10:31:21 -07:00
$return[$key] = $row[$key];
}
2025-03-11 07:46:31 +01:00
next($this->rows);
2013-07-06 10:31:21 -07:00
return $return;
}
2013-07-06 10:31:21 -07:00
function fetch_row() {
$return = $this->fetch_assoc();
if (!$return) {
return $return;
}
return array_values($return);
}
2013-07-06 10:31:21 -07:00
function fetch_field() {
2025-03-11 07:46:31 +01:00
$keys = array_keys($this->rows[0]);
return (object) array('name' => $keys[$this->offset++]);
2013-07-06 10:31:21 -07:00
}
}
}
2025-03-05 14:12:42 +01:00
class Driver extends SqlDriver {
static $possibleDrivers = array("SimpleXML + allow_url_fopen");
static $jush = "simpledb";
2025-03-11 08:08:32 +01:00
public $operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "IS NOT NULL");
public $grouping = array("count");
2014-01-11 17:27:04 -08:00
public $primary = "itemName()";
2025-03-11 07:56:28 +01:00
private function chunkRequest($ids, $action, $params, $expand = array()) {
$connection = connection();
2013-07-06 10:31:21 -07:00
foreach (array_chunk($ids, 25) as $chunk) {
$params2 = $params;
foreach ($chunk as $i => $id) {
$params2["Item.$i.ItemName"] = $id;
foreach ($expand as $key => $val) {
$params2["Item.$i.$key"] = $val;
}
}
if (!sdb_request($action, $params2)) {
return false;
}
}
$connection->affected_rows = count($ids);
2013-07-06 10:31:21 -07:00
return true;
}
2025-03-11 07:56:28 +01:00
private function extractIds($table, $queryWhere, $limit) {
2013-07-06 10:31:21 -07:00
$return = array();
2013-08-09 17:16:06 -07:00
if (preg_match_all("~itemName\(\) = (('[^']*+')+)~", $queryWhere, $matches)) {
2025-03-05 12:28:01 +01:00
$return = array_map('Adminer\idf_unescape', $matches[1]);
2013-07-06 10:31:21 -07:00
} else {
foreach (sdb_request_all('Select', 'Item', array('SelectExpression' => 'SELECT itemName() FROM ' . table($table) . $queryWhere . ($limit ? " LIMIT 1" : ""))) as $item) {
$return[] = $item->Name;
}
}
return $return;
}
2014-01-15 08:23:26 -08:00
function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) {
$connection = connection();
2013-07-09 17:38:13 -07:00
$connection->next = $_GET["next"];
2014-01-08 23:14:37 -08:00
$return = parent::select($table, $select, $where, $group, $order, $limit, $page, $print);
2013-07-09 17:38:13 -07:00
$connection->next = 0;
return $return;
}
2013-07-06 10:31:21 -07:00
function delete($table, $queryWhere, $limit = 0) {
2025-03-11 07:56:28 +01:00
return $this->chunkRequest(
$this->extractIds($table, $queryWhere, $limit),
2013-07-06 10:31:21 -07:00
'BatchDeleteAttributes',
array('DomainName' => $table)
);
}
2013-07-06 10:31:21 -07:00
function update($table, $set, $queryWhere, $limit = 0, $separator = "\n") {
$delete = array();
$insert = array();
$i = 0;
2025-03-11 07:56:28 +01:00
$ids = $this->extractIds($table, $queryWhere, $limit);
2013-08-09 17:16:06 -07:00
$id = idf_unescape($set["`itemName()`"]);
unset($set["`itemName()`"]);
2013-07-06 10:31:21 -07:00
foreach ($set as $key => $val) {
$key = idf_unescape($key);
2013-08-09 17:16:06 -07:00
if ($val == "NULL" || ($id != "" && array($id) != $ids)) {
2013-07-06 10:31:21 -07:00
$delete["Attribute." . count($delete) . ".Name"] = $key;
2013-08-09 17:16:06 -07:00
}
if ($val != "NULL") {
2013-08-09 15:49:34 -07:00
foreach ((array) $val as $k => $v) {
$insert["Attribute.$i.Name"] = $key;
$insert["Attribute.$i.Value"] = (is_array($val) ? $v : idf_unescape($v));
if (!$k) {
$insert["Attribute.$i.Replace"] = "true";
}
$i++;
}
2013-07-06 10:31:21 -07:00
}
}
$params = array('DomainName' => $table);
2025-03-11 07:56:28 +01:00
return (!$insert || $this->chunkRequest(($id != "" ? array($id) : $ids), 'BatchPutAttributes', $params, $insert))
&& (!$delete || $this->chunkRequest($ids, 'BatchDeleteAttributes', $params, $delete))
2013-07-06 10:31:21 -07:00
;
}
2013-07-06 10:31:21 -07:00
function insert($table, $set) {
$params = array("DomainName" => $table);
$i = 0;
foreach ($set as $name => $value) {
if ($value != "NULL") {
$name = idf_unescape($name);
if ($name == "itemName()") {
2013-08-09 16:26:51 -07:00
$params["ItemName"] = idf_unescape($value);
2013-07-06 10:31:21 -07:00
} else {
2013-08-09 16:26:51 -07:00
foreach ((array) $value as $val) {
$params["Attribute.$i.Name"] = $name;
$params["Attribute.$i.Value"] = (is_array($value) ? $val : idf_unescape($value));
$i++;
}
2013-07-06 10:31:21 -07:00
}
}
}
return sdb_request('PutAttributes', $params);
}
2013-07-09 11:34:12 -07:00
function insertUpdate($table, $rows, $primary) {
//! use one batch request
foreach ($rows as $set) {
if (!$this->update($table, $set, "WHERE `itemName()` = " . q($set["`itemName()`"]))) {
return false;
}
}
return true;
2013-07-09 10:51:38 -07:00
}
2013-07-09 11:43:01 -07:00
function begin() {
return false;
}
2013-07-09 11:43:01 -07:00
function commit() {
return false;
}
2013-07-09 11:43:01 -07:00
function rollback() {
return false;
}
2025-02-21 13:53:18 +01:00
2018-03-09 18:06:19 +01:00
function slowQuery($query, $timeout) {
2025-03-11 07:49:10 +01:00
$this->conn->timeout = $timeout;
2018-03-09 18:06:19 +01:00
return $query;
}
2013-07-06 10:31:21 -07:00
}
2025-03-07 12:03:29 +01:00
function connect($credentials) {
list($host, , $password) = $credentials;
2025-02-18 07:58:27 +01:00
if (!preg_match('~^(https?://)?[-a-z\d.]+(:\d+)?$~', $host)) {
return lang('Invalid server.');
}
2018-05-04 16:52:41 +02:00
if ($password != "") {
return lang('Database does not support password.');
}
2025-03-05 14:12:42 +01:00
return new Db;
2013-07-06 10:31:21 -07:00
}
2013-07-06 10:31:21 -07:00
function support($feature) {
return preg_match('~sql~', $feature);
2013-07-06 10:31:21 -07:00
}
2013-07-06 10:31:21 -07:00
function logged_user() {
$adminer = adminer();
2013-07-06 10:31:21 -07:00
$credentials = $adminer->credentials();
return $credentials[1];
}
2013-07-06 10:31:21 -07:00
function get_databases() {
return array("domain");
}
2013-07-06 10:31:21 -07:00
function collations() {
return array();
}
2013-07-06 10:31:21 -07:00
function db_collation($db, $collations) {
}
2013-07-06 10:31:21 -07:00
function tables_list() {
$connection = connection();
2013-07-06 10:31:21 -07:00
$return = array();
foreach (sdb_request_all('ListDomains', 'DomainName') as $table) {
$return[(string) $table] = 'table';
}
2025-03-06 17:34:21 +01:00
if ($connection->error && defined('Adminer\PAGE_HEADER')) {
2013-07-06 10:31:21 -07:00
echo "<p class='error'>" . error() . "\n";
}
return $return;
}
2013-07-06 10:31:21 -07:00
function table_status($name = "", $fast = false) {
$return = array();
foreach (($name != "" ? array($name => true) : tables_list()) as $table => $type) {
$row = array("Name" => $table, "Auto_increment" => "");
if (!$fast) {
$meta = sdb_request('DomainMetadata', array('DomainName' => $table));
if ($meta) {
2025-03-05 14:59:13 +01:00
foreach (
array(
"Rows" => "ItemCount",
"Data_length" => "ItemNamesSizeBytes",
"Index_length" => "AttributeValuesSizeBytes",
"Data_free" => "AttributeNamesSizeBytes",
) as $key => $val
) {
2013-07-06 10:31:21 -07:00
$row[$key] = (string) $meta->$val;
}
}
}
if ($name != "") {
return $row;
}
$return[$table] = $row;
}
return $return;
}
2013-07-06 10:31:21 -07:00
function explain($connection, $query) {
}
2013-07-06 10:31:21 -07:00
function error() {
$connection = connection();
2013-07-06 10:31:21 -07:00
return h($connection->error);
}
2013-07-06 10:31:21 -07:00
function information_schema() {
}
2013-07-06 10:31:21 -07:00
function indexes($table, $connection2 = null) {
return array(
array("type" => "PRIMARY", "columns" => array("itemName()")),
);
}
2013-07-06 10:31:21 -07:00
function fields($table) {
2014-01-11 15:44:03 -08:00
return fields_from_edit();
2013-07-06 10:31:21 -07:00
}
2013-07-06 10:31:21 -07:00
function foreign_keys($table) {
return array();
}
2013-07-06 10:31:21 -07:00
function table($idf) {
return idf_escape($idf);
}
2013-07-06 10:31:21 -07:00
function idf_escape($idf) {
return "`" . str_replace("`", "``", $idf) . "`";
}
2013-07-06 10:31:21 -07:00
function limit($query, $where, $limit, $offset = 0, $separator = " ") {
return " $query$where" . ($limit !== null ? $separator . "LIMIT $limit" : "");
}
2013-07-06 10:31:21 -07:00
function unconvert_field($field, $return) {
return $return;
}
2013-07-06 10:31:21 -07:00
function fk_support($table_status) {
}
2013-07-06 10:31:21 -07:00
function engines() {
return array();
}
2013-07-06 10:31:21 -07:00
function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
return ($table == "" && sdb_request('CreateDomain', array('DomainName' => $name)));
}
2013-07-06 10:31:21 -07:00
function drop_tables($tables) {
foreach ($tables as $table) {
if (!sdb_request('DeleteDomain', array('DomainName' => $table))) {
return false;
}
}
return true;
}
2013-07-06 10:31:21 -07:00
function count_tables($databases) {
foreach ($databases as $db) {
return array($db => count(tables_list()));
}
}
2013-07-06 10:31:21 -07:00
function found_rows($table_status, $where) {
return ($where ? null : $table_status["Rows"]);
}
2013-07-06 10:31:21 -07:00
function last_id() {
}
2013-07-06 10:31:21 -07:00
function sdb_request($action, $params = array()) {
$adminer = adminer();
$connection = connection();
2013-07-06 10:31:21 -07:00
list($host, $params['AWSAccessKeyId'], $secret) = $adminer->credentials();
$params['Action'] = $action;
$params['Timestamp'] = gmdate('Y-m-d\TH:i:s+00:00');
$params['Version'] = '2009-04-15';
$params['SignatureVersion'] = 2;
$params['SignatureMethod'] = 'HmacSHA1';
ksort($params);
$query = '';
foreach ($params as $key => $val) {
$query .= '&' . rawurlencode($key) . '=' . rawurlencode($val);
}
$query = str_replace('%7E', '~', substr($query, 1));
2025-03-05 15:45:37 +01:00
$query .= "&Signature=" . urlencode(base64_encode(hash_hmac('sha1', "POST\n" . preg_replace('~^https?://~', '', $host) . "\n/\n$query", $secret, true)));
$file = @file_get_contents((preg_match('~^https?://~', $host) ? $host : "http://$host"), false, stream_context_create(array('http' => array(
2013-07-06 10:31:21 -07:00
'method' => 'POST', // may not fit in URL with GET
'content' => $query,
2025-03-05 15:45:37 +01:00
'ignore_errors' => 1,
'follow_location' => 0,
'max_redirects' => 0,
2013-07-06 10:31:21 -07:00
))));
2013-07-06 22:33:19 -07:00
if (!$file) {
2025-02-18 08:16:53 +01:00
$this->error = lang('Invalid credentials.');
2013-07-06 10:31:21 -07:00
return false;
}
2013-07-06 22:33:19 -07:00
libxml_use_internal_errors(true);
2025-02-18 08:42:30 +01:00
libxml_disable_entity_loader();
2013-07-06 22:33:19 -07:00
$xml = simplexml_load_string($file);
if (!$xml) {
$error = libxml_get_last_error();
$connection->error = $error->message;
return false;
}
2013-07-06 10:31:21 -07:00
if ($xml->Errors) {
$error = $xml->Errors->Error;
$connection->error = "$error->Message ($error->Code)";
return false;
}
$connection->error = '';
$tag = $action . "Result";
2025-03-06 18:12:22 +01:00
return ($xml->$tag ?: true);
2013-07-06 10:31:21 -07:00
}
2013-07-06 10:31:21 -07:00
function sdb_request_all($action, $tag, $params = array(), $timeout = 0) {
$return = array();
$start = ($timeout ? microtime(true) : 0);
$limit = (preg_match('~LIMIT\s+(\d+)\s*$~i', $params['SelectExpression'], $match) ? $match[1] : 0);
do {
$xml = sdb_request($action, $params);
if (!$xml) {
break;
}
foreach ($xml->$tag as $element) {
$return[] = $element;
}
if ($limit && count($return) >= $limit) {
$_GET["next"] = $xml->NextToken;
break;
}
if ($timeout && microtime(true) - $start > $timeout) {
return false;
}
$params['NextToken'] = $xml->NextToken;
if ($limit) {
$params['SelectExpression'] = preg_replace('~\d+\s*$~', $limit - count($return), $params['SelectExpression']);
}
} while ($xml->NextToken);
return $return;
}
}