-
+
diff --git a/panels/tb_droptables.php b/panels/tb_droptables.php
index 6f2a92a..de68877 100644
--- a/panels/tb_droptables.php
+++ b/panels/tb_droptables.php
@@ -23,11 +23,11 @@
-
+
-
+
@@ -35,7 +35,7 @@
=$tb_strings['SQLCommand']?>
-
+
=$MESSAGES['CONFIRM_MANY_TABLES_DELETE']?>
From 778248828471c33308c3dac97d83643b168e68fa Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 20 Jan 2026 11:00:12 +0000
Subject: [PATCH 08/42] Initial plan
From 0a977026bcfd29d4fd5bd2bc10abbf96057319dd Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 20 Jan 2026 11:15:38 +0000
Subject: [PATCH 09/42] Initial plan
From bc983c0bb07fabc7b4a9c533a64afcf9265288f5 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 20 Jan 2026 11:20:31 +0000
Subject: [PATCH 10/42] Fix XSS vulnerabilities in showblob.php and
showimage.php
Co-authored-by: mariuz <18359+mariuz@users.noreply.github.com>
---
showblob.php | 16 +++++++++-------
showimage.php | 6 +++---
2 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/showblob.php b/showblob.php
index d6910ce..d38af13 100644
--- a/showblob.php
+++ b/showblob.php
@@ -15,13 +15,13 @@
require './inc/script_start.inc.php';
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
- $table = get_request_data('table', 'GET');
- $col = get_request_data('col', 'GET');
- $where = get_request_data('where', 'GET');
+ $table = htmlspecialchars(get_request_data('table', 'GET'), ENT_QUOTES, 'UTF-8');
+ $col = htmlspecialchars(get_request_data('col', 'GET'), ENT_QUOTES, 'UTF-8');
+ $where = htmlspecialchars(get_request_data('where', 'GET'), ENT_QUOTES, 'UTF-8');
} else {
- $table = get_request_data('table');
- $col = get_request_data('col');
- $where = get_request_data('where');
+ $table = htmlspecialchars(get_request_data('table'), ENT_QUOTES, 'UTF-8');
+ $col = htmlspecialchars(get_request_data('col'), ENT_QUOTES, 'UTF-8');
+ $where = htmlspecialchars(get_request_data('where'), ENT_QUOTES, 'UTF-8');
$s_wt['blob_as'][$col] = get_request_data('blobtype');
}
@@ -61,7 +61,9 @@
echo '
'.htmlspecialchars($blob)."
\n";
break;
case 'html':
- echo $blob;
+ // Note: HTML blob display is intentionally unescaped to allow rendering of HTML content.
+ // This should only be used with trusted blob data. For untrusted data, use 'text' mode instead.
+ echo htmlspecialchars($blob, ENT_QUOTES, 'UTF-8');
break;
case 'hex':
echo hex_view($blob);
diff --git a/showimage.php b/showimage.php
index 3884e01..508f75f 100644
--- a/showimage.php
+++ b/showimage.php
@@ -24,9 +24,9 @@
$dbhandle = db_connect()
or fb_error();
-$table = $_GET['table'];
-$col = $_GET['col'];
-$where = $_GET['where'];
+$table = htmlspecialchars($_GET['table'], ENT_QUOTES, 'UTF-8');
+$col = htmlspecialchars($_GET['col'], ENT_QUOTES, 'UTF-8');
+$where = htmlspecialchars($_GET['where'], ENT_QUOTES, 'UTF-8');
$sql = sprintf('SELECT %s FROM %s %s', $col, $table, $where);
$blob = get_blob_content($sql);
From 3d28a4e158c2f59add5066d163c874804510560a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 20 Jan 2026 11:24:21 +0000
Subject: [PATCH 11/42] Fix header injection vulnerability in settings.php
Co-authored-by: mariuz <18359+mariuz@users.noreply.github.com>
---
settings.php | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/settings.php b/settings.php
index 6eb52c6..6188f66 100644
--- a/settings.php
+++ b/settings.php
@@ -34,7 +34,16 @@
$s_stylesheet_etag = '';
}
-header("Location: " . $_SERVER["HTTP_REFERER"]);
+// Redirect back to referer, but validate it first to prevent header injection
+$referer = isset($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : 'index.php';
+// Validate referer to prevent header injection - only allow same-origin URLs
+if (filter_var($referer, FILTER_VALIDATE_URL) &&
+ (parse_url($referer, PHP_URL_HOST) === $_SERVER['HTTP_HOST'] ||
+ parse_url($referer, PHP_URL_HOST) === null)) {
+ header("Location: " . $referer);
+} else {
+ header("Location: index.php");
+}
require('./inc/script_end.inc.php');
From 7474a15492fb4afe58db84c5de742df33e4f3f6b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 20 Jan 2026 11:27:09 +0000
Subject: [PATCH 12/42] Address code review feedback - improve SQL injection
prevention and URL validation
Co-authored-by: mariuz <18359+mariuz@users.noreply.github.com>
---
settings.php | 17 +++++++++++++----
showblob.php | 30 +++++++++++++++++++++---------
showimage.php | 18 +++++++++++++++---
3 files changed, 49 insertions(+), 16 deletions(-)
diff --git a/settings.php b/settings.php
index 6188f66..4e0087c 100644
--- a/settings.php
+++ b/settings.php
@@ -37,11 +37,20 @@
// Redirect back to referer, but validate it first to prevent header injection
$referer = isset($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : 'index.php';
// Validate referer to prevent header injection - only allow same-origin URLs
-if (filter_var($referer, FILTER_VALIDATE_URL) &&
- (parse_url($referer, PHP_URL_HOST) === $_SERVER['HTTP_HOST'] ||
- parse_url($referer, PHP_URL_HOST) === null)) {
- header("Location: " . $referer);
+$referer_host = parse_url($referer, PHP_URL_HOST);
+$current_host = $_SERVER['HTTP_HOST'];
+
+// Allow only same-origin URLs (when host matches) or relative URLs (when host is null)
+// Reject external URLs and malformed URLs
+if (filter_var($referer, FILTER_VALIDATE_URL)) {
+ // Absolute URL - must be same origin
+ if ($referer_host === $current_host) {
+ header("Location: " . $referer);
+ } else {
+ header("Location: index.php");
+ }
} else {
+ // Not a valid absolute URL - use default
header("Location: index.php");
}
diff --git a/showblob.php b/showblob.php
index d38af13..2f0b937 100644
--- a/showblob.php
+++ b/showblob.php
@@ -15,18 +15,29 @@
require './inc/script_start.inc.php';
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
- $table = htmlspecialchars(get_request_data('table', 'GET'), ENT_QUOTES, 'UTF-8');
- $col = htmlspecialchars(get_request_data('col', 'GET'), ENT_QUOTES, 'UTF-8');
- $where = htmlspecialchars(get_request_data('where', 'GET'), ENT_QUOTES, 'UTF-8');
+ $table = get_request_data('table', 'GET');
+ $col = get_request_data('col', 'GET');
+ $where = get_request_data('where', 'GET');
} else {
- $table = htmlspecialchars(get_request_data('table'), ENT_QUOTES, 'UTF-8');
- $col = htmlspecialchars(get_request_data('col'), ENT_QUOTES, 'UTF-8');
- $where = htmlspecialchars(get_request_data('where'), ENT_QUOTES, 'UTF-8');
+ $table = get_request_data('table');
+ $col = get_request_data('col');
+ $where = get_request_data('where');
$s_wt['blob_as'][$col] = get_request_data('blobtype');
}
-$imageurl = 'showimage.php?where='.urlencode($where).'&table='.$table.'&col='.$col;
+// Validate SQL identifiers to prevent SQL injection
+// Table and column names should only contain alphanumeric characters and underscores
+if (!preg_match('/^[a-zA-Z0-9_$]+$/', $table)) {
+ die('Invalid table name');
+}
+if (!preg_match('/^[a-zA-Z0-9_$]+$/', $col)) {
+ die('Invalid column name');
+}
+// Where clause validation is complex, so we trust it comes from internal app logic
+// In production, this should use parameterized queries
+
+$imageurl = 'showimage.php?where='.urlencode($where).'&table='.urlencode($table).'&col='.urlencode($col);
$imageurl .= '&'.uniqid('UNIQ_');
$blob = get_blob_content(sprintf('SELECT %s FROM %s %s', $col, $table, $where));
@@ -61,8 +72,9 @@
echo '
'.htmlspecialchars($blob)."
\n";
break;
case 'html':
- // Note: HTML blob display is intentionally unescaped to allow rendering of HTML content.
- // This should only be used with trusted blob data. For untrusted data, use 'text' mode instead.
+ // Note: Displaying HTML blob content with escaping to prevent XSS attacks.
+ // The HTML will be shown as plain text. To render actual HTML, this feature
+ // should only be used with trusted blob data in a controlled environment.
echo htmlspecialchars($blob, ENT_QUOTES, 'UTF-8');
break;
case 'hex':
diff --git a/showimage.php b/showimage.php
index 508f75f..4fa7e14 100644
--- a/showimage.php
+++ b/showimage.php
@@ -24,9 +24,21 @@
$dbhandle = db_connect()
or fb_error();
-$table = htmlspecialchars($_GET['table'], ENT_QUOTES, 'UTF-8');
-$col = htmlspecialchars($_GET['col'], ENT_QUOTES, 'UTF-8');
-$where = htmlspecialchars($_GET['where'], ENT_QUOTES, 'UTF-8');
+$table = $_GET['table'];
+$col = $_GET['col'];
+$where = $_GET['where'];
+
+// Validate SQL identifiers to prevent SQL injection
+// Table and column names should only contain alphanumeric characters and underscores
+if (!preg_match('/^[a-zA-Z0-9_$]+$/', $table)) {
+ die('Invalid table name');
+}
+if (!preg_match('/^[a-zA-Z0-9_$]+$/', $col)) {
+ die('Invalid column name');
+}
+// Where clause validation is complex, so we trust it comes from internal app logic
+// In production, this should use parameterized queries
+
$sql = sprintf('SELECT %s FROM %s %s', $col, $table, $where);
$blob = get_blob_content($sql);
From 76a57f327ccfbc15798ad694b1d743eea5362256 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 20 Jan 2026 11:28:22 +0000
Subject: [PATCH 13/42] Add warning comments for WHERE clause and support
relative URLs in referer validation
Co-authored-by: mariuz <18359+mariuz@users.noreply.github.com>
---
settings.php | 8 +++++---
showblob.php | 5 +++--
showimage.php | 5 +++--
3 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/settings.php b/settings.php
index 4e0087c..9089fe3 100644
--- a/settings.php
+++ b/settings.php
@@ -40,8 +40,7 @@
$referer_host = parse_url($referer, PHP_URL_HOST);
$current_host = $_SERVER['HTTP_HOST'];
-// Allow only same-origin URLs (when host matches) or relative URLs (when host is null)
-// Reject external URLs and malformed URLs
+// Allow same-origin absolute URLs or relative URLs
if (filter_var($referer, FILTER_VALIDATE_URL)) {
// Absolute URL - must be same origin
if ($referer_host === $current_host) {
@@ -49,8 +48,11 @@
} else {
header("Location: index.php");
}
+} elseif (strpos($referer, '/') === 0) {
+ // Relative URL starting with / - safe to use
+ header("Location: " . $referer);
} else {
- // Not a valid absolute URL - use default
+ // Not a valid URL - use default
header("Location: index.php");
}
diff --git a/showblob.php b/showblob.php
index 2f0b937..1041fa1 100644
--- a/showblob.php
+++ b/showblob.php
@@ -34,8 +34,9 @@
if (!preg_match('/^[a-zA-Z0-9_$]+$/', $col)) {
die('Invalid column name');
}
-// Where clause validation is complex, so we trust it comes from internal app logic
-// In production, this should use parameterized queries
+// WARNING: WHERE clause validation is complex and not implemented here
+// The WHERE parameter remains a potential SQL injection vector
+// This should use parameterized queries in production
$imageurl = 'showimage.php?where='.urlencode($where).'&table='.urlencode($table).'&col='.urlencode($col);
$imageurl .= '&'.uniqid('UNIQ_');
diff --git a/showimage.php b/showimage.php
index 4fa7e14..5242e03 100644
--- a/showimage.php
+++ b/showimage.php
@@ -36,8 +36,9 @@
if (!preg_match('/^[a-zA-Z0-9_$]+$/', $col)) {
die('Invalid column name');
}
-// Where clause validation is complex, so we trust it comes from internal app logic
-// In production, this should use parameterized queries
+// WARNING: WHERE clause validation is complex and not implemented here
+// The WHERE parameter remains a potential SQL injection vector
+// This should use parameterized queries in production
$sql = sprintf('SELECT %s FROM %s %s', $col, $table, $where);
$blob = get_blob_content($sql);
From 72174b695b18a58d97bcac7dc33e73ece35caac6 Mon Sep 17 00:00:00 2001
From: Popa Adrian Marius
Date: Tue, 24 Feb 2026 15:43:09 +0200
Subject: [PATCH 14/42] docs: improve README structure and content
---
README.md | 127 ++++++++++++++++++++++++++++++------------------------
1 file changed, 70 insertions(+), 57 deletions(-)
diff --git a/README.md b/README.md
index 4ce82de..3084a7a 100644
--- a/README.md
+++ b/README.md
@@ -1,85 +1,98 @@
-# FirebirdWebAdmin is a web frontend for the Firebird database server
+# FirebirdWebAdmin
+
+**FirebirdWebAdmin** is a lightweight, powerful web-based administration tool for the Firebird database server. It provides an intuitive interface for managing databases, tables, and other database objects directly from your browser.
[](https://crowdin.com/project/firebirdwebadmin)
[](https://codeclimate.com/github/mariuz/firebirdwebadmin)
+[](https://opensource.org/licenses/GPL-2.0)
+[](https://php.net)
+
+---
+
+## ๐ Features
-By now it has the functionalities for
-
-* creating, deleting, modifying databases, tables, generators, views, triggers, domains, indices, stored procedures, udf's, exceptions, roles and database users
-* performing sql expressions on databases and display the results
-* import and export of data through files in the csv format
-* browsing through the contents of tables and views, watching them growing while typing in data
-* selecting data for deleting and editing while browsing tables
-* inserting, deleting, displaying the contents of blob fields
-* diplaying database metadata, browsing the firebird system tables
-* database backup and restore, database maintenance
+### ๐ Database & Object Management
+* **Database Operations:** Create, delete, and modify databases.
+* **Schema Management:** Manage tables, views, triggers, domains, indices, and generators.
+* **Business Logic:** Create and edit stored procedures and User Defined Functions (UDFs).
+* **Security:** Manage database users and roles.
+* **Exceptions:** Define and manage database exceptions.
-Some of the features are only available if the database- and the web-server are running on the same machine. The reason is that php have to call the Firebird tools (isql, gsec, gstat, etc.) to perform certain actions.
+### ๐ Data Manipulation
+* **SQL Console:** Execute SQL expressions and scripts with result display.
+* **Data Browsing:** Browse table and view contents with real-time updates.
+* **Editing:** Insert, edit, and delete data rows while browsing.
+* **Blob Support:** Handle BLOB fields (display and edit contents).
+* **Import/Export:** Seamlessly import and export data using CSV format.
-## Overview
+### ๐ Administration & Maintenance
+* **Maintenance:** Database backup and restore capabilities.
+* **Monitoring:** Display database metadata and browse system tables.
+* **Statistics:** Access database and server statistics (requires local access).
+* **Maintenance Tools:** Integrated database maintenance functions.
-1. [Documentation](#documentation)
-2. [Requirements](#requirements)
-3. [ChangeLog](#requirements)
-4. [Contributing](#contributing)
-5. [Copyright notice](#copyright-notice)
+> **Note:** Some administrative features (like backup/restore and statistics) require PHP to have access to Firebird command-line tools (`isql`, `gsec`, `gstat`, etc.) and may require the web server to run on the same machine as the database server.
-## Documentation
+---
-There is no documentation available yet, but if you are familiar with Firebird you will have no troubles using FirebirdWebAdmin.
+## ๐ Requirements
-For some basic configuration settings have a look to the file `./inc/configuration.inc.php` before you start the programm.
+* **PHP:** Version 5.5 or higher (PHP 7.x and 8.x recommended).
+ * Must be compiled with `pdo_firebird` or `interbase` support.
+ * `pcre` support enabled.
+* **Database:** Firebird 2.x, 3.x, or 4.x.
+* **Web Server:** Apache 2.x, Nginx, or any server with PHP support.
+* **Operating System:** Linux (tested), Windows (compatible).
-Here is how to use and install on Ubuntu
+---
-Firebird documentation is located on this page
+## โ๏ธ Installation & Configuration
-## Requirements
+1. **Download:** Clone this repository or download the source code.
+ ```bash
+ git clone https://github.com/mariuz/firebirdwebadmin.git
+ ```
+2. **Web Server Setup:** Place the directory in your web server's document root (e.g., `/var/www/html/`).
+3. **Configuration:**
+ * Open `inc/configuration.inc.php`.
+ * Configure the `BINPATH` to point to your Firebird binaries (e.g., `/usr/bin/`).
+ * Set `TMPPATH` to a directory writable by the web server.
+ * Adjust default connection settings if necessary.
+4. **Access:** Navigate to the directory in your browser (e.g., `http://localhost/firebirdwebadmin/`).
-This is the environment I'm using for the development. Other components are not or less tested. So if you got problems make sure you are not using older software components.
+---
-PHP with compiled in support for Firebird/InterBase and pcre (but any version >= 5.5 should work)
+## ๐ Documentation
-Firebird 2.x.x for Linux,
-Apache 2.x or any server with php support
+While there is no exhaustive manual, users familiar with Firebird will find the interface intuitive.
-## ChangeLog
+* **Configuration:** Check `inc/configuration.inc.php` for advanced settings.
+* **Ubuntu Guide:** [How to install Firebird on Ubuntu](https://help.ubuntu.com/community/Firebird3.0)
+* **Firebird Official Docs:** [Firebird Documentation](https://www.firebirdsql.org/en/documentation/)
-### Version 3.4.1 (27.02.2020)
+---
-* [enhancement:] Adjust "Accessories" page UI.
-* [enhancement:] Remove Crowdin badge from footer.
-* [enhancement:] Update debug_funcs.inc.php
-* [bugfix:] Don't warn if "isql" is "isql-fb" on Linux
-* [typo:] Correct typo: firebirid -> firebird
-* [bugfix] fix sql create database
-* [enhancement:] Add Character Sets
-* [enhancement:] Quiet PHP7.2 deprecation warning โฆ
-* [enhancement:] Further create_function refactor
-* [enhancement:] Remove unused/outdated markableFbwaTable.
-* [enhancement:] cosmetics
+## ๐ ChangeLog
-#### Further informations
+See [CHANGELOG.md](CHANGELOG.md) for the full history of changes.
-* See [CHANGELOG.md][changelog] to get the full changelog.
+---
-## Contributing
+## ๐ค Contributing
-1. Fork it
-2. Create your feature branch (`git checkout -b my-new-feature`)
-3. Commit your changes (`git commit -am 'Add some feature'`)
-4. Push to the branch (`git push origin my-new-feature`)
-5. Create new Pull Request
+We welcome contributions! To contribute:
-## Copyright notice
+1. Fork the repository.
+2. Create a feature branch (`git checkout -b feature/amazing-feature`).
+3. Commit your changes (`git commit -m 'Add amazing feature'`).
+4. Push to the branch (`git push origin feature/amazing-feature`).
+5. Open a Pull Request.
- (C) 2000,2001,2002,2003,2004 Lutz Brueckner
- Kapellenstr. 1A
- 22117 Hamburg, Germany
+---
-FirebirdWebAdmin is published under the terms of the [GNU GPL v.2][gnu_gpl_v2_license], please read the file LICENCE for details.
+## โ๏ธ License
-This software is provided 'as-is', without any expressed or implied warranty. In no event will the author be held liable for any damages arising from the use of this software.
+**FirebirdWebAdmin** is published under the terms of the [GNU GPL v.2](https://opensource.org/licenses/GPL-2.0).
+See the `LICENSE` file for details.
-[gnu_gpl_v2_license]: https://opensource.org/licenses/GPL-2.0
-[changelog]: CHANGELOG.md
+ยฉ 2000-2026 Lutz Brueckner and contributors.
From 90c6c9f7b7b152b8229c1c69be90f48f9134edc2 Mon Sep 17 00:00:00 2001
From: Popa Adrian Marius
Date: Tue, 24 Feb 2026 15:59:52 +0200
Subject: [PATCH 15/42] refactor: Replace XMLHttpRequestClient with fetch API
---
CHANGELOG.md | 5 ++
inc/javascript.inc.php | 54 +++++---------------
js/XMLHttpRequestClient.js | 69 -------------------------
js/miscellaneous.js | 101 +++++++++++++++++++++++++++++++++++--
4 files changed, 116 insertions(+), 113 deletions(-)
delete mode 100644 js/XMLHttpRequestClient.js
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3a9539c..a6d16e2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
# ChangeLog
+## Version 3.4.2 (24.02.2026)
+
+* [enhancement:] Refactored all AJAX calls to use the modern `fetch` API.
+* [enhancement:] Removed the outdated and insecure `XMLHttpRequestClient.js` library.
+
## Version 3.4.1 (27.02.2020)
* [enhancement:] Adjust "Accessories" page UI.
diff --git a/inc/javascript.inc.php b/inc/javascript.inc.php
index 0205179..b255c69 100644
--- a/inc/javascript.inc.php
+++ b/inc/javascript.inc.php
@@ -152,21 +152,6 @@ function adjustCollation(source, target) {
return $js;
}
-//
-// include the XMLHttpRequestClient library
-//
-function js_xml_http_request_client()
-{
- static $done = false;
-
- if ($done == true) {
- return '';
- }
- $done = true;
-
- return js_javascript_file('js/XMLHttpRequestClient.js');
-}
-
//
// return the URL of the server-script for the XMLHttpRequests
//
@@ -195,8 +180,7 @@ function js_request_column_config_form()
$js = <<
function requestColumnConfigForm(fk_table, table, column, divId) {
- var req = new XMLHttpRequestClient("$server_url");
- req.Request("column_config_form", new Array(fk_table, table, column), "setInnerHtml", new Array(divId));
+ doRequest("column_config_form", [fk_table, table, column], "setInnerHtml", [divId]);
}
@@ -215,8 +199,7 @@ function js_request_close_panel()
$js = <<
function requestClosedPanel(idx, active) {
- var req = new XMLHttpRequestClient("$server_url");
- req.Request("closed_panel", new Array(idx, active), "setInnerHtml", new Array("p" + idx));
+ doRequest("closed_panel", [idx, active], "setInnerHtml", ["p" + idx]);
}
@@ -241,12 +224,10 @@ function js_request_details()
$js = <<
function requestDetail(type, name, title) {
- var req = new XMLHttpRequestClient("$server_url");
- req.Request("detail_view", new Array(type, name, title), "setInnerHtml", new Array(detailPrefix(type) + '_' + name));
+ doRequest("detail_view", [type, name, title], "setInnerHtml", [detailPrefix(type) + '_' + name]);
}
function closeDetail(type, id, name, title) {
- var req = new XMLHttpRequestClient("$server_url");
- req.Request("detail_close", new Array(type, name, title), "setInnerHtml", new Array(id));
+ doRequest("detail_close", [type, name, title], "setInnerHtml", [id]);
}
@@ -267,8 +248,7 @@ function js_request_fk()
$js = <<
function requestFKValues(table, column, value) {
- var req = new XMLHttpRequestClient("$server_url");
- req.Request("fk_values", new Array(table, column, value), "setInnerHtml", new Array("fk"));
+ doRequest("fk_values", [table, column, value], "setInnerHtml", ["fk"]);
}
@@ -287,12 +267,10 @@ function js_request_filter_fields()
$js = <<
function getFilterFields(table) {
- var req = new XMLHttpRequestClient("$server_url");
- req.Request("systable_filter_fields", new Array(table), "setInnerHtml", new Array("systable_field"));
+ doRequest("systable_filter_fields", [table], "setInnerHtml", ["systable_field"]);
}
function getFilterValues(table, field) {
- var req = new XMLHttpRequestClient("$server_url");
- req.Request("systable_filter_values", new Array(table, field), "setInnerHtml", new Array("systable_value"));
+ doRequest("systable_filter_values", [table, field], "setInnerHtml", ["systable_value"]);
}
@@ -311,8 +289,7 @@ function js_request_table_columns()
$js = <<
function requestTableColumns(table, id, restriction) {
- var req = new XMLHttpRequestClient("$server_url");
- req.Request("table_columns_selectlist", new Array(table, id, restriction), "setInnerHtml", new Array(id));
+ doRequest("table_columns_selectlist", [table, id, restriction], "setInnerHtml", [id]);
}
@@ -332,8 +309,7 @@ function js_request_sql_buffer()
$js = <<
function requestSqlBuffer(idx) {
- var req = new XMLHttpRequestClient("$server_url");
- req.Request("sql_buffer", new Array(idx), "putSqlBuffer", new Array(idx));
+ doRequest("sql_buffer", [idx], "putSqlBuffer", [idx]);
}
function putSqlBuffer(sql, idx) {
@@ -356,8 +332,7 @@ function js_data_export()
$js = <<
function replaceExportFormatOptions(format) {
- var req = new XMLHttpRequestClient("$server_url");
- req.Request("data_export_format_options", new Array(format), "setInnerHtml", new Array("dt_export_format_options"));
+ doRequest("data_export_format_options", [format], "setInnerHtml", ["dt_export_format_options"]);
hide("dt_export_iframe");
@@ -371,13 +346,11 @@ function replaceExportFormatOptions(format) {
}
function setExportTarget(target) {
- var req = new XMLHttpRequestClient("$server_url");
- req.Request("set_export_target", new Array(target), "", new Array());
+ doRequest("set_export_target", [target], "", []);
}
function setExportSource(source) {
- var req = new XMLHttpRequestClient("$server_url");
- req.Request("set_export_source", new Array(source), "", new Array());
+ doRequest("set_export_source", [source], "", []);
hide("dt_export_iframe");
@@ -414,8 +387,7 @@ function js_request_comment_area()
$js = <<
function requestCommentArea(type, name) {
- var req = new XMLHttpRequestClient("$server_url");
- req.Request("comment_area", new Array(type, name), "setInnerHtml", new Array(detailPrefix(type) + 'c_' + name));
+ doRequest("comment_area", [type, name], "setInnerHtml", [detailPrefix(type) + 'c_' + name]);
}
diff --git a/js/XMLHttpRequestClient.js b/js/XMLHttpRequestClient.js
deleted file mode 100644
index b9b36e5..0000000
--- a/js/XMLHttpRequestClient.js
+++ /dev/null
@@ -1,69 +0,0 @@
-// Purpose javascript implementation of a client class for XMLHttpRequests
-// Author Lutz Brueckner
-// Copyright (c) 2000-2006 by Lutz Brueckner,
-// published under the terms of the GNU General Public Licence v.2,
-// see file LICENCE for details
-
-
-/*
- by defining the request object in the global scope
- it is reusable for multiple calls on mozilla browsers
-*/
-var xmlreq = false;
-
-function XMLHttpRequestClient(server_url) {
-
- var method = 'GET';
- var serverUrl = server_url;
- var response = null;
- var jsCallback = null;
- var jsCallbackParameters = null;
- var debug = false;
-
- this.Request = doRequest;
-
- xmlreq = new XMLHttpRequest();
- return;
-
- function doRequest(handler, handler_parameters, callback, callback_parameters) {
-
- jsCallback = callback;
- jsCallbackParameters = callback_parameters;
-
- var sep = serverUrl.search(/\?/) == -1 ? '?' : '&';
- xmlreq.onreadystatechange = ProcessReqChange;
- xmlreq.open(method, serverUrl + sep + 'f=' + handler + _getUrlParameters(handler_parameters), true);
- xmlreq.setRequestHeader('Content-Type', 'text/xml; charset=' + php_charset);
- xmlreq.send(null);
- }
-
- function ProcessReqChange() {
-
- if (xmlreq.readyState == 4) {
- if (jsCallback != null) {
- response = xmlreq.responseText;
- eval(jsCallback + "(response" + _getParametersList(jsCallbackParameters) + ")");
- }
- }
- }
-
- function _getUrlParameters(parameters) {
-
- var str = '';
- for (var i=0; i {
+ url.searchParams.append(`p${i}`, param);
+ });
+
+ fetch(url)
+ .then(response => {
+ if (!response.ok) {
+ throw new Error('Network response was not ok');
+ }
+ return response.text();
+ })
+ .then(html => {
+ displayFKValues(html);
+ })
+ .catch(error => {
+ console.error('There has been a problem with your fetch operation:', error);
+ });
}
function displayFKValues(html) {
@@ -35,20 +53,97 @@ function displayFKValues(html) {
}
function detailPrefix(type) {
+
switch (type) {
+
case 'table':
+
return 't';
+
break;
+
case 'view':
+
return 'v';
+
break;
+
case 'trigger':
+
return 'r';
+
break;
+
case 'procedure':
+
return 'p';
+
break;
+
default:
+
return '';
+
}
-}
\ No newline at end of file
+
+}
+
+
+
+// A modern fetch-based replacement for the old XMLHttpRequestClient.Request
+
+function doRequest(handler, handler_parameters, callback, callback_parameters) {
+
+ const url = new URL(php_xml_http_request_server_url);
+
+ url.searchParams.append('f', handler);
+
+ handler_parameters.forEach((param, i) => {
+
+ url.searchParams.append(`p${i}`, param);
+
+ });
+
+
+
+ fetch(url)
+
+ .then(response => {
+
+ if (!response.ok) {
+
+ throw new Error(`Network response was not ok for handler: ${handler}`);
+
+ }
+
+ return response.text();
+
+ })
+
+ .then(textResponse => {
+
+ // Get the callback function from the window object
+
+ const callbackFn = window[callback];
+
+ if (typeof callbackFn === 'function') {
+
+ // Call the function with the response and any extra parameters
+
+ callbackFn(textResponse, ...callback_parameters);
+
+ } else {
+
+ console.error(`Callback function "${callback}" not found.`);
+
+ }
+
+ })
+
+ .catch(error => {
+
+ console.error('There has been a problem with your fetch operation:', error);
+
+ });
+
+}
From f573e73ac63875dbc72fd0b6012a815ee9832ef5 Mon Sep 17 00:00:00 2001
From: Popa Adrian Marius
Date: Tue, 24 Feb 2026 16:43:19 +0200
Subject: [PATCH 16/42] feat(testing): Add Playwright E2E tests with GitHub
Actions
---
.github/docker/php-apache-firebird/Dockerfile | 2 +
.github/workflows/playwright.yml | 72 +++++++++++++++++
.gitignore | 9 ++-
docker-compose.yml | 31 ++++++++
package-lock.json | 79 +++++++++++++++++++
package.json | 7 +-
playwright.config.js | 45 +++++++++++
tests/e2e/example.spec.js | 18 +++++
8 files changed, 260 insertions(+), 3 deletions(-)
create mode 100644 .github/docker/php-apache-firebird/Dockerfile
create mode 100644 .github/workflows/playwright.yml
create mode 100644 docker-compose.yml
create mode 100644 package-lock.json
create mode 100644 playwright.config.js
create mode 100644 tests/e2e/example.spec.js
diff --git a/.github/docker/php-apache-firebird/Dockerfile b/.github/docker/php-apache-firebird/Dockerfile
new file mode 100644
index 0000000..ab82819
--- /dev/null
+++ b/.github/docker/php-apache-firebird/Dockerfile
@@ -0,0 +1,2 @@
+FROM php:8.1-apache
+RUN docker-php-ext-install pdo_firebird && a2enmod rewrite
diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
new file mode 100644
index 0000000..c038513
--- /dev/null
+++ b/.github/workflows/playwright.yml
@@ -0,0 +1,72 @@
+name: Playwright Tests
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: 18
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Install Playwright browsers
+ run: npx playwright install --with-deps
+
+ - name: Configure application for testing
+ run: |
+ cp inc/configuration.inc.php inc/configuration.inc.php.bak
+ sed -i "s/define('DB_USER', 'SYSDBA');/define('DB_USER', 'SYSDBA');/" inc/configuration.inc.php
+ sed -i "s/define('DB_PASS', '');/define('DB_PASS', 'test');/" inc/configuration.inc.php
+ sed -i "s/define('DB_HOST', 'localhost');/define('DB_HOST', 'firebird');/" inc/configuration.inc.php
+ sed -i "s|define('DB_PATH', '/var/lib/firebird/3.0/data/employee.fdb');|define('DB_PATH', 'test.fdb');|" inc/configuration.inc.php
+
+ - name: Start services
+ run: docker-compose up -d
+
+ - name: Wait for services to be healthy
+ run: |
+ echo "Waiting for services to become healthy..."
+ # This command will wait for the healthchecks defined in docker-compose.yml to pass.
+ # It will exit with an error if the services do not become healthy within the timeout.
+ docker-compose ps
+ max_wait=300
+ current_wait=0
+ while [ $current_wait -lt $max_wait ]; do
+ if [ "$(docker-compose ps -q web | xargs docker inspect -f '{{.State.Health.Status}}')" = "healthy" ] &&
+ [ "$(docker-compose ps -q firebird | xargs docker inspect -f '{{.State.Health.Status}}')" = "healthy" ]; then
+ echo "Services are healthy!"
+ docker-compose logs
+ exit 0
+ fi
+ echo -n "."
+ sleep 5
+ current_wait=$((current_wait + 5))
+ done
+ echo "Services did not become healthy in time."
+ docker-compose logs
+ exit 1
+
+ - name: Run Playwright tests
+ run: npx playwright test
+ env:
+ BASE_URL: http://localhost:8080
+
+ - name: Stop services
+ if: always()
+ run: docker-compose down
+
+ - name: Restore config file
+ if: always()
+ run: |
+ mv inc/configuration.inc.php.bak inc/configuration.inc.php
diff --git a/.gitignore b/.gitignore
index 4037493..a06a842 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,4 +5,11 @@
# git config --global core.excludesfile '~/.gitignore_global'
# PhpStorm
-.idea/**/*
\ No newline at end of file
+
+.idea/**/*
+
+
+
+# Node dependencies
+
+node_modules/
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..67463b0
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,31 @@
+version: '3.8'
+services:
+ firebird:
+ image: firebird/firebird:3.0
+ ports:
+ - "3050:3050"
+ environment:
+ FIREBIRD_PASSWORD: test
+ FIREBIRD_DB: test.fdb
+ healthcheck:
+ test: ["CMD", "gbak", "-user", "sysdba", "-password", "test", "localhost:/firebird/data/test.fdb", "/dev/null"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+ web:
+ build:
+ context: .
+ dockerfile: .github/docker/php-apache-firebird/Dockerfile
+ ports:
+ - "8080:80"
+ volumes:
+ - .:/var/www/html
+ depends_on:
+ firebird:
+ condition: service_healthy
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://localhost/database.php"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..c4d90c1
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,79 @@
+{
+ "name": "firebird-web-admin",
+ "version": "3.4.1",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "firebird-web-admin",
+ "version": "3.4.1",
+ "license": "GPL-2.0",
+ "devDependencies": {
+ "@playwright/test": "^1.58.2"
+ }
+ },
+ "node_modules/@playwright/test": {
+ "version": "1.58.2",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz",
+ "integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "playwright": "1.58.2"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/playwright": {
+ "version": "1.58.2",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz",
+ "integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "playwright-core": "1.58.2"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "fsevents": "2.3.2"
+ }
+ },
+ "node_modules/playwright-core": {
+ "version": "1.58.2",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz",
+ "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "playwright-core": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
index a70e74a..1abcf43 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
"description": "FirebirdWebAdmin is a web frontend for the Firebird database server.",
"main": "index.js",
"scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
+ "test": "npx playwright test"
},
"repository": {
"type": "git",
@@ -34,5 +34,8 @@
"bugs": {
"url": "https://github.com/mariuz/firebirdwebadmin/issues"
},
- "homepage": "https://github.com/mariuz/firebirdwebadmin#readme"
+ "homepage": "https://github.com/mariuz/firebirdwebadmin#readme",
+ "devDependencies": {
+ "@playwright/test": "^1.58.2"
+ }
}
diff --git a/playwright.config.js b/playwright.config.js
new file mode 100644
index 0000000..4872824
--- /dev/null
+++ b/playwright.config.js
@@ -0,0 +1,45 @@
+// @ts-check
+const { defineConfig, devices } = require('@playwright/test');
+
+/**
+ * @see https://playwright.dev/docs/test-configuration
+ */
+module.exports = defineConfig({
+ testDir: './tests/e2e',
+ /* Run tests in files in parallel */
+ fullyParallel: true,
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
+ forbidOnly: !!process.env.CI,
+ /* Retry on CI only */
+ retries: process.env.CI ? 2 : 0,
+ /* Opt out of parallel tests on CI. */
+ workers: process.env.CI ? 1 : undefined,
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
+ reporter: 'html',
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
+ use: {
+ /* Base URL to use in actions like `await page.goto('/')`. */
+ baseURL: process.env.BASE_URL || 'http://localhost:8080',
+
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
+ trace: 'on-first-retry',
+ },
+
+ /* Configure projects for major browsers */
+ projects: [
+ {
+ name: 'chromium',
+ use: { ...devices['Desktop Chrome'] },
+ },
+
+ {
+ name: 'firefox',
+ use: { ...devices['Desktop Firefox'] },
+ },
+
+ {
+ name: 'webkit',
+ use: { ...devices['Desktop Safari'] },
+ },
+ ],
+});
diff --git a/tests/e2e/example.spec.js b/tests/e2e/example.spec.js
new file mode 100644
index 0000000..5067a96
--- /dev/null
+++ b/tests/e2e/example.spec.js
@@ -0,0 +1,18 @@
+import { test, expect } from '@playwright/test';
+
+test('has title', async ({ page }) => {
+ await page.goto('/database.php');
+
+ // Expect a title "to contain" a substring.
+ await expect(page).toHaveTitle(/Firebird Web Admin \/ Database/);
+});
+
+test('login form is visible', async ({ page }) => {
+ await page.goto('/database.php');
+
+ // Expect the login form to be visible
+ await expect(page.locator('form[action="database.php"]')).toBeVisible();
+ await expect(page.getByLabel('Username')).toBeVisible();
+ await expect(page.getByLabel('Password')).toBeVisible();
+ await expect(page.getByRole('button', { name: 'Login' })).toBeVisible();
+});
From 2d8e0c34f8e6f9cf54f9cea18e203812918e1f4b Mon Sep 17 00:00:00 2001
From: Popa Adrian Marius
Date: Tue, 24 Feb 2026 17:04:57 +0200
Subject: [PATCH 17/42] fix docker-compose command not found
---
.github/workflows/playwright.yml | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
index c038513..647a5ff 100644
--- a/.github/workflows/playwright.yml
+++ b/.github/workflows/playwright.yml
@@ -32,21 +32,21 @@ jobs:
sed -i "s|define('DB_PATH', '/var/lib/firebird/3.0/data/employee.fdb');|define('DB_PATH', 'test.fdb');|" inc/configuration.inc.php
- name: Start services
- run: docker-compose up -d
+ run: docker compose up -d
- name: Wait for services to be healthy
run: |
echo "Waiting for services to become healthy..."
# This command will wait for the healthchecks defined in docker-compose.yml to pass.
# It will exit with an error if the services do not become healthy within the timeout.
- docker-compose ps
+ docker compose ps
max_wait=300
current_wait=0
while [ $current_wait -lt $max_wait ]; do
if [ "$(docker-compose ps -q web | xargs docker inspect -f '{{.State.Health.Status}}')" = "healthy" ] &&
[ "$(docker-compose ps -q firebird | xargs docker inspect -f '{{.State.Health.Status}}')" = "healthy" ]; then
echo "Services are healthy!"
- docker-compose logs
+ docker compose logs
exit 0
fi
echo -n "."
@@ -54,7 +54,7 @@ jobs:
current_wait=$((current_wait + 5))
done
echo "Services did not become healthy in time."
- docker-compose logs
+ docker compose logs
exit 1
- name: Run Playwright tests
@@ -64,7 +64,7 @@ jobs:
- name: Stop services
if: always()
- run: docker-compose down
+ run: docker compose down
- name: Restore config file
if: always()
From 30eb78e5fd4cabedc9a33eed8b2a0bc57e7e9523 Mon Sep 17 00:00:00 2001
From: Popa Adrian Marius
Date: Tue, 24 Feb 2026 17:12:21 +0200
Subject: [PATCH 18/42] fix(ci): address obsolete docker-compose version and
incorrect Firebird image name
---
.github/docker/php-apache-firebird/Dockerfile | 3 ++-
.github/workflows/playwright.yml | 11 +++++------
docker-compose.yml | 5 ++---
3 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/.github/docker/php-apache-firebird/Dockerfile b/.github/docker/php-apache-firebird/Dockerfile
index ab82819..5ecab89 100644
--- a/.github/docker/php-apache-firebird/Dockerfile
+++ b/.github/docker/php-apache-firebird/Dockerfile
@@ -1,2 +1,3 @@
FROM php:8.1-apache
-RUN docker-php-ext-install pdo_firebird && a2enmod rewrite
+RUN apt-get update && apt-get install -y firebird-dev && \
+ docker-php-ext-install pdo_firebird && a2enmod rewrite
diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
index 647a5ff..2d2592b 100644
--- a/.github/workflows/playwright.yml
+++ b/.github/workflows/playwright.yml
@@ -26,10 +26,9 @@ jobs:
- name: Configure application for testing
run: |
cp inc/configuration.inc.php inc/configuration.inc.php.bak
- sed -i "s/define('DB_USER', 'SYSDBA');/define('DB_USER', 'SYSDBA');/" inc/configuration.inc.php
- sed -i "s/define('DB_PASS', '');/define('DB_PASS', 'test');/" inc/configuration.inc.php
- sed -i "s/define('DB_HOST', 'localhost');/define('DB_HOST', 'firebird');/" inc/configuration.inc.php
- sed -i "s|define('DB_PATH', '/var/lib/firebird/3.0/data/employee.fdb');|define('DB_PATH', 'test.fdb');|" inc/configuration.inc.php
+ sed -i "s/define('DEFAULT_HOST', 'localhost');/define('DEFAULT_HOST', 'firebird');/" inc/configuration.inc.php
+ sed -i "s/define('DEFAULT_DB', 'employee.fdb');/define('DEFAULT_DB', 'test.fdb');/" inc/configuration.inc.php
+ sed -i "s|define('DEFAULT_PATH', '/var/lib/firebird/2.5/data/');|define('DEFAULT_PATH', '/firebird/data/');|" inc/configuration.inc.php
- name: Start services
run: docker compose up -d
@@ -43,8 +42,8 @@ jobs:
max_wait=300
current_wait=0
while [ $current_wait -lt $max_wait ]; do
- if [ "$(docker-compose ps -q web | xargs docker inspect -f '{{.State.Health.Status}}')" = "healthy" ] &&
- [ "$(docker-compose ps -q firebird | xargs docker inspect -f '{{.State.Health.Status}}')" = "healthy" ]; then
+ if [ "$(docker compose ps -q web | xargs docker inspect -f '{{.State.Health.Status}}')" = "healthy" ] &&
+ [ "$(docker compose ps -q firebird | xargs docker inspect -f '{{.State.Health.Status}}')" = "healthy" ]; then
echo "Services are healthy!"
docker compose logs
exit 0
diff --git a/docker-compose.yml b/docker-compose.yml
index 67463b0..cbb43a7 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,12 +1,11 @@
-version: '3.8'
services:
firebird:
- image: firebird/firebird:3.0
+ image: firebirdsql/firebird:3.0
ports:
- "3050:3050"
environment:
FIREBIRD_PASSWORD: test
- FIREBIRD_DB: test.fdb
+ FIREBIRD_DATABASE: test.fdb
healthcheck:
test: ["CMD", "gbak", "-user", "sysdba", "-password", "test", "localhost:/firebird/data/test.fdb", "/dev/null"]
interval: 10s
From 87d211e7ee7a9b06373cd66e8f902397419ea1e0 Mon Sep 17 00:00:00 2001
From: Popa Adrian Marius
Date: Tue, 24 Feb 2026 17:14:57 +0200
Subject: [PATCH 19/42] fix(ci): install firebird extension from PECL for
fbird_* functions
---
.github/docker/php-apache-firebird/Dockerfile | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/.github/docker/php-apache-firebird/Dockerfile b/.github/docker/php-apache-firebird/Dockerfile
index 5ecab89..41443fe 100644
--- a/.github/docker/php-apache-firebird/Dockerfile
+++ b/.github/docker/php-apache-firebird/Dockerfile
@@ -1,3 +1,6 @@
FROM php:8.1-apache
RUN apt-get update && apt-get install -y firebird-dev && \
- docker-php-ext-install pdo_firebird && a2enmod rewrite
+ pecl install firebird && \
+ docker-php-ext-install pdo_firebird && \
+ docker-php-ext-enable firebird && \
+ a2enmod rewrite
From 7656acf52f697fd74016e1e3f9e0d91998a71c2b Mon Sep 17 00:00:00 2001
From: Popa Adrian Marius
Date: Tue, 24 Feb 2026 17:17:06 +0200
Subject: [PATCH 20/42] fix(ci): compile firebird extension from source
(GitHub)
---
.github/docker/php-apache-firebird/Dockerfile | 23 +++++++++++++++----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/.github/docker/php-apache-firebird/Dockerfile b/.github/docker/php-apache-firebird/Dockerfile
index 41443fe..8731da5 100644
--- a/.github/docker/php-apache-firebird/Dockerfile
+++ b/.github/docker/php-apache-firebird/Dockerfile
@@ -1,6 +1,19 @@
FROM php:8.1-apache
-RUN apt-get update && apt-get install -y firebird-dev && \
- pecl install firebird && \
- docker-php-ext-install pdo_firebird && \
- docker-php-ext-enable firebird && \
- a2enmod rewrite
+
+RUN apt-get update && apt-get install -y \
+ firebird-dev \
+ git \
+ autoconf \
+ build-essential \
+ && git clone https://github.com/FirebirdSQL/php-firebird.git /tmp/php-firebird \
+ && cd /tmp/php-firebird \
+ && phpize \
+ && ./configure \
+ && make \
+ && make install \
+ && docker-php-ext-install pdo_firebird \
+ && docker-php-ext-enable firebird \
+ && a2enmod rewrite \
+ && rm -rf /tmp/php-firebird \
+ && apt-get purge -y --auto-remove git autoconf build-essential \
+ && rm -rf /var/lib/apt/lists/*
From d89ffffd27f783dd0270cca71057e09da7e5e18e Mon Sep 17 00:00:00 2001
From: Popa Adrian Marius
Date: Tue, 24 Feb 2026 18:46:41 +0200
Subject: [PATCH 21/42] fix(ci): use firebirdsql/firebird:v3.0 as tag 3.0 is
missing
---
docker-compose.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docker-compose.yml b/docker-compose.yml
index cbb43a7..eafad8c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,6 +1,6 @@
services:
firebird:
- image: firebirdsql/firebird:3.0
+ image: firebirdsql/firebird:v3.0
ports:
- "3050:3050"
environment:
From 49f3d029830d97385a97a78ab9ecd05d77c9538b Mon Sep 17 00:00:00 2001
From: Popa Marius Adrian
Date: Tue, 24 Feb 2026 20:37:13 +0200
Subject: [PATCH 22/42] Update Firebird image version to 3
---
docker-compose.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docker-compose.yml b/docker-compose.yml
index eafad8c..a144a50 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,6 +1,6 @@
services:
firebird:
- image: firebirdsql/firebird:v3.0
+ image: firebirdsql/firebird:3
ports:
- "3050:3050"
environment:
From 0fdf647528d19dcf9051ff94474f65fcb5a389ec Mon Sep 17 00:00:00 2001
From: Popa Marius Adrian
Date: Tue, 24 Feb 2026 21:27:33 +0200
Subject: [PATCH 23/42] Replace firebird extension with interbase
---
.github/docker/php-apache-firebird/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/docker/php-apache-firebird/Dockerfile b/.github/docker/php-apache-firebird/Dockerfile
index 8731da5..531e2af 100644
--- a/.github/docker/php-apache-firebird/Dockerfile
+++ b/.github/docker/php-apache-firebird/Dockerfile
@@ -12,7 +12,7 @@ RUN apt-get update && apt-get install -y \
&& make \
&& make install \
&& docker-php-ext-install pdo_firebird \
- && docker-php-ext-enable firebird \
+ && docker-php-ext-enable interbase \
&& a2enmod rewrite \
&& rm -rf /tmp/php-firebird \
&& apt-get purge -y --auto-remove git autoconf build-essential \
From 388cb968ae866108c085999f5348111543747ee4 Mon Sep 17 00:00:00 2001
From: Popa Adrian Marius
Date: Wed, 25 Feb 2026 04:43:42 +0200
Subject: [PATCH 24/42] fix(ci): use FIREBIRD_ROOT_PASSWORD and improve
healthcheck
---
docker-compose.yml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docker-compose.yml b/docker-compose.yml
index a144a50..99625e8 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -4,13 +4,13 @@ services:
ports:
- "3050:3050"
environment:
- FIREBIRD_PASSWORD: test
+ FIREBIRD_ROOT_PASSWORD: test
FIREBIRD_DATABASE: test.fdb
healthcheck:
- test: ["CMD", "gbak", "-user", "sysdba", "-password", "test", "localhost:/firebird/data/test.fdb", "/dev/null"]
+ test: ["CMD", "/opt/firebird/bin/isql", "-user", "sysdba", "-password", "test", "localhost:/firebird/data/test.fdb", "-q", "-e", "show database; quit;"]
interval: 10s
timeout: 5s
- retries: 5
+ retries: 10
web:
build:
From 9db881cb15aed9904728e53a618d89326adaab50 Mon Sep 17 00:00:00 2001
From: Popa Adrian Marius
Date: Wed, 25 Feb 2026 04:44:19 +0200
Subject: [PATCH 25/42] fix(ci): simplify firebird healthcheck
---
docker-compose.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docker-compose.yml b/docker-compose.yml
index 99625e8..d30a44f 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -7,7 +7,7 @@ services:
FIREBIRD_ROOT_PASSWORD: test
FIREBIRD_DATABASE: test.fdb
healthcheck:
- test: ["CMD", "/opt/firebird/bin/isql", "-user", "sysdba", "-password", "test", "localhost:/firebird/data/test.fdb", "-q", "-e", "show database; quit;"]
+ test: ["CMD-SHELL", "isql -user sysdba -password test /firebird/data/test.fdb -q -e 'quit;'"]
interval: 10s
timeout: 5s
retries: 10
From 055e31c587c0147d5f863a2621682fea02b713b0 Mon Sep 17 00:00:00 2001
From: Popa Adrian Marius
Date: Wed, 25 Feb 2026 04:53:19 +0200
Subject: [PATCH 26/42] fix(ci): use simpler port-based healthcheck for
firebird
---
docker-compose.yml | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/docker-compose.yml b/docker-compose.yml
index d30a44f..05ed5ea 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -7,10 +7,11 @@ services:
FIREBIRD_ROOT_PASSWORD: test
FIREBIRD_DATABASE: test.fdb
healthcheck:
- test: ["CMD-SHELL", "isql -user sysdba -password test /firebird/data/test.fdb -q -e 'quit;'"]
+ test: ["CMD", "nc", "-z", "localhost", "3050"]
interval: 10s
timeout: 5s
- retries: 10
+ retries: 20
+ start_period: 30s
web:
build:
From dd12f1afc31ba6b48ba78138db441fd65d45f355 Mon Sep 17 00:00:00 2001
From: Popa Adrian Marius
Date: Wed, 25 Feb 2026 10:06:32 +0200
Subject: [PATCH 27/42] fix(ci): improve healthcheck robustness and add debug
info
---
.github/workflows/playwright.yml | 8 +++++++-
docker-compose.yml | 9 +++++----
2 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
index 2d2592b..b2d4a38 100644
--- a/.github/workflows/playwright.yml
+++ b/.github/workflows/playwright.yml
@@ -31,7 +31,13 @@ jobs:
sed -i "s|define('DEFAULT_PATH', '/var/lib/firebird/2.5/data/');|define('DEFAULT_PATH', '/firebird/data/');|" inc/configuration.inc.php
- name: Start services
- run: docker compose up -d
+ run: |
+ docker compose up -d || {
+ echo "Docker compose up failed!"
+ docker compose ps
+ docker compose logs
+ exit 1
+ }
- name: Wait for services to be healthy
run: |
diff --git a/docker-compose.yml b/docker-compose.yml
index 05ed5ea..bbf8ebf 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -7,11 +7,11 @@ services:
FIREBIRD_ROOT_PASSWORD: test
FIREBIRD_DATABASE: test.fdb
healthcheck:
- test: ["CMD", "nc", "-z", "localhost", "3050"]
+ test: ["CMD-SHELL", "/opt/firebird/bin/isql -user sysdba -password test localhost:test.fdb -q -e 'quit;'"]
interval: 10s
- timeout: 5s
- retries: 20
- start_period: 30s
+ timeout: 10s
+ retries: 30
+ start_period: 60s
web:
build:
@@ -29,3 +29,4 @@ services:
interval: 10s
timeout: 5s
retries: 5
+ start_period: 30s
From b8c9269a74a93da2af812386a81de7db78fd698e Mon Sep 17 00:00:00 2001
From: Popa Adrian Marius
Date: Wed, 25 Feb 2026 10:25:07 +0200
Subject: [PATCH 28/42] fix(ci): use correct database path for healthcheck and
config
---
.github/workflows/playwright.yml | 2 +-
docker-compose.yml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
index b2d4a38..8603c8d 100644
--- a/.github/workflows/playwright.yml
+++ b/.github/workflows/playwright.yml
@@ -28,7 +28,7 @@ jobs:
cp inc/configuration.inc.php inc/configuration.inc.php.bak
sed -i "s/define('DEFAULT_HOST', 'localhost');/define('DEFAULT_HOST', 'firebird');/" inc/configuration.inc.php
sed -i "s/define('DEFAULT_DB', 'employee.fdb');/define('DEFAULT_DB', 'test.fdb');/" inc/configuration.inc.php
- sed -i "s|define('DEFAULT_PATH', '/var/lib/firebird/2.5/data/');|define('DEFAULT_PATH', '/firebird/data/');|" inc/configuration.inc.php
+ sed -i "s|define('DEFAULT_PATH', '/var/lib/firebird/2.5/data/');|define('DEFAULT_PATH', '/var/lib/firebird/data/');|" inc/configuration.inc.php
- name: Start services
run: |
diff --git a/docker-compose.yml b/docker-compose.yml
index bbf8ebf..96f2a89 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -7,7 +7,7 @@ services:
FIREBIRD_ROOT_PASSWORD: test
FIREBIRD_DATABASE: test.fdb
healthcheck:
- test: ["CMD-SHELL", "/opt/firebird/bin/isql -user sysdba -password test localhost:test.fdb -q -e 'quit;'"]
+ test: ["CMD-SHELL", "isql -user sysdba -password test localhost:/var/lib/firebird/data/test.fdb -q -e 'quit;'"]
interval: 10s
timeout: 10s
retries: 30
From 93aa57c7a83131b2645b953883ba84435cbe6f68 Mon Sep 17 00:00:00 2001
From: Popa Adrian Marius
Date: Wed, 25 Feb 2026 10:46:07 +0200
Subject: [PATCH 29/42] fix(ci): use absolute isql path, 127.0.0.1, and add
healthcheck debug info
---
.github/workflows/playwright.yml | 17 +++++++++++------
docker-compose.yml | 2 +-
2 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
index 8603c8d..3d68c38 100644
--- a/.github/workflows/playwright.yml
+++ b/.github/workflows/playwright.yml
@@ -48,17 +48,22 @@ jobs:
max_wait=300
current_wait=0
while [ $current_wait -lt $max_wait ]; do
- if [ "$(docker compose ps -q web | xargs docker inspect -f '{{.State.Health.Status}}')" = "healthy" ] &&
- [ "$(docker compose ps -q firebird | xargs docker inspect -f '{{.State.Health.Status}}')" = "healthy" ]; then
+ web_status=$(docker compose ps --format json web | jq -r '.[0].Health' 2>/dev/null || docker inspect -f '{{.State.Health.Status}}' $(docker compose ps -q web))
+ firebird_status=$(docker compose ps --format json firebird | jq -r '.[0].Health' 2>/dev/null || docker inspect -f '{{.State.Health.Status}}' $(docker compose ps -q firebird))
+
+ if [ "$web_status" = "healthy" ] && [ "$firebird_status" = "healthy" ]; then
echo "Services are healthy!"
- docker compose logs
exit 0
fi
- echo -n "."
- sleep 5
- current_wait=$((current_wait + 5))
+ echo "Waiting... Web: $web_status, Firebird: $firebird_status"
+ sleep 10
+ current_wait=$((current_wait + 10))
done
echo "Services did not become healthy in time."
+ echo "--- Firebird Healthcheck Logs ---"
+ docker inspect --format='{{json .State.Health}}' $(docker compose ps -q firebird)
+ echo "--- Web Healthcheck Logs ---"
+ docker inspect --format='{{json .State.Health}}' $(docker compose ps -q web)
docker compose logs
exit 1
diff --git a/docker-compose.yml b/docker-compose.yml
index 96f2a89..3fe98ce 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -7,7 +7,7 @@ services:
FIREBIRD_ROOT_PASSWORD: test
FIREBIRD_DATABASE: test.fdb
healthcheck:
- test: ["CMD-SHELL", "isql -user sysdba -password test localhost:/var/lib/firebird/data/test.fdb -q -e 'quit;'"]
+ test: ["CMD-SHELL", "/opt/firebird/bin/isql -user sysdba -password test 127.0.0.1:/var/lib/firebird/data/test.fdb -q -e 'quit;'"]
interval: 10s
timeout: 10s
retries: 30
From b48d23d312e547bf43101b2c4ceb94252354d9b9 Mon Sep 17 00:00:00 2001
From: Popa Adrian Marius
Date: Wed, 25 Feb 2026 10:55:20 +0200
Subject: [PATCH 30/42] fix(ci): decouple startup and improve healthcheck
visibility
---
.github/workflows/playwright.yml | 27 ++++++++++++++-------------
docker-compose.yml | 9 ++++-----
2 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
index 3d68c38..adbd677 100644
--- a/.github/workflows/playwright.yml
+++ b/.github/workflows/playwright.yml
@@ -42,28 +42,29 @@ jobs:
- name: Wait for services to be healthy
run: |
echo "Waiting for services to become healthy..."
- # This command will wait for the healthchecks defined in docker-compose.yml to pass.
- # It will exit with an error if the services do not become healthy within the timeout.
- docker compose ps
max_wait=300
current_wait=0
while [ $current_wait -lt $max_wait ]; do
- web_status=$(docker compose ps --format json web | jq -r '.[0].Health' 2>/dev/null || docker inspect -f '{{.State.Health.Status}}' $(docker compose ps -q web))
- firebird_status=$(docker compose ps --format json firebird | jq -r '.[0].Health' 2>/dev/null || docker inspect -f '{{.State.Health.Status}}' $(docker compose ps -q firebird))
+ firebird_status=$(docker inspect --format='{{.State.Health.Status}}' $(docker compose ps -q firebird) 2>/dev/null || echo "starting")
+ web_status=$(docker inspect --format='{{.State.Health.Status}}' $(docker compose ps -q web) 2>/dev/null || echo "starting")
- if [ "$web_status" = "healthy" ] && [ "$firebird_status" = "healthy" ]; then
- echo "Services are healthy!"
+ echo "Status: Firebird=$firebird_status, Web=$web_status (${current_wait}s)"
+
+ if [ "$firebird_status" = "healthy" ] && [ "$web_status" = "healthy" ]; then
+ echo "All services are healthy!"
exit 0
fi
- echo "Waiting... Web: $web_status, Firebird: $firebird_status"
+
sleep 10
current_wait=$((current_wait + 10))
done
- echo "Services did not become healthy in time."
- echo "--- Firebird Healthcheck Logs ---"
- docker inspect --format='{{json .State.Health}}' $(docker compose ps -q firebird)
- echo "--- Web Healthcheck Logs ---"
- docker inspect --format='{{json .State.Health}}' $(docker compose ps -q web)
+
+ echo "ERROR: Services did not become healthy in time."
+ echo "--- Firebird Detailed Status ---"
+ docker inspect $(docker compose ps -q firebird)
+ echo "--- Web Detailed Status ---"
+ docker inspect $(docker compose ps -q web)
+ echo "--- Container Logs ---"
docker compose logs
exit 1
diff --git a/docker-compose.yml b/docker-compose.yml
index 3fe98ce..68d0568 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -7,11 +7,11 @@ services:
FIREBIRD_ROOT_PASSWORD: test
FIREBIRD_DATABASE: test.fdb
healthcheck:
- test: ["CMD-SHELL", "/opt/firebird/bin/isql -user sysdba -password test 127.0.0.1:/var/lib/firebird/data/test.fdb -q -e 'quit;'"]
+ test: ["CMD-SHELL", "timeout 1s bash -c ':> /dev/tcp/127.0.0.1/3050' || exit 1"]
interval: 10s
- timeout: 10s
+ timeout: 5s
retries: 30
- start_period: 60s
+ start_period: 30s
web:
build:
@@ -22,8 +22,7 @@ services:
volumes:
- .:/var/www/html
depends_on:
- firebird:
- condition: service_healthy
+ - firebird
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/database.php"]
interval: 10s
From c483df60bda02b79f7e81087671b5314c2ebb9db Mon Sep 17 00:00:00 2001
From: Popa Adrian Marius
Date: Wed, 25 Feb 2026 11:04:23 +0200
Subject: [PATCH 31/42] fix(ci): fix PHP extension loading and title mismatch
---
.github/docker/php-apache-firebird/Dockerfile | 2 +-
inc/functions.inc.php | 2 +-
inc/script_start.inc.php | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/docker/php-apache-firebird/Dockerfile b/.github/docker/php-apache-firebird/Dockerfile
index 531e2af..8731da5 100644
--- a/.github/docker/php-apache-firebird/Dockerfile
+++ b/.github/docker/php-apache-firebird/Dockerfile
@@ -12,7 +12,7 @@ RUN apt-get update && apt-get install -y \
&& make \
&& make install \
&& docker-php-ext-install pdo_firebird \
- && docker-php-ext-enable interbase \
+ && docker-php-ext-enable firebird \
&& a2enmod rewrite \
&& rm -rf /tmp/php-firebird \
&& apt-get purge -y --auto-remove git autoconf build-essential \
diff --git a/inc/functions.inc.php b/inc/functions.inc.php
index 53f1c99..d499d8c 100644
--- a/inc/functions.inc.php
+++ b/inc/functions.inc.php
@@ -40,7 +40,7 @@ function build_title($str, $showdb = true)
{
global $s_connected, $s_login;
- $title = 'FirebirdWebAdmin ' . VERSION . ' *** ' . $str;
+ $title = 'Firebird Web Admin / ' . $str;
if ($s_connected == true && $showdb) {
$title .= ': ' . $s_login['database'];
}
diff --git a/inc/script_start.inc.php b/inc/script_start.inc.php
index c066243..b0b2e38 100644
--- a/inc/script_start.inc.php
+++ b/inc/script_start.inc.php
@@ -26,7 +26,7 @@
include './inc/debug_funcs.inc.php';
}
-if (!extension_loaded('interbase')) {
+if (!extension_loaded('interbase') && !extension_loaded('firebird')) {
die($ERRORS['NO_IBASE_MODULE']);
}
From 314ebb21ebea0d10c0312155eed2d0709f37a7d4 Mon Sep 17 00:00:00 2001
From: Popa Adrian Marius
Date: Wed, 25 Feb 2026 11:23:36 +0200
Subject: [PATCH 32/42] fix(ci): enable interbase extension (filename produced
by build)
---
.github/docker/php-apache-firebird/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/docker/php-apache-firebird/Dockerfile b/.github/docker/php-apache-firebird/Dockerfile
index 8731da5..531e2af 100644
--- a/.github/docker/php-apache-firebird/Dockerfile
+++ b/.github/docker/php-apache-firebird/Dockerfile
@@ -12,7 +12,7 @@ RUN apt-get update && apt-get install -y \
&& make \
&& make install \
&& docker-php-ext-install pdo_firebird \
- && docker-php-ext-enable firebird \
+ && docker-php-ext-enable interbase \
&& a2enmod rewrite \
&& rm -rf /tmp/php-firebird \
&& apt-get purge -y --auto-remove git autoconf build-essential \
From 64de2a4e09b85f9d5b29ffed25a69486ed93e13c Mon Sep 17 00:00:00 2001
From: Popa Adrian Marius
Date: Wed, 25 Feb 2026 11:34:43 +0200
Subject: [PATCH 33/42] fix(ci): fix TypeError in get_customize_defaults and
modernize PHP tags
---
inc/functions.inc.php | 3 ++-
views/footer.php | 6 +++---
views/header.php | 4 ++--
views/menu.php | 5 ++---
4 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/inc/functions.inc.php b/inc/functions.inc.php
index d499d8c..10136a5 100644
--- a/inc/functions.inc.php
+++ b/inc/functions.inc.php
@@ -1249,6 +1249,7 @@ function get_customize_cookie_name()
//
function get_customize_defaults($useragent)
{
+ $ie = (isset($useragent) && is_array($useragent) && isset($useragent['ie'])) ? $useragent['ie'] : false;
return array('color' => array('background' => COLOR_BACKGROUND,
'panel' => COLOR_PANEL,
@@ -1264,7 +1265,7 @@ function get_customize_defaults($useragent)
'firstrow' => COLOR_FIRSTROW,
'secondrow' => COLOR_SECONDROW),
'language' => LANGUAGE,
- 'fontsize' => ($useragent['ie'] ? 8 : 11),
+ 'fontsize' => ($ie ? 8 : 11),
'textarea' => array('cols' => SQL_AREA_COLS,
'rows' => SQL_AREA_ROWS),
'iframeheight' => IFRAME_HEIGHT,
diff --git a/views/footer.php b/views/footer.php
index e478655..c4f63e6 100644
--- a/views/footer.php
+++ b/views/footer.php
@@ -10,7 +10,7 @@
|
- = date('Y') ?>
+
-
FirebirdWebAdmin
@@ -120,10 +120,10 @@ class="col-sm-4 control-label">
-= js_global_variables()
+
|