diff --git a/README.md b/README.md
index 99bc7b32c..f5313327d 100644
--- a/README.md
+++ b/README.md
@@ -48,7 +48,7 @@ For an overview of the software quality over time and the evolving metrics, chec
| functions.php | ❌ | yyyy-mm-dd |
| groups.php | ❌ | yyyy-mm-dd |
| help.php | ❌ | yyyy-mm-dd |
-| history.php | ❌ | yyyy-mm-dd |
+| history.php | ✅ | 2025-09-14 |
| index.php | ✅ | 2024-12-26 |
| indexes.php | ❌ | yyyy-mm-dd |
| info.php | ❌ | yyyy-mm-dd |
diff --git a/all_db.php b/all_db.php
index 881e3cc0e..b7fbda72c 100644
--- a/all_db.php
+++ b/all_db.php
@@ -1,5 +1,7 @@
printHeader($lang['strhistory']);
-
- // Bring to the front always
- echo "
\n";
-
- echo "
";
-
- if (!isset($_REQUEST['database'])) {
- echo "{$lang['strnodatabaseselected']}
\n";
- return;
- }
-
- if (isset($_SESSION['history'][$_REQUEST['server']][$_REQUEST['database']])) {
- include_once('classes/ArrayRecordSet.php');
-
- $history = new ArrayRecordSet($_SESSION['history'][$_REQUEST['server']][$_REQUEST['database']]);
-
- $columns = array(
- 'query' => array(
- 'title' => $lang['strsql'],
- 'field' => field('query'),
- ),
- 'paginate' => array(
- 'title' => $lang['strpaginate'],
- 'field' => field('paginate'),
- 'type' => 'yesno',
- ),
- 'actions' => array(
- 'title' => $lang['stractions'],
- ),
- );
-
- $actions = array(
- 'run' => array(
- 'content' => $lang['strexecute'],
- 'attr' => array (
- 'href' => array (
- 'url' => 'sql.php',
- 'urlvars' => array (
- 'subject' => 'history',
- 'nohistory' => 't',
- 'queryid' => field('queryid'),
- 'paginate' => field('paginate')
- )
- ),
- 'target' => 'detail'
- )
- ),
- 'remove' => array(
- 'content' => $lang['strdelete'],
- 'attr' => array (
- 'href' => array (
- 'url' => 'history.php',
- 'urlvars' => array (
- 'action' => 'confdelhistory',
- 'queryid' => field('queryid'),
- )
- )
- )
- )
- );
-
- $misc->printTable($history, $columns, $actions, 'history-history', $lang['strnohistory']);
- } else {
- echo "{$lang['strnohistory']}
\n";
- }
-
- $navlinks = array (
- 'refresh' => array (
- 'attr' => array (
- 'href' => array (
- 'url' => 'history.php',
- 'urlvars' => array (
- 'action' => 'history',
- 'server' => $_REQUEST['server'],
- 'database' => $_REQUEST['database'],
- )
- )
- ),
- 'content' => $lang['strrefresh']
- )
- );
-
- if (
- isset($_SESSION['history'][$_REQUEST['server']][$_REQUEST['database']])
- && count($_SESSION['history'][$_REQUEST['server']][$_REQUEST['database']])
- ) {
- $navlinks['download'] = array (
- 'attr' => array (
- 'href' => array (
- 'url' => 'history.php',
- 'urlvars' => array (
- 'action' => 'download',
- 'server' => $_REQUEST['server'],
- 'database' => $_REQUEST['database']
- )
- )
- ),
- 'content' => $lang['strdownload']
- );
- $navlinks['clear'] = array (
- 'attr' => array (
- 'href' => array (
- 'url' => 'history.php',
- 'urlvars' => array(
- 'action' => 'confclearhistory',
- 'server' => $_REQUEST['server'],
- 'database' => $_REQUEST['database']
- )
- )
- ),
- 'content' => $lang['strclearhistory']
- );
- }
-
- $misc->printNavLinks($navlinks, 'history-history', get_defined_vars());
-}
-
-function doDelHistory($qid, $confirm)
-{
- global $misc, $lang;
-
- if ($confirm) {
- $misc->printHeader($lang['strhistory']);
-
- // Bring to the front always
- echo "\n";
-
- echo "{$lang['strdelhistory']}
\n";
- echo "{$lang['strconfdelhistory']}
\n";
-
- echo "", htmlentities($_SESSION['history'][$_REQUEST['server']][$_REQUEST['database']][$qid]['query'], ENT_QUOTES, 'UTF-8'), "
";
- echo "\n";
- } else {
- unset($_SESSION['history'][$_REQUEST['server']][$_REQUEST['database']][$qid]);
- }
-}
-
-function doClearHistory($confirm)
-{
- global $misc, $lang;
-
- if ($confirm) {
- $misc->printHeader($lang['strhistory']);
-
- // Bring to the front always
- echo "\n";
-
- echo "{$lang['strclearhistory']}
\n";
- echo "{$lang['strconfclearhistory']}
\n";
-
- echo "\n";
- } else {
- unset($_SESSION['history'][$_REQUEST['server']][$_REQUEST['database']]);
- }
-}
-
-function doDownloadHistory()
-{
- header('Content-Type: application/download');
- $datetime = date('YmdHis');
- header("Content-Disposition: attachment; filename=history{$datetime}.sql");
-
- foreach ($_SESSION['history'][$_REQUEST['server']][$_REQUEST['database']] as $queries) {
- $query = rtrim($queries['query']);
- echo $query;
- if (substr($query, -1) != ';') {
- echo ';';
- }
- echo "\n";
- }
-
- exit;
-}
-
-switch ($action) {
- case 'confdelhistory':
- doDelHistory($_REQUEST['queryid'], true);
- break;
- case 'delhistory':
- if (isset($_POST['yes'])) {
- doDelHistory($_REQUEST['queryid'], false);
- }
- doDefault();
- break;
- case 'confclearhistory':
- doClearHistory(true);
- break;
- case 'clearhistory':
- if (isset($_POST['yes'])) {
- doClearHistory(false);
- }
- doDefault();
- break;
- case 'download':
- doDownloadHistory();
- break;
- default:
- doDefault();
-}
-
- // Set the name of the window
- $misc->setWindowName('history');
- $misc->printFooter();
+$website = new History();
+echo $website->buildHtmlString();
diff --git a/history_clear.php b/history_clear.php
new file mode 100644
index 000000000..5af80847b
--- /dev/null
+++ b/history_clear.php
@@ -0,0 +1,10 @@
+buildHtmlString();
diff --git a/history_delete.php b/history_delete.php
new file mode 100644
index 000000000..ef3b527ef
--- /dev/null
+++ b/history_delete.php
@@ -0,0 +1,10 @@
+buildHtmlString();
diff --git a/history_download.php b/history_download.php
new file mode 100644
index 000000000..d25035c63
--- /dev/null
+++ b/history_download.php
@@ -0,0 +1,10 @@
+buildHtmlString();
diff --git a/intro.php b/intro.php
index 24bf91f5a..03ded545e 100644
--- a/intro.php
+++ b/intro.php
@@ -1,5 +1,7 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Api/Servers/Tree.php b/src/Api/Servers/Tree.php
index edca84dae..5b06b7856 100644
--- a/src/Api/Servers/Tree.php
+++ b/src/Api/Servers/Tree.php
@@ -22,14 +22,20 @@ public function outputXmlTree(): void
$dom->formatOutput = true;
$dom->encoding = 'utf-8';
- $logins = isset($_SESSION['webdbLogin']) && is_array($_SESSION['webdbLogin']) ? $_SESSION['webdbLogin'] : [];
+ $logins = isset($_SESSION['webdbLogin']) && is_array($_SESSION['webdbLogin'])
+ ? $_SESSION['webdbLogin']
+ : [];
$root = $dom->createElement('tree');
$serverIdParam = RequestParameter::getString('server');
- $serverSession = !is_null($serverIdParam) ? ServerSession::fromServerId($serverIdParam) : null;
+ $serverSession = !is_null($serverIdParam)
+ ? ServerSession::fromServerId($serverIdParam)
+ : null;
+
if (!is_null($serverSession)) {
$dbConnection = $serverSession->getDatabaseConnection();
$dbs = $dbConnection->getDatabases();
+
foreach ($dbs as $dbData) {
$actionUrl = 'redirect.php';
$actionUrlParams = [
@@ -53,6 +59,7 @@ public function outputXmlTree(): void
}
} else {
$configuredServers = Config::getServers();
+
foreach ($configuredServers as $configuredServer) {
$tree = $dom->createElement('tree');
$tree->setAttribute('text', (string)$configuredServer->Name);
@@ -65,6 +72,7 @@ public function outputXmlTree(): void
$tree->setAttribute('action', $actionUrl);
$username = '';
+
if (
isset($logins[$serverId]) &&
is_array($logins[$serverId]) &&
@@ -80,7 +88,9 @@ public function outputXmlTree(): void
$tree->setAttribute('src', $srcUrl);
}
- $iconName = $username !== '' ? 'Server' : 'DisconnectedServer';
+ $iconName = $username !== ''
+ ? 'Server'
+ : 'DisconnectedServer';
$tree->setAttribute('icon', Config::getIcon($iconName));
$tree->setAttribute('openicon', Config::getIcon($iconName));
$tree->setAttribute('tooltip', $serverId);
diff --git a/src/Config.php b/src/Config.php
index f1925673d..056c32569 100644
--- a/src/Config.php
+++ b/src/Config.php
@@ -13,7 +13,7 @@
* 'extra_session_security'?: bool,
* 'left_width'?: int,
* 'owned_only'?: bool,
- * 'servers'?: Server[],
+ * 'servers'?: array,
* 'show_advanced'?: bool,
* 'show_system'?: bool
* }
@@ -38,6 +38,7 @@ final class Config
public static function extraSessionSecurity(): bool
{
$conf = self::tryGetConfigFileData();
+
return ($conf['extra_session_security'] ?? true) === true;
}
@@ -48,18 +49,22 @@ public static function getAvailableLocales(): array
{
$localeDir = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'locale';
$langDir = dir($localeDir);
+
if ($langDir === false) {
return [];
}
self::$availableLocales = [];
- while (false !== ($entry = $langDir->read())) {
+
+ while (($entry = $langDir->read()) !== false) {
if ($entry === '.' || $entry === '..') {
continue;
}
+
if (!is_dir($localeDir . DIRECTORY_SEPARATOR . $entry)) {
continue;
}
+
if (preg_match('/^(?P[a-z]{2})_(?P[A-Z]{2})$/', $entry, $matches)) {
self::$availableLocales[] = $entry;
}
@@ -74,6 +79,7 @@ public static function getAvailableLocales(): array
public static function getIcon(string|array $icon): string
{
$possiblePaths = [];
+
if (is_string($icon)) {
$theme = self::theme();
$path = "images/themes/{$theme}/{$icon}";
@@ -99,17 +105,19 @@ public static function getIcon(string|array $icon): string
}
/**
- * @return Server[]
+ * @return array
*/
public static function getServers(): array
{
$conf = self::tryGetConfigFileData();
+
return $conf['servers'] ?? [];
}
public static function leftWidth(): int
{
$conf = self::tryGetConfigFileData();
+
return $conf['left_width'] ?? 200;
}
@@ -117,17 +125,19 @@ public static function locale(): string
{
if (!isset(self::$data['locale'])) {
$locale = null;
+
if (
isset($_REQUEST['language']) &&
is_string($_REQUEST['language']) &&
self::languageIsAvailable($_REQUEST['language'])
) {
$locale = self::getNormalizedLocaleFromLocaleOrLanguage($_REQUEST['language']);
+
if (!is_null($locale)) {
setcookie(
name: 'webdbLanguage',
value: $locale,
- expires_or_options: time() + 31_536_000 // 1 year.
+ expires_or_options: time() + 31_536_000, // 1 year.
);
}
}
@@ -151,6 +161,7 @@ public static function locale(): string
}
$conf = self::tryGetConfigFileData();
+
if (
is_null($locale) &&
isset($conf['default_lang']) &&
@@ -164,21 +175,26 @@ public static function locale(): string
'/\s*(?P[a-z]{1,8}(?:-[a-z]{1,8})*)(?:;q=(?P[01](?:.\d{0,3})?))?\s*(?:,|$)/',
strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE']),
$matches,
- PREG_SET_ORDER
+ PREG_SET_ORDER,
);
$acceptLanguages = [];
- foreach ($matches as $match) { // $match[1] = language tag, [2] = quality
+
+ foreach ($matches as $match) { // $match[1] = language tag, [2] = quality
if (!isset($match['quality'])) {
- $match['quality'] = 1; // Default quality to 1
+ $match['quality'] = 1; // Default quality to 1
}
+
if ($match['quality'] <= 0 || $match['quality'] > 1) {
continue;
}
+
if (!self::languageIsAvailable($match['language'])) {
continue;
}
+
$normalizedLocale = self::getNormalizedLocaleFromLocaleOrLanguage($match['language']);
+
if (is_null($normalizedLocale)) {
continue;
}
@@ -224,6 +240,7 @@ public static function locale(): string
public static function getServerById(string $serverId): ?Server
{
$servers = self::getServers();
+
foreach ($servers as $server) {
if ($serverId === $server->id()) {
return $server;
@@ -236,6 +253,7 @@ public static function getServerById(string $serverId): ?Server
public static function ownedOnly(): bool
{
$conf = self::tryGetConfigFileData();
+
return $conf['owned_only'] ?? false;
}
@@ -245,6 +263,7 @@ public static function ownedOnly(): bool
public static function serverExists(string $serverId): bool
{
$servers = self::getServers();
+
foreach ($servers as $server) {
if ($serverId === $server->id()) {
return true;
@@ -257,12 +276,14 @@ public static function serverExists(string $serverId): bool
public static function showAdvanced(): bool
{
$conf = self::tryGetConfigFileData();
+
return $conf['show_advanced'] ?? false;
}
public static function showSystem(): bool
{
$conf = self::tryGetConfigFileData();
+
return $conf['show_system'] ?? false;
}
@@ -273,6 +294,7 @@ public static function theme(): string
if (isset($_REQUEST['server']) && is_string($_REQUEST['server'])) {
$serverIdTheme = self::tryGetThemeByServerId($_REQUEST['server']);
+
if ($serverIdTheme !== '') {
self::$data['theme'] = $serverIdTheme;
}
@@ -294,15 +316,11 @@ public static function theme(): string
self::$data['theme'] = $_SESSION['ppaTheme'];
}
- if (
- isset($_REQUEST['theme']) &&
- is_string($_REQUEST['theme']) &&
- Themes::cssExists($_REQUEST['theme'])
- ) {
+ if (isset($_REQUEST['theme']) && is_string($_REQUEST['theme']) && Themes::cssExists($_REQUEST['theme'])) {
setcookie(
name: 'ppaTheme',
value: $_REQUEST['theme'],
- expires_or_options: time() + 31_536_000 // 1 year.
+ expires_or_options: time() + 31_536_000, // 1 year.
);
self::$data['theme'] = $_REQUEST['theme'];
}
@@ -321,6 +339,7 @@ private static function getNormalizedLocaleFromLocaleOrLanguage(string $localeOr
$lowerCasedLocaleOrLanguage = strtolower($localeOrLanguage);
$languageIdsWithLocales = Language::getAvailableLanguageIdsWithLocales();
+
if (isset($languageIdsWithLocales[$lowerCasedLocaleOrLanguage])) {
return $languageIdsWithLocales[$lowerCasedLocaleOrLanguage];
}
@@ -331,10 +350,13 @@ private static function getNormalizedLocaleFromLocaleOrLanguage(string $localeOr
private static function languageIsAvailable(string $language): bool
{
$normalizedLocale = self::getNormalizedLocaleFromLocaleOrLanguage($language);
+
if (is_null($normalizedLocale)) {
return false;
}
+
$availableLocales = self::getAvailableLocales();
+
foreach ($availableLocales as $locale) {
if ($locale === $normalizedLocale) {
return true;
@@ -354,29 +376,37 @@ private static function tryGetConfigFileData(): array
$confDir = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'conf';
$yamlConfigFile = $confDir . DIRECTORY_SEPARATOR . 'config.yaml';
+
if (!file_exists($yamlConfigFile)) {
$yamlConfigFile = $confDir . DIRECTORY_SEPARATOR . 'config.yml';
}
+
$configYamlFileEnv = getenv('PHPPGADMIN_CONFIG_YAML_FILE');
+
if (is_string($configYamlFileEnv) && $configYamlFileEnv !== '') {
$yamlConfigFile = $confDir . DIRECTORY_SEPARATOR . $configYamlFileEnv;
}
if (file_exists($yamlConfigFile)) {
$yaml = (new YamlParser())->parseFile($yamlConfigFile);
+
if (is_array($yaml)) {
if (isset($yaml['default_lang']) && is_string($yaml['default_lang'])) {
self::$conf['default_lang'] = $yaml['default_lang'];
}
+
if (isset($yaml['extra_session_security']) && is_bool($yaml['extra_session_security'])) {
self::$conf['extra_session_security'] = $yaml['extra_session_security'];
}
+
if (isset($yaml['left_width']) && is_int($yaml['left_width'])) {
self::$conf['left_width'] = $yaml['left_width'];
}
+
if (isset($yaml['owned_only']) && is_bool($yaml['owned_only'])) {
self::$conf['owned_only'] = $yaml['owned_only'];
}
+
if (isset($yaml['servers']) && is_array($yaml['servers'])) {
self::$conf['servers'] = [];
@@ -417,9 +447,11 @@ private static function tryGetConfigFileData(): array
*/
}
}
+
if (isset($yaml['show_advanced']) && is_bool($yaml['show_advanced'])) {
self::$conf['show_advanced'] = $yaml['show_advanced'];
}
+
if (isset($yaml['show_system']) && is_bool($yaml['show_system'])) {
self::$conf['show_system'] = $yaml['show_system'];
}
@@ -438,6 +470,7 @@ private static function tryGetThemeByServerId(string $serverId): string
$servers = self::getServers();
$tmpTheme = '';
+
foreach ($servers as $info) {
if ($serverId !== $info->id()) {
continue;
diff --git a/src/DDD/Entities/Server.php b/src/DDD/Entities/Server.php
index 964db3bde..e4bb5966f 100644
--- a/src/DDD/Entities/Server.php
+++ b/src/DDD/Entities/Server.php
@@ -24,7 +24,7 @@ public function __construct(
protected SslMode $sslMode = SslMode::ALLOW,
protected DatabaseName $defaultDb = new DatabaseName('template1'),
protected Filename $pgDumpPath = new Filename('/usr/bin/pg_dump'),
- protected Filename $pgDumpAllPath = new Filename('/usr/bin/pg_dumpall')
+ protected Filename $pgDumpAllPath = new Filename('/usr/bin/pg_dumpall'),
) {
}
@@ -34,31 +34,37 @@ public function __construct(
public static function fromArray(array $input): self
{
$name = '';
+ $host = '127.0.0.1';
+ $port = 5_432;
+ $sslMode = 'allow';
+ $defaultDb = 'template1';
+ $pgDumpPath = '/usr/bin/pg_dump';
+ $pgDumpAllPath = '/usr/bin/pg_dumpall';
+
if (isset($input['desc']) && is_string($input['desc'])) {
$name = $input['desc'];
}
- $host = '127.0.0.1';
if (isset($input['host']) && is_string($input['host'])) {
$host = $input['host'];
}
- $port = 5432;
+
if (isset($input['port']) && is_int($input['port'])) {
$port = $input['port'];
}
- $sslMode = 'allow';
+
if (isset($input['sslmode']) && is_string($input['sslmode'])) {
$sslMode = strtolower($input['sslmode']);
}
- $defaultDb = 'template1';
+
if (isset($input['defaultdb']) && is_string($input['defaultdb'])) {
$defaultDb = $input['defaultdb'];
}
- $pgDumpPath = '/usr/bin/pg_dump';
+
if (isset($input['pgdumppath']) && is_string($input['pgdumppath'])) {
$pgDumpPath = $input['pgdumppath'];
}
- $pgDumpAllPath = '/usr/bin/pg_dumpall';
+
if (isset($input['pg_dumpall_path']) && is_string($input['pg_dumpall_path'])) {
$pgDumpAllPath = $input['pg_dumpall_path'];
}
@@ -70,7 +76,7 @@ public static function fromArray(array $input): self
sslMode: SslMode::from($sslMode),
defaultDb: new DatabaseName($defaultDb),
pgDumpPath: new Filename($pgDumpPath),
- pgDumpAllPath: new Filename($pgDumpAllPath)
+ pgDumpAllPath: new Filename($pgDumpAllPath),
);
}
diff --git a/src/DDD/Entities/ServerSession.php b/src/DDD/Entities/ServerSession.php
index a76c4dd1d..c1ecedaed 100644
--- a/src/DDD/Entities/ServerSession.php
+++ b/src/DDD/Entities/ServerSession.php
@@ -33,7 +33,7 @@ public function __construct(
DatabaseName $defaultDb = new DatabaseName('template1'),
Filename $pgDumpPath = new Filename('/usr/bin/pg_dump'),
Filename $pgDumpAllPath = new Filename('/usr/bin/pg_dumpall'),
- private Platform $platform = new Platform('PostgreSQL')
+ private Platform $platform = new Platform('PostgreSQL'),
) {
parent::__construct(
name: $name,
@@ -42,13 +42,14 @@ public function __construct(
sslMode: $sslMode,
defaultDb: $defaultDb,
pgDumpPath: $pgDumpPath,
- pgDumpAllPath: $pgDumpAllPath
+ pgDumpAllPath: $pgDumpAllPath,
);
}
public static function fromServerId(string $serverId): ?self
{
$servers = Config::getServers();
+
foreach ($servers as $server) {
if ($server->id() !== $serverId) {
continue;
@@ -106,7 +107,7 @@ public static function fromServerId(string $serverId): ?self
defaultDb: new DatabaseName((string)$server->DefaultDb),
pgDumpPath: new Filename((string)$server->PgDumpPath),
pgDumpAllPath: new Filename((string)$server->PgDumpAllPath),
- platform: new Platform($platform)
+ platform: new Platform($platform),
);
}
}
@@ -131,7 +132,7 @@ public function getDatabaseConnection(): PhpPgAdminConnection
sslmode: $this->SslMode->value,
user: (string)$this->Username,
password: (string)$this->Password,
- database: 'postgres'
+ database: 'postgres',
);
$connection->exec("SET client_encoding TO 'UTF-8'");
@@ -142,22 +143,29 @@ public function getDatabaseConnection(): PhpPgAdminConnection
public static function isLoggedIn(string $serverId): bool
{
+ if (!isset($_SESSION['webdbLogin']) || !is_array($_SESSION['webdbLogin'])) {
+ return false;
+ }
+
+ if (!isset($_SESSION['webdbLogin'][$serverId]) || !is_array($_SESSION['webdbLogin'][$serverId])) {
+ return false;
+ }
+
if (
- isset($_SESSION['webdbLogin']) &&
- is_array($_SESSION['webdbLogin']) &&
- isset($_SESSION['webdbLogin'][$serverId]) &&
- is_array($_SESSION['webdbLogin'][$serverId]) &&
- isset($_SESSION['webdbLogin'][$serverId]['username']) &&
- is_string($_SESSION['webdbLogin'][$serverId]['username']) &&
- $_SESSION['webdbLogin'][$serverId]['username'] !== '' &&
- isset($_SESSION['webdbLogin'][$serverId]['password']) &&
- is_string($_SESSION['webdbLogin'][$serverId]['password']) &&
- $_SESSION['webdbLogin'][$serverId]['password'] !== ''
+ !isset($_SESSION['webdbLogin'][$serverId]['username']) ||
+ !isset($_SESSION['webdbLogin'][$serverId]['password'])
) {
- return true;
+ return false;
+ }
+
+ $sessionUsername = $_SESSION['webdbLogin'][$serverId]['username'];
+ $sessionPassword = $_SESSION['webdbLogin'][$serverId]['password'];
+
+ if (!is_string($sessionUsername) || !is_string($sessionPassword)) {
+ return false;
}
- return false;
+ return $sessionUsername !== '' && $sessionPassword !== '';
}
public function __get(string $name): mixed
diff --git a/src/DDD/Repositories/History.php b/src/DDD/Repositories/History.php
new file mode 100644
index 000000000..365506f4b
--- /dev/null
+++ b/src/DDD/Repositories/History.php
@@ -0,0 +1,93 @@
+
+ */
+ public static function getHistory(string $serverId, string $database): array
+ {
+ $history = [];
+
+ if (!isset($_SESSION['history']) || !is_array($_SESSION['history'])) {
+ return $history;
+ }
+
+ if (!isset($_SESSION['history'][$serverId]) || !is_array($_SESSION['history'][$serverId])) {
+ return $history;
+ }
+
+ if (
+ !isset($_SESSION['history'][$serverId][$database]) ||
+ !is_array($_SESSION['history'][$serverId][$database])
+ ) {
+ return $history;
+ }
+
+ foreach ($_SESSION['history'][$serverId][$database] as $queryId => $entry) {
+ if (!is_string($queryId) || !is_array($entry)) {
+ continue;
+ }
+
+ if (!isset($entry['query']) || !is_string($entry['query'])) {
+ continue;
+ }
+
+ $paginate = false;
+
+ if (isset($entry['paginate']) && is_string($entry['paginate'])) {
+ $paginate = $entry['paginate'] === 't';
+ }
+
+ $history[$queryId] = [
+ 'paginate' => $paginate,
+ 'query' => $entry['query'],
+ ];
+ }
+
+ return $history;
+ }
+
+ /**
+ * @return array{'query': string, 'paginate': bool}|null
+ */
+ public static function getHistoryEntry(string $serverId, string $database, string $queryId): ?array
+ {
+ $history = self::getHistory($serverId, $database);
+
+ return $history[$queryId] ?? null;
+ }
+}
diff --git a/src/DDD/ValueObjects/DbSize.php b/src/DDD/ValueObjects/DbSize.php
index 13dfc87f8..10a54b448 100644
--- a/src/DDD/ValueObjects/DbSize.php
+++ b/src/DDD/ValueObjects/DbSize.php
@@ -28,14 +28,17 @@ public function prettyFormat(): string
_('GB'),
_('TB'),
];
+
foreach ($unitStrings as $unitString) {
if ($this->size < $limit * $multiplier) {
return sprintf('%d %s', floor(($this->size + $multiplier / 2) / $multiplier), $unitString);
}
+
$multiplier *= 1_024;
}
$multiplier /= 1_024;
+
return sprintf('%d %s', floor(($this->size + $multiplier / 2) / $multiplier), $unitString);
}
diff --git a/src/DDD/ValueObjects/Server/DatabaseName.php b/src/DDD/ValueObjects/Server/DatabaseName.php
index 515fd6fc3..4f70e52c9 100644
--- a/src/DDD/ValueObjects/Server/DatabaseName.php
+++ b/src/DDD/ValueObjects/Server/DatabaseName.php
@@ -11,6 +11,7 @@ final class DatabaseName implements \Stringable
public function __construct(string $name)
{
$name = trim($name);
+
if (empty($name)) {
throw new \InvalidArgumentException('Database name cannot be empty!');
}
diff --git a/src/DDD/ValueObjects/Server/Host.php b/src/DDD/ValueObjects/Server/Host.php
index 5d1af6c59..690d6cae9 100644
--- a/src/DDD/ValueObjects/Server/Host.php
+++ b/src/DDD/ValueObjects/Server/Host.php
@@ -11,6 +11,7 @@ final class Host implements \Stringable
public function __construct(string $host = '127.0.0.1')
{
$host = trim($host);
+
if (empty($host)) {
throw new \InvalidArgumentException('Host cannot be empty!');
}
diff --git a/src/DDD/ValueObjects/Server/Name.php b/src/DDD/ValueObjects/Server/Name.php
index c11dc2435..96f93aefa 100644
--- a/src/DDD/ValueObjects/Server/Name.php
+++ b/src/DDD/ValueObjects/Server/Name.php
@@ -11,6 +11,7 @@ final class Name implements \Stringable
public function __construct(string $name)
{
$name = trim($name);
+
if (empty($name)) {
throw new \InvalidArgumentException('Server name cannot be empty!');
}
diff --git a/src/DDD/ValueObjects/Server/Port.php b/src/DDD/ValueObjects/Server/Port.php
index 4567f7ec9..201461e18 100644
--- a/src/DDD/ValueObjects/Server/Port.php
+++ b/src/DDD/ValueObjects/Server/Port.php
@@ -9,9 +9,9 @@
*/
final class Port
{
- public function __construct(private int $port = 5432)
+ public function __construct(private int $port = 5_432)
{
- if ($port < 1 || $port > 65535) {
+ if ($port < 1 || $port > 65_535) {
throw new \InvalidArgumentException('Port must be between 1 and 65535');
}
}
diff --git a/src/DDD/ValueObjects/ServerSession/Password.php b/src/DDD/ValueObjects/ServerSession/Password.php
index 412ddf582..9cc9edfbf 100644
--- a/src/DDD/ValueObjects/ServerSession/Password.php
+++ b/src/DDD/ValueObjects/ServerSession/Password.php
@@ -11,6 +11,7 @@ final class Password implements \Stringable
public function __construct(string $password)
{
$password = trim($password);
+
if (empty($password)) {
throw new \InvalidArgumentException('ServerSession password cannot be empty!');
}
diff --git a/src/DDD/ValueObjects/ServerSession/Platform.php b/src/DDD/ValueObjects/ServerSession/Platform.php
index ab1a4baea..add478c00 100644
--- a/src/DDD/ValueObjects/ServerSession/Platform.php
+++ b/src/DDD/ValueObjects/ServerSession/Platform.php
@@ -11,6 +11,7 @@ final class Platform implements \Stringable
public function __construct(string $name)
{
$name = trim($name);
+
if (empty($name)) {
throw new \InvalidArgumentException('ServerSession platform cannot be empty!');
}
diff --git a/src/DDD/ValueObjects/ServerSession/Username.php b/src/DDD/ValueObjects/ServerSession/Username.php
index 110211a08..6e96ab041 100644
--- a/src/DDD/ValueObjects/ServerSession/Username.php
+++ b/src/DDD/ValueObjects/ServerSession/Username.php
@@ -11,6 +11,7 @@ final class Username implements \Stringable
public function __construct(string $name)
{
$name = trim($name);
+
if (empty($name)) {
throw new \InvalidArgumentException('ServerSession username cannot be empty!');
}
diff --git a/src/Database/PhpPgAdminConnection.php b/src/Database/PhpPgAdminConnection.php
index 14faf90ec..ae33f7b71 100644
--- a/src/Database/PhpPgAdminConnection.php
+++ b/src/Database/PhpPgAdminConnection.php
@@ -11,11 +11,9 @@
final class PhpPgAdminConnection extends \PDO
{
/**
- * Map of database encoding names to HTTP encoding names. If a
+ * Map of database encoding names to HTTP encoding names. If a
* database encoding does not appear in this list, then its HTTP
* encoding name is the same as its database encoding name.
- *
- * @var array
*/
public const CODEMAP = [
'BIG5' => 'BIG5',
@@ -74,7 +72,7 @@ public function alterDatabase(
string $dbName,
string $newName,
?string $newOwner = null,
- ?string $comment = null
+ ?string $comment = null,
): void {
if (!$this->beginTransaction()) {
throw new \PDOException('Failed to begin transaction.');
@@ -150,7 +148,7 @@ public function createDatabase(
string $comment = '',
string $template = 'template1',
string $lcCollate = '',
- string $lcCType = ''
+ string $lcCType = '',
): void {
$escapedDatabase = self::escapeIdentifier($database);
$escapedTemplate = self::escapeIdentifier($template);
@@ -158,23 +156,28 @@ public function createDatabase(
$sqlParams = [];
if ($encoding !== '') {
- if (!in_array($encoding, array_keys(self::CODEMAP))) {
+ if (!in_array(needle: $encoding, haystack: array_keys(self::CODEMAP), strict: true)) {
throw new \InvalidArgumentException("Invalid encoding: {$encoding}");
}
+
$sql .= " ENCODING = '{$encoding}'";
}
$availableCollations = $this->getAvailableCollations();
+
if ($lcCollate !== '') {
- if (!in_array($lcCollate, $availableCollations)) {
+ if (!in_array(needle: $lcCollate, haystack: $availableCollations, strict: true)) {
throw new \InvalidArgumentException("Invalid LC_COLLATE: {$lcCollate}");
}
+
$sql .= " LC_COLLATE = '{$lcCollate}'";
}
+
if ($lcCType !== '') {
- if (!in_array($lcCType, $availableCollations)) {
+ if (!in_array(needle: $lcCType, haystack: $availableCollations, strict: true)) {
throw new \InvalidArgumentException("Invalid LC_CTYPE: {$lcCType}");
}
+
$sql .= " LC_CTYPE = '{$lcCType}'";
}
@@ -184,6 +187,7 @@ public function createDatabase(
}
$statement = $this->prepare($sql);
+
if ($statement === false) {
throw new \PDOException('Failed to prepare SQL statement for creating database.');
}
@@ -201,26 +205,30 @@ public function dropDatabase(string $database): void
{
$escapedDatabase = self::escapeIdentifier($database);
$statement = "DROP DATABASE \"{$escapedDatabase}\"";
+
if ($this->exec($statement) === false) {
throw new \PDOException('Failed to execute SQL statement for dropping database.');
}
}
/**
- * @return string[]
+ * @return array
*/
public function getAvailableCollations(): array
{
$query = "SELECT collname FROM pg_collation WHERE collname LIKE '%.%' ORDER BY collname";
$statement = $this->prepare($query);
+
if ($statement === false) {
throw new \PDOException('Failed to prepare SQL statement for getting available collations.');
}
+
if (!$statement->execute()) {
throw new \PDOException('Failed to execute SQL statement for getting available collations.');
}
$collations = [];
+
while ($row = $statement->fetch()) {
if (is_array($row) && isset($row['collname']) && is_string($row['collname'])) {
$collations[] = $row['collname'];
@@ -238,14 +246,17 @@ public function getDatabaseComment(string $database): string
WHERE pg_database.datname = :database";
$sqlParams = ['database' => $database];
$statement = $this->prepare($sql);
+
if ($statement === false) {
throw new \PDOException('Failed to prepare SQL statement for getting database comment.');
}
+
if (!$statement->execute($sqlParams)) {
throw new \PDOException('Failed to execute SQL statement for getting database comment.');
}
$result = $statement->fetch();
+
if ($result === false) { // no comment found
return '';
}
@@ -270,14 +281,17 @@ public function getDatabaseOwner(string $database): string
'database' => $database,
];
$statement = $this->prepare($sql);
+
if ($statement === false) {
throw new \PDOException('Failed to prepare SQL statement for getting database owner.');
}
+
if (!$statement->execute($sqlParams)) {
throw new \PDOException('Failed to execute SQL statement for getting database owner.');
}
$result = $statement->fetch();
+
if (!is_array($result)) {
throw new \PDOException('Failed to fetch database owner.');
}
@@ -305,7 +319,9 @@ public function getDatabases(): array
{
$serverInfo = ServerSession::fromRequestParameter();
- $whereClause = Config::showSystem() ? 'pdb.datallowconn' : 'NOT pdb.datistemplate';
+ $whereClause = Config::showSystem()
+ ? 'pdb.datallowconn'
+ : 'NOT pdb.datistemplate';
if (!is_null($serverInfo) && Config::ownedOnly() && !$this->isSuperUser()) {
$whereClause = " AND pg_has_role('{$serverInfo->Username}'::name, pr.rolname, 'USAGE')";
@@ -334,6 +350,7 @@ public function getDatabases(): array
ORDER BY {$orderBy}";
$statement = $this->prepare($sql);
+
if ($statement === false) {
throw new \PDOException('Failed to prepare SQL statement for getting databases.');
}
@@ -343,32 +360,51 @@ public function getDatabases(): array
}
$result = [];
+ $requiredFields = [
+ 'datname',
+ 'datowner',
+ 'datencoding',
+ 'datcollate',
+ 'datctype',
+ 'tablespace',
+ 'dbsize',
+ ];
+
while ($row = $statement->fetch()) {
if (!is_array($row)) {
continue;
}
+ foreach ($requiredFields as $field) {
+ if (!isset($row[$field])) {
+ continue 2;
+ }
+ }
+
if (
- isset($row['datname']) && is_string($row['datname']) &&
- isset($row['datowner']) && is_string($row['datowner']) &&
- isset($row['datencoding']) && is_string($row['datencoding']) &&
- isset($row['datcollate']) && is_string($row['datcollate']) &&
- isset($row['datctype']) && is_string($row['datctype']) &&
- isset($row['tablespace']) && is_string($row['tablespace']) &&
- isset($row['dbsize']) && is_int($row['dbsize'])
+ !is_string($row['datname']) ||
+ !is_string($row['datowner']) ||
+ !is_string($row['datencoding']) ||
+ !is_string($row['datcollate']) ||
+ !is_string($row['datctype']) ||
+ !is_string($row['tablespace']) ||
+ !is_int($row['dbsize'])
) {
- $result[] = [
- 'datcollate' => $row['datcollate'],
- 'datcomment' => isset($row['datcomment']) && is_string($row['datcomment']) ?
- $row['datcomment'] : '',
- 'datctype' => $row['datctype'],
- 'datencoding' => $row['datencoding'],
- 'datname' => $row['datname'],
- 'datowner' => $row['datowner'],
- 'dbsize' => $row['dbsize'],
- 'tablespace' => $row['tablespace'],
- ];
+ continue;
}
+
+ $result[] = [
+ 'datcollate' => $row['datcollate'],
+ 'datcomment' => isset($row['datcomment']) && is_string($row['datcomment'])
+ ? $row['datcomment']
+ : '',
+ 'datctype' => $row['datctype'],
+ 'datencoding' => $row['datencoding'],
+ 'datname' => $row['datname'],
+ 'datowner' => $row['datowner'],
+ 'dbsize' => $row['dbsize'],
+ 'tablespace' => $row['tablespace'],
+ ];
}
return $result;
@@ -389,34 +425,48 @@ public function getUsers(): array
FROM pg_user
ORDER BY usename";
$statement = $this->prepare($sql);
+
if ($statement === false) {
throw new \PDOException('Failed to prepare SQL statement for getting users.');
}
+
if (!$statement->execute()) {
throw new \PDOException('Failed to execute SQL statement for getting users.');
}
$result = [];
+ $requiredFields = [
+ 'usename',
+ 'usesuper',
+ 'usecreatedb',
+ ];
+
while ($row = $statement->fetch()) {
if (!is_array($row)) {
continue;
}
- if (
- isset($row['usename']) && is_string($row['usename']) &&
- isset($row['usesuper']) && is_bool($row['usesuper']) &&
- isset($row['usecreatedb']) && is_bool($row['usecreatedb'])
- ) {
- $result[] = [
- 'useconfig' => isset($row['useconfig']) && is_string($row['useconfig']) ?
- $row['useconfig'] : '',
- 'usecreatedb' => $row['usecreatedb'],
- 'useexpires' => isset($row['useexpires']) && is_string($row['useexpires']) ?
- $row['useexpires'] : '',
- 'usename' => $row['usename'],
- 'usesuper' => $row['usesuper'],
- ];
+ foreach ($requiredFields as $field) {
+ if (!isset($row[$field])) {
+ continue 2;
+ }
+ }
+
+ if (!is_string($row['usename']) || !is_bool($row['usesuper']) || !is_bool($row['usecreatedb'])) {
+ continue;
}
+
+ $result[] = [
+ 'useconfig' => isset($row['useconfig']) && is_string($row['useconfig'])
+ ? $row['useconfig']
+ : '',
+ 'usecreatedb' => $row['usecreatedb'],
+ 'useexpires' => isset($row['useexpires']) && is_string($row['useexpires'])
+ ? $row['useexpires']
+ : '',
+ 'usename' => $row['usename'],
+ 'usesuper' => $row['usesuper'],
+ ];
}
return $result;
@@ -432,22 +482,27 @@ public function isSuperUser(string $username = ''): bool
{
if (empty($username)) {
$statement = $this->query("SHOW is_superuser");
+
if ($statement !== false) {
$isSuperUserColumn = $statement->fetchColumn();
+
return $isSuperUserColumn === 'on';
}
}
$sql = "SELECT usesuper FROM pg_user WHERE usename = :username";
$statement = $this->prepare($sql);
+
if ($statement === false) {
return false;
}
+
if (!$statement->execute(['username' => $username])) {
return false;
}
$rows = $statement->fetchAll();
+
if (empty($rows)) {
return false;
}
@@ -465,7 +520,9 @@ public function setDatabaseComment(string $database, ?string $comment = null): v
{
$escapedDatabase = self::escapeIdentifier($database);
$statement = "COMMENT ON DATABASE \"{$escapedDatabase}\" IS ";
- $statement .= !is_null($comment) ? $this->quote($comment) : 'NULL';
+ $statement .= !is_null($comment)
+ ? $this->quote($comment)
+ : 'NULL';
if ($this->exec($statement) === false) {
throw new \PDOException('Failed to execute SQL statement for setting database comment.');
@@ -477,13 +534,17 @@ public static function loginDataIsValid(
int $port,
SslMode $sslmode,
string $user,
- string $password
+ string $password,
): bool {
$dsn = "pgsql:host={$host};port={$port};sslmode={$sslmode->value}";
+
try {
- $_ = new \PDO(dsn: $dsn, username: $user, password: $password);
+ new \PDO(dsn: $dsn, username: $user, password: $password);
+
return true;
} catch (\PDOException $e) {
+ error_log($e->getMessage());
+
return false;
}
}
diff --git a/src/RequestParameter.php b/src/RequestParameter.php
index 2bfe328f7..455f05188 100644
--- a/src/RequestParameter.php
+++ b/src/RequestParameter.php
@@ -9,9 +9,11 @@ final class RequestParameter
public static function getString(string $name, ?string $default = null): ?string
{
$value = filter_input(INPUT_GET, $name, FILTER_DEFAULT);
+
if (!is_string($value)) {
$value = filter_input(INPUT_POST, $name, FILTER_DEFAULT);
}
+
if (!is_string($value)) {
$value = $default;
}
diff --git a/src/Session.php b/src/Session.php
index c8ba1eef1..94f749d95 100644
--- a/src/Session.php
+++ b/src/Session.php
@@ -14,6 +14,7 @@ public static function destroy(): void
session_name(self::NAME);
session_start();
}
+
unset($_SESSION);
session_destroy();
}
@@ -23,10 +24,12 @@ public static function start(): void
if (Config::extraSessionSecurity()) {
if (ini_get('session.auto_start')) {
$setting = strtolower(ini_get('session.cookie_samesite') ?: '');
+
if (session_name() !== self::NAME && $setting !== 'lax' && $setting !== 'strict') {
session_destroy();
session_name(self::NAME);
ini_set('session.cookie_samesite', 'Strict');
+
if (!session_start()) {
throw new \RuntimeException('Session could not be started');
}
@@ -34,12 +37,14 @@ public static function start(): void
} elseif (session_status() !== PHP_SESSION_ACTIVE) {
session_name(self::NAME);
ini_set('session.cookie_samesite', 'Strict');
+
if (!session_start()) {
throw new \RuntimeException('Session could not be started');
}
}
} elseif (!ini_get('session.auto_start')) {
session_name(self::NAME);
+
if (!session_start()) {
throw new \RuntimeException('Session could not be started');
}
diff --git a/src/Website.php b/src/Website.php
index 35e2781ce..133947681 100644
--- a/src/Website.php
+++ b/src/Website.php
@@ -51,6 +51,7 @@ public function buildHtmlDocument(): \DOMDocument
public function buildHtmlString(): string
{
$dom = $this->buildHtmlDocument();
+
return $dom->saveHTML() ?: '';
}
@@ -63,17 +64,22 @@ protected function buildHtmlHead(\DOMDocument $dom): \DOMElement
{
$head = $dom->createElement('head');
- $meta = $dom->createElement('meta');
- $meta->setAttribute('http-equiv', 'Content-Type');
- $meta->setAttribute('content', 'text/html; charset=utf-8');
- $head->appendChild($meta);
+ $metaContentType = $dom->createElement('meta');
+ $metaContentType->setAttribute('http-equiv', 'Content-Type');
+ $metaContentType->setAttribute('content', 'text/html; charset=utf-8');
+ $head->appendChild($metaContentType);
+
+ $metaColorScheme = $dom->createElement('meta');
+ $metaColorScheme->setAttribute('name', 'color-scheme');
+ $metaColorScheme->setAttribute('content', 'light dark');
+ $head->appendChild($metaColorScheme);
$formatTitle = '';
- if (!empty($this->title)) {
- $formatTitle = self::APP_NAME . ' - ' . $this->title;
- } else {
- $formatTitle = self::APP_NAME;
- }
+
+ $formatTitle = !empty($this->title)
+ ? self::APP_NAME . ' - ' . $this->title
+ : self::APP_NAME;
+
$title = $dom->createElement('title');
$title->appendChild($dom->createTextNode($formatTitle));
$head->appendChild($title);
diff --git a/src/Website/AllDb.php b/src/Website/AllDb.php
index d301ba1f7..749aa02e7 100644
--- a/src/Website/AllDb.php
+++ b/src/Website/AllDb.php
@@ -91,6 +91,7 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$body->appendChild(WebsiteComponents::buildServerDatabasesTabs($dom, $tabLinks));
$message = RequestParameter::getString('message') ?? '';
+
if (!empty($message)) {
$body->appendChild(WebsiteComponents::buildMessage($dom, $message));
}
diff --git a/src/Website/AllDbExport.php b/src/Website/AllDbExport.php
index 9b0d24bcb..c90fbb273 100644
--- a/src/Website/AllDbExport.php
+++ b/src/Website/AllDbExport.php
@@ -122,11 +122,13 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$formatSelect = $dom->createElement('select');
$formatSelect->setAttribute('name', 'd_format');
$formatOptions = ['copy', 'sql'];
+
foreach ($formatOptions as $option) {
$optionElement = $dom->createElement('option', strtoupper($option));
$optionElement->setAttribute('value', $option);
$formatSelect->appendChild($optionElement);
}
+
$rowOnlyDataColumnOptions->appendChild($formatSelect);
$rowOnlyData->appendChild($rowOnlyDataColumnFormat);
$rowOnlyData->appendChild($rowOnlyDataColumnOptions);
@@ -173,13 +175,16 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$rowStructureAndDataColumnOptions->appendChild($dom->createTextNode(_('Format')));
$rowStructureAndDataColumnOptions->appendChild($dom->createEntityReference('nbsp'));
$clonedFormatSelect = $formatSelect->cloneNode(true);
+
if ($clonedFormatSelect instanceof \DOMElement) {
$clonedFormatSelect->setAttribute('name', 'sd_format');
$rowStructureAndDataColumnOptions->appendChild($clonedFormatSelect);
}
+
$rowStructureAndDataColumnOptions->appendChild($dom->createElement('br'));
$clonedCleanInputForStructureOnly = $cleanInputForStructureOnly->cloneNode(true);
$clonedCleanInputForStructureOnlyLabel = $cleanInputForStructureOnlyLabel->cloneNode(true);
+
if (
$clonedCleanInputForStructureOnly instanceof \DOMElement &&
$clonedCleanInputForStructureOnlyLabel instanceof \DOMElement
diff --git a/src/Website/AlterDb.php b/src/Website/AlterDb.php
index 588c7f37f..1be19ff59 100644
--- a/src/Website/AlterDb.php
+++ b/src/Website/AlterDb.php
@@ -16,41 +16,49 @@ public function __construct()
{
parent::__construct();
- if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST') {
- $serverId = RequestParameter::getString('server') ?? '';
-
- $oldName = RequestParameter::getString('oldname');
- $newName = RequestParameter::getString('newname');
- if (is_null($oldName) || is_null($newName)) {
- $this->message = _('Database alter failed.');
- return;
- }
+ if (!(isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST')) {
+ return;
+ }
- $serverSession = ServerSession::fromServerId($serverId);
- if (!is_null($serverSession)) {
- $db = $serverSession->getDatabaseConnection();
- try {
- $db->alterDatabase(
- dbName: $oldName,
- newName: $newName,
- newOwner: RequestParameter::getString('owner'),
- comment: RequestParameter::getString('dbcomment'),
- );
-
- if (!headers_sent()) {
- $redirectUrl = 'all_db.php';
- $redirectUrlParams = [
- 'server' => $serverId,
- 'subject' => 'server',
- ];
-
- header('Location: ' . $redirectUrl . '?' . http_build_query($redirectUrlParams));
- die();
- }
- } catch (\PDOException $e) {
- $this->message = _('Database alter failed.');
- }
+ $serverId = RequestParameter::getString('server') ?? '';
+
+ $oldName = RequestParameter::getString('oldname');
+ $newName = RequestParameter::getString('newname');
+
+ if (is_null($oldName) || is_null($newName)) {
+ $this->message = _('Database alter failed.');
+
+ return;
+ }
+
+ $serverSession = ServerSession::fromServerId($serverId);
+
+ if (is_null($serverSession)) {
+ return;
+ }
+
+ $db = $serverSession->getDatabaseConnection();
+
+ try {
+ $db->alterDatabase(
+ dbName: $oldName,
+ newName: $newName,
+ newOwner: RequestParameter::getString('owner'),
+ comment: RequestParameter::getString('dbcomment'),
+ );
+
+ if (!headers_sent()) {
+ $redirectUrl = 'all_db.php';
+ $redirectUrlParams = [
+ 'server' => $serverId,
+ 'subject' => 'server',
+ ];
+
+ header('Location: ' . $redirectUrl . '?' . http_build_query($redirectUrlParams));
+ die;
}
+ } catch (\PDOException $e) {
+ $this->message = _('Database alter failed.') . ' - ' . $e->getMessage();
}
}
@@ -73,7 +81,7 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
urlParams: [
'help' => 'pg.database.alter',
'server' => $serverId,
- ]
+ ],
);
$h2->appendChild($aHelp);
$body->appendChild($h2);
@@ -121,17 +129,21 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$db = $serverSession?->getDatabaseConnection();
$dbOwner = $db?->getDatabaseOwner($database);
$dbUsers = $db?->getUsers();
+
if (is_iterable($dbUsers)) {
foreach ($dbUsers as $dbUser) {
$username = $dbUser['usename'];
$optionOwner = $dom->createElement('option', $username);
$optionOwner->setAttribute('value', $username);
+
if ($dbOwner === $username) {
$optionOwner->setAttribute('selected', 'selected');
}
+
$selectOwner->appendChild($optionOwner);
}
}
+
$tdOwner->appendChild($selectOwner);
$trOwner->appendChild($thOwner);
$trOwner->appendChild($tdOwner);
diff --git a/src/Website/Browser.php b/src/Website/Browser.php
index 8a4880fc5..914d401c8 100644
--- a/src/Website/Browser.php
+++ b/src/Website/Browser.php
@@ -99,7 +99,7 @@ protected function buildHtmlHead(\DOMDocument $dom): \DOMElement
$style = $dom->createElement('style');
$style->setAttribute('type', 'text/css');
$style->appendChild($dom->createTextNode(
- '.webfx-tree-children { background-image: url("' . Config::getIcon('I') . '"); }'
+ '.webfx-tree-children { background-image: url("' . Config::getIcon('I') . '"); }',
));
$head->appendChild($style);
diff --git a/src/Website/CreateDb.php b/src/Website/CreateDb.php
index 8dc8377dc..348e10302 100644
--- a/src/Website/CreateDb.php
+++ b/src/Website/CreateDb.php
@@ -18,37 +18,7 @@ public function __construct()
parent::__construct();
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST') {
- $formName = RequestParameter::getString('formName') ?? '';
-
- if (!empty($formName)) {
- $serverId = RequestParameter::getString('server') ?? '';
- $serverSession = ServerSession::fromServerId($serverId);
- if (!is_null($serverSession)) {
- $db = $serverSession->getDatabaseConnection();
- $db->createDatabase(
- database: $formName,
- encoding: RequestParameter::getString('formEncoding') ?? '',
- tablespace: RequestParameter::getString('formTablespace') ?? '',
- comment: RequestParameter::getString('formComment') ?? '',
- template: RequestParameter::getString('formTemplate') ?? 'template1',
- lcCollate: RequestParameter::getString('formCollate') ?? '',
- lcCType: RequestParameter::getString('formCType') ?? ''
- );
- if (!headers_sent()) {
- $redirectUrl = 'all_db.php';
- $redirectUrlParams = [
- 'server' => $serverId,
- 'subject' => 'server',
- ];
- header('Location: ' . $redirectUrl . '?' . http_build_query($redirectUrlParams));
- die();
- }
-
- $this->message = _('Database creation failed.');
- }
- } else {
- $this->message = _('You must give a name for your database.');
- }
+ $this->handlePostRequest();
}
}
@@ -69,7 +39,7 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
urlParams: [
'help' => 'pg.database.create',
'server' => $serverId,
- ]
+ ],
);
$h2->appendChild($aHelp);
$body->appendChild($h2);
@@ -118,37 +88,50 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$selectTemplate->setAttribute('id', 'db-template');
$db = $serverSession?->getDatabaseConnection();
$dbs = $db?->getDatabases();
+
if (is_iterable($dbs)) {
$formTemplate = RequestParameter::getString('formTemplate') ?? '';
$optionTemplate0 = $dom->createElement('option', 'template0');
$optionTemplate0->setAttribute('value', 'template0');
+
if ($formTemplate === 'template0') {
$optionTemplate0->setAttribute('selected', 'selected');
}
+
$selectTemplate->appendChild($optionTemplate0);
$optionTemplate1 = $dom->createElement('option', 'template1');
$optionTemplate1->setAttribute('value', 'template1');
+
if ($formTemplate === 'template1' || $formTemplate === '') {
$optionTemplate1->setAttribute('selected', 'selected');
}
+
$formTemplate1 = RequestParameter::getString('formTemplate') ?? '';
+
if ($formTemplate1 === 'template1') {
$optionTemplate1->setAttribute('selected', 'selected');
}
+
$selectTemplate->appendChild($optionTemplate1);
foreach ($dbs as $dbData) {
$dbName = $dbData['datname'];
- if ($dbName !== 'template1') {
- $optionTemplate = $dom->createElement('option', $dbName);
- $optionTemplate->setAttribute('value', $dbName);
- if ($formTemplate === $dbName) {
- $optionTemplate->setAttribute('selected', 'selected');
- }
- $selectTemplate->appendChild($optionTemplate);
+
+ if ($dbName === 'template1') {
+ continue;
}
+
+ $optionTemplate = $dom->createElement('option', $dbName);
+ $optionTemplate->setAttribute('value', $dbName);
+
+ if ($formTemplate === $dbName) {
+ $optionTemplate->setAttribute('selected', 'selected');
+ }
+
+ $selectTemplate->appendChild($optionTemplate);
}
}
+
$tdTemplateValue->appendChild($selectTemplate);
$trTemplate->appendChild($thTemplate);
$trTemplate->appendChild($tdTemplateValue);
@@ -169,14 +152,18 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$emptyOption->setAttribute('value', '');
$selectEncoding->appendChild($emptyOption);
$formEncoding = RequestParameter::getString('formEncoding') ?? '';
+
foreach (PhpPgAdminConnection::CODEMAP as $key => $value) {
$optionEncoding = $dom->createElement('option', $key);
$optionEncoding->setAttribute('value', $key);
+
if ($formEncoding === $key) {
$optionEncoding->setAttribute('selected', 'selected');
}
+
$selectEncoding->appendChild($optionEncoding);
}
+
$tdEncodingValue->appendChild($selectEncoding);
$trEncoding->appendChild($thEncoding);
$trEncoding->appendChild($tdEncodingValue);
@@ -198,16 +185,20 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$emptyOption->setAttribute('value', '');
$selectCollation->appendChild($emptyOption);
$availableCollations = $db?->getAvailableCollations();
+
if (!is_null($availableCollations)) {
foreach ($availableCollations as $collation) {
$option = $dom->createElement('option', $collation);
$option->setAttribute('value', $collation);
+
if ($formCollate === $collation) {
$option->setAttribute('selected', 'selected');
}
+
$selectCollation->appendChild($option);
}
}
+
$tdCollationValue->appendChild($selectCollation);
$trCollation->appendChild($thCollation);
$trCollation->appendChild($tdCollationValue);
@@ -228,16 +219,20 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$emptyOption = $dom->createElement('option');
$emptyOption->setAttribute('value', '');
$selectCType->appendChild($emptyOption);
+
if (!is_null($availableCollations)) {
foreach ($availableCollations as $collation) {
$option = $dom->createElement('option', $collation);
$option->setAttribute('value', $collation);
+
if ($formCType === $collation) {
$option->setAttribute('selected', 'selected');
}
+
$selectCType->appendChild($option);
}
}
+
$tdCTypeValue->appendChild($selectCType);
$trCType->appendChild($thCType);
$trCType->appendChild($tdCTypeValue);
@@ -302,4 +297,41 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
return $body;
}
+
+ private function handlePostRequest(): void
+ {
+ $formName = RequestParameter::getString('formName') ?? '';
+
+ if (!empty($formName)) {
+ $serverId = RequestParameter::getString('server') ?? '';
+ $serverSession = ServerSession::fromServerId($serverId);
+
+ if (!is_null($serverSession)) {
+ $db = $serverSession->getDatabaseConnection();
+ $db->createDatabase(
+ database: $formName,
+ encoding: RequestParameter::getString('formEncoding') ?? '',
+ tablespace: RequestParameter::getString('formTablespace') ?? '',
+ comment: RequestParameter::getString('formComment') ?? '',
+ template: RequestParameter::getString('formTemplate') ?? 'template1',
+ lcCollate: RequestParameter::getString('formCollate') ?? '',
+ lcCType: RequestParameter::getString('formCType') ?? '',
+ );
+
+ if (!headers_sent()) {
+ $redirectUrl = 'all_db.php';
+ $redirectUrlParams = [
+ 'server' => $serverId,
+ 'subject' => 'server',
+ ];
+ header('Location: ' . $redirectUrl . '?' . http_build_query($redirectUrlParams));
+ die;
+ }
+
+ $this->message = _('Database creation failed.');
+ }
+ } else {
+ $this->message = _('You must give a name for your database.');
+ }
+ }
}
diff --git a/src/Website/DropDb.php b/src/Website/DropDb.php
index 4ba05ed64..7b3f452bd 100644
--- a/src/Website/DropDb.php
+++ b/src/Website/DropDb.php
@@ -15,29 +15,7 @@ public function __construct()
parent::__construct();
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST') {
- $database = RequestParameter::getString('database') ?? '';
- $serverId = RequestParameter::getString('server') ?? '';
- $serverSession = ServerSession::fromServerId($serverId);
- if (!is_null($serverSession) && !empty($database)) {
- $redirectUrl = 'all_db.php';
- $redirectUrlParams = [
- 'server' => $serverId,
- 'subject' => 'server',
- ];
-
- $db = $serverSession->getDatabaseConnection();
- try {
- $db->dropDatabase($database);
- $redirectUrlParams['message'] = _('Database dropped.');
- } catch (\Exception $e) {
- $redirectUrlParams['message'] = _('Database drop failed.');
- }
-
- if (!headers_sent()) {
- header('Location: ' . $redirectUrl . '?' . http_build_query($redirectUrlParams));
- die();
- }
- }
+ $this->handlePostRequest();
}
}
@@ -58,7 +36,7 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
urlParams: [
'help' => 'pg.database.drop',
'server' => $serverId,
- ]
+ ],
);
$h2->appendChild($aHelp);
$body->appendChild($h2);
@@ -67,7 +45,7 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$form->setAttribute('method', 'post');
$p = $dom->createElement(
'p',
- sprintf(_('Are you sure you want to drop the database "%s"?'), $database)
+ sprintf(_('Are you sure you want to drop the database "%s"?'), $database),
);
$inputHiddenDatabase = $dom->createElement('input');
$inputHiddenDatabase->setAttribute('type', 'hidden');
@@ -101,4 +79,35 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
return $body;
}
+
+ private function handlePostRequest(): void
+ {
+ $database = RequestParameter::getString('database') ?? '';
+ $serverId = RequestParameter::getString('server') ?? '';
+ $serverSession = ServerSession::fromServerId($serverId);
+
+ if (is_null($serverSession) || empty($database)) {
+ return;
+ }
+
+ $redirectUrl = 'all_db.php';
+ $redirectUrlParams = [
+ 'server' => $serverId,
+ 'subject' => 'server',
+ ];
+
+ $db = $serverSession->getDatabaseConnection();
+
+ try {
+ $db->dropDatabase($database);
+ $redirectUrlParams['message'] = _('Database dropped.');
+ } catch (\Throwable $e) {
+ $redirectUrlParams['message'] = _('Database drop failed.') . ' - ' . $e->getMessage();
+ }
+
+ if (!headers_sent()) {
+ header('Location: ' . $redirectUrl . '?' . http_build_query($redirectUrlParams));
+ die;
+ }
+ }
}
diff --git a/src/Website/Exception.php b/src/Website/Exception.php
index 29b565ca6..a52eb3944 100644
--- a/src/Website/Exception.php
+++ b/src/Website/Exception.php
@@ -16,10 +16,12 @@ public function __construct(private \Throwable $exception)
public static function handle(\Throwable $exception): void
{
$exceptionCode = $exception->getCode();
+
if (is_int($exceptionCode)) {
$statusCode = StatusCode::tryFrom($exceptionCode) ?? StatusCode::InternalServerError;
header($statusCode->buildHeader());
}
+
$website = new self($exception);
print $website->buildHtmlString();
}
@@ -30,7 +32,7 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$h1 = $dom->createElement(
'h1',
- htmlentities($this->exception->getCode() . ': ' . $this->exception->getMessage())
+ htmlentities($this->exception->getCode() . ': ' . $this->exception->getMessage()),
);
$body->appendChild($h1);
diff --git a/src/Website/History.php b/src/Website/History.php
new file mode 100644
index 000000000..3bf9e9980
--- /dev/null
+++ b/src/Website/History.php
@@ -0,0 +1,278 @@
+scripts['history'] = [
+ 'src' => 'js/history.js',
+ ];
+ }
+
+ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
+ {
+ $body = parent::buildHtmlBody($dom);
+
+ $serverId = RequestParameter::getString('server') ?? '';
+ $selectedDatabase = RequestParameter::getString('database') ?? '';
+
+ $form = $dom->createElement('form');
+ $form->setAttribute('method', 'post');
+
+ $serverSession = ServerSession::fromServerId($serverId);
+ $db = $serverSession?->getDatabaseConnection();
+
+ $table = $dom->createElement('table');
+ $table->setAttribute('style', 'width: 100%;');
+ $tBody = $dom->createElement('tbody');
+ $tr = $dom->createElement('tr');
+
+ $tdLeft = $dom->createElement('td');
+ $labelForServer = $dom->createElement('label');
+ $labelForServer->setAttribute('for', 'server');
+ $labelForServer->appendChild($dom->createTextNode(_('Server')));
+ $serverHelpLink = WebsiteComponents::buildHelpLink(
+ dom: $dom,
+ url: 'help.php',
+ urlParams: [
+ 'help' => 'pg.server',
+ 'server' => $serverId,
+ ],
+ );
+ $serverSelect = $dom->createElement('select');
+ $serverSelect->setAttribute('name', 'server');
+ $serverSelect->setAttribute('id', 'server');
+ $serverSelect->setAttribute('onchange', 'changeServer(event)');
+ $servers = Config::getServers();
+
+ foreach ($servers as $server) {
+ $options = $dom->createElement('option');
+ $options->setAttribute('value', $server->id());
+
+ if ($serverId === $server->id()) {
+ $options->setAttribute('selected', 'selected');
+ }
+
+ $options->appendChild($dom->createTextNode((string)$server->Name . ' (' . $server->id() . ')'));
+ $serverSelect->appendChild($options);
+ }
+
+ $tdLeft->appendChild($labelForServer);
+ $tdLeft->appendChild($serverHelpLink);
+ $tdLeft->appendChild($dom->createTextNode(': '));
+ $tdLeft->appendChild($serverSelect);
+
+ $tdRight = $dom->createElement('td');
+ $tdRight->setAttribute('style', 'text-align: right;');
+ $labelForDatabase = $dom->createElement('label');
+ $labelForDatabase->setAttribute('for', 'database');
+ $labelForDatabase->appendChild($dom->createTextNode(_('Database')));
+ $databaseHelpLink = WebsiteComponents::buildHelpLink(
+ dom: $dom,
+ url: 'help.php',
+ urlParams: [
+ 'help' => 'pg.database',
+ 'server' => $serverId,
+ ],
+ );
+ $databaseSelect = $dom->createElement('select');
+ $databaseSelect->setAttribute('name', 'database');
+ $databaseSelect->setAttribute('id', 'database');
+ $databaseSelect->setAttribute('onchange', 'changeServer(event)');
+ $databases = $db?->getDatabases() ?? [];
+ $emptyOption = $dom->createElement('option');
+ $emptyOption->setAttribute('value', '');
+ $emptyOption->appendChild($dom->createTextNode('---'));
+ $databaseSelect->appendChild($emptyOption);
+
+ foreach ($databases as $database) {
+ $options = $dom->createElement('option');
+ $options->setAttribute('value', $database['datname']);
+
+ if ($selectedDatabase === $database['datname']) {
+ $options->setAttribute('selected', 'selected');
+ }
+
+ $options->appendChild($dom->createTextNode($database['datname']));
+ $databaseSelect->appendChild($options);
+ }
+
+ $tdRight->appendChild($labelForDatabase);
+ $tdRight->appendChild($databaseHelpLink);
+ $tdRight->appendChild($dom->createTextNode(': '));
+ $tdRight->appendChild($databaseSelect);
+
+ $tr->appendChild($tdLeft);
+ $tr->appendChild($tdRight);
+ $tBody->appendChild($tr);
+ $table->appendChild($tBody);
+
+ $form->appendChild($table);
+ $body->appendChild($form);
+ $body->appendChild($dom->createElement('br'));
+
+ if ($selectedDatabase !== '') {
+ $history = HistoryRepository::getHistory($serverId, $selectedDatabase);
+ $historyCount = count($history);
+
+ $body->appendChild(
+ $this->buildHistoryTable(
+ $dom,
+ $history,
+ $serverId,
+ $selectedDatabase,
+ ),
+ );
+
+ if ($historyCount === 0) {
+ $pNoHistory = $dom->createElement('p');
+ $pNoHistory->appendChild($dom->createTextNode(_('No history.')));
+ $body->appendChild($pNoHistory);
+ }
+
+ $ulNavLink = $dom->createElement('ul');
+ $ulNavLink->setAttribute('class', 'navlink');
+
+ $liRefresh = $dom->createElement('li');
+ $aRefresh = $dom->createElement('a');
+ $requestUri = '';
+
+ if (isset($_SERVER['REQUEST_URI']) && is_string($_SERVER['REQUEST_URI'])) {
+ $requestUri = $_SERVER['REQUEST_URI'];
+ }
+
+ $aRefresh->setAttribute('href', $requestUri);
+ $aRefresh->appendChild($dom->createTextNode(_('Refresh')));
+ $liRefresh->appendChild($aRefresh);
+
+ $ulNavLink->appendChild($liRefresh);
+
+ if ($historyCount > 0) {
+ $liDownload = $dom->createElement('li');
+ $aDownload = $dom->createElement('a');
+ $downloadUrl = 'history_download.php';
+ $downloadUrlParams = [
+ 'database' => $selectedDatabase,
+ 'server' => $serverId,
+ ];
+ $aDownload->setAttribute('href', $downloadUrl . '?' . http_build_query($downloadUrlParams));
+ $aDownload->appendChild($dom->createTextNode(_('Download')));
+ $liDownload->appendChild($aDownload);
+ $ulNavLink->appendChild($liDownload);
+
+ $liClear = $dom->createElement('li');
+ $aClear = $dom->createElement('a');
+ $clearUrl = 'history_clear.php';
+ $clearUrlParams = [
+ 'database' => $selectedDatabase,
+ 'server' => $serverId,
+ ];
+ $aClear->setAttribute('href', $clearUrl . '?' . http_build_query($clearUrlParams));
+ $aClear->appendChild($dom->createTextNode(_('Clear history')));
+ $liClear->appendChild($aClear);
+ $ulNavLink->appendChild($liClear);
+ }
+
+ $body->appendChild($ulNavLink);
+ } else {
+ $pPleaseSelectDatabase = $dom->createElement('p');
+ $pPleaseSelectDatabase->appendChild($dom->createTextNode(_('Please, select a database.')));
+ $body->appendChild($pPleaseSelectDatabase);
+ }
+
+ return $body;
+ }
+
+ /**
+ * @param array $history
+ */
+ private function buildHistoryTable(
+ \DOMDocument $dom,
+ array $history,
+ string $serverId,
+ string $selectedDatabase,
+ ): \DOMElement {
+ $table = $dom->createElement('table');
+
+ $tHead = $dom->createElement('thead');
+ $trHead = $dom->createElement('tr');
+ $thQuery = $dom->createElement('th');
+ $thQuery->setAttribute('class', 'data');
+ $thQuery->appendChild($dom->createTextNode(_('SQL')));
+ $trHead->appendChild($thQuery);
+ $thPaginate = $dom->createElement('th');
+ $thPaginate->setAttribute('class', 'data');
+ $thPaginate->appendChild($dom->createTextNode(_('Paginate results')));
+ $trHead->appendChild($thPaginate);
+ $thActions = $dom->createElement('th');
+ $thActions->setAttribute('class', 'data');
+ $thActions->setAttribute('colspan', '2');
+ $thActions->appendChild($dom->createTextNode(_('Actions')));
+ $trHead->appendChild($thActions);
+ $tHead->appendChild($trHead);
+ $table->appendChild($tHead);
+
+ $tBody = $dom->createElement('tbody');
+ $historyCounter = 0;
+
+ foreach ($history as $queryId => $historyData) {
+ $historyCounter++;
+
+ $tr = $dom->createElement('tr');
+ $tr->setAttribute('class', 'data' . ($historyCounter % 2 !== 0 ? '1' : '2'));
+ $tdQuery = $dom->createElement('td');
+ $tdQuery->appendChild($dom->createTextNode($historyData['query']));
+ $tdPaginate = $dom->createElement('td');
+ $tdPaginate->setAttribute('style', 'text-align: center;');
+ $tdPaginate->appendChild($dom->createTextNode($historyData['paginate'] ? _('Yes') : _('No')));
+ $tdExecute = $dom->createElement('td');
+ $tdExecute->setAttribute('class', 'opbutton' . ($historyCounter % 2 !== 0 ? '1' : '2'));
+ $executeLink = $dom->createElement('a');
+ $executeUrl = 'sql.php';
+ $executeUrlParams = [
+ 'database' => $selectedDatabase,
+ 'nohistory' => 't',
+ 'paginate' => $historyData['paginate'] ? 't' : 'f',
+ 'queryid' => $queryId,
+ 'server' => $serverId,
+ 'subject' => 'history',
+ ];
+ $executeLink->setAttribute('href', $executeUrl . '?' . http_build_query($executeUrlParams));
+ $executeLink->setAttribute('target', 'detail');
+ $executeLink->appendChild($dom->createTextNode(_('Execute')));
+ $tdExecute->appendChild($executeLink);
+ $tdDelete = $dom->createElement('td');
+ $tdDelete->setAttribute('class', 'opbutton' . ($historyCounter % 2 !== 0 ? '1' : '2'));
+ $deleteLink = $dom->createElement('a');
+ $deleteUrl = 'history_delete.php';
+ $deleteUrlParams = [
+ 'database' => $selectedDatabase,
+ 'queryid' => $queryId,
+ 'server' => $serverId,
+ ];
+ $deleteLink->setAttribute('href', $deleteUrl . '?' . http_build_query($deleteUrlParams));
+ $deleteLink->appendChild($dom->createTextNode(_('Delete')));
+ $tdDelete->appendChild($deleteLink);
+ $tr->appendChild($tdQuery);
+ $tr->appendChild($tdPaginate);
+ $tr->appendChild($tdExecute);
+ $tr->appendChild($tdDelete);
+
+ $tBody->appendChild($tr);
+ }
+
+ $table->appendChild($tBody);
+
+ return $table;
+ }
+}
diff --git a/src/Website/HistoryClear.php b/src/Website/HistoryClear.php
new file mode 100644
index 000000000..db467755a
--- /dev/null
+++ b/src/Website/HistoryClear.php
@@ -0,0 +1,89 @@
+ $selectedDatabase,
+ 'server' => $serverId,
+ 'subject' => 'table',
+ ];
+ header('Location: ' . $redirectUrl . '?' . http_build_query($redirectUrlParams));
+ }
+
+ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
+ {
+ $body = parent::buildHtmlBody($dom);
+
+ $serverId = RequestParameter::getString('server') ?? '';
+ $selectedDatabase = RequestParameter::getString('database') ?? '';
+
+ $h3 = $dom->createElement('h3');
+ $h3->appendChild($dom->createTextNode(_('Clear history')));
+ $body->appendChild($h3);
+
+ $p = $dom->createElement('p');
+ $p->appendChild($dom->createTextNode(_('Really clear history?')));
+ $body->appendChild($p);
+
+ $form = $dom->createElement('form');
+ $form->setAttribute('method', 'post');
+ $inputServer = $dom->createElement('input');
+ $inputServer->setAttribute('type', 'hidden');
+ $inputServer->setAttribute('name', 'server');
+ $inputServer->setAttribute('value', $serverId);
+ $inputDatabase = $dom->createElement('input');
+ $inputDatabase->setAttribute('type', 'hidden');
+ $inputDatabase->setAttribute('name', 'database');
+ $inputDatabase->setAttribute('value', $selectedDatabase);
+ $inputYes = $dom->createElement('input');
+ $inputYes->setAttribute('type', 'submit');
+ $inputYes->setAttribute('name', 'yes');
+ $inputYes->setAttribute('value', _('Yes'));
+ $inputNo = $dom->createElement('input');
+ $inputNo->setAttribute('type', 'submit');
+ $inputNo->setAttribute('name', 'no');
+ $inputNo->setAttribute('value', _('No'));
+ $form->appendChild($inputServer);
+ $form->appendChild($inputDatabase);
+ $form->appendChild($inputYes);
+ $form->appendChild($dom->createTextNode(' '));
+ $form->appendChild($inputNo);
+ $body->appendChild($form);
+
+ return $body;
+ }
+}
diff --git a/src/Website/HistoryDelete.php b/src/Website/HistoryDelete.php
new file mode 100644
index 000000000..3a0da2053
--- /dev/null
+++ b/src/Website/HistoryDelete.php
@@ -0,0 +1,106 @@
+ $selectedDatabase,
+ 'server' => $serverId,
+ 'subject' => 'table',
+ ];
+ header('Location: ' . $redirectUrl . '?' . http_build_query($redirectUrlParams));
+ }
+
+ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
+ {
+ $body = parent::buildHtmlBody($dom);
+
+ $queryId = RequestParameter::getString('queryid') ?? '';
+ $serverId = RequestParameter::getString('server') ?? '';
+ $selectedDatabase = RequestParameter::getString('database') ?? '';
+
+ $historyEntry = History::getHistoryEntry($serverId, $selectedDatabase, $queryId);
+
+ if (is_null($historyEntry)) {
+ return $body;
+ }
+
+ $h3 = $dom->createElement('h3');
+ $h3->appendChild($dom->createTextNode(_('Delete from history')));
+ $body->appendChild($h3);
+
+ $p = $dom->createElement('p');
+ $p->appendChild($dom->createTextNode(_('Really remove this request from history?')));
+ $body->appendChild($p);
+
+ $pre = $dom->createElement('pre');
+ $pre->appendChild($dom->createTextNode($historyEntry['query']));
+ $body->appendChild($pre);
+
+ $form = $dom->createElement('form');
+ $form->setAttribute('method', 'post');
+ $inputQueryId = $dom->createElement('input');
+ $inputQueryId->setAttribute('type', 'hidden');
+ $inputQueryId->setAttribute('name', 'queryid');
+ $inputQueryId->setAttribute('value', $queryId);
+ $inputServer = $dom->createElement('input');
+ $inputServer->setAttribute('type', 'hidden');
+ $inputServer->setAttribute('name', 'server');
+ $inputServer->setAttribute('value', $serverId);
+ $inputDatabase = $dom->createElement('input');
+ $inputDatabase->setAttribute('type', 'hidden');
+ $inputDatabase->setAttribute('name', 'database');
+ $inputDatabase->setAttribute('value', $selectedDatabase);
+ $inputYes = $dom->createElement('input');
+ $inputYes->setAttribute('type', 'submit');
+ $inputYes->setAttribute('name', 'yes');
+ $inputYes->setAttribute('value', _('Yes'));
+ $inputNo = $dom->createElement('input');
+ $inputNo->setAttribute('type', 'submit');
+ $inputNo->setAttribute('name', 'no');
+ $inputNo->setAttribute('value', _('No'));
+ $form->appendChild($inputQueryId);
+ $form->appendChild($inputServer);
+ $form->appendChild($inputDatabase);
+ $form->appendChild($inputYes);
+ $form->appendChild($dom->createTextNode(' '));
+ $form->appendChild($inputNo);
+ $body->appendChild($form);
+
+ return $body;
+ }
+}
diff --git a/src/Website/HistoryDownload.php b/src/Website/HistoryDownload.php
new file mode 100644
index 000000000..a94631e6a
--- /dev/null
+++ b/src/Website/HistoryDownload.php
@@ -0,0 +1,42 @@
+format('Y-m-d_H-i-s') . '.sql';
+
+ header('Content-Type: application/download');
+ header("Content-Disposition: attachment; filename={$filename}");
+ }
+
+ foreach ($history as $queries) {
+ $query = trim($queries['query']);
+ print $query;
+
+ if (substr($query, -1) !== ';') {
+ print ';';
+ }
+
+ print "\n";
+ }
+
+ exit;
+ }
+}
diff --git a/src/Website/Intro.php b/src/Website/Intro.php
index be0bc6056..98b293342 100644
--- a/src/Website/Intro.php
+++ b/src/Website/Intro.php
@@ -35,17 +35,21 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$currentLocale = Config::locale();
$languageIdsWithLocales = Language::getAvailableLanguageIdsWithLocales();
+
foreach ($languageIdsWithLocales as $languageId => $locale) {
Language::setLocale($locale);
$option = $dom->createElement('option', _('applang'));
$option->setAttribute('value', $languageId);
$option->setAttribute('data-locale', $locale);
$option->setAttribute('data-language-id', $languageId);
+
if ($locale === $currentLocale) {
$option->setAttribute('selected', 'selected');
}
+
$select->appendChild($option);
}
+
// Reset locale
Language::setLocale($currentLocale);
@@ -62,14 +66,18 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$select->setAttribute('name', 'theme');
$select->setAttribute('onchange', 'this.form.submit()');
$themes = Themes::available();
+
foreach ($themes as $theme => $label) {
$option = $dom->createElement('option', $label);
$option->setAttribute('value', $theme);
+
if ($theme === Config::theme()) {
$option->setAttribute('selected', 'selected');
}
+
$select->appendChild($option);
}
+
$td->appendChild($select);
$tr->appendChild($td);
$table->appendChild($tr);
@@ -101,6 +109,7 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$body->appendChild(WebsiteComponents::buildBackToTopLink($dom));
$languageParam = RequestParameter::getString('language');
+
if (!is_null($languageParam)) {
$scriptElement = $dom->createElement('script');
$scriptElement->setAttribute('type', 'text/javascript');
diff --git a/src/Website/Login.php b/src/Website/Login.php
index 5e98d3857..0c0833d93 100644
--- a/src/Website/Login.php
+++ b/src/Website/Login.php
@@ -17,64 +17,8 @@ public function __construct()
$this->title = _('Login');
- if (
- isset($_SERVER['REQUEST_METHOD']) &&
- is_string($_SERVER['REQUEST_METHOD']) &&
- $_SERVER['REQUEST_METHOD'] === 'POST'
- ) {
- $loginServer = RequestParameter::getString('loginServer');
- if (is_null($loginServer)) {
- throw new \InvalidArgumentException('Parameter "loginServer" is required');
- }
- $loginUsername = RequestParameter::getString('loginUsername');
- if (is_null($loginUsername)) {
- throw new \InvalidArgumentException('Parameter "loginUsername" is required');
- }
-
- $server = Config::getServerById($loginServer);
- if (is_null($server)) {
- throw new \InvalidArgumentException('Server not found');
- }
- $loginPassword = RequestParameter::getString('loginPassword_' . hash('sha256', (string)$server->Name));
- if (is_null($loginPassword)) {
- throw new \InvalidArgumentException('Parameter "loginPassword" is required');
- }
-
- if (
- !PhpPgAdminConnection::loginDataIsValid(
- host: (string)$server->Host,
- port: $server->Port->Value,
- sslmode: $server->SslMode,
- user: $loginUsername,
- password: $loginPassword
- )
- ) {
- $this->message = _('Login failed');
- return;
- }
-
- if (!isset($_SESSION['webdbLogin']) || !is_array($_SESSION['webdbLogin'])) {
- $_SESSION['webdbLogin'] = [];
- }
- $_SESSION['webdbLogin'][$loginServer] = [
- 'defaultdb' => (string)$server->DefaultDb,
- 'desc' => (string)$server->Name,
- 'host' => (string)$server->Host,
- 'password' => $loginPassword,
- 'pg_dumpall_path' => '/usr/bin/pg_dumpall',
- 'pg_dump_path' => '/usr/bin/pg_dump',
- //'pgVersion' => $server->Version->Value,
- //'platform' => 'PostgreSQL ' . $server->Version->Value,
- 'port' => $server->Port->Value,
- 'sslmode' => $server->SslMode->value,
- 'username' => $loginUsername,
- ];
-
- $redirectLocationUrlParams = [
- 'server' => $loginServer,
- ];
- header('Location: ./all_db.php?' . http_build_query($redirectLocationUrlParams));
- exit;
+ if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST') {
+ $this->handlePostRequest();
}
}
@@ -86,11 +30,13 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$body->appendChild(WebsiteComponents::buildTrail($dom));
$serverId = RequestParameter::getString('server');
+
if (is_null($serverId)) {
throw new \InvalidArgumentException('Parameter "server" is required');
}
$server = Config::getServerById($serverId);
+
if (is_null($server)) {
throw new \InvalidArgumentException('Server not found');
}
@@ -104,9 +50,11 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$form = $dom->createElement('form');
$form->setAttribute('id', 'login_form');
$loginFormAction = '';
+
if (isset($_SERVER['SCRIPT_NAME']) && is_string($_SERVER['SCRIPT_NAME'])) {
$loginFormAction = $_SERVER['SCRIPT_NAME'];
}
+
$form->setAttribute('action', $loginFormAction);
$form->setAttribute('method', 'post');
$form->setAttribute('name', 'login_form');
@@ -178,4 +126,69 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
return $body;
}
+
+ private function handlePostRequest(): void
+ {
+ $loginServer = RequestParameter::getString('loginServer');
+
+ if (is_null($loginServer)) {
+ throw new \InvalidArgumentException('Parameter "loginServer" is required');
+ }
+
+ $loginUsername = RequestParameter::getString('loginUsername');
+
+ if (is_null($loginUsername)) {
+ throw new \InvalidArgumentException('Parameter "loginUsername" is required');
+ }
+
+ $server = Config::getServerById($loginServer);
+
+ if (is_null($server)) {
+ throw new \InvalidArgumentException('Server not found');
+ }
+
+ $loginPassword = RequestParameter::getString('loginPassword_' . hash('sha256', (string)$server->Name));
+
+ if (is_null($loginPassword)) {
+ throw new \InvalidArgumentException('Parameter "loginPassword" is required');
+ }
+
+ $loginIsValid = PhpPgAdminConnection::loginDataIsValid(
+ host: (string)$server->Host,
+ port: $server->Port->Value,
+ sslmode: $server->SslMode,
+ user: $loginUsername,
+ password: $loginPassword,
+ );
+
+ if (!$loginIsValid) {
+ $this->message = _('Login failed');
+
+ return;
+ }
+
+ if (!isset($_SESSION['webdbLogin']) || !is_array($_SESSION['webdbLogin'])) {
+ $_SESSION['webdbLogin'] = [];
+ }
+
+ $_SESSION['webdbLogin'][$loginServer] = [
+ 'defaultdb' => (string)$server->DefaultDb,
+ 'desc' => (string)$server->Name,
+ 'host' => (string)$server->Host,
+ 'password' => $loginPassword,
+ 'pg_dumpall_path' => '/usr/bin/pg_dumpall',
+ 'pg_dump_path' => '/usr/bin/pg_dump',
+ //'pgVersion' => $server->Version->Value,
+ //'platform' => 'PostgreSQL ' . $server->Version->Value,
+ 'port' => $server->Port->Value,
+ 'sslmode' => $server->SslMode->value,
+ 'username' => $loginUsername,
+ ];
+
+ $redirectLocationUrlParams = [
+ 'server' => $loginServer,
+ ];
+ header('Location: ./all_db.php?' . http_build_query($redirectLocationUrlParams));
+ exit;
+ }
}
diff --git a/src/Website/Redirect.php b/src/Website/Redirect.php
index 59de0bc37..a8c237fd6 100644
--- a/src/Website/Redirect.php
+++ b/src/Website/Redirect.php
@@ -13,11 +13,9 @@ final class Redirect extends Website
public function tryRedirect(): void
{
$subject = RequestParameter::getString('subject');
+
if (is_null($subject)) {
- throw new \InvalidArgumentException(
- 'Missing required parameter: subject',
- StatusCode::BadRequest->value
- );
+ throw new \InvalidArgumentException('Missing required parameter: subject', StatusCode::BadRequest->value);
}
match ($subject) {
@@ -25,7 +23,7 @@ public function tryRedirect(): void
'server' => $this->redirectToServer(),
default => trigger_error(
'Redirecting subject ("' . $subject . '") not found the new way. Continue the old way!',
- E_USER_DEPRECATED
+ E_USER_DEPRECATED,
)
};
}
@@ -40,6 +38,7 @@ private function redirectToRoot(): void
private function redirectToServer(): void
{
$server = RequestParameter::getString('server');
+
if (is_null($server)) {
throw new \InvalidArgumentException('Missing required parameter: server', StatusCode::BadRequest->value);
}
@@ -47,7 +46,7 @@ private function redirectToServer(): void
if (!Config::serverExists($server)) {
throw new \InvalidArgumentException(
_('Attempt to connect with invalid server parameter, possibly someone is trying to hack your system.'),
- StatusCode::BadRequest->value
+ StatusCode::BadRequest->value,
);
}
@@ -62,7 +61,7 @@ private function redirectToServer(): void
unset($locationUrlParams['subject']);
}
- $locationUrl = $locationUrl . '?' . http_build_query($locationUrlParams);
+ $locationUrl .= '?' . http_build_query($locationUrlParams);
header('Location: ' . $locationUrl);
exit;
diff --git a/src/Website/ServerLogout.php b/src/Website/ServerLogout.php
index 845ad1545..c0c1f77a7 100644
--- a/src/Website/ServerLogout.php
+++ b/src/Website/ServerLogout.php
@@ -41,6 +41,7 @@ protected function buildHtmlHead(\DOMDocument $dom): \DOMElement
$head = parent::buildHtmlHead($dom);
$redirectUrl = './servers.php';
+
if (isset($_SERVER['HTTP_REFERER']) && is_string($_SERVER['HTTP_REFERER'])) {
$redirectUrl = $_SERVER['HTTP_REFERER'];
}
diff --git a/src/Website/Servers.php b/src/Website/Servers.php
index db620dd29..10e7f7bf4 100644
--- a/src/Website/Servers.php
+++ b/src/Website/Servers.php
@@ -48,8 +48,11 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$table->appendChild($tHead);
$tBody = $dom->createElement('tbody');
- $logins = isset($_SESSION['webdbLogin']) && is_array($_SESSION['webdbLogin']) ? $_SESSION['webdbLogin'] : [];
+ $logins = isset($_SESSION['webdbLogin']) && is_array($_SESSION['webdbLogin'])
+ ? $_SESSION['webdbLogin']
+ : [];
$servers = Config::getServers();
+
foreach ($servers as $index => $server) {
$tr = $dom->createElement('tr');
$tr->setAttribute('class', 'data' . ($index + 1));
@@ -69,6 +72,7 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$td = $dom->createElement('td', (string)$server->Port->Value);
$tr->appendChild($td);
$username = '';
+
if (
isset($logins[$serverId]) &&
is_array($logins[$serverId]) &&
@@ -77,9 +81,11 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
) {
$username = $logins[$serverId]['username'];
}
+
$td = $dom->createElement('td', $username);
$tr->appendChild($td);
$td = $dom->createElement('td');
+
if ($username !== '') {
$td->setAttribute('class', 'opbutton' . ($index + 1));
$a = $dom->createElement('a', _('Logout'));
@@ -90,9 +96,11 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$a->setAttribute('href', $logoutUrl);
$td->appendChild($a);
}
+
$tr->appendChild($td);
$tBody->appendChild($tr);
}
+
$table->appendChild($tBody);
$body->appendChild($table);
diff --git a/src/Website/SqlEdit.php b/src/Website/SqlEdit.php
index 2f1f0b3c2..faf0e0ff3 100644
--- a/src/Website/SqlEdit.php
+++ b/src/Website/SqlEdit.php
@@ -89,7 +89,7 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
urlParams: [
'help' => 'pg.server',
'server' => $serverId,
- ]
+ ],
);
$labelForServer->appendChild($helpLink);
$tdServerSelection->appendChild($labelForServer);
@@ -99,15 +99,19 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$serverSelection->setAttribute('id', 'server');
$serverSelection->setAttribute('onchange', 'changeServer(event)');
$servers = Config::getServers();
+
foreach ($servers as $server) {
$option = $dom->createElement('option');
$option->setAttribute('value', $server->id());
+
if ($server->id() === $serverId) {
$option->setAttribute('selected', 'selected');
}
+
$option->appendChild($dom->createTextNode($server->Name . ' (' . $server->id() . ')'));
$serverSelection->appendChild($option);
}
+
$tdServerSelection->appendChild($serverSelection);
$tdDatabaseSelection = $dom->createElement('td');
@@ -121,7 +125,7 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
urlParams: [
'help' => 'pg.database',
'server' => $serverId,
- ]
+ ],
);
$labelForDatabase->appendChild($helpLink);
$labelForDatabase->appendChild($dom->createTextNode(': '));
@@ -134,21 +138,26 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
$emptyOption->setAttribute('value', '');
$databaseSelection->appendChild($emptyOption);
$serverSession = ServerSession::fromServerId($serverId);
+
if (!is_null($serverSession)) {
$databaseParam = RequestParameter::getString('database');
$db = $serverSession->getDatabaseConnection();
$dbs = $db->getDatabases();
+
foreach ($dbs as $dbMetaData) {
$option = $dom->createElement('option');
$option->setAttribute('value', $dbMetaData['datname']);
+
if ($dbMetaData['datname'] === $databaseParam) {
$option->setAttribute('selected', 'selected');
}
+
$option->appendChild($dom->createTextNode($dbMetaData['datname']));
$databaseSelection->appendChild($option);
}
}
+
$tdDatabaseSelection->appendChild($databaseSelection);
$tr->appendChild($tdServerSelection);
@@ -173,6 +182,7 @@ protected function buildHtmlBody(\DOMDocument $dom): \DOMElement
private function appendFindPart(\DOMElement $element): void
{
$dom = $element->ownerDocument;
+
if (is_null($dom)) {
throw new \RuntimeException('DOMDocument is not set for the element.');
}
@@ -203,6 +213,7 @@ private function appendFindPart(\DOMElement $element): void
'TRIGGER' => _('Triggers'),
'VIEW' => _('Views'),
];
+
foreach ($filterArray as $key => $value) {
$option = $dom->createElement('option');
$option->setAttribute('value', $key);
@@ -233,6 +244,7 @@ private function appendFindPart(\DOMElement $element): void
private function appendSqlPart(\DOMElement $element, string $serverId): void
{
$dom = $element->ownerDocument;
+
if (is_null($dom)) {
throw new \RuntimeException('DOMDocument is not set for the element.');
}
@@ -248,7 +260,7 @@ private function appendSqlPart(\DOMElement $element, string $serverId): void
urlParams: [
'help' => 'pg.schema.search_path',
'server' => $serverId,
- ]
+ ],
);
$pSchemaSearchPath->appendChild($searchPathHelp);
$pSchemaSearchPath->appendChild($dom->createTextNode(': '));
diff --git a/src/WebsiteComponents.php b/src/WebsiteComponents.php
index af8aa26c9..3b2507e39 100644
--- a/src/WebsiteComponents.php
+++ b/src/WebsiteComponents.php
@@ -62,8 +62,10 @@ public static function buildDatabasesTable(\DOMDocument $dom, ?ServerSession $se
$tBody = $dom->createElement('tbody');
$dbs = $dbConnection?->getDatabases();
+
if (is_iterable($dbs)) {
$dbCounter = 0;
+
foreach ($dbs as $db) {
$dbCounter++;
@@ -163,15 +165,17 @@ public static function buildDatabasesTable(\DOMDocument $dom, ?ServerSession $se
}
/**
- * @param array $urlParams
+ * @param array $urlParams
*/
public static function buildHelpLink(\DOMDocument $dom, string $url, ?array $urlParams = null): \DOMElement
{
$a = $dom->createElement('a', '?');
$href = $url;
+
if (!is_null($urlParams)) {
$href .= '?' . http_build_query($urlParams);
}
+
$a->setAttribute('href', $href);
$a->setAttribute('class', 'help');
$a->setAttribute('title', _('Help'));
@@ -185,12 +189,13 @@ public static function buildMessage(\DOMDocument $dom, string $message): \DOMEle
$pMessage = $dom->createElement('p');
$pMessage->setAttribute('class', 'message');
$pMessage->appendChild($dom->createTextNode($message));
+
return $pMessage;
}
public static function buildMultipleActionsTableForDatabases(
\DOMDocument $dom,
- ?ServerSession $serverSession
+ ?ServerSession $serverSession,
): \DOMElement {
$table = $dom->createElement('table');
@@ -254,7 +259,7 @@ public static function buildMultipleActionsTableForDatabases(
}
/**
- * @param array{'url': string, 'url-params'?: array, 'label': string}[] $navLinks
+ * @param array, 'label': string}> $navLinks
*/
public static function buildNavLinks(\DOMDocument $dom, array $navLinks): \DOMElement
{
@@ -265,9 +270,11 @@ public static function buildNavLinks(\DOMDocument $dom, array $navLinks): \DOMEl
$li = $dom->createElement('li');
$a = $dom->createElement('a', $navLink['label']);
$href = $navLink['url'];
+
if (isset($navLink['url-params'])) {
$href .= '?' . http_build_query($navLink['url-params']);
}
+
$a->setAttribute('href', $href);
$li->appendChild($a);
$ul->appendChild($li);
@@ -326,7 +333,7 @@ public static function buildRootTabs(\DOMDocument $dom, string $activeTab): \DOM
}
/**
- * @param array{
+ * @param array,
* 'label': string,
@@ -336,7 +343,7 @@ public static function buildRootTabs(\DOMDocument $dom, string $activeTab): \DOM
* 'url': string,
* 'url-params'?: array
* }
- * }[] $tabLinks
+ * }> $tabLinks
*/
public static function buildServerDatabasesTabs(\DOMDocument $dom, array $tabLinks): \DOMElement
{
@@ -349,16 +356,20 @@ public static function buildServerDatabasesTabs(\DOMDocument $dom, array $tabLin
foreach ($tabLinks as $tabLink) {
$td = $dom->createElement('td');
$tdClass = 'tab';
+
if (isset($tabLink['active']) && $tabLink['active']) {
$tdClass .= ' active';
}
+
$td->setAttribute('class', $tdClass);
$td->setAttribute('style', 'width: 20%');
$href = $tabLink['url'];
+
if (isset($tabLink['url-params'])) {
$href .= '?' . http_build_query($tabLink['url-params']);
}
+
$a = $dom->createElement('a');
$a->setAttribute('href', $href);
$spanIcon = $dom->createElement('span');
@@ -377,7 +388,7 @@ public static function buildServerDatabasesTabs(\DOMDocument $dom, array $tabLin
$aHelp = self::buildHelpLink(
dom: $dom,
url: $tabLink['help']['url'],
- urlParams: $tabLink['help']['url-params'] ?? []
+ urlParams: $tabLink['help']['url-params'] ?? [],
);
$td->appendChild($aHelp);
}
@@ -403,12 +414,12 @@ public static function buildTopBar(\DOMDocument $dom): \DOMElement
$aAlertBanner = $dom->createElement('a');
$aAlertBanner->setAttribute(
'href',
- 'https://www.php.net/manual/en/session.configuration.php#ini.session.cookie-samesite'
+ 'https://www.php.net/manual/en/session.configuration.php#ini.session.cookie-samesite',
);
$aAlertBanner->setAttribute('target', '_blank');
$aAlertBanner->setAttribute('rel', 'noopener noreferrer');
$aAlertBanner->appendChild($dom->createTextNode(
- _('You are running phpPgAdmin with session security disabled. This is a potential security risk!')
+ _('You are running phpPgAdmin with session security disabled. This is a potential security risk!'),
));
$pAlertBanner->appendChild($aAlertBanner);
$divAlertBanner->appendChild($pAlertBanner);
@@ -423,13 +434,14 @@ public static function buildTopBar(\DOMDocument $dom): \DOMElement
$trTopbar = $dom->createElement('tr');
$serverSession = ServerSession::fromRequestParameter();
+
if (!is_null($serverSession)) {
$topLeftContent = sprintf(
_("%s running on %s:%s -- You are logged in as user \"%s\""),
'' . htmlspecialchars((string)$serverSession->Platform) . '',
'' . htmlspecialchars((string)$serverSession->Host) . '',
'' . $serverSession->Port->Value . '',
- '' . htmlspecialchars((string)$serverSession->Username) . ''
+ '' . htmlspecialchars((string)$serverSession->Username) . '',
);
$fragment = $dom->createDocumentFragment();
$fragment->appendXML($topLeftContent);
@@ -519,7 +531,6 @@ private static function buildTopBarLinks(\DOMDocument $dom, ServerSession $serve
'text' => _('History'),
'url' => 'history.php',
'url-params' => [
- 'action' => 'pophistory',
'server' => $serverSession->id(),
'subject' => 'table',
],
@@ -546,9 +557,11 @@ private static function buildTopBarLinks(\DOMDocument $dom, ServerSession $serve
$li = $dom->createElement('li');
$a = $dom->createElement('a', $link['text']);
$a->setAttribute('href', $link['url'] . '?' . http_build_query($link['url-params']));
+
if (isset($link['target'])) {
$a->setAttribute('target', $link['target']);
}
+
$a->setAttribute('id', 'toplink_' . $key);
$li->appendChild($a);
$ulTopLinks->appendChild($li);
@@ -581,6 +594,7 @@ private static function buildTrailForServer(\DOMDocument $dom): \DOMElement
$imgIcon->setAttribute('alt', _('Server'));
$spanIcon->appendChild($imgIcon);
$a->appendChild($spanIcon);
+
if (!is_null($serverSession)) {
$spanLabel = $dom->createElement('span', (string)$serverSession->Name);
$spanLabel->setAttribute('class', 'label');
@@ -595,7 +609,7 @@ private static function buildTrailForServer(\DOMDocument $dom): \DOMElement
urlParams: [
'help' => 'pg.server',
'server' => $serverId,
- ]
+ ],
);
$td->appendChild($aHelp);
$td->appendChild($dom->createTextNode(': '));