Adminer With Custom Login Servers Selector Plugin Run In Docker
Tags: adminer, docker, database
Published: 2024-01-21 12:56:51

In the world of database management, Adminer has emerged as a compact yet powerful tool for handling a wide range of database tasks. While its core functionality is impressive, the real power of Adminer lies in its extensibility through plugins. In this post, we’ll dive into the creation and implementation of a custom plugin for Adminer.

Repo: [https://github.com/garis-space/adminer-login-servers](https://github.com/garis-space/adminer-login-servers)

---

**The Genesis of the Plugin**
The Adminer Login Server Selector Plugin was born out of a need to streamline the process of connecting to various database servers. Traditionally, connecting to different servers in Adminer requires manual entry of connection details — a process that can be tedious and error-prone. This plugin elegantly solves this problem by allowing users to select their desired server from a predefined list.

---

**How Does the Plugin Work?**
The plugin, written in PHP, integrates seamlessly with Adminer. Here’s a breakdown of its functionality:

- **Dynamic Server List:** The plugin reads a JSON-formatted list of server configurations from an environment variable, ADMINER_SERVERS. This list can include details for multiple servers, each with its own driver, server address, username, password, and database name.

- **User Interface Integration:** In the Adminer login form, the plugin injects a dropdown menu populated with the server names defined in the ADMINER_SERVERS variable. Users can select a server from this dropdown, and the plugin automatically fills in the corresponding connection details.

- **Customization and Flexibility:** The plugin is flexible and easily customizable. Users can add, remove, or modify server configurations in the environment variable without altering the plugin’s code.

---

**Adminer Login Servers Plugin Code**

```php
<?php

/**
 * Display servers list from defined ADMINER_SERVERS variable.
 * @link https://www.adminer.org/plugins/#use
 * @author https://github.com/garis-space
*/
class AdminerLoginServers {
  /**
   * Set servers from environment variable
   * Example:
   * $_ENV['ADMINER_SERVERS'] = '{
   *  "Server 1":{"driver":"pgsql","server":"","username":"","password":"","db":""},
   *  "Server 2":{"driver":"pgsql","server":"","username":"","password":"","db":""}
   * }';
  */
  function __construct() {
    $this->servers = array();
    if ($_ENV['ADMINER_SERVERS']) {
      $this->servers = json_decode($_ENV['ADMINER_SERVERS'], true);
    }

    if ($_POST["auth"]["custom_server"]) {
      $key = $_POST["auth"]["custom_server"];
      $_POST["auth"]["driver"] = $this->servers[$key]["driver"];
      $_POST["auth"]["server"] = $this->servers[$key]["server"];
      $_POST["auth"]["username"] = $this->servers[$key]["username"];
      $_POST["auth"]["password"] = $this->servers[$key]["password"];
      $_POST["auth"]["db"] = $this->servers[$key]["db"];
    }
  }

  function loginFormField($name, $heading, $value) {
    if ($name == 'driver') {
      return '<tr><th>Driver<td>' . $value;
    } elseif ($name == 'server') {
      return '<tr><th>Host<td>' . $value;
    } elseif ($name == 'db' && $_ENV['ADMINER_SERVERS'] != '') {
      $out = $heading . $value;
      $out .= '<tr><th><td>or';
      $out .= '<tr><th>Server<td><select name="auth[custom_server]">';
      $out .= '<option value="" selected>--</option>';
      foreach ($this->servers as $serverName => $serverConfig) {
          $out .= '<option value="' . htmlspecialchars($serverName) . '">' . htmlspecialchars($serverName) . '</option>';
      }
      $out .= '</select>';
      return $out;
    }
  }
}

return new AdminerLoginServers();
```

---

**Configuring Servers via `compose.yml` or `.env`**
One of the standout features of this plugin is its ability to integrate with Docker Compose and environment variable configurations. This integration offers a high degree of flexibility and ease of use, especially in development and testing environments.

In the `compose.yml` file, you can define in the `ADMINER_SERVERS` variable only the server data you want to keep in your repository and save the rest in the .env file. As you have surely noticed, the `ADMINER_SERVERS` variable from the .env file is added to the end of the permanently defined `ADMINER_SERVERS` list from compose.yml file. This allows you to separate different login credentials for different environments.

**compose.yml file**

```
x-env-file: &env-file
  env_file: .env
x-restart: &restart
  restart: always

services:
  postgres-12:
    ...

  postgres-16:
    ...

  adminer:
    <<: [*env-file, *restart]
    image: adminer:latest
    container_name: adminer
    environment:
      # Login Servers Plugin
      - ADMINER_SERVERS={
          "[env1] PostgreSQL 12":{
            "driver":"pgsql",
            "server":"${POSTGRES_12_HOST}",
            "username":"${POSTGRES_12_USER:-postgres}",
            "password":"${POSTGRES_12_PASSWORD}",
            "db":"${POSTGRES_12_DB:-postgres}"
          },
          "[env2] PostgreSQL 16":{
            "driver":"pgsql",
            "server":"${POSTGRES_16_HOST}",
            "username":"${POSTGRES_16_USER:-postgres}",
            "password":"${POSTGRES_16_PASSWORD}",
            "db":"${POSTGRES_16_DB:-postgres}"
          } ${ADMINER_SERVERS}
        }
    volumes:
      - ./adminer/login-servers.php:/var/www/html/plugins-enabled/login-servers.php
    ports:
      - 8080:8080
```

**.env file**

```
# Adminer
ADMINER_SERVERS=',
  "[env3] GCP Cloud SQL":{
    "driver":"pgsql",
    "server":"postgres-16",
    "username":"postgres",
    "password":"super_secret_password",
    "db":"postgres"
  },
  "[env4] AWS RDS":{
    "driver":"pgsql",
    "server":"postgres-16",
    "username":"postgres",
    "password":"super_secret_password",
    "db":"postgres"
  },
  "[env5] Azure SQL":{
    "driver":"pgsql",
    "server":"postgres-16",
    "username":"postgres",
    "password":"super_secret_password",
    "db":"postgres"
  }
'
```

---

**Conclusion**
The Adminer Login Server Selector Plugin is a testament to the power of customization in software development. By bridging the gap between user convenience and functional flexibility, this plugin not only enhances the Adminer experience but also demonstrates the vast possibilities within the realms of PHP and Docker. It’s an excellent example of how a small, focused tool can make a significant impact on workflow efficiency.