diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 113ec42be..faa801277 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -10,10 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: php-actions/composer@v6
- - uses: php-actions/phpcs@v1
- with:
- path: .
- standard: phpcs.xml
- - uses: php-actions/phpstan@v3
+ - run: composer phpcs
+ - run: composer phpstan
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 8c5dcfbf6..000000000
--- a/Makefile
+++ /dev/null
@@ -1,39 +0,0 @@
-ROOT_DIRECTORY = $(shell dirname "$(realpath $(lastword $(MAKEFILE_LIST)))")
-PHP := $(shell which php)
-PORT := 8000
-
-
-.DEFAULT_GOAL := default
-
-
-.PHONY: default
-default: compile
-
-.PHONY: compile
-compile:
- $(PHP) $(ROOT_DIRECTORY)/compile.php
-
-.PHONY: server
-server:
- php \
- --server 127.0.0.1:$(PORT) \
- --docroot $(ROOT_DIRECTORY)
-
-.PHONY: initialize
-initialize:
- git \
- -C $(ROOT_DIRECTORY) \
- submodule \
- update \
- --init \
- --recursive
-
-.PHONY: clean
-clean:
- rm \
- --recursive \
- --force \
- $(ROOT_DIRECTORY)/adminer.php
-
-.PHONY: clean.all
-clean.all: clean
diff --git a/README.md b/README.md
index 856aab018..863bbaf41 100644
--- a/README.md
+++ b/README.md
@@ -22,5 +22,13 @@ If downloaded from Git then run: `git submodule update --init`
- `lang.php` - Update translations
- `tests/*.html` - Katalon Recorder test suites
+## Composer Scripts
+Install the development tools first with `composer install`.
+
+- `composer initialize` - Update Git submodules
+- `composer phpcs` - Run the coding standard check using [phpcs.xml](/phpcs.xml)
+- `composer phpcbf` - Automatically fix coding standard issues where possible using [phpcs.xml](/phpcs.xml)
+- `composer phpstan` - Run PHPStan using `phpstan.neon`
+
## Plugins
There are several plugins distributed with Adminer, as well as many user-contributed plugins listed on the [Adminer Plugins page](https://www.adminer.org/plugins/).
diff --git a/adminer/call.inc.php b/adminer/call.inc.php
index b35da5ba6..44ffbdfb3 100644
--- a/adminer/call.inc.php
+++ b/adminer/call.inc.php
@@ -1,4 +1,5 @@
$field) {
$foreign_key = $foreign_keys[$field["type"]];
- $type_field = ($foreign_key !== null ? $referencable_primary[$foreign_key] : $field); //! can collide with user defined type
+ $type_field = (isset($referencable_primary[$foreign_key]) ? $referencable_primary[$foreign_key] : $field); //! can collide with user defined type
if ($field["field"] != "") {
if (!$field["generated"]) {
$field["default"] = null;
diff --git a/adminer/database.inc.php b/adminer/database.inc.php
index 828f9d176..320a0f26f 100644
--- a/adminer/database.inc.php
+++ b/adminer/database.inc.php
@@ -1,4 +1,5 @@
"MySQL / MariaDB") + SqlDriver::$drivers;
@@ -30,7 +31,7 @@ function attach(string $server, string $username, string $password): string {
null,
(is_numeric($port) ? intval($port) : ini_get("mysqli.default_port")),
(is_numeric($port) ? null : $port),
- ($ssl ? ($ssl['verify'] !== false ? 2048 : 64) : 0) // 2048 - MYSQLI_CLIENT_SSL, 64 - MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT (not available before PHP 5.6.16)
+ ($ssl ? (isset($ssl['verify']) && $ssl['verify'] === false ? 64 : 2048) : 0) // 2048 - MYSQLI_CLIENT_SSL, 64 - MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT (not available before PHP 5.6.16)
);
$this->options(MYSQLI_OPT_LOCAL_INFILE, 0);
return ($return ? '' : $this->error);
diff --git a/adminer/drivers/oracle.inc.php b/adminer/drivers/oracle.inc.php
index 831effc9d..45a682240 100644
--- a/adminer/drivers/oracle.inc.php
+++ b/adminer/drivers/oracle.inc.php
@@ -1,4 +1,5 @@
= 70100) {
- $return = implode("\n", pg_last_notice($this->link, 2)); // 2 - PGSQL_NOTICE_ALL
+ $notice = pg_last_notice($this->link, 2); // 2 - PGSQL_NOTICE_ALL
+ $return = implode("\n", (array) $notice);
pg_last_notice($this->link, 3); // 3 - PGSQL_NOTICE_CLEAR
} else {
$return = pg_last_notice($this->link);
diff --git a/adminer/drivers/sqlite.inc.php b/adminer/drivers/sqlite.inc.php
index f6f5384cb..e8520ee70 100644
--- a/adminer/drivers/sqlite.inc.php
+++ b/adminer/drivers/sqlite.inc.php
@@ -1,4 +1,5 @@
element */
@@ -172,7 +173,7 @@ function hidden_fields(array $process, array $ignore = array(), string $prefix =
/** Print hidden fields for GET forms */
function hidden_fields_get(): void {
echo (sid() ? input_hidden(session_name(), session_id()) : '');
- echo (SERVER !== null ? input_hidden(DRIVER, SERVER) : "");
+ echo input_hidden(DRIVER, SERVER);
echo input_hidden("username", $_GET["username"]);
}
diff --git a/adminer/include/lang.inc.php b/adminer/include/lang.inc.php
index be59a6ed2..c338aecb1 100644
--- a/adminer/include/lang.inc.php
+++ b/adminer/include/lang.inc.php
@@ -1,4 +1,5 @@
=7.4"
},
+ "require-dev": {
+ "phpstan/phpstan": "^1.12",
+ "squizlabs/php_codesniffer": "^3.11"
+ },
"scripts": {
"check": [
- "phpcs",
- "phpstan analyse -c phpstan.neon"
+ "@phpcs",
+ "@phpstan"
],
"compile": "@php compile.php",
- "clean": "rm -f adminer*.php editor*.php"
+ "clean": "rm -f adminer*.php editor*.php",
+ "initialize": "git submodule update --init --recursive",
+ "phpcbf": "sh -c 'if [ -x vendor/bin/phpcbf ]; then exec vendor/bin/phpcbf --standard=phpcs.xml .; fi; bin=\"$(composer global config bin-dir --absolute 2>/dev/null)/phpcbf\"; if [ -x \"$bin\" ]; then exec \"$bin\" --standard=phpcs.xml .; fi; exec phpcbf --standard=phpcs.xml .'",
+ "phpcs": "sh -c 'if [ -x vendor/bin/phpcs ]; then exec vendor/bin/phpcs --standard=phpcs.xml --report=full .; fi; bin=\"$(composer global config bin-dir --absolute 2>/dev/null)/phpcs\"; if [ -x \"$bin\" ]; then exec \"$bin\" --standard=phpcs.xml --report=full .; fi; exec phpcs --standard=phpcs.xml --report=full .'",
+ "phpstan": "sh -c 'if [ -x vendor/bin/phpstan ]; then exec vendor/bin/phpstan analyse -c phpstan.neon --memory-limit=512M; fi; bin=\"$(composer global config bin-dir --absolute 2>/dev/null)/phpstan\"; if [ -x \"$bin\" ]; then exec \"$bin\" analyse -c phpstan.neon --memory-limit=512M; fi; exec phpstan analyse -c phpstan.neon --memory-limit=512M'"
}
}
diff --git a/editor/db.inc.php b/editor/db.inc.php
index 301538852..13274e1a0 100644
--- a/editor/db.inc.php
+++ b/editor/db.inc.php
@@ -1,4 +1,5 @@
select_db(adminer()->database());
diff --git a/editor/include/editing.inc.php b/editor/include/editing.inc.php
index 207f361b4..e34d1ad1c 100644
--- a/editor/include/editing.inc.php
+++ b/editor/include/editing.inc.php
@@ -1,4 +1,5 @@
/externals/
/designs/
/(adminer|editor)[-.]
+ /vendor
@@ -51,6 +52,7 @@
adminer/include/pdo.inc.php
adminer/plugins/foreign-system.php
adminer/plugins/drivers/
+ plugins/*
@@ -79,7 +81,6 @@
-
@@ -93,19 +94,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/phpstan.neon b/phpstan.neon
index 1b2253aea..8c6394b05 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -9,7 +9,6 @@ parameters:
- "~Function Adminer\\\\queries\\(\\) never returns Adminer\\\\Result~" # mysqli_result
# not real problems
- - identifier: include.fileNotFound # includes in include/ relative from index.php
- "~^Function (set_magic_quotes_runtime|mysql_)~" # PHP < 7 functions
- "~an unknown class OCI-?Lob~" # this looks like PHPStan bug
- "~^Variable \\$error might not be defined~" # declared in bootstrap.inc.php
@@ -22,7 +21,6 @@ parameters:
- "~expects bool~" # truthy values
- "~fread expects int<1, max>, 100000~" # 1e6
- "~'strlen' given~" # used as a bool callback
- - "~between int<70100~" # PHP_VERSION_ID check
-
message: "~ type specified~" # duplicate functions and methods
@@ -31,9 +29,6 @@ parameters:
- adminer/drivers/*
# it probably doesn't like $ar[$key] instead of isset($ar[$key]) and thinks that $ar[$key] is always set
- - identifier: identical.alwaysFalse
- - identifier: notEqual.alwaysFalse
- - identifier: notIdentical.alwaysTrue
- identifier: booleanNot.alwaysTrue
- identifier: booleanNot.alwaysFalse
- identifier: booleanAnd.alwaysFalse
@@ -46,7 +41,7 @@ parameters:
- identifier: isset.offset
- identifier: deadCode.unreachable
- "~Function Adminer\\\\get_driver\\(\\) never returns null~"
- - "~on array\\{}~"
+ - "~Strict comparison using === between .* will always evaluate to false\\.~"
paths:
- adminer/drivers/mysql.inc.php # other drivers inherit the annotations so we take them from here
@@ -59,9 +54,15 @@ parameters:
- adminer/elastic.php
- adminer/sqlite.php
+ parallel:
+ jobSize: 20
+ processTimeout: 600.0
+ maximumNumberOfProcesses: 1
+ minimumNumberOfJobsPerProcess: 2
+ buffer: 134217728
+
phpVersion:
- min: 70100
- max: 80499
+ 70400
typeAliases:
TableStatus: "array{Name:string, Engine?:?string, Comment?:string, Oid?:numeric-string, Rows?:?numeric-string, Collation?:string, Auto_increment?:?numeric-string, Data_length?:numeric-string, Index_length?:numeric-string, Data_free?:numeric-string, Create_options?:string, partition?:numeric-string, nspname?:string}"
diff --git a/plugins/drivers/clickhouse.php b/plugins/drivers/clickhouse.php
index e443df451..9517df46c 100644
--- a/plugins/drivers/clickhouse.php
+++ b/plugins/drivers/clickhouse.php
@@ -1,4 +1,5 @@
and link to the uploaded files from select
diff --git a/plugins/login-table.php b/plugins/login-table.php
index 52c0a23ab..e661bf12f 100644
--- a/plugins/login-table.php
+++ b/plugins/login-table.php
@@ -1,4 +1,5 @@